Esempio n. 1
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
}
Esempio n. 2
0
func Test_nls03(tst *testing.T) {

	//verbose()
	chk.PrintTitle("nls03. 2 eqs system with trig functions")

	e := math.E
	ffcn := func(fx, x []float64) error {
		fx[0] = 0.5*sin(x[0]*x[1]) - 0.25*x[1]/pi - 0.5*x[0]
		fx[1] = (1.0-0.25/pi)*(math.Exp(2.0*x[0])-e) + e*x[1]/pi - 2.0*e*x[0]
		return nil
	}
	Jfcn := func(dfdx *la.Triplet, x []float64) error {
		dfdx.Start()
		dfdx.Put(0, 0, 0.5*x[1]*cos(x[0]*x[1])-0.5)
		dfdx.Put(0, 1, 0.5*x[0]*cos(x[0]*x[1])-0.25/pi)
		dfdx.Put(1, 0, (2.0-0.5/pi)*math.Exp(2.0*x[0])-2.0*e)
		dfdx.Put(1, 1, e/pi)
		return nil
	}
	JfcnD := func(dfdx [][]float64, x []float64) error {
		dfdx[0][0] = 0.5*x[1]*cos(x[0]*x[1]) - 0.5
		dfdx[0][1] = 0.5*x[0]*cos(x[0]*x[1]) - 0.25/pi
		dfdx[1][0] = (2.0-0.5/pi)*math.Exp(2.0*x[0]) - 2.0*e
		dfdx[1][1] = e / pi
		return nil
	}

	x := []float64{0.4, 3.0}
	fx := make([]float64, len(x))
	atol := 1e-6
	rtol := 1e-3
	ftol := 10 * EPS
	neq := len(x)

	prms := map[string]float64{
		"atol":    atol,
		"rtol":    rtol,
		"ftol":    ftol,
		"lSearch": 0.0, // does not work with line search
	}

	// init
	var nls_sps NlSolver // sparse
	var nls_den NlSolver // dense
	nls_sps.Init(neq, ffcn, Jfcn, nil, false, false, prms)
	nls_den.Init(neq, ffcn, nil, JfcnD, true, false, prms)
	defer nls_sps.Clean()
	defer nls_den.Clean()

	io.PfMag("\n/////////////////////// sparse //////////////////////////////////////////\n")

	x = []float64{0.4, 3.0}
	io.PfYel("\n--- sparse ------------- with x = %v --------------\n", x)
	err := nls_sps.Solve(x, false)
	if err != nil {
		chk.Panic(err.Error())
	}
	ffcn(fx, x)
	io.Pf("x    = %v  expected = %v\n", x, []float64{-0.2605992900257, 0.6225308965998})
	io.Pf("f(x) = %v\n", fx)
	chk.Vector(tst, "x", 1e-13, x, []float64{-0.2605992900257, 0.6225308965998})
	chk.Vector(tst, "f(x) = 0? ", 1e-11, fx, nil)

	x = []float64{0.7, 4.0}
	io.PfYel("\n--- sparse ------------- with x = %v --------------\n", x)
	//rtol = 1e-2
	err = nls_sps.Solve(x, false)
	if err != nil {
		chk.Panic(err.Error())
	}
	ffcn(fx, x)
	io.Pf("x    = %v  expected = %v\n", x, []float64{0.5000000377836, 3.1415927055406})
	io.Pf("f(x) = %v\n", fx)
	chk.Vector(tst, "x  ", 1e-7, x, []float64{0.5000000377836, 3.1415927055406})
	chk.Vector(tst, "f(x) = 0? ", 1e-7, fx, nil)

	x = []float64{1.0, 4.0}
	io.PfYel("\n--- sparse ------------- with x = %v ---------------\n", x)
	//lSearch, chkConv := false, true  // this combination fails due to divergence
	//lSearch, chkConv := false, false // this combination works but results are different
	//lSearch, chkConv := true, true   // this combination works but results are wrong => fails
	nls_sps.ChkConv = false
	err = nls_sps.Solve(x, false)
	if err != nil {
		chk.Panic(err.Error())
	}
	ffcn(fx, x)
	io.Pf("x    = %v  expected = %v\n", x, []float64{0.5, pi})
	io.Pf("f(x) = %v << converges to a different solution\n", fx)
	chk.Vector(tst, "f(x) = 0? ", 1e-8, fx, nil)

	io.PfMag("\n/////////////////////// dense //////////////////////////////////////////\n")

	x = []float64{0.4, 3.0}
	io.PfYel("\n--- dense ------------- with x = %v --------------\n", x)
	err = nls_den.Solve(x, false)
	if err != nil {
		chk.Panic(err.Error())
	}
	ffcn(fx, x)
	io.Pf("x    = %v  expected = %v\n", x, []float64{-0.2605992900257, 0.6225308965998})
	io.Pf("f(x) = %v\n", fx)
	chk.Vector(tst, "x", 1e-13, x, []float64{-0.2605992900257, 0.6225308965998})
	chk.Vector(tst, "f(x) = 0? ", 1e-11, fx, nil)

	x = []float64{0.7, 4.0}
	io.PfYel("\n--- dense ------------- with x = %v --------------\n", x)
	//rtol = 1e-2
	err = nls_den.Solve(x, false)
	if err != nil {
		chk.Panic(err.Error())
	}
	ffcn(fx, x)
	io.Pf("x    = %v  expected = %v\n", x, []float64{0.5000000377836, 3.1415927055406})
	io.Pf("f(x) = %v\n", fx)
	chk.Vector(tst, "x  ", 1e-7, x, []float64{0.5000000377836, 3.1415927055406})
	chk.Vector(tst, "f(x) = 0? ", 1e-7, fx, nil)

	x = []float64{1.0, 4.0}
	io.PfYel("\n--- dense ------------- with x = %v ---------------\n", x)
	nls_den.ChkConv = false
	err = nls_den.Solve(x, false)
	if err != nil {
		chk.Panic(err.Error())
	}
	ffcn(fx, x)
	io.Pf("x    = %v  expected = %v\n", x, []float64{0.5, pi})
	io.Pf("f(x) = %v << converges to a different solution\n", fx)
	chk.Vector(tst, "f(x) = 0? ", 1e-8, fx, nil)
}