예제 #1
0
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
}
예제 #2
0
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
}