func main() { // input matrix in Triplet format // including repeated positions. e.g. (0,0) var A la.Triplet A.Init(5, 5, 13) A.Put(0, 0, 1.0) // << repeated A.Put(0, 0, 1.0) // << repeated A.Put(1, 0, 3.0) A.Put(0, 1, 3.0) A.Put(2, 1, -1.0) A.Put(4, 1, 4.0) A.Put(1, 2, 4.0) A.Put(2, 2, -3.0) A.Put(3, 2, 1.0) A.Put(4, 2, 2.0) A.Put(2, 3, 2.0) A.Put(1, 4, 6.0) A.Put(4, 4, 1.0) // right-hand-side b := []float64{8.0, 45.0, -3.0, 3.0, 19.0} // allocate solver lis := la.GetSolver("umfpack") defer lis.Clean() // info symmetric := false verbose := false timing := false // initialise solver (R)eal err := lis.InitR(&A, symmetric, verbose, timing) if err != nil { io.Pfred("solver failed:\n%v", err) return } // factorise err = lis.Fact() if err != nil { io.Pfred("solver failed:\n%v", err) return } // solve (R)eal var dummy bool x := make([]float64, len(b)) err = lis.SolveR(x, b, dummy) // x := inv(a) * b if err != nil { io.Pfred("solver failed:\n%v", err) return } // output la.PrintMat("a", A.ToMatrix(nil).ToDense(), "%5g", false) la.PrintVec("b", b, "%v ", false) la.PrintVec("x", x, "%v ", false) }
// NewDomain returns a new domain func NewDomain(reg *inp.Region, distr bool) *Domain { var dom Domain dom.Reg = reg dom.Msh = reg.Msh if distr { if LogErrCond(Global.Nproc != len(dom.Msh.Part2cells), "number of processors must be equal to the number of partitions defined in mesh file. %d != %d", Global.Nproc, len(dom.Msh.Part2cells)) { return nil } } dom.LinSol = la.GetSolver(Global.Sim.LinSol.Name) return &dom }
// Init initialises LinIpm func (o *LinIpm) Init(A *la.CCMatrix, b, c []float64, prms fun.Prms) { // problem o.A, o.B, o.C = A, b, c // constants o.NmaxIt = 50 o.Tol = 1e-8 for _, p := range prms { switch p.N { case "nmaxit": o.NmaxIt = int(p.V) } } // dimensions o.Nx = len(o.C) o.Nl = len(o.B) o.Ny = 2*o.Nx + o.Nl ix, jx := 0, o.Nx il, jl := o.Nx, o.Nx+o.Nl is, js := o.Nx+o.Nl, o.Ny // solution vector o.Y = make([]float64, o.Ny) o.X = o.Y[ix:jx] o.L = o.Y[il:jl] o.S = o.Y[is:js] o.Mdy = make([]float64, o.Ny) o.Mdx = o.Mdy[ix:jx] o.Mdl = o.Mdy[il:jl] o.Mds = o.Mdy[is:js] // affine solution o.R = make([]float64, o.Ny) o.Rx = o.R[ix:jx] o.Rl = o.R[il:jl] o.Rs = o.R[is:js] o.J = new(la.Triplet) nnz := 2*o.Nl*o.Nx + 3*o.Nx o.J.Init(o.Ny, o.Ny, nnz) // linear solver o.Lis = la.GetSolver("umfpack") }
// NewDomains returns domains func NewDomains(sim *inp.Simulation, dyncfs *DynCoefs, hydsta *HydroStatic, proc, nproc int, distr bool) (doms []*Domain) { doms = make([]*Domain, len(sim.Regions)) for i, reg := range sim.Regions { doms[i] = new(Domain) doms[i].Distr = distr doms[i].Proc = proc doms[i].Sim = sim doms[i].Reg = reg doms[i].Msh = reg.Msh if distr { if nproc != len(reg.Msh.Part2cells) { chk.Panic("number of processors must be equal to the number of partitions defined in mesh file. %d != %d", nproc, len(reg.Msh.Part2cells)) } } doms[i].LinSol = la.GetSolver(sim.LinSol.Name) doms[i].DynCfs = dyncfs doms[i].HydSta = hydsta } return }
func main() { // given the following matrix of complex numbers: // _ _ // | 19.73 12.11-i 5i 0 0 | // | -0.51i 32.3+7i 23.07 i 0 | // A = | 0 -0.51i 70+7.3i 3.95 19+31.83i | // | 0 0 1+1.1i 50.17 45.51 | // |_ 0 0 0 -9.351i 55 _| // // and the following vector: // _ _ // | 77.38+8.82i | // | 157.48+19.8i | // b = | 1175.62+20.69i | // | 912.12-801.75i | // |_ 550-1060.4i _| // // solve: // A.x = b // // the solution is: // _ _ // | 3.3-i | // | 1+0.17i | // x = | 5.5 | // | 9 | // |_ 10-17.75i _| // flag indicating to store (real,complex) values in monolithic form => 1D array xzmono := false // input matrix in Complex Triplet format var A la.TripletC A.Init(5, 5, 16, xzmono) // 5 x 5 matrix with 16 non-zeros // first column A.Put(0, 0, 19.73, 0) // i=0, j=0, real=19.73, complex=0 A.Put(1, 0, 0, -0.51) // i=1, j=0, real=0, complex=-0.51 // second column A.Put(0, 1, 12.11, -1) // i=0, j=1, real=12.11, complex=-1 A.Put(1, 1, 32.3, 7) A.Put(2, 1, 0, -0.51) // third column A.Put(0, 2, 0, 5) A.Put(1, 2, 23.07, 0) A.Put(2, 2, 70, 7.3) A.Put(3, 2, 1, 1.1) // fourth column A.Put(1, 3, 0, 1) A.Put(2, 3, 3.95, 0) A.Put(3, 3, 50.17, 0) A.Put(4, 3, 0, -9.351) // fifth column A.Put(2, 4, 19, 31.83) A.Put(3, 4, 45.51, 0) A.Put(4, 4, 55, 0) // right-hand-side b := []complex128{ 77.38 + 8.82i, 157.48 + 19.8i, 1175.62 + 20.69i, 912.12 - 801.75i, 550 - 1060.4i, } // allocate solver lis := la.GetSolver("umfpack") defer lis.Clean() // info symmetric := false verbose := false timing := false // initialise solver (C)omplex err := lis.InitC(&A, symmetric, verbose, timing) if err != nil { io.Pfred("solver failed:\n%v", err) return } // factorise err = lis.Fact() if err != nil { io.Pfred("solver failed:\n%v", err) return } // auxiliary variables bR, bC := la.ComplexToRC(b) // real and complex components of b xR := make([]float64, len(b)) // real compoments of x xC := make([]float64, len(b)) // complex compoments of x // solve (C)omplex var dummy bool err = lis.SolveC(xR, xC, bR, bC, dummy) // x := inv(A) * b if err != nil { io.Pfred("solver failed:\n%v", err) return } // join solution vector x := la.RCtoComplex(xR, xC) // output a := A.ToMatrix(nil) io.Pforan("A.x = b\n") la.PrintMatC("A", a.ToDense(), "(%5g", "%+6gi) ", false) la.PrintVecC("b", b, "(%g", "%+gi) ", false) la.PrintVecC("x", x, "(%.3f", "%+.3fi) ", false) }
// Init initialises solver // Input: // useSp -- Use sparse solver with JfcnSp // useDn -- Use dense solver (matrix inversion) with JfcnDn // numJ -- Use numeric Jacobian (sparse version only) // prms -- atol, rtol, ftol, lSearch, lsMaxIt, maxIt func (o *NlSolver) Init(neq int, Ffcn Cb_f, JfcnSp Cb_J, JfcnDn Cb_Jd, useDn, numJ bool, prms map[string]float64) { // set default values atol, rtol, ftol := 1e-8, 1e-8, 1e-9 o.LsMaxIt = 20 o.MaxIt = 20 o.ChkConv = true // read parameters for k, v := range prms { switch k { case "atol": atol = v case "rtol": rtol = v case "ftol": ftol = v case "lSearch": o.Lsearch = v > 0.0 case "lsMaxIt": o.LsMaxIt = int(v) case "maxIt": o.MaxIt = int(v) } } // set tolerances o.SetTols(atol, rtol, ftol, EPS) // auxiliary data o.neq = neq o.scal = make([]float64, o.neq) o.fx = make([]float64, o.neq) o.mdx = make([]float64, o.neq) // callbacks o.Ffcn, o.JfcnSp, o.JfcnDn = Ffcn, JfcnSp, JfcnDn // type of linear solver and Jacobian matrix (numerical or analytical: sparse only) o.useDn, o.numJ = useDn, numJ // use dense linear solver if o.useDn { o.J = la.MatAlloc(o.neq, o.neq) o.Ji = la.MatAlloc(o.neq, o.neq) // use sparse linear solver } else { o.Jtri.Init(o.neq, o.neq, o.neq*o.neq) if JfcnSp == nil { o.numJ = true } if o.numJ { o.w = make([]float64, o.neq) } o.lis = la.GetSolver("umfpack") } // allocate slices for line search o.dφdx = make([]float64, o.neq) o.x0 = make([]float64, o.neq) }
// Solve solves from (xa,ya) to (xb,yb) => find yb (stored in y) func (o *ODE) Solve(y []float64, x, xb, Δx float64, fixstp bool, args ...interface{}) (err error) { // check if xb < x { err = chk.Err(_ode_err3, xb, x) return } // derived variables o.fnewt = max(10.0*o.ϵ/o.Rtol, min(0.03, math.Sqrt(o.Rtol))) // initial step size Δx = min(Δx, xb-x) if fixstp { o.h = Δx } else { o.h = min(Δx, o.IniH) } o.hprev = o.h // output initial state if o.out != nil { o.out(true, o.h, x, y, args...) } // stat variables o.nfeval = 0 o.njeval = 0 o.nsteps = 0 o.naccepted = 0 o.nrejected = 0 o.ndecomp = 0 o.nlinsol = 0 o.nitmax = 0 // control variables o.doinit = true o.first = true o.last = false o.reject = false o.diverg = false o.dvfac = 0 o.η = 1.0 o.jacIsOK = false o.reuseJdec = false o.reuseJ = false o.nit = 0 o.hopt = o.h o.θ = o.θmax // local error indicator var rerr float64 // linear solver lsname := "umfpack" if o.Distr { lsname = "mumps" } o.lsolR = la.GetSolver(lsname) o.lsolC = la.GetSolver(lsname) // clean up and show stat before leaving defer func() { o.lsolR.Clean() o.lsolC.Clean() if !o.silent { o.Stat() } }() // first scaling variable la.VecScaleAbs(o.scal, o.Atol, o.Rtol, y) // o.scal := o.Atol + o.Rtol * abs(y) // fixed steps if fixstp { la.VecCopy(o.w[0], 1, y) // copy initial values to worksapce if o.Verbose { io.Pfgreen("x = %v\n", x) } for x < xb { //if x + o.h > xb { o.h = xb - x } if o.jac == nil { // numerical Jacobian if o.method == "Radau5" { o.nfeval += 1 o.fcn(o.f0, x, y, args...) } } o.reuseJdec = false o.reuseJ = false o.jacIsOK = false o.step(o, y, x, args...) o.nsteps += 1 o.doinit = false o.first = false o.hprev = o.h x += o.h o.accept(o, y) if o.out != nil { o.out(false, o.h, x, y, args...) } if o.Verbose { io.Pfgreen("x = %v\n", x) } } return } // first function evaluation o.nfeval += 1 o.fcn(o.f0, x, y, args...) // o.f0 := f(x,y) // time loop var dxmax, xstep, fac, div, dxnew, facgus, old_h, old_rerr float64 var dxratio float64 var failed bool for x < xb { dxmax, xstep = Δx, x+Δx failed = false for iss := 0; iss < o.NmaxSS+1; iss++ { // total number of substeps o.nsteps += 1 // error: did not converge if iss == o.NmaxSS { failed = true break } // converged? if x-xstep >= 0.0 { break } // step update rerr, err = o.step(o, y, x, args...) // initialise only once o.doinit = false // iterations diverging ? if o.diverg { o.diverg = false o.reject = true o.last = false o.h = o.dvfac * o.h continue } // step size change fac = min(o.Mfac, o.Mfac*float64(1+2*o.NmaxIt)/float64(o.nit+2*o.NmaxIt)) div = max(o.Mmin, min(o.Mmax, math.Pow(rerr, 0.25)/fac)) dxnew = o.h / div // accepted if rerr < 1.0 { // set flags o.naccepted += 1 o.first = false o.jacIsOK = false // update x and y o.hprev = o.h x += o.h o.accept(o, y) // output if o.out != nil { o.out(false, o.h, x, y, args...) } // converged ? if o.last { o.hopt = o.h // optimal h break } // predictive controller of Gustafsson if o.PredCtrl { if o.naccepted > 1 { facgus = (old_h / o.h) * math.Pow(math.Pow(rerr, 2.0)/old_rerr, 0.25) / o.Mfac facgus = max(o.Mmin, min(o.Mmax, facgus)) div = max(div, facgus) dxnew = o.h / div } old_h = o.h old_rerr = max(1.0e-2, rerr) } // calc new scal and f0 la.VecScaleAbs(o.scal, o.Atol, o.Rtol, y) // o.scal := o.Atol + o.Rtol * abs(y) o.nfeval += 1 o.fcn(o.f0, x, y, args...) // o.f0 := f(x,y) // new step size dxnew = min(dxnew, dxmax) if o.reject { // do not alow o.h to grow if previous was a reject dxnew = min(o.h, dxnew) } o.reject = false // do not reuse current Jacobian and decomposition by default o.reuseJdec = false // last step ? if x+dxnew-xstep >= 0.0 { o.last = true o.h = xstep - x } else { dxratio = dxnew / o.h o.reuseJdec = (o.θ <= o.θmax && dxratio >= o.C1h && dxratio <= o.C2h) if !o.reuseJdec { o.h = dxnew } } // check θ to decide if at least the Jacobian can be reused if !o.reuseJdec { o.reuseJ = (o.θ <= o.θmax) } // rejected } else { // set flags if o.naccepted > 0 { o.nrejected += 1 } o.reject = true o.last = false // new step size if o.first { o.h = 0.1 * o.h } else { o.h = dxnew } // last step if x+o.h > xstep { o.h = xstep - x } } } // sub-stepping failed if failed { err = chk.Err(_ode_err2, o.NmaxSS) break } } return }