Пример #1
0
// ReadMsh reads .msh file
func ReadMsh(fnk string) (nurbss []*Nurbs) {

	// read file
	fn := fnk + ".msh"
	buf, err := io.ReadFile(fn)
	if err != nil {
		chk.Panic("ReadMsh cannot read file = '%s', %v'", fn, err)
	}

	// decode
	var dat Data
	err = json.Unmarshal(buf, &dat)
	if err != nil {
		chk.Panic("ReadMsh cannot unmarshal file = '%s', %v'", fn, err)
	}

	// list of vertices
	verts := make([][]float64, len(dat.Verts))
	for i, _ := range dat.Verts {
		verts[i] = make([]float64, 4)
		for j := 0; j < 4; j++ {
			verts[i][j] = dat.Verts[i].C[j]
		}
	}

	// allocate NURBSs
	nurbss = make([]*Nurbs, len(dat.Nurbss))
	for i, v := range dat.Nurbss {
		nurbss[i] = new(Nurbs)
		nurbss[i].Init(v.Gnd, v.Ords, v.Knots)
		nurbss[i].SetControl(verts, v.Ctrls)
	}
	return
}
Пример #2
0
func PyFile(filename string) {
	b, err := io.ReadFile(filename)
	if err != nil {
		chk.Panic("PyFile failed:\n%v", err)
	}
	io.Ff(&bb, string(b))
}
Пример #3
0
// Read reads configuration parameters from JSON file
func (o *Parameters) Read(filenamepath string) {
	o.Default()
	b, err := io.ReadFile(filenamepath)
	if err != nil {
		chk.Panic("cannot read parameters file %q", filenamepath)
	}
	err = json.Unmarshal(b, o)
	if err != nil {
		chk.Panic("cannot unmarshal parameters file %q", filenamepath)
	}
	return
}
Пример #4
0
// NewData allocates and initialises a new FEM data structure
func NewData(fnkey string, cpu int) *FemData {

	// load data
	var o FemData
	buf, err := io.ReadFile("od-" + fnkey + ".json")
	if err != nil {
		chk.Panic("cannot load data:\n%v", err)
	}
	err = json.Unmarshal(buf, &o)
	if err != nil {
		chk.Panic("cannot unmarshal data:\n%v", err)
	}

	// load FEM data
	o.Analysis = fem.NewMain(fnkey+".sim", io.Sf("cpu%d", cpu), false, false, false, false, false, cpu)
	o.Dom = o.Analysis.Domains[0]
	o.Sim = o.Dom.Sim
	o.Vars = o.Dom.Sim.AdjRandom

	// backup dependent variables
	for _, prm := range o.Sim.AdjDependent {
		prm.S = prm.V // copy V into S
	}

	// set stage
	err = o.Analysis.SetStage(0)
	if err != nil {
		chk.Panic("cannot set stage:\n%v", err)
	}

	// equations to track U
	verts := o.Dom.Msh.Verts
	if o.VtagU < 0 {
		verts = o.Dom.Msh.VertTag2verts[o.VtagU]
		if len(verts) < 1 {
			chk.Panic("cannot find vertices with tag = %d\n", o.VtagU)
		}
	}
	o.EqsU = make([]int, len(verts))
	for i, vert := range verts {
		eq := o.Dom.Vid2node[vert.Id].GetEq(o.Ukey)
		if eq < 0 {
			chk.Panic("cannot find equation corresponding to vertex id=%d and ukey=%q", vert.Id, o.Ukey)
		}
		o.EqsU[i] = eq
	}
	return &o
}
Пример #5
0
func read_pyfem_rod_data(fn string) []PyfemRodData {

	// read file
	b, err := io.ReadFile(fn)
	if err != nil {
		chk.Panic("%v\n", err.Error())
	}

	// decode
	var dat []PyfemRodData
	err = json.Unmarshal(b, &dat)
	if err != nil {
		chk.Panic("%v\n", err.Error())
	}
	return dat
}
Пример #6
0
// ReadJson reads json file
func (o *Path) ReadJson(ndim int, fname string) (err error) {

	// read file
	b, err := io.ReadFile(fname)
	if err != nil {
		return chk.Err(_path_err11, fname, err)
	}

	// decode
	err = json.Unmarshal(b, o)
	if err != nil {
		return chk.Err(_path_err12, fname, err)
	}

	// set additional information
	return o.Init(ndim)
}
Пример #7
0
func main() {

	// filename
	filename, fnkey := io.ArgToFilename(0, "sg1121", ".sim", true)

	// results
	out.Start(filename, 0, 0)
	out.Define("A", out.N{30})
	out.LoadResults(nil)

	// plot FEM results
	out.Plot("t", "uy", "A", plt.Fmt{C: "k", Ls: "-", L: "gofem"}, -1)

	// old results
	b, err := io.ReadFile("cmp/sg1121gofemold.json")
	if err != nil {
		io.PfRed("cannot read comparison file\n")
		return
	}
	var gofemold struct {
		Time, Uy30 []float64
	}
	err = json.Unmarshal(b, &gofemold)
	if err != nil {
		io.PfRed("cannot unmarshal comparison file\n")
		return
	}

	// mechsys results
	_, res, err := io.ReadTable("cmp/sg1121mechsysN30.cmp")
	if err != nil {
		io.PfRed("cannot read mechsys comparison file\n")
		return
	}

	// save
	plt.SetForPng(0.8, 400, 200)
	out.Draw("/tmp", fnkey+".png", false, func(i, j, n int) {
		plt.Plot(gofemold.Time, gofemold.Uy30, "'r-', lw=2, label='gofemOld'")
		plt.Plot(res["Time"], res["uy"], "'b-', label='mechsys'")
	})
}
Пример #8
0
// ReadMat reads all materials data from a .mat JSON file
//  Note: returns nil on errors
func ReadMat(dir, fn string) *MatDb {

	// new mat
	var o MatDb

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

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

	// results
	return &o
}
Пример #9
0
// ReadMat reads all materials data from a .mat JSON file
//  Note: returns nil on errors
func ReadMat(dir, fn string) *MatDb {

	// new mat
	var o MatDb

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

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

	// log
	log.Printf("mat: fn=%s nfunctions=%d nmaterials=%d\n", fn, len(o.Functions), len(o.Materials))
	return &o
}
Пример #10
0
// Read reads mesh
func Read(fn string) (o *Mesh, err error) {

	// new mesh
	o = new(Mesh)

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

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

	// check
	err = o.Check()
	return
}
Пример #11
0
// ReadConfParams reads configuration parameters from JSON file
func ReadConfParams(filenamepath string) *ConfParams {

	// new params
	var o ConfParams
	o.SetDefault()

	// read file
	b, err := io.ReadFile(filenamepath)
	if err != nil {
		chk.Panic("cannot read parameters file %q", filenamepath)
	}

	// decode
	err = json.Unmarshal(b, &o)
	if err != nil {
		chk.Panic("cannot unmarshal parameters file %q", filenamepath)
	}

	// results
	o.CalcDerived()
	return &o
}
Пример #12
0
func Test_step02(tst *testing.T) {

	//verbose()
	chk.PrintTitle("step02")

	buf, err := io.ReadFile("data/beadpanel.step")
	if err != nil {
		tst.Errorf("cannot read file:\n%v", err)
		return
	}
	dat := string(buf)

	var stp STEP
	err = stp.ParseDATA(dat)
	if err != nil {
		tst.Errorf("Parse filed:\n%v", err)
		return
	}

	for _, c := range stp.BScurves {
		io.Pforan("c = %v\n", c)
	}
}
Пример #13
0
// MatfileNew2Old converts a new mat file to the old mat file format
//  convertsymbols -- convert back symbols with Greek characters to UTF-8
func MatfileNew2Old(dirout string, fnold, fnnew string, convertsymbols bool) {

	// read file
	b, err := io.ReadFile(fnnew)
	if err != nil {
		io.PfRed("cannot open file: %v", err.Error())
		return
	}

	// decode
	var mats_new MatDb
	err = json.Unmarshal(b, &mats_new)
	if err != nil {
		io.PfRed("cannot unmarshal file: %v", err.Error())
		return
	}

	// oldmatdata implements the old data format
	type oldmatdata struct {
		Name  string
		Desc  string
		Model string
		Prms  []string
		Vals  []float64
		Units []string
		Extra string
	}

	// convert
	var mats_old []oldmatdata
	for _, m := range mats_new.Materials {
		var oldmat oldmatdata
		oldmat.Name = m.Name
		oldmat.Desc = m.Desc
		oldmat.Model = m.Model
		oldmat.Extra = m.Extra
		for _, prm := range m.Prms {
			name := prm.N
			if convertsymbols {
				if n, ok := invertedconversiontable[prm.N]; ok {
					name = n
				}
			}
			oldmat.Prms = append(oldmat.Prms, name)
			oldmat.Vals = append(oldmat.Vals, prm.V)
			if len(prm.U) > 0 {
				oldmat.Units = append(oldmat.Units, prm.U)
			}
		}
		mats_old = append(mats_old, oldmat)
	}

	// encode
	buf, err := json.MarshalIndent(mats_old, "", "  ")
	if err != nil {
		return
	}

	// save file
	if dirout == "" {
		io.WriteFileS(fnold, string(buf))
		return
	}
	io.WriteFileSD(dirout, fnold, string(buf))
}
Пример #14
0
// MatfileOld2New converts an old mat file to new mat file format
//  convertsymbols -- convert symbols with Greek characters to ANSI
func MatfileOld2New(dirout string, fnnew, fnold string, convertsymbols bool) {

	// oldmatdata implements the old data format
	type oldmatdata struct {
		Name  string
		Desc  string
		Model string
		Prms  []string
		Vals  []float64
		Units []string
		Extra string
	}

	// data holder
	var mats_old []oldmatdata

	// read file
	b, err := io.ReadFile(fnold)
	if err != nil {
		chk.Panic("cannot open file: %v", err.Error())
	}

	// decode
	err = json.Unmarshal(b, &mats_old)
	if err != nil {
		chk.Panic("cannot unmarshal file: %v", err.Error())
	}

	// new data holder
	var mats_new MatDb
	for _, m := range mats_old {
		prms := []*fun.Prm{}
		has_units := len(m.Units) == len(m.Prms)
		for i, prm := range m.Prms {
			name := prm
			if convertsymbols {
				if n, ok := conversiontable[prm]; ok {
					name = n
				}
			}
			if has_units {
				prms = append(prms, &fun.Prm{N: name, V: m.Vals[i], U: m.Units[i]})
			} else {
				prms = append(prms, &fun.Prm{N: name, V: m.Vals[i]})
			}
		}
		mat_new := Material{
			Name:  m.Name,
			Desc:  m.Desc,
			Model: m.Model,
			Extra: m.Extra,
			Prms:  prms,
		}
		mats_new.Materials = append(mats_new.Materials, &mat_new)
	}

	// save file
	if dirout == "" {
		io.WriteFileS(fnnew, mats_new.String())
		return
	}
	io.WriteFileSD(dirout, fnnew, mats_new.String())
}
Пример #15
0
// NewData allocates and initialises a new FEM data structure
func NewData(filename, fnkey string, cpu int) *FemData {

	// load opt data
	var o FemData
	buf, err := io.ReadFile("od-" + fnkey + ".json")
	if err != nil {
		chk.Panic("cannot load opt data:\n%v", err)
	}
	err = json.Unmarshal(buf, &o.Opt)
	if err != nil {
		chk.Panic("cannot unmarshal opt data:\n%v", err)
	}
	o.Opt.CalcDerived()

	// load FEM data
	o.Analysis = fem.NewFEM(filename, io.Sf("cpu%d", cpu), false, false, false, false, false, cpu)
	o.Reg = o.Analysis.Sim.Regions[0]
	o.Dom = o.Analysis.Domains[0]

	// required vertices
	for _, vtag := range o.Opt.ReqVtags {
		verts := o.Dom.Msh.VertTag2verts[vtag]
		for _, vert := range verts {
			o.ReqVids = append(o.ReqVids, vert.Id)
		}
	}

	// groups
	o.Ncells = len(o.Dom.Msh.Cells)
	o.Cid2xid = make([]int, o.Ncells)
	if o.Opt.Groups {
		o.Nareas = len(o.Dom.Msh.CellTag2cells)
		for tag, cells := range o.Dom.Msh.CellTag2cells {
			xid := -tag - 1
			for _, cell := range cells {
				o.Cid2xid[cell.Id] = xid
			}
		}
	} else { // all cells
		o.Nareas = o.Ncells
		for i, _ := range o.Dom.Msh.Cells {
			o.Cid2xid[i] = i
		}
	}

	// vertex to track deflection
	o.VidU = -1 // allvertices
	if o.Opt.VtagU < 0 {
		verts := o.Dom.Msh.VertTag2verts[o.Opt.VtagU]
		if len(verts) != 1 {
			chk.Panic("cannot set vertex to track deflection: verts = %v", verts)
		}
		o.VidU = verts[0].Id
	}

	// compute max weight
	o.Analysis.SetStage(0)
	for _, elem := range o.Dom.Elems {
		ele := elem.(*fem.ElastRod)
		o.MaxWeight += ele.Mdl.Rho * ele.Mdl.A * ele.L
	}
	return &o
}
Пример #16
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
}
Пример #17
0
// testing_compare_results_u compares results with u-formulation
func TestingCompareResultsU(tst *testing.T, simfname, cmpfname string, tolK, tolu, tols float64, skipK, verbose bool) {

	// only root can run this test
	if !Global.Root {
		return
	}

	// read summary
	sum := ReadSum(Global.Dirout, Global.Fnkey)
	if sum == nil {
		tst.Error("cannot read summary file for simulation=%q\n", simfname)
		return
	}

	// allocate domain
	distr := false
	d := NewDomain(Global.Sim.Regions[0], distr)
	if !d.SetStage(0, Global.Sim.Stages[0], distr) {
		tst.Errorf("TestingCompareResultsU: SetStage failed\n")
		return
	}

	// read file
	buf, err := io.ReadFile(cmpfname)
	if err != nil {
		tst.Errorf("TestingCompareResultsU: ReadFile failed\n")
		return
	}

	// unmarshal json
	var cmp_set T_results_set
	err = json.Unmarshal(buf, &cmp_set)
	if err != nil {
		tst.Errorf("TestingCompareResultsU: Unmarshal failed\n")
		return
	}

	// run comparisons
	dmult := 1.0
	for idx, cmp := range cmp_set {

		// displacements multiplier
		if idx == 0 && math.Abs(cmp.DispMult) > 1e-10 {
			dmult = cmp.DispMult
		}

		// time index
		tidx := idx + 1
		if verbose {
			io.PfYel("\n\ntidx = %d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n", tidx)
		}

		// load gofem results
		if !d.In(sum, tidx, true) {
			tst.Errorf("TestingCompareResultsU: reading of results failed\n")
			return
		}
		if verbose {
			io.Pfyel("time = %v\n", d.Sol.T)
		}

		// check K matrices
		if !skipK {
			if verbose {
				io.Pfgreen(". . . checking K matrices . . .\n")
			}
			for eid, Ksg := range cmp.Kmats {
				if e, ok := d.Elems[eid].(*ElemU); ok {
					if !e.AddToKb(d.Kb, d.Sol, true) {
						tst.Errorf("TestingCompareResultsU: AddToKb failed\n")
						return
					}
					chk.Matrix(tst, io.Sf("K%d", eid), tolK, e.K, Ksg)
				}
			}
		}

		// check displacements
		if verbose {
			io.Pfgreen(". . . checking displacements . . .\n")
		}
		for nid, usg := range cmp.Disp {
			ix := d.Vid2node[nid].Dofs[0].Eq
			iy := d.Vid2node[nid].Dofs[1].Eq
			chk.AnaNum(tst, "ux", tolu, d.Sol.Y[ix], usg[0]*dmult, verbose)
			chk.AnaNum(tst, "uy", tolu, d.Sol.Y[iy], usg[1]*dmult, verbose)
			if len(usg) == 3 {
				iz := d.Vid2node[nid].Dofs[2].Eq
				chk.AnaNum(tst, "uz", tolu, d.Sol.Y[iz], usg[2]*dmult, verbose)
			}
		}

		// check stresses
		if true {
			if verbose {
				io.Pfgreen(". . . checking stresses . . .\n")
			}
			for eid, sig := range cmp.Sigmas {
				if verbose {
					io.Pforan("eid = %d\n", eid)
				}
				if e, ok := d.Cid2elem[eid].(*ElemU); ok {
					for ip, val := range sig {
						if verbose {
							io.Pfgrey2("ip = %d\n", ip)
						}
						σ := e.States[ip].Sig
						if len(val) == 6 {
							chk.AnaNum(tst, "sx ", tols, σ[0], val[0], verbose)
							chk.AnaNum(tst, "sy ", tols, σ[1], val[1], verbose)
						} else {
							chk.AnaNum(tst, "sx ", tols, σ[0], val[0], verbose)
							chk.AnaNum(tst, "sy ", tols, σ[1], val[1], verbose)
							chk.AnaNum(tst, "sxy", tols, σ[3]/SQ2, val[2], verbose)
							if len(val) > 3 { // sx, sy, sxy, sz
								chk.AnaNum(tst, "sz ", tols, σ[2], val[3], verbose)
							}
						}
					}
				}
			}
		}
	}
}
Пример #18
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
}
Пример #19
0
// testing_compare_results_u compares results with u-formulation
func TestingCompareResultsU(tst *testing.T, simfilepath, cmpfname, alias string, tolK, tolu, tols float64, skipK, verbose bool) {

	// FEM structure
	fem := NewFEM(simfilepath, alias, false, false, true, false, verbose, 0)

	// set stage
	err := fem.SetStage(0)
	if err != nil {
		chk.Panic("cannot set stage:\n%v", err)
	}

	// zero solution
	err = fem.ZeroStage(0, true)
	if err != nil {
		chk.Panic("cannot zero stage data:\n%v", err)
	}

	// read file with comparison results
	buf, err := io.ReadFile(cmpfname)
	if err != nil {
		tst.Errorf("TestingCompareResultsU: ReadFile failed\n")
		return
	}

	// unmarshal json
	var cmp_set T_results_set
	err = json.Unmarshal(buf, &cmp_set)
	if err != nil {
		tst.Errorf("TestingCompareResultsU: Unmarshal failed\n")
		return
	}

	// run comparisons
	dom := fem.Domains[0]
	dmult := 1.0
	for idx, cmp := range cmp_set {

		// displacements multiplier
		if idx == 0 && math.Abs(cmp.DispMult) > 1e-10 {
			dmult = cmp.DispMult
		}

		// time index
		tidx := idx + 1
		if verbose {
			io.PfYel("\n\ntidx = %d . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n", tidx)
		}

		// load gofem results
		err = dom.Read(fem.Summary, tidx, 0, true)
		if err != nil {
			chk.Panic("cannot read 'gofem' results:\n%v", err)
		}
		if verbose {
			io.Pfyel("time = %v\n", dom.Sol.T)
		}

		// check K matrices
		if !skipK {
			if verbose {
				io.Pfgreen(". . . checking K matrices . . .\n")
			}
			for eid, Ksg := range cmp.Kmats {
				if e, ok := dom.Elems[eid].(*ElemU); ok {
					err = e.AddToKb(dom.Kb, dom.Sol, true)
					if err != nil {
						chk.Panic("TestingCompareResultsU: AddToKb failed\n")
					}
					chk.Matrix(tst, io.Sf("K%d", eid), tolK, e.K, Ksg)
				}
				if e, ok := dom.Elems[eid].(*Rod); ok {
					err = e.AddToKb(dom.Kb, dom.Sol, true)
					if err != nil {
						chk.Panic("TestingCompareResultsU: AddToKb failed\n")
					}
					chk.Matrix(tst, io.Sf("K%d", eid), tolK, e.K, Ksg)
				}
				if e, ok := dom.Elems[eid].(*ElastRod); ok {
					err = e.AddToKb(dom.Kb, dom.Sol, true)
					if err != nil {
						chk.Panic("TestingCompareResultsU: AddToKb failed\n")
					}
					chk.Matrix(tst, io.Sf("K%d", eid), tolK, e.K, Ksg)
				}
			}
		}

		// check displacements
		if verbose {
			io.Pfgreen(". . . checking displacements . . .\n")
		}
		for nid, usg := range cmp.Disp {
			ix := dom.Vid2node[nid].Dofs[0].Eq
			iy := dom.Vid2node[nid].Dofs[1].Eq
			chk.AnaNum(tst, "ux", tolu, dom.Sol.Y[ix], usg[0]*dmult, verbose)
			chk.AnaNum(tst, "uy", tolu, dom.Sol.Y[iy], usg[1]*dmult, verbose)
			if len(usg) == 3 {
				iz := dom.Vid2node[nid].Dofs[2].Eq
				chk.AnaNum(tst, "uz", tolu, dom.Sol.Y[iz], usg[2]*dmult, verbose)
			}
		}

		// check stresses
		if true {
			if verbose {
				io.Pfgreen(". . . checking stresses . . .\n")
			}
			for eid, sig := range cmp.Sigmas {
				if verbose {
					io.Pforan("eid = %d\n", eid)
				}
				if e, ok := dom.Cid2elem[eid].(*ElemU); ok {
					for ip, val := range sig {
						if verbose {
							io.Pfgrey2("ip = %d\n", ip)
						}
						σ := e.States[ip].Sig
						if len(val) == 6 {
							chk.AnaNum(tst, "sx ", tols, σ[0], val[0], verbose)
							chk.AnaNum(tst, "sy ", tols, σ[1], val[1], verbose)
						} else {
							chk.AnaNum(tst, "sx ", tols, σ[0], val[0], verbose)
							chk.AnaNum(tst, "sy ", tols, σ[1], val[1], verbose)
							chk.AnaNum(tst, "sxy", tols, σ[3]/SQ2, val[2], verbose)
							if len(val) > 3 { // sx, sy, sxy, sz
								chk.AnaNum(tst, "sz ", tols, σ[2], val[3], verbose)
							}
						}
					}
				}
				if e, ok := dom.Cid2elem[eid].(*Rod); ok {
					for ip, val := range sig {
						if verbose {
							io.Pfgrey2("ip = %d\n", ip)
						}
						σ := e.States[ip].Sig
						chk.AnaNum(tst, "sig", tols, σ, val[0], verbose)
					}
				}
				if e, ok := dom.Cid2elem[eid].(*ElastRod); ok {
					dat := e.OutIpsData()
					for ip, val := range sig {
						if verbose {
							io.Pfgrey2("ip = %d\n", ip)
						}
						res := dat[ip].Calc(dom.Sol)
						σ := res["sig"]
						chk.AnaNum(tst, "sig", tols, σ, val[0], verbose)
					}
				}
			}
		}
	}
}
Пример #20
0
func test_rwstep01(tst *testing.T) {

	verbose()
	chk.PrintTitle("rwstep01")

	buf, err := io.ReadFile("rw/data/beadpanel.step")
	if err != nil {
		tst.Errorf("cannot read file:\n%v", err)
		return
	}
	dat := string(buf)

	var stp rw.STEP
	err = stp.ParseDATA(dat)
	if err != nil {
		tst.Errorf("Parse filed:\n%v", err)
		return
	}

	var bsplines []*Bspline

	for _, scurve := range stp.Scurves {
		curve := stp.BScurves[scurve.Curve_3d]
		if curve == nil {
			continue
		}

		// collect vertices
		nv := len(curve.Control_points_list)
		verts := utl.DblsAlloc(nv, 4)
		for i, key := range curve.Control_points_list {
			if p, ok := stp.Points[key]; ok {
				for j := 0; j < 3; j++ {
					verts[i][j] = p.Coordinates[j]
				}
				verts[i][3] = 1.0
			} else {
				chk.Panic("cannot find point %q", key)
			}
		}

		// collect knots
		nk := 0
		for _, m := range curve.Knot_multiplicities {
			nk += m
		}
		knots := make([]float64, nk)
		k := 0
		for i, u := range curve.Knots {
			m := curve.Knot_multiplicities[i]
			for j := 0; j < m; j++ {
				knots[k] = u
				k++
			}
		}

		// create B-spline
		bsp := new(Bspline)
		bsp.Init(knots, curve.Degree)
		bsp.SetControl(verts)
		bsplines = append(bsplines, bsp)
	}

	if true {
		io.Pforan("n = %v\n", len(bsplines))
		for i, bsp := range bsplines {
			bsp.Draw3d("", "", 21, i == 0)
		}
		//plt.Show()
	}
}
Пример #21
0
func Test_sg1121(tst *testing.T) {

	//verbose()
	chk.PrintTitle("sg1121")

	// run simulation
	if !Start("data/sg1121.sim", true, chk.Verbose) {
		tst.Errorf("test failed\n")
		return
	}

	// make sure to flush log
	defer End()

	// run simulation
	if !Run() {
		tst.Errorf("test failed\n")
		return
	}

	// plot
	doplot := false
	if doplot {

		// read summary
		sum := ReadSum(Global.Dirout, Global.Fnkey)

		// allocate domain
		distr := false
		d := NewDomain(Global.Sim.Regions[0], distr)
		if !d.SetStage(0, Global.Sim.Stages[0], distr) {
			tst.Errorf("SetStage failed\n")
			return
		}

		// selected node and dof index
		nidx := 30
		didx := 1

		// new results
		ntout := len(sum.OutTimes)
		uy := make([]float64, ntout)
		for tidx := 0; tidx < ntout; tidx++ {
			if !d.ReadSol(sum.Dirout, sum.Fnkey, tidx) {
				tst.Errorf("test failed:\n")
				return
			}
			nod := d.Nodes[nidx]
			eq := nod.Dofs[didx].Eq
			uy[tidx] = d.Sol.Y[eq]
			// check
			if math.Abs(d.Sol.T-sum.OutTimes[tidx]) > 1e-14 {
				tst.Errorf("output times do not match time in solution array")
				return
			}
		}
		plt.Plot(sum.OutTimes, uy, "'k*-', clip_on=0, label='gofem'")

		// old results
		b, err := io.ReadFile("cmp/sg1121gofemold.json")
		if err != nil {
			tst.Errorf("cannot read comparison file\n")
			return
		}
		var gofemold struct {
			Time, Uy30 []float64
		}
		err = json.Unmarshal(b, &gofemold)
		if err != nil {
			tst.Errorf("cannot unmarshal comparison file\n")
			return
		}
		plt.Plot(gofemold.Time, gofemold.Uy30, "'ro-', label='gofemOld'")

		// mechsys results
		_, res, err := io.ReadTable("cmp/sg1121mechsysN30.cmp")
		if err != nil {
			tst.Errorf("cannot read mechsys comparison file\n")
			return
		}
		plt.Plot(res["Time"], res["uy"], "'b+-', label='mechsys'")

		// show figure
		plt.Gll("$t$", "$u_y$", "")
		plt.Show()
	}
}
Пример #22
0
func main() {

	// read README.md file
	md, err := io.ReadFile("README.md")
	if err != nil {
		io.PfRed("cannot read README.md\n")
		return
	}

	// process markdown
	//html := string(blackfriday.MarkdownCommon(md))

	flags := 0 |
		blackfriday.HTML_USE_XHTML |
		blackfriday.HTML_USE_SMARTYPANTS |
		blackfriday.HTML_SMARTYPANTS_LATEX_DASHES

	extensions := 0 |
		blackfriday.EXTENSION_NO_INTRA_EMPHASIS |
		blackfriday.EXTENSION_TABLES |
		blackfriday.EXTENSION_FENCED_CODE |
		blackfriday.EXTENSION_AUTOLINK |
		blackfriday.EXTENSION_STRIKETHROUGH |
		blackfriday.EXTENSION_SPACE_HEADERS |
		blackfriday.EXTENSION_HEADER_IDS |
		blackfriday.EXTENSION_BACKSLASH_LINE_BREAK |
		blackfriday.EXTENSION_DEFINITION_LISTS

	renderer := blackfriday.HtmlRenderer(flags, "", "")
	html := string(blackfriday.MarkdownOptions(md, renderer, blackfriday.Options{Extensions: extensions}))

	// environment variable => figures path
	path := os.ExpandEnv("${GOPATH}/src/github.com/cpmech/gofem/")
	io.Pforan("path = %v\n", path)

	// set path of figures
	html = strings.Replace(html, "img src=\"", io.Sf("img src=\"%s/examples/", path), -1)

	// set header and footer
	html = `<!DOCTYPE HTML>
<html>
<head>
<title>Gofem &ndash; Examples</title>
<meta charset="utf-8" />

<style>
h1 {color:#0064cb; font-family:verdana; font-size:200%;}
h2 {color:#0064cb}
h3 {color:#0064cb}
a:hover {background-color:#5397dc;}
#container {
	width:500px;
	text-align:center;
}
#container img {
	max-width:100%;
	height:auto;
}
</style>

</head>
<body>
` + html + `
</body>
</html>`

	// write file
	io.WriteFileVD("/tmp", "gofem-README.html", bytes.NewBuffer([]byte(html)))
	//io.WriteFileVD("/tmp", "gofem-README.html", bytes.NewBuffer(html))
}
Пример #23
0
// ReadSim reads all simulation data from a .sim JSON file
//  Notes:  1) this function initialises log file
//          2) returns nil on errors
func ReadSim(dir, fn, logPrefix string, erasefiles bool) *Simulation {

	// new sim
	var o Simulation

	// read file
	b, err := io.ReadFile(filepath.Join(dir, fn))
	if err != nil {
		io.PfRed("sim: cannot read simulation file %s/%s\n%v\n", dir, fn, err)
		return nil
	}

	// set default values
	o.Data.SetDefault()
	o.Solver.SetDefault()
	o.LinSol.SetDefault()

	// decode
	err = json.Unmarshal(b, &o)
	if err != nil {
		io.PfRed("sim: cannot unmarshal simulation file %s/%s\n%v\n", dir, fn, err)
		return nil
	}

	// derived data
	o.Data.PostProcess(dir, fn, erasefiles)
	o.LinSol.PostProcess()
	o.Solver.PostProcess()

	// init log file
	err = InitLogFile(o.Data.DirOut, logPrefix+o.Data.FnameKey)
	if err != nil {
		io.PfRed("sim: cannot create log file\n%v", err)
		return nil
	}

	// read materials database
	o.Mdb = ReadMat(o.Data.FnameDir, o.Data.Matfile)
	if LogErrCond(o.Mdb == nil, "sim: cannot read materials file") {
		return nil
	}

	// for all regions
	for i, reg := range o.Regions {

		// read mesh
		reg.Msh = ReadMsh(o.Data.FnameDir, reg.Mshfile)
		if LogErrCond(reg.Msh == nil, "cannot read mesh file") {
			return nil
		}

		// dependent variables
		reg.etag2idx = make(map[int]int)
		for j, ed := range reg.ElemsData {
			reg.etag2idx[ed.Tag] = j
		}

		// get ndim and max elevation
		if i == 0 {
			o.Ndim = reg.Msh.Ndim
			o.MaxElev = reg.Msh.Ymax
			if o.Ndim == 3 {
				o.MaxElev = reg.Msh.Zmax
			}
		} else {
			if LogErrCond(reg.Msh.Ndim != o.Ndim, "all meshes must have the same ndim. %d != %d") {
				return nil
			}
			if o.Ndim == 2 {
				o.MaxElev = max(o.MaxElev, reg.Msh.Ymax)
			} else {
				o.MaxElev = max(o.MaxElev, reg.Msh.Zmax)
			}
		}

		// get water data
		for _, mat := range o.Mdb.Materials {
			if mat.Model == "porous" {
				if prm := mat.Prms.Find("RhoL0"); prm != nil {
					o.WaterRho0 = prm.V
				}
				if prm := mat.Prms.Find("BulkL"); prm != nil {
					o.WaterBulk = prm.V
				}
			}
		}
	}

	// water level
	o.WaterLevel = max(o.Data.Wlevel, o.MaxElev)

	// for all stages
	var t float64
	for i, stg := range o.Stages {

		// fix Tf
		if stg.Control.Tf < 1e-14 {
			stg.Control.Tf = 1
		}

		// fix Dt
		if stg.Control.DtFcn == "" {
			if stg.Control.Dt < 1e-14 {
				stg.Control.Dt = 1
			}
			stg.Control.DtFunc = &fun.Cte{C: stg.Control.Dt}
		} else {
			stg.Control.DtFunc = o.Functions.Get(stg.Control.DtFcn)
			if LogErrCond(stg.Control.DtFunc == nil, "sim: cannot get Dt function named %s\n", stg.Control.DtFcn) {
				return nil
			}
			stg.Control.Dt = stg.Control.DtFunc.F(t, nil)
		}

		// fix DtOut
		if stg.Control.DtoFcn == "" {
			if stg.Control.DtOut < 1e-14 {
				stg.Control.DtOut = stg.Control.Dt
				stg.Control.DtoFunc = stg.Control.DtFunc
			} else {
				if stg.Control.DtOut < stg.Control.Dt {
					stg.Control.DtOut = stg.Control.Dt
				}
				stg.Control.DtoFunc = &fun.Cte{C: stg.Control.DtOut}
			}
		} else {
			stg.Control.DtoFunc = o.Functions.Get(stg.Control.DtoFcn)
			if LogErrCond(stg.Control.DtoFunc == nil, "sim: cannot get DtOut function named %s\n", stg.Control.DtoFcn) {
				return nil
			}
			stg.Control.DtOut = stg.Control.DtoFunc.F(t, nil)
		}

		// first stage
		if i == 0 {

			// gravity
			for _, econd := range stg.EleConds {
				for j, key := range econd.Keys {
					if key == "g" {
						if o.Gfcn == nil {
							o.Gfcn = o.Functions.Get(econd.Funcs[j])
							if LogErrCond(o.Gfcn == nil, "sim: cannot find gravity function in functions database") {
								return nil
							}
							break
						}
					}
				}
			}
			if o.Gfcn == nil {
				o.Gfcn = &fun.Cte{C: 10}
			}
		}

		// update time
		t += stg.Control.Tf
	}

	// log
	log.Printf("sim: file=%s/%s desc=%q nfunctions=%d nregions=%d nstages=%d linsol=%s itol=%g\n", dir, fn, o.Data.Desc, len(o.Functions), len(o.Regions), len(o.Stages), o.LinSol.Name, o.Solver.Itol)
	return &o
}
Пример #24
0
func main() {

	// input data file
	inpfn := "data/loccmdrv1.inp"
	flag.Parse()
	if len(flag.Args()) > 0 {
		inpfn = flag.Arg(0)
	}
	if io.FnExt(inpfn) == "" {
		inpfn += ".inp"
	}

	// read and parse input data
	var in Input
	b, err := io.ReadFile(inpfn)
	if err != nil {
		io.PfRed("cannot read %s\n", inpfn)
		return
	}
	err = json.Unmarshal(b, &in)
	if err != nil {
		io.PfRed("cannot parse %s\n", inpfn)
		return
	}
	in.PostProcess()

	// print input data
	io.Pf("%v\n", in)

	// load simulation
	sim := inp.ReadSim(in.Dir, in.SimFn, "cmd_", false)
	if sim == nil {
		io.PfRed("cannot load simulation\n")
		return
	}

	// get material data
	mat := sim.Mdb.Get(in.MatName)
	if mat == nil {
		io.PfRed("cannot get material\n")
		return
	}
	//io.Pfcyan("mat = %v\n", mat)

	// get and initialise model
	mdl, _ := msolid.GetModel(in.SimFn, in.MatName, mat.Model, false)
	if mdl == nil {
		io.PfRed("cannot allocate model\n")
		return
	}
	ndim := 3
	pstress := false
	mdl.Init(ndim, pstress, mat.Prms)
	//io.Pforan("mdl = %v\n", mdl)

	// load path
	var pth msolid.Path
	err = pth.ReadJson(ndim, path.Join(in.Dir, in.PathFn))
	if err != nil {
		io.PfRed("cannot read path file %v\n", err)
		return
	}
	//io.PfYel("pth = %v\n", pth)

	// driver
	var drv msolid.Driver
	drv.InitWithModel(ndim, mdl)

	// run
	err = drv.Run(&pth)
	if err != nil {
		io.Pfred("driver: Run failed: %v\n", err)
	}

	// plot
	//if false {
	if true {
		var plr msolid.Plotter
		plr.SetFig(false, in.FigEps, in.FigProp, in.FigWid, "/tmp", "cmd_"+in.SimFn)
		var epm msolid.EPmodel
		if m, ok := mdl.(msolid.EPmodel); ok {
			plr.SetModel(m)
			epm = m
		}
		if epm != nil {
			//plr.Phi = epm.Get_phi()
			b := epm.Get_bsmp()
			epm.Set_bsmp(0)
			plr.YsClr0 = "magenta"
			plr.Plot(in.PlotSet, drv.Res, nil, true, false)
			epm.Set_bsmp(b)
		}
		plr.YsClr0 = "green"
		plr.Plot(in.PlotSet, drv.Res, drv.Eps, false, true)
	}

	// plot ys
	if false {
		//if true {
		plt.Reset()
		m := mdl.(*msolid.SmpInvs)
		φ := m.Get_phi()
		σcCte := 10.0
		M := tsr.Phi2M(φ, "oct")
		rmin, rmax := 0.0, 1.28*M*σcCte
		nr, nα := 31, 81
		//nr,   nα   := 31, 1001
		npolarc := true
		simplec := false
		only0 := false
		grads := false
		showpts := false
		ferr := 10.0
		tsr.PlotOct("fig_isofun02.png", σcCte, rmin, rmax, nr, nα, φ, m.Isof.Fa, m.Isof.Ga,
			npolarc, simplec, only0, grads, showpts, true, true, ferr)
	}
}
Пример #25
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	mshfn, fnkey := io.ArgToFilename(0, "data/sgm57", ".msh", true)

	// old mesh
	var old OldMesh

	// read file
	b, err := io.ReadFile(mshfn)
	if err != nil {
		chk.Panic("%v", err)
	}

	// decode
	err = json.Unmarshal(b, &old)
	if err != nil {
		chk.Panic("%v", err)
	}

	// verts: find largest strings
	var ndim int
	L := make([]int, 5)
	for _, v := range old.Verts {
		L[0] = utl.Imax(L[0], len(io.Sf("%d", v.Id)))
		L[1] = utl.Imax(L[1], len(io.Sf("%d", v.Tag)))
		for j, x := range v.C {
			L[2+j] = utl.Imax(L[2+j], len(io.Sf("%g", x)))
		}
		ndim = len(v.C)
	}
	S := make([]string, 5)
	for i, l := range L {
		S[i] = io.Sf("%d", l)
	}

	// write vertices
	buf := new(bytes.Buffer)
	io.Ff(buf, "{\n  \"verts\":[\n")
	for i, v := range old.Verts {
		if i > 0 {
			io.Ff(buf, ",\n")
		}
		io.Ff(buf, "    {\"i\":%"+S[0]+"d, \"t\":%"+S[1]+"d, \"x\":[", v.Id, v.Tag)
		for j, x := range v.C {
			if j > 0 {
				io.Ff(buf, ", ")
			}
			io.Ff(buf, "%"+S[2+j]+"g", x)
		}
		io.Ff(buf, "] }")
	}

	// cells: find largest strings
	n := 30
	L = make([]int, n*2)
	for _, c := range old.Cells {
		L[0] = utl.Imax(L[0], len(io.Sf("%d", c.Id)))
		L[1] = utl.Imax(L[1], len(io.Sf("%d", c.Tag)))
		L[2] = utl.Imax(L[2], len(io.Sf("%d", c.Part)))
		for j, v := range c.Verts {
			L[3+j] = utl.Imax(L[3+j], len(io.Sf("%d", v)))
		}
	}
	S = make([]string, n*2)
	for i, l := range L {
		S[i] = io.Sf("%d", l)
	}
	io.Ff(buf, "\n  ],")

	// write cells
	io.Ff(buf, "\n  \"cells\":[\n")
	for i, c := range old.Cells {
		if i > 0 {
			io.Ff(buf, ",\n")
		}
		io.Ff(buf, "    {\"i\":%"+S[0]+"d, \"t\":%"+S[1]+"d, \"p\":%"+S[2]+"d, \"y\":%q, \"v\":[", c.Id, c.Tag, c.Part, c.Type)
		for j, v := range c.Verts {
			if j > 0 {
				io.Ff(buf, ", ")
			}
			io.Ff(buf, "%"+S[3+j]+"d", v)
		}
		io.Ff(buf, "]")
		if len(c.FTags) > 0 {
			io.Ff(buf, ", ")
			if ndim == 2 {
				io.Ff(buf, "\"et\":[")
			} else {
				io.Ff(buf, "\"ft\":[")
			}
			for j, t := range c.FTags {
				if j > 0 {
					io.Ff(buf, ", ")
				}
				io.Ff(buf, "%d", t)
			}
			io.Ff(buf, "]")
		}
		io.Ff(buf, " }")
	}
	io.Ff(buf, "\n  ]\n}")
	io.WriteFileVD("/tmp/gosl", fnkey+"-new.msh", buf)

	// check
	m, err := msh.Read("/tmp/gosl/" + fnkey + "-new.msh")
	if err != nil {
		chk.Panic("cannot read new mesh:\n%v", err)
	}
	m.Check()
}