Exemple #1
0
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))
}
Exemple #2
0
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")
	}
}
Exemple #3
0
// 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
}
Exemple #4
0
// 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
}
Exemple #5
0
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_)
}
Exemple #6
0
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)
}
Exemple #7
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)
}
Exemple #8
0
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)
}
Exemple #9
0
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)
		}
	}
}
Exemple #10
0
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) },
		)
	}
}
Exemple #11
0
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) },
		)
	}
}
Exemple #12
0
// 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
}