Hauptseite | Liste aller Namensbereiche | Klassenhierarchie | Alphabetische Liste | Datenstrukturen | Auflistung der Dateien | Datenstruktur-Elemente | Datei-Elemente

RungeKuttaAdaptive.cpp

gehe zur Dokumentation dieser Datei
00001 /*
00002 Autor: $Author: kunkel $ State: $State: Exp $
00003 Datum: $Date: 2005/05/30 12:35:25 $
00004 Version: $Revision: 1.1 $
00005 */
00006 
00011 #include "RungeKuttaAdaptive.h"
00012 
00017 void RungeKuttaAdaptive::save(ostream & FILE) {
00018     FILE << "!!BEGININTEGRATOR!!" << endl;
00019     FILE << "0 eps: " <<  eps << endl;
00020     FILE << "1000 !!END INTEGRATOR!!"<< endl;
00021 }
00022 
00027 void RungeKuttaAdaptive::load(istream & FILE) {
00028     int option_=0;
00029     string s;
00030 
00031     // lese solange in der Datei bis Daten des Integrators kommen
00032     // (integrator mark)
00033     while (! FILE.fail() ) {
00034         FILE >> s;
00035         if(s == "!!BEGININTEGRATOR!!")
00036             break;
00037     }
00038     if(s != "!!BEGININTEGRATOR!!")
00039         cerr << "WARNING INTEGRATOR MARK NOT FOUND!" << endl;
00040     while (! FILE.fail() ) {
00041         FILE >> option_ >> s;
00042         switch(option_) {
00043             // lade Genauigkeitseinstellung
00044         case 0:
00045             FILE >> eps;
00046             break;
00047             // hiernach kommen keine Einstellungen mehr
00048         case 1000:
00049             return;
00050             break;
00051         default:
00052             cerr << "WARNING read unknown option " << option_ << " "
00053             << s << endl;
00054         }
00055     }
00056 }
00057 
00061 void RungeKuttaAdaptive::createAttributeWindow() {
00062     createBasisAttributeWindow();
00063 
00064     // tue nichts, wenn AttributeWindow fuer diesen Integrator bereits existiert
00065     if(editAttributes->additionalInformation != 0)
00066         return;
00067 
00068     // allokiere Speicher fuer additionalInformation (Schrittweite)
00069     GLUI * aw= editAttributes->attributeWindow;
00070     editAttributes->additionalInformation = (void *)(new double);
00071 
00072     GLUI_Rollout * pO = aw->add_rollout("RungeKutta Adaptive Options",true);
00073 
00074     // Spinner um Genauigkeit (eps) einzustellen
00075     aw->add_spinner_to_panel(pO,"eps", GLUI_SPINNER_DOUBLE,
00076                              (double*)(editAttributes->additionalInformation));
00077 
00078     // lade aktuelle Genauigkeit
00079     loadAttributes();
00080 
00081     // aktualisiere Spinner
00082     aw->sync_live();
00083 }
00084 
00088 void RungeKuttaAdaptive::loadAttributes() {
00089     *((double *)editAttributes->additionalInformation) =  eps;
00090 }
00091 
00095 void RungeKuttaAdaptive::saveAttributes() {
00096     eps = *((double *)(editAttributes->additionalInformation));
00097 }
00098 
00103 void RungeKuttaAdaptive::deleteAdditionalInformation(void * additionalInformation) {
00104     delete((double *)(additionalInformation));
00105 }
00106 
00110 RungeKuttaAdaptive::RungeKuttaAdaptive() {
00111     n=0;
00112     t = 0;
00113     objnumber = 0;
00114 
00115     // empfohlene Genauigkeit
00116     eps=1e-8;
00117 }
00118 
00125 double RungeKuttaAdaptive::integrate(double time) {
00126 
00127     // bestimme Objektanzahl
00128     objnumber = objects->size();
00129     if(objnumber==0)
00130         return t;
00131 
00132     // allokiere Speicher fuer Massen und Radien
00133     m = new double[objnumber] -1;
00134     radius = new double[objnumber] -1;
00135 
00136     // berechne Anzahl der DGLn
00137     n = 6*objnumber;
00138 
00139     // allokiere Speicher fuer DGLn
00140     double *y = new double[n] - 1;
00141     double *dydx = new double[n] -1;
00142 
00143     int k=1, i=1, j=objnumber*3+1;
00144     // hole alte Radien, Massen, Positionen und Geschwindigkeiten
00145     for (objectList::iterator g=objects->begin() ; g != objects->end();g ++) {
00146         Object & obj = **g;
00147         m[k]=obj.mass;
00148         radius[k]=obj.radius;
00149         y[i]=obj.pos.x;
00150         y[i+1]=obj.pos.y;
00151         y[i+2]=obj.pos.z;
00152         y[j]=obj.v.x;
00153         y[j+1]=obj.v.y;
00154         y[j+2]=obj.v.z;
00155         k+=1;
00156         i+=3;
00157         j+=3;
00158     }
00159 
00160     // max. Schrittlaenge
00161     double stepsize = time;
00162     nextsteplength = 0;
00163 
00164     // bisher berechnete Zeitspanne
00165     double t_ = 0;
00166 
00167     // solange integrieren, bis Zeitpunkt time erreicht ist
00168     while(t_ < time ) {
00169 
00170         // berechne zum ersten Mal die Ableitungen dydx
00171         derivs(t,y,dydx);
00172 
00173         // starte Integrator, wenn Kollision stattfindet, while-Schleife
00174         // abbrechen
00175         if(rkqs(y,dydx,n,& t_, stepsize,eps,y,& actualsteplength,
00176                 & nextsteplength))
00177             break;
00178 
00179         // max Schrittlaenge verringern
00180         stepsize = time-t_;
00181     }
00182 
00183     // aktualisiere t fuer return
00184     t += t_;
00185 
00186     i=1;
00187     j=objnumber*3+1;
00188     // kopiere neue Daten in die Objektliste
00189     for (objectList::iterator g=objects->begin() ; g != objects->end();g ++) {
00190         Object & obj = **g;
00191         obj.pos.x=y[i];
00192         obj.pos.y=y[i+1];
00193         obj.pos.z=y[i+2];
00194         obj.v.x=y[j];
00195         obj.v.y=y[j+1];
00196         obj.v.z=y[j+2];
00197         i+=3;
00198         j+=3;
00199     }
00200 
00201     // gebe integrierte Zeitspanne zurueck
00202     return t;
00203 }
00204 
00208 list<Collisionspair>* RungeKuttaAdaptive::getCollisionslist() {
00209     return &collisions;
00210 }
00211 
00218 double RungeKuttaAdaptive::distance(const int i, const int j, const double x[]) {
00219     if(i==j)
00220         return 0;
00221     double sum=0;
00222     // berechne euklidischen Abstand
00223     for(int d=1; d<=3; d++) {
00224         sum += sqr(x[(i-1)*3+d]-x[(j-1)*3+d]);
00225     }
00226     return sqrt(sum);
00227 }
00228 
00235 double RungeKuttaAdaptive::acceleration(const int i, const int komponente, const double x[] ) {
00236     double sum=0;
00237     // iteriere ueber alle anderen Objekte und bereche einzeln den gravitativen
00238     // Einfluss
00239     for(int j=1; j <= objnumber;j++) {
00240         if (j==i)
00241             continue;
00242         // Formel fuer Gravitationskraft
00243         sum+=(x[(j-1)*3+komponente]-x[(i-1)*3+komponente])*m[j] /
00244              cubic(distance(i,j,x));
00245     }
00246     // Gravitationskonstante Gamma nicht vergessen
00247     return sum*GAMMA;
00248 }
00249 
00256 void RungeKuttaAdaptive::derivs(double a, double b[], double dbda[]) {
00257     //X'(t) = V(t-1)
00258     for(int i=1; i <= n/2; i++) {
00259         dbda[i]= b[i+n/2];
00260     }
00261     //V'(T) = A(t-1)
00262     for(int i=n/2+1; i <= n; i++) {
00263         dbda[i] = acceleration((i-n/2+2)/3 ,(((i-n/2+2))%3)+1, b);
00264     }
00265 }
00266 
00267 
00272 void RungeKuttaAdaptive::rkck(double y[], double dydx[], int n, double x, double h, double yout[], double yerr[]) {
00273     int i;
00274     static double a2=0.2,a3=0.3,a4=0.6,a5=1.0,a6=0.875,b21=0.2,
00275                                           b31=3.0/40.0,b32=9.0/40.0,b41=0.3,b42 = -0.9,b43=1.2,
00276                                                                                   b51 = -11.0/54.0, b52=2.5,b53 = -70.0/27.0,b54=35.0/27.0,
00277                                                                                                                   b61=1631.0/55296.0,b62=175.0/512.0,b63=575.0/13824.0,
00278                                                                                                                                                          b64=44275.0/110592.0,b65=253.0/4096.0,c1=37.0/378.0,
00279                                                                                                                                                                                   c3=250.0/621.0,c4=125.0/594.0,c6=512.0/1771.0,
00280                                                                                                                                                                                                                    dc5 = -277.00/14336.0;
00281 
00282     double dc1=c1-2825.0/27648.0,dc3=c3-18575.0/48384.0,
00283                                      dc4=c4-13525.0/55296.0,dc6=c6-0.25;
00284     double *ak2,*ak3,*ak4,*ak5,*ak6,*ytemp;
00285 
00286     ak2=vec(1,n);
00287     ak3=vec(1,n);
00288     ak4=vec(1,n);
00289     ak5=vec(1,n);
00290     ak6=vec(1,n);
00291     ytemp=vec(1,n);
00292     for (i=1;i<=n;i++)
00293         ytemp[i]=y[i]+b21*h*dydx[i];
00294     derivs(x+a2*h,ytemp,ak2);
00295     for (i=1;i<=n;i++)
00296         ytemp[i]=y[i]+h*(b31*dydx[i]+b32*ak2[i]);
00297     derivs(x+a3*h,ytemp,ak3);
00298     for (i=1;i<=n;i++)
00299         ytemp[i]=y[i]+h*(b41*dydx[i]+b42*ak2[i]+b43*ak3[i]);
00300     derivs(x+a4*h,ytemp,ak4);
00301     for (i=1;i<=n;i++)
00302         ytemp[i]=y[i]+h*(b51*dydx[i]+b52*ak2[i]+b53*ak3[i]+b54*ak4[i]);
00303 
00304     derivs(x+a5*h,ytemp,ak5);
00305     for (i=1;i<=n;i++)
00306         ytemp[i]=y[i]+h*(b61*dydx[i]+b62*ak2[i]+b63*ak3[i]+b64*ak4[i]
00307                          +b65*ak5[i]);
00308     derivs(x+a6*h,ytemp,ak6);
00309     for (i=1;i<=n;i++)
00310         yout[i]=y[i]+h*(c1*dydx[i]+c3*ak3[i]+c4*ak4[i]+c6*ak6[i]);
00311     for (i=1;i<=n;i++)
00312         yerr[i]=h*(dc1*dydx[i]+dc3*ak3[i]+dc4*ak4[i]+dc5*ak5[i]+dc6*ak6[i]);
00313     free_vec(ytemp,1,n);
00314     free_vec(ak6,1,n);
00315     free_vec(ak5,1,n);
00316     free_vec(ak4,1,n);
00317     free_vec(ak3,1,n);
00318     free_vec(ak2,1,n);
00319 }
00320 
00327 bool RungeKuttaAdaptive::rkqs(double y[], double dydx[], int n, double *x, double htry, double eps, double yscal[], double *hdid, double *hnext) {
00328 
00329     int i;
00330     double errmax,h,htemp,xnew,*yerr,*ytemp;
00331 
00332     yerr=vec(1,n);
00333     ytemp=vec(1,n);
00334     h=htry;
00335 
00336     int counter=0;
00337     for (;;) {
00338         rkck(y,dydx,n,*x,h,ytemp,yerr);
00339         errmax=0.0;
00340         for (i=1;i<=n;i++)
00341             errmax=max(errmax,abs(yerr[i]/yscal[i]));
00342         errmax /= eps;
00343         if (errmax <= 1.0)
00344             break;
00345         htemp=SAFETY*h*(double) (pow(errmax,PSHRNK));
00346         h=(h >= 0.0 ? max(htemp,0.1*h) : min(htemp,0.1*h));
00347         xnew=(*x)+h;
00348 
00349         // falls der Integrator nicht von der Stelle kommt -> abbrechen
00350         if(xnew == *x)
00351             throw Error("stepsize underflow in rungekuttaadaptive (type 1)");
00352 
00353         // falls Integrator zu lange braucht -> abbrechen
00354         if(counter > 1000)
00355             throw Error("stepsize underflow in rungekuttaadaptive (type 2)");
00356         counter++;
00357     }
00358     if (errmax > ERRCON)
00359         *hnext=SAFETY*h*(double) pow(errmax,PGROW);
00360     else
00361         *hnext=5.0*h;
00362     *x += (*hdid=h);
00363 
00364 
00365     // ueberpruefe ob Ueberlappungen von Objekten (Kollisionsen) stattgefunden
00366     // haben
00367     for (int i=1; i <= objnumber; i++) {
00368         for (int j=i;  j <= objnumber; j++) {
00369             if(i==j)
00370                 continue;
00371             Vector newposi(ytemp[3*(i-1)+1], ytemp[3*(i-1)+2], ytemp[3*(i-1)+3]);
00372             Vector newposj(ytemp[3*(j-1)+1], ytemp[3*(j-1)+2], ytemp[3*(j-1)+3]);
00373             if ((newposi - newposj).length() <= radius[i]+radius[j]) {
00374                 // falls Ueberlappungen stattgefunden haben, speichere diese in
00375                 // Kollisionsliste
00376                 collisions.push_back(Collisionspair(i,j));
00377             }
00378         }
00379     }
00380 
00381     for (i=1;i<=n;i++)
00382         y[i]=ytemp[i];
00383     free_vec(ytemp,1,n);
00384     free_vec(yerr,1,n);
00385 
00386     // geben false zurueck, wenn keine Kollision stattgefunden hat,sonst true
00387     if(collisions.empty())
00388         return false;
00389     else
00390         return true;
00391 }
00392 
00399 void RungeKuttaAdaptive::free_vec(double *v, long nl, long nh) {
00400     free((FREE_ARG) (v+nl-NR_END));
00401 }
00402 
00408 double *RungeKuttaAdaptive::vec(long nl, long nh) {
00409     double *v;
00410 
00411     v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double)));
00412     if (!v)
00413         throw Error("allocation failure in vec()");
00414     return v-nl+NR_END;
00415 }

Erzeugt am Mon May 30 14:31:15 2005 für Sunsystembuildingandsimulation von doxygen 1.3.6