// xfem_set_info sets extra information for XFEM elements func xfem_set_info(info *Info, cell *inp.Cell, edat *inp.ElemData) (ykeys []string) { // flags xmat, xcrk, xfem := false, false, false if s_xmat, found := io.Keycode(edat.Extra, "xmat"); found { xmat = io.Atob(s_xmat) xfem = true } if s_xcrk, found := io.Keycode(edat.Extra, "xcrk"); found { xcrk = io.Atob(s_xcrk) xfem = true } _ = xcrk // TODO // skip if not XFEM if !xfem { return } // extra information nverts := cell.Shp.Nverts if xmat { for m := 0; m < nverts; m++ { info.Dofs[m] = append(info.Dofs[m], "am") } info.Y2F["am"] = "nil" info.T2vars = append(info.T2vars, "am") } return }
func GetSolidFlags(extra string) (useB, debug bool, thickness float64) { // defaults useB = false debug = false thickness = 1.0 // flag: use B matrix if s_useB, found := io.Keycode(extra, "useB"); found { useB = io.Atob(s_useB) } // fix useB flag in case of axisymmetric simulation if Global.Sim.Data.Axisym { useB = true } // flag: thickess => plane-stress if s_thick, found := io.Keycode(extra, "thick"); found { thickness = io.Atof(s_thick) } // fix thickness flag if !Global.Sim.Data.Pstress { thickness = 1.0 } // flag: debug if s_debug, found := io.Keycode(extra, "debug"); found { debug = io.Atob(s_debug) } return }
// get_porous_parameters extracts parameters based on region data func get_porous_parameters(mdb *inp.MatDb, reg *inp.Region, ctag int) (RhoS0, nf0 float64, err error) { edat := reg.Etag2data(ctag) mat := mdb.Get(edat.Mat) if mat.Model != "group" { err = chk.Err("geost: material type describing layer must be 'group' with porous data") return } if matname, found := io.Keycode(mat.Extra, "p"); found { m := mdb.Get(matname) for _, p := range m.Prms { switch p.N { case "RhoS0": RhoS0 = p.V case "nf0": nf0 = p.V } } } if RhoS0 < 1e-7 { err = chk.Err("geost: initial density of solids RhoS0=%g is incorrect", RhoS0) return } if nf0 < 1e-7 { err = chk.Err("geost: initial porosity nf0=%g is incorrect", nf0) } return }
// GroupGet parses group data // Note: returns nil on failure func (o MatDb) GroupGet(matname, key string) *Material { mat := o.Get(matname) if mat == nil { return nil } if submatname, found := io.Keycode(mat.Extra, key); found { return o.Get(submatname) } return nil }
// GroupGet3 parses group data func (o MatDb) GroupGet3(matname, key1, key2, key3 string) (m1, m2, m3 *Material, err error) { mat := o.Get(matname) if mat == nil { err = chk.Err("cannot find material named %q", matname) return } var submat1, submat2, submat3 string var found bool if submat1, found = io.Keycode(mat.Extra, key1); found { m1 = o.Get(submat1) } else { err = chk.Err("cannot find key %q in grouped material data %q", key1, mat.Extra) return } if submat2, found = io.Keycode(mat.Extra, key2); found { m2 = o.Get(submat2) } else { err = chk.Err("cannot find key %q in grouped material data %q", key2, mat.Extra) return } if submat3, found = io.Keycode(mat.Extra, key3); found { m3 = o.Get(submat3) } else { err = chk.Err("cannot find key %q in grouped material data %q", key3, mat.Extra) return } errmsg := "" if m1 == nil { errmsg += io.Sf("material data in grouped materials (!%s:%s) cannot be found\n", key1, submat1) } if m2 == nil { errmsg += io.Sf("material data in grouped materials (!%s:%s) cannot be found\n", key2, submat2) } if m3 == nil { errmsg += io.Sf("material data in grouped materials (!%s:%s) cannot be found\n", key3, submat3) } if errmsg != "" { err = chk.Err(errmsg) } return }
func GetSeepFaceFlags(extra string) (Macaulay bool, BetRamp, Kappa float64) { // defaults Macaulay = false BetRamp = math.Ln2 / 0.01 Kappa = 1.0 // use macaulay function ? if s_mac, found := io.Keycode(extra, "mac"); found { Macaulay = io.Atob(s_mac) } // coefficient for smooth ramp function if s_bet, found := io.Keycode(extra, "bet"); found { BetRamp = io.Atof(s_bet) } // κ coefficient if s_kap, found := io.Keycode(extra, "kap"); found { Kappa = io.Atof(s_kap) } return }
// Init initialises this structure func (o *SmallElasticity) Init(ndim int, pstress bool, prms fun.Prms) (err error) { o.Nsig = 2 * ndim o.Pse = pstress var has_E, has_ν, has_l, has_G, has_K bool for _, p := range prms { switch p.N { case "E": o.E, has_E = p.V, true case "nu": o.Nu, has_ν = p.V, true case "l": o.L, has_l = p.V, true case "G": o.G, has_G = p.V, true case "K": o.K, has_K = p.V, true } if skgc, found := io.Keycode(p.Extra, "kgc"); found { o.Kgc = GetKgc(skgc, prms) if o.Kgc == nil { return chk.Err("cannot find kgc model named %s", skgc) } err = o.Kgc.Init(prms) if err != nil { return } } } switch { case has_E && has_ν: o.L = Calc_l_from_Enu(o.E, o.Nu) o.G = Calc_G_from_Enu(o.E, o.Nu) o.K = Calc_K_from_Enu(o.E, o.Nu) case has_l && has_G: o.E = Calc_E_from_lG(o.L, o.G) o.Nu = Calc_nu_from_lG(o.L, o.G) o.K = Calc_K_from_lG(o.L, o.G) case has_K && has_G: o.E = Calc_E_from_KG(o.K, o.G) o.Nu = Calc_nu_from_KG(o.K, o.G) o.L = Calc_l_from_KG(o.K, o.G) case has_K && has_ν: o.E = Calc_E_from_Knu(o.K, o.Nu) o.G = Calc_G_from_Knu(o.K, o.Nu) o.L = Calc_l_from_Knu(o.K, o.Nu) default: return chk.Err("combination of Elastic constants is incorrect. options are {E,nu}, {l,G}, {K,G} and {K,nu}\n") } return }
// xfem_init initialises variables need by xfem model func (o *ElemU) xfem_init(edat *inp.ElemData) { // flags o.Xmat, o.Xcrk, o.Xfem = false, false, false if s_xmat, found := io.Keycode(edat.Extra, "xmat"); found { o.Xmat = io.Atob(s_xmat) o.Xfem = true } if s_xcrk, found := io.Keycode(edat.Extra, "xcrk"); found { o.Xcrk = io.Atob(s_xcrk) o.Xfem = true } // skip if not XFEM if !o.Xfem { return } // auxiliary variables switch { case o.Xmat: o.Na = 1 case o.Xcrk: o.Na = 4 // TODO: this is 2D only if o.Ndim != 2 { chk.Panic("xfem with crack works in 2D only for now") } } // allocate extrem XFEM coupling matrices nverts := o.Cell.Shp.Nverts o.Amap = make([]int, o.Na*nverts) o.Kua = la.MatAlloc(o.Nu, o.Na) o.Kau = la.MatAlloc(o.Na, o.Nu) o.Kaa = la.MatAlloc(o.Na, o.Na) }
func GetAndInitSolidModel(mdb *inp.MatDb, matname, simfnk string, ndim int, pstress bool) (mdl msolid.Model, prms fun.Prms, err error) { // material name matdata := mdb.Get(matname) if matdata == nil { err = chk.Err("materials database failed on getting %q (solid) material\n", matname) return } mdlname := matdata.Model // handle groups if mdlname == "group" { if s_matname, found := io.Keycode(matdata.Extra, "s"); found { matname = s_matname matdata = mdb.Get(matname) if matdata == nil { err = chk.Err("materials database failed on getting %q (solid/sub) material\n", matname) return } mdlname = matdata.Model } else { err = chk.Err("cannot find solid model in grouped material data. 's' subkey needed in Extra field") return } } // initialise model mdl, existent := msolid.GetModel(simfnk, matname, mdlname, false) if mdl == nil { err = chk.Err("cannot find solid model named %q", mdlname) return } if !existent { err = mdl.Init(ndim, pstress, matdata.Prms) if err != nil { err = chk.Err("solid model initialisation failed:\n%v", err) return } } // results prms = matdata.Prms return }
// 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 } }
// Set sets a constraint if it does NOT exist yet. // key -- can be Dof key such as "ux", "uy" or constraint type such as "mpc" or "rigid" // extra -- is a keycode-style data. e.g. "!type:incsup2d !alp:30" // Notes: 1) the default for key is single point constraint; e.g. "ux", "uy", ... // 2) hydraulic head can be set with key == "H" func (o *EssentialBcs) Set(key string, nodes []*Node, fcn fun.Func, extra string) (err error) { // len(nod) must be greater than 0 chk.IntAssertLessThan(0, len(nodes)) // 0 < len(nod) // skip nil node if nodes[0] == nil { return } // space dimension ndim := len(nodes[0].Vert.C) // rigid element if key == "rigid" { a := nodes[0].Dofs for i := 1; i < len(nodes); i++ { for j, b := range nodes[i].Dofs { o.add(key, []int{a[j].Eq, b.Eq}, []float64{1, -1}, &fun.Zero) } } return // success } // inclined support if key == "incsup" { // check if ndim != 2 { return chk.Err("inclined support works only in 2D for now") } // get data var α float64 if val, found := io.Keycode(extra, "alp"); found { α = io.Atof(val) * math.Pi / 180.0 } co, si := math.Cos(α), math.Sin(α) // set for all nodes for _, nod := range nodes { // find existent constraints and deactivate them eqx := nod.Dofs[0].Eq eqy := nod.Dofs[1].Eq for _, eq := range []int{eqx, eqy} { for _, idx := range o.Eq2idx[eq] { pair := o.BcsTmp[idx] if pair.bc.Key != "rigid" { pair.bc.Inact = true } } } // set constraint o.add(key, []int{eqx, eqy}, []float64{co, si}, &fun.Zero) } return // success } // hydraulic head if key == "hst" { // set for all nodes for _, nod := range nodes { // create function // Note: fcn is a shift such that pl = pl(z) - shift(t) d := nod.GetDof("pl") if d == nil { continue // node doesn't have key. ex: pl in qua8/qua4 elements } z := nod.Vert.C[1] // 2D if ndim == 3 { z = nod.Vert.C[2] // 3D } plVal, _, err := o.HydFcn.Calc(z) if err != nil { return chk.Err("cannot set hst (hydrostatic) essential boundary condition") } pl := fun.Add{ B: 1, Fb: &fun.Cte{C: plVal}, A: -1, Fa: fcn, } // set constraint o.add_single("pl", d.Eq, &pl) } return // success } // single-point constraint for _, nod := range nodes { d := nod.GetDof(key) if d == nil { return // success } o.add_single(key, d.Eq, fcn) } // success return }
// register element func init() { // information allocator infogetters["p"] = func(sim *inp.Simulation, cell *inp.Cell, edat *inp.ElemData) *Info { // new info var info Info // number of nodes in element nverts := cell.GetNverts(edat.Lbb) // 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 if len(cell.FaceBcs) > 0 { lverts := cell.FaceBcs.GetVerts("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(sim *inp.Simulation, cell *inp.Cell, edat *inp.ElemData, x [][]float64) Elem { // basic data var o ElemP o.Cell = cell o.X = x o.Np = o.Cell.Shp.Nverts o.Ndim = sim.Ndim // integration points var err error o.IpsElem, o.IpsFace, err = o.Cell.Shp.GetIps(edat.Nip, edat.Nipf) if err != nil { chk.Panic("cannot allocate integration points of p-element with nip=%d and nipf=%d:\n%v", edat.Nip, edat.Nipf, err) } nip := len(o.IpsElem) // models o.Mdl, err = GetAndInitPorousModel(sim.MatParams, edat.Mat, sim.Key) if err != nil { chk.Panic("cannot get model for p-element {tag=%d id=%d material=%q}:\n%v", cell.Tag, cell.Id, edat.Mat, err) } // local starred variables o.ψl = make([]float64, nip) // scratchpad. computed @ each ip o.g = make([]float64, o.Ndim) o.gpl = make([]float64, o.Ndim) o.ρwl = make([]float64, o.Ndim) o.tmp = make([]float64, o.Ndim) o.Kpp = la.MatAlloc(o.Np, o.Np) o.res = new(mporous.LsVars) // vertices on seepage faces var seepverts []int if len(cell.FaceBcs) > 0 { lverts := cell.FaceBcs.GetVerts("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 cell.FaceBcs { 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.Cell.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 err = o.Cell.Shp.Extrapolator(o.Emat, o.IpsElem) if err != nil { chk.Panic("cannot build extrapolator matrix for p-element:\n%v", err) } } // additional seepage condition structures: hydrostatic flags if fc.Cond == "seep" { if len(o.Hst) == 0 { o.Hst = make([]bool, len(cell.FaceBcs)) } if s_val, found := io.Keycode(fc.Extra, "plmax"); found { o.Hst[idx] = (s_val == "hst") } } } // return new element return &o } }