// CalcAtIp calculates volume data such as S and G at natural coordinate r // Input: // x[ndim][nverts+?] -- coordinates matrix of solid element // ip -- integration point // Output: // S, DSdR, DxdR, DRdx, G, and J func (o *Shape) CalcAtIp(x [][]float64, ip *Ipoint, derivs bool) (err error) { // S and dSdR o.Func(o.S, o.dSdR, ip.R, ip.S, ip.T, derivs) if !derivs { return } if o.Gndim == 1 { // calculate Jvec3d == dxdR for i := 0; i < len(x); i++ { o.Jvec3d[i] = 0.0 for m := 0; m < o.Nverts; m++ { o.Jvec3d[i] += x[i][m] * o.dSdR[m][0] // dxdR := x * dSdR } } // calculate J = norm of Jvec3d o.J = la.VecNorm(o.Jvec3d) // calculate G for m := 0; m < o.Nverts; m++ { o.Gvec[m] = o.dSdR[m][0] / o.J } return } // dxdR := sum_n x * dSdR => dx_i/dR_j := sum_n x^n_i * dS^n/dR_j for i := 0; i < len(x); i++ { for j := 0; j < o.Gndim; j++ { o.dxdR[i][j] = 0.0 for n := 0; n < o.Nverts; n++ { o.dxdR[i][j] += x[i][n] * o.dSdR[n][j] } } } // dRdx := inv(dxdR) o.J, err = la.MatInv(o.dRdx, o.dxdR, MINDET) if err != nil { return } // G == dSdx := dSdR * dRdx => dS^m/dR_i := sum_i dS^m/dR_i * dR_i/dx_j la.MatMul(o.G, 1, o.dSdR, o.dRdx) return }
// InvMap computes the natural coordinates r, given the real coordinate y // Input: // y[ndim] -- are the 2D/3D point coordinates // x[ndim][nverts+?] -- coordinates matrix of solid element // Output: // r[3] -- are the natural coordinates of given point func (o *Shape) InvMap(r, y []float64, x [][]float64) (err error) { // check if o.Gndim == 1 { return chk.Err("Inverse mapping is not implemented in 1D\n") } var δRnorm float64 e := make([]float64, o.Gndim) // residual δr := make([]float64, o.Gndim) // corrector r[0], r[1], r[2] = 0, 0, 0 // first trial it := 0 derivs := true for it = 0; it < INVMAP_NIT; it++ { // shape functions and derivatives o.Func(o.S, o.dSdR, r[0], r[1], r[2], derivs) // residual: e = y - x * S for i := 0; i < o.Gndim; i++ { e[i] = y[i] for j := 0; j < o.Nverts; j++ { e[i] -= x[i][j] * o.S[j] } } // Jmat == dxdR = x * dSdR; for i := 0; i < len(x); i++ { for j := 0; j < o.Gndim; j++ { o.dxdR[i][j] = 0.0 for k := 0; k < o.Nverts; k++ { o.dxdR[i][j] += x[i][k] * o.dSdR[k][j] // dxdR := x * dSdR } } } // Jimat == dRdx = Jmat.inverse(); o.J, err = la.MatInv(o.dRdx, o.dxdR, MINDET) if err != nil { return } // corrector: dR = Jimat * e for i := 0; i < o.Gndim; i++ { δr[i] = 0.0 for j := 0; j < o.Gndim; j++ { δr[i] += o.dRdx[i][j] * e[j] } } // converged? δRnorm = 0.0 for i := 0; i < o.Gndim; i++ { r[i] += δr[i] δRnorm += δr[i] * δr[i] // fix r outside range if r[i] < -1.0 || r[i] > 1.0 { if math.Abs(r[i]-(-1.0)) < INVMAP_TOL { r[i] = -1.0 } if math.Abs(r[i]-1.0) < INVMAP_TOL { r[i] = 1.0 } } } if math.Sqrt(δRnorm) < INVMAP_TOL { break } } // check if it == INVMAP_NIT { return } return }