void pendelum::rk4() { /*We are using the fourth-order-Runge-Kutta-algorithm We have to calculate the parameters k1, k2, k3, k4 for v and phi, so we use to arrays k1[2] and k2[2] for this k1[0], k2[0] are the parameters for phi, k1[1], k2[1] are the parameters for v */ int i; double t_h; double yout[2],y_h[2]; //k1[2],k2[2],k3[2],k4[2],y_k[2]; t_h=0; y_h[0]=y[0]; //phi y_h[1]=y[1]; //v ofstream fout("rk4.out"); fout.setf(ios::scientific); fout.precision(20); for(i=1; i<=n; i++){ rk4_step(t_h,y_h,yout,delta_t_roof); fout<<i*delta_t<<"\t\t"<<yout[0]<<"\t\t"<<yout[1]<<"\n"; t_h+=delta_t_roof; y_h[0]=yout[0]; y_h[1]=yout[1]; } fout.close; }
static int rk4_apply (void *vstate, size_t dim, double t, double h, double y[], double yerr[], const double dydt_in[], double dydt_out[], const gsl_odeiv_system * sys) { rk4_state_t *state = (rk4_state_t *) vstate; size_t i; double *const k = state->k; double *const k1 = state->k1; double *const y0 = state->y0; double *const y_onestep = state->y_onestep; DBL_MEMCPY (y0, y, dim); if (dydt_in != NULL) { DBL_MEMCPY (k, dydt_in, dim); } else { int s = GSL_ODEIV_FN_EVAL (sys, t, y0, k); if (s != GSL_SUCCESS) { return s; } } /* Error estimation is done by step doubling procedure */ /* Save first point derivatives*/ DBL_MEMCPY (k1, k, dim); /* First traverse h with one step (save to y_onestep) */ DBL_MEMCPY (y_onestep, y, dim); { int s = rk4_step (y_onestep, state, h, t, dim, sys); if (s != GSL_SUCCESS) { return s; } } /* Then with two steps with half step length (save to y) */ DBL_MEMCPY (k, k1, dim); { int s = rk4_step (y, state, h/2.0, t, dim, sys); if (s != GSL_SUCCESS) { /* Restore original values */ DBL_MEMCPY (y, y0, dim); return s; } } /* Update before second step */ { int s = GSL_ODEIV_FN_EVAL (sys, t + h/2.0, y, k); if (s != GSL_SUCCESS) { /* Restore original values */ DBL_MEMCPY (y, y0, dim); return s; } } /* Save original y0 to k1 for possible failures */ DBL_MEMCPY (k1, y0, dim); /* Update y0 for second step */ DBL_MEMCPY (y0, y, dim); { int s = rk4_step (y, state, h/2.0, t + h/2.0, dim, sys); if (s != GSL_SUCCESS) { /* Restore original values */ DBL_MEMCPY (y, k1, dim); return s; } } /* Derivatives at output */ if (dydt_out != NULL) { int s = GSL_ODEIV_FN_EVAL (sys, t + h, y, dydt_out); if (s != GSL_SUCCESS) { /* Restore original values */ DBL_MEMCPY (y, k1, dim); return s; } } /* Error estimation yerr = C * 0.5 * | y(onestep) - y(twosteps) | / (2^order - 1) constant C is approximately 8.0 to ensure 90% of samples lie within the error (assuming a gaussian distribution with prior p(sigma)=1/sigma.) */ for (i = 0; i < dim; i++) { yerr[i] = 4.0 * (y[i] - y_onestep[i]) / 15.0; } return GSL_SUCCESS; }
inline void do_step( const double dt ) { rk4_step( phase_lattice<dim>() , m_x , m_t , dt ); }
void pendelum::asc() { /* We are using the Runge-Kutta-algorithm with adaptive stepsize control according to "Numerical Recipes in C", S. 574 ff. At first we calculate y(x+h) using rk4-method => y1 Then we calculate y(x+h) using two times rk4-method at x+h/2 and x+h => y2 The difference between these values is called "delta" If it is smaller than a given value, we calculate y(x+h) by y2 + (delta)/15 (page 575, Numerical R.) If delta is not smaller than ... we calculate a new stepsize using h_new=(Safety)*h_old*(.../delta)^(0.25) where "Safety" is constant (page 577 N.R.) and start again with calculating y(x+h)... */ int i; double t_h,h_alt,h_neu,hh,errmax; double yout[2],y_h[2],y_m[2],y1[2],y2[2], delta[2], yscal[2]; const double eps=1.0e-6; const double safety=0.9; const double errcon=6.0e-4; const double tiny=1.0e-30; t_h=0; y_h[0]=y[0]; //phi y_h[1]=y[1]; //v h_neu=delta_t_roof; ofstream fout("asc.out"); fout.setf(ios::scientific); fout.precision(20); for(i=0;i<=n;i++){ /* The error is scaled against yscal We use a yscal of the form yscal = fabs(y[i]) + fabs(h*derivatives[i]) (N.R. page 567) */ derivatives(t_h,y_h,yout); yscal[0]=fabs(y[0])+fabs(h_neu*yout[0])+tiny; yscal[1]=fabs(y[1])+fabs(h_neu*yout[1])+tiny; /* the do-while-loop is used until the */ do{ /* Calculating y2 by two half steps */ h_alt=h_neu; hh=h_alt*0.5; rk4_step(t_h, y_h, y_m, hh); rk4_step(t_h+hh,y_m,y2,hh); /* Calculating y1 by one normal step */ rk4_step(t_h,y_h,y1,h_alt); /* Now we have two values for phi and v at the time t_h + h in y2 and y1 We can now calculate the delta for phi and v */ delta[0]=fabs(y1[0]-y2[0]); delta[1]=fabs(y1[1]-y2[1]); errmax=(delta[0]/yscal[0] > delta[1]/yscal[1] ? delta[0]/yscal[0] : delta[1]/yscal[1]); /*We scale delta against the constant yscal Then we take the biggest one and call it errmax */ errmax=(double)errmax/eps; /*We divide errmax by eps and have only */ h_neu=safety*h_alt*exp(-0.25*log(errmax)); }while(errmax>1.0); /*Now we are outside the do-while-loop and have a delta which is small enough So we can calculate the new values of phi and v */ yout[0]=y_h[0]+delta[0]/15.0; yout[1]=y_h[1]+delta[1]/15.0; fout<<(double)(t_h+h_alt)/omega_0<<"\t\t"<<yout[0]<<"\t\t"<<yout[1]<<"\n"; // Calculating of the new stepsize h_neu=(errmax > errcon ? safety*h_alt*exp(-0.20*log(errmax)) : 4.0*h_alt); y_h[0]=yout[0]; y_h[1]=yout[1]; t_h+=h_neu; } }
inline void do_step( const double dt ) { rk4_step( lorenz() , m_x , m_t , dt ); }