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

Last change on this file since 4083 was 3205, checked in by ansari, 18 years ago

Suppression flags MWERKS (compilo CodeWarrior pour MacOS8,9) , Reza 10/04/2007

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