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

Last change on this file since 424 was 244, checked in by ansari, 26 years ago

beaucoup modifs rz+cmv 22/4/99

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