// CheckDSdR checks dSdR derivatives of shape structures func CheckDSdR(tst *testing.T, shape *Shape, r []float64, tol float64, verbose bool) { // auxiliary r_tmp := make([]float64, len(r)) S_tmp := make([]float64, shape.Nverts) // analytical shape.Func(shape.S, shape.DSdR, r, true, -1) // numerical for n := 0; n < shape.Nverts; n++ { for i := 0; i < shape.Gndim; i++ { dSndRi, _ := num.DerivCentral(func(t float64, args ...interface{}) (Sn float64) { copy(r_tmp, r) r_tmp[i] = t shape.Func(S_tmp, nil, r_tmp, false, -1) Sn = S_tmp[n] return }, r[i], 1e-1) if verbose { io.Pfgrey2(" dS%ddR%d @ %5.2f = %v (num: %v)\n", n, i, r, shape.DSdR[n][i], dSndRi) } if math.Abs(shape.DSdR[n][i]-dSndRi) > tol { tst.Errorf("nurbs dS%ddR%d failed with err = %g\n", n, i, math.Abs(shape.DSdR[n][i]-dSndRi)) return } } } }
// CheckDSdx checks G=dSdx derivatives of shape structures func CheckDSdx(tst *testing.T, shape *Shape, xmat [][]float64, x []float64, tol float64, verbose bool) { // find r corresponding to x r := make([]float64, 3) err := shape.InvMap(r, x, xmat) if err != nil { tst.Errorf("InvMap failed:\n%v", err) return } // analytical err = shape.CalcAtIp(xmat, r, true) if err != nil { tst.Errorf("CalcAtIp failed:\n%v", err) return } // numerical x_tmp := make([]float64, len(x)) for n := 0; n < shape.Nverts; n++ { for i := 0; i < shape.Gndim; i++ { dSnDxi, _ := num.DerivCentral(func(t float64, args ...interface{}) (Sn float64) { copy(x_tmp, x) x_tmp[i] = t err = shape.InvMap(r, x_tmp, xmat) if err != nil { tst.Errorf("InvMap failed:\n%v", err) return } err = shape.CalcAtIp(xmat, r, false) if err != nil { tst.Errorf("CalcAtIp failed:\n%v", err) return } Sn = shape.S[n] return }, x[i], 1e-1) if verbose { io.Pfgrey2(" dS%dDx%d @ %5.2f = %v (num: %v)\n", n, i, x, shape.G[n][i], dSnDxi) } if math.Abs(shape.G[n][i]-dSnDxi) > tol { tst.Errorf("nurbs dS%dDx%d failed with err = %g\n", n, i, math.Abs(shape.G[n][i]-dSnDxi)) return } } } }
// checkDerivs checks dSdR derivatives of shape structures func checkDerivs(tst *testing.T, shape string, r []float64, tol float64, verbose bool) { // information fcn := Functions[shape] ndim := GeomNdim[shape] nverts := NumVerts[shape] // allocate slices S := make([]float64, nverts) dSdR := utl.DblsAlloc(nverts, ndim) // auxiliary r_tmp := make([]float64, len(r)) S_tmp := make([]float64, nverts) // analytical fcn(S, dSdR, r, true) // numerical for n := 0; n < nverts; n++ { for i := 0; i < ndim; i++ { dSndRi, _ := num.DerivCentral(func(t float64, args ...interface{}) (Sn float64) { copy(r_tmp, r) r_tmp[i] = t fcn(S_tmp, nil, r_tmp, false) Sn = S_tmp[n] return }, r[i], 1e-1) if verbose { io.Pfgrey2(" dS%ddR%d @ %5.2f = %v (num: %v)\n", n, i, r, dSdR[n][i], dSndRi) } if math.Abs(dSdR[n][i]-dSndRi) > tol { tst.Errorf("nurbs dS%ddR%d failed with err = %g\n", n, i, math.Abs(dSdR[n][i]-dSndRi)) return } } } }
// 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) } } } } } } } }
// Run computes β starting witn an initial guess func (o *ReliabFORM) Run(βtrial float64, verbose bool, args ...interface{}) (β float64, μ, σ, x []float64) { // initial random variables β = βtrial nx := len(o.μ) μ = make([]float64, nx) // mean values (equivalent normal value) σ = make([]float64, nx) // deviation values (equivalent normal value) x = make([]float64, nx) // current vector of random variables defining min(β) for i := 0; i < nx; i++ { μ[i] = o.μ[i] σ[i] = o.σ[i] x[i] = o.μ[i] } // lognormal distribution structure var lnd DistLogNormal // has lognormal random variable? haslrv := false for _, found := range o.lrv { if found { haslrv = true break } } // function to compute β with x-constant // gβ(β) = g(μ - β・A・σ) = 0 var err error gβfcn := func(fy, y []float64) error { βtmp := y[0] for i := 0; i < nx; i++ { o.xtmp[i] = μ[i] - βtmp*o.α[i]*σ[i] } fy[0], err = o.gfcn(o.xtmp, args) if err != nil { chk.Panic("cannot compute gfcn(%v):\n%v", o.xtmp, err) } return nil } // derivative of gβ w.r.t β hβfcn := func(dfdy [][]float64, y []float64) error { βtmp := y[0] for i := 0; i < nx; i++ { o.xtmp[i] = μ[i] - βtmp*o.α[i]*σ[i] } err = o.hfcn(o.dgdx, o.xtmp, args) if err != nil { chk.Panic("cannot compute hfcn(%v):\n%v", o.xtmp, err) } dfdy[0][0] = 0 for i := 0; i < nx; i++ { dfdy[0][0] -= o.dgdx[i] * o.α[i] * σ[i] } return nil } // nonlinear solver with y[0] = β // solving: gβ(β) = g(μ - β・A・σ) = 0 var nls num.NlSolver nls.Init(1, gβfcn, nil, hβfcn, true, false, nil) defer nls.Clean() // message if verbose { io.Pf("\n%s", io.StrThickLine(60)) } // plotting plot := o.PlotFnk != "" if nx != 2 { plot = false } if plot { if o.PlotNp < 3 { o.PlotNp = 41 } var umin, umax, vmin, vmax float64 if o.PlotCf < 1 { o.PlotCf = 2 } if len(o.PlotUrange) == 0 { umin, umax = μ[0]-o.PlotCf*μ[0], μ[0]+o.PlotCf*μ[0] vmin, vmax = μ[1]-o.PlotCf*μ[1], μ[1]+o.PlotCf*μ[1] } else { chk.IntAssert(len(o.PlotUrange), 2) chk.IntAssert(len(o.PlotVrange), 2) umin, umax = o.PlotUrange[0], o.PlotUrange[1] vmin, vmax = o.PlotVrange[0], o.PlotVrange[1] } o.PlotU, o.PlotV = utl.MeshGrid2D(umin, umax, vmin, vmax, o.PlotNp, o.PlotNp) o.PlotZ = la.MatAlloc(o.PlotNp, o.PlotNp) plt.SetForEps(0.8, 300) for i := 0; i < o.PlotNp; i++ { for j := 0; j < o.PlotNp; j++ { o.xtmp[0] = o.PlotU[i][j] o.xtmp[1] = o.PlotV[i][j] o.PlotZ[i][j], err = o.gfcn(o.xtmp, args) if err != nil { chk.Panic("cannot compute gfcn(%v):\n%v", x, err) } } } plt.Contour(o.PlotU, o.PlotV, o.PlotZ, "") plt.ContourSimple(o.PlotU, o.PlotV, o.PlotZ, true, 8, "levels=[0], colors=['yellow']") plt.PlotOne(x[0], x[1], "'ro', label='initial'") } // iterations to find β var dat VarData B := []float64{β} itB := 0 for itB = 0; itB < o.NmaxItB; itB++ { // message if verbose { gx, err := o.gfcn(x, args) if err != nil { chk.Panic("cannot compute gfcn(%v):\n%v", x, err) } io.Pf("%s itB=%d β=%g g=%g\n", io.StrThinLine(60), itB, β, gx) } // plot if plot { plt.PlotOne(x[0], x[1], "'r.'") } // compute direction cosines itA := 0 for itA = 0; itA < o.NmaxItA; itA++ { // has lognormal random variable (lrv) if haslrv { // find equivalent normal mean and std deviation for lognormal variables for i := 0; i < nx; i++ { if o.lrv[i] { // set distribution dat.M, dat.S = o.μ[i], o.σ[i] lnd.Init(&dat) // update μ and σ fx := lnd.Pdf(x[i]) Φinvx := (math.Log(x[i]) - lnd.M) / lnd.S φx := math.Exp(-Φinvx*Φinvx/2.0) / math.Sqrt2 / math.SqrtPi σ[i] = φx / fx μ[i] = x[i] - Φinvx*σ[i] } } } // compute direction cosines err = o.hfcn(o.dgdx, x, args) if err != nil { chk.Panic("cannot compute hfcn(%v):\n%v", x, err) } den := 0.0 for i := 0; i < nx; i++ { den += math.Pow(o.dgdx[i]*σ[i], 2.0) } den = math.Sqrt(den) αerr := 0.0 // difference on α for i := 0; i < nx; i++ { αnew := o.dgdx[i] * σ[i] / den αerr += math.Pow(αnew-o.α[i], 2.0) o.α[i] = αnew } αerr = math.Sqrt(αerr) // message if verbose { io.Pf(" itA=%d\n", itA) io.Pf("%12s%12s%12s%12s\n", "x", "μ", "σ", "α") for i := 0; i < nx; i++ { io.Pf("%12.3f%12.3f%12.3f%12.3f\n", x[i], μ[i], σ[i], o.α[i]) } } // update x-star for i := 0; i < nx; i++ { x[i] = μ[i] - β*o.α[i]*σ[i] } // check convergence on α if itA > 1 && αerr < o.TolA { if verbose { io.Pfgrey(". . . converged on α with αerr=%g . . .\n", αerr) } break } } // failed to converge on α if itA == o.NmaxItA { chk.Panic("failed to convege on α") } // compute new β B[0] = β nls.Solve(B, o.NlsSilent) βerr := math.Abs(B[0] - β) β = B[0] if o.NlsCheckJ { nls.CheckJ(B, o.NlsCheckJtol, true, false) } // update x-star for i := 0; i < nx; i++ { x[i] = μ[i] - β*o.α[i]*σ[i] } // check convergence on β if βerr < o.TolB { if verbose { io.Pfgrey2(". . . converged on β with βerr=%g . . .\n", βerr) } break } } // failed to converge on β if itB == o.NmaxItB { chk.Panic("failed to converge on β") } // message if verbose { gx, err := o.gfcn(x, args) if err != nil { chk.Panic("cannot compute gfcn(%v):\n%v", x, err) } io.Pfgreen("x = %v\n", x) io.Pfgreen("g = %v\n", gx) io.PfGreen("β = %v\n", β) } // plot if plot { plt.Gll("$x_0$", "$x_1$", "") plt.Cross("") plt.SaveD("/tmp/gosl", "fig_form_"+o.PlotFnk+".eps") } return }
func Test_shape01(tst *testing.T) { //utl.Tsilent = false chk.PrintTitle("Test shape01") for name, shape := range factory { io.Pfyel("--------------------------------- %-6s---------------------------------\n", name) // check S tol := 1e-17 errS := 0.0 if name == "tri10" { tol = 1e-14 } for n := 0; n < shape.Nverts; n++ { rst := []float64{0, 0, 0} for i := 0; i < shape.Gndim; i++ { rst[i] = shape.NatCoords[i][n] } shape.Func(shape.S, shape.dSdR, rst[0], rst[1], rst[2], false) io.Pforan("S = %v\n", shape.S) for m := 0; m < shape.Nverts; m++ { if n == m { errS += math.Abs(shape.S[m] - 1.0) } else { errS += math.Abs(shape.S[m]) } } } if errS > tol { tst.Errorf("%s failed with err = %g\n", name, errS) return } // check dSdR tol = 1e-14 h := 1.0e-1 S_temp := make([]float64, shape.Nverts) if name == "lin5" || name == "tri15" || name == "lin4" || name == "tri10" || name == "qua12" || name == "qua16" { tol = 1.0e-10 } for n := 0; n < shape.Nverts; n++ { rst := []float64{0, 0, 0} for i := 0; i < shape.Gndim; i++ { rst[i] = shape.NatCoords[i][n] } // analytical shape.Func(shape.S, shape.dSdR, rst[0], rst[1], rst[2], true) // numerical for i := 0; i < shape.Gndim; i++ { dSndRi, _ := num.DerivCentral(func(x float64, args ...interface{}) (Sn float64) { rst_temp := []float64{rst[0], rst[1], rst[2]} rst_temp[i] = x shape.Func(S_temp, nil, rst_temp[0], rst_temp[1], rst_temp[2], false) Sn = S_temp[n] return }, rst[i], h) io.Pfgrey2(" dS%ddR%d @ [% 4.1f % 4.1f % 4.1f] = %v (num: %v)\n", n, i, rst[0], rst[1], rst[2], shape.dSdR[n][i], dSndRi) tol2 := tol if name == "tri15" && n == 11 && i == 1 { tol2 = 1.0e-9 } if math.Abs(shape.dSdR[n][i]-dSndRi) > tol2 { tst.Errorf("%s dS%ddR%d failed with err = %g\n", name, n, i, math.Abs(shape.dSdR[n][i]-dSndRi)) return } //chk.Scalar(tst, fmt.Sprintf("dS%ddR%d", n, i), tol2, dSdR[n][i], dSndRi) } } // check face vertices tol = 1e-17 errS = 0.0 if name == "tri10" { tol = 1e-14 } nfaces := len(shape.FaceLocalV) if nfaces == 0 { continue } for k := 0; k < nfaces; k++ { for n := range shape.FaceLocalV[k] { rst := []float64{0, 0, 0} for i := 0; i < shape.Gndim; i++ { rst[i] = shape.NatCoords[i][n] } shape.Func(shape.S, shape.dSdR, rst[0], rst[1], rst[2], false) io.Pforan("S = %v\n", shape.S) for m := range shape.FaceLocalV[k] { if n == m { errS += math.Abs(shape.S[m] - 1.0) } else { errS += math.Abs(shape.S[m]) } } } } io.Pforan("%g\n", errS) if errS > tol { tst.Errorf("%s failed with err = %g\n", name, errS) return } io.PfGreen("OK\n") } }
// 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) } } } } } }