// 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 }
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) }