00001
00002
00003
00004
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
00032
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
00044 case 0:
00045 FILE >> eps;
00046 break;
00047
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
00065 if(editAttributes->additionalInformation != 0)
00066 return;
00067
00068
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
00075 aw->add_spinner_to_panel(pO,"eps", GLUI_SPINNER_DOUBLE,
00076 (double*)(editAttributes->additionalInformation));
00077
00078
00079 loadAttributes();
00080
00081
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
00116 eps=1e-8;
00117 }
00118
00125 double RungeKuttaAdaptive::integrate(double time) {
00126
00127
00128 objnumber = objects->size();
00129 if(objnumber==0)
00130 return t;
00131
00132
00133 m = new double[objnumber] -1;
00134 radius = new double[objnumber] -1;
00135
00136
00137 n = 6*objnumber;
00138
00139
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
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
00161 double stepsize = time;
00162 nextsteplength = 0;
00163
00164
00165 double t_ = 0;
00166
00167
00168 while(t_ < time ) {
00169
00170
00171 derivs(t,y,dydx);
00172
00173
00174
00175 if(rkqs(y,dydx,n,& t_, stepsize,eps,y,& actualsteplength,
00176 & nextsteplength))
00177 break;
00178
00179
00180 stepsize = time-t_;
00181 }
00182
00183
00184 t += t_;
00185
00186 i=1;
00187 j=objnumber*3+1;
00188
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
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
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
00238
00239 for(int j=1; j <= objnumber;j++) {
00240 if (j==i)
00241 continue;
00242
00243 sum+=(x[(j-1)*3+komponente]-x[(i-1)*3+komponente])*m[j] /
00244 cubic(distance(i,j,x));
00245 }
00246
00247 return sum*GAMMA;
00248 }
00249
00256 void RungeKuttaAdaptive::derivs(double a, double b[], double dbda[]) {
00257
00258 for(int i=1; i <= n/2; i++) {
00259 dbda[i]= b[i+n/2];
00260 }
00261
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
00350 if(xnew == *x)
00351 throw Error("stepsize underflow in rungekuttaadaptive (type 1)");
00352
00353
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
00366
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
00375
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
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 }