func plot_cone(α float64, preservePrev bool) { nu, nv := 11, 21 l := 1.2 r := math.Tan(α) * l S, T := utl.MeshGrid2D(0, l, 0, 2.0*PI, nu, nv) X := la.MatAlloc(nv, nu) Y := la.MatAlloc(nv, nu) Z := la.MatAlloc(nv, nu) u := make([]float64, 3) v := make([]float64, 3) L := rot_matrix() for j := 0; j < nu; j++ { for i := 0; i < nv; i++ { u[0] = S[i][j] * r * math.Cos(T[i][j]) u[1] = S[i][j] * r * math.Sin(T[i][j]) u[2] = S[i][j] la.MatVecMul(v, 1, L, u) X[i][j], Y[i][j], Z[i][j] = v[0], v[1], v[2] } } pp := 0 if preservePrev { pp = 1 } plt.Wireframe(X, Y, Z, io.Sf("color='b', lw=0.5, preservePrev=%d", pp)) }
func Test_invs05(tst *testing.T) { //verbose() chk.PrintTitle("invs05") if SAVEPLOT { plt.Reset() plt.SetForPng(1, 500, 125) PlotRosette(1.1, true, true, true, 7) } addtoplot := func(σa, σb float64, σ []float64) { plt.PlotOne(σa, σb, "'ro', ms=5") plt.Text(σa, σb, io.Sf("$\\sigma_{123}=(%g,%g,%g)$", σ[0], σ[1], σ[2]), "size=8") } dotest := func(σ []float64, σacor, σbcor, σccor, θcor, tolσ float64) { w := M_w(σ) θ2 := math.Asin(w) * 180.0 / (3.0 * math.Pi) θ3 := M_θ(σ) σa, σb, σc := L2O(σ[0], σ[1], σ[2]) σ0, σ1, σ2 := O2L(σa, σb, σc) σI, σA := make([]float64, 3), []float64{σa, σb, σc} la.MatVecMul(σI, 1, O2Lmat(), σA) // σI := L * σA io.Pf("σa σb σc = %v %v %v\n", σa, σb, σc) io.Pf("w = %v\n", w) io.Pf("θ2, θ3 = %v, %v\n", θ2, θ3) chk.Scalar(tst, "σa", 1e-17, σa, σacor) chk.Scalar(tst, "σb", 1e-17, σb, σbcor) chk.Scalar(tst, "σc", 1e-17, σc, σccor) chk.Scalar(tst, "σ0", tolσ, σ0, σ[0]) chk.Scalar(tst, "σ1", tolσ, σ1, σ[1]) chk.Scalar(tst, "σ2", tolσ, σ2, σ[2]) chk.Scalar(tst, "σI0", tolσ, σI[0], σ[0]) chk.Scalar(tst, "σI1", tolσ, σI[1], σ[1]) chk.Scalar(tst, "σI2", tolσ, σI[2], σ[2]) chk.Scalar(tst, "θ2", 1e-6, θ2, θcor) chk.Scalar(tst, "θ3", 1e-17, θ3, θ2) addtoplot(σa, σb, σ) } dotest([]float64{-1, 0, 0, 0}, 0, 2.0/SQ6, 1.0/SQ3, 30, 1e-15) dotest([]float64{0, -1, 0, 0}, 1.0/SQ2, -1.0/SQ6, 1.0/SQ3, 30, 1e-15) dotest([]float64{0, 0, -1, 0}, -1.0/SQ2, -1.0/SQ6, 1.0/SQ3, 30, 1e-15) if SAVEPLOT { plt.Gll("$\\sigma_a$", "$\\sigma_b$", "") plt.Equal() plt.SaveD("/tmp/gosl", "fig_invs05.png") } }
// adds -R to global residual vector fb func (o Beam) AddToRhs(fb []float64, sol *Solution) (ok bool) { // node displacements for i, I := range o.Umap { o.ue[i] = sol.Y[I] } // steady/dynamics if Global.Sim.Data.Steady { la.MatVecMul(o.fi, 1, o.K, o.ue) } else { dc := Global.DynCoefs for i := 0; i < o.Nu; i++ { o.fi[i] = 0 for j := 0; j < o.Nu; j++ { o.fi[i] += o.M[i][j]*(dc.α1*o.ue[j]-o.ζe[j]) + o.K[i][j]*o.ue[j] } } } // distributed loads if o.Hasq { dx := o.X[0][1] - o.X[0][0] dy := o.X[1][1] - o.X[1][0] l := math.Sqrt(dx*dx + dy*dy) qnL := o.QnL.F(sol.T, nil) qnR := o.QnR.F(sol.T, nil) qt := o.Qt.F(sol.T, nil) o.fxl[0] = qt * l / 2.0 o.fxl[1] = l * (7.0*qnL + 3.0*qnR) / 20.0 o.fxl[2] = l * l * (3.0*qnL + 2.0*qnR) / 60.0 o.fxl[3] = qt * l / 2.0 o.fxl[4] = l * (3.0*qnL + 7.0*qnR) / 20.0 o.fxl[5] = -l * l * (2.0*qnL + 3.0*qnR) / 60.0 la.MatTrVecMulAdd(o.fi, -1.0, o.T, o.fxl) // Rus -= fx; fx = trans(T) * fxl } // add to fb for i, I := range o.Umap { fb[I] -= o.fi[i] } return true }
// adds -R to global residual vector fb func (o *Beam) AddToRhs(fb []float64, sol *Solution) (err error) { // node displacements for i, I := range o.Umap { o.ue[i] = sol.Y[I] } // steady/dynamics if sol.Steady { la.MatVecMul(o.fi, 1, o.K, o.ue) } else { α1 := sol.DynCfs.α1 for i := 0; i < o.Nu; i++ { o.fi[i] = 0 for j := 0; j < o.Nu; j++ { o.fi[i] += o.M[i][j]*(α1*o.ue[j]-o.ζe[j]) + o.K[i][j]*o.ue[j] } } } // distributed loads if o.Hasq { dx := o.X[0][1] - o.X[0][0] dy := o.X[1][1] - o.X[1][0] l := math.Sqrt(dx*dx + dy*dy) qnL, qnR, qt := o.calc_loads(sol.T) o.fxl[0] = qt * l / 2.0 o.fxl[1] = l * (7.0*qnL + 3.0*qnR) / 20.0 o.fxl[2] = l * l * (3.0*qnL + 2.0*qnR) / 60.0 o.fxl[3] = qt * l / 2.0 o.fxl[4] = l * (3.0*qnL + 7.0*qnR) / 20.0 o.fxl[5] = -l * l * (2.0*qnL + 3.0*qnR) / 60.0 la.MatTrVecMulAdd(o.fi, -1.0, o.T, o.fxl) // Rus -= fx; fx = trans(T) * fxl } // add to fb for i, I := range o.Umap { fb[I] -= o.fi[i] } return }
func Test_invs02(tst *testing.T) { //verbose() chk.PrintTitle("invs02") eps := [][]float64{ {100 / 200.0, 150 / 200.0, 5 / 200.0}, {150 / 200.0, 100 / 200.0, 10 / 200.0}, {5 / 200.0, 10 / 200.0, 100 / 200.0}, } ε := make([]float64, 6) e := make([]float64, 6) e_ := make([]float64, 6) Ten2Man(ε, eps) εv := M_εv(ε) εd := M_εd(ε) eno, εv_, εd_ := M_devε(e, ε) Lε := make([]float64, 3) err := M_EigenValsNum(Lε, ε) if err != nil { tst.Errorf("test failed: %v\n", err) return } Lεv, Lεd := L_strains(Lε) la.MatVecMul(e_, 1, Psd, ε) la.PrintMat("eps", eps, "%8g", false) io.Pf("ε = %v\n", ε) io.Pf("e = %v\n", e) io.Pf("e_ = %v\n", e_) io.Pf("eno = %v\n", eno) io.Pf("εv = %v Lεv=%v\n", εv, Lεv) io.Pf("εd = %v Lεd=%v\n", εd, Lεd) io.Pf("εd_ = %v\n", εd_) chk.Scalar(tst, "Lεv", 1e-17, Lεv, εv) chk.Scalar(tst, "Lεd", 1e-15, Lεd, εd) chk.Scalar(tst, "εv", 1e-17, εv, εv_) chk.Scalar(tst, "εv", 1e-17, εv, eps[0][0]+eps[1][1]+eps[2][2]) chk.Scalar(tst, "εd", 1e-13, εd, εd_) chk.Vector(tst, "e", 1e-17, e, e_) }
func Test_invs03(tst *testing.T) { //verbose() chk.PrintTitle("invs03") // square with vertical stress only under plane-strain E, ν := 210000.0, 0.49999 qY := 240.0 σx := 0.0 σy := -qY / math.Sqrt(ν*ν-ν+1.0) σz := ν * (σx + σy) εx := -(ν*σz + ν*σy - σx) / E εy := -(ν*σz - σy + ν*σx) / E εz := 0.0 // check c := E / ((1.0 + ν) * (1.0 - 2.0*ν)) De := [][]float64{ {c * (1.0 - ν), c * ν, c * ν, 0.0}, {c * ν, c * (1.0 - ν), c * ν, 0.0}, {c * ν, c * ν, c * (1.0 - ν), 0.0}, {0.0, 0.0, 0.0, c * (1.0 - 2.0*ν)}, } ε := [][]float64{ {εx, 0, 0}, {0, εy, 0}, {0, 0, εz}, } εm := make([]float64, 4) σm := make([]float64, 4) Ten2Man(εm, ε) la.MatVecMul(σm, 1, De, εm) q := M_q(σm) θ := M_θ(σm) io.Pfcyan("σm = %v\n", σm) io.Pfcyan("q = %v\n", q) io.Pfcyan("θ = %v\n", θ) chk.Scalar(tst, "q", 1e-10, q, qY) chk.Scalar(tst, "θ", 1e-3, θ, 0) }
func Test_linipm03(tst *testing.T) { //verbose() chk.PrintTitle("linipm03") t0 := time.Now() defer func() { io.Pfblue2("\ntime elapsed = %v\n", time.Now().Sub(t0)) }() // read LP A, b, c, l, u := ReadLPfortran("data/afiro.dat") //A, b, c, l, u := ReadLPfortran("data/adlittle.dat") //A, b, c, l, u := ReadLPfortran("data/share1b.dat") // check for unbounded variables nx := len(c) for i := 0; i < nx; i++ { if math.Abs(l[i]) > 1e-15 { chk.Panic("cannot handle l != 0 yet") } if math.Abs(u[i]-1e20) > 1e-15 { chk.Panic("cannot handle u != ∞ yet") } } // solve LP var ipm LinIpm defer ipm.Clean() ipm.Init(A, b, c, nil) err := ipm.Solve(chk.Verbose) if err != nil { tst.Errorf("ipm failed:\n%v", err) return } // check io.Pf("\n") bres := make([]float64, len(b)) la.MatVecMul(bres, 1, A.ToDense(), ipm.X) chk.Vector(tst, "A*x=b", 1e-13, bres, b) }
func Test_invs01(tst *testing.T) { //verbose() chk.PrintTitle("invs01") sig := [][]float64{ {100, 150, 5}, {150, 100, 10}, {5, 10, 100}, } σ := make([]float64, 6) s := make([]float64, 6) s_ := make([]float64, 6) Ten2Man(σ, sig) // σ := sig p := M_p(σ) q := M_q(σ) θ := M_θ(σ) sno, p_, q_ := M_devσ(s, σ) p1, q1, θ1 := M_pqθ(σ) la.MatVecMul(s_, 1, Psd, σ) la.PrintMat("sig", sig, "%8g", false) io.Pf("σ = %v\n", σ) io.Pf("s = %v\n", s) io.Pf("s_ = %v\n", s_) io.Pf("sno = %v\n", sno) io.Pf("p = %v\n", p) io.Pf("q = %v\n", q) io.Pf("q_ = %v\n", q_) io.Pf("θ = %v\n", θ) chk.Scalar(tst, "p", 1e-17, p, p_) chk.Scalar(tst, "p", 1e-17, p, -100) chk.Scalar(tst, "q", 1e-17, q, 260.52830940226056) chk.Scalar(tst, "q", 1e-13, q, q_) chk.Vector(tst, "s", 1e-17, s, s_) chk.Scalar(tst, "p1", 1e-17, p, p1) chk.Scalar(tst, "q1", 1e-13, q, q1) chk.Scalar(tst, "θ1", 1e-17, θ, θ1) }
func Test_extrapapolation(tst *testing.T) { //verbose() chk.PrintTitle("Test extrapolation") GetIpNums := func(name string) []int { var nums []int for key, _ := range ipsfactory { name_n := strings.Split(key, "_") if name_n[0] == name { nip := io.Atoi(name_n[1]) nums = append(nums, nip) } } return nums } for name, shape := range factory { gndim := shape.Gndim if gndim == 1 { continue } io.Pfyel("--------------------------------- %-6s---------------------------------\n", name) for _, nip := range GetIpNums(shape.Type) { if nip <= 1 { continue } io.Pfblue("nip = %v\n", nip) tol := 1.0e-13 // create a N vector with nodal values nverts := shape.Nverts X := shape.NatCoords delta := rand.Float64() N := make([]float64, shape.Nverts) for i := 0; i < shape.Nverts; i++ { var x, y, z float64 x = X[0][i] y = X[1][i] if shape.Gndim == 3 { z = X[2][i] } N[i] = x + y + z + delta } io.Pfblue("N = %v\n", N) // calculate P vector with corresponding values at ips key := name + "_" + strconv.Itoa(nip) ips := ipsfactory[key] P := make([]float64, nip) Xip := la.MatAlloc(nip, 4) // ips local coordinates for i := 0; i < nip; i++ { var x, y, z float64 x = ips[i][0] y = ips[i][1] z = ips[i][2] Xip[i][0] = x Xip[i][1] = y Xip[i][2] = z P[i] = x + y + z + delta } // Allocate E matrix E := la.MatAlloc(nverts, nip) // Calculate extrapolator matrix shape.Extrapolator(E, ips) // Recalculate nodal values NN = E*P NN := make([]float64, shape.Nverts) la.MatVecMul(NN, 1.0, E, P) io.Pfblue("N ext= %v\n", NN) // Compare vectors N and NN msg := name + "_" + strconv.Itoa(nip) chk.Vector(tst, msg, tol, NN, N) } } }
func Test_linipm02(tst *testing.T) { //verbose() chk.PrintTitle("linipm02") // linear program // min 2*x0 + x1 // s.t. -x0 + x1 ≤ 1 // x0 + x1 ≥ 2 → -x0 - x1 ≤ -2 // x0 - 2*x1 ≤ 4 // x1 ≥ 0 // standard (step 1) add slack // s.t. -x0 + x1 + x2 = 1 // -x0 - x1 + x3 = -2 // x0 - 2*x1 + x4 = 4 // standard (step 2) // replace x0 := x0_ - x5 // because it's unbounded // min 2*x0_ + x1 - 2*x5 // s.t. -x0_ + x1 + x2 + x5 = 1 // -x0_ - x1 + x3 + x5 = -2 // x0_ - 2*x1 + x4 - x5 = 4 // x0_,x1,x2,x3,x4,x5 ≥ 0 var T la.Triplet T.Init(3, 6, 12) T.Put(0, 0, -1) T.Put(0, 1, 1) T.Put(0, 2, 1) T.Put(0, 5, 1) T.Put(1, 0, -1) T.Put(1, 1, -1) T.Put(1, 3, 1) T.Put(1, 5, 1) T.Put(2, 0, 1) T.Put(2, 1, -2) T.Put(2, 4, 1) T.Put(2, 5, -1) Am := T.ToMatrix(nil) A := Am.ToDense() c := []float64{2, 1, 0, 0, 0, -2} b := []float64{1, -2, 4} // print LP la.PrintMat("A", A, "%6g", false) la.PrintVec("b", b, "%6g", false) la.PrintVec("c", c, "%6g", false) io.Pf("\n") // solve LP var ipm LinIpm defer ipm.Clean() ipm.Init(Am, b, c, nil) err := ipm.Solve(chk.Verbose) if err != nil { tst.Errorf("ipm failed:\n%v", err) return } // check io.Pf("\n") bres := make([]float64, len(b)) la.MatVecMul(bres, 1, A, ipm.X) io.Pforan("bres = %v\n", bres) chk.Vector(tst, "A*x=b", 1e-8, bres, b) // fix and check x x := ipm.X[:2] x[0] -= ipm.X[5] io.Pforan("x = %v\n", x) chk.Vector(tst, "x", 1e-8, x, []float64{0.5, 1.5}) // plot if true && chk.Verbose { f := func(x []float64) float64 { return c[0]*x[0] + c[1]*x[1] } g := func(x []float64, i int) float64 { return A[i][0]*x[0] + A[i][1]*x[1] - b[i] } np := 41 vmin, vmax := []float64{-2.0, -2.0}, []float64{2.0, 2.0} PlotTwoVarsContour("/tmp/gosl", "test_linipm02", x, np, nil, true, vmin, vmax, f, func(x []float64) float64 { return g(x, 0) }, func(x []float64) float64 { return g(x, 1) }, ) } }
func Test_linipm01(tst *testing.T) { //verbose() chk.PrintTitle("linipm01") // linear programming problem // min -4*x0 - 5*x1 // s.t. 2*x0 + x1 ≤ 3 // x0 + 2*x1 ≤ 3 // x0,x1 ≥ 0 // standard: // 2*x0 + x1 + x2 = 3 // x0 + 2*x1 + x3 = 3 // x0,x1,x2,x3 ≥ 0 var T la.Triplet T.Init(2, 4, 6) T.Put(0, 0, 2.0) T.Put(0, 1, 1.0) T.Put(0, 2, 1.0) T.Put(1, 0, 1.0) T.Put(1, 1, 2.0) T.Put(1, 3, 1.0) Am := T.ToMatrix(nil) A := Am.ToDense() c := []float64{-4, -5, 0, 0} b := []float64{3, 3} // print LP la.PrintMat("A", A, "%6g", false) la.PrintVec("b", b, "%6g", false) la.PrintVec("c", c, "%6g", false) io.Pf("\n") // solve LP var ipm LinIpm defer ipm.Clean() ipm.Init(Am, b, c, nil) err := ipm.Solve(chk.Verbose) if err != nil { tst.Errorf("ipm failed:\n%v", err) return } // check io.Pf("\n") io.Pforan("x = %v\n", ipm.X) io.Pfcyan("λ = %v\n", ipm.L) io.Pforan("s = %v\n", ipm.S) x := ipm.X[:2] bres := make([]float64, 2) la.MatVecMul(bres, 1, A, x) io.Pforan("bres = %v\n", bres) chk.Vector(tst, "x", 1e-9, x, []float64{1, 1}) chk.Vector(tst, "A*x=b", 1e-8, bres, b) // plot if true && chk.Verbose { f := func(x []float64) float64 { return c[0]*x[0] + c[1]*x[1] } g := func(x []float64, i int) float64 { return A[i][0]*x[0] + A[i][1]*x[1] - b[i] } np := 41 vmin, vmax := []float64{-2.0, -2.0}, []float64{2.0, 2.0} PlotTwoVarsContour("/tmp/gosl", "test_linipm01", x, np, nil, true, vmin, vmax, f, func(x []float64) float64 { return g(x, 0) }, func(x []float64) float64 { return g(x, 1) }, ) } }
// Connect connects rod/solid elements in this Rjoint func (o *Rjoint) Connect(cid2elem []Elem, c *inp.Cell) (nnzK int, err error) { // get rod and solid elements rodId := c.JlinId sldId := c.JsldId o.Rod = cid2elem[rodId].(*Rod) o.Sld = cid2elem[sldId].(*ElemU) if o.Rod == nil { err = chk.Err("cannot find joint's rod cell with id == %d", rodId) return } if o.Sld == nil { err = chk.Err("cannot find joint's solid cell with id == %d", sldId) return } // total number of dofs o.Ny = o.Rod.Nu + o.Sld.Nu // material model name matdata := o.Sim.MatParams.Get(o.Edat.Mat) if matdata == nil { err = chk.Err("materials database failed on getting %q material\n", o.Edat.Mat) return } // initialise model err = o.Mdl.Init(matdata.Prms) if err != nil { err = chk.Err("model initialisation failed:\n%v", err) return } // parameters for _, p := range matdata.Prms { switch p.N { case "h": o.h = p.V case "k1": o.k1 = p.V case "k2": o.k2 = p.V case "mu": if p.V > 0.0 { o.Coulomb = true } } } // auxiliary nsig := 2 * o.Ndim // rod data rodH := o.Rod.Cell.Shp rodNp := len(o.Rod.IpsElem) rodNn := rodH.Nverts rodNu := o.Rod.Nu // solid data sldH := o.Sld.Cell.Shp sldS := sldH.S sldNp := len(o.Sld.IpsElem) sldNn := sldH.Nverts sldNu := o.Sld.Nu // shape functions of solid @ nodes of rod o.Nmat = la.MatAlloc(sldNn, rodNn) rodYn := make([]float64, o.Ndim) rodRn := make([]float64, 3) for m := 0; m < rodNn; m++ { for i := 0; i < o.Ndim; i++ { rodYn[i] = o.Rod.X[i][m] } err = sldH.InvMap(rodRn, rodYn, o.Sld.X) if err != nil { return } err = sldH.CalcAtR(o.Sld.X, rodRn, false) if err != nil { return } for n := 0; n < sldNn; n++ { o.Nmat[n][m] = sldH.S[n] } } // coulomb model => σc depends on p values of solid if o.Coulomb { // allocate variables o.Pmat = la.MatAlloc(sldNn, rodNp) o.Emat = la.MatAlloc(sldNn, sldNp) o.rodRp = la.MatAlloc(rodNp, 3) o.σNo = la.MatAlloc(sldNn, nsig) o.σIp = make([]float64, nsig) o.t1 = make([]float64, o.Ndim) o.t2 = make([]float64, o.Ndim) // extrapolator matrix err = sldH.Extrapolator(o.Emat, o.Sld.IpsElem) if err != nil { return } // shape function of solid @ ips of rod for idx, ip := range o.Rod.IpsElem { rodYp := rodH.IpRealCoords(o.Rod.X, ip) err = sldH.InvMap(o.rodRp[idx], rodYp, o.Sld.X) if err != nil { return } err = sldH.CalcAtR(o.Sld.X, o.rodRp[idx], false) if err != nil { return } for n := 0; n < sldNn; n++ { o.Pmat[n][idx] = sldS[n] } } } // joint direction @ ip[idx]; corotational system aligned with rod element o.e0 = la.MatAlloc(rodNp, o.Ndim) o.e1 = la.MatAlloc(rodNp, o.Ndim) o.e2 = la.MatAlloc(rodNp, o.Ndim) π := make([]float64, o.Ndim) // Eq. (27) Q := la.MatAlloc(o.Ndim, o.Ndim) α := 666.0 Jvec := rodH.Jvec3d[:o.Ndim] for idx, ip := range o.Rod.IpsElem { // auxiliary e0, e1, e2 := o.e0[idx], o.e1[idx], o.e2[idx] // interpolation functions and gradients err = rodH.CalcAtIp(o.Rod.X, ip, true) if err != nil { return } // compute basis vectors J := rodH.J π[0] = Jvec[0] + α π[1] = Jvec[1] e0[0] = Jvec[0] / J e0[1] = Jvec[1] / J if o.Ndim == 3 { π[2] = Jvec[2] e0[2] = Jvec[2] / J } la.MatSetDiag(Q, 1) la.VecOuterAdd(Q, -1, e0, e0) // Q := I - e0 dyad e0 la.MatVecMul(e1, 1, Q, π) // Eq. (29) * norm(E1) la.VecScale(e1, 0, 1.0/la.VecNorm(e1), e1) if o.Ndim == 3 { e2[0] = e0[1]*e1[2] - e0[2]*e1[1] e2[1] = e0[2]*e1[0] - e0[0]*e1[2] e2[2] = e0[0]*e1[1] - e0[1]*e1[0] } // compute auxiliary tensors if o.Coulomb { e1_dy_e1 := tsr.Alloc2() e2_dy_e2 := tsr.Alloc2() for i := 0; i < o.Ndim; i++ { for j := 0; j < o.Ndim; j++ { e1_dy_e1[i][j] = e1[i] * e1[j] e2_dy_e2[i][j] = e2[i] * e2[j] } } } } // auxiliary variables o.ΔuC = la.MatAlloc(rodNn, o.Ndim) o.Δw = make([]float64, o.Ndim) o.qb = make([]float64, o.Ndim) o.fC = make([]float64, rodNu) // temporary Jacobian matrices. see Eq. (57) o.Krr = la.MatAlloc(rodNu, rodNu) o.Krs = la.MatAlloc(rodNu, sldNu) o.Ksr = la.MatAlloc(sldNu, rodNu) o.Kss = la.MatAlloc(sldNu, sldNu) // debugging //if true { if false { o.debug_print_init() } // success return o.Ny * o.Ny, nil }