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

Last change on this file since 2526 was 2506, checked in by ansari, 22 years ago

Remplacement THROW par throw - Reza 15/03/2004

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