// CheckDerivT checks derivatives w.r.t to t for fixed coordinates x func CheckDerivT(tst *testing.T, o Func, t0, tf float64, xcte []float64, np int, tskip []float64, sktol, dtol, dtol2 float64, ver bool) { t := utl.LinSpace(t0, tf, np) for i := 0; i < np; i++ { g := o.G(t[i], xcte) h := o.H(t[i], xcte) skip := false for _, val := range tskip { if math.Abs(val-t[i]) < sktol { skip = true break } } if skip { continue } dnum := num.DerivCen(func(t float64, args ...interface{}) (res float64) { return o.F(t, xcte) }, t[i]) chk.AnaNum(tst, io.Sf("G(%10f)", t[i]), dtol, g, dnum, ver) dnum2 := num.DerivCen(func(t float64, args ...interface{}) (res float64) { return o.G(t, xcte) }, t[i]) chk.AnaNum(tst, io.Sf("H(%10f)", t[i]), dtol2, h, dnum2, ver) } }
// CheckDerivs compares analytical with numerical derivatives func (o *Nurbs) CheckDerivs(tst *testing.T, nn int, tol float64, ver bool) { dana := make([]float64, 2) dnum := make([]float64, 2) for _, u := range utl.LinSpace(o.b[0].tmin, o.b[0].tmax, nn) { for _, v := range utl.LinSpace(o.b[1].tmin, o.b[1].tmax, nn) { uu := []float64{u, v} o.CalcBasisAndDerivs(uu) for i := 0; i < o.n[0]; i++ { for j := 0; j < o.n[1]; j++ { l := i + j*o.n[0] o.GetDerivL(dana, l) o.NumericalDeriv(dnum, uu, l) chk.AnaNum(tst, io.Sf("dR[%d][%d][0](%g,%g)", i, j, uu[0], uu[1]), tol, dana[0], dnum[0], ver) chk.AnaNum(tst, io.Sf("dR[%d][%d][1](%g,%g)", i, j, uu[0], uu[1]), tol, dana[1], dnum[1], ver) } } } } }
func Test_hyperelast02(tst *testing.T) { //verbose() chk.PrintTitle("hyperelast02 (linear)") E, ν := 1500.0, 0.25 K := Calc_K_from_Enu(E, ν) G := Calc_G_from_Enu(E, ν) io.Pforan("K = %v\n", K) io.Pforan("G = %v\n", G) var m HyperElast1 m.Init(2, false, []*fun.Prm{ &fun.Prm{N: "K0", V: K}, &fun.Prm{N: "G0", V: G}, &fun.Prm{N: "le", V: 1}, }) io.Pforan("m = %+v\n", m) ε := []float64{-0.001, -0.002, -0.003} σ := make([]float64, 3) m.L_update(σ, ε) io.Pfblue2("ε = %v\n", ε) io.Pfcyan("σ = %v\n", σ) D := la.MatAlloc(3, 3) m.L_CalcD(D, ε) la.PrintMat("D", D, "%14.6f", false) tol := 1e-11 verb := io.Verbose var tmp float64 for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum := num.DerivCen(func(x float64, args ...interface{}) (res float64) { tmp, ε[j] = ε[j], x m.L_update(σ, ε) res = σ[i] ε[j] = tmp return }, ε[j]) chk.AnaNum(tst, io.Sf("D%d%d", i, j), tol, D[i][j], dnum, verb) } } }
// CheckDerivX checks derivatives w.r.t to x for fixed t func CheckDerivX(tst *testing.T, o Func, tcte float64, xmin, xmax []float64, np int, xskip [][]float64, sktol, dtol float64, ver bool) { ndim := len(xmin) dx := make([]float64, ndim) for i := 0; i < ndim; i++ { dx[i] = (xmax[i] - xmin[i]) / float64(np-1) } x := make([]float64, ndim) g := make([]float64, ndim) nz := 1 if ndim == 3 { nz = np } xtmp := make([]float64, ndim) for k := 0; k < nz; k++ { if ndim == 3 { x[2] = xmin[2] + float64(k)*dx[2] } for j := 0; j < np; j++ { x[1] = xmin[1] + float64(j)*dx[1] for i := 0; i < np; i++ { x[0] = xmin[0] + float64(i)*dx[0] o.Grad(g, tcte, x) for l := 0; l < ndim; l++ { skip := false for _, val := range xskip { if math.Abs(val[l]-x[l]) < sktol { skip = true break } } if skip { continue } dnum := num.DerivCen(func(s float64, args ...interface{}) (res float64) { copy(xtmp, x) xtmp[l] = s return o.F(tcte, xtmp) }, x[l]) chk.AnaNum(tst, io.Sf("dFdX(t,%10v)[%d]", x, l), dtol, g[l], dnum, ver) } } } } }
func Test_hyperelast03(tst *testing.T) { //verbose() chk.PrintTitle("hyperelast03 (nonlinear)") var m HyperElast1 m.Init(2, false, []*fun.Prm{ &fun.Prm{N: "kap", V: 0.05}, &fun.Prm{N: "kapb", V: 20.0}, &fun.Prm{N: "G0", V: 1500}, &fun.Prm{N: "pr", V: 2.2}, &fun.Prm{N: "pt", V: 11.0}, }) io.Pforan("m = %+v\n", m) ε := []float64{-0.001, -0.002, -0.003} σ := make([]float64, 3) m.L_update(σ, ε) io.Pfblue2("ε = %v\n", ε) io.Pfcyan("σ = %v\n", σ) D := la.MatAlloc(3, 3) m.L_CalcD(D, ε) la.PrintMat("D", D, "%14.6f", false) tol := 1e-7 verb := io.Verbose var tmp float64 for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum := num.DerivCen(func(x float64, args ...interface{}) (res float64) { tmp, ε[j] = ε[j], x m.L_update(σ, ε) res = σ[i] ε[j] = tmp return }, ε[j]) chk.AnaNum(tst, io.Sf("D%d%d", i, j), tol, D[i][j], dnum, verb) } } }
// check performs the checking of Kb using numerical derivatives func (o *testKb) check(label string, d *Domain, e Elem, Imap, Jmap []int, Kana [][]float64, restore func()) { var imap, jmap []int if o.ni < 0 { imap = Imap } else { if o.ni <= len(Imap) { imap = Imap[:o.ni] } } if o.nj < 0 { jmap = Jmap } else { if o.nj <= len(Jmap) { jmap = Jmap[:o.nj] } } step := 1e-6 //derivfcn := num.DerivForward //derivfcn := num.DerivBackward derivfcn := num.DerivCentral var tmp float64 for i, I := range imap { for j, J := range jmap { dnum, _ := derivfcn(func(x float64, args ...interface{}) (res float64) { tmp, d.Sol.Y[J] = d.Sol.Y[J], x for k := 0; k < d.Ny; k++ { o.Fbtmp[k] = 0 d.Sol.ΔY[k] = d.Sol.Y[k] - o.Yold[k] } restore() e.Update(d.Sol) e.AddToRhs(o.Fbtmp, d.Sol) res = -o.Fbtmp[I] d.Sol.Y[J] = tmp return res }, d.Sol.Y[J], step) chk.AnaNum(o.tst, io.Sf(label+"%3d%3d", i, j), o.tol, Kana[i][j], dnum, o.verb) } } }
// 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) } } } } } } } }
func Test_spo751a(tst *testing.T) { /* de Souza Neto, Perić and Owen, ex 7.5.1 p244 * * 22 * . * 19 ,' `. * ,' '. * 17 ,' \ * .' \ * 14 ,' `. \ 21 * 12 ,' \ ' * 9 .' \ ' * 7 ,' `. \ 16 ' * 4 .' \ . ` * 2 ' `. \ 11 . | * `. \ 6 . | | * 1. . | | | * | | | | | * ----------------------------- * 0 3 5 8 10 13 15 18 20 */ //verbose() chk.PrintTitle("spo751a") // start simulation analysis := NewFEM("data/spo751.sim", "", true, false, false, false, chk.Verbose, 0) // set stage err := analysis.SetStage(0) if err != nil { tst.Errorf("SetStage failed:\n%v", err) return } // initialise solution vectros err = analysis.ZeroStage(0, true) if err != nil { tst.Errorf("ZeroStage failed:\n%v", err) return } // domain dom := analysis.Domains[0] // nodes and elements chk.IntAssert(len(dom.Nodes), 23) chk.IntAssert(len(dom.Elems), 4) // check dofs for _, nod := range dom.Nodes { chk.IntAssert(len(nod.Dofs), 2) } // check equations nids, eqs := get_nids_eqs(dom) chk.Ints(tst, "nids", nids, []int{0, 5, 7, 2, 3, 6, 4, 1, 10, 12, 8, 11, 9, 15, 17, 13, 16, 14, 20, 22, 18, 21, 19}) chk.Ints(tst, "eqs", eqs, utl.IntRange(23*2)) // check solution arrays ny := 23 * 2 nλ := 9 + 9 nyb := ny + nλ chk.IntAssert(len(dom.Sol.Y), ny) chk.IntAssert(len(dom.Sol.Dydt), 0) chk.IntAssert(len(dom.Sol.D2ydt2), 0) chk.IntAssert(len(dom.Sol.Psi), 0) chk.IntAssert(len(dom.Sol.Zet), 0) chk.IntAssert(len(dom.Sol.Chi), 0) chk.IntAssert(len(dom.Sol.L), nλ) chk.IntAssert(len(dom.Sol.ΔY), ny) // check linear solver arrays chk.IntAssert(len(dom.Fb), nyb) chk.IntAssert(len(dom.Wb), nyb) // check umap umaps := [][]int{ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {2, 3, 16, 17, 18, 19, 4, 5, 20, 21, 22, 23, 24, 25, 10, 11}, {16, 17, 26, 27, 28, 29, 18, 19, 30, 31, 32, 33, 34, 35, 22, 23}, {26, 27, 36, 37, 38, 39, 28, 29, 40, 41, 42, 43, 44, 45, 32, 33}, } for i, ele := range dom.Elems { e := ele.(*ElemU) io.Pforan("e%d.umap = %v\n", e.Id(), e.Umap) chk.Ints(tst, "umap", e.Umap, umaps[i]) } // constraints chk.IntAssert(len(dom.EssenBcs.Bcs), nλ) var ct_uy_eqs []int // constrained uy equations [sorted] var ct_incsup_xeqs []int var ct_incsup_yeqs []int αrad := 120.0 * math.Pi / 180.0 cα, sα := math.Cos(αrad), math.Sin(αrad) for _, c := range dom.EssenBcs.Bcs { chk.IntAssertLessThanOrEqualTo(1, len(c.Eqs)) // 1 ≤ neqs io.Pforan("c.Key=%s c.Eqs=%v\n", c.Key, c.Eqs) if len(c.Eqs) == 1 { if c.Key == "uy" { ct_uy_eqs = append(ct_uy_eqs, c.Eqs[0]) continue } } else { if c.Key == "incsup" { ct_incsup_xeqs = append(ct_incsup_xeqs, c.Eqs[0]) ct_incsup_yeqs = append(ct_incsup_yeqs, c.Eqs[1]) chk.AnaNum(tst, "cos(α)", 1e-15, c.ValsA[0], cα, false) chk.AnaNum(tst, "sin(α)", 1e-15, c.ValsA[1], sα, false) continue } } tst.Errorf("key %s is incorrect", c.Key) } sort.Ints(ct_uy_eqs) sort.Ints(ct_incsup_xeqs) sort.Ints(ct_incsup_yeqs) chk.Ints(tst, "constrained uy equations", ct_uy_eqs, []int{1, 3, 9, 17, 21, 27, 31, 37, 41}) chk.Ints(tst, "incsup x equations", ct_incsup_xeqs, []int{4, 6, 12, 18, 24, 28, 34, 38, 44}) chk.Ints(tst, "incsup y equations", ct_incsup_yeqs, []int{5, 7, 13, 19, 25, 29, 35, 39, 45}) }
func Test_ops03(tst *testing.T) { //verbose() chk.PrintTitle("ops03") nonsymTol := 1e-15 dtol := 1e-9 dver := chk.Verbose nd := test_nd for idxA := 0; idxA < len(test_nd)-3; idxA++ { //for idxA := 0; idxA < 1; idxA++ { // tensor and eigenvalues A := test_AA[idxA] a := M_Alloc2(nd[idxA]) Ten2Man(a, A) io.PfYel("\n\ntst # %d ###################################################################################\n", idxA) io.Pfblue2("a = %v\n", a) // inverse Ai := Alloc2() ai := M_Alloc2(nd[idxA]) detA, err := Inv(Ai, A) if err != nil { chk.Panic("%v", err) } deta_ := M_Det(a) deta, err := M_Inv(ai, a, MINDET) if err != nil { chk.Panic("%v", err) } Ai_ := Alloc2() Man2Ten(Ai_, ai) aia := M_Alloc2(nd[idxA]) err = M_Dot(aia, ai, a, nonsymTol) if err != nil { chk.Panic("%v", err) } chk.Scalar(tst, "detA", 1e-14, detA, deta) chk.Scalar(tst, "deta", 1e-14, deta, deta_) chk.Matrix(tst, "Ai", 1e-14, Ai, Ai_) chk.Vector(tst, "ai*a", 1e-15, aia, Im[:2*nd[idxA]]) io.Pforan("ai*a = %v\n", aia) // derivative of inverse dtol_tmp := dtol if idxA == 5 { dtol = 1e-8 } var tmp float64 ai_tmp := M_Alloc2(nd[idxA]) daida := M_Alloc4(nd[idxA]) M_InvDeriv(daida, ai) io.Pforan("ai = %v\n", ai) for i := 0; i < len(a); i++ { for j := 0; j < len(a); j++ { //dnum, _ := num.DerivForward(func(x float64, args ...interface{}) (res float64) { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x _, err := M_Inv(ai_tmp, a, MINDET) a[j] = tmp if err != nil { chk.Panic("daida failed:\n%v", err) } return ai_tmp[i] }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("dai/da[%d][%d]", i, j), dtol, daida[i][j], dnum, dver) } } dtol = dtol_tmp } }
func Test_ops01(tst *testing.T) { //verbose() chk.PrintTitle("ops01") // basic derivatives dver := chk.Verbose dtol := 1e-5 // invariants derivatives dveri := false dtoli1 := []float64{1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6} dtoli2 := []float64{1e-6, 1e-5, 1e-6, 1e-4, 1e-5, 1e-6, 1e-6, 1e-6, 1e-6, 1e-6} dtoli3 := []float64{1e-6, 1e-3, 1e-6, 1e-3, 1e-3, 1e-6, 1e-6, 1e-6, 1e-5, 1e-6} // lode derivatives dverw := chk.Verbose dtolw := 1e-8 nd := test_nd for m := 0; m < len(test_nd)-3; m++ { //for m := 0; m < 3; m++ { A := test_AA[m] a := M_Alloc2(nd[m]) Ten2Man(a, A) trA := Tr(A) tra := M_Tr(a) detA := Det(A) deta := M_Det(a) devA := Dev(A) deva := M_Dev(a) devA_ := Alloc2() a2 := M_Alloc2(nd[m]) A2 := Alloc2() A2_ := Alloc2() trDevA := Tr(devA) deva__ := M_Alloc2(nd[m]) devA__ := Alloc2() s2 := M_Alloc2(nd[m]) M_Sq(a2, a) M_Sq(s2, deva) Man2Ten(A2, a2) Man2Ten(devA_, deva) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { for k := 0; k < 3; k++ { A2_[i][j] += A[i][k] * A[k][j] } } } for i := 0; i < len(a); i++ { for j := 0; j < len(a); j++ { deva__[i] += Psd[i][j] * a[j] } } for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { for k := 0; k < 3; k++ { for l := 0; l < 3; l++ { devA__[i][j] += M2TT(Psd, i, j, k, l) * A[k][l] } } } } // check basic if math.Abs(trA-tra) > 1e-17 { chk.Panic("tra failed. diff = %g", trA-tra) } if math.Abs(detA-deta) > 1e-14 { chk.Panic("detA failed. diff = %g", detA-deta) } if math.Abs(trDevA) > 1e-13 { chk.Panic("trDevA failed. error = %g", trDevA) } chk.Matrix(tst, "devA", 1e-13, devA, devA_) chk.Matrix(tst, "devA", 1e-13, devA, devA__) chk.Vector(tst, "devA", 1e-13, deva, deva__) chk.Matrix(tst, "A²", 1e-11, A2, A2_) // check tr(s2) io.Pfblue2("tr(s²) = %v\n", M_Tr(s2)) if M_Tr(s2) < 1 { chk.Panic("Tr(s2) failed") } // check derivatives da2da := M_Alloc4(nd[m]) a2tmp := M_Alloc2(nd[m]) // a2tmp == a² M_SqDeriv(da2da, a) var tmp float64 for i := 0; i < len(a); i++ { for j := 0; j < len(a); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x M_Sq(a2tmp, a) a[j] = tmp return a2tmp[i] }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("da²/da[%d][%d]", i, j), dtol, da2da[i][j], dnum, dver) } } // characteristic invariants I1, I2, I3 := M_CharInvs(a) I2a := 0.5 * (tra*tra - M_Tr(a2)) I1_, I2_, I3_, dI1da, dI2da, dI3da := M_CharInvsAndDerivs(a) if math.Abs(I1-tra) > 1e-17 { chk.Panic("I1 failed (a). error = %v", I1-tra) } if math.Abs(I2-I2a) > 1e-12 { chk.Panic("I2 failed (a). error = %v (I2=%v, I2_=%v)", I2-I2a, I2, I2a) } if math.Abs(I3-deta) > 1e-17 { chk.Panic("I3 failed (a). error = %v", I3-deta) } if math.Abs(I1-I1_) > 1e-17 { chk.Panic("I1 failed (b). error = %v", I1-I1_) } if math.Abs(I2-I2_) > 1e-17 { chk.Panic("I2 failed (b). error = %v", I2-I2_) } if math.Abs(I3-I3_) > 1e-17 { chk.Panic("I3 failed (b). error = %v", I3-I3_) } // dI1da for j := 0; j < len(a); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x i1, _, _ := M_CharInvs(a) a[j] = tmp return i1 }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("dI1/da[%d]", j), dtoli1[m], dI1da[j], dnum, dveri) } // dI2da for j := 0; j < len(a); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x _, i2, _ := M_CharInvs(a) a[j] = tmp return i2 }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("dI2/da[%d]", j), dtoli2[m], dI2da[j], dnum, dveri) } // dI3da for j := 0; j < len(a); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x _, _, i3 := M_CharInvs(a) a[j] = tmp return i3 }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("dI3/da[%d]", j), dtoli3[m], dI3da[j], dnum, dveri) } // dDet(a)/da DdetaDa := make([]float64, len(a)) M_DetDeriv(DdetaDa, a) for j := 0; j < len(a); j++ { chk.AnaNum(tst, io.Sf("dDet(a)/da[%d]", j), dtoli3[m], dI3da[j], DdetaDa[j], dveri) } // lode angle if true { s := M_Alloc2(nd[m]) dwda := M_Alloc2(nd[m]) dwda_ := M_Alloc2(nd[m]) d2wdada := M_Alloc4(nd[m]) p, q, w := M_pqws(s, a) M_LodeDeriv1(dwda, a, s, p, q, w) M_LodeDeriv2(d2wdada, dwda_, a, s, p, q, w) chk.Vector(tst, "s", 1e-13, deva, s) chk.Vector(tst, "dwda", 1e-13, dwda, dwda_) // dwda for j := 0; j < len(a); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x res = M_w(a) a[j] = tmp return res }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("dw/da[%d]", j), dtolw, dwda[j], dnum, dverw) } // d2wdada s_tmp := M_Alloc2(nd[m]) dwda_tmp := M_Alloc2(nd[m]) for i := 0; i < len(a); i++ { for j := 0; j < len(a); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x p_tmp, q_tmp, w_tmp := M_pqws(s_tmp, a) M_LodeDeriv1(dwda_tmp, a, s_tmp, p_tmp, q_tmp, w_tmp) a[j] = tmp return dwda_tmp[i] }, a[j], 1e-6) chk.AnaNum(tst, io.Sf("d2w/dada[%d][%d]", i, j), dtolw, d2wdada[i][j], dnum, dverw) } } } } }
func Test_up01a(tst *testing.T) { /* this tests simulates seepage flow along a column * by reducing the initial hydrostatic pressure at * at the bottom of the column * * using mesh from col104elay.msh * * Nodes / Tags Equations * ux uy pl ux uy pl * 8 o----o----o 9 (-5) 53 54 55 o----o----o 50 51 52 * | 14 | . . . | 58 59 | . . . * | (-1) | . . . | | . . . * 21 o o o 22 (-6) 60 61 . o o o 56 57 . * | 26 | . . . | 62 63 | . . . * | | . . . | | . . . * 6 o----o----o 7 (-4) 39 40 41 o----o----o 36 37 38 * | 13 | . . . | 44 45 | . . . * | (-1) | . . . | | . . . * 19 | o o 20 (-6) 46 47 . | o o 42 43 . * | 25 | . . . | 48 49 | . . . * | | . . . | | . . . * 4 o----o----o 5 (-3) 25 26 27 o----o----o 22 23 24 * | 12 | . . . | 30 31 | . . . * | (-2) | . . . | | . . . * 17 o o o 18 (-6) 32 33 . o o o 28 29 . * | 24 | . . . | 34 35 | . . . * | | . . . | | . . . * 2 o----o----o 3 (-2) 9 10 11 o----o----o 6 7 8 * | 11 | . . . | 16 17 | . . . * | (-2) | . . . | | . . . * 15 o o o 16 (-6) 18 19 o o o 14 15 * | 23 | . . . | 20 21 | . . . * | | . . . | | . . . * 0 o----o----o 1 (-1) 0 1 2 o----o----o 3 4 5 * 10 12 13 */ // capture errors and flush log defer End() //verbose() chk.PrintTitle("up01a") // start simulation if !Start("data/up01.sim", true, chk.Verbose) { chk.Panic("cannot start simulation") } // domain distr := false dom := NewDomain(Global.Sim.Regions[0], distr) if dom == nil { chk.Panic("cannot allocate new domain") } // set stage if !dom.SetStage(0, Global.Sim.Stages[0], distr) { chk.Panic("cannot set stage") } // nodes and elements chk.IntAssert(len(dom.Nodes), 27) chk.IntAssert(len(dom.Elems), 4) if true { // nodes with pl nods_with_pl := map[int]bool{0: true, 2: true, 4: true, 6: true, 8: true, 1: true, 3: true, 5: true, 7: true, 9: true} // check dofs for _, nod := range dom.Nodes { if nods_with_pl[nod.Vert.Id] { chk.IntAssert(len(nod.Dofs), 3) chk.StrAssert(nod.Dofs[0].Key, "ux") chk.StrAssert(nod.Dofs[1].Key, "uy") chk.StrAssert(nod.Dofs[2].Key, "pl") } else { chk.IntAssert(len(nod.Dofs), 2) chk.StrAssert(nod.Dofs[0].Key, "ux") chk.StrAssert(nod.Dofs[1].Key, "uy") } } // check equations nids, eqs := get_nids_eqs(dom) chk.Ints(tst, "eqs", eqs, utl.IntRange(10*3+17*2)) chk.Ints(tst, "nids", nids, []int{ 0, 1, 3, 2, 10, 16, 11, 15, 23, 5, 4, 18, 12, 17, 24, 7, 6, 20, 13, 19, 25, 9, 8, 22, 14, 21, 26, }) // check pmap Pmaps := [][]int{ {2, 5, 8, 11}, {11, 8, 24, 27}, {27, 24, 38, 41}, {41, 38, 52, 55}, } Umaps := [][]int{ {0, 1, 3, 4, 6, 7, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21}, {9, 10, 6, 7, 22, 23, 25, 26, 16, 17, 28, 29, 30, 31, 32, 33, 34, 35}, {25, 26, 22, 23, 36, 37, 39, 40, 30, 31, 42, 43, 44, 45, 46, 47, 48, 49}, {39, 40, 36, 37, 50, 51, 53, 54, 44, 45, 56, 57, 58, 59, 60, 61, 62, 63}, } for i, ele := range dom.Elems { e := ele.(*ElemUP) io.Pfpink("%2d : Pmap = %v\n", e.Id(), e.P.Pmap) io.Pfpink("%2d : Umap = %v\n", e.Id(), e.U.Umap) chk.Ints(tst, "Pmap", e.P.Pmap, Pmaps[i]) chk.Ints(tst, "Umap", e.U.Umap, Umaps[i]) } // constraints chk.IntAssert(len(dom.EssenBcs.Bcs), 9*2+2+3) var ct_ux_eqs []int // equations with ux prescribed [sorted] var ct_uy_eqs []int // equations with uy prescribed [sorted] var ct_pl_eqs []int // equations with pl prescribed [sorted] for _, c := range dom.EssenBcs.Bcs { chk.IntAssert(len(c.Eqs), 1) eq := c.Eqs[0] io.Pfgrey("key=%v eq=%v\n", c.Key, eq) switch c.Key { case "ux": ct_ux_eqs = append(ct_ux_eqs, eq) case "uy": ct_uy_eqs = append(ct_uy_eqs, eq) case "pl": ct_pl_eqs = append(ct_pl_eqs, eq) default: tst.Errorf("key %s is incorrect", c.Key) } } sort.Ints(ct_ux_eqs) sort.Ints(ct_uy_eqs) sort.Ints(ct_pl_eqs) chk.Ints(tst, "equations with ux prescribed", ct_ux_eqs, []int{0, 3, 6, 9, 14, 18, 22, 25, 28, 32, 36, 39, 42, 46, 50, 53, 56, 60}) chk.Ints(tst, "equations with uy prescribed", ct_uy_eqs, []int{1, 4, 13}) chk.Ints(tst, "equations with pl prescribed", ct_pl_eqs, []int{2, 5}) } // initial values @ nodes io.Pforan("initial values @ nodes\n") for _, nod := range dom.Nodes { z := nod.Vert.C[1] for _, dof := range nod.Dofs { u := dom.Sol.Y[dof.Eq] switch dof.Key { case "ux": chk.Scalar(tst, io.Sf("nod %3d : ux(@ %4g)= %6g", nod.Vert.Id, z, u), 1e-17, u, 0) case "uy": chk.Scalar(tst, io.Sf("nod %3d : uy(@ %4g)= %6g", nod.Vert.Id, z, u), 1e-17, u, 0) case "pl": plC, _, _ := Global.HydroSt.Calc(z) chk.Scalar(tst, io.Sf("nod %3d : pl(@ %4g)= %6g", nod.Vert.Id, z, u), 1e-13, u, plC) } } } // intial values @ integration points io.Pforan("initial values @ integration points\n") for _, ele := range dom.Elems { e := ele.(*ElemUP) for idx, ip := range e.P.IpsElem { s := e.P.States[idx] z := e.P.Shp.IpRealCoords(e.P.X, ip)[1] chk.AnaNum(tst, io.Sf("sl(z=%11.8f)", z), 1e-17, s.A_sl, 1, chk.Verbose) } } // parameters ν := 0.2 // Poisson's coefficient K0 := ν / (1.0 - ν) // earth pressure at rest nf := 0.3 // porosity sl := 1.0 // saturation ρL := 1.0 // intrinsic (real) density of liquid ρS_top := 2.0 // intrinsic (real) density of solids in top layer ρS_bot := 3.0 // intrinsic (real) density of solids in bottom layer h := 5.0 // height of each layer g := 10.0 // gravity // densities nl := nf * sl // volume fraction of luqid ns := 1.0 - nf // volume fraction of solid ρl := nl * ρL // partial density of liquid ρs_top := ns * ρS_top // partial density of solids in top layer ρs_bot := ns * ρS_bot // partial density of solids in bottom layer ρ_top := ρl + ρs_top // density of mixture in top layer ρ_bot := ρl + ρs_bot // density of mixture in bottom layer // absolute values of stresses σV_z5 := ρ_top * g * h // total vertical stress @ elevation z = 5 m (absolute value) σV_z0 := σV_z5 + ρ_bot*g*h // total vertical stress @ elevation z = 0 m (absolute value) io.Pfyel("ρ_top = %g\n", ρ_top) io.Pfyel("ρ_bot = %g\n", ρ_bot) io.Pfyel("|ΔσV_top| = %g\n", ρ_top*g*h) io.Pfyel("|ΔσV_bot| = %g\n", ρ_bot*g*h) io.PfYel("|σV|(@ z=0) = %g\n", σV_z0) io.PfYel("|σV|(@ z=5) = %g\n", σV_z5) // stress functions var sig fun.Pts var pres fun.Pts sig.Init(fun.Prms{ &fun.Prm{N: "t0", V: 0.00}, {N: "y0", V: -σV_z0}, &fun.Prm{N: "t1", V: 5.00}, {N: "y1", V: -σV_z5}, &fun.Prm{N: "t2", V: 10.00}, {N: "y2", V: 0.0}, }) pres.Init(fun.Prms{ &fun.Prm{N: "t0", V: 0.00}, {N: "y0", V: 100}, &fun.Prm{N: "t1", V: 10.00}, {N: "y1", V: 0}, }) // check stresses io.Pforan("initial stresses @ integration points\n") for _, ele := range dom.Elems { e := ele.(*ElemUP) for idx, ip := range e.U.IpsElem { z := e.U.Shp.IpRealCoords(e.U.X, ip)[1] σe := e.U.States[idx].Sig sv := sig.F(z, nil) sve := sv + pres.F(z, nil) she := sve * K0 if math.Abs(σe[2]-σe[0]) > 1e-17 { tst.Errorf("[1;31mσx is not equal to σz: %g != %g[0m\n", σe[2], σe[0]) return } if math.Abs(σe[3]) > 1e-17 { tst.Errorf("[1;31mσxy is not equal to zero: %g != 0[0m\n", σe[3]) return } chk.AnaNum(tst, io.Sf("sx(z=%11.8f)", z), 0.0003792, σe[0], she, chk.Verbose) chk.AnaNum(tst, io.Sf("sy(z=%11.8f)", z), 0.001517, σe[1], sve, chk.Verbose) } } return }
func Test_geninvs01(tst *testing.T) { //verbose() chk.PrintTitle("geninvs01") // coefficients for smp invariants smp_a := -1.0 smp_b := 0.5 smp_β := 1e-1 // derivative values become too high with smp_ϵ := 1e-1 // small β and ϵ @ zero // constants for checking derivatives dver := chk.Verbose dtol := 1e-6 dtol2 := 1e-6 // run tests nd := test_nd for idxA := 0; idxA < len(test_nd); idxA++ { //for idxA := 10; idxA < 11; idxA++ { // tensor and eigenvalues A := test_AA[idxA] a := M_Alloc2(nd[idxA]) Ten2Man(a, A) L := make([]float64, 3) M_EigenValsNum(L, a) // SMP derivs and SMP director dndL := la.MatAlloc(3, 3) dNdL := make([]float64, 3) d2ndLdL := utl.Deep3alloc(3, 3, 3) N := make([]float64, 3) F := make([]float64, 3) G := make([]float64, 3) m := SmpDerivs1(dndL, dNdL, N, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpDerivs2(d2ndLdL, L, smp_a, smp_b, smp_β, smp_ϵ, m, N, F, G, dNdL, dndL) n := make([]float64, 3) SmpUnitDirector(n, m, N) // SMP invariants p, q, err := GenInvs(L, n, smp_a) if err != nil { chk.Panic("SmpInvs failed:\n%v", err) } // output io.PfYel("\n\ntst # %d ###################################################################################\n", idxA) io.Pfblue2("L = %v\n", L) io.Pforan("n = %v\n", n) io.Pforan("p = %v\n", p) io.Pforan("q = %v\n", q) // check invariants tvec := make([]float64, 3) GenTvec(tvec, L, n) proj := make([]float64, 3) // projection of tvec along n tdn := la.VecDot(tvec, n) // tvec dot n for i := 0; i < 3; i++ { proj[i] = tdn * n[i] } norm_proj := la.VecNorm(proj) norm_tvec := la.VecNorm(tvec) q_ := GENINVSQEPS + math.Sqrt(norm_tvec*norm_tvec-norm_proj*norm_proj) io.Pforan("proj = %v\n", proj) io.Pforan("norm(proj) = %v == p\n", norm_proj) chk.Scalar(tst, "p", 1e-14, math.Abs(p), norm_proj) chk.Scalar(tst, "q", 1e-13, q, q_) // dt/dL var tmp float64 N_tmp := make([]float64, 3) n_tmp := make([]float64, 3) tvec_tmp := make([]float64, 3) dtdL := la.MatAlloc(3, 3) GenTvecDeriv1(dtdL, L, n, dndL) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenTvec(tvec_tmp, L, n_tmp) L[j] = tmp return tvec_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dt/dL[%d][%d]", i, j), dtol, dtdL[i][j], dnum, dver) } } // d²t/dLdL io.Pfpink("\nd²t/dLdL\n") dNdL_tmp := make([]float64, 3) dndL_tmp := la.MatAlloc(3, 3) dtdL_tmp := la.MatAlloc(3, 3) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { for k := 0; k < 3; k++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[k] = L[k], x m_tmp := SmpDerivs1(dndL_tmp, dNdL_tmp, N_tmp, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenTvecDeriv1(dtdL_tmp, L, n_tmp, dndL_tmp) L[k] = tmp return dtdL_tmp[i][j] }, L[k], 1e-6) dana := GenTvecDeriv2(i, j, k, L, dndL, d2ndLdL[i][j][k]) chk.AnaNum(tst, io.Sf("d²t[%d]/dL[%d]dL[%d]", i, j, k), dtol2, dana, dnum, dver) } } } // change tolerance dtol_tmp := dtol switch idxA { case 5, 11: dtol = 1e-5 case 12: dtol = 0.0013 } // first order derivatives dpdL := make([]float64, 3) dqdL := make([]float64, 3) p_, q_, err := GenInvsDeriv1(dpdL, dqdL, L, n, dndL, smp_a) if err != nil { chk.Panic("%v", err) } chk.Scalar(tst, "p", 1e-17, p, p_) chk.Scalar(tst, "q", 1e-17, q, q_) var ptmp, qtmp float64 io.Pfpink("\ndp/dL\n") for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) ptmp, _, err = GenInvs(L, n_tmp, smp_a) if err != nil { chk.Panic("DerivCentral: SmpInvs failed:\n%v", err) } L[j] = tmp return ptmp }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dp/dL[%d]", j), dtol, dpdL[j], dnum, dver) } io.Pfpink("\ndq/dL\n") for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) _, qtmp, err = GenInvs(L, n_tmp, smp_a) if err != nil { chk.Panic("DerivCentral: SmpInvs failed:\n%v", err) } L[j] = tmp return qtmp }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dq/dL[%d]", j), dtol, dqdL[j], dnum, dver) } // recover tolerance dtol = dtol_tmp // change tolerance io.Pforan("dtol2 = %v\n", dtol2) dtol2_tmp := dtol2 switch idxA { case 5: dtol2 = 1e-5 case 10: dtol2 = 0.72 case 11: dtol2 = 1e-5 case 12: dtol2 = 544 } // second order derivatives dpdL_tmp := make([]float64, 3) dqdL_tmp := make([]float64, 3) d2pdLdL := la.MatAlloc(3, 3) d2qdLdL := la.MatAlloc(3, 3) GenInvsDeriv2(d2pdLdL, d2qdLdL, L, n, dpdL, dqdL, p, q, dndL, d2ndLdL, smp_a) io.Pfpink("\nd²p/dLdL\n") for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDerivs1(dndL_tmp, dNdL_tmp, N_tmp, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenInvsDeriv1(dpdL_tmp, dqdL_tmp, L, n_tmp, dndL_tmp, smp_a) L[j] = tmp return dpdL_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("d²p/dL[%d][%d]", i, j), dtol2, d2pdLdL[i][j], dnum, dver) } } io.Pfpink("\nd²q/dLdL\n") for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDerivs1(dndL_tmp, dNdL_tmp, N_tmp, F, G, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) GenInvsDeriv1(dpdL_tmp, dqdL_tmp, L, n_tmp, dndL_tmp, smp_a) L[j] = tmp return dqdL_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("d²q/dL[%d][%d]", i, j), dtol2, d2qdLdL[i][j], dnum, dver) } } // recover tolerance dtol2 = dtol2_tmp } }
func Test_noncteM01(tst *testing.T) { //verbose() chk.PrintTitle("noncteM01") prms := []string{"φ", "Mfix"} vals := []float64{32, 0} var o NcteM o.Init(prms, vals) // check if math.Abs(o.M(1)-o.Mcs) > 1e-17 { chk.Panic("M(+1) failed. err = %v", o.M(1)-o.Mcs) } if o.Mfix { if math.Abs(o.M(-1)-o.Mcs) > 1e-17 { chk.Panic("M(-1) failed. err = %v", o.M(-1)-o.Mcs) } } else { Mext := 6.0 * math.Sin(32*math.Pi/180) / (3 + math.Sin(32*math.Pi/180)) if math.Abs(o.M(-1)-Mext) > 1e-15 { chk.Panic("M(-1) failed. err = %v", o.M(-1)-Mext) } } ver, tol := chk.Verbose, 1e-9 var tmp float64 for _, w := range utl.LinSpace(-1, 1, 11) { dMdw := o.DMdw(w) d2Mdw2 := o.D2Mdw2(w) dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, w = w, x res, w = o.M(w), tmp return }, w, 1e-6) chk.AnaNum(tst, "dM/dw ", tol, dMdw, dnum, ver) dnum, _ = num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, w = w, x res, w = o.DMdw(w), tmp return }, w, 1e-6) chk.AnaNum(tst, "d²M/dw²", tol, d2Mdw2, dnum, ver) } ver, tol = chk.Verbose, 1e-9 nd := test_nd for m := 0; m < len(test_nd)-3; m++ { //for m := 0; m < 3; m++ { A := test_AA[m] σ := M_Alloc2(nd[m]) Ten2Man(σ, A) s := M_Alloc2(nd[m]) dMdσ := M_Alloc2(nd[m]) d2Mdσdσ := M_Alloc4(nd[m]) p, q, w := M_pqws(s, σ) o.Deriv2(d2Mdσdσ, dMdσ, σ, s, p, q, w) io.Pforan("σ = %v\n", σ) io.Pforan("tr(dMdσ) = %v\n", M_Tr(dMdσ)) if math.Abs(M_Tr(dMdσ)) > 1e-16 { chk.Panic("tr(dMdσ)=%v failed", M_Tr(dMdσ)) } I_dc_d2Mdσdσ := M_Alloc2(nd[m]) // I:d²M/dσdσ for j := 0; j < len(σ); j++ { for k := 0; k < len(σ); k++ { I_dc_d2Mdσdσ[j] += Im[k] * d2Mdσdσ[k][j] } } //io.Pfblue2("I_dc_d2Mdσdσ = %v\n", I_dc_d2Mdσdσ) chk.Vector(tst, "I_dc_d2Mdσdσ", 1e-15, I_dc_d2Mdσdσ, nil) // dMdσ for j := 0; j < len(σ); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, σ[j] = σ[j], x w := M_w(σ) σ[j] = tmp return o.M(w) }, σ[j], 1e-6) chk.AnaNum(tst, io.Sf("dM/dσ[%d]", j), tol, dMdσ[j], dnum, ver) } // d²Mdσdσ s_tmp := M_Alloc2(nd[m]) dMdσ_tmp := M_Alloc2(nd[m]) for i := 0; i < len(σ); i++ { for j := 0; j < len(σ); j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, σ[j] = σ[j], x p_tmp, q_tmp, w_tmp := M_pqws(s_tmp, σ) o.Deriv1(dMdσ_tmp, σ, s_tmp, p_tmp, q_tmp, w_tmp) σ[j] = tmp return dMdσ_tmp[i] }, σ[j], 1e-6) chk.AnaNum(tst, io.Sf("d²M/dσdσ[%d][%d]", i, j), tol, d2Mdσdσ[i][j], dnum, ver) } } } }
// Check checks derivatives func Check(tst *testing.T, mdl Model, pc0, sl0, pcf float64, npts int, tolCc, tolD1a, tolD1b, tolD2a, tolD2b float64, verbose bool, pcSkip []float64, tolSkip float64, doplot bool) { // nonrate model nr_mdl, is_nonrate := mdl.(Nonrate) io.Pforan("is_nonrate = %v\n", is_nonrate) // for all pc stations Pc := utl.LinSpace(pc0, pcf, npts) Sl := make([]float64, npts) Sl[0] = sl0 var err error for i := 1; i < npts; i++ { // update and plot Sl[i], err = Update(mdl, Pc[i-1], Sl[i-1], Pc[i]-Pc[i-1]) if err != nil { tst.Errorf("Update failed: %v\n", err) return } if doplot { plt.PlotOne(Pc[i], Sl[i], "'ko', clip_on=0") } // skip point on checking of derivatives if doskip(Pc[i], pcSkip, tolSkip) { continue } // wetting flag wet := Pc[i]-Pc[i-1] < 0 // check Cc = dsl/dpc io.Pforan("\npc=%g, sl=%g, wetting=%v\n", Pc[i], Sl[i], wet) if is_nonrate { // analytical Cc Cc_ana, err := mdl.Cc(Pc[i], Sl[i], wet) if err != nil { tst.Errorf("Cc failed: %v\n", err) return } // numerical Cc Cc_num, _ := num.DerivCentral(func(x float64, args ...interface{}) float64 { return nr_mdl.Sl(x) }, Pc[i], 1e-3) chk.AnaNum(tst, "Cc = ∂sl/∂pc ", tolCc, Cc_ana, Cc_num, verbose) } // compute all derivatives L, Lx, J, Jx, Jy, err := mdl.Derivs(Pc[i], Sl[i], wet) if err != nil { tst.Errorf("Derivs failed: %v\n", err) return } L_ana_A := L L_ana_B, err := mdl.L(Pc[i], Sl[i], wet) if err != nil { tst.Errorf("L failed: %v\n", err) return } Lx_ana := Lx Jx_ana := Jx Jy_ana := Jy J_ana_A := J J_ana_B, err := mdl.J(Pc[i], Sl[i], wet) if err != nil { tst.Errorf("J failed: %v\n", err) return } // numerical L = ∂Cc/∂pc L_num, _ := num.DerivCentral(func(x float64, args ...interface{}) float64 { Cctmp, _ := mdl.Cc(x, Sl[i], wet) return Cctmp }, Pc[i], 1e-3) chk.AnaNum(tst, "L = ∂Cc/∂pc ", tolD1a, L_ana_A, L_num, verbose) // numerical Lx := ∂²Cc/∂pc² Lx_num, _ := num.DerivCentral(func(x float64, args ...interface{}) float64 { Ltmp, _, _, _, _, _ := mdl.Derivs(x, Sl[i], wet) return Ltmp }, Pc[i], 1e-3) chk.AnaNum(tst, "Lx = ∂²Cc/∂pc² ", tolD2a, Lx_ana, Lx_num, verbose) // numerical J := ∂Cc/∂sl (version A) J_num, _ := num.DerivCentral(func(x float64, args ...interface{}) float64 { Ccval, _ := mdl.Cc(Pc[i], x, wet) return Ccval }, Sl[i], 1e-3) chk.AnaNum(tst, "J = ∂Cc/∂sl ", tolD1b, J_ana_A, J_num, verbose) // numerical Jx := ∂²Cc/(∂pc ∂sl) Jx_num, _ := num.DerivCentral(func(x float64, args ...interface{}) float64 { Ltmp, _, _, _, _, _ := mdl.Derivs(Pc[i], x, wet) return Ltmp }, Sl[i], 1e-3) chk.AnaNum(tst, "Jx = ∂²Cc/∂pc∂sl", tolD2b, Jx_ana, Jx_num, verbose) // numerical Jy := ∂²Cc/∂sl² Jy_num, _ := num.DerivCentral(func(x float64, args ...interface{}) float64 { Jtmp, _ := mdl.J(Pc[i], x, wet) return Jtmp }, Sl[i], 1e-3) chk.AnaNum(tst, "Jy = ∂²Cc/∂sl² ", tolD2b, Jy_ana, Jy_num, verbose) // check A and B derivatives chk.Scalar(tst, "L_A == L_B", 1e-17, L_ana_A, L_ana_B) chk.Scalar(tst, "J_A == J_B", 1e-17, J_ana_A, J_ana_B) } }
func Test_smpinvs02(tst *testing.T) { //verbose() chk.PrintTitle("smpinvs02") // coefficients for smp invariants smp_a := -1.0 smp_b := 0.5 smp_β := 1e-1 // derivative values become too high with smp_ϵ := 1e-1 // small β and ϵ @ zero // constants for checking derivatives dver := chk.Verbose dtol := 1e-9 dtol2 := 1e-8 // run tests nd := test_nd for idxA := 0; idxA < len(test_nd); idxA++ { //for idxA := 0; idxA < 1; idxA++ { //for idxA := 10; idxA < 11; idxA++ { // tensor and eigenvalues A := test_AA[idxA] a := M_Alloc2(nd[idxA]) Ten2Man(a, A) L := make([]float64, 3) M_EigenValsNum(L, a) // SMP director N := make([]float64, 3) n := make([]float64, 3) m := SmpDirector(N, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n, m, N) // output io.PfYel("\n\ntst # %d ###################################################################################\n", idxA) io.Pforan("L = %v\n", L) io.Pforan("N = %v\n", N) io.Pforan("m = %v\n", m) io.Pfpink("n = %v\n", n) chk.Vector(tst, "L", 1e-12, L, test_λ[idxA]) chk.Scalar(tst, "norm(n)==1", 1e-15, la.VecNorm(n), 1) chk.Scalar(tst, "m=norm(N)", 1e-14, m, la.VecNorm(N)) // dN/dL var tmp float64 N_tmp := make([]float64, 3) dNdL := make([]float64, 3) SmpDirectorDeriv1(dNdL, L, smp_a, smp_b, smp_β, smp_ϵ) io.Pfpink("\ndNdL = %v\n", dNdL) for i := 0; i < 3; i++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[i] = L[i], x SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) L[i] = tmp return N_tmp[i] }, L[i], 1e-6) chk.AnaNum(tst, io.Sf("dN/dL[%d][%d]", i, i), dtol, dNdL[i], dnum, dver) } // dm/dL n_tmp := make([]float64, 3) dmdL := make([]float64, 3) SmpNormDirectorDeriv1(dmdL, m, N, dNdL) io.Pfpink("\ndmdL = %v\n", dmdL) for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) L[j] = tmp return m_tmp }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dm/dL[%d]", j), dtol, dmdL[j], dnum, dver) } // dn/dL dndL := la.MatAlloc(3, 3) SmpUnitDirectorDeriv1(dndL, m, N, dNdL, dmdL) io.Pfpink("\ndndL = %v\n", dndL) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpUnitDirector(n_tmp, m_tmp, N_tmp) L[j] = tmp return n_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("dn/dL[%d][%d]", i, j), dtol, dndL[i][j], dnum, dver) } } // change tolerance dtol2_tmp := dtol2 if idxA == 10 || idxA == 11 { dtol2 = 1e-6 } // d²m/dLdL dNdL_tmp := make([]float64, 3) dmdL_tmp := make([]float64, 3) d2NdL2 := make([]float64, 3) d2mdLdL := la.MatAlloc(3, 3) SmpDirectorDeriv2(d2NdL2, L, smp_a, smp_b, smp_β, smp_ϵ) SmpNormDirectorDeriv2(d2mdLdL, L, smp_a, smp_b, smp_β, smp_ϵ, m, N, dNdL, d2NdL2, dmdL) io.Pfpink("\nd2mdLdL = %v\n", d2mdLdL) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[j] = L[j], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpDirectorDeriv1(dNdL_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpNormDirectorDeriv1(dmdL_tmp, m_tmp, N_tmp, dNdL_tmp) L[j] = tmp return dmdL_tmp[i] }, L[j], 1e-6) chk.AnaNum(tst, io.Sf("d2m/dL[%d]dL[%d]", i, j), dtol2, d2mdLdL[i][j], dnum, dver) } } // d²N/dLdL io.Pfpink("\nd²N/dLdL\n") for i := 0; i < 3; i++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[i] = L[i], x SmpDirectorDeriv1(dNdL_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) L[i] = tmp return dNdL_tmp[i] }, L[i], 1e-6) chk.AnaNum(tst, io.Sf("d²N[%d]/dL[%d]dL[%d]", i, i, i), dtol2, d2NdL2[i], dnum, dver) } // d²n/dLdL io.Pfpink("\nd²n/dLdL\n") dndL_tmp := la.MatAlloc(3, 3) d2ndLdL := utl.Deep3alloc(3, 3, 3) SmpUnitDirectorDeriv2(d2ndLdL, m, N, dNdL, d2NdL2, dmdL, n, d2mdLdL, dndL) for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { for k := 0; k < 3; k++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, L[k] = L[k], x m_tmp := SmpDirector(N_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpDirectorDeriv1(dNdL_tmp, L, smp_a, smp_b, smp_β, smp_ϵ) SmpNormDirectorDeriv1(dmdL_tmp, m_tmp, N_tmp, dNdL_tmp) SmpUnitDirectorDeriv1(dndL_tmp, m_tmp, N_tmp, dNdL_tmp, dmdL_tmp) L[k] = tmp return dndL_tmp[i][j] }, L[k], 1e-6) chk.AnaNum(tst, io.Sf("d²n[%d]/dL[%d]dL[%d]", i, j, k), dtol2, d2ndLdL[i][j][k], dnum, dver) } } } // recover tolerance dtol2 = dtol2_tmp // SMP derivs //if false { if true { io.Pfpink("\nSMP derivs\n") dndL_ := la.MatAlloc(3, 3) dNdL_ := make([]float64, 3) d2ndLdL_ := utl.Deep3alloc(3, 3, 3) N_ := make([]float64, 3) F_ := make([]float64, 3) G_ := make([]float64, 3) m_ := SmpDerivs1(dndL_, dNdL_, N_, F_, G_, L, smp_a, smp_b, smp_β, smp_ϵ) SmpDerivs2(d2ndLdL_, L, smp_a, smp_b, smp_β, smp_ϵ, m_, N_, F_, G_, dNdL_, dndL_) chk.Scalar(tst, "m_", 1e-14, m_, m) chk.Vector(tst, "N_", 1e-15, N_, N) chk.Vector(tst, "dNdL_", 1e-15, dNdL_, dNdL) chk.Matrix(tst, "dndL_", 1e-13, dndL_, dndL) chk.Deep3(tst, "d2ndLdL_", 1e-11, d2ndLdL_, d2ndLdL) } } }
// 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) } } } } } }