// 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 } } } }
func main() { // define function and derivative function y_fcn := func(x float64) float64 { return math.Sin(x) } dydx_fcn := func(x float64) float64 { return math.Cos(x) } d2ydx2_fcn := func(x float64) float64 { return -math.Sin(x) } // run test for 11 points X := utl.LinSpace(0, 2*math.Pi, 11) io.Pf(" %8s %23s %23s %23s\n", "x", "analytical", "numerical", "error") for _, x := range X { // analytical derivatives dydx_ana := dydx_fcn(x) d2ydx2_ana := d2ydx2_fcn(x) // numerical derivative: dydx dydx_num, _ := num.DerivCentral(func(t float64, args ...interface{}) float64 { return y_fcn(t) }, x, 1e-3) // numerical derivative d2ydx2 d2ydx2_num, _ := num.DerivCentral(func(t float64, args ...interface{}) float64 { return dydx_fcn(t) }, x, 1e-3) // check chk.PrintAnaNum(io.Sf("dy/dx @ %.6f", x), 1e-10, dydx_ana, dydx_num, true) chk.PrintAnaNum(io.Sf("d²y/dx² @ %.6f", x), 1e-10, d2ydx2_ana, d2ydx2_num, true) } // generate 101 points for plotting X = utl.LinSpace(0, 2*math.Pi, 101) Y := make([]float64, len(X)) for i, x := range X { Y[i] = y_fcn(x) } // plot plt.SetForPng(0.75, 300, 150) plt.Plot(X, Y, "'b.-', clip_on=0, markevery=10, label='y(x)=sin(x)'") plt.Gll("x", "y", "") plt.SaveD("/tmp/gosl", "num_deriv01.png") }
func main() { // define function and derivative function y_fcn := func(x float64) float64 { return math.Sin(x) } dydx_fcn := func(x float64) float64 { return math.Cos(x) } d2ydx2_fcn := func(x float64) float64 { return -math.Sin(x) } // run test for 11 points X := utl.LinSpace(0, 2*math.Pi, 11) for _, x := range X { // analytical derivatives dydx_ana := dydx_fcn(x) d2ydx2_ana := d2ydx2_fcn(x) // numerical derivative: dydx dydx_num, _ := num.DerivCentral(func(t float64, args ...interface{}) float64 { return y_fcn(t) }, x, 1e-3) // numerical derivative d2ydx2 d2ydx2_num, _ := num.DerivCentral(func(t float64, args ...interface{}) float64 { return dydx_fcn(t) }, x, 1e-3) // check chk.PrintAnaNum(io.Sf("dy/dx @ %.6f", x), 1e-10, dydx_ana, dydx_num, true) chk.PrintAnaNum(io.Sf("d²y/dx² @ %.6f", x), 1e-10, d2ydx2_ana, d2ydx2_num, true) } // generate 101 points X = utl.LinSpace(0, 2*math.Pi, 101) Y := make([]float64, len(X)) for i, x := range X { Y[i] = y_fcn(x) } // plot plt.Plot(X, Y, "'b.-'") plt.Gll("x", "y", "") plt.Show() }
// CheckEigenprojsDerivs checks the derivatives of eigen projectors w.r.t defining tensor func CheckEigenprojsDerivs(a []float64, tol float64, ver bool, zero float64) { // compute eigenvalues and eigenprojectors ncp := len(a) λ := make([]float64, 3) P := la.MatAlloc(3, ncp) docalc := func() { err := M_EigenValsProjsNum(P, λ, a) if err != nil { chk.Panic("eigenprojs.go: CheckEigenprojsDerivs failed:\n %v", err.Error()) } } // compute derivatives of eigenprojectors docalc() dPda := utl.Deep3alloc(3, ncp, ncp) err := M_EigenProjsDerivAuto(dPda, a, λ, P) if err != nil { chk.Panic("%v", err) } // check var tmp float64 has_error := false for k := 0; k < 3; k++ { for i := 0; i < ncp; i++ { for j := 0; j < ncp; j++ { dnum, _ := num.DerivCentral(func(x float64, args ...interface{}) (res float64) { tmp, a[j] = a[j], x docalc() a[j] = tmp return P[k][i] }, a[j], 1e-6) err := chk.PrintAnaNum(io.Sf("dP%d[%d]/da[%d]", k, i, j), tol, dPda[k][i][j], dnum, ver) if err != nil { has_error = true } } } if ver { io.Pf("\n") } } if has_error { chk.Panic(_eigenprojs_err8) } 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 } } } }
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_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") } }
// CheckDerivs check derivatives computed by isotropic function func (o *IsoFun) CheckDerivs(A []float64, tol, tol2, tolq, tol3 float64, ver bool, args ...interface{}) (err error) { // L and invariants chk.IntAssert(len(A), o.ncp) L := make([]float64, 3) err = M_EigenValsNum(L, A) if err != nil { return } p, q, err := GenInvs(L, o.n, o.a) if err != nil { return } io.Pforan("L = %v\n", L) io.Pforan("p, q = %v, %v\n", p, q) // constants h := 1e-6 var has_error error // derivatives of callback functions /////////////// // df/dp, df/dq, d²f/dp², d²f/dq², d²f/dpdq dfdp, dfdq := o.gfcn(p, q, args...) d2fdp2, d2fdq2, d2fdpdq := o.hfcn(p, q, args...) if ver { io.Pfpink("\nd w.r.t invariants . . . \n") } // check df/dp dfdp_num, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { return o.ffcn(x, q, args...) }, p, h) err = chk.PrintAnaNum("df/dp ", tol, dfdp, dfdp_num, ver) if err != nil { has_error = err } // check df/dq dfdq_num, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { return o.ffcn(p, x, args...) }, q, h) err = chk.PrintAnaNum("df/dq ", tol, dfdq, dfdq_num, ver) if err != nil { has_error = err } // check d²f/dp² d2fdp2_num, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { dfdp_tmp, _ := o.gfcn(x, q, args...) return dfdp_tmp }, p, h) err = chk.PrintAnaNum("d²f/dp² ", tol, d2fdp2, d2fdp2_num, ver) if err != nil { has_error = err } // check d²f/dq² d2fdq2_num, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { _, dfdq_tmp := o.gfcn(p, x, args...) return dfdq_tmp }, q, h) err = chk.PrintAnaNum("d²f/dq² ", tol, d2fdq2, d2fdq2_num, ver) if err != nil { has_error = err } // check d²f/dpdq d2fdpdq_num, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { dfdp_tmp, _ := o.gfcn(p, x, args...) return dfdp_tmp }, q, h) err = chk.PrintAnaNum("d²f/dpdq", tol, d2fdpdq, d2fdpdq_num, ver) if err != nil { has_error = err } // derivatives w.r.t eigenvalues /////////////////// // df/dL and d²f/dLdL _, err = o.Gp(L, args...) if err != nil { chk.Panic("Gp failed:\n%v", err) } err = o.HafterGp(args...) if err != nil { chk.Panic("HafterGp failed:\n%v", err) } dfdL := make([]float64, 3) d2pdLdL := la.MatAlloc(3, 3) d2qdLdL := la.MatAlloc(3, 3) d2fdLdL := la.MatAlloc(3, 3) copy(dfdL, o.DfdL) la.MatCopy(d2pdLdL, 1, o.d2pdLdL) la.MatCopy(d2qdLdL, 1, o.d2qdLdL) la.MatCopy(d2fdLdL, 1, o.DgdL) // check df/dL if ver { io.Pfpink("\ndf/dL . . . . . . . . \n") } var fval, tmp float64 for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, L[j] = L[j], x defer func() { L[j] = tmp }() fval, err = o.Fp(L, args...) if err != nil { chk.Panic("Fp failed:\n%v", err) } return fval }, L[j], h) err := chk.PrintAnaNum(io.Sf("df/dL[%d]", j), tol, dfdL[j], dnum, ver) if err != nil { has_error = err } } // check d²p/dLdL if ver { io.Pfpink("\nd²p/dLdL . . . . . . . . \n") } for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, L[j] = L[j], x defer func() { L[j] = tmp }() _, err = o.Gp(L, args...) if err != nil { chk.Panic("Gp failed\n%v", err) } return o.dpdL[i] }, L[j], h) err := chk.PrintAnaNum(io.Sf("d²p/dL[%d]dL[%d]", i, j), tol2, d2pdLdL[i][j], dnum, ver) if err != nil { has_error = err } } } // check d²q/dLdL if ver { io.Pfpink("\nd²q/dLdL . . . . . . . . \n") } for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, L[j] = L[j], x defer func() { L[j] = tmp }() _, err = o.Gp(L, args...) if err != nil { chk.Panic("Gp failed\n%v", err) } return o.dqdL[i] }, L[j], h) err := chk.PrintAnaNum(io.Sf("d²q/dL[%d]dL[%d]", i, j), tolq, d2qdLdL[i][j], dnum, ver) if err != nil { has_error = err } } } // check d²f/dLdL if ver { io.Pfpink("\nd²f/dLdL . . . . . . . . \n") } for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, L[j] = L[j], x defer func() { L[j] = tmp }() _, err = o.Gp(L, args...) if err != nil { chk.Panic("Gp failed\n%v", err) } return o.DfdL[i] }, L[j], h) err := chk.PrintAnaNum(io.Sf("d²f/dL[%d]dL[%d]", i, j), tol2, d2fdLdL[i][j], dnum, ver) if err != nil { has_error = err } } } // derivatives w.r.t full tensor /////////////////// // dfdA and d²f/dAdA ncp := len(A) dfdA := make([]float64, ncp) d2fdAdA := la.MatAlloc(ncp, ncp) _, err = o.Ga(dfdA, A, args...) // also computes P, L and Acpy if err != nil { chk.Panic("Ga failed:\n%v", err) } err = o.HafterGa(d2fdAdA, args...) // also computes dPdA if err != nil { chk.Panic("HafterGa failed:\n%v", err) } // check df/dA if ver { io.Pfpink("\ndf/dA . . . . . . . . \n") } for j := 0; j < ncp; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, A[j] = A[j], x defer func() { A[j] = tmp }() fval, err = o.Fa(A, args...) if err != nil { chk.Panic("Fa failed:\n%v", err) } return fval }, A[j], h) err := chk.PrintAnaNum(io.Sf("df/dA[%d]", j), tol, dfdA[j], dnum, ver) if err != nil { has_error = err } } // check dP/dA if false { for k := 0; k < 3; k++ { if ver { io.Pfpink("\ndP%d/dA . . . . . . . . \n", k) } for i := 0; i < ncp; i++ { for j := 0; j < ncp; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, A[j] = A[j], x defer func() { A[j] = tmp }() err = M_EigenValsProjsNum(o.P, o.L, o.Acpy) if err != nil { chk.Panic("M_EigenValsProjsNum failed:\n%v", err) } return o.P[k][i] }, A[j], h) err := chk.PrintAnaNum(io.Sf("dP%d/dA[%d]dA[%d]", k, i, j), tol, o.dPdA[k][i][j], dnum, ver) if err != nil { has_error = err } } } } } // check d²f/dAdA if ver { io.Pfpink("\nd²f/dAdA . . . . . . . . \n") } dfdA_tmp := make([]float64, ncp) for i := 0; i < ncp; i++ { for j := 0; j < ncp; j++ { dnum, _ := num.DerivCentral(func(x float64, notused ...interface{}) (res float64) { tmp, A[j] = A[j], x defer func() { A[j] = tmp }() _, err = o.Ga(dfdA_tmp, A, args...) if err != nil { chk.Panic("Ga failed:\n%v", err) } return dfdA_tmp[i] }, A[j], h) dtol := tol2 if i == j && (i == 3 || i == 4 || i == 5) { dtol = tol3 } err := chk.PrintAnaNum(io.Sf("d²f/dA[%d]dA[%d]", i, j), dtol, d2fdAdA[i][j], dnum, ver) if err != nil { has_error = err } } } // any errors? if has_error != nil { err = has_error } 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) } } }
// M_EigenProjsDerivNum returns the derivatives of the eigenprojectors w.r.t its defining tensor // using the finite differences method. // Input: // a -- tensor in Mandel basis // h -- step size for finite differences // Output: // dPda -- derivatives [3][ncp][ncp] func M_EigenProjsDerivNum(dPda [][][]float64, a []float64, h float64) (err error) { ncp := len(a) λ := make([]float64, 3) P := la.MatAlloc(3, ncp) Q := Alloc2() A := Alloc2() q2p := func(k int) { switch k { case 0: P[0][0] = Q[0][0] * Q[0][0] P[0][1] = Q[1][0] * Q[1][0] P[0][2] = Q[2][0] * Q[2][0] P[0][3] = Q[0][0] * Q[1][0] * SQ2 if ncp == 6 { P[0][4] = Q[1][0] * Q[2][0] * SQ2 P[0][5] = Q[2][0] * Q[0][0] * SQ2 } case 1: P[1][0] = Q[0][1] * Q[0][1] P[1][1] = Q[1][1] * Q[1][1] P[1][2] = Q[2][1] * Q[2][1] P[1][3] = Q[0][1] * Q[1][1] * SQ2 if ncp == 6 { P[1][4] = Q[1][1] * Q[2][1] * SQ2 P[1][5] = Q[2][1] * Q[0][1] * SQ2 } case 2: P[2][0] = Q[0][2] * Q[0][2] P[2][1] = Q[1][2] * Q[1][2] P[2][2] = Q[2][2] * Q[2][2] P[2][3] = Q[0][2] * Q[1][2] * SQ2 if ncp == 6 { P[2][4] = Q[1][2] * Q[2][2] * SQ2 P[2][5] = Q[2][2] * Q[0][2] * SQ2 } } } var tmp float64 failed := false for k := 0; k < 3; k++ { for i := 0; i < ncp; i++ { for j := 0; j < ncp; j++ { dPda[k][i][j], _ = num.DerivCentral(func(x float64, args ...interface{}) float64 { tmp, a[j] = a[j], x defer func() { a[j] = tmp }() Man2Ten(A, a) _, err = la.Jacobi(Q, λ, A) if err != nil { failed = true return 0 } q2p(k) return P[k][i] }, a[j], h) if failed { return } } } } return }