source: Sophya/trunk/SophyaLib/NTools/cspline.cc@ 3201

Last change on this file since 3201 was 2808, checked in by ansari, 20 years ago

MAJ documentation - Reza 14/6/2005

File size: 11.2 KB
Line 
1#include "sopnamsp.h"
2#include "machdefs.h"
3
4#include <stdlib.h>
5#include <stdio.h>
6#include <math.h>
7#include <iostream>
8
9#ifdef __MWERKS__
10 #include <iostream>
11#endif
12
13#include "nbtri.h"
14#include "cspline.h"
15
16/*!
17 \class SOPHYA::CSpline
18 \ingroup NTools
19 Spline 3 smoother (interpolator) for 1-D data points (y = f(x))
20 \sa CSpline2
21*/
22
23/*!
24 Createur pour spline 3 sur "x[0->n],y[0->n]" avec "yp1,ypn" derivees
25 au premier et dernier points et "natural" indiquant les types de
26 contraintes sur les derivees 2sd au premier et dernier point.
27 "order" doit etre mis a "true" si le tableau de "x[]" n'est pas ordonne
28 dans l'ordre des "x" croissants ("x[i]<x[i+1]"): cette option
29 realloue la place pour les tableaux "x,y" autrement seule une
30 connection aux tableaux "x,y" externes est realisee.
31*/
32CSpline::CSpline(int n,double* x,double* y,double yp1,double ypn
33 ,int natural,bool order)
34 : Nel(0), corrupt_Y2(true), XY_Created(false), Natural(natural)
35 , YP1(yp1), YPn(ypn), X(NULL), Y(NULL), Y2(NULL), tmp(NULL)
36{
37SetNewTab(n,x,y,order,true);
38if( x != NULL && y != NULL) ComputeCSpline();
39
40}
41
42//! Createur par defaut.
43CSpline::CSpline(double yp1,double ypn,int natural)
44 : Nel(0), corrupt_Y2(true), XY_Created(false), Natural(natural)
45 , YP1(yp1), YPn(ypn), X(NULL), Y(NULL), Y2(NULL), tmp(NULL)
46{
47}
48
49//////////////////////////////////////////////////////////////////////////////
50//! destructeur
51CSpline::~CSpline()
52{
53DelTab();
54}
55
56/*!
57 Pour changer les tableaux sans recreer la classe,
58 memes arguments que dans le createur.
59 Pour connecter les tableaux "x[n],y[n]" aux pointeurs internes "X,Y"
60 Si "order=true", on considere que x n'est pas range par ordre
61 des "x" croissants. La methode alloue de la place pour des tableaux
62 internes "X,Y" qu'elle re-ordonne par "x" croissant.
63 "force=true" impose la reallocation des divers buffers, sinon
64 la reallocation n'a lieu que si le nombre de points augmente.
65*/
66void CSpline::SetNewTab(int n,double* x,double* y,bool order,bool force)
67{
68ASSERT( n>3 );
69
70// allocation des buffers Y2 et tmp
71if( n>Nel || force ) {
72 if( Y2 != NULL ) delete [] Y2;
73 if( tmp != NULL ) delete [] tmp;
74 Y2 = new double[n];
75 tmp = new double[n];
76}
77// des-allocation eventuelle de X,Y
78if( XY_Created ) {
79 if( !order || n>Nel || force ) {
80 if( X != NULL ) delete [] X; X = NULL;
81 if( Y != NULL ) delete [] Y; Y = NULL;
82 XY_Created = false;
83 }
84}
85// allocation eventuelle de X,Y
86if( order ) {
87 if( !XY_Created || n>Nel || force ) {
88 X = new double[n];
89 Y = new double[n];
90 XY_Created = true;
91 }
92}
93Nel = n;
94corrupt_Y2 = true;
95
96if( x==NULL || y==NULL ) return;
97
98// Classement eventuel par ordre des x croissants
99if( order ) {
100 if( tmp == NULL ) tmp = new double[n];
101 ind = (int_4 *) tmp;
102 tri_double(x,ind,(int_4) Nel);
103 for(int i=0;i<Nel;i++) {
104 X[i] = x[ind[i]];
105 Y[i] = y[ind[i]];
106 if( i>0 ) if( X[i-1]>= X[i] ) {
107 printf("CSpline::SetNewTab_Erreur: X[%d]>=X[%d] (%g>=%g)\n"
108 ,i-1,i,X[i-1],X[i]);
109 throw ParmError(PExcLongMessage(""));
110 }
111 }
112} else { X = x; Y = y; }
113
114}
115
116//////////////////////////////////////////////////////////////////////////////
117//! destruction des divers tableaux en tenant compte des allocations/connections
118void CSpline::DelTab()
119{
120if( X != NULL && XY_Created ) delete [] X; X = NULL;
121if( Y != NULL && XY_Created ) delete [] Y; Y = NULL;
122if( Y2 != NULL ) delete [] Y2; Y2 = NULL;
123if( tmp != NULL ) delete [] tmp; tmp = NULL;
124}
125
126//////////////////////////////////////////////////////////////////////////////
127/*!
128 Pour changer les valeurs des derivees 1ere au 1er et dernier points
129 Valeurs imposees des derivees 1ere au points "X[0]" et "X[Nel-1]".
130*/
131void CSpline::SetBound1er(double yp1,double ypn)
132{
133if( yp1 == YP1 && ypn == YPn ) return;
134
135YP1 = yp1;
136YPn = ypn;
137
138corrupt_Y2 = true;
139}
140
141//! Pour calculer les tableaux de coeff permettant le calcul des interpolations spline.
142void CSpline::ComputeCSpline()
143{
144// on ne fait rien si les tableaux ne sont pas connectes
145if( X == NULL || Y == NULL ) {
146 printf("CSpline::ComputeCSpline()_Erreur: tableaux non connectes X=%p Y=%p\n"
147 ,X,Y);
148 return;
149}
150// On ne fait rien si rien n'a change!
151if( ! corrupt_Y2 ) return;
152// protection si tmp a ete desalloue pour gain de place (ex: CSpline2)
153if( tmp == NULL ) tmp = new double[Nel];
154
155double p,qn,sig,un;
156
157if (Natural & Natural1)
158 Y2[0] = tmp[0] = 0.0;
159else {
160 Y2[0] = -0.5;
161 tmp[0] = (3.0/(X[1]-X[0]))*((Y[1]-Y[0])/(X[1]-X[0])-YP1);
162}
163
164for (int i=1;i<Nel-1;i++) {
165 sig = (X[i]-X[i-1])/(X[i+1]-X[i-1]);
166 p = sig * Y2[i-1] + 2.0;
167 Y2[i] = (sig-1.0)/p;
168 tmp[i]= (Y[i+1]-Y[i])/(X[i+1]-X[i]) - (Y[i]-Y[i-1])/(X[i]-X[i-1]);
169 tmp[i]= (6.0*tmp[i]/(X[i+1]-X[i-1])-sig*tmp[i-1])/p;
170}
171
172if (Natural & NaturalN)
173 qn = un = 0.0;
174else {
175 qn = 0.5;
176 un = (3.0/(X[Nel-1]-X[Nel-2]))
177 *(YPn-(Y[Nel-1]-Y[Nel-2])/(X[Nel-1]-X[Nel-2]));
178}
179Y2[Nel-1] = (un-qn*tmp[Nel-2])/(qn*Y2[Nel-2]+1.0);
180for (int k=Nel-2;k>=0;k--) Y2[k] = Y2[k]*Y2[k+1] + tmp[k];
181
182corrupt_Y2 = false;
183}
184
185//! Interpolation spline en \b x
186double CSpline::CSplineInt(double x)
187{
188int klo,khi,k;
189double h,b,a,y = 0.;
190
191if( corrupt_Y2 ) {
192 cout<<"CSpline::CSplineInt: calcul des coef du spline corrupted"<<endl;
193 throw ParmError(PExcLongMessage(""));
194}
195
196klo = 0;
197khi = Nel-1;
198while (khi-klo > 1) {
199 k = (khi+klo) >> 1;
200 if (X[k] > x) khi=k;
201 else klo=k;
202}
203h=X[khi]-X[klo];
204
205if (h == 0.0) {
206 cout<<"CSpline::CSplineInt: pout khi="<<khi<<" klo="<<klo
207 <<" memes valeurs de X[]: "<<X[khi]<<endl;
208 throw ParmError(PExcLongMessage(""));
209}
210
211a = (X[khi]-x)/h;
212b = (x-X[klo])/h;
213y = a*Y[klo]+b*Y[khi]+((a*a*a-a)*Y2[klo]+(b*b*b-b)*Y2[khi])*(h*h)/6.0;
214
215return y;
216}
217
218
219//////////////////////////////////////////////////////////////////////////////
220//////////////////////////////////////////////////////////////////////////////
221
222/*!
223 \class SOPHYA::CSpline2
224 \ingroup NTools
225 Spline smoother (interpolator) for 2-D data points (y = f(x1,x2))
226 \sa CSpline
227*/
228
229/*!
230 Contructeur - Meme commentaire que pour CSpline avec:
231 \verbatim
232 x1[n1]: liste des coordonnees selon l axe 1
233 x2[n2]: liste des coordonnees selon l axe 2
234 y[n1*n2]: liste des valeurs avec le rangement suivant
235 x1[0]......x1[n1-1] x1[0]......x1[n1-1] ... x1[0]......x1[n1-1]
236 | 0<=i<n1 | | 0<=i<n1 | ... | 0<=i<n1 |
237 | j=0 X2[0] j=1 X2[1] j=n2-1 X2[n2-1]
238 \endverbatim
239*/
240CSpline2::CSpline2(int n1,double* x1,int n2,double* x2,double* y
241 ,int natural,bool order)
242 : Nel1(0), Nel2(0), corrupt_Y2(true), XY_Created(false), Natural(natural)
243 , X1(NULL), X2(NULL), Y(NULL), Y2(NULL)
244 , Nel_S(0), S(NULL), Sint(NULL), tmp(NULL)
245{
246SetNewTab(n1,x1,n2,x2,y,order,true);
247if( x1 != NULL && x2 != NULL && y != NULL) ComputeCSpline();
248
249}
250
251//! Createur par defaut.
252CSpline2::CSpline2(int natural)
253 : Nel1(0), Nel2(0), corrupt_Y2(true), XY_Created(false), Natural(natural)
254 , X1(NULL), X2(NULL), Y(NULL), Y2(NULL)
255 , Nel_S(0), S(NULL), Sint(NULL), tmp(NULL)
256{
257}
258
259//////////////////////////////////////////////////////////////////////////////
260CSpline2::~CSpline2()
261{
262DelTab();
263}
264
265//////////////////////////////////////////////////////////////////////////////
266//! Voir commentaire meme methode de CSpline
267void CSpline2::SetNewTab(int n1,double* x1,int n2,double* x2,double* y
268 ,bool order,bool force)
269{
270ASSERT( n1>3 && n2>3 );
271
272int n = ( n1 < n2 ) ? n2 : n1;
273
274// allocation des buffers Y2 et tmp et des CSpline 1D
275if( n1>Nel1 || n2>Nel2 || force ) {
276 if( Y2 != NULL ) delete [] Y2;
277 if( tmp != NULL ) delete [] tmp;
278 Y2 = new double[n1*n2];
279 tmp = new double[n];
280
281 // et les CSpline[n1] pour memoriser les interpolations sur x1(0->n1)
282 if( S != NULL ) {
283 for(int i=0;i<Nel_S;i++) if(S[i] != NULL) { delete S[i]; S[i]=NULL;}
284 delete S; S = NULL;
285 }
286 S = new CSpline * [n2];
287 for(int j=0;j<n2;j++) {
288 S[j] = new CSpline(n1,NULL,NULL,0.,0.,Natural);
289 S[j]->Free_Tmp();
290 }
291 Nel_S = n2;
292
293 if( S != NULL ) { delete Sint; Sint = NULL;}
294 Sint = new CSpline(n2,NULL,NULL,0.,0.,Natural);
295
296}
297// des-allocation eventuelle de X1,X2,Y
298if( XY_Created ) {
299 if( !order || n1>Nel1 || n2>Nel2 || force ) {
300 if( X1 != NULL ) delete [] X1; X1 = NULL;
301 if( X2 != NULL ) delete [] X2; X2 = NULL;
302 if( Y != NULL ) delete [] Y; Y = NULL;
303 XY_Created = false;
304 }
305}
306// allocation eventuelle de X1,X2,Y
307if( order ) {
308 if( !XY_Created || n1>Nel1 || n2>Nel1 || force ) {
309 X1 = new double[n1];
310 X2 = new double[n2];
311 Y = new double[n1*n2];
312 XY_Created = true;
313 }
314}
315Nel1 = n1; Nel2 = n2;
316corrupt_Y2 = true;
317
318if( x1==NULL || x2==NULL || y==NULL ) return;
319
320// Classement eventuel par ordre des x1 et x2 croissants
321if( order ) {
322
323 if( tmp == NULL ) tmp = new double[n];
324 ind = (int_4 *) tmp;
325 double* Ytmp = new double[n1*n2];
326
327 // tri par valeur croissantes de x1
328 tri_double(x1,ind,(int_4) Nel1);
329 for(int i=0;i<Nel1;i++) {
330 X1[i] = x1[ind[i]];
331 if( i>0 ) if( X1[i-1] >= X1[i] )
332 { printf("CSpline::SetNewTab_Erreur: X1[%d]>=X1[%d] (%g>=%g)\n"
333 ,i-1,i,X1[i-1],X1[i]);
334 throw ParmError(PExcLongMessage("")); }
335 for(int j=0;j<Nel2;j++) Ytmp[j*Nel1+i] = y[j*Nel1+ind[i]];
336 }
337
338 // tri par valeur croissantes de x2
339 tri_double(x2,ind,(int_4) Nel2);
340 for(int j=0;j<Nel2;j++) {
341 X2[j] = x2[ind[j]];
342 if( j>0 ) if( X2[j-1] >= X2[j] )
343 { printf("CSpline::SetNewTab_Erreur: X2[%d]>=X2[%d] (%g>=%g)\n"
344 ,j-1,j,X2[j-1],X2[j]);
345 throw ParmError(PExcLongMessage("")); }
346 for(int i=0;i<Nel1;i++) Y[j*Nel1+i] = Ytmp[j*Nel1+ind[i]];
347 }
348 delete [] Ytmp;
349
350} else {
351
352 X1 = x1;
353 X2 = x2;
354 Y = y;
355
356}
357
358}
359
360//////////////////////////////////////////////////////////////////////////////
361void CSpline2::DelTab()
362{
363if( X1 != NULL && XY_Created ) delete [] X1; X1 = NULL;
364if( X2 != NULL && XY_Created ) delete [] X2; X2 = NULL;
365if( Y != NULL && XY_Created ) delete [] Y; Y = NULL;
366if( Y2 != NULL ) delete [] Y2; Y2 = NULL;
367if( tmp != NULL ) delete [] tmp; tmp = NULL;
368if( S != NULL ) {
369 for(int i=0;i<Nel_S;i++) if(S[i] != NULL) { delete S[i]; S[i]=NULL;}
370 delete S; S = NULL;
371}
372if( Sint != NULL ) { delete Sint; Sint=NULL;}
373}
374
375//////////////////////////////////////////////////////////////////////////////
376//! Voir commentaire meme methode de CSpline
377void CSpline2::ComputeCSpline()
378{
379// on ne fait rien si X1 ou X2 ou Y non connectes
380if( X1 == NULL || X2 == NULL || Y == NULL ) return;
381// On ne fait rien si rien n'a change
382if( ! corrupt_Y2 ) return;
383
384for(int j=0; j<Nel2; j++) {
385 // on n'alloue pas de place nouvelle, on utilise CSpline2::tmp
386 S[j]->tmp = tmp;
387 // connection de X1,Y au spline 1D sans ordre demande
388 S[j]->SetNewTab(Nel1,X1,&Y[j*Nel1],false,false);
389 // calcul des coeff splien pour l'interpolation future
390 S[j]->ComputeCSpline();
391}
392
393corrupt_Y2 = false;
394}
395
396//////////////////////////////////////////////////////////////////////////////
397//! Calcule la valeur interpole (spline) pour le point \b (x1,x2)
398double CSpline2::CSplineInt(double x1,double x2)
399{
400// calcul de la valeur Y pour x=x1 et remplissage du tampon tmp
401for(int j=0;j<Nel2;j++) tmp[j] = S[j]->CSplineInt(x1);
402
403// connection X2,tmp pour interpolation selon x=x2
404Sint->SetNewTab(Nel2,X2,tmp,false,false);
405// calcul des coeff pour interpolation selon X2
406Sint->ComputeCSpline();
407// Interpolation finale
408return Sint->CSplineInt(x2);
409}
410
Note: See TracBrowser for help on using the repository browser.