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

RungeKutta.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 "RungeKutta.h"
00012 
00013 #include "Message.h"
00014 
00019 void RungeKutta::save(ostream & FILE) {
00020     FILE << "!!BEGININTEGRATOR!!" << endl;
00021     FILE << "0 stepsize: " <<  h << endl;
00022     FILE << "1000 !!END INTEGRATOR!!"<< endl;
00023 }
00024 
00029 void RungeKutta::load(istream & FILE) {
00030     int option_=0;
00031     string s;
00032 
00033     // lese solange in der Datei bis Daten des Integrators kommen
00034     // (integrator mark)
00035     while (! FILE.fail() ) {
00036         FILE >> s;
00037         if(s == "!!BEGININTEGRATOR!!")
00038             break;
00039     }
00040     if(s != "!!BEGININTEGRATOR!!")
00041         cerr << "WARNING INTEGRATOR MARK NOT FOUND!" << endl;
00042     while (! FILE.fail() ) {
00043         FILE >> option_ >> s;
00044         switch(option_) {
00045             // lade Schrittweite
00046         case 0:
00047             FILE >> h;
00048             break;
00049             // hiernach kommen keine Einstellungen mehr
00050         case 1000:
00051             return;
00052             break;
00053         default:
00054             cerr << "WARNING read unknown option " << option_ << " "
00055             << s << endl;
00056         }
00057     }
00058 }
00059 
00063 void RungeKutta::createAttributeWindow() {
00064     createBasisAttributeWindow();
00065 
00066     // tue nichts, wenn AttributeWindow fuer diesen Integrator bereits existiert
00067     if(editAttributes->additionalInformation != 0)
00068         return;
00069 
00070     // allokiere Speicher fuer additionalInformation (Schrittweite)
00071     GLUI * aw= editAttributes->attributeWindow;
00072     editAttributes->additionalInformation = (void *)(new float);
00073 
00074     // Spinner um Schrittweite einzustellen
00075     GLUI_Rollout * pO = aw->add_rollout("RungeKutta Options",true);
00076     aw->add_spinner_to_panel(pO,"Stepwidth", GLUI_SPINNER_DOUBLE,
00077                              (double*)(editAttributes->additionalInformation));
00078 
00079     // lade aktuelle Genauigkeit
00080     loadAttributes();
00081 
00082     // aktualisiere Spinner
00083     aw->sync_live();
00084 }
00085 
00089 void RungeKutta::loadAttributes() {
00090     *((double *)editAttributes->additionalInformation) = h;
00091 }
00092 
00096 void RungeKutta::saveAttributes() {
00097     h = *((double *)(editAttributes->additionalInformation));
00098 }
00099 
00104 void RungeKutta::deleteAdditionalInformation(void * additionalInformation) {
00105     delete((double *)(additionalInformation));
00106 }
00107 
00112 RungeKutta::RungeKutta():t(0),h(0.1),n(0),objnumber(0) {}
00113 
00120 double RungeKutta::integrate(double time) {
00121 
00122     // bestimme Objektanzahl
00123     objnumber = objects->size();
00124     if(objnumber==0)
00125         return t;
00126     // allokiere Speicher fuer Massen und Radien
00127     m = new double[objnumber] -1;
00128     radius = new double[objnumber] -1;
00129     // berechne Anzahl der DGLn
00130     n = 6*objnumber;
00131     // allokiere Speicher fuer DGLn
00132     double *y = new double[n] - 1;
00133     double *dydx = new double[n] -1;
00134     double *yout = new double[n] -1;
00135 
00136     int k=1, i=1, j=objnumber*3+1;
00137     // hole alte Radien, Massen, Positionen und Geschwindigkeiten
00138     for (objectList::iterator g=objects->begin() ; g != objects->end();g ++) {
00139         Object & obj = **g;
00140         m[k]=obj.mass;
00141         radius[k]=obj.radius;
00142         y[i]=obj.pos.x;
00143         y[i+1]=obj.pos.y;
00144         y[i+2]=obj.pos.z;
00145         y[j]=obj.v.x;
00146         y[j+1]=obj.v.y;
00147         y[j+2]=obj.v.z;
00148         k+=1;
00149         i+=3;
00150         j+=3;
00151     }
00152 
00153     // bisher berechnete Zeitspanne
00154     double t_ = 0;
00155 
00156     // solange integrieren, bis Zeitpunkt time erreicht ist
00157     while(t_ < time) {
00158 
00159         // berechne zum ersten Mal die Ableitungen dydx
00160         derivs(t_,y,dydx);
00161 
00162         // starte Integrator, wenn Kollision stattfindet, while-Schleife
00163         // abbrechen; falls Schritteweite h über time hinausfuehren wuerde, nur
00164         // mit h=time-t_ integrieren
00165         if(t_+h <= time) {
00166             t_ += rk4(y,dydx,n,t_,h,yout);
00167             if(!collisions.empty())
00168                 break;
00169         } else {
00170             t_ += rk4(y,dydx,n,t_,time-t_,yout);
00171             if(!collisions.empty())
00172                 break;
00173         }
00174 
00175         // kopierere die Ergebnisse
00176         for (int i=1; i <= n; i++) {
00177             y[i] = yout[i];
00178         }
00179     }
00180     // aktualisiere t fuer return
00181     t += t_;
00182 
00183     i=1;
00184     j=objnumber*3+1;
00185     // kopiere neue Daten in die Objektliste
00186     for (objectList::iterator g=objects->begin() ; g != objects->end();g ++) {
00187         Object & obj = **g;
00188         obj.pos.x=y[i];
00189         obj.pos.y=y[i+1];
00190         obj.pos.z=y[i+2];
00191         obj.v.x=y[j];
00192         obj.v.y=y[j+1];
00193         obj.v.z=y[j+2];
00194         i+=3;
00195         j+=3;
00196     }
00197 
00198     // gebe integrierte Zeitspanne zurueck
00199     return t;
00200 }
00201 
00205 list<Collisionspair>* RungeKutta::getCollisionslist() {
00206     return &collisions;
00207 }
00208 
00215 double RungeKutta::distance(const int i, const int j, const double x[]) {
00216     if(i==j)
00217         return 0;
00218     double sum=0;
00219     // berechne euklidischen Abstand
00220     for(int d=1; d<=3; d++) {
00221         sum += sqr(x[(i-1)*3+d]-x[(j-1)*3+d]);
00222     }
00223     return sqrt(sum);
00224 }
00225 
00232 double RungeKutta::acceleration(const int i, const int komponent, const double x[] ) {
00233     double sum=0;
00234     // iteriere ueber alle anderen Objekte und bereche einzeln den gravitativen
00235     // Einfluss
00236     for(int j=1; j <= objnumber;j++) {
00237         if (j==i)
00238             continue;
00239         // Formel fuer Gravitationskraft
00240         sum+=(x[(j-1)*3+komponent]-x[(i-1)*3+komponent])*m[j]
00241              / cubic(distance(i,j,x));
00242     }
00243     // Gravitationskonstante Gamma nicht vergessen
00244     return sum*GAMMA;
00245 }
00246 
00253 void RungeKutta::derivs(double a, double b[], double dbda[]) {
00254     //X'(t) = V(t-1)
00255     for(int i=1; i <= n/2; i++) {
00256         dbda[i]= b[i+n/2];
00257     }
00258     //V'(T) = A(t-1)
00259     for(int i=n/2+1; i <= n; i++) {
00260         dbda[i] = acceleration((i-n/2+2)/3 ,(((i-n/2+2))%3)+1, b) ;
00261     }
00262 }
00263 
00270 double RungeKutta::rk4(double y[], double dydx[], int n, double x, double h, double yout[]) {
00271     int i;
00272     double xh,hh,h6,*dym,*dyt,*yt;
00273 
00274     dym=vec(1,n);
00275     dyt=vec(1,n);
00276     yt=vec(1,n);
00277     hh=h*0.5;
00278     h6=h/6.0;
00279     xh=x+hh;
00280 
00281     for (i=1;i<=n;i++)
00282         yt[i]=y[i]+hh*dydx[i];
00283     derivs(xh,yt,dyt);
00284     for (i=1;i<=n;i++)
00285         yt[i]=y[i]+hh*dyt[i];
00286     derivs(xh,yt,dym);
00287     for (i=1;i<=n;i++) {
00288         yt[i]=y[i]+h*dym[i];
00289         dym[i] += dyt[i];
00290     }
00291     derivs(x+h,yt,dyt);
00292     for (i=1;i<=n;i++)
00293         yout[i]=y[i]+h6*(dydx[i]+dyt[i]+2.0*dym[i]);
00294 
00295     // Überprüfe ob Schritteweite verringert werden muß
00296     for (int i=1; i <= objnumber; i++) {
00297         for (int j=1;  j <= objnumber; j++) {
00298             if(i==j)
00299                 continue;
00300             Vector newposi(yout[3*(i-1)+1], yout[3*(i-1)+2], yout[3*(i-1)+3]);
00301             Vector oldposi(y[3*(i-1)+1], y[3*(i-1)+2], y[3*(i-1)+3]);
00302             Vector newposj(yout[3*(j-1)+1], yout[3*(j-1)+2], yout[3*(j-1)+3]);
00303             Vector oldposj(y[3*(j-1)+1], y[3*(j-1)+2], y[3*(j-1)+3]);
00304             double dist = (oldposi - oldposj).length();
00305             double potdistred = (newposi - oldposi).length() +
00306                                 (newposj - oldposj).length();
00307 
00308             // Ueberpruefe, ob Objekte mit aktueller Schrittweite aneinander
00309             // vorbei fliegen koennten, so dass Kollision nicht unbedingt
00310             // entscheidbar ist
00311             if (dist <= potdistred) {
00312                 free_vec(yt,1,n);
00313                 free_vec(dyt,1,n);
00314                 free_vec(dym,1,n);
00315                 Message::msg(Message::MSG,
00316                              "Collision possible: reducing stepsize");
00317                 // halbiere Schrittweite, wenn sie nicht schon zu klein ist
00318                 if(h > 1e-10)
00319                     return rk4(y, dydx, n, x, h/2, yout);
00320             }
00321         }
00322     }
00323 
00324     // ueberpruefe ob Ueberlappungen von Objekten (Kollisionsen) stattgefunden
00325     // haben
00326     for (int i=1; i <= objnumber; i++) {
00327         for (int j=i;  j <= objnumber; j++) {
00328             if(i==j)
00329                 continue;
00330             Vector newposi(yout[3*(i-1)+1], yout[3*(i-1)+2], yout[3*(i-1)+3]);
00331             Vector newposj(yout[3*(j-1)+1], yout[3*(j-1)+2], yout[3*(j-1)+3]);
00332             if ((newposi - newposj).length() <= radius[i]+radius[j]) {
00333                 // falls Ueberlappungen stattgefunden haben, speichere diese in
00334                 // Kollisionsliste
00335                 collisions.push_back(Collisionspair(i,j));
00336             }
00337         }
00338     }
00339 
00340     free_vec(yt,1,n);
00341     free_vec(dyt,1,n);
00342     free_vec(dym,1,n);
00343 
00344     // gebe durchgefuehrte Schrittweite zurueck
00345     return h;
00346 }
00347 
00354 void RungeKutta::free_vec(double *v, long nl, long nh) {
00355     free((FREE_ARG) (v+nl-NR_END));
00356 }
00357 
00363 double *RungeKutta::vec(long nl, long nh) {
00364     double *v;
00365 
00366     v=(double *)malloc((size_t) ((nh-nl+1+NR_END)*sizeof(double)));
00367     if (!v)
00368         throw Error("allocation failure in vec()");
00369     return v-nl+NR_END;
00370 }

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