Beispiel #1
0
// run_iterations solves the nonlinear problem
func run_iterations(t, Δt float64, d *Domain, dc *DynCoefs, sum *Summary, dbgKb DebugKb_t) (diverging bool, err error) {

	// zero accumulated increments
	la.VecFill(d.Sol.ΔY, 0)

	// calculate global starred vectors and interpolate starred variables from nodes to integration points
	if !d.Sim.Data.Steady {

		// compute starred vectors
		for _, I := range d.T1eqs {
			d.Sol.Psi[I] = dc.β1*d.Sol.Y[I] + dc.β2*d.Sol.Dydt[I]
		}
		for _, I := range d.T2eqs {
			d.Sol.Zet[I] = dc.α1*d.Sol.Y[I] + dc.α2*d.Sol.Dydt[I] + dc.α3*d.Sol.D2ydt2[I]
			d.Sol.Chi[I] = dc.α4*d.Sol.Y[I] + dc.α5*d.Sol.Dydt[I] + dc.α6*d.Sol.D2ydt2[I]
		}

		// set internal starred variables
		for _, e := range d.Elems {
			err = e.InterpStarVars(d.Sol)
			if err != nil {
				err = chk.Err("cannot compute starred variables:\n%v", err)
				return
			}
		}
	}

	// auxiliary variables
	var it int
	var largFb, largFb0, Lδu float64
	var prevFb, prevLδu float64
	dat := d.Sim.Solver

	// message
	if dat.ShowR {
		io.Pf("\n%13s%4s%23s%23s\n", "t", "it", "largFb", "Lδu")
		defer func() {
			io.Pf("%13.6e%4d%23.15e%23.15e\n", t, it, largFb, Lδu)
		}()
	}

	// iterations
	for it = 0; it < dat.NmaxIt; it++ {

		// assemble right-hand side vector (fb) with negative of residuals
		la.VecFill(d.Fb, 0)
		for _, e := range d.Elems {
			err = e.AddToRhs(d.Fb, d.Sol)
			if err != nil {
				return
			}
		}

		// join all fb
		if d.Distr {
			mpi.AllReduceSum(d.Fb, d.Wb) // this must be done here because there might be nodes sharing boundary conditions
		}

		// point natural boundary conditions; e.g. concentrated loads
		d.PtNatBcs.AddToRhs(d.Fb, t)

		// essential boundary conditioins; e.g. constraints
		d.EssenBcs.AddToRhs(d.Fb, d.Sol)

		// find largest absolute component of fb
		largFb = la.VecLargest(d.Fb, 1)

		// save residual
		if d.Sim.Data.Stat {
			if sum != nil {
				sum.Resids.Append(it == 0, largFb)
			}
		}

		// check largFb value
		if it == 0 {
			// store largest absolute component of fb
			largFb0 = largFb
		} else {
			// check convergence on Lf0
			if largFb < dat.FbTol*largFb0 { // converged on fb
				break
			}
			// check convergence on fb_min
			if largFb < dat.FbMin { // converged with smallest value of fb
				break
			}
		}

		// check divergence on fb
		if it > 1 && dat.DvgCtrl {
			if largFb > prevFb {
				diverging = true
				break
			}
		}
		prevFb = largFb

		// assemble Jacobian matrix
		do_asm_fact := (it == 0 || !dat.CteTg)
		if do_asm_fact {

			// assemble element matrices
			d.Kb.Start()
			for _, e := range d.Elems {
				err = e.AddToKb(d.Kb, d.Sol, it == 0)
				if err != nil {
					return
				}
			}

			// debug
			if dbgKb != nil {
				dbgKb(d, it)
			}

			// join A and tr(A) matrices into Kb
			if d.Proc == 0 {
				d.Kb.PutMatAndMatT(&d.EssenBcs.A)
			}

			// initialise linear solver
			if d.InitLSol {
				err = d.LinSol.InitR(d.Kb, d.Sim.LinSol.Symmetric, d.Sim.LinSol.Verbose, d.Sim.LinSol.Timing)
				if err != nil {
					err = chk.Err("cannot initialise linear solver:\n%v", err)
					return
				}
				d.InitLSol = false
			}

			// perform factorisation
			err = d.LinSol.Fact()
			if err != nil {
				err = chk.Err("factorisation failed:\n%v", err)
				return
			}
		}

		// solve for wb := δyb
		err = d.LinSol.SolveR(d.Wb, d.Fb, false)
		if err != nil {
			err = chk.Err("solve failed:%v\n", err)
			return
		}

		// update primary variables (y)
		for i := 0; i < d.Ny; i++ {
			d.Sol.Y[i] += d.Wb[i]  // y += δy
			d.Sol.ΔY[i] += d.Wb[i] // ΔY += δy
		}
		if !d.Sim.Data.Steady {
			for _, I := range d.T1eqs {
				d.Sol.Dydt[I] = dc.β1*d.Sol.Y[I] - d.Sol.Psi[I]
			}
			for _, I := range d.T2eqs {
				d.Sol.Dydt[I] = dc.α4*d.Sol.Y[I] - d.Sol.Chi[I]
				d.Sol.D2ydt2[I] = dc.α1*d.Sol.Y[I] - d.Sol.Zet[I]
			}
		}

		// update Lagrange multipliers (λ)
		for i := 0; i < d.Nlam; i++ {
			d.Sol.L[i] += d.Wb[d.Ny+i] // λ += δλ
		}

		// backup / restore
		if it == 0 {
			// create backup copy of all secondary variables
			for _, e := range d.ElemIntvars {
				e.BackupIvs(false)
			}
		} else {
			// recover last converged state from backup copy
			for _, e := range d.ElemIntvars {
				e.RestoreIvs(false)
			}
		}

		// update secondary variables
		for _, e := range d.Elems {
			err = e.Update(d.Sol)
			if err != nil {
				break
			}
		}

		// compute RMS norm of δu and check convegence on δu
		Lδu = la.VecRmsErr(d.Wb[:d.Ny], dat.Atol, dat.Rtol, d.Sol.Y[:d.Ny])

		// message
		if dat.ShowR {
			io.Pf("%13.6e%4d%23.15e%23.15e\n", t, it, largFb, Lδu)
		}

		// stop if converged on δu
		if Lδu < dat.Itol {
			break
		}

		// check divergence on Lδu
		if it > 1 && dat.DvgCtrl {
			if Lδu > prevLδu {
				diverging = true
				break
			}
		}
		prevLδu = Lδu
	}

	// check if iterations diverged
	if it == dat.NmaxIt {
		err = chk.Err("max number of iterations reached: it = %d\n", it)
	}
	return
}
Beispiel #2
0
// run_iterations solves the nonlinear problem
func run_iterations(t, Δt float64, d *Domain, sum *Summary) (diverging, ok bool) {

	// zero accumulated increments
	la.VecFill(d.Sol.ΔY, 0)

	// calculate global starred vectors and interpolate starred variables from nodes to integration points
	if LogErr(d.star_vars(Δt), "cannot compute starred variables") {
		return
	}

	// auxiliary variables
	var it int
	var largFb, largFb0, Lδu float64
	var prevFb, prevLδu float64

	// message
	if Global.Sim.Data.ShowR {
		io.Pf("\n%13s%4s%23s%23s\n", "t", "it", "largFb", "Lδu")
		defer func() {
			io.Pf("%13.6e%4d%23.15e%23.15e\n", t, it, largFb, Lδu)
		}()
	}

	// iterations
	for it = 0; it < Global.Sim.Solver.NmaxIt; it++ {

		// assemble right-hand side vector (fb) with negative of residuals
		la.VecFill(d.Fb, 0)
		for _, e := range d.Elems {
			if !e.AddToRhs(d.Fb, d.Sol) {
				break
			}
		}
		if Stop() {
			return
		}

		// join all fb
		if Global.Distr {
			mpi.AllReduceSum(d.Fb, d.Wb) // this must be done here because there might be nodes sharing boundary conditions
		}

		// point natural boundary conditions; e.g. concentrated loads
		d.PtNatBcs.AddToRhs(d.Fb, t)

		// essential boundary conditioins; e.g. constraints
		d.EssenBcs.AddToRhs(d.Fb, d.Sol)

		// debug
		if Global.Debug {
			//la.PrintVec("fb", d.Fb[:d.Ny], "%13.10f ", false)
			//panic("stop")
		}

		// find largest absolute component of fb
		largFb = la.VecLargest(d.Fb, 1)

		// save residual
		if Global.Stat {
			sum.Resids.Append(it == 0, largFb)
		}

		// check largFb value
		if it == 0 {
			// store largest absolute component of fb
			largFb0 = largFb
		} else {
			// check convergence on Lf0
			if largFb < Global.Sim.Solver.FbTol*largFb0 { // converged on fb
				break
			}
			// check convergence on fb_min
			if largFb < Global.Sim.Solver.FbMin { // converged with smallest value of fb
				break
			}
		}

		// check divergence on fb
		if it > 1 && Global.Sim.Solver.DvgCtrl {
			if largFb > prevFb {
				diverging = true
				break
			}
		}
		prevFb = largFb

		// assemble Jacobian matrix
		do_asm_fact := (it == 0 || !Global.Sim.Data.CteTg)
		if do_asm_fact {

			// assemble element matrices
			d.Kb.Start()
			for _, e := range d.Elems {
				if !e.AddToKb(d.Kb, d.Sol, it == 0) {
					break
				}
			}
			if Stop() {
				return
			}

			// debug
			if Global.DebugKb != nil {
				Global.DebugKb(d, it)
			}

			// join A and tr(A) matrices into Kb
			if Global.Root {
				d.Kb.PutMatAndMatT(&d.EssenBcs.A)
			}

			// initialise linear solver
			if d.InitLSol {
				if LogErr(d.LinSol.InitR(d.Kb, Global.Sim.LinSol.Symmetric, Global.Sim.LinSol.Verbose, Global.Sim.LinSol.Timing), "cannot initialise linear solver") {
					return
				}
				d.InitLSol = false
			}

			// perform factorisation
			LogErr(d.LinSol.Fact(), "factorisation")
			if Stop() {
				return
			}
		}

		// debug
		//KK := d.Kb.ToMatrix(nil).ToDense()
		//la.PrintMat("KK", KK, "%20.10f", false)
		//panic("stop")

		// solve for wb := δyb
		LogErr(d.LinSol.SolveR(d.Wb, d.Fb, false), "solve")
		if Stop() {
			return
		}

		// debug
		if Global.Debug {
			//la.PrintVec("wb", d.Wb[:d.Ny], "%13.10f ", false)
		}

		// update primary variables (y)
		for i := 0; i < d.Ny; i++ {
			d.Sol.Y[i] += d.Wb[i]  // y += δy
			d.Sol.ΔY[i] += d.Wb[i] // ΔY += δy
		}
		if !Global.Sim.Data.Steady {
			for _, I := range d.T1eqs {
				d.Sol.Dydt[I] = Global.DynCoefs.β1*d.Sol.Y[I] - d.Sol.Psi[I]
			}
			for _, I := range d.T2eqs {
				d.Sol.Dydt[I] = Global.DynCoefs.α4*d.Sol.Y[I] - d.Sol.Chi[I]
				d.Sol.D2ydt2[I] = Global.DynCoefs.α1*d.Sol.Y[I] - d.Sol.Zet[I]
			}
		}

		// update Lagrange multipliers (λ)
		for i := 0; i < d.Nlam; i++ {
			d.Sol.L[i] += d.Wb[d.Ny+i] // λ += δλ
		}

		// backup / restore
		if it == 0 {
			// create backup copy of all secondary variables
			for _, e := range d.ElemIntvars {
				e.BackupIvs(false)
			}
		} else {
			// recover last converged state from backup copy
			for _, e := range d.ElemIntvars {
				e.RestoreIvs(false)
			}
		}

		// update secondary variables
		for _, e := range d.Elems {
			if !e.Update(d.Sol) {
				break
			}
		}
		if Stop() {
			return
		}

		// compute RMS norm of δu and check convegence on δu
		Lδu = la.VecRmsErr(d.Wb[:d.Ny], Global.Sim.Solver.Atol, Global.Sim.Solver.Rtol, d.Sol.Y[:d.Ny])

		// message
		if Global.Sim.Data.ShowR {
			io.Pf("%13.6e%4d%23.15e%23.15e\n", t, it, largFb, Lδu)
		}

		// stop if converged on δu
		if Lδu < Global.Sim.Solver.Itol {
			break
		}

		// check divergence on Lδu
		if it > 1 && Global.Sim.Solver.DvgCtrl {
			if Lδu > prevLδu {
				diverging = true
				break
			}
		}
		prevLδu = Lδu
	}

	// check if iterations diverged
	if it == Global.Sim.Solver.NmaxIt {
		io.PfMag("max number of iterations reached: it = %d\n", it)
		return
	}

	// success
	ok = true
	return
}
Beispiel #3
0
// Solve solves non-linear problem f(x) == 0
func (o *NlSolver) Solve(x []float64, silent bool) (err error) {

	// compute scaling vector
	la.VecScaleAbs(o.scal, o.atol, o.rtol, x) // scal := Atol + Rtol*abs(x)

	// evaluate function @ x
	err = o.Ffcn(o.fx, x) // fx := f(x)
	o.NFeval, o.NJeval = 1, 0
	if err != nil {
		return
	}

	// show message
	if !silent {
		o.msg("", 0, 0, 0, true, false)
	}

	// iterations
	var Ldx, Ldx_prev, Θ float64 // RMS norm of delta x, convergence rate
	var fx_max float64
	var nfv int
	for o.It = 0; o.It < o.MaxIt; o.It++ {

		// check convergence on f(x)
		fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0
		if fx_max < o.ftol {
			if !silent {
				o.msg("fx_max(ini)", o.It, Ldx, fx_max, false, true)
			}
			break
		}

		// show message
		if !silent {
			o.msg("", o.It, Ldx, fx_max, false, false)
		}

		// output
		if o.Out != nil {
			o.Out(x)
		}

		// evaluate Jacobian @ x
		if o.It == 0 || !o.CteJac {
			if o.useDn {
				err = o.JfcnDn(o.J, x)
			} else {
				if o.numJ {
					err = Jacobian(&o.Jtri, o.Ffcn, x, o.fx, o.w, false)
					o.NFeval += o.neq
				} else {
					err = o.JfcnSp(&o.Jtri, x)
				}
			}
			o.NJeval += 1
			if err != nil {
				return
			}
		}

		// dense solution
		if o.useDn {

			// invert matrix
			err = la.MatInvG(o.Ji, o.J, 1e-10)
			if err != nil {
				return chk.Err(_nls_err1, err.Error())
			}

			// solve linear system (compute mdx) and compute lin-search data
			o.φ = 0.0
			for i := 0; i < o.neq; i++ {
				o.mdx[i], o.dφdx[i] = 0.0, 0.0
				for j := 0; j < o.neq; j++ {
					o.mdx[i] += o.Ji[i][j] * o.fx[j] // mdx  = inv(J) * fx
					o.dφdx[i] += o.J[j][i] * o.fx[j] // dφdx = tra(J) * fx
				}
				o.φ += o.fx[i] * o.fx[i]
			}
			o.φ *= 0.5

			// sparse solution
		} else {

			// init sparse solver
			if o.It == 0 {
				symmetric, verbose, timing := false, false, false
				err := o.lis.InitR(&o.Jtri, symmetric, verbose, timing)
				if err != nil {
					return chk.Err(_nls_err9, err.Error())
				}
			}

			// factorisation (must be done for all iterations)
			o.lis.Fact()

			// solve linear system => compute mdx
			o.lis.SolveR(o.mdx, o.fx, false) // mdx = inv(J) * fx   false => !sumToRoot

			// compute lin-search data
			if o.Lsearch {
				o.φ = 0.5 * la.VecDot(o.fx, o.fx)
				la.SpTriMatTrVecMul(o.dφdx, &o.Jtri, o.fx) // dφdx := transpose(J) * fx
			}
		}

		//io.Pforan("φ    = %v\n", o.φ)
		//io.Pforan("dφdx = %v\n", o.dφdx)

		// update x
		Ldx = 0.0
		for i := 0; i < o.neq; i++ {
			o.x0[i] = x[i]
			x[i] -= o.mdx[i]
			Ldx += (o.mdx[i] / o.scal[i]) * (o.mdx[i] / o.scal[i])
		}
		Ldx = math.Sqrt(Ldx / float64(o.neq))

		// calculate fx := f(x) @ update x
		err = o.Ffcn(o.fx, x)
		o.NFeval += 1
		if err != nil {
			return
		}

		// check convergence on f(x) => avoid line-search if converged already
		fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0
		if fx_max < o.ftol {
			if !silent {
				o.msg("fx_max", o.It, Ldx, fx_max, false, true)
			}
			break
		}

		// check convergence on Ldx
		if Ldx < o.fnewt {
			if !silent {
				o.msg("Ldx", o.It, Ldx, fx_max, false, true)
			}
			break
		}

		// call line-search => update x and fx
		if o.Lsearch {
			nfv, err = LineSearch(x, o.fx, o.Ffcn, o.mdx, o.x0, o.dφdx, o.φ, o.LsMaxIt, true)
			o.NFeval += nfv
			if err != nil {
				return chk.Err(_nls_err2, err.Error())
			}
			Ldx = 0.0
			for i := 0; i < o.neq; i++ {
				Ldx += ((x[i] - o.x0[i]) / o.scal[i]) * ((x[i] - o.x0[i]) / o.scal[i])
			}
			Ldx = math.Sqrt(Ldx / float64(o.neq))
			fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0
			if Ldx < o.fnewt {
				if !silent {
					o.msg("Ldx(linsrch)", o.It, Ldx, fx_max, false, true)
				}
				break
			}
		}

		// check convergence rate
		if o.It > 0 && o.ChkConv {
			Θ = Ldx / Ldx_prev
			if Θ > 0.99 {
				return chk.Err(_nls_err3, Θ, Ldx, Ldx_prev)
			}
		}
		Ldx_prev = Ldx
	}

	// output
	if o.Out != nil {
		o.Out(x)
	}

	// check convergence
	if o.It == o.MaxIt {
		err = chk.Err(_nls_err4, o.It)
	}
	return
}