func (o *RichardsonExtrap) Init(d *Domain, Dt fun.Func) { // backup variables o.Y_big = make([]float64, d.Ny) // auxiliary variables o.nsteps = 0 o.naccept = 0 o.nreject = 0 o.ngustaf = 0 o.reject = false o.laststep = false // divergence control o.ndiverg = 0 o.prevdiv = false o.diverging = false // time loop o.Δt = Dt.F(0, nil) o.Δtcpy = o.Δt }
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 *SolverImplicit) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, dbgKb DebugKb_t) (err error) { // auxiliary md := 1.0 // time step multiplier if divergence control is on ndiverg := 0 // number of steps diverging // control t := o.doms[0].Sol.T dat := o.doms[0].Sim.Solver 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) } } // time loop var Δt float64 var lasttimestep bool for t < tf { // check for continued divergence if ndiverg >= dat.NdvgMax { return chk.Err("continuous divergence after %d steps reached", ndiverg) } // time increment Δt = dtFunc.F(t, nil) * md if t+Δt >= tf { lasttimestep = true } if Δt < dat.DtMin { if md < 1 { return chk.Err("Δt increment is too small: %g < %g", Δt, dat.DtMin) } } t += Δt // dynamic coefficients if !steady { err = o.dc.CalcBoth(Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients") } } // message if verbose { if !dat.ShowR { io.PfWhite("%30.15f\r", t) } } // for all domains docontinue := false for _, d := range o.doms { // backup solution if divergence control is on if dat.DvgCtrl { d.backup() } // run iterations d.Sol.T = t d.Sol.Dt = Δt diverging, err := run_iterations(t, Δt, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("run_iterations failed:\n%v", err) } // restore solution and reduce time step if divergence control is on if dat.DvgCtrl { if diverging { if verbose { io.Pfred(". . . iterations diverging (%2d) . . .\n", ndiverg+1) } d.restore() t -= Δt d.Sol.T = t md *= 0.5 ndiverg += 1 docontinue = true break } ndiverg = 0 md = 1.0 } } if docontinue { continue } // perform output if t >= tout || lasttimestep { 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) } } return }
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 }
func (o *SolverLinearImplicit) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, notused DebugKb_t) (err error) { // control t := o.dom.Sol.T tout := t + dtoFunc.F(t, nil) steady := o.dom.Sim.Data.Steady // first output if o.sum != nil { err = o.sum.SaveDomains(t, []*Domain{o.dom}, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } // auxiliary variables Y := o.dom.Sol.Y ψ := o.dom.Sol.Psi ζ := o.dom.Sol.Zet χ := o.dom.Sol.Chi dydt := o.dom.Sol.Dydt d2ydt2 := o.dom.Sol.D2ydt2 // time loop first := true var Δt float64 var lasttimestep bool for t < tf { // time increment Δt = dtFunc.F(t, nil) if t+Δt >= tf { lasttimestep = true } t += Δt // update time variable in solution array o.dom.Sol.T = t o.dom.Sol.Dt = Δt // dynamic coefficients if !steady { err = o.dc.CalcBoth(Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients") } } // message if verbose { io.PfWhite("%30.15f\r", t) } // calculate global starred vectors and interpolate starred variables from nodes to integration points if !steady { // compute starred vectors for _, I := range o.dom.T1eqs { ψ[I] = Y[I] - o.dom.Sol.ΔY[I] } for _, I := range o.dom.T2eqs { ζ[I] = Y[I] χ[I] = Y[I] } // set internal starred variables for _, e := range o.dom.Elems { err = e.InterpStarVars(o.dom.Sol) if err != nil { err = chk.Err("cannot compute starred variables:\n%v", err) return } } } // solve linear problem err := solve_linear_problem(t, o.dom, o.dc, o.sum, first) if err != nil { return chk.Err("solve_linear_problem failed:\n%v", err) } first = false // update velocity and acceleration if !steady { for _, I := range o.dom.T1eqs { dydt[I] = Y[I] - ψ[I] } for _, I := range o.dom.T2eqs { dydt[I] = o.dc.α4*Y[I] - χ[I] d2ydt2[I] = o.dc.α1*Y[I] - ζ[I] } } // perform output if t >= tout || lasttimestep { if o.sum != nil { err = o.sum.SaveDomains(t, []*Domain{o.dom}, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } tout += dtoFunc.F(t, nil) } } return }