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

Last change on this file since 2631 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

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