NCBI C++ ToolKit
SplinePchip.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*--------------------------------------------------------------------------*\
2  | |
3  | Copyright (C) 2016 |
4  | |
5  | , __ , __ |
6  | /|/ \ /|/ \ |
7  | | __/ _ ,_ | __/ _ ,_ |
8  | | \|/ / | | | | \|/ / | | | |
9  | |(__/|__/ |_/ \_/|/|(__/|__/ |_/ \_/|/ |
10  | /| /| |
11  | \| \| |
12  | |
13  | Enrico Bertolazzi |
14  | Dipartimento di Ingegneria Industriale |
15  | Universita` degli Studi di Trento |
16  | email: enrico.bertolazzi@unitn.it |
17  | |
18 \*--------------------------------------------------------------------------*/
19 
20 
21 #include <ncbi_pch.hpp>
22 #include <gui/utils/splines/Splines.hh>
23 
24 #include <cmath>
25 
26 /**
27  *
28  */
29 
30 namespace Splines {
31 
32  using namespace std; // load standard namspace
33 
34  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35 
36  static
37  inline
38  real_type
39  max_abs( real_type a, real_type b ) {
40  real_type res = std::abs(a);
41  if ( res < std::abs(b) ) res = std::abs(b);
42  return res;
43  }
44 
45  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
46 
47  static
48  inline
49  real_type
50  min_abs( real_type a, real_type b ) {
51  real_type res = std::abs(a);
52  if ( res > std::abs(b) ) res = std::abs(b);
53  return res;
54  }
55 
56  /*
57  // ____ _ _ ____ _ _
58  // | _ \ ___| |__ (_)_ __/ ___| _ __ | (_)_ __ ___
59  // | |_) / __| '_ \| | '_ \___ \| '_ \| | | '_ \ / _ \
60  // | __/ (__| | | | | |_) |__) | |_) | | | | | | __/
61  // |_| \___|_| |_|_| .__/____/| .__/|_|_|_| |_|\___|
62  // |_| |_|
63  */
64 
65  static
66  inline
67  int
68  signTest( real_type const a, real_type const b ) {
69  int sa = 0;
70  int sb = 0;
71  if ( a > 0 ) sa = 1;
72  else if ( a < 0 ) sa = -1;
73  if ( b > 0 ) sb = 1;
74  else if ( b < 0 ) sb = -1;
75  return sa*sb;
76  }
77 
78  /*!
79  | Reference:
80  | ==========
81  |
82  | F.N. Fritsch, R.E. Carlson:
83  | Monotone Piecewise Cubic Interpolation,
84  | SIAM J. Numer. Anal. Vol 17, No. 2, April 1980
85  |
86  | F.N. Fritsch and J. Butland:
87  | A method for constructing local monotone piecewise cubic interpolants,
88  | SIAM Journal on Scientific and Statistical Computing 5, 2 (June 1984), pp. 300-304.
89  \*/
90  void
91  pchip( real_type const X[],
92  real_type const Y[],
93  real_type Yp[],
94  integer n ) {
95 
96  integer ierr = 0;
97 
98  // function definition is ok, go on.
99  real_type h1 = X[1] - X[0];
100  real_type del1 = (Y[1]-Y[0])/h1;
101  real_type dsave = del1;
102 
103  // special case n=2 -- use linear interpolation.
104  if ( n == 1 ) { Yp[0] = Yp[1] = del1; return; }
105 
106  real_type h2 = X[2] - X[1];
107  real_type del2 = (Y[2]-Y[1])/h2;
108 
109  // Set Yp[0] via non-centered three-point formula, adjusted to be shape-preserving.
110  real_type hsum = h1 + h2;
111  real_type w1 = (h1 + hsum)/hsum;
112  real_type w2 = -h1/hsum;
113  Yp[0] = w1*del1 + w2*del2;
114  real_type dmin, dmax;
115  if ( signTest(Yp[0],del1) <= 0 ) {
116  Yp[0] = 0;
117  } else if ( signTest(del1,del2) < 0 ) {
118  // NEED DO THIS CHECK ONLY IF MONOTONICITY SWITCHES.
119  dmax = 3*del1;
120  if ( std::abs(Yp[0]) > std::abs(dmax) ) Yp[0] = dmax;
121  }
122 
123  // loop through interior points.
124  for ( integer i = 1; i < n; ++i ) {
125  if ( i > 1 ) {
126  h1 = h2;
127  h2 = X[i+1] - X[i];
128  hsum = h1 + h2;
129  del1 = del2;
130  del2 = (Y[i+1] - Y[i])/h2;
131  }
132  // set Yp[i]=0 unless data are strictly monotonic.
133  Yp[i] = 0;
134  // count number of changes in direction of monotonicity.
135  switch ( signTest(del1,del2) ) {
136  case -1:
137  if ( isZero(del2) ) break;
138  if ( signTest(dsave,del2) < 0 ) ++ierr;
139  dsave = del2;
140  break;
141  case 0:
142  ++ierr;
143  dsave = del2;
144  break;
145  case 1: // use brodlie modification of butland formula.
146  w1 = (1+h1/hsum)/3;
147  w2 = (1+h2/hsum)/3;
148  dmax = max_abs( del1, del2 );
149  dmin = min_abs( del1, del2 );
150  real_type drat1 = del1/dmax;
151  real_type drat2 = del2/dmax;
152  Yp[i] = dmin/(w1*drat1 + w2*drat2);
153  break;
154  }
155  }
156  // set Yp[n] via non-centered three-point formula, adjusted to be shape-preserving.
157  w1 = -h2/hsum;
158  w2 = (h2 + hsum)/hsum;
159  Yp[n] = w1*del1 + w2*del2;
160  if ( signTest(Yp[n],del2) <= 0 ) {
161  Yp[n] = 0;
162  } else if ( signTest(del1,del2) < 0 ) {
163  // need do this check only if monotonicity switches.
164  dmax = 3*del2;
165  if ( abs(Yp[n]) > abs(dmax) ) Yp[n] = dmax;
166  }
167  // cout << "ierr = " << ierr << '\n';
168  }
169 
170  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
171 
172  void
173  PchipSpline::build() {
174  SPLINE_ASSERT( npts > 1,
175  "PchipSpline::build(): npts = " << npts <<
176  " not enought points" );
177  integer ibegin = 0;
178  integer iend = 0;
179  do {
180  // cerca intervallo monotono strettamente crescente
181  while ( ++iend < npts && X[iend-1] < X[iend] ) {};
182  pchip( X+ibegin, Y+ibegin, Yp+ibegin, (iend-ibegin)-1 );
183  ibegin = iend;
184  } while ( iend < npts );
185 
186  SPLINE_CHECK_NAN(Yp,"PchipSpline::build(): Yp",npts);
187  //pchip( X, Y, Yp, npts -1 );
188  }
189 
190 }
int i
yy_size_t n
Various kind of splines.
void pchip(real_type const X[], real_type const Y[], real_type Yp[], integer n)
Definition: SplinePchip.cpp:91
static int signTest(real_type const a, real_type const b)
Definition: SplinePchip.cpp:68
static real_type min_abs(real_type a, real_type b)
Definition: SplinePchip.cpp:50
static real_type max_abs(real_type a, real_type b)
Definition: SplinePchip.cpp:39
#define abs(a)
Definition: ncbi_heapmgr.c:130
unsigned int a
Definition: ncbi_localip.c:102
Modified on Fri Sep 20 14:58:13 2024 by modify_doxy.py rev. 669887