00001
00002
00003
00004
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
00034
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
00046 case 0:
00047 FILE >> h;
00048 break;
00049
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
00067 if(editAttributes->additionalInformation != 0)
00068 return;
00069
00070
00071 GLUI * aw= editAttributes->attributeWindow;
00072 editAttributes->additionalInformation = (void *)(new float);
00073
00074
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
00080 loadAttributes();
00081
00082
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
00123 objnumber = objects->size();
00124 if(objnumber==0)
00125 return t;
00126
00127 m = new double[objnumber] -1;
00128 radius = new double[objnumber] -1;
00129
00130 n = 6*objnumber;
00131
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
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
00154 double t_ = 0;
00155
00156
00157 while(t_ < time) {
00158
00159
00160 derivs(t_,y,dydx);
00161
00162
00163
00164
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
00176 for (int i=1; i <= n; i++) {
00177 y[i] = yout[i];
00178 }
00179 }
00180
00181 t += t_;
00182
00183 i=1;
00184 j=objnumber*3+1;
00185
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
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
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
00235
00236 for(int j=1; j <= objnumber;j++) {
00237 if (j==i)
00238 continue;
00239
00240 sum+=(x[(j-1)*3+komponent]-x[(i-1)*3+komponent])*m[j]
00241 / cubic(distance(i,j,x));
00242 }
00243
00244 return sum*GAMMA;
00245 }
00246
00253 void RungeKutta::derivs(double a, double b[], double dbda[]) {
00254
00255 for(int i=1; i <= n/2; i++) {
00256 dbda[i]= b[i+n/2];
00257 }
00258
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
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
00309
00310
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
00318 if(h > 1e-10)
00319 return rk4(y, dydx, n, x, h/2, yout);
00320 }
00321 }
00322 }
00323
00324
00325
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
00334
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
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 }