func (o *RichardsonExtrap) Run(d *Domain, s *Summary, DtOut fun.Func, time *float64, tf, tout float64, tidx *int) (ok bool) { // stat defer func() { if Global.Root { log.Printf("total number of steps = %d\n", o.nsteps) log.Printf("number of accepted steps = %d\n", o.naccept) log.Printf("number of rejected steps = %d\n", o.nreject) log.Printf("number of Gustaffson's corrections = %d\n", o.ngustaf) } }() // constants atol := Global.Sim.Solver.REatol rtol := Global.Sim.Solver.RErtol mmin := Global.Sim.Solver.REmmin mmax := Global.Sim.Solver.REmmax mfac := Global.Sim.Solver.REmfac // time loop t := *time defer func() { *time = t }() var ΔtOld, rerrOld float64 for t < tf { // check for continued divergence if LogErrCond(o.ndiverg >= Global.Sim.Solver.NdvgMax, "continuous divergence after %d steps reached", o.ndiverg) { return } // check time increment if LogErrCond(o.Δt < Global.Sim.Solver.DtMin, "Δt increment is too small: %g < %g", o.Δt, Global.Sim.Solver.DtMin) { return } // compute dynamic coefficients if LogErr(Global.DynCoefs.CalcBoth(o.Δt), "cannot compute dynamic coefficients") { return } // check for maximum number of substeps o.nsteps += 1 if LogErrCond(o.nsteps >= Global.Sim.Solver.REnssmax, "RE: max number of steps reached: %d", o.nsteps) { return } // backup domain d.backup() // single step with Δt d.Sol.T = t + o.Δt o.diverging, ok = run_iterations(t+o.Δt, o.Δt, d, s) if !ok { return } if Global.Sim.Solver.DvgCtrl { if o.divergence_control(d, "big step") { continue } } // save intermediate state for i := 0; i < d.Ny; i++ { o.Y_big[i] = d.Sol.Y[i] } // restore initial state d.restore() // 1st halved step d.Sol.T = t + o.Δt/2.0 o.diverging, ok = run_iterations(t+o.Δt/2.0, o.Δt/2.0, d, s) if !ok { break } if Global.Sim.Solver.DvgCtrl { if o.divergence_control(d, "1st half step") { continue } } // 2nd halved step d.Sol.T = t + o.Δt o.diverging, ok = run_iterations(t+o.Δt, o.Δt/2.0, d, s) if !ok { break } if Global.Sim.Solver.DvgCtrl { if o.divergence_control(d, "2nd half step") { continue } } // Richardson's extrapolation error rerr := la.VecRmsError(d.Sol.Y, o.Y_big, atol, rtol, d.Sol.Y) / 3.0 // step size change m := min(mmax, max(mmin, mfac*math.Pow(1.0/rerr, 1.0/2.0))) ΔtNew := m * o.Δt // accepted if rerr < 1.0 { // update variables o.naccept += 1 t += o.Δt d.Sol.T = t // output if Global.Verbose { if !Global.Sim.Data.ShowR && !Global.Debug { io.PfWhite("%30.15f\r", t) } } //if true { if t >= tout || o.laststep { s.OutTimes = append(s.OutTimes, t) if !d.Out(*tidx) { return } tout += DtOut.F(t, nil) *tidx += 1 } // reached final time if o.laststep { if Global.Verbose { io.Pfgreen("\n\nRichardson extrapolation succeeded\n") } return true } // predictive controller of Gustafsson if !Global.Sim.Solver.REnogus { if o.naccept > 1 { m = mfac * (o.Δt / ΔtOld) * math.Sqrt(1.0/rerr) * math.Sqrt(rerrOld/rerr) if m*o.Δt < ΔtNew { o.ngustaf += 1 } ΔtNew = min(ΔtNew, m*o.Δt) } ΔtOld = o.Δt rerrOld = max(0.9, rerr) // 1e-2 } // next step size if o.reject { // do not alow Δt to grow if previous was a reject ΔtNew = min(o.Δt, ΔtNew) } o.reject = false o.Δt = ΔtNew if t+ΔtNew-tf >= 0.0 { o.laststep = true o.Δt = tf - t } // rejected } else { // restore state d.restore() // set flags o.nreject += 1 o.reject = true o.laststep = false // next step size o.Δt = ΔtNew if t+o.Δt > tf { o.Δt = tf - t } } } return true }
func (o *RichardsonExtrap) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, dbgKb DebugKb_t) (err error) { // constants dat := o.doms[0].Sim.Solver atol := dat.REatol rtol := dat.RErtol mmin := dat.REmmin mmax := dat.REmmax mfac := dat.REmfac // control t := o.doms[0].Sol.T tout := t + dtoFunc.F(t, nil) steady := o.doms[0].Sim.Data.Steady // first output if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } // domain and variables d := o.doms[0] o.Y_big = make([]float64, d.Ny) // time loop o.Δt = dtFunc.F(t, nil) o.Δtcpy = o.Δt var ΔtOld, rerrOld float64 for t < tf { // check for continued divergence if o.ndiverg >= dat.NdvgMax { return chk.Err("continuous divergence after %d steps reached", o.ndiverg) } // check time increment if o.Δt < dat.DtMin { return chk.Err("Δt increment is too small: %g < %g", o.Δt, dat.DtMin) } // dynamic coefficients if !steady { err = o.dc.CalcBoth(o.Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients:\n%v", err) } } // check for maximum number of substeps o.nsteps += 1 if o.nsteps >= dat.REnssmax { return chk.Err("RE: max number of steps reached: %d", o.nsteps) } // backup domain d.backup() // single step with Δt d.Sol.T = t + o.Δt d.Sol.Dt = o.Δt o.diverging, err = run_iterations(t+o.Δt, o.Δt, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("single step with Δt: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "big step", verbose) { continue } } // save intermediate state for i := 0; i < d.Ny; i++ { o.Y_big[i] = d.Sol.Y[i] } // restore initial state d.restore() // 1st halved step d.Sol.T = t + o.Δt/2.0 d.Sol.Dt = o.Δt / 2.0 o.diverging, err = run_iterations(t+o.Δt/2.0, o.Δt/2.0, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("1st halved step: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "1st half step", verbose) { continue } } // 2nd halved step d.Sol.T = t + o.Δt d.Sol.Dt = o.Δt o.diverging, err = run_iterations(t+o.Δt, o.Δt/2.0, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("2nd halved step: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "2nd half step", verbose) { continue } } // Richardson's extrapolation error rerr := la.VecRmsError(d.Sol.Y, o.Y_big, atol, rtol, d.Sol.Y) / 3.0 // step size change m := utl.Min(mmax, utl.Max(mmin, mfac*math.Pow(1.0/rerr, 1.0/2.0))) ΔtNew := m * o.Δt // accepted if rerr < 1.0 { // update variables o.naccept += 1 t += o.Δt d.Sol.T = t // output if verbose { if !dat.ShowR { io.PfWhite("%30.15f\r", t) } } if t >= tout || o.laststep { if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } tout += dtoFunc.F(t, nil) } // reached final time if o.laststep { if verbose { io.Pfgreen("\n\nRichardson extrapolation succeeded\n") } return } // predictive controller of Gustafsson if !dat.REnogus { if o.naccept > 1 { m = mfac * (o.Δt / ΔtOld) * math.Sqrt(1.0/rerr) * math.Sqrt(rerrOld/rerr) if m*o.Δt < ΔtNew { o.ngustaf += 1 } ΔtNew = utl.Min(ΔtNew, m*o.Δt) } ΔtOld = o.Δt rerrOld = utl.Max(0.9, rerr) // 1e-2 } // next step size if o.reject { // do not alow Δt to grow if previous was a reject ΔtNew = utl.Min(o.Δt, ΔtNew) } o.reject = false o.Δt = ΔtNew if t+ΔtNew-tf >= 0.0 { o.laststep = true o.Δt = tf - t } // rejected } else { // restore state d.restore() // set flags o.nreject += 1 o.reject = true o.laststep = false // next step size o.Δt = ΔtNew if t+o.Δt > tf { o.Δt = tf - t } } } return }