Beispiel #1
0
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
}
Beispiel #2
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
}
Beispiel #3
0
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
}
Beispiel #4
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
}
Beispiel #5
0
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
}