// Extrapolator computes the extrapolation matrix for this Shape with a combination of integration points 'ips' // Note: E[nverts][nip] must be pre-allocated func (o *Shape) Extrapolator(E [][]float64, ips []*Ipoint) (err error) { la.MatFill(E, 0) nip := len(ips) N := o.GetShapeMatAtIps(ips) if nip < o.Nverts { ξ := o.GetNodesNatCoordsMat() ξh := o.GetIpsNatCoordsMat(ips) ξhi := la.MatAlloc(o.Gndim+1, nip) Ni := la.MatAlloc(o.Nverts, nip) err = la.MatInvG(Ni, N, 1e-10) if err != nil { return } err = la.MatInvG(ξhi, ξh, 1e-10) if err != nil { return } ξhξhI := la.MatAlloc(nip, nip) // ξh * inv(ξh) for k := 0; k < o.Gndim+1; k++ { for j := 0; j < nip; j++ { for i := 0; i < nip; i++ { ξhξhI[i][j] += ξh[i][k] * ξhi[k][j] } for i := 0; i < o.Nverts; i++ { E[i][j] += ξ[i][k] * ξhi[k][j] // ξ * inv(ξh) } } } for i := 0; i < o.Nverts; i++ { for j := 0; j < nip; j++ { for k := 0; k < nip; k++ { I_kj := 0.0 if j == k { I_kj = 1.0 } E[i][j] += Ni[i][k] * (I_kj - ξhξhI[k][j]) } } } } else { err = la.MatInvG(E, N, 1e-10) if err != nil { return } } return }
// CalcD computes algorithmic tangent operator func (o *PrincStrainsUp) CalcD(D [][]float64, s *State) (err error) { // elastic response if !s.Loading { o.Mdl.ElastD(D, s) return } // eigenvalues/projectors of trial elastic strain err = tsr.M_EigenValsProjsNum(o.P, o.Lεetr, s.EpsTr) if err != nil { return } // derivatives of eigenprojectors w.r.t trial elastic strains err = tsr.M_EigenProjsDerivAuto(o.dPdT, s.EpsTr, o.Lεetr, o.P) if err != nil { io.Pforan("EpsTr = %v\n", s.EpsTr) io.Pforan("Lεetr = %v\n", o.Lεetr) la.PrintMat("P", o.P, "%10g", false) return } // eigenvalues of strains err = tsr.M_EigenValsNum(o.Lεe, s.EpsE) if err != nil { return } // compute Lσ, De and Jacobian o.Mdl.E_CalcSig(o.Lσ, o.Lεe) err = o.Mdl.L_SecondDerivs(o.N, o.Nb, o.A, o.h, o.Mb, o.a, o.b, o.c, o.Lσ, s.Alp) if err != nil { return err } o.Mdl.E_CalcDe(o.De, o.Lεe) o.calcJafterDerivs(o.J, o.Lεe, s.Alp, s.Dgam) // invert Jacobian => Ji err = la.MatInvG(o.Ji, o.J, 1e-10) if err != nil { return } // compute De and Dt = De * Ji for i := 0; i < 3; i++ { for j := 0; j < 3; j++ { o.Dt[i][j] = 0 for k := 0; k < 3; k++ { o.Dt[i][j] += o.De[i][k] * o.Ji[k][j] } } } // compute D for i := 0; i < o.Nsig; i++ { for j := 0; j < o.Nsig; j++ { D[i][j] = 0.0 for k := 0; k < 3; k++ { for l := 0; l < 3; l++ { D[i][j] += o.Dt[k][l] * o.P[k][i] * o.P[l][j] } D[i][j] += o.Lσ[k] * o.dPdT[k][i][j] } } } return }
// Solve solves non-linear problem f(x) == 0 func (o *NlSolver) Solve(x []float64, silent bool) (err error) { // compute scaling vector la.VecScaleAbs(o.scal, o.atol, o.rtol, x) // scal := Atol + Rtol*abs(x) // evaluate function @ x err = o.Ffcn(o.fx, x) // fx := f(x) o.NFeval, o.NJeval = 1, 0 if err != nil { return } // show message if !silent { o.msg("", 0, 0, 0, true, false) } // iterations var Ldx, Ldx_prev, Θ float64 // RMS norm of delta x, convergence rate var fx_max float64 var nfv int for o.It = 0; o.It < o.MaxIt; o.It++ { // check convergence on f(x) fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0 if fx_max < o.ftol { if !silent { o.msg("fx_max(ini)", o.It, Ldx, fx_max, false, true) } break } // show message if !silent { o.msg("", o.It, Ldx, fx_max, false, false) } // output if o.Out != nil { o.Out(x) } // evaluate Jacobian @ x if o.It == 0 || !o.CteJac { if o.useDn { err = o.JfcnDn(o.J, x) } else { if o.numJ { err = Jacobian(&o.Jtri, o.Ffcn, x, o.fx, o.w, false) o.NFeval += o.neq } else { err = o.JfcnSp(&o.Jtri, x) } } o.NJeval += 1 if err != nil { return } } // dense solution if o.useDn { // invert matrix err = la.MatInvG(o.Ji, o.J, 1e-10) if err != nil { return chk.Err(_nls_err1, err.Error()) } // solve linear system (compute mdx) and compute lin-search data o.φ = 0.0 for i := 0; i < o.neq; i++ { o.mdx[i], o.dφdx[i] = 0.0, 0.0 for j := 0; j < o.neq; j++ { o.mdx[i] += o.Ji[i][j] * o.fx[j] // mdx = inv(J) * fx o.dφdx[i] += o.J[j][i] * o.fx[j] // dφdx = tra(J) * fx } o.φ += o.fx[i] * o.fx[i] } o.φ *= 0.5 // sparse solution } else { // init sparse solver if o.It == 0 { symmetric, verbose, timing := false, false, false err := o.lis.InitR(&o.Jtri, symmetric, verbose, timing) if err != nil { return chk.Err(_nls_err9, err.Error()) } } // factorisation (must be done for all iterations) o.lis.Fact() // solve linear system => compute mdx o.lis.SolveR(o.mdx, o.fx, false) // mdx = inv(J) * fx false => !sumToRoot // compute lin-search data if o.Lsearch { o.φ = 0.5 * la.VecDot(o.fx, o.fx) la.SpTriMatTrVecMul(o.dφdx, &o.Jtri, o.fx) // dφdx := transpose(J) * fx } } //io.Pforan("φ = %v\n", o.φ) //io.Pforan("dφdx = %v\n", o.dφdx) // update x Ldx = 0.0 for i := 0; i < o.neq; i++ { o.x0[i] = x[i] x[i] -= o.mdx[i] Ldx += (o.mdx[i] / o.scal[i]) * (o.mdx[i] / o.scal[i]) } Ldx = math.Sqrt(Ldx / float64(o.neq)) // calculate fx := f(x) @ update x err = o.Ffcn(o.fx, x) o.NFeval += 1 if err != nil { return } // check convergence on f(x) => avoid line-search if converged already fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0 if fx_max < o.ftol { if !silent { o.msg("fx_max", o.It, Ldx, fx_max, false, true) } break } // check convergence on Ldx if Ldx < o.fnewt { if !silent { o.msg("Ldx", o.It, Ldx, fx_max, false, true) } break } // call line-search => update x and fx if o.Lsearch { nfv, err = LineSearch(x, o.fx, o.Ffcn, o.mdx, o.x0, o.dφdx, o.φ, o.LsMaxIt, true) o.NFeval += nfv if err != nil { return chk.Err(_nls_err2, err.Error()) } Ldx = 0.0 for i := 0; i < o.neq; i++ { Ldx += ((x[i] - o.x0[i]) / o.scal[i]) * ((x[i] - o.x0[i]) / o.scal[i]) } Ldx = math.Sqrt(Ldx / float64(o.neq)) fx_max = la.VecLargest(o.fx, 1.0) // den = 1.0 if Ldx < o.fnewt { if !silent { o.msg("Ldx(linsrch)", o.It, Ldx, fx_max, false, true) } break } } // check convergence rate if o.It > 0 && o.ChkConv { Θ = Ldx / Ldx_prev if Θ > 0.99 { return chk.Err(_nls_err3, Θ, Ldx, Ldx_prev) } } Ldx_prev = Ldx } // output if o.Out != nil { o.Out(x) } // check convergence if o.It == o.MaxIt { err = chk.Err(_nls_err4, o.It) } return }