func (o *ElemU) contact_g(x []float64) float64 { if false { return x[0] - 1.025 } r := make([]float64, 3) Y := o.contact_get_Y() qua4 := shp.Get("qua4", 0) //o.Sim.GoroutineId) qua4.InvMap(r, x, Y) δ := o.Cell.Shp.CellBryDist(r) return δ }
// register element func init() { // information allocator infogetters["phi"] = func(cellType string, faceConds []*FaceCond) *Info { // new info var info Info nverts := shp.GetNverts(cellType) ykeys := []string{"h"} info.Dofs = make([][]string, nverts) for m := 0; m < nverts; m++ { info.Dofs[m] = ykeys } info.T1vars = ykeys // return information return &info } // element allocator eallocators["phi"] = func(cellType string, faceConds []*FaceCond, cid int, edat *inp.ElemData, x [][]float64) Elem { // basic data var o ElemPhi o.Cid = cid o.X = x o.Shp = shp.Get(cellType) // cellType: e.g. "tri6", "qua8" o.Nu = o.Shp.Nverts // integration points o.IpsElem, _ = GetIntegrationPoints(edat.Nip, edat.Nipf, cellType) if o.IpsElem == nil { return nil // => failed } // local starred variables nip := len(o.IpsElem) o.ψs = make([]float64, nip) // scratchpad. computed @ each ip o.K = la.MatAlloc(o.Nu, o.Nu) // return new element return &o } }
// GetSimilar allocates a copy of this cell // Note: the resulting cell with share the same slices as the original one => not a full copy func (o *Cell) GetSimilar(lbb bool) (newcell *Cell) { // new cell newcell = new(Cell) // input data newcell.Id = o.Id newcell.Tag = o.Tag newcell.Geo = o.Geo newcell.Type = o.Type newcell.Part = o.Part newcell.Verts = o.Verts newcell.FTags = o.FTags newcell.STags = o.STags newcell.JlinId = o.JlinId newcell.JsldId = o.JsldId // neighbours newcell.Neighs = o.Neighs // new cell type ctype := o.Shp.Type if lbb { ctype = o.Shp.BasicType } // derived if o.Shp.Nurbs == nil { newcell.Shp = shp.Get(ctype, o.GoroutineId) if newcell.Shp == nil { chk.Panic("cannot allocate \"shape\" structure for cell type = %q\n", ctype) } } else { chk.Panic("cannot handle similar cells with NURBS yet") } newcell.FaceBcs = o.FaceBcs newcell.GoroutineId = o.GoroutineId // specific problems data newcell.IsJoint = o.IsJoint newcell.SeepVerts = o.SeepVerts // NURBS newcell.Nrb = o.Nrb newcell.Span = o.Span return }
func (o *ElemU) contact_dgdx(dgdx, x []float64) { if false { dgdx[0], dgdx[1] = 1.0, 0.0 } r := make([]float64, 3) Y := o.contact_get_Y() qua4 := shp.Get("qua4", 0) //o.Sim.GoroutineId) qua4.InvMap(r, x, Y) dfdR := make([]float64, 2) o.Cell.Shp.CellBryDistDeriv(dfdR, r) qua4.CalcAtR(Y, r, true) dgdx[0], dgdx[1] = 0.0, 0.0 for i := 0; i < 2; i++ { for k := 0; k < 2; k++ { dgdx[i] += dfdR[k] * qua4.DRdx[k][i] } } }
// register element func init() { // information allocator infogetters["u"] = func(cellType string, faceConds []*FaceCond) *Info { // new info var info Info // number of nodes in element nverts := shp.GetNverts(cellType) // solution variables ykeys := []string{"ux", "uy"} if Global.Ndim == 3 { ykeys = []string{"ux", "uy", "uz"} } info.Dofs = make([][]string, nverts) for m := 0; m < nverts; m++ { info.Dofs[m] = ykeys } // maps info.Y2F = map[string]string{"ux": "fx", "uy": "fy", "uz": "fz"} // t1 and t2 variables info.T2vars = ykeys return &info } // element allocator eallocators["u"] = func(cellType string, faceConds []*FaceCond, cid int, edat *inp.ElemData, x [][]float64) Elem { // basic data var o ElemU o.Cid = cid o.X = x o.Shp = shp.Get(cellType) ndim := Global.Ndim o.Nu = ndim * o.Shp.Nverts // parse flags o.UseB, o.Debug, o.Thickness = GetSolidFlags(edat.Extra) // integration points o.IpsElem, o.IpsFace = GetIntegrationPoints(edat.Nip, edat.Nipf, cellType) if o.IpsElem == nil || o.IpsFace == nil { return nil } nip := len(o.IpsElem) // model var prms fun.Prms o.Model, prms = GetAndInitSolidModel(edat.Mat, ndim) if o.Model == nil { return nil } // model specialisations switch m := o.Model.(type) { case msolid.Small: o.MdlSmall = m case msolid.Large: o.MdlLarge = m default: chk.Panic("__internal_error__: 'u' element cannot determine the type of the material model") } // parameters for _, p := range prms { switch p.N { case "rho": o.Rho = p.V case "Cdam": o.Cdam = p.V } } // local starred variables o.ζs = la.MatAlloc(nip, ndim) o.χs = la.MatAlloc(nip, ndim) o.divχs = make([]float64, nip) // scratchpad. computed @ each ip nsig := 2 * ndim o.grav = make([]float64, ndim) o.us = make([]float64, ndim) o.fi = make([]float64, o.Nu) o.D = la.MatAlloc(nsig, nsig) o.K = la.MatAlloc(o.Nu, o.Nu) if o.UseB { o.B = la.MatAlloc(nsig, o.Nu) } // strains o.ε = make([]float64, nsig) o.Δε = make([]float64, nsig) // variables for debugging if o.Debug { o.fex = make([]float64, o.Shp.Nverts) o.fey = make([]float64, o.Shp.Nverts) if ndim == 3 { o.fez = make([]float64, o.Shp.Nverts) } } // surface loads (natural boundary conditions) for _, fc := range faceConds { o.NatBcs = append(o.NatBcs, &NaturalBc{fc.Cond, fc.FaceId, fc.Func, fc.Extra}) } // return new element return &o } }
// 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 }
// register element func init() { // information allocator infogetters["rod"] = func(cellType string, faceConds []*FaceCond) *Info { // new info var info Info // number of nodes in element nverts := shp.GetNverts(cellType) // solution variables ykeys := []string{"ux", "uy"} if Global.Ndim == 3 { ykeys = []string{"ux", "uy", "uz"} } info.Dofs = make([][]string, nverts) for m := 0; m < nverts; m++ { info.Dofs[m] = ykeys } // maps info.Y2F = map[string]string{"ux": "fx", "uy": "fy", "uz": "fz"} // t1 and t2 variables info.T2vars = ykeys return &info } // element allocator eallocators["rod"] = func(cellType string, faceConds []*FaceCond, cid int, edat *inp.ElemData, x [][]float64) Elem { // basic data var o Rod o.Cid = cid o.X = x o.Shp = shp.Get(cellType) ndim := Global.Ndim o.Nu = ndim * o.Shp.Nverts var err error // material model name matname := edat.Mat matdata := Global.Sim.Mdb.Get(matname) if LogErrCond(matdata == nil, "materials database failed on getting %q material\n", matname) { return nil } mdlname := matdata.Model o.Model = msolid.GetOnedSolid(Global.Sim.Data.FnameKey, matname, mdlname, false) if LogErrCond(o.Model == nil, "cannot find model named %s\n", mdlname) { return nil } err = o.Model.Init(ndim, matdata.Prms) if LogErr(err, "Model.Init failed") { return nil } // parameters for _, p := range matdata.Prms { switch p.N { case "A": o.A = p.V case "rho": o.Rho = p.V } } // integration points var nip int if s_nip, found := io.Keycode(edat.Extra, "nip"); found { nip = io.Atoi(s_nip) } o.IpsElem, err = shp.GetIps(o.Shp.Type, nip) if LogErr(err, "GetIps failed") { return nil } nip = len(o.IpsElem) // scratchpad. computed @ each ip o.K = la.MatAlloc(o.Nu, o.Nu) o.M = la.MatAlloc(o.Nu, o.Nu) o.ue = make([]float64, o.Nu) o.Rus = make([]float64, o.Nu) // scratchpad. computed @ each ip o.grav = make([]float64, ndim) o.us = make([]float64, ndim) o.fi = make([]float64, o.Nu) // return new element return &o } }
// register element func init() { // information allocator infogetters["p"] = func(cellType string, faceConds []*FaceCond) *Info { // new info var info Info // number of nodes in element nverts := shp.GetNverts(cellType) // solution variables ykeys := []string{"pl"} info.Dofs = make([][]string, nverts) for m := 0; m < nverts; m++ { info.Dofs[m] = ykeys } // maps info.Y2F = map[string]string{"pl": "ql"} // vertices on seepage faces lverts := GetVertsWithCond(faceConds, "seep") for _, m := range lverts { if m < nverts { // avoid adding vertices of superelement (e.g. qua8 vertices in this qua4 cell) info.Dofs[m] = append(info.Dofs[m], "fl") } } if len(lverts) > 0 { ykeys = append(ykeys, "fl") info.Y2F["fl"] = "nil" } // t1 and t2 variables info.T1vars = ykeys return &info } // element allocator eallocators["p"] = func(cellType string, faceConds []*FaceCond, cid int, edat *inp.ElemData, x [][]float64) Elem { // basic data var o ElemP o.Cid = cid o.X = x o.Shp = shp.Get(cellType) o.Np = o.Shp.Nverts // integration points o.IpsElem, o.IpsFace = GetIntegrationPoints(edat.Nip, edat.Nipf, cellType) if o.IpsElem == nil || o.IpsFace == nil { return nil } nip := len(o.IpsElem) // models o.Mdl = GetAndInitPorousModel(edat.Mat) if o.Mdl == nil { return nil } // local starred variables o.ψl = make([]float64, nip) // scratchpad. computed @ each ip ndim := Global.Ndim o.g = make([]float64, ndim) o.gpl = make([]float64, ndim) o.ρwl = make([]float64, ndim) o.tmp = make([]float64, ndim) o.Kpp = la.MatAlloc(o.Np, o.Np) o.res = new(mporous.LsVars) // vertices on seepage faces var seepverts []int lverts := GetVertsWithCond(faceConds, "seep") for _, m := range lverts { if m < o.Np { // avoid adding vertices of superelement (e.g. qua8 vertices in this qua4 cell) seepverts = append(seepverts, m) } } o.Nf = len(seepverts) o.HasSeep = o.Nf > 0 if o.HasSeep { // vertices on seepage face; numbering o.SeepId2vid = seepverts o.Vid2seepId = utl.IntVals(o.Np, -1) o.Fmap = make([]int, o.Nf) for μ, m := range o.SeepId2vid { o.Vid2seepId[m] = μ } // flags o.Macaulay, o.βrmp, o.κ = GetSeepFaceFlags(edat.Extra) // allocate coupling matrices o.Kpf = la.MatAlloc(o.Np, o.Nf) o.Kfp = la.MatAlloc(o.Nf, o.Np) o.Kff = la.MatAlloc(o.Nf, o.Nf) } // set natural boundary conditions for idx, fc := range faceConds { o.NatBcs = append(o.NatBcs, &NaturalBc{fc.Cond, fc.FaceId, fc.Func, fc.Extra}) // allocate extrapolation structures if fc.Cond == "ql" || fc.Cond == "seep" { nv := o.Shp.Nverts nip := len(o.IpsElem) o.ρl_ex = make([]float64, nv) o.dρldpl_ex = la.MatAlloc(nv, nv) o.Emat = la.MatAlloc(nv, nip) o.DoExtrap = true if LogErr(o.Shp.Extrapolator(o.Emat, o.IpsElem), "element allocation") { return nil } } // additional seepage condition structures: hydrostatic flags if fc.Cond == "seep" { if len(o.Hst) == 0 { o.Hst = make([]bool, len(faceConds)) } if s_val, found := io.Keycode(fc.Extra, "plmax"); found { o.Hst[idx] = (s_val == "hst") } } } // return new element return &o } }
// 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 }