Exemple #1
0
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)
}
Exemple #2
0
// 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
}
Exemple #3
0
// 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")
}
Exemple #4
0
// 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
}
Exemple #5
0
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)
}
Exemple #6
0
// 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)
}
Exemple #7
0
// 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
}