func (o *Plotter) Plot_Dgam_f(x, y []float64, res []*State, sts [][]float64, last bool) { if o.m == nil { o.set_empty() return } nr := len(res) k := nr - 1 ys := o.m.YieldFuncs(res[0]) fc0 := ys[0] xmi, xma, ymi, yma := res[0].Dgam, res[0].Dgam, fc0, fc0 for i := 0; i < nr; i++ { x[i] = res[i].Dgam ys = o.m.YieldFuncs(res[i]) y[i] = ys[0] xmi = utl.Min(xmi, x[i]) xma = utl.Max(xma, x[i]) ymi = utl.Min(ymi, y[i]) yma = utl.Max(yma, y[i]) } //o.DrawRamp(xmi, xma, ymi, yma) plt.Plot(x, y, io.Sf("'r.', ls='%s', clip_on=0, color='%s', marker='%s', label=r'%s'", o.Ls, o.Clr, o.Mrk, o.Lbl)) plt.PlotOne(x[0], y[0], io.Sf("'bo', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.SpMrk, o.SpMs)) plt.PlotOne(x[k], y[k], io.Sf("'bs', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.EpMrk, o.EpMs)) if last { plt.Gll("$\\Delta\\gamma$", "$f$", "") if lims, ok := o.Lims["Dgam,f"]; ok { plt.AxisLims(lims) } } }
func (o *RefM1) wetting(x, y float64) { o.Dw = utl.Max(o.y0-y, 0.0) o.λwb = o.λw * (1.0 - math.Exp(-o.βw*o.Dw)) o.yw = -o.λw*x - math.Log(o.c3w+o.c2w*math.Exp(o.c1w*x))/o.βw o.D = utl.Max(y-o.yw, 0.0) o.λb = o.λwb * math.Exp(-o.β1*o.D) return }
func (o *RefM1) drying(x, y float64) { o.Dd = utl.Max(y-o.yr, 0.0) o.λdb = o.λd * (1.0 - math.Exp(-o.βd*o.Dd)) o.yd = -o.λd*x + math.Log(o.c3d+o.c2d*math.Exp(o.c1d*x))/o.βd o.D = utl.Max(o.yd-y, 0.0) o.β2b = o.β2 * math.Pow(utl.Max(y, 0.0), o.α) o.λb = o.λdb * math.Exp(-o.β2b*o.D) return }
// CalcScaleFactor computes scale factor based on mesh dimensions // Input: // Y -- results; e.g. bending moments // coef -- coefficient to scale max(dimension) divided by max(Y); e.g. 0.1 // Output: // sf -- scaling factor func (o *Mesh) CalcScaleFactor(Y []float64, coef float64) (sf float64) { if len(Y) < 2 { chk.Panic("at least two values are required in Y in order to compute scaling factor") } dx := o.Xmax - o.Xmin dy := o.Ymax - o.Ymin d := utl.Max(dx, dy) Ymax := math.Abs(Y[0]) for i := 1; i < len(Y); i++ { Ymax = utl.Max(Ymax, Y[i]) } return coef * d / Ymax }
// PlotAllBendingMoments plots all bending moments // Input: // dom -- Domain // nstations -- number of stations // withtext -- show bending moment values // numfmt -- number format for values // tolM -- tolerance to clip absolute values of M // coef -- coefficient to scale max(dimension) divided by max(Y); e.g. 0.1 // Output: // beams -- all beam elements // allM -- bending moments corresponding to all beams func PlotAllBendingMoments(dom *Domain, nstations int, withtext bool, numfmt string, tolM, coef float64) (beams []*Beam, allM [][]float64) { // collect beams for _, elem := range dom.Elems { if beam, ok := elem.(*Beam); ok { beams = append(beams, beam) } } // compute bending moments allM = make([][]float64, len(beams)) for i, beam := range beams { _, allM[i] = beam.CalcVandM(dom.Sol, 0, nstations) } // scaling factor maxAbsM := la.MatLargest(allM, 1) dist := utl.Max(dom.Msh.Xmax-dom.Msh.Xmin, dom.Msh.Ymax-dom.Msh.Ymin) sf := 1.0 if maxAbsM > 1e-7 { sf = coef * dist / maxAbsM } // draw dom.Msh.Draw2d() for i, beam := range beams { beam.PlotDiagMoment(allM[i], withtext, numfmt, tolM, sf) } return }
func GetLimits(o *Nurbs) (xmin, xmax, xdel []float64) { xmin = []float64{math.Inf(+1), math.Inf(+1), math.Inf(+1)} xmax = []float64{math.Inf(-1), math.Inf(-1), math.Inf(-1)} xdel = []float64{0, 0, 0} for k := 0; k < o.n[2]; k++ { for j := 0; j < o.n[1]; j++ { for i := 0; i < o.n[0]; i++ { x := o.GetQ(i, j, k) for r := 0; r < o.gnd; r++ { xmin[r] = utl.Min(xmin[r], x[r]) xmax[r] = utl.Max(xmax[r], x[r]) } } } } for i := 0; i < 3; i++ { xdel[i] = xmax[i] - xmin[i] } for i := o.gnd; i < 3; i++ { xmin[i] = 0 xmax[i] = 0 xdel[i] = 0 } return }
// derivatives func (o *RefM1) Derivs(pc, sl float64, wet bool) (L, Lx, J, Jx, Jy float64, err error) { if pc <= 0 { return } if sl < o.yr { sl = o.yr } x := math.Log(1.0 + pc) var DλbDx, DλbDy, D2λbDx2, D2λbDyDx, D2λbDy2 float64 if wet && !o.nowet { o.wetting(x, sl) DywDx := -o.λw - o.c1w*o.c2w*math.Exp(o.c1w*x)/(o.βw*(o.c3w+o.c2w*math.Exp(o.c1w*x))) DλbDx = o.β1 * o.λb * DywDx DλbDy = (o.βw*(o.λwb-o.λw) - o.λwb*o.β1) * math.Exp(-o.β1*o.D) D2ywDx2 := -o.c1w * o.c1w * o.c2w * o.c3w * math.Exp(o.c1w*x) / (o.βw * math.Pow(o.c3w+o.c2w*math.Exp(o.c1w*x), 2.0)) D2λbDx2 = o.β1 * (DλbDx*DywDx + o.λb*D2ywDx2) D2λbDyDx = o.β1 * DλbDy * DywDx DλwbDy := -o.λw * math.Exp(-o.βw*o.Dw) * o.βw D2λbDy2 = (o.βw*DλwbDy-DλwbDy*o.β1)*math.Exp(-o.β1*o.D) - (o.βw*(o.λwb-o.λw)-o.λwb*o.β1)*math.Exp(-o.β1*o.D)*o.β1 } else { o.drying(x, sl) DydDx := -o.λd + o.c1d*o.c2d*math.Exp(o.c1d*x)/(o.βd*(o.c3d+o.c2d*math.Exp(o.c1d*x))) DλbDx = -o.β2b * o.λb * DydDx Dβ2bDy := o.α * o.β2 * math.Pow(utl.Max(sl, 0.0), o.α-1.0) DλbDy = (o.βd*(o.λd-o.λdb) + o.λdb*(o.β2b-Dβ2bDy*o.D)) * math.Exp(-o.β2b*o.D) D2ydDx2 := o.c1d * o.c1d * o.c2d * o.c3d * math.Exp(o.c1d*x) / (o.βd * math.Pow(o.c3d+o.c2d*math.Exp(o.c1d*x), 2.0)) D2λbDx2 = -o.β2b * (DλbDx*DydDx + o.λb*D2ydDx2) D2λbDyDx = -(o.β2b*DλbDy + o.λb*Dβ2bDy) * DydDx DλdbDy := o.λd * math.Exp(-o.βd*o.Dd) * o.βd Dβ2bDy2 := o.α * o.β2 * math.Pow(utl.Max(sl, 0.0), o.α-2.0) * (o.α - 1.0) D2λbDy2 = (-o.βd*DλdbDy+DλdbDy*(o.β2b-Dβ2bDy*o.D)+o.λdb*(2.0*Dβ2bDy-Dβ2bDy2*o.D))*math.Exp(-o.β2b*o.D) + (o.βd*(o.λd-o.λdb)+o.λdb*(o.β2b-Dβ2bDy*o.D))*math.Exp(-o.β2b*o.D)*(-Dβ2bDy*o.D+o.β2b) } den := 1.0 + pc den2 := den * den L = (o.λb - DλbDx) / den2 Lx = ((DλbDx-D2λbDx2)/den2 - 2.0*L) / den J = -DλbDy / den Jx = -(D2λbDyDx/den + J) / den Jy = -D2λbDy2 / den return }
// J computes J = ∂Cc/∂sl func (o RefM1) J(pc, sl float64, wet bool) (float64, error) { if pc <= 0 { return 0, nil } if sl < o.yr { sl = o.yr } x := math.Log(1.0 + pc) var DλbDy float64 if wet && !o.nowet { o.wetting(x, sl) DλbDy = (o.βw*(o.λwb-o.λw) - o.λwb*o.β1) * math.Exp(-o.β1*o.D) } else { o.drying(x, sl) Dβ2bDy := o.α * o.β2 * math.Pow(utl.Max(sl, 0.0), o.α-1.0) DλbDy = (o.βd*(o.λd-o.λdb) + o.λdb*(o.β2b-Dβ2bDy*o.D)) * math.Exp(-o.β2b*o.D) } return -DλbDy / (1.0 + pc), nil }
// RunFEA runs FE analysis. func RunFEA(x []float64, cpu int) (lsf, failed float64) { // FemData o := FEMDATA[cpu] // check for NaNs defer func() { if math.IsNaN(failed) || math.IsNaN(lsf) { io.PfRed("x = %+#v\n", x) chk.Panic("NaN: failed=%v lsf=%v\n", failed, lsf) } }() // adjust parameters for i, v := range o.Vars { v.Prm.Set(x[i]) } for _, prm := range o.Sim.AdjDependent { if prm.N == "I22" { prm.Set(prm.S * prm.Other.V * prm.Other.V) } } o.Dom.RecomputeKM() // run err := o.Analysis.SolveOneStage(0, true) if err != nil { failed = 1 return } // displacement based limit-state-function if o.AwdU > 0 { δ := o.Dom.Sol.Y[o.EqsU[0]] for i := 1; i < len(o.EqsU); i++ { δ = utl.Max(δ, o.Dom.Sol.Y[o.EqsU[i]]) } lsf = o.AwdU - δ } return }
func (o *RichardsonExtrap) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, dbgKb DebugKb_t) (err error) { // constants dat := o.doms[0].Sim.Solver atol := dat.REatol rtol := dat.RErtol mmin := dat.REmmin mmax := dat.REmmax mfac := dat.REmfac // control t := o.doms[0].Sol.T tout := t + dtoFunc.F(t, nil) steady := o.doms[0].Sim.Data.Steady // first output if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } // domain and variables d := o.doms[0] o.Y_big = make([]float64, d.Ny) // time loop o.Δt = dtFunc.F(t, nil) o.Δtcpy = o.Δt var ΔtOld, rerrOld float64 for t < tf { // check for continued divergence if o.ndiverg >= dat.NdvgMax { return chk.Err("continuous divergence after %d steps reached", o.ndiverg) } // check time increment if o.Δt < dat.DtMin { return chk.Err("Δt increment is too small: %g < %g", o.Δt, dat.DtMin) } // dynamic coefficients if !steady { err = o.dc.CalcBoth(o.Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients:\n%v", err) } } // check for maximum number of substeps o.nsteps += 1 if o.nsteps >= dat.REnssmax { return chk.Err("RE: max number of steps reached: %d", o.nsteps) } // backup domain d.backup() // single step with Δt d.Sol.T = t + o.Δt d.Sol.Dt = o.Δt o.diverging, err = run_iterations(t+o.Δt, o.Δt, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("single step with Δt: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "big step", verbose) { continue } } // save intermediate state for i := 0; i < d.Ny; i++ { o.Y_big[i] = d.Sol.Y[i] } // restore initial state d.restore() // 1st halved step d.Sol.T = t + o.Δt/2.0 d.Sol.Dt = o.Δt / 2.0 o.diverging, err = run_iterations(t+o.Δt/2.0, o.Δt/2.0, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("1st halved step: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "1st half step", verbose) { continue } } // 2nd halved step d.Sol.T = t + o.Δt d.Sol.Dt = o.Δt o.diverging, err = run_iterations(t+o.Δt, o.Δt/2.0, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("2nd halved step: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "2nd half step", verbose) { continue } } // Richardson's extrapolation error rerr := la.VecRmsError(d.Sol.Y, o.Y_big, atol, rtol, d.Sol.Y) / 3.0 // step size change m := utl.Min(mmax, utl.Max(mmin, mfac*math.Pow(1.0/rerr, 1.0/2.0))) ΔtNew := m * o.Δt // accepted if rerr < 1.0 { // update variables o.naccept += 1 t += o.Δt d.Sol.T = t // output if verbose { if !dat.ShowR { io.PfWhite("%30.15f\r", t) } } if t >= tout || o.laststep { if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } tout += dtoFunc.F(t, nil) } // reached final time if o.laststep { if verbose { io.Pfgreen("\n\nRichardson extrapolation succeeded\n") } return } // predictive controller of Gustafsson if !dat.REnogus { if o.naccept > 1 { m = mfac * (o.Δt / ΔtOld) * math.Sqrt(1.0/rerr) * math.Sqrt(rerrOld/rerr) if m*o.Δt < ΔtNew { o.ngustaf += 1 } ΔtNew = utl.Min(ΔtNew, m*o.Δt) } ΔtOld = o.Δt rerrOld = utl.Max(0.9, rerr) // 1e-2 } // next step size if o.reject { // do not alow Δt to grow if previous was a reject ΔtNew = utl.Min(o.Δt, ΔtNew) } o.reject = false o.Δt = ΔtNew if t+ΔtNew-tf >= 0.0 { o.laststep = true o.Δt = tf - t } // rejected } else { // restore state d.restore() // set flags o.nreject += 1 o.reject = true o.laststep = false // next step size o.Δt = ΔtNew if t+o.Δt > tf { o.Δt = tf - t } } } return }
// Compute computes limits, find non-dominated Pareto fronts, and compute crowd distances func (o *Metrics) Compute(sols []*Solution) (nfronts int) { // reset variables and find limits z := o.Fsizes nsol := len(sols) for i, sol := range sols { // reset values sol.Nwins = 0 sol.Nlosses = 0 sol.FrontId = 0 sol.DistCrowd = 0 sol.DistNeigh = INF z[i] = 0 // check oors for j := 0; j < o.prms.Noor; j++ { if math.IsNaN(sol.Oor[j]) { chk.Panic("NaN found in out-of-range value array\n\txFlt = %v\n\txInt = %v\n\tova = %v\n\toor = %v", sol.Flt, sol.Int, sol.Ova, sol.Oor) } } // ovas range for j := 0; j < o.prms.Nova; j++ { x := sol.Ova[j] if math.IsNaN(x) { chk.Panic("NaN found in objective value array\n\txFlt = %v\n\txInt = %v\n\tova = %v\n\toor = %v", sol.Flt, sol.Int, sol.Ova, sol.Oor) } if i == 0 { o.Omin[j] = x o.Omax[j] = x } else { o.Omin[j] = utl.Min(o.Omin[j], x) o.Omax[j] = utl.Max(o.Omax[j], x) } } // floats range for j := 0; j < o.prms.Nflt; j++ { x := sol.Flt[j] if i == 0 { o.Fmin[j] = x o.Fmax[j] = x } else { o.Fmin[j] = utl.Min(o.Fmin[j], x) o.Fmax[j] = utl.Max(o.Fmax[j], x) } } // ints range for j := 0; j < o.prms.Nint; j++ { x := sol.Int[j] if i == 0 { o.Imin[j] = x o.Imax[j] = x } else { o.Imin[j] = utl.Imin(o.Imin[j], x) o.Imax[j] = utl.Imax(o.Imax[j], x) } } } // compute neighbour distance for i := 0; i < nsol; i++ { A := sols[i] for j := i + 1; j < nsol; j++ { B := sols[j] o.closest(A, B) } } // skip if single-objective problem if o.prms.Nova < 2 { return } // compute wins/losses data for i := 0; i < nsol; i++ { A := sols[i] for j := i + 1; j < nsol; j++ { B := sols[j] A_win, B_win := A.Compare(B) if A_win { A.WinOver[A.Nwins] = B A.Nwins++ B.Nlosses++ } if B_win { B.WinOver[B.Nwins] = A B.Nwins++ A.Nlosses++ } } } // first front for _, sol := range sols { if sol.Nlosses == 0 { o.Fronts[0][z[0]] = sol z[0]++ } } // next fronts for r, front := range o.Fronts { if z[r] == 0 { break } s := r + 1 nfronts++ for i := 0; i < z[r]; i++ { A := front[i] for j := 0; j < A.Nwins; j++ { B := A.WinOver[j] B.Nlosses-- if B.Nlosses == 0 { // B belongs to next front B.FrontId = s o.Fronts[s][z[s]] = B z[s]++ } } } } // crowd distances for r := 0; r < nfronts; r++ { l, m := z[r], z[r]-1 if l == 1 { o.Fronts[r][0].DistCrowd = -1 continue } F := o.Fronts[r][:l] for j := 0; j < o.prms.Nova; j++ { SortByOva(F, j) δ := o.Omax[j] - o.Omin[j] + 1e-15 F[0].DistCrowd = INF F[m].DistCrowd = INF for i := 1; i < m; i++ { F[i].DistCrowd += ((F[i].Ova[j] - F[i-1].Ova[j]) / δ) * ((F[i+1].Ova[j] - F[i].Ova[j]) / δ) } } } return }
// NodesOnPlane finds vertices located on {x,y,z} plane and returns an iterator // that can be used to extract results on the plane. An {u,v}-coordinates system is built // on the plane. // Input: // ftag -- cells' face tag; e.g. -31 // Output: // dat -- plane data holding vertices on plane and other information; see above // Note: // 1) this function works with 3D cells only // 2) faces on cells must be either "qua4" or "qua8" types // 3) middle nodes in "qua8" are disregarded in order to buidl an {u,v} grid // 4) the resulting mesh on plane must be equally spaced; i.e. Δx and Δy are constant; // but not necessarily equal to each other func NodesOnPlane(ftag int) *PlaneData { // check ndim := Dom.Msh.Ndim if ndim != 3 { chk.Panic("this function works in 3D only") } // loop over cells on face with given face tag var dat PlaneData dat.Plane = -1 dat.Ids = make(map[int]bool) dat.Dx = make([]float64, ndim) Δx := make([]float64, ndim) first := true cells := Dom.Msh.FaceTag2cells[ftag] for _, cell := range cells { for fidx, cftag := range cell.C.FTags { if cftag == ftag { // check face type ftype := cell.C.Shp.FaceType if !(ftype == "qua4" || ftype == "qua8") { chk.Panic("can only handle qua4 or qua8 faces for now. ftype=%q", ftype) } // vertices on face flvids := cell.C.Shp.FaceLocalVerts[fidx] nv := len(flvids) if nv == 8 { nv = 4 // avoid middle nodes } for i := 0; i < nv; i++ { vid := cell.C.Verts[flvids[i]] dat.Ids[vid] = true } // compute and check increments in global coordinates for i := 1; i < nv; i++ { a := cell.C.Verts[flvids[i]] b := cell.C.Verts[flvids[i-1]] xa := Dom.Msh.Verts[a].C xb := Dom.Msh.Verts[b].C for j := 0; j < ndim; j++ { Δx[j] = utl.Max(Δx[j], math.Abs(xa[j]-xb[j])) } } if first { for j := 0; j < ndim; j++ { dat.Dx[j] = Δx[j] } first = false } else { for j := 0; j < ndim; j++ { if math.Abs(dat.Dx[j]-Δx[j]) > 1e-10 { chk.Panic("all faces must have the same Δx,Δy,Δz") } } } // find which plane vertices are located on => which plane this face is parallel to perpto := -1 // "perpendicular to" indicator switch { case Δx[0] < DIST_TOL: // plane perpendicular to x-axis perpto = 0 case Δx[1] < DIST_TOL: // plane perpendicular to y-axis perpto = 1 case Δx[2] < DIST_TOL: // plane perpendicular to z-axis perpto = 2 default: chk.Panic("planes must be perpendicular to one of the x-y-z axes") } if dat.Plane < 0 { dat.Plane = perpto } else { if perpto != dat.Plane { chk.Panic("all planes must be perperdicular to the same axis") } } } } } // uv: indices and increments dat.Iu = make([]int, 2) dat.Du = make([]float64, 2) switch dat.Plane { case 0: // plane perpendicular to x-axis dat.Iu = []int{1, 2} case 1: // plane perpendicular to y-axis dat.Iu = []int{0, 2} case 2: // plane perpendicular to z-axis dat.Iu = []int{0, 1} } for j := 0; j < 2; j++ { dat.Du[j] = dat.Dx[dat.Iu[j]] } // uv: limits dat.Umin = make([]float64, 2) dat.Umax = make([]float64, 2) first = true for vid, _ := range dat.Ids { x := Dom.Msh.Verts[vid].C if first { for j := 0; j < 2; j++ { dat.Umin[j] = x[dat.Iu[j]] dat.Umax[j] = x[dat.Iu[j]] } first = false } else { for j := 0; j < 2; j++ { dat.Umin[j] = utl.Min(dat.Umin[j], x[dat.Iu[j]]) dat.Umax[j] = utl.Max(dat.Umax[j], x[dat.Iu[j]]) } } } // uv: size of grid dat.Nu = make([]int, 2) for j := 0; j < 2; j++ { dat.Nu[j] = int((dat.Umax[j]-dat.Umin[j])/dat.Du[j]) + 1 } // uv: bins dd := DIST_TOL * 2 nb := 20 dat.Ubins.Init([]float64{dat.Umin[0] - dd, dat.Umin[1] - dd}, []float64{dat.Umax[0] + dd, dat.Umax[1] + dd}, nb) u := []float64{0, 0} for vid, _ := range dat.Ids { x := Dom.Msh.Verts[vid].C for j := 0; j < 2; j++ { u[j] = x[dat.Iu[j]] } err := dat.Ubins.Append(u, vid) if err != nil { chk.Panic("cannot append {u,v} coordinate to bins. u=%v", u) } } // allocate F dat.F = la.MatAlloc(dat.Nu[0], dat.Nu[1]) return &dat }
// SetGeoSt sets the initial state to a hydrostatic condition func (o *Domain) SetGeoSt(stg *inp.Stage) (err error) { // check layers definition geo := stg.GeoSt if len(geo.Layers) < 1 { return chk.Err("geost: layers must be defined by specifying what tags belong to which layer") } // get region if len(o.Sim.Regions) != 1 { return chk.Err("geost: can only handle one domain for now") } reg := o.Sim.Regions[0] // gravity grav := o.Sim.Gravity.F(0, nil) // fix UseK0 nlayers := len(geo.Layers) if len(geo.UseK0) != nlayers { geo.UseK0 = make([]bool, nlayers) } // initialise layers var L GeoLayers L = make([]*GeoLayer, nlayers) ndim := o.Sim.Ndim nodehandled := make(map[int]bool) ctaghandled := make(map[int]bool) // required to make sure all elements were initialised for i, tags := range geo.Layers { // new layer L[i] = new(GeoLayer) L[i].Tags = tags L[i].Zmin = o.Sim.MaxElev L[i].Zmax = 0 L[i].Cl = o.Sim.WaterRho0 / o.Sim.WaterBulk // get porous parameters L[i].RhoS0, L[i].nf0, err = get_porous_parameters(o.Sim.MatParams, reg, tags[0]) if err != nil { return } // parameters if geo.UseK0[i] { L[i].K0 = geo.K0[i] } else { L[i].K0 = geo.Nu[i] / (1.0 - geo.Nu[i]) } if L[i].K0 < 1e-7 { return chk.Err("geost: K0 or Nu is incorect: K0=%g, Nu=%g", L[i].K0, geo.Nu) } // for each tag of cells in this layer for _, tag := range tags { // check tags cells := o.Msh.CellTag2cells[tag] if len(cells) < 1 { return chk.Err("geost: there are no cells with tag = %d", tag) } // set nodes and elements and find min and max z-coordinates for _, c := range cells { L[i].Elems = append(L[i].Elems, o.Cid2elem[c.Id]) for _, v := range c.Verts { if !nodehandled[v] { L[i].Nodes = append(L[i].Nodes, o.Vid2node[v]) } L[i].Zmin = utl.Min(L[i].Zmin, o.Msh.Verts[v].C[ndim-1]) L[i].Zmax = utl.Max(L[i].Zmax, o.Msh.Verts[v].C[ndim-1]) nodehandled[v] = true } ctaghandled[c.Tag] = true } } } // make sure all elements tags were handled for tag, _ := range o.Msh.CellTag2cells { if !ctaghandled[tag] { return chk.Err("geost: there are cells not included in any layer: ctag=%d", tag) } } // sort layers from top to bottom sort.Sort(L) // set previous/top states in layers and compute Sol.Y for i, lay := range L { // previous state var top *geostate ρS := lay.RhoS0 nf := lay.nf0 sl := 1.0 if i == 0 { pl := (o.Sim.WaterLevel - o.Sim.MaxElev) * o.Sim.WaterRho0 * grav ρL := o.Sim.WaterRho0 ρ := nf*sl*ρL + (1.0-nf)*ρS σV := -o.Sim.Data.Surch top = &geostate{pl, ρL, ρ, σV} } else { top, err = L[i-1].Calc(L[i-1].Zmin) if err != nil { return chk.Err("cannot compute state @ bottom of layer:\n%v", err) } ρL := top.ρL top.ρ = nf*sl*ρL + (1.0-nf)*ρS } // start layer lay.Start(top, grav) // set nodes for _, nod := range lay.Nodes { z := nod.Vert.C[ndim-1] s, err := lay.Calc(z) if err != nil { return chk.Err("cannot compute state @ node z = %g\n%v", z, err) } dof := nod.GetDof("pl") if dof != nil { o.Sol.Y[dof.Eq] = s.pl } } // set elements for _, elem := range lay.Elems { if ele, okk := elem.(ElemIntvars); okk { // build slices coords := ele.Ipoints() nip := len(coords) svT := make([]float64, nip) // total vertical stresses for i := 0; i < nip; i++ { z := coords[i][ndim-1] s, err := lay.Calc(z) if err != nil { return chk.Err("cannot compute state @ ip z = %g\n%v", z, err) } svT[i] = -s.σV } ivs := map[string][]float64{"svT": svT, "K0": []float64{lay.K0}} // set element's states err = ele.SetIniIvs(o.Sol, ivs) if err != nil { return chk.Err("geost: element's internal values setting failed:\n%v", err) } } } } return }
// FindAlongSegment gets the ids of entries that lie close to a segment // Note: the initial (xi) and final (xf) points on segment defined a bounding box of valid points func (o Bins) FindAlongSegment(xi, xf []float64, tol float64) []int { // auxiliary variables var sbins []*Bin // selected bins lmax := utl.Max(o.S[0], o.S[1]) if o.Ndim == 3 { lmax = utl.Max(lmax, o.S[2]) } btol := 0.9 * lmax // tolerance for bins var p, pi, pf Point pi.X = xi[0] pf.X = xf[0] pi.Y = xi[1] pf.Y = xf[1] if o.Ndim == 3 { pi.Z = xi[2] pf.Z = xf[2] } else { xi = []float64{xi[0], xi[1], -1} xf = []float64{xf[0], xf[1], 1} } // loop along all bins var i, j, k int var x, y, z float64 nxy := o.N[0] * o.N[1] for idx, bin := range o.All { // skip empty bins if bin == nil { continue } // coordinates of bin center i = idx % o.N[0] // indices representing bin j = (idx % nxy) / o.N[0] x = o.Xi[0] + float64(i)*o.S[0] // coordinates of bin corner y = o.Xi[1] + float64(j)*o.S[1] x += o.S[0] / 2.0 y += o.S[1] / 2.0 if o.Ndim == 3 { k = idx / nxy z = o.Xi[2] + float64(k)*o.S[2] z += o.S[2] / 2.0 } // check if bin is near line p = Point{x, y, z} d := DistPointLine(&p, &pi, &pf, tol, false) if d <= btol { sbins = append(sbins, bin) } } // entries ids var ids []int // find closest points for _, bin := range sbins { for _, entry := range bin.Entries { x = entry.X[0] y = entry.X[1] if o.Ndim == 3 { z = entry.X[0] } p := Point{x, y, z} d := DistPointLine(&p, &pi, &pf, tol, false) if d <= tol { if IsPointIn(&p, xi, xf, tol) { ids = append(ids, entry.Id) } } } } return ids }
func (o *Plotter) Plot_oct(x, y []float64, res []*State, sts [][]float64, last bool) { // stress path nr := len(res) k := nr - 1 var σa, σb, xmi, xma, ymi, yma float64 for i := 0; i < nr; i++ { σa, σb, _ = tsr.PQW2O(o.P[i], o.Q[i], o.W[i]) x[i], y[i] = σa, σb o.maxR = utl.Max(o.maxR, math.Sqrt(σa*σa+σb*σb)) if i == 0 { xmi, xma = x[i], x[i] ymi, yma = y[i], y[i] } else { xmi = utl.Min(xmi, x[i]) xma = utl.Max(xma, x[i]) ymi = utl.Min(ymi, y[i]) yma = utl.Max(yma, y[i]) } } plt.Plot(x, y, io.Sf("'r.', ls='%s', clip_on=0, color='%s', marker='%s', label=r'%s'", o.Ls, o.Clr, o.Mrk, o.Lbl)) plt.PlotOne(x[0], y[0], io.Sf("'bo', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.SpMrk, o.SpMs)) plt.PlotOne(x[k], y[k], io.Sf("'bs', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.EpMrk, o.EpMs)) // fix range and max radius xmi, xma, ymi, yma = o.fix_range(0, xmi, xma, ymi, yma) rr := math.Sqrt((xma-xmi)*(xma-xmi) + (yma-ymi)*(yma-ymi)) if o.maxR < rr { o.maxR = rr } if o.maxR < 1e-10 { o.maxR = 1 } if yma > -xmi { xmi = -yma } if o.OctLims != nil { xmi, xma, ymi, yma = o.OctLims[0], o.OctLims[1], o.OctLims[2], o.OctLims[3] } //xmi, xma, ymi, yma = -20000, 20000, -20000, 20000 // yield surface var σcmax float64 if o.WithYs && o.m != nil { //io.Pforan("xmi,xma ymi,yma = %v,%v %v,%v\n", xmi,xma, ymi,yma) dx := (xma - xmi) / float64(o.NptsOct-1) dy := (yma - ymi) / float64(o.NptsOct-1) xx := la.MatAlloc(o.NptsOct, o.NptsOct) yy := la.MatAlloc(o.NptsOct, o.NptsOct) zz := la.MatAlloc(o.NptsOct, o.NptsOct) var λ0, λ1, λ2, σc float64 v := NewState(len(res[0].Sig), len(res[0].Alp), false, len(res[0].EpsE) > 0) for k := 0; k < nr; k++ { copy(v.Alp, res[k].Alp) v.Dgam = res[k].Dgam σc = tsr.M_p(res[k].Sig) * tsr.SQ3 //σc = 30000 σcmax = utl.Max(σcmax, σc) for i := 0; i < o.NptsOct; i++ { for j := 0; j < o.NptsOct; j++ { xx[i][j] = xmi + float64(i)*dx yy[i][j] = ymi + float64(j)*dy λ0, λ1, λ2 = tsr.O2L(xx[i][j], yy[i][j], σc) v.Sig[0], v.Sig[1], v.Sig[2] = λ0, λ1, λ2 ys := o.m.YieldFuncs(v) zz[i][j] = ys[0] } } plt.ContourSimple(xx, yy, zz, false, 8, io.Sf("colors=['%s'], levels=[0], linestyles=['%s'], linewidths=[%g], clip_on=0", o.YsClr0, o.YsLs0, o.YsLw0)+o.ArgsYs) } } // predictor-corrector if len(o.PreCor) > 1 { var σa, σb, σanew, σbnew float64 for i := 1; i < len(o.PreCor); i++ { σa, σb, _ = tsr.M_oct(o.PreCor[i-1]) σanew, σbnew, _ = tsr.M_oct(o.PreCor[i]) if math.Abs(σanew-σa) > 1e-7 || math.Abs(σbnew-σb) > 1e-7 { //plt.Plot([]float64{σa,σanew}, []float64{σb,σbnew}, "'k+', ms=3, color='k'") plt.Arrow(σa, σb, σanew, σbnew, io.Sf("sc=%d, fc='%s', ec='%s'", o.ArrWid, o.ClrPC, o.ClrPC)) } o.maxR = utl.Max(o.maxR, math.Sqrt(σa*σa+σb*σb)) o.maxR = utl.Max(o.maxR, math.Sqrt(σanew*σanew+σbnew*σbnew)) } } // rosette and settings if last { tsr.PlotRefOct(o.Phi, σcmax, true) tsr.PlotRosette(o.maxR, false, true, true, 6) if o.OctAxOff { plt.AxisOff() } plt.Gll("$\\sigma_a$", "$\\sigma_b$", "") if lims, ok := o.Lims["oct"]; ok { plt.AxisLims(lims) } if lims, ok := o.Lims["oct,ys"]; ok { plt.AxisLims(lims) } } }
func (o *Plotter) Plot_p_q(x, y []float64, res []*State, sts [][]float64, last bool) { // stress path nr := len(res) k := nr - 1 var xmi, xma, ymi, yma float64 for i := 0; i < nr; i++ { x[i], y[i] = o.P[i], o.Q[i] if o.Multq { mult := fun.Sign(o.W[i]) y[i] *= mult } if o.UseOct { x[i] *= tsr.SQ3 y[i] *= tsr.SQ2by3 } if i == 0 { xmi, xma = x[i], x[i] ymi, yma = y[i], y[i] } else { xmi = utl.Min(xmi, x[i]) xma = utl.Max(xma, x[i]) ymi = utl.Min(ymi, y[i]) yma = utl.Max(yma, y[i]) } if o.SMPon { x[i], y[i], _ = tsr.M_pq_smp(res[i].Sig, o.SMPa, o.SMPb, o.SMPβ, o.SMPϵ) } } plt.Plot(x, y, io.Sf("'r.', ls='%s', clip_on=0, color='%s', marker='%s', label=r'%s'", o.Ls, o.Clr, o.Mrk, o.Lbl)) plt.PlotOne(x[0], y[0], io.Sf("'bo', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.SpMrk, o.SpMs)) plt.PlotOne(x[k], y[k], io.Sf("'bs', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.EpMrk, o.EpMs)) // yield surface if o.WithYs && o.m != nil { mx, my := 1.0, 1.0 if o.UseOct { mx, my = tsr.SQ3, tsr.SQ2by3 } if o.UsePmin { xmi = utl.Min(xmi, o.Pmin*mx) } if o.UsePmax { xma = utl.Max(xma, o.Pmax*mx) yma = utl.Max(yma, o.Pmax*my) } xmi, xma, ymi, yma = o.fix_range(xmi, xmi, xma, ymi, yma) if o.PqLims != nil { xmi, xma, ymi, yma = o.PqLims[0], o.PqLims[1], o.PqLims[2], o.PqLims[3] } //io.Pforan("xmi,xma ymi,yma = %v,%v %v,%v\n", xmi,xma, ymi,yma) dx := (xma - xmi) / float64(o.NptsPq-1) dy := (yma - ymi) / float64(o.NptsPq-1) xx := la.MatAlloc(o.NptsPq, o.NptsPq) yy := la.MatAlloc(o.NptsPq, o.NptsPq) za := la.MatAlloc(o.NptsPq, o.NptsPq) zb := la.MatAlloc(o.NptsPq, o.NptsPq) var p, q, σa, σb, σc, λ0, λ1, λ2 float64 v := NewState(len(res[0].Sig), len(res[0].Alp), false, len(res[0].EpsE) > 0) for k := 0; k < nr; k++ { copy(v.Alp, res[k].Alp) v.Dgam = res[k].Dgam for i := 0; i < o.NptsPq; i++ { for j := 0; j < o.NptsPq; j++ { xx[i][j] = xmi + float64(i)*dx yy[i][j] = ymi + float64(j)*dy p, q = xx[i][j], yy[i][j] if o.UseOct { p /= tsr.SQ3 q /= tsr.SQ2by3 } σa, σb, σc = tsr.PQW2O(p, q, o.W[k]) λ0, λ1, λ2 = tsr.O2L(σa, σb, σc) v.Sig[0], v.Sig[1], v.Sig[2] = λ0, λ1, λ2 ys := o.m.YieldFuncs(v) za[i][j] = ys[0] if o.nsurf > 1 { zb[i][j] = ys[1] } if o.SMPon { xx[i][j], yy[i][j], _ = tsr.M_pq_smp(v.Sig, o.SMPa, o.SMPb, o.SMPβ, o.SMPϵ) } } } plt.ContourSimple(xx, yy, za, false, 8, io.Sf("colors=['%s'], levels=[0], linestyles=['%s'], linewidths=[%g], clip_on=0", o.YsClr0, o.YsLs0, o.YsLw0)+o.ArgsYs) if o.nsurf > 1 { plt.ContourSimple(xx, yy, zb, false, 8, io.Sf("colors=['%s'], levels=[0], linestyles=['%s'], linewidths=[%g], clip_on=0", o.YsClr1, o.YsLs1, o.YsLw1)+o.ArgsYs) } } } // predictor-corrector if len(o.PreCor) > 1 { var p, q, pnew, qnew float64 for i := 1; i < len(o.PreCor); i++ { p = tsr.M_p(o.PreCor[i-1]) q = tsr.M_q(o.PreCor[i-1]) pnew = tsr.M_p(o.PreCor[i]) qnew = tsr.M_q(o.PreCor[i]) if o.UseOct { p *= tsr.SQ3 pnew *= tsr.SQ3 q *= tsr.SQ2by3 qnew *= tsr.SQ2by3 } if o.SMPon { p, q, _ = tsr.M_pq_smp(o.PreCor[i-1], o.SMPa, o.SMPb, o.SMPβ, o.SMPϵ) pnew, qnew, _ = tsr.M_pq_smp(o.PreCor[i], o.SMPa, o.SMPb, o.SMPβ, o.SMPϵ) } if math.Abs(pnew-p) > 1e-10 || math.Abs(qnew-q) > 1e-10 { plt.Arrow(p, q, pnew, qnew, io.Sf("sc=%d, fc='%s', ec='%s'", o.ArrWid, o.ClrPC, o.ClrPC)) } } } // settings if last { plt.Equal() xl, yl := "$p_{cam}$", "$q_{cam}$" if o.UseOct { xl, yl = "$p_{oct}$", "$q_{oct}$" } if o.SMPon { xl, yl = "$p_{smp}$", "$q_{smp}$" } if o.AxLblX != "" { xl = o.AxLblX } if o.AxLblY != "" { yl = o.AxLblY } plt.Gll(xl, yl, "leg_out=1, leg_ncol=4, leg_hlen=1.5") if lims, ok := o.Lims["p,q"]; ok { plt.AxisLims(lims) } if lims, ok := o.Lims["p,q,ys"]; ok { plt.AxisLims(lims) } } }
func (o *Plotter) Plot_s3_s1(x, y []float64, res []*State, sts [][]float64, last bool) { // stress path nr := len(res) k := nr - 1 x2 := make([]float64, nr) var xmi, xma, ymi, yma float64 for i := 0; i < nr; i++ { σ1, σ2, σ3, err := tsr.M_PrincValsNum(res[i].Sig) if err != nil { chk.Panic("computation of eigenvalues failed", err) } x[i], y[i] = -tsr.SQ2*σ3, -σ1 x2[i] = -tsr.SQ2 * σ2 if i == 0 { xmi, xma = x[i], x[i] ymi, yma = y[i], y[i] } else { xmi = utl.Min(utl.Min(xmi, x[i]), x2[i]) xma = utl.Max(utl.Max(xma, x[i]), x2[i]) ymi = utl.Min(ymi, y[i]) yma = utl.Max(yma, y[i]) } } plt.Plot(x, y, io.Sf("'r.', ls='%s', clip_on=0, color='%s', marker='%s', label=r'$\\sigma_3$ %s'", o.Ls, o.Clr, o.Mrk, o.Lbl)) plt.Plot(x2, y, io.Sf("'r.', ls='%s', clip_on=0, color='%s', marker='%s', label=r'$\\sigma_2$ %s'", o.LsAlt, o.Clr, o.Mrk, o.Lbl)) plt.PlotOne(x[0], y[0], io.Sf("'bo', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.SpMrk, o.SpMs)) plt.PlotOne(x[k], y[k], io.Sf("'bs', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.EpMrk, o.EpMs)) // yield surface if o.WithYs && o.m != nil { if o.UsePmin { xmi = utl.Min(xmi, o.Pmin*tsr.SQ2) ymi = utl.Min(ymi, o.Pmin) } if o.UsePmax { xma = utl.Max(xma, o.Pmax*tsr.SQ2) yma = utl.Max(yma, o.Pmax) } xmi, xma, ymi, yma = o.fix_range(0, xmi, xma, ymi, yma) if o.S3s1Lims != nil { xmi, xma, ymi, yma = o.S3s1Lims[0], o.S3s1Lims[1], o.S3s1Lims[2], o.S3s1Lims[3] } //io.Pforan("xmi,xma ymi,yma = %v,%v %v,%v\n", xmi,xma, ymi,yma) dx := (xma - xmi) / float64(o.NptsSig-1) dy := (yma - ymi) / float64(o.NptsSig-1) xx := la.MatAlloc(o.NptsSig, o.NptsSig) yy := la.MatAlloc(o.NptsSig, o.NptsSig) zz := la.MatAlloc(o.NptsSig, o.NptsSig) v := NewState(len(res[0].Sig), len(res[0].Alp), false, len(res[0].EpsE) > 0) for k := 0; k < nr; k++ { copy(v.Alp, res[k].Alp) v.Dgam = res[k].Dgam for i := 0; i < o.NptsSig; i++ { for j := 0; j < o.NptsSig; j++ { xx[i][j] = xmi + float64(i)*dx yy[i][j] = ymi + float64(j)*dy v.Sig[0], v.Sig[1], v.Sig[2] = -yy[i][j], -xx[i][j]/tsr.SQ2, -xx[i][j]/tsr.SQ2 ys := o.m.YieldFuncs(v) zz[i][j] = ys[0] } } plt.ContourSimple(xx, yy, zz, false, 8, io.Sf("colors=['%s'], levels=[0], linestyles=['%s'], linewidths=[%g], clip_on=0", o.YsClr0, o.YsLs0, o.YsLw0)+o.ArgsYs) } } // predictor-corrector if len(o.PreCor) > 1 { var σ3, σ1, σ3new, σ1new float64 for i := 1; i < len(o.PreCor); i++ { σ1, _, σ3, _ = tsr.M_PrincValsNum(o.PreCor[i-1]) σ1new, _, σ3new, _ = tsr.M_PrincValsNum(o.PreCor[i]) if math.Abs(σ3new-σ3) > 1e-7 || math.Abs(σ1new-σ1) > 1e-7 { plt.Arrow(-σ3*tsr.SQ2, -σ1, -σ3new*tsr.SQ2, -σ1new, io.Sf("sc=%d, fc='%s', ec='%s'", o.ArrWid, o.ClrPC, o.ClrPC)) } } } // settings if last { plt.Equal() plt.Gll("$-\\sqrt{2}\\sigma_3$", "$-\\sigma_1$", "leg=1, leg_out=1, leg_ncol=4, leg_hlen=2") if lims, ok := o.Lims["s3,s1"]; ok { plt.AxisLims(lims) } if lims, ok := o.Lims["s3,s1,ys"]; ok { plt.AxisLims(lims) } } }
// 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 }
func Test_flt03(tst *testing.T) { //verbose() chk.PrintTitle("flt03. sin⁶(5 π x) multimodal") // configuration C := NewConfParams() C.Nova = 1 C.Noor = 2 C.Nisl = 4 C.Ninds = 24 C.GAtype = "crowd" C.DiffEvol = true C.CrowdSize = 3 C.ParetoPhi = 0.01 C.CompProb = true C.Tf = 100 C.Dtmig = 60 C.RangeFlt = [][]float64{{0, 0.9999999999999}} C.PopFltGen = PopFltGen C.CalcDerived() rnd.Init(C.Seed) // post-processing function values := utl.Deep3alloc(C.Tf/10, C.Nisl, C.Ninds) C.PostProc = func(idIsland, time int, pop Population) { if time%10 == 0 { k := time / 10 for i, ind := range pop { values[k][idIsland][i] = ind.GetFloat(0) } } } // functions yfcn := func(x float64) float64 { return math.Pow(math.Sin(5.0*math.Pi*x), 6.0) } fcn := func(f, g, h []float64, x []float64) { f[0] = -yfcn(x[0]) } // simple problem sim := NewSimpleFltProb(fcn, 1, 0, 0, C) sim.Run(chk.Verbose) // write histograms and plot if chk.Verbose { // write histograms var buf bytes.Buffer hist := rnd.Histogram{Stations: utl.LinSpace(0, 1, 13)} for k := 0; k < C.Tf/10; k++ { for i := 0; i < C.Nisl; i++ { clear := false if i == 0 { clear = true } hist.Count(values[k][i], clear) } io.Ff(&buf, "\ntime=%d\n%v", k*10, rnd.TextHist(hist.GenLabels("%4.2f"), hist.Counts, 60)) } io.WriteFileVD("/tmp/goga", "test_flt03_hist.txt", &buf) // plot plt.SetForEps(0.8, 300) xmin := sim.Evo.Islands[0].Pop[0].GetFloat(0) xmax := xmin for k := 0; k < C.Nisl; k++ { for _, ind := range sim.Evo.Islands[k].Pop { x := ind.GetFloat(0) y := yfcn(x) xmin = utl.Min(xmin, x) xmax = utl.Max(xmax, x) plt.PlotOne(x, y, "'r.',clip_on=0,zorder=20") } } np := 401 X := utl.LinSpace(0, 1, np) Y := make([]float64, np) for i := 0; i < np; i++ { Y[i] = yfcn(X[i]) } plt.Plot(X, Y, "'b-',clip_on=0,zorder=10") plt.Gll("$x$", "$y$", "") plt.SaveD("/tmp/goga", "test_flt03_func.eps") } }
// Start starts handling of results given a simulation input file func Start(simfnpath string, stageIdx, regionIdx int) { // fem structure Analysis = fem.NewFEM(simfnpath, "", false, false, true, false, false, 0) Dom = Analysis.Domains[regionIdx] Sum = Analysis.Summary // set stage err := Analysis.SetStage(stageIdx) if err != nil { chk.Panic("cannot set stage:\n%v", err) } // initialise solution vectors err = Analysis.ZeroStage(stageIdx, true) if err != nil { chk.Panic("cannot initialise solution vectors:\n%v", err) } // clear previous data Ipoints = make([]*fem.OutIpData, 0) Cid2ips = make([][]int, len(Dom.Msh.Cells)) Ipkey2ips = make(map[string][]int) Ipkeys = make(map[string]bool) Planes = make(map[string]*PlaneData) Results = make(map[string]Points) TimeInds = make([]int, 0) Times = make([]float64, 0) Splots = make([]*SplotDat, 0) // bins m := Dom.Msh δ := TolC * 2 xi := []float64{m.Xmin - δ, m.Ymin - δ} xf := []float64{m.Xmax + δ, m.Ymax + δ} if m.Ndim == 3 { xi = append(xi, m.Zmin-δ) xf = append(xf, m.Zmax+δ) } err = NodBins.Init(xi, xf, Ndiv) if err != nil { chk.Panic("cannot initialise bins for nodes: %v", err) } err = IpsBins.Init(xi, xf, Ndiv) if err != nil { chk.Panic("cannot initialise bins for integration points: %v", err) } // add nodes to bins for _, nod := range Dom.Nodes { err := NodBins.Append(nod.Vert.C, nod.Vert.Id) if err != nil { return } } // to find limits ndim := Dom.Msh.Ndim IpsMin = make([]float64, ndim) IpsMax = make([]float64, ndim) first := true // add integration points to slice of ips and to bins for cid, ele := range Dom.Cid2elem { if ele == nil { continue } dat := ele.OutIpsData() nip := len(dat) ids := make([]int, nip) for i, d := range dat { // add to bins ipid := len(Ipoints) ids[i] = ipid Ipoints = append(Ipoints, d) err = IpsBins.Append(d.X, ipid) if err != nil { chk.Panic("cannot append to bins of integration points: %v", err) } // set auxiliary map vals := d.Calc(Dom.Sol) for key, _ := range vals { utl.StrIntsMapAppend(&Ipkey2ips, key, ipid) Ipkeys[key] = true } // limits if first { for j := 0; j < ndim; j++ { IpsMin[j] = d.X[j] IpsMax[j] = d.X[j] } first = false } else { for j := 0; j < ndim; j++ { IpsMin[j] = utl.Min(IpsMin[j], d.X[j]) IpsMax[j] = utl.Max(IpsMax[j], d.X[j]) } } } Cid2ips[cid] = ids } }
// RunFEM runs FE analysis. func (o *FemData) RunFEM(Enabled []int, Areas []float64, draw int, debug bool) (mobility, failed, weight, umax, smax, errU, errS float64) { // check for NaNs defer func() { if math.IsNaN(mobility) || math.IsNaN(failed) || math.IsNaN(weight) || math.IsNaN(umax) || math.IsNaN(smax) || math.IsNaN(errU) || math.IsNaN(errS) { io.PfRed("enabled := %+#v\n", Enabled) io.PfRed("areas := %+#v\n", Areas) chk.Panic("NaN: mobility=%v failed=%v weight=%v umax=%v smax=%v errU=%v errS=%v\n", mobility, failed, weight, umax, smax, errU, errS) } }() // set connectivity if o.Opt.BinInt { for cid, ena := range Enabled { o.Dom.Msh.Cells[cid].Disabled = true if ena == 1 { o.Dom.Msh.Cells[cid].Disabled = false } } } else { for _, cell := range o.Dom.Msh.Cells { cid := cell.Id xid := o.Cid2xid[cid] o.Dom.Msh.Cells[cid].Disabled = true if Areas[xid] >= o.Opt.aEps { o.Dom.Msh.Cells[cid].Disabled = false } } } // set stage o.Analysis.SetStage(0) // check for required vertices nnod := len(o.Dom.Nodes) for _, vid := range o.ReqVids { if o.Dom.Vid2node[vid] == nil { //io.Pforan("required vertex (%d) missing\n", vid) mobility, failed, errU, errS = float64(1+2*nnod), 1, 1, 1 return } } // compute mobility if o.Opt.Mobility { m := len(o.Dom.Elems) d := len(o.Dom.EssenBcs.Bcs) M := 2*nnod - m - d if M > 0 { //io.Pforan("full mobility: M=%v\n", M) mobility, failed, errU, errS = float64(M), 1, 1, 1 return } } // set elements' cross-sectional areas and compute weight for _, elem := range o.Dom.Elems { ele := elem.(*fem.ElastRod) cid := ele.Cell.Id xid := o.Cid2xid[cid] ele.Mdl.A = Areas[xid] ele.Recompute(false) weight += ele.Mdl.Rho * ele.Mdl.A * ele.L } // run FE analysis err := o.Analysis.SolveOneStage(0, true) if err != nil { //io.Pforan("analysis failed\n") mobility, failed, errU, errS = 0, 1, 1, 1 return } // find maximum deflection // Note that sometimes a mechanism can happen that makes the tip to move upwards if o.VidU >= 0 { eq := o.Dom.Vid2node[o.VidU].GetEq("uy") uy := o.Dom.Sol.Y[eq] umax = math.Abs(uy) } else { for _, nod := range o.Dom.Nodes { eq := nod.GetEq("uy") uy := o.Dom.Sol.Y[eq] umax = utl.Max(umax, math.Abs(uy)) } } errU = fun.Ramp(umax - o.Opt.Uawd) // find max stress for _, elem := range o.Dom.Elems { ele := elem.(*fem.ElastRod) tag := ele.Cell.Tag sig := ele.CalcSig(o.Dom.Sol) smax = utl.Max(smax, math.Abs(sig)) errS = utl.Max(errS, o.Opt.CalcErrSig(tag, sig)) } errS = fun.Ramp(errS) // draw if draw > 0 { lwds := make(map[int]float64) for _, elem := range o.Dom.Elems { ele := elem.(*fem.ElastRod) cid := ele.Cell.Id lwds[cid] = 0.1 + ele.Mdl.A/20.0 } o.Dom.Msh.Draw2d(true, false, lwds, 1) //plt.Title(io.Sf("weight=%.3f deflection=%.6f", weight, umax), "") //plt.SaveD("/tmp/goga", io.Sf("mesh-topology-%03d.eps", draw)) } // debug if false && (umax > 0 && errS < 1e-10) { io.PfYel("enabled := %+#v\n", Enabled) io.Pf("areas := %+#v\n", Areas) io.Pf("weight = %v\n", weight) io.Pf("umax = %v\n", umax) io.Pf("smax = %v\n", smax) io.Pf("errU = %v\n", errU) io.Pf("errS = %v\n", errS) // post-processing msh := o.Dom.Msh vid := msh.VertTag2verts[-4][0].Id nod := o.Dom.Vid2node[vid] eqy := nod.GetEq("uy") uy := o.Dom.Sol.Y[eqy] io.Pfblue2("%2d : uy = %g\n", vid, uy) } return }
// Draw draws grid // r -- radius of circles // W -- width of paths // dwt -- δwt for positioning text (w = W/2) // arrow_scale -- scale for arrows. use 0 for default value func (o *Graph) Draw(dirout, fname string, r, W, dwt, arrow_scale float64, verts_lbls map[int]string, verts_fsz float64, verts_clr string, edges_lbls map[int]string, edges_fsz float64, edges_clr string) { if len(o.Verts) < 1 { return } xmin, ymin := o.Verts[0][0], o.Verts[0][1] xmax, ymax := xmin, ymin var lbl string for i, v := range o.Verts { if verts_lbls == nil { lbl = io.Sf("%d", i) } else { lbl = verts_lbls[i] } plt.Text(v[0], v[1], lbl, io.Sf("clip_on=0, color='%s', fontsize=%g, ha='center', va='center'", verts_clr, verts_fsz)) plt.Circle(v[0], v[1], r, "clip_on=0, ec='k', lw=0.8") xmin, ymin = utl.Min(xmin, v[0]), utl.Min(ymin, v[1]) xmax, ymax = utl.Max(xmax, v[0]), utl.Max(ymax, v[1]) } if W > 2*r { W = 1.8 * r } w := W / 2.0 xa, xb := make([]float64, 2), make([]float64, 2) xc, dx := make([]float64, 2), make([]float64, 2) mu, nu := make([]float64, 2), make([]float64, 2) xi, xj := make([]float64, 2), make([]float64, 2) l := math.Sqrt(r*r - w*w) var L float64 if arrow_scale <= 0 { arrow_scale = 20 } for k, e := range o.Edges { L = 0.0 for i := 0; i < 2; i++ { xa[i] = o.Verts[e[0]][i] xb[i] = o.Verts[e[1]][i] xc[i] = (xa[i] + xb[i]) / 2.0 dx[i] = xb[i] - xa[i] L += dx[i] * dx[i] } L = math.Sqrt(L) mu[0], mu[1] = dx[0]/L, dx[1]/L nu[0], nu[1] = -dx[1]/L, dx[0]/L for i := 0; i < 2; i++ { xi[i] = xa[i] + l*mu[i] - w*nu[i] xj[i] = xb[i] - l*mu[i] - w*nu[i] xc[i] = (xi[i]+xj[i])/2.0 - dwt*nu[i] } plt.Arrow(xi[0], xi[1], xj[0], xj[1], io.Sf("st='->', sc=%g", arrow_scale)) if edges_lbls == nil { lbl = io.Sf("%d", k) } else { lbl = edges_lbls[k] } plt.Text(xc[0], xc[1], lbl, io.Sf("clip_on=0, color='%s', fontsize=%g, ha='center', va='center'", edges_clr, edges_fsz)) } xmin -= r xmax += r ymin -= r ymax += r plt.AxisOff() plt.Equal() plt.AxisRange(xmin, xmax, ymin, ymax) plt.SaveD(dirout, fname) }
func (o *Plotter) Plot_p_ev(x, y []float64, res []*State, sts [][]float64, last bool) { nr := len(res) if len(sts) != nr { return } k := nr - 1 var x0, x1 []float64 if !o.NoAlp { x0, x1 = make([]float64, nr), make([]float64, nr) } withα := false if o.LogP { xmin := o.calc_x(o.P[0]) xmax := xmin for i := 0; i < nr; i++ { x[i], y[i] = o.calc_x(o.P[i]), o.Ev[i]*100.0 if !o.NoAlp && len(res[i].Alp) > 0 { withα = true x0[i] = o.calc_x(res[i].Alp[0]) if o.nsurf > 1 { x1[i] = o.calc_x(res[i].Alp[1]) } } xmin = utl.Min(xmin, x[i]) xmax = utl.Max(xmax, x[i]) } } else { xmin := o.P[0] xmax := xmin for i := 0; i < nr; i++ { x[i], y[i] = o.P[i], o.Ev[i]*100.0 if !o.NoAlp && len(res[i].Alp) > 0 { withα = true x0[i] = res[i].Alp[0] if o.nsurf > 1 { x1[i] = res[i].Alp[1] } } xmin = utl.Min(xmin, x[i]) xmax = utl.Max(xmax, x[i]) } } if withα { plt.Plot(x0, y, io.Sf("'r-', ls='--', lw=3, clip_on=0, color='grey', label=r'%s'", o.Lbl+" $\\alpha_0$")) if o.nsurf > 1 { plt.Plot(x1, y, io.Sf("'r-', ls=':', lw=3, clip_on=0, color='grey', label=r'%s'", o.Lbl+" $\\alpha_1$")) } } plt.Plot(x, y, io.Sf("'r.', ls='-', clip_on=0, color='%s', marker='%s', label=r'%s'", o.Clr, o.Mrk, o.Lbl)) plt.PlotOne(x[0], y[0], io.Sf("'bo', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.SpMrk, o.SpMs)) plt.PlotOne(x[k], y[k], io.Sf("'bs', clip_on=0, color='%s', marker='%s', ms=%d", o.SpClr, o.EpMrk, o.EpMs)) if last { xlbl := "$p$" if o.LogP { xlbl = "$\\log{[1+(p+p_t)/p_r]}$" } plt.Gll(xlbl, "$\\varepsilon_v\\;[\\%]$", "leg_out=1, leg_ncol=4, leg_hlen=2") if lims, ok := o.Lims["p,ev"]; ok { plt.AxisLims(lims) } } }