avtIVPSolver::Result avtIVPAdamsBashforth::Step(avtIVPField* field, double t_max, avtIVPStep* ivpstep) { const double direction = sign( 1.0, t_max - t ); h = sign( h, direction ); bool last = false; // do not run past integration end if( (t + 1.01*h - t_max) * direction > 0.0 ) { last = true; h = t_max - t; } // stepsize underflow? if( 0.1*std::abs(h) <= std::abs(t)*epsilon ) return avtIVPSolver::STEPSIZE_UNDERFLOW; avtIVPSolver::Result res; avtIVPField::Result fieldResult; avtVector yNew = yCur; // Use a fourth-order Runga Kutta integration to seed the Adams-Bashforth. if( numStep < ADAMS_BASHFORTH_NSTEPS ) { // Save the first vector values in the history. if( numStep == 0 ) { if ((fieldResult = (*field)(t, yCur, history[0])) != avtIVPField::OK) return ConvertResult(fieldResult); } res = RK4Step( field, yNew ); } else res = ABStep( field, yNew ); if (res == OK) { ivpstep->resize(2); if( convertToCartesian ) { (*ivpstep)[0] = field->ConvertToCartesian( yCur ); (*ivpstep)[1] = field->ConvertToCartesian( yNew ); } else { (*ivpstep)[0] = yCur; (*ivpstep)[1] = yNew; } ivpstep->t0 = t; ivpstep->t1 = t + h; numStep++; // Update the history to save the last 5 vector values. history[4] = history[3]; history[3] = history[2]; history[2] = history[1]; history[1] = history[0]; if ((fieldResult = (*field)(t, yNew, history[0])) != avtIVPField::OK) return ConvertResult(fieldResult); yCur = yNew; t = t+h; if( last ) res = avtIVPSolver::TERMINATE; // Reset the step size on sucessful step. h = h_max; } return res; }
avtIVPSolver::Result avtIVPAdamsBashforth::Step(const avtIVPField* field, const TerminateType &termType, const double &end, avtIVPStep* ivpstep) { double t_max; if (termType == TIME) t_max = end; else if (termType == DISTANCE || termType == STEPS || termType == INTERSECTIONS) { t_max = std::numeric_limits<double>::max(); if (end < 0) t_max = -t_max; } const double direction = sign( 1.0, t_max - t ); h = sign( h, direction ); // do not run past integration end if( (t + 1.01*h - t_max) * direction > 0.0 ) { h = t_max - t; } // stepsize underflow? if( 0.1*std::abs(h) <= std::abs(t)*epsilon ) { return avtIVPSolver::STEPSIZE_UNDERFLOW; } avtIVPSolver::Result res; avtVector yNew = yCur; // Use a forth order Runga Kutta integration to seed the Adams-Bashforth. if ( initialized < NSTEPS ) { // Save the first vector values in the history. if( initialized == 0 ) { history[0] = (*field)(t,yCur); } res = RK4Step( field, yNew ); ++initialized; } else { res = ABStep( field, yNew ); } if ( res == avtIVPSolver::OK ) { ivpstep->resize(2); (*ivpstep)[0] = yCur; (*ivpstep)[1] = yNew; ivpstep->tStart = t; ivpstep->tEnd = t + h; numStep++; // Handle distanced based termination. if (termType == TIME) { if ((end > 0 && t >= end) || (end < 0 && t <= end)) return TERMINATE; } else if (termType == DISTANCE) { double len = ivpstep->length(); //debug1<<"ABStep: "<<t<<" d: "<<d<<" => "<<(d+len)<<" h= "<<h<<" len= "<<len<<" sEps= "<<stiffness_eps<<endl; if (len < stiffness_eps) { degenerate_iterations++; if (degenerate_iterations > 15) { //debug1<<"********** STIFFNESS ***************************\n"; return STIFFNESS_DETECTED; } } else degenerate_iterations = 0; if (d+len > fabs(end)) throw avtIVPField::Undefined(); else if (d+len >= fabs(end)) return TERMINATE; d = d+len; } else if (termType == STEPS && numStep >= (int)fabs(end)) return TERMINATE; if (end < 0.0) { ivpstep->velStart = (*field)(t,yCur); ivpstep->velEnd = (*field)((t+h),yNew); } else { ivpstep->velStart = - (*field)(t,yCur); ivpstep->velEnd = - (*field)((t+h),yNew); } // Update the history to save the last 5 vector values. history[4] = history[3]; history[3] = history[2]; history[2] = history[1]; history[1] = history[0]; history[0] = (*field)(t,yNew); yCur = yNew; t = t+h; } // Reset the step size on sucessful step. h = h_max; return res; }