Пример #1
0
func TestJacobian03(tst *testing.T) {

	//verbose()
	chk.PrintTitle("TestJacobian 03")

	// grid
	var g fdm.Grid2D
	//g.Init(1.0, 1.0, 4, 4)
	g.Init(1.0, 1.0, 6, 6)
	//g.Init(1.0, 1.0, 11, 11)

	// equations numbering
	var e fdm.Equations
	peq := utl.IntUnique(g.L, g.R, g.B, g.T)
	e.Init(g.N, peq)

	// K11 and K12
	var K11, K12 la.Triplet
	fdm.InitK11andK12(&K11, &K12, &e)

	// assembly
	F1 := make([]float64, e.N1)
	fdm.Assemble(&K11, &K12, F1, nil, &g, &e)

	// prescribed values
	U2 := make([]float64, e.N2)
	for _, eq := range g.L {
		U2[e.FR2[eq]] = 50.0
	}
	for _, eq := range g.R {
		U2[e.FR2[eq]] = 0.0
	}
	for _, eq := range g.B {
		U2[e.FR2[eq]] = 0.0
	}
	for _, eq := range g.T {
		U2[e.FR2[eq]] = 50.0
	}

	// functions
	k11 := K11.ToMatrix(nil)
	k12 := K12.ToMatrix(nil)
	ffcn := func(fU1, U1 []float64) error { // K11*U1 + K12*U2 - F1
		la.VecCopy(fU1, -1, F1)            // fU1 := (-F1)
		la.SpMatVecMulAdd(fU1, 1, k11, U1) // fU1 += K11*U1
		la.SpMatVecMulAdd(fU1, 1, k12, U2) // fU1 += K12*U2
		return nil
	}
	Jfcn := func(dfU1dU1 *la.Triplet, U1 []float64) error {
		fdm.Assemble(dfU1dU1, &K12, F1, nil, &g, &e)
		return nil
	}
	U1 := make([]float64, e.N1)
	CompareJac(tst, ffcn, Jfcn, U1, 0.0075)

	print_jac := false
	if print_jac {
		W1 := make([]float64, e.N1)
		fU1 := make([]float64, e.N1)
		ffcn(fU1, U1)
		var Jnum la.Triplet
		Jnum.Init(e.N1, e.N1, e.N1*e.N1)
		Jacobian(&Jnum, ffcn, U1, fU1, W1)
		la.PrintMat("K11 ", K11.ToMatrix(nil).ToDense(), "%g ", false)
		la.PrintMat("Jnum", Jnum.ToMatrix(nil).ToDense(), "%g ", false)
	}

	test_ffcn := false
	if test_ffcn {
		Uc := []float64{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, 25.0, 325.0 / 22.0, 100.0 / 11.0, 50.0 / 11.0,
			0.0, 50.0, 775.0 / 22.0, 25.0, 375.0 / 22.0, 100.0 / 11.0, 0.0, 50.0, 450.0 / 11.0, 725.0 / 22.0,
			25.0, 325.0 / 22.0, 0.0, 50.0, 500.0 / 11.0, 450.0 / 11.0, 775.0 / 22.0, 25.0, 0.0, 50.0, 50.0,
			50.0, 50.0, 50.0, 50.0,
		}
		for i := 0; i < e.N1; i++ {
			U1[i] = Uc[e.RF1[i]]
		}
		fU1 := make([]float64, e.N1)
		min, max := la.VecMinMax(fU1)
		io.Pf("min/max fU1 = %v\n", min, max)
	}
}
Пример #2
0
// ReadMsh reads a mesh for FE analyses
//  Note: returns nil on errors
func ReadMsh(dir, fn string) *Mesh {

	// new mesh
	var o Mesh

	// read file
	o.FnamePath = filepath.Join(dir, fn)
	b, err := io.ReadFile(o.FnamePath)
	if LogErr(err, "msh: cannot open mesh file "+o.FnamePath) {
		return nil
	}

	// decode
	if LogErr(json.Unmarshal(b, &o), "msh: cannot unmarshal mesh file "+fn+"\n") {
		return nil
	}

	// check
	if LogErrCond(len(o.Verts) < 2, "msh: mesh must have at least 2 vertices and 1 cell") {
		return nil
	}
	if LogErrCond(len(o.Cells) < 1, "msh: mesh must have at least 2 vertices and 1 cell") {
		return nil
	}

	// vertex related derived data
	o.Ndim = 2
	o.Xmin = o.Verts[0].C[0]
	o.Ymin = o.Verts[0].C[1]
	if len(o.Verts[0].C) > 2 {
		o.Zmin = o.Verts[0].C[2]
	}
	o.Xmax = o.Xmin
	o.Ymax = o.Ymin
	o.Zmax = o.Zmin
	o.VertTag2verts = make(map[int][]*Vert)
	for i, v := range o.Verts {

		// check vertex id
		if LogErrCond(v.Id != i, "msh: vertices must be sequentially numbered. %d != %d\n", v.Id, i) {
			return nil
		}

		// ndim
		nd := len(v.C)
		if LogErrCond(nd < 2 || nd > 4, "msh: ndim must be 2 or 3\n") {
			return nil
		}
		if nd == 3 {
			if math.Abs(v.C[2]) > Ztol {
				o.Ndim = 3
			}
		}

		// tags
		if v.Tag < 0 {
			verts := o.VertTag2verts[v.Tag]
			o.VertTag2verts[v.Tag] = append(verts, v)
		}

		// limits
		o.Xmin = min(o.Xmin, v.C[0])
		o.Xmax = max(o.Xmax, v.C[0])
		o.Ymin = min(o.Ymin, v.C[1])
		o.Ymax = max(o.Ymax, v.C[1])
		if nd > 2 {
			o.Zmin = min(o.Zmin, v.C[2])
			o.Zmax = max(o.Zmax, v.C[2])
		}
	}

	// derived data
	o.CellTag2cells = make(map[int][]*Cell)
	o.FaceTag2cells = make(map[int][]CellFaceId)
	o.FaceTag2verts = make(map[int][]int)
	o.SeamTag2cells = make(map[int][]CellSeamId)
	o.Ctype2cells = make(map[string][]*Cell)
	o.Part2cells = make(map[int][]*Cell)
	for i, c := range o.Cells {

		// check id and tag
		if LogErrCond(c.Id != i, "msh: cells must be sequentially numbered. %d != %d\n", c.Id, i) {
			return nil
		}
		if LogErrCond(c.Tag >= 0, "msh: cell tags must be negative\n") {
			return nil
		}

		// face tags
		cells := o.CellTag2cells[c.Tag]
		o.CellTag2cells[c.Tag] = append(cells, c)
		for i, ftag := range c.FTags {
			if ftag < 0 {
				pairs := o.FaceTag2cells[ftag]
				o.FaceTag2cells[ftag] = append(pairs, CellFaceId{c, i})
				for _, l := range shp.GetFaceLocalVerts(c.Type, i) {
					utl.IntIntsMapAppend(&o.FaceTag2verts, ftag, o.Verts[c.Verts[l]].Id)
				}
			}
		}

		// seam tags
		if o.Ndim == 3 {
			for i, stag := range c.STags {
				if stag < 0 {
					pairs := o.SeamTag2cells[stag]
					o.SeamTag2cells[stag] = append(pairs, CellSeamId{c, i})
				}
			}
		}

		// cell type => cells
		cells = o.Ctype2cells[c.Type]
		o.Ctype2cells[c.Type] = append(cells, c)

		// partition => cells
		cells = o.Part2cells[c.Part]
		o.Part2cells[c.Part] = append(cells, c)

		// get shape structure
		switch c.Type {
		case "joint":
			c.IsJoint = true
		default:
			c.Shp = shp.Get(c.Type)
			if LogErrCond(c.Shp == nil, "msh: cannot find shape type == %q\n", c.Type) {
				return nil
			}
		}
	}

	// remove duplicates
	for ftag, verts := range o.FaceTag2verts {
		o.FaceTag2verts[ftag] = utl.IntUnique(verts)
	}

	// log
	log.Printf("msh: fn=%s nverts=%d ncells=%d ncelltags=%d nfacetags=%d nseamtags=%d nverttags=%d ncelltypes=%d npart=%d\n", fn, len(o.Verts), len(o.Cells), len(o.CellTag2cells), len(o.FaceTag2cells), len(o.SeamTag2cells), len(o.VertTag2verts), len(o.Ctype2cells), len(o.Part2cells))
	return &o
}
Пример #3
0
func Test_nls04(tst *testing.T) {

	//verbose()
	chk.PrintTitle("nls04. finite differences problem")

	// grid
	var g fdm.Grid2D
	g.Init(1.0, 1.0, 6, 6)

	// equations numbering
	var e fdm.Equations
	peq := utl.IntUnique(g.L, g.R, g.B, g.T)
	e.Init(g.N, peq)

	// K11 and K12
	var K11, K12 la.Triplet
	fdm.InitK11andK12(&K11, &K12, &e)

	// assembly
	F1 := make([]float64, e.N1)
	fdm.Assemble(&K11, &K12, F1, nil, &g, &e)

	// prescribed values
	U2 := make([]float64, e.N2)
	for _, eq := range g.L {
		U2[e.FR2[eq]] = 50.0
	}
	for _, eq := range g.R {
		U2[e.FR2[eq]] = 0.0
	}
	for _, eq := range g.B {
		U2[e.FR2[eq]] = 0.0
	}
	for _, eq := range g.T {
		U2[e.FR2[eq]] = 50.0
	}

	// functions
	k11 := K11.ToMatrix(nil)
	k12 := K12.ToMatrix(nil)
	ffcn := func(fU1, U1 []float64) error { // K11*U1 + K12*U2 - F1
		la.VecCopy(fU1, -1, F1)            // fU1 := (-F1)
		la.SpMatVecMulAdd(fU1, 1, k11, U1) // fU1 += K11*U1
		la.SpMatVecMulAdd(fU1, 1, k12, U2) // fU1 += K12*U2
		return nil
	}
	Jfcn := func(dfU1dU1 *la.Triplet, U1 []float64) error {
		fdm.Assemble(dfU1dU1, &K12, F1, nil, &g, &e)
		return nil
	}
	JfcnD := func(dfU1dU1 [][]float64, U1 []float64) error {
		la.MatCopy(dfU1dU1, 1, K11.ToMatrix(nil).ToDense())
		return nil
	}

	prms := map[string]float64{
		"atol":    1e-8,
		"rtol":    1e-8,
		"ftol":    1e-12,
		"lSearch": 0.0,
	}

	// init
	var nls_sps NlSolver // sparse analytical
	var nls_num NlSolver // sparse numerical
	var nls_den NlSolver // dense analytical
	nls_sps.Init(e.N1, ffcn, Jfcn, nil, false, false, prms)
	nls_num.Init(e.N1, ffcn, nil, nil, false, true, prms)
	nls_den.Init(e.N1, ffcn, nil, JfcnD, true, false, prms)
	defer nls_sps.Clean()
	defer nls_num.Clean()
	defer nls_den.Clean()

	// results
	U1sps := make([]float64, e.N1)
	U1num := make([]float64, e.N1)
	U1den := make([]float64, e.N1)
	Usps := make([]float64, e.N)
	Unum := make([]float64, e.N)
	Uden := make([]float64, e.N)

	// solution
	Uc := []float64{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 50.0, 25.0, 325.0 / 22.0, 100.0 / 11.0, 50.0 / 11.0,
		0.0, 50.0, 775.0 / 22.0, 25.0, 375.0 / 22.0, 100.0 / 11.0, 0.0, 50.0, 450.0 / 11.0, 725.0 / 22.0,
		25.0, 325.0 / 22.0, 0.0, 50.0, 500.0 / 11.0, 450.0 / 11.0, 775.0 / 22.0, 25.0, 0.0, 50.0, 50.0,
		50.0, 50.0, 50.0, 50.0,
	}

	io.PfYel("\n---- sparse -------- Analytical Jacobian -------------------\n")

	// solve
	err := nls_sps.Solve(U1sps, false)
	if err != nil {
		chk.Panic(err.Error())
	}

	// check
	fdm.JoinVecs(Usps, U1sps, U2, &e)
	chk.Vector(tst, "Usps", 1e-14, Usps, Uc)

	// plot
	if false {
		g.Contour("results", "fig_t_heat_square", nil, Usps, 11, false)
	}

	io.PfYel("\n---- dense -------- Analytical Jacobian -------------------\n")

	// solve
	err = nls_den.Solve(U1den, false)
	if err != nil {
		chk.Panic(err.Error())
	}

	// check
	fdm.JoinVecs(Uden, U1den, U2, &e)
	chk.Vector(tst, "Uden", 1e-14, Uden, Uc)

	io.PfYel("\n---- sparse -------- Numerical Jacobian -------------------\n")

	// solve
	err = nls_num.Solve(U1num, false)
	if err != nil {
		chk.Panic(err.Error())
	}

	// check
	fdm.JoinVecs(Unum, U1num, U2, &e)
	chk.Vector(tst, "Unum", 1e-14, Unum, Uc)
}
Пример #4
0
// ReadMsh reads a mesh for FE analyses
//  Note: returns nil on errors
func ReadMsh(dir, fn string, goroutineId int) (o *Mesh, err error) {

	// new mesh
	o = new(Mesh)

	// read file
	o.FnamePath = filepath.Join(dir, fn)
	b, err := io.ReadFile(o.FnamePath)
	if err != nil {
		return
	}

	// decode
	err = json.Unmarshal(b, &o)
	if err != nil {
		return
	}

	// check
	if len(o.Verts) < 2 {
		err = chk.Err("at least 2 vertices are required in mesh\n")
		return
	}
	if len(o.Cells) < 1 {
		err = chk.Err("at least 1 cell is required in mesh\n")
		return
	}

	// variables for NURBS
	var controlpts [][]float64
	has_nurbs := false
	if len(o.Nurbss) > 0 {
		controlpts = make([][]float64, len(o.Verts))
		has_nurbs = true
	}

	// vertex related derived data
	o.Ndim = 2
	o.Xmin = o.Verts[0].C[0]
	o.Ymin = o.Verts[0].C[1]
	if len(o.Verts[0].C) > 2 {
		o.Zmin = o.Verts[0].C[2]
	}
	o.Xmax = o.Xmin
	o.Ymax = o.Ymin
	o.Zmax = o.Zmin
	o.VertTag2verts = make(map[int][]*Vert)
	for i, v := range o.Verts {

		// check vertex id
		if v.Id != i {
			err = chk.Err("vertices ids must coincide with order in \"verts\" list. %d != %d\n", v.Id, i)
			return
		}

		// ndim
		nd := len(v.C)
		if nd < 2 || nd > 4 {
			err = chk.Err("number of space dimensions must be 2, 3 or 4 (NURBS). %d is invalid\n", nd)
			return
		}
		if nd == 3 {
			if math.Abs(v.C[2]) > Ztol {
				o.Ndim = 3
			}
		}

		// tags
		if v.Tag < 0 {
			verts := o.VertTag2verts[v.Tag]
			o.VertTag2verts[v.Tag] = append(verts, v)
		}

		// limits
		o.Xmin = utl.Min(o.Xmin, v.C[0])
		o.Xmax = utl.Max(o.Xmax, v.C[0])
		o.Ymin = utl.Min(o.Ymin, v.C[1])
		o.Ymax = utl.Max(o.Ymax, v.C[1])
		if nd > 2 {
			o.Zmin = utl.Min(o.Zmin, v.C[2])
			o.Zmax = utl.Max(o.Zmax, v.C[2])
		}

		// control points to initialise NURBS
		if has_nurbs {
			controlpts[i] = make([]float64, 4)
			for j := 0; j < 4; j++ {
				controlpts[i][j] = v.C[j]
			}
		}
	}

	// allocate NURBSs
	o.PtNurbs = make([]*gm.Nurbs, len(o.Nurbss))
	o.NrbFaces = make([][]*gm.Nurbs, len(o.Nurbss))
	for i, d := range o.Nurbss {
		o.PtNurbs[i] = new(gm.Nurbs)
		o.PtNurbs[i].Init(d.Gnd, d.Ords, d.Knots)
		o.PtNurbs[i].SetControl(controlpts, d.Ctrls)
		o.NrbFaces[i] = o.PtNurbs[i].ExtractSurfaces()
	}

	// derived data
	o.CellTag2cells = make(map[int][]*Cell)
	o.FaceTag2cells = make(map[int][]CellFaceId)
	o.FaceTag2verts = make(map[int][]int)
	o.SeamTag2cells = make(map[int][]CellSeamId)
	o.Ctype2cells = make(map[string][]*Cell)
	o.Part2cells = make(map[int][]*Cell)
	for i, c := range o.Cells {

		// check id and tag
		if c.Id != i {
			err = chk.Err("cells ids must coincide with order in \"verts\" list. %d != %d\n", c.Id, i)
			return
		}
		if c.Tag >= 0 {
			err = chk.Err("cells tags must be negative. %d is incorrect\n", c.Tag)
			return
		}

		// get shape structure
		switch c.Type {
		case "joint":
			c.IsJoint = true
		case "nurbs":
			c.Shp = shp.GetShapeNurbs(o.PtNurbs[c.Nrb], o.NrbFaces[c.Nrb], c.Span)
			if c.Shp == nil {
				err = chk.Err("cannot allocate \"shape\" structure for cell type = %q\n", c.Type)
				return
			}
		default:
			c.Shp = shp.Get(c.Type, goroutineId)
			if c.Shp == nil {
				err = chk.Err("cannot allocate \"shape\" structure for cell type = %q\n", c.Type)
				return
			}
		}
		c.GoroutineId = goroutineId

		// face tags
		cells := o.CellTag2cells[c.Tag]
		o.CellTag2cells[c.Tag] = append(cells, c)
		for i, ftag := range c.FTags {
			if ftag < 0 {
				pairs := o.FaceTag2cells[ftag]
				o.FaceTag2cells[ftag] = append(pairs, CellFaceId{c, i})
				for _, l := range c.Shp.FaceLocalVerts[i] {
					utl.IntIntsMapAppend(&o.FaceTag2verts, ftag, o.Verts[c.Verts[l]].Id)
				}
			}
		}

		// seam tags
		if o.Ndim == 3 {
			for i, stag := range c.STags {
				if stag < 0 {
					pairs := o.SeamTag2cells[stag]
					o.SeamTag2cells[stag] = append(pairs, CellSeamId{c, i})
				}
			}
		}

		// cell type => cells
		cells = o.Ctype2cells[c.Type]
		o.Ctype2cells[c.Type] = append(cells, c)

		// partition => cells
		cells = o.Part2cells[c.Part]
		o.Part2cells[c.Part] = append(cells, c)
	}

	// remove duplicates
	for ftag, verts := range o.FaceTag2verts {
		o.FaceTag2verts[ftag] = utl.IntUnique(verts)
	}

	// results
	return
}