@@ -230,11 +230,11 @@ struct setNaturalSplineBoundaryCondition<BoundaryConditionType::Clamped, T, Tx,
230230
231231
232232template <typename T>
233- void cyclic_thomas_algorithm (const std::vector<T> &a, const std::vector<T> &b, const std::vector<T> &c, std::vector<T> &d)
233+ void cyclic_thomas_algorithm (const std::vector<T> &a, const std::vector<T> &b, const std::vector<T> &c, std::vector<T> &d, const std:: size_t exclude_rows= 0 )
234234{
235235 // See https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm#Variants
236236
237- const auto nx = d.size ();
237+ const auto nx = d.size () - exclude_rows; // last exclude_rows rows are not used
238238
239239 std::vector<T> cmod (nx);
240240 std::vector<T> v (nx);
@@ -243,27 +243,31 @@ void cyclic_thomas_algorithm(const std::vector<T> &a, const std::vector<T> &b, c
243243 v[1 ] = -a[1 ]/b[1 ];
244244 d[1 ] = d[1 ]/b[1 ];
245245
246- for (auto ix = 2 ; ix < nx-1 ; ++ix) {
246+ for (auto ix = 2 ; ix < nx-1 ; ++ix)
247+ {
247248 const T m = T (1.0 )/(b[ix] - a[ix]*cmod[ix-1 ]);
248249 cmod[ix] = m*c[ix];
249250 v[ix] = (T (0.0 ) - a[ix]*v[ix-1 ]) * m;
250251 d[ix] = (d[ix] - a[ix]*d[ix-1 ]) * m;
251252 }
252253
253254 const T m = T (1.0 )/(b[nx-1 ] - a[nx-1 ]*cmod[nx-2 ]);
254- cmod[nx - 1 ] = m*c[nx-1 ];
255- v[nx - 1 ] = m*(-c[0 ] - a[nx-1 ]*v[nx-2 ]);
256- d[nx - 1 ] = m*(d[nx-1 ] - a[nx-1 ]*d[nx-2 ]);
255+ cmod[nx- 1 ] = m*c[nx-1 ];
256+ v[nx- 1 ] = m*(-c[0 ] - a[nx-1 ]*v[nx-2 ]);
257+ d[nx- 1 ] = m*(d[nx-1 ] - a[nx-1 ]*d[nx-2 ]);
257258
258- for (auto ix = nx - 2 ; ix >= 1 ; --ix) {
259+ for (auto ix = nx - 2 ; ix >= 1 ; --ix)
260+ {
259261 v[ix] -= cmod[ix]*v[ix+1 ];
260262 d[ix] -= cmod[ix]*d[ix+1 ];
261263 }
262264
263265 d[0 ] = (d[0 ] - a[0 ]*d[nx-1 ] - c[0 ]*d[1 ])/(b[0 ] + a[0 ]*v[nx-1 ] + c[0 ]*v[1 ]);
264266
265267 for (auto ix = 1 ; ix < nx; ++ix)
268+ {
266269 d[ix] += d[0 ]*v[ix];
270+ }
267271}
268272
269273
@@ -274,7 +278,8 @@ struct setNaturalSplineBoundaryCondition<BoundaryConditionType::Periodic, T, Tx,
274278
275279 // Periodic boundary conditions, it is assumed that f[0] == f[nx-1] !
276280
277- const auto nsys = a.size ();
281+ // last equation is for periodicity and not used in cyclic thomas algorithm
282+ const auto nsys = d.size () - 1 ;
278283
279284 // Row 0
280285 {
@@ -298,7 +303,9 @@ struct setNaturalSplineBoundaryCondition<BoundaryConditionType::Periodic, T, Tx,
298303 d[nsys-1 ] = 3.0 *((f[nsys-1 ] - f[nsys-2 ])/(dxL*dxL) + (f[0 ] - f[nsys-1 ])/(dxR*dxR));
299304 }
300305
301- cyclic_thomas_algorithm<T>(a, b, c, d);
306+ cyclic_thomas_algorithm<T>(a, b, c, d, 1 ); // exclude last row
307+
308+ d.back () = d.front (); // duplicate endpoint slope for periodic BC
302309 }
303310};
304311
@@ -310,18 +317,17 @@ std::vector<T> natural_spline_slopes(const Tx x, const Tf f)
310317
311318 const auto nx = x.size ();
312319
313- // Periodic with duplicated endpoint → reduce system
314- constexpr bool is_periodic = (BC == BoundaryConditionType::Periodic);
315- const auto nsys = is_periodic ? nx - 1 : nx;
316-
317320 // vectors that fill up the tridiagonal matrix
318- std::vector<T> a (nsys , T{0 }); // first value of a is only used for periodic BC
319- std::vector<T> b (nsys , T{0 });
320- std::vector<T> c (nsys , T{0 }); // last value of c is only used for periodic BC
321+ std::vector<T> a (nx , T{0 }); // first value of a is only used for periodic BC
322+ std::vector<T> b (nx , T{0 });
323+ std::vector<T> c (nx , T{0 }); // last value of c is only used for periodic BC
321324 // right hand side
322- std::vector<T> d (nsys , T{0 });
325+ std::vector<T> d (nx , T{0 });
323326
324- for (auto i = 1 ; i < nsys-1 ; ++i)
327+ // For Periodic BD the last row is not used
328+ constexpr bool is_periodic = (BC == BoundaryConditionType::Periodic);
329+
330+ for (auto i = 1 ; i < (is_periodic ? nx-2 : nx-1 ); ++i)
325331 {
326332 T dxL = x[i] - x[i-1 ];
327333 T dxR = x[i+1 ] - x[i];
@@ -333,17 +339,6 @@ std::vector<T> natural_spline_slopes(const Tx x, const Tf f)
333339
334340 setNaturalSplineBoundaryCondition<BC, T, Tx, Tf>{}(x, f, a, b, c, d);
335341
336- if constexpr (is_periodic)
337- {
338- std::vector<T> full (nx);
339- for (auto i = 0 ; i < nsys; ++i)
340- {
341- full[i] = d[i];
342- }
343- full[nx-1 ] = full[0 ]; // duplicate endpoint slope
344- return full;
345- }
346-
347342 return d;
348343}
349344
0 commit comments