Skip to content

Commit 2fa22ac

Browse files
committed
rewritten Akima
1 parent 1a56a1b commit 2fa22ac

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1306
-1415
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ if ( UTILS_ENABLE_TESTS )
169169

170170
set(
171171
EXELISTCPP
172-
test1 test2 test3 test4 test5 test6 test8 test9 test10
172+
test01 test02 test03 test04 test05 test06 test08 test09 test10 test11
173173
)
174174

175175
add_custom_target( "${PROJECT_NAME}_all_tests" ALL )

src/SplineAkima.cc

Lines changed: 54 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -56,64 +56,65 @@ namespace Splines {
5656

5757
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5858

59-
static
60-
real_type
61-
akima_one(
62-
real_type const epsi,
63-
real_type const di_m2,
64-
real_type const di_m1,
65-
real_type const di,
66-
real_type const di_p1
67-
) {
68-
real_type wl { abs(di_p1 - di) };
69-
real_type wr { abs(di_m1 - di_m2) };
70-
real_type den { wl + wr };
71-
if ( den <= epsi ) { wl = wr = 0.5; den = 1; } // if epsi == 0
72-
real_type const num{ wl * di_m1 + wr * di };
73-
return num / den;
74-
}
75-
76-
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
77-
7859
void
7960
Akima_build(
8061
real_type const X[],
8162
real_type const Y[],
8263
real_type Yp[],
83-
integer const npts
64+
real_type m[], // work vector dimension N
65+
integer N
8466
) {
85-
86-
UTILS_ASSERT( npts >= 2, "Akima_build require at least 2 points" );
8767

88-
if ( npts == 2 ) { // solo 2 punti, niente da fare
68+
UTILS_ASSERT( N >= 2, "Akima_build require at least 2 points" );
69+
70+
if ( N == 2 ) { // solo 2 punti, niente da fare
8971
Yp[0] = Yp[1] = (Y[1]-Y[0])/(X[1]-X[0]);
90-
} else {
91-
Malloc_real mem("Akima_build");
92-
real_type * m{ mem.malloc( npts+3 ) };
93-
94-
// calcolo slopes (npts-1) intervals + 4
95-
for ( integer i{1}; i < npts; ++i )
96-
m[i+1] = (Y[i]-Y[i-1])/(X[i]-X[i-1]);
97-
98-
// extra slope at the boundary
99-
m[1] = 2*m[2]-m[3];
100-
m[0] = 2*m[1]-m[2];
101-
m[npts+1] = 2*m[npts]-m[npts-1];
102-
m[npts+2] = 2*m[npts+1]-m[npts];
103-
104-
// minimum delta slope
105-
real_type epsi{0};
106-
for ( integer i{0}; i < npts+2; ++i ) {
107-
real_type const dm{ std::abs(m[i+1]-m[i]) };
108-
if ( dm > epsi ) epsi = dm;
109-
}
110-
epsi *= 1E-8;
72+
return;
73+
}
74+
75+
// 1. Calcola le pendenze m_i = (Y[i+1] - Y[i]) / (X[i+1] - X[i])
76+
for ( integer i{0}; i < N-1; ++i ) {
77+
UTILS_ASSERT(
78+
X[i+1] > X[i],
79+
"Akima_build, X must be strictly increasing X[{}] = {}, X[{}] = {}",
80+
i, X[i], i+1, X[i+1]
81+
);
82+
m[i] = (Y[i+1] - Y[i]) / (X[i+1] - X[i]);
83+
}
11184

112-
// 0 1 2 3 4---- n-1 n n+1 n+2
113-
// + + + + +
114-
for ( integer i{0}; i < npts; ++i )
115-
Yp[i] = akima_one( epsi, m[i], m[i+1], m[i+2], m[i+3] );
85+
// 2. Calcolo epsi
86+
real_type epsi{0};
87+
for ( integer i{0}; i < N-2; ++i ) {
88+
real_type const dm{ std::abs(m[i+1]-m[i]) };
89+
if ( dm > epsi ) epsi = dm;
90+
}
91+
epsi *= 1E-8;
92+
93+
// 3. Calcola le derivate nei punti interni (i = 1..N-2)
94+
for ( integer i{1}; i < N-1; ++i ) {
95+
// Estrapola le pendenze se necessario (ai bordi)
96+
real_type const m_im2 { (i >= 2) ? m[i-2] : 2*m[i-1] - m[i] }; // m_{i-2}
97+
real_type const m_im1 { m[i-1] }; // m_{i-1}
98+
real_type const m_i { m[i] }; // m_i
99+
real_type const m_ip1 { (i < N-2) ? m[i+1] : 2*m[i] - m[i-1] }; // m_{i+1}
100+
101+
// Pesatura di Akima (come in MATLAB makima)
102+
// https://blogs.mathworks.com/cleve/2019/04/29/makima-piecewise-cubic-interpolation/#d9a97978-0b09-4a1f-a6a5-504d088631d0
103+
real_type const w_left { std::abs( m_ip1 - m_i ) + std::abs( m_ip1 + m_i ) / 2 };
104+
real_type const w_right { std::abs( m_im1 - m_im2 ) + std::abs( m_im1 + m_im2 ) / 2 };
105+
real_type const sum_w { w_left + w_right };
106+
107+
if ( sum_w > epsi ) {
108+
Yp[i] = (w_right * m_im1 + w_left * m_i) / sum_w;
109+
} else {
110+
Yp[i] = 0.5*(m_im1 + m_i); // Caso speciale
111+
}
116112
}
113+
114+
// 4. Derivate ai bordi (i=0 e i=N-1)
115+
// Estrapolazione quadratica
116+
Yp[0] = m[0] + (m[0] - m[1]) * (X[0] - X[1]) / (X[2] - X[0]);
117+
Yp[N-1] = m[N-2] + (m[N-2] - m[N-3]) * (X[N-1] - X[N-2]) / (X[N-1] - X[N-3]);
117118
}
118119

119120
#endif
@@ -128,10 +129,14 @@ namespace Splines {
128129
Utils::check_NaN( m_Y, msg+" Y ", m_npts, __LINE__, __FILE__ );
129130
integer ibegin{0};
130131
integer iend{0};
132+
133+
Malloc_real m_mem("AkimaSpline::work memory");
134+
real_type * m_work{ m_mem.malloc( m_npts ) };
135+
131136
do {
132137
// cerca intervallo monotono strettamente crescente
133138
while ( ++iend < m_npts && m_X[iend-1] < m_X[iend] ) {}
134-
Akima_build( m_X+ibegin, m_Y+ibegin, m_Yp+ibegin, iend-ibegin );
139+
Akima_build( m_X+ibegin, m_Y+ibegin, m_Yp+ibegin, m_work, iend-ibegin );
135140
ibegin = iend;
136141
} while ( iend < m_npts );
137142

0 commit comments

Comments
 (0)