// AddToKb adds element K to global Jacobian matrix Kb func (o *ElastRod) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (err error) { for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return }
/* Jacobian ======== Calculates (with N=n-1): df0dx0, df0dx1, df0dx2, ... df0dxN df1dx0, df1dx1, df1dx2, ... df1dxN . . . . . . . . . . . . . dfNdx0, dfNdx1, dfNdx2, ... dfNdxN INPUT: ffcn : f(x) function x : station where dfdx has to be calculated fx : f @ x w : workspace with size == n == len(x) RETURNS: J : dfdx @ x [must be pre-allocated] */ func Jacobian(J *la.Triplet, ffcn Cb_f, x, fx, w []float64, distr bool) (err error) { ndim := len(x) start, endp1 := 0, ndim if distr { id, sz := mpi.Rank(), mpi.Size() start, endp1 = (id*ndim)/sz, ((id+1)*ndim)/sz if J.Max() == 0 { J.Init(ndim, ndim, (endp1-start)*ndim) } } else { if J.Max() == 0 { J.Init(ndim, ndim, ndim*ndim) } } J.Start() // NOTE: cannot split calculation by columns unless the f function is // independently calculated by each MPI processor. // Otherwise, the AllReduce in f calculation would // join pieces of f from different processors calculated for // different x values (δx[col] from different columns). /* for col := start; col < endp1; col++ { xsafe := x[col] delta := math.Sqrt(EPS * max(CTE1, math.Abs(xsafe))) x[col] = xsafe + delta ffcn(w, x) // fnew io.Pforan("x = %v, f = %v\n", x, w) for row := 0; row < ndim; row++ { J.Put(row, col, (w[row]-fx[row])/delta) } x[col] = xsafe } */ var df float64 for col := 0; col < ndim; col++ { xsafe := x[col] delta := math.Sqrt(EPS * max(CTE1, math.Abs(xsafe))) x[col] = xsafe + delta err = ffcn(w, x) // w := f(x+δx[col]) if err != nil { return } for row := start; row < endp1; row++ { df = w[row] - fx[row] //if math.Abs(df) > EPS { J.Put(row, col, df/delta) //} } x[col] = xsafe } return }
// AddToKb adds element K to global Jacobian matrix Kb func (o *Rod) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (err error) { // zero K matrix la.MatFill(o.K, 0) la.MatFill(o.M, 0) // TODO: implement mass matrix // for each integration point var E float64 nverts := o.Cell.Shp.Nverts for idx, ip := range o.IpsElem { // interpolation functions, gradients and variables @ ip err = o.ipvars(idx, sol) if err != nil { return } // auxiliary coef := ip[3] Jvec := o.Cell.Shp.Jvec3d G := o.Cell.Shp.Gvec J := o.Cell.Shp.J // add contribution to consistent tangent matrix for m := 0; m < nverts; m++ { for n := 0; n < nverts; n++ { for i := 0; i < o.Ndim; i++ { for j := 0; j < o.Ndim; j++ { r := i + m*o.Ndim c := j + n*o.Ndim E, err = o.Model.CalcD(o.States[idx], firstIt) if err != nil { return } o.K[r][c] += coef * o.A * E * G[m] * G[n] * Jvec[i] * Jvec[j] / J } } } } } // add K to sparse matrix Kb for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() if mpi.Rank() == 0 { chk.PrintTitle("Test SumToRoot 01") } M := [][]float64{ {1000, 1000, 1000, 1011, 1021, 1000}, {1000, 1000, 1000, 1012, 1022, 1000}, {1000, 1000, 1000, 1013, 1023, 1000}, {1011, 1012, 1013, 1000, 1000, 1000}, {1021, 1022, 1023, 1000, 1000, 1000}, {1000, 1000, 1000, 1000, 1000, 1000}, } id, sz, m := mpi.Rank(), mpi.Size(), len(M) start, endp1 := (id*m)/sz, ((id+1)*m)/sz if sz > 6 { chk.Panic("this test works with at most 6 processors") } var J la.Triplet J.Init(m, m, m*m) for i := start; i < endp1; i++ { for j := 0; j < m; j++ { J.Put(i, j, M[i][j]) } } la.PrintMat(fmt.Sprintf("J @ proc # %d", id), J.ToMatrix(nil).ToDense(), "%10.1f", false) la.SpTriSumToRoot(&J) var tst testing.T if mpi.Rank() == 0 { chk.Matrix(&tst, "J @ proc 0", 1.0e-17, J.ToMatrix(nil).ToDense(), [][]float64{ {1000, 1000, 1000, 1011, 1021, 1000}, {1000, 1000, 1000, 1012, 1022, 1000}, {1000, 1000, 1000, 1013, 1023, 1000}, {1011, 1012, 1013, 1000, 1000, 1000}, {1021, 1022, 1023, 1000, 1000, 1000}, {1000, 1000, 1000, 1000, 1000, 1000}, }) } }
// adds element K to global Jacobian matrix Kb func (o Rod) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (ok bool) { // zero K matrix la.MatFill(o.K, 0) la.MatFill(o.M, 0) // for each integration point nverts := o.Shp.Nverts ndim := Global.Ndim for idx, ip := range o.IpsElem { // interpolation functions, gradients and variables @ ip if !o.ipvars(idx, sol) { return } // auxiliary coef := ip.W Jvec := o.Shp.Jvec3d G := o.Shp.Gvec J := o.Shp.J // add contribution to consistent tangent matrix for m := 0; m < nverts; m++ { for n := 0; n < nverts; n++ { for i := 0; i < ndim; i++ { for j := 0; j < ndim; j++ { r := i + m*ndim c := j + n*ndim E, err := o.Model.CalcD(o.States[idx], firstIt) if LogErr(err, "AddToKb") { return } o.K[r][c] += coef * o.A * E * G[m] * G[n] * Jvec[i] * Jvec[j] / J } } } } } // add K to sparse matrix Kb for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return true }
// adds element K to global Jacobian matrix Kb func (o Beam) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (ok bool) { if Global.Sim.Data.Steady { for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } } else { dc := Global.DynCoefs for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.M[i][j]*dc.α1+o.K[i][j]) } } } return true }
// adds element K to global Jacobian matrix Kb func (o *Beam) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (err error) { if sol.Steady { for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return } α1 := sol.DynCfs.α1 for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.M[i][j]*α1+o.K[i][j]) } } return }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() myrank := mpi.Rank() if myrank == 0 { chk.PrintTitle("Test MUMPS Sol 02") } ndim := 10 id, sz := mpi.Rank(), mpi.Size() start, endp1 := (id*ndim)/sz, ((id+1)*ndim)/sz if mpi.Size() > ndim { chk.Panic("the number of processors must be smaller than or equal to %d", ndim) } b := make([]float64, ndim) var t la.Triplet t.Init(ndim, ndim, ndim*ndim) for i := start; i < endp1; i++ { j := i if i > 0 { j = i - 1 } for ; j < ndim; j++ { val := 10.0 - float64(j) if i > j { val -= 1.0 } t.Put(i, j, val) } b[i] = float64(i + 1) } x_correct := []float64{-1, 8, -65, 454, -2725, 13624, -54497, 163490, -326981, 326991} sum_b_to_root := true la.RunMumpsTestR(&t, 1e-4, b, x_correct, sum_b_to_root) }
// AddToKb adds element K to global Jacobian matrix Kb func (o *ElemPhi) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (err error) { // auxiliary nverts := o.Cell.Shp.Nverts // zero K matrix la.MatFill(o.K, 0) dt := sol.Dt * 2 // for each integration point for iip, ip := range o.IpsElem { // interpolation functions and gradients err = o.Cell.Shp.CalcAtIp(o.X, ip, true) if err != nil { return } // auxiliary variables coef := o.Cell.Shp.J * ip[3] S := o.Cell.Shp.S G := o.Cell.Shp.G // add to right hand side vector for m := 0; m < nverts; m++ { for n := 0; n < nverts; n++ { o.K[m][n] -= coef * (S[m]*S[n] + dt*dt/6.0*(o.v_0[iip][0]*G[m][0]+o.v_0[iip][1]*G[m][1])*(o.v_0[iip][0]*G[n][0]+o.v_0[iip][1]*G[n][1])) / dt } } } // add K to sparse matrix Kb for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return }
func Assemble(K11, K12 *la.Triplet, F1 []float64, src Cb_src, g *Grid2D, e *Equations) { K11.Start() K12.Start() la.VecFill(F1, 0.0) kx, ky := 1.0, 1.0 alp, bet, gam := 2.0*(kx/g.Dxx+ky/g.Dyy), -kx/g.Dxx, -ky/g.Dyy mol := []float64{alp, bet, bet, gam, gam} for i, I := range e.RF1 { col, row := I%g.Nx, I/g.Nx nodes := []int{I, I - 1, I + 1, I - g.Nx, I + g.Nx} // I, left, right, bottom, top if col == 0 { nodes[1] = nodes[2] } if col == g.Nx-1 { nodes[2] = nodes[1] } if row == 0 { nodes[3] = nodes[4] } if row == g.Ny-1 { nodes[4] = nodes[3] } for k, J := range nodes { j1, j2 := e.FR1[J], e.FR2[J] // 1 or 2? if j1 > -1 { // 11 K11.Put(i, j1, mol[k]) } else { // 12 K12.Put(i, j2, mol[k]) } } if src != nil { x := float64(col) * g.Dx y := float64(row) * g.Dy F1[i] += src(x, y) } } }
// AddToKb adds element K to global Jacobian matrix Kb func (o *ElemPhi) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (ok bool) { // auxiliary β1 := Global.DynCoefs.β1 nverts := o.Shp.Nverts // zero K matrix la.MatFill(o.K, 0) // for each integration point for _, ip := range o.IpsElem { // interpolation functions and gradients if LogErr(o.Shp.CalcAtIp(o.X, ip, true), "InterpStarVars") { return } // auxiliary variables coef := o.Shp.J * ip.W S := o.Shp.S // add to right hand side vector for m := 0; m < nverts; m++ { for n := 0; n < nverts; n++ { o.K[m][n] += coef * S[m] * S[n] * β1 } } } // add K to sparse matrix Kb for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return true }
// Jacobian computes Jacobian (sparse) matrix // Calculates (with N=n-1): // df0dx0, df0dx1, df0dx2, ... df0dxN // df1dx0, df1dx1, df1dx2, ... df1dxN // . . . . . . . . . . . . . // dfNdx0, dfNdx1, dfNdx2, ... dfNdxN // INPUT: // ffcn : f(x) function // x : station where dfdx has to be calculated // fx : f @ x // w : workspace with size == n == len(x) // RETURNS: // J : dfdx @ x [must be pre-allocated] func Jacobian(J *la.Triplet, ffcn Cb_f, x, fx, w []float64) (err error) { ndim := len(x) start, endp1 := 0, ndim if J.Max() == 0 { J.Init(ndim, ndim, ndim*ndim) } J.Start() var df float64 for col := 0; col < ndim; col++ { xsafe := x[col] delta := math.Sqrt(EPS * max(CTE1, math.Abs(xsafe))) x[col] = xsafe + delta err = ffcn(w, x) // w := f(x+δx[col]) if err != nil { return } for row := start; row < endp1; row++ { df = w[row] - fx[row] J.Put(row, col, df/delta) } x[col] = xsafe } return }
func IpBmatrix_sparse(B *la.Triplet, ndim, nne int, G [][]float64, radius float64, S []float64, axisym bool) { B.Start() if ndim == 3 { for i := 0; i < nne; i++ { B.Put(0, 0+i*3, G[i][0]) B.Put(1, 1+i*3, G[i][1]) B.Put(2, 2+i*3, G[i][2]) B.Put(3, 0+i*3, G[i][1]/SQ2) B.Put(4, 1+i*3, G[i][2]/SQ2) B.Put(5, 2+i*3, G[i][0]/SQ2) B.Put(3, 1+i*3, G[i][0]/SQ2) B.Put(4, 2+i*3, G[i][1]/SQ2) B.Put(5, 0+i*3, G[i][2]/SQ2) } return } if axisym { for i := 0; i < nne; i++ { B.Put(0, 0+i*2, G[i][0]) B.Put(1, 1+i*2, G[i][1]) B.Put(2, 0+i*2, S[i]/radius) B.Put(3, 0+i*2, G[i][1]/SQ2) B.Put(3, 1+i*2, G[i][0]/SQ2) } return } for i := 0; i < nne; i++ { B.Put(0, 0+i*2, G[i][0]) B.Put(1, 1+i*2, G[i][1]) B.Put(3, 0+i*2, G[i][1]/SQ2) B.Put(3, 1+i*2, G[i][0]/SQ2) } }
func main() { // input matrix in Triplet format // including repeated positions. e.g. (0,0) var A la.Triplet A.Init(5, 5, 13) A.Put(0, 0, 1.0) // << repeated A.Put(0, 0, 1.0) // << repeated A.Put(1, 0, 3.0) A.Put(0, 1, 3.0) A.Put(2, 1, -1.0) A.Put(4, 1, 4.0) A.Put(1, 2, 4.0) A.Put(2, 2, -3.0) A.Put(3, 2, 1.0) A.Put(4, 2, 2.0) A.Put(2, 3, 2.0) A.Put(1, 4, 6.0) A.Put(4, 4, 1.0) // right-hand-side b := []float64{8.0, 45.0, -3.0, 3.0, 19.0} // solve x, err := la.SolveRealLinSys(&A, b) if err != nil { io.Pfred("solver failed:\n%v", err) return } // output la.PrintMat("a", A.ToMatrix(nil).ToDense(), "%5g", false) la.PrintVec("b", b, "%v ", false) la.PrintVec("x", x, "%v ", false) }
func main() { // input matrix in Triplet format // including repeated positions. e.g. (0,0) var A la.Triplet A.Init(5, 5, 13) A.Put(0, 0, 1.0) // << repeated A.Put(0, 0, 1.0) // << repeated A.Put(1, 0, 3.0) A.Put(0, 1, 3.0) A.Put(2, 1, -1.0) A.Put(4, 1, 4.0) A.Put(1, 2, 4.0) A.Put(2, 2, -3.0) A.Put(3, 2, 1.0) A.Put(4, 2, 2.0) A.Put(2, 3, 2.0) A.Put(1, 4, 6.0) A.Put(4, 4, 1.0) // right-hand-side b := []float64{8.0, 45.0, -3.0, 3.0, 19.0} // allocate solver lis := la.GetSolver("umfpack") defer lis.Clean() // info symmetric := false verbose := false timing := false // initialise solver (R)eal err := lis.InitR(&A, symmetric, verbose, timing) if err != nil { io.Pfred("solver failed:\n%v", err) return } // factorise err = lis.Fact() if err != nil { io.Pfred("solver failed:\n%v", err) return } // solve (R)eal var dummy bool x := make([]float64, len(b)) err = lis.SolveR(x, b, dummy) // x := inv(a) * b if err != nil { io.Pfred("solver failed:\n%v", err) return } // output la.PrintMat("a", A.ToMatrix(nil).ToDense(), "%5g", false) la.PrintVec("b", b, "%v ", false) la.PrintVec("x", x, "%v ", false) }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() if mpi.Rank() == 0 { chk.PrintTitle("Test ODE 04b (MPI)") io.Pfcyan("Hairer-Wanner VII-p376 Transistor Amplifier (MPI)\n") io.Pfcyan("(from E Hairer's website, not the system in the book)\n") } if mpi.Size() != 3 { chk.Panic(">> error: this test requires 3 MPI processors\n") return } // RIGHT-HAND SIDE OF THE AMPLIFIER PROBLEM w := make([]float64, 8) // workspace fcn := func(f []float64, x float64, y []float64, args ...interface{}) error { d := args[0].(*HWtransData) UET := d.UE * math.Sin(d.W*x) FAC1 := d.BETA * (math.Exp((y[3]-y[2])/d.UF) - 1.0) FAC2 := d.BETA * (math.Exp((y[6]-y[5])/d.UF) - 1.0) la.VecFill(f, 0) switch mpi.Rank() { case 0: f[0] = y[0] / d.R9 case 1: f[1] = (y[1]-d.UB)/d.R8 + d.ALPHA*FAC1 f[2] = y[2]/d.R7 - FAC1 case 2: f[3] = y[3]/d.R5 + (y[3]-d.UB)/d.R6 + (1.0-d.ALPHA)*FAC1 f[4] = (y[4]-d.UB)/d.R4 + d.ALPHA*FAC2 f[5] = y[5]/d.R3 - FAC2 f[6] = y[6]/d.R1 + (y[6]-d.UB)/d.R2 + (1.0-d.ALPHA)*FAC2 f[7] = (y[7] - UET) / d.R0 } mpi.AllReduceSum(f, w) return nil } // JACOBIAN OF THE AMPLIFIER PROBLEM jac := func(dfdy *la.Triplet, x float64, y []float64, args ...interface{}) error { d := args[0].(*HWtransData) FAC14 := d.BETA * math.Exp((y[3]-y[2])/d.UF) / d.UF FAC27 := d.BETA * math.Exp((y[6]-y[5])/d.UF) / d.UF if dfdy.Max() == 0 { dfdy.Init(8, 8, 16) } NU := 2 dfdy.Start() switch mpi.Rank() { case 0: dfdy.Put(2+0-NU, 0, 1.0/d.R9) dfdy.Put(2+1-NU, 1, 1.0/d.R8) dfdy.Put(1+2-NU, 2, -d.ALPHA*FAC14) dfdy.Put(0+3-NU, 3, d.ALPHA*FAC14) dfdy.Put(2+2-NU, 2, 1.0/d.R7+FAC14) case 1: dfdy.Put(1+3-NU, 3, -FAC14) dfdy.Put(2+3-NU, 3, 1.0/d.R5+1.0/d.R6+(1.0-d.ALPHA)*FAC14) dfdy.Put(3+2-NU, 2, -(1.0-d.ALPHA)*FAC14) dfdy.Put(2+4-NU, 4, 1.0/d.R4) dfdy.Put(1+5-NU, 5, -d.ALPHA*FAC27) case 2: dfdy.Put(0+6-NU, 6, d.ALPHA*FAC27) dfdy.Put(2+5-NU, 5, 1.0/d.R3+FAC27) dfdy.Put(1+6-NU, 6, -FAC27) dfdy.Put(2+6-NU, 6, 1.0/d.R1+1.0/d.R2+(1.0-d.ALPHA)*FAC27) dfdy.Put(3+5-NU, 5, -(1.0-d.ALPHA)*FAC27) dfdy.Put(2+7-NU, 7, 1.0/d.R0) } return nil } // MATRIX "M" c1, c2, c3, c4, c5 := 1.0e-6, 2.0e-6, 3.0e-6, 4.0e-6, 5.0e-6 var M la.Triplet M.Init(8, 8, 14) M.Start() NU := 1 switch mpi.Rank() { case 0: M.Put(1+0-NU, 0, -c5) M.Put(0+1-NU, 1, c5) M.Put(2+0-NU, 0, c5) M.Put(1+1-NU, 1, -c5) M.Put(1+2-NU, 2, -c4) M.Put(1+3-NU, 3, -c3) case 1: M.Put(0+4-NU, 4, c3) M.Put(2+3-NU, 3, c3) M.Put(1+4-NU, 4, -c3) case 2: M.Put(1+5-NU, 5, -c2) M.Put(1+6-NU, 6, -c1) M.Put(0+7-NU, 7, c1) M.Put(2+6-NU, 6, c1) M.Put(1+7-NU, 7, -c1) } // WRITE FILE FUNCTION idxstp := 1 var b bytes.Buffer out := func(first bool, dx, x float64, y []float64, args ...interface{}) error { if mpi.Rank() == 0 { if first { fmt.Fprintf(&b, "%6s%23s%23s%23s%23s%23s%23s%23s%23s%23s\n", "ns", "x", "y0", "y1", "y2", "y3", "y4", "y5", "y6", "y7") } fmt.Fprintf(&b, "%6d%23.15E", idxstp, x) for j := 0; j < len(y); j++ { fmt.Fprintf(&b, "%23.15E", y[j]) } fmt.Fprintf(&b, "\n") idxstp += 1 } return nil } defer func() { if mpi.Rank() == 0 { io.WriteFileD("/tmp/gosl", "hwamplifierB.res", &b) } }() // INITIAL DATA D, xa, xb, ya := HWtransIni() // SET ODE SOLVER silent := false fixstp := false //method := "Dopri5" method := "Radau5" ndim := len(ya) //numjac := true numjac := false var osol ode.ODE osol.Pll = true if numjac { osol.Init(method, ndim, fcn, nil, &M, out, silent) } else { osol.Init(method, ndim, fcn, jac, &M, out, silent) } osol.IniH = 1.0e-6 // initial step size // SET TOLERANCES atol, rtol := 1e-11, 1e-5 osol.SetTol(atol, rtol) // RUN t0 := time.Now() if fixstp { osol.Solve(ya, xa, xb, 0.01, fixstp, &D) } else { osol.Solve(ya, xa, xb, xb-xa, fixstp, &D) } if mpi.Rank() == 0 { io.Pfmag("elapsed time = %v\n", time.Now().Sub(t0)) } }
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) }, ) } }
// contact_add_to_jac adds coupled equations due to contact modelling to Jacobian func (o *ElemU) contact_add_to_jac(Kb *la.Triplet, sol *Solution) (err error) { // clear matrices for i := 0; i < o.Nq; i++ { for j := 0; j < o.Nq; j++ { o.Kqq[i][j] = 0 } for j := 0; j < o.Nu; j++ { o.Kqu[i][j] = 0 o.Kuq[j][i] = 0 } } // compute surface integral var qb, db, Hb float64 dddu := make([]float64, o.Ndim) for _, nbc := range o.NatBcs { // loop over ips of face for _, ipf := range o.IpsFace { // contact switch nbc.Key { case "contact": // interpolation functions and gradients @ face iface := nbc.IdxFace err = o.Cell.Shp.CalcAtFaceIp(o.X, ipf, iface) if err != nil { return } Sf := o.Cell.Shp.Sf nvec := o.Cell.Shp.Fnvec coef := ipf[3] * o.Thickness Jf := la.VecNorm(nvec) // variables extrapolated to face qb = o.fipvars(iface, sol) xf := o.Cell.Shp.FaceIpRealCoords(o.X, ipf, iface) la.VecAdd(xf, 1, o.us) // add displacement: x = X + u db = o.contact_g(xf) o.contact_dgdx(dddu, xf) // compute derivatives Hb = o.contact_rampD1(qb + o.κ*db) for i, m := range o.Cell.Shp.FaceLocalVerts[iface] { μ := o.Vid2contactId[m] for j, n := range o.Cell.Shp.FaceLocalVerts[iface] { ν := o.Vid2contactId[n] o.Kqq[μ][ν] += coef * Jf * Sf[i] * Sf[j] * (1.0 - Hb) for k := 0; k < o.Ndim; k++ { r := k + m*o.Ndim c := k + n*o.Ndim val := coef * Sf[i] * Sf[j] * Hb * o.κ * dddu[k] * Jf o.Kuq[r][ν] += coef * Sf[i] * Sf[j] * Hb * nvec[k] o.Kqu[μ][c] -= val o.K[r][c] += val } } } } } } // add Ks to sparse matrix Kb for i, I := range o.Qmap { for j, J := range o.Qmap { Kb.Put(I, J, o.Kqq[i][j]) } for j, J := range o.Umap { Kb.Put(I, J, o.Kqu[i][j]) Kb.Put(J, I, o.Kuq[j][i]) } } for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() if mpi.Rank() == 0 { chk.PrintTitle("ode04: Hairer-Wanner VII-p376 Transistor Amplifier\n") } if mpi.Size() != 3 { chk.Panic(">> error: this test requires 3 MPI processors\n") return } // data UE, UB, UF, ALPHA, BETA := 0.1, 6.0, 0.026, 0.99, 1.0e-6 R0, R1, R2, R3, R4, R5 := 1000.0, 9000.0, 9000.0, 9000.0, 9000.0, 9000.0 R6, R7, R8, R9 := 9000.0, 9000.0, 9000.0, 9000.0 W := 2.0 * 3.141592654 * 100.0 // initial values xa := 0.0 ya := []float64{0.0, UB, UB / (R6/R5 + 1.0), UB / (R6/R5 + 1.0), UB, UB / (R2/R1 + 1.0), UB / (R2/R1 + 1.0), 0.0} // endpoint of integration xb := 0.05 //xb = 0.0123 // OK //xb = 0.01235 // !OK // right-hand side of the amplifier problem w := make([]float64, 8) // workspace fcn := func(f []float64, dx, x float64, y []float64, args ...interface{}) error { UET := UE * math.Sin(W*x) FAC1 := BETA * (math.Exp((y[3]-y[2])/UF) - 1.0) FAC2 := BETA * (math.Exp((y[6]-y[5])/UF) - 1.0) la.VecFill(f, 0) switch mpi.Rank() { case 0: f[0] = y[0] / R9 case 1: f[1] = (y[1]-UB)/R8 + ALPHA*FAC1 f[2] = y[2]/R7 - FAC1 case 2: f[3] = y[3]/R5 + (y[3]-UB)/R6 + (1.0-ALPHA)*FAC1 f[4] = (y[4]-UB)/R4 + ALPHA*FAC2 f[5] = y[5]/R3 - FAC2 f[6] = y[6]/R1 + (y[6]-UB)/R2 + (1.0-ALPHA)*FAC2 f[7] = (y[7] - UET) / R0 } mpi.AllReduceSum(f, w) return nil } // Jacobian of the amplifier problem jac := func(dfdy *la.Triplet, dx, x float64, y []float64, args ...interface{}) error { FAC14 := BETA * math.Exp((y[3]-y[2])/UF) / UF FAC27 := BETA * math.Exp((y[6]-y[5])/UF) / UF if dfdy.Max() == 0 { dfdy.Init(8, 8, 16) } NU := 2 dfdy.Start() switch mpi.Rank() { case 0: dfdy.Put(2+0-NU, 0, 1.0/R9) dfdy.Put(2+1-NU, 1, 1.0/R8) dfdy.Put(1+2-NU, 2, -ALPHA*FAC14) dfdy.Put(0+3-NU, 3, ALPHA*FAC14) dfdy.Put(2+2-NU, 2, 1.0/R7+FAC14) case 1: dfdy.Put(1+3-NU, 3, -FAC14) dfdy.Put(2+3-NU, 3, 1.0/R5+1.0/R6+(1.0-ALPHA)*FAC14) dfdy.Put(3+2-NU, 2, -(1.0-ALPHA)*FAC14) dfdy.Put(2+4-NU, 4, 1.0/R4) dfdy.Put(1+5-NU, 5, -ALPHA*FAC27) case 2: dfdy.Put(0+6-NU, 6, ALPHA*FAC27) dfdy.Put(2+5-NU, 5, 1.0/R3+FAC27) dfdy.Put(1+6-NU, 6, -FAC27) dfdy.Put(2+6-NU, 6, 1.0/R1+1.0/R2+(1.0-ALPHA)*FAC27) dfdy.Put(3+5-NU, 5, -(1.0-ALPHA)*FAC27) dfdy.Put(2+7-NU, 7, 1.0/R0) } return nil } // matrix "M" c1, c2, c3, c4, c5 := 1.0e-6, 2.0e-6, 3.0e-6, 4.0e-6, 5.0e-6 var M la.Triplet M.Init(8, 8, 14) M.Start() NU := 1 switch mpi.Rank() { case 0: M.Put(1+0-NU, 0, -c5) M.Put(0+1-NU, 1, c5) M.Put(2+0-NU, 0, c5) M.Put(1+1-NU, 1, -c5) M.Put(1+2-NU, 2, -c4) M.Put(1+3-NU, 3, -c3) case 1: M.Put(0+4-NU, 4, c3) M.Put(2+3-NU, 3, c3) M.Put(1+4-NU, 4, -c3) case 2: M.Put(1+5-NU, 5, -c2) M.Put(1+6-NU, 6, -c1) M.Put(0+7-NU, 7, c1) M.Put(2+6-NU, 6, c1) M.Put(1+7-NU, 7, -c1) } // flags silent := false fixstp := false //method := "Dopri5" method := "Radau5" ndim := len(ya) numjac := false // structure to hold numerical results res := ode.Results{Method: method} // ODE solver var osol ode.Solver osol.Pll = true // solve problem if numjac { osol.Init(method, ndim, fcn, nil, &M, ode.SimpleOutput, silent) } else { osol.Init(method, ndim, fcn, jac, &M, ode.SimpleOutput, silent) } osol.IniH = 1.0e-6 // initial step size // set tolerances atol, rtol := 1e-11, 1e-5 osol.SetTol(atol, rtol) // run t0 := time.Now() if fixstp { osol.Solve(ya, xa, xb, 0.01, fixstp, &res) } else { osol.Solve(ya, xa, xb, xb-xa, fixstp, &res) } // plot if mpi.Rank() == 0 { io.Pfmag("elapsed time = %v\n", time.Now().Sub(t0)) plt.SetForEps(2.0, 400) args := "'b-', marker='.', lw=1, clip_on=0" ode.Plot("/tmp/gosl/ode", "hwamplifier_mpi.eps", &res, nil, xa, xb, "", args, func() { _, T, err := io.ReadTable("data/radau5_hwamplifier.dat") if err != nil { chk.Panic("%v", err) } for j := 0; j < ndim; j++ { plt.Subplot(ndim+1, 1, j+1) plt.Plot(T["x"], T[io.Sf("y%d", j)], "'k+',label='reference',ms=10") } }) } }
// AddToKb adds element K to global Jacobian matrix Kb func (o ElemP) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (ok bool) { // clear matrices la.MatFill(o.Kpp, 0) ndim := Global.Ndim nverts := o.Shp.Nverts if o.DoExtrap { for i := 0; i < nverts; i++ { o.ρl_ex[i] = 0 for j := 0; j < nverts; j++ { o.dρldpl_ex[i][j] = 0 } } } // for each integration point Cl := o.Mdl.Cl β1 := Global.DynCoefs.β1 var coef, plt, klr, ρL, ρl, Cpl, dCpldpl, dklrdpl float64 for idx, ip := range o.IpsElem { // interpolation functions, gradients and variables @ ip if !o.ipvars(idx, sol) { return } coef = o.Shp.J * ip.W S := o.Shp.S G := o.Shp.G // tpm variables plt = β1*o.pl - o.ψl[idx] klr = o.Mdl.Cnd.Klr(o.States[idx].A_sl) ρL = o.States[idx].A_ρL if LogErr(o.Mdl.CalcLs(o.res, o.States[idx], o.pl, 0, true), "AddToKb") { return } ρl = o.res.A_ρl Cpl = o.res.Cpl dCpldpl = o.res.DCpldpl dklrdpl = o.res.Dklrdpl // Kpp := dRpl/dpl. see Eqs. (18), (A.2) and (A.3) of [1] for n := 0; n < nverts; n++ { for j := 0; j < ndim; j++ { o.tmp[j] = S[n]*dklrdpl*(ρL*o.g[j]-o.gpl[j]) + klr*(S[n]*Cl*o.g[j]-G[n][j]) } for m := 0; m < nverts; m++ { o.Kpp[m][n] += coef * S[m] * S[n] * (dCpldpl*plt + β1*Cpl) for i := 0; i < ndim; i++ { for j := 0; j < ndim; j++ { o.Kpp[m][n] -= coef * G[m][i] * o.Mdl.Klsat[i][j] * o.tmp[j] } } if o.DoExtrap { // inner summation term in Eq. (22) o.dρldpl_ex[m][n] += o.Emat[m][idx] * Cpl * S[n] } } if o.DoExtrap { // Eq. (19) o.ρl_ex[n] += o.Emat[n][idx] * ρl } } } // add to Kb if o.HasSeep { // contribution from natural boundary conditions if !o.add_natbcs_to_jac(sol) { return } // add to sparse matrix Kb for i, I := range o.Pmap { for j, J := range o.Pmap { Kb.Put(I, J, o.Kpp[i][j]) } for j, J := range o.Fmap { Kb.Put(I, J, o.Kpf[i][j]) Kb.Put(J, I, o.Kfp[j][i]) } } for i, I := range o.Fmap { for j, J := range o.Fmap { Kb.Put(I, J, o.Kff[i][j]) } } } else { // add to sparse matrix Kb for i, I := range o.Pmap { for j, J := range o.Pmap { Kb.Put(I, J, o.Kpp[i][j]) } } } return true }
// adds element K to global Jacobian matrix Kb func (o *Rjoint) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (err error) { // auxiliary rodH := o.Rod.Cell.Shp rodS := rodH.S rodNn := rodH.Nverts sldH := o.Sld.Cell.Shp sldNn := sldH.Nverts // zero K matrices for i, _ := range o.Rod.Umap { for j, _ := range o.Rod.Umap { o.Krr[i][j] = 0 } for j, _ := range o.Sld.Umap { o.Krs[i][j] = 0 o.Ksr[j][i] = 0 } } la.MatFill(o.Kss, 0) // auxiliary var coef float64 var DτDω float64 var Dwb0Du_nj, Dwb1Du_nj, Dwb2Du_nj float64 var DτDu_nj, DqbDu_nij float64 var Dwb0Dur_nj, Dwb1Dur_nj, Dwb2Dur_nj float64 var DqbDur_nij float64 // loop over rod's integration points 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 } coef = ip[3] * rodH.J // model derivatives DτDω, err = o.Mdl.CalcD(o.States[idx], firstIt) if err != nil { return } // compute derivatives for j := 0; j < o.Ndim; j++ { // Krr and Ksr; derivatives with respect to ur_nj for n := 0; n < rodNn; n++ { // ∂wb/∂ur Eq (A.4) Dwb0Dur_nj = -rodS[n] * e0[j] Dwb1Dur_nj = -rodS[n] * e1[j] Dwb2Dur_nj = -rodS[n] * e2[j] // compute ∂■/∂ur derivatives c := j + n*o.Ndim for i := 0; i < o.Ndim; i++ { // ∂qb/∂ur Eq (A.2) DqbDur_nij = o.h*e0[i]*(DτDω*Dwb0Dur_nj) + o.k1*e1[i]*Dwb1Dur_nj + o.k2*e2[i]*Dwb2Dur_nj // Krr := ∂fr/∂ur Eq (58) for m := 0; m < rodNn; m++ { r := i + m*o.Ndim o.Krr[r][c] -= coef * rodS[m] * DqbDur_nij } // Ksr := ∂fs/∂ur Eq (60) for m := 0; m < sldNn; m++ { r := i + m*o.Ndim for p := 0; p < rodNn; p++ { o.Ksr[r][c] += coef * o.Nmat[m][p] * rodS[p] * DqbDur_nij } } } } // Krs and Kss for n := 0; n < sldNn; n++ { // ∂wb/∂us Eq (A.5) Dwb0Du_nj, Dwb1Du_nj, Dwb2Du_nj = 0, 0, 0 for m := 0; m < rodNn; m++ { Dwb0Du_nj += rodS[m] * o.Nmat[n][m] * e0[j] Dwb1Du_nj += rodS[m] * o.Nmat[n][m] * e1[j] Dwb2Du_nj += rodS[m] * o.Nmat[n][m] * e2[j] } // ∂τ/∂us_nj hightlighted term in Eq (A.3) DτDu_nj = DτDω * Dwb0Du_nj // compute ∂■/∂us derivatives c := j + n*o.Ndim for i := 0; i < o.Ndim; i++ { // ∂qb/∂us Eq (A.3) DqbDu_nij = o.h*e0[i]*DτDu_nj + o.k1*e1[i]*Dwb1Du_nj + o.k2*e2[i]*Dwb2Du_nj // Krs := ∂fr/∂us Eq (59) for m := 0; m < rodNn; m++ { r := i + m*o.Ndim o.Krs[r][c] -= coef * rodS[m] * DqbDu_nij } // Kss := ∂fs/∂us Eq (61) for m := 0; m < sldNn; m++ { r := i + m*o.Ndim for p := 0; p < rodNn; p++ { o.Kss[r][c] += coef * o.Nmat[m][p] * rodS[p] * DqbDu_nij } } } } } } // debug //if true { if false { o.debug_print_K() } // add K to sparse matrix Kb for i, I := range o.Rod.Umap { for j, J := range o.Rod.Umap { Kb.Put(I, J, o.Krr[i][j]) } for j, J := range o.Sld.Umap { Kb.Put(I, J, o.Krs[i][j]) Kb.Put(J, I, o.Ksr[j][i]) } } for i, I := range o.Sld.Umap { for j, J := range o.Sld.Umap { Kb.Put(I, J, o.Kss[i][j]) } } return }
// adds element K to global Jacobian matrix Kb func (o ElemUP) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (ok bool) { // clear matrices ndim := Global.Ndim u_nverts := o.U.Shp.Nverts p_nverts := o.P.Shp.Nverts la.MatFill(o.P.Kpp, 0) for i := 0; i < o.U.Nu; i++ { for j := 0; j < o.P.Np; j++ { o.Kup[i][j] = 0 o.Kpu[j][i] = 0 } for j := 0; j < o.U.Nu; j++ { o.U.K[i][j] = 0 } } if o.P.DoExtrap { for i := 0; i < p_nverts; i++ { o.P.ρl_ex[i] = 0 for j := 0; j < p_nverts; j++ { o.P.dρldpl_ex[i][j] = 0 } for j := 0; j < o.U.Nu; j++ { o.dρldus_ex[i][j] = 0 } } } // for each integration point dc := Global.DynCoefs var coef, plt, klr, ρL, Cl, divvs float64 var ρl, ρ, Cpl, Cvs, dρdpl, dpdpl, dCpldpl, dCvsdpl, dklrdpl, dCpldusM, dρldusM, dρdusM float64 var r, c int for idx, ip := range o.U.IpsElem { // interpolation functions, gradients and variables @ ip if !o.ipvars(idx, sol) { return } coef = o.U.Shp.J * ip.W S := o.U.Shp.S G := o.U.Shp.G Sb := o.P.Shp.S Gb := o.P.Shp.G // axisymmetric case radius := 1.0 if Global.Sim.Data.Axisym { radius = o.U.Shp.AxisymGetRadius(o.U.X) coef *= radius } // auxiliary divvs = dc.α4*o.divus - o.U.divχs[idx] // divergence of Eq (35a) [1] // tpm variables plt = dc.β1*o.P.pl - o.P.ψl[idx] // Eq (35c) [1] klr = o.P.Mdl.Cnd.Klr(o.P.States[idx].A_sl) ρL = o.P.States[idx].A_ρL Cl = o.P.Mdl.Cl if LogErr(o.P.Mdl.CalcLs(o.P.res, o.P.States[idx], o.P.pl, o.divus, true), "AddToKb") { return } ρl = o.P.res.A_ρl ρ = o.P.res.A_ρ Cpl = o.P.res.Cpl Cvs = o.P.res.Cvs dρdpl = o.P.res.Dρdpl dpdpl = o.P.res.Dpdpl dCpldpl = o.P.res.DCpldpl dCvsdpl = o.P.res.DCvsdpl dklrdpl = o.P.res.Dklrdpl dCpldusM = o.P.res.DCpldusM dρldusM = o.P.res.DρldusM dρdusM = o.P.res.DρdusM // Kpu, Kup and Kpp for n := 0; n < p_nverts; n++ { for j := 0; j < ndim; j++ { // Kpu := ∂Rl^n/∂us^m and Kup := ∂Rus^m/∂pl^n; see Eq (47) of [1] for m := 0; m < u_nverts; m++ { c = j + m*ndim // add ∂rlb/∂us^m: Eqs (A.3) and (A.6) of [1] o.Kpu[n][c] += coef * Sb[n] * (dCpldusM*plt + dc.α4*Cvs) * G[m][j] // add ∂(ρl.wl)/∂us^m: Eq (A.8) of [1] for i := 0; i < ndim; i++ { o.Kpu[n][c] += coef * Gb[n][i] * S[m] * dc.α1 * ρL * klr * o.P.Mdl.Klsat[i][j] } // add ∂rl/∂pl^n and ∂p/∂pl^n: Eqs (A.9) and (A.11) of [1] o.Kup[c][n] += coef * (S[m]*Sb[n]*dρdpl*o.bs[j] - G[m][j]*Sb[n]*dpdpl) // for seepage face if o.P.DoExtrap { o.dρldus_ex[n][c] += o.P.Emat[n][idx] * dρldusM * G[m][j] } } // term in brackets in Eq (A.7) of [1] o.P.tmp[j] = Sb[n]*dklrdpl*o.hl[j] - klr*(Sb[n]*Cl*o.bs[j]+Gb[n][j]) } // Kpp := ∂Rl^m/∂pl^n; see Eq (47) of [1] for m := 0; m < p_nverts; m++ { // add ∂rlb/dpl^n: Eq (A.5) of [1] o.P.Kpp[m][n] += coef * Sb[m] * Sb[n] * (dCpldpl*plt + dCvsdpl*divvs + dc.β1*Cpl) // add ∂(ρl.wl)/∂us^m: Eq (A.7) of [1] for i := 0; i < ndim; i++ { for j := 0; j < ndim; j++ { o.P.Kpp[m][n] -= coef * Gb[m][i] * o.P.Mdl.Klsat[i][j] * o.P.tmp[j] } } // inner summation term in Eq (22) of [2] if o.P.DoExtrap { o.P.dρldpl_ex[m][n] += o.P.Emat[m][idx] * Cpl * Sb[n] } } // Eq. (19) of [2] if o.P.DoExtrap { o.P.ρl_ex[n] += o.P.Emat[n][idx] * ρl } } // Kuu: add ∂rub^m/∂us^n; see Eqs (47) and (A.10) of [1] for m := 0; m < u_nverts; m++ { for i := 0; i < ndim; i++ { r = i + m*ndim for n := 0; n < u_nverts; n++ { for j := 0; j < ndim; j++ { c = j + n*ndim o.U.K[r][c] += coef * S[m] * (S[n]*dc.α1*ρ*tsr.It[i][j] + dρdusM*o.bs[i]*G[n][j]) } } } } // consistent tangent model matrix if LogErr(o.U.MdlSmall.CalcD(o.U.D, o.U.States[idx], firstIt), "AddToKb") { return } // Kuu: add stiffness term ∂(σe・G^m)/∂us^n if o.U.UseB { IpBmatrix(o.U.B, ndim, u_nverts, G, radius, S) la.MatTrMulAdd3(o.U.K, coef, o.U.B, o.U.D, o.U.B) // K += coef * tr(B) * D * B } else { IpAddToKt(o.U.K, u_nverts, ndim, coef, G, o.U.D) } } // contribution from natural boundary conditions if o.P.HasSeep { if !o.P.add_natbcs_to_jac(sol) { return } if !o.add_natbcs_to_jac(sol) { return } } // add K to sparse matrix Kb // _ _ // | Kuu Kup 0 | // | Kpu Kpp Kpf | // |_ Kfu Kfp Kff _| // for i, I := range o.P.Pmap { for j, J := range o.P.Pmap { Kb.Put(I, J, o.P.Kpp[i][j]) } for j, J := range o.P.Fmap { Kb.Put(I, J, o.P.Kpf[i][j]) Kb.Put(J, I, o.P.Kfp[j][i]) } for j, J := range o.U.Umap { Kb.Put(I, J, o.Kpu[i][j]) Kb.Put(J, I, o.Kup[j][i]) } } for i, I := range o.P.Fmap { for j, J := range o.P.Fmap { Kb.Put(I, J, o.P.Kff[i][j]) } } for i, I := range o.U.Umap { for j, J := range o.U.Umap { Kb.Put(I, J, o.U.K[i][j]) } } return true }
// AddToKb adds element K to global Jacobian matrix Kb func (o *ElemU) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (ok bool) { // zero K matrix la.MatFill(o.K, 0) // for each integration point dc := Global.DynCoefs ndim := Global.Ndim nverts := o.Shp.Nverts for idx, ip := range o.IpsElem { // interpolation functions, gradients and variables @ ip if !o.ipvars(idx, sol) { return } // check Jacobian if o.Shp.J < 0 { LogErrCond(true, "ElemU: eid=%d: Jacobian is negative = %g\n", o.Id(), o.Shp.J) return } // auxiliary coef := o.Shp.J * ip.W * o.Thickness S := o.Shp.S G := o.Shp.G // consistent tangent model matrix if LogErr(o.MdlSmall.CalcD(o.D, o.States[idx], firstIt), "AddToKb") { return } // add contribution to consistent tangent matrix if o.UseB { radius := 1.0 if Global.Sim.Data.Axisym { radius = o.Shp.AxisymGetRadius(o.X) coef *= radius } IpBmatrix(o.B, ndim, nverts, G, radius, S) la.MatTrMulAdd3(o.K, coef, o.B, o.D, o.B) // K += coef * tr(B) * D * B } else { IpAddToKt(o.K, nverts, ndim, coef, G, o.D) } // dynamic term if !Global.Sim.Data.Steady { for m := 0; m < nverts; m++ { for i := 0; i < ndim; i++ { r := i + m*ndim for n := 0; n < nverts; n++ { c := i + n*ndim o.K[r][c] += coef * S[m] * S[n] * (o.Rho*dc.α1 + o.Cdam*dc.α4) } } } } } // add K to sparse matrix Kb for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } return true }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() myrank := mpi.Rank() if myrank == 0 { chk.PrintTitle("Test MUMPS Sol 01b") } var t la.Triplet b := []float64{8.0, 45.0, -3.0, 3.0, 19.0} switch mpi.Size() { case 1: t.Init(5, 5, 13) t.Put(0, 0, 1.0) t.Put(0, 0, 1.0) t.Put(1, 0, 3.0) t.Put(0, 1, 3.0) t.Put(2, 1, -1.0) t.Put(4, 1, 4.0) t.Put(1, 2, 4.0) t.Put(2, 2, -3.0) t.Put(3, 2, 1.0) t.Put(4, 2, 2.0) t.Put(2, 3, 2.0) t.Put(1, 4, 6.0) t.Put(4, 4, 1.0) case 2: la.VecFill(b, 0) if myrank == 0 { t.Init(5, 5, 8) t.Put(0, 0, 1.0) t.Put(0, 0, 1.0) t.Put(1, 0, 3.0) t.Put(0, 1, 3.0) t.Put(2, 1, -1.0) t.Put(4, 1, 1.0) t.Put(4, 1, 1.5) t.Put(4, 1, 1.5) b[0] = 8.0 b[1] = 40.0 b[2] = 1.5 } else { t.Init(5, 5, 8) t.Put(1, 2, 4.0) t.Put(2, 2, -3.0) t.Put(3, 2, 1.0) t.Put(4, 2, 2.0) t.Put(2, 3, 2.0) t.Put(1, 4, 6.0) t.Put(4, 4, 0.5) t.Put(4, 4, 0.5) b[1] = 5.0 b[2] = -4.5 b[3] = 3.0 b[4] = 19.0 } default: chk.Panic("this test needs 1 or 2 procs") } x_correct := []float64{1, 2, 3, 4, 5} sum_b_to_root := true la.RunMumpsTestR(&t, 1e-14, b, x_correct, sum_b_to_root) }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() myrank := mpi.Rank() if myrank == 0 { chk.PrintTitle("Test MUMPS Sol 01a") } var t la.Triplet switch mpi.Size() { case 1: t.Init(5, 5, 13) t.Put(0, 0, 1.0) t.Put(0, 0, 1.0) t.Put(1, 0, 3.0) t.Put(0, 1, 3.0) t.Put(2, 1, -1.0) t.Put(4, 1, 4.0) t.Put(1, 2, 4.0) t.Put(2, 2, -3.0) t.Put(3, 2, 1.0) t.Put(4, 2, 2.0) t.Put(2, 3, 2.0) t.Put(1, 4, 6.0) t.Put(4, 4, 1.0) case 2: if myrank == 0 { t.Init(5, 5, 6) t.Put(0, 0, 1.0) t.Put(0, 0, 1.0) t.Put(1, 0, 3.0) t.Put(0, 1, 3.0) t.Put(2, 1, -1.0) t.Put(4, 1, 4.0) } else { t.Init(5, 5, 7) t.Put(1, 2, 4.0) t.Put(2, 2, -3.0) t.Put(3, 2, 1.0) t.Put(4, 2, 2.0) t.Put(2, 3, 2.0) t.Put(1, 4, 6.0) t.Put(4, 4, 1.0) } default: chk.Panic("this test needs 1 or 2 procs") } b := []float64{8.0, 45.0, -3.0, 3.0, 19.0} x_correct := []float64{1, 2, 3, 4, 5} sum_b_to_root := false la.RunMumpsTestR(&t, 1e-14, b, x_correct, sum_b_to_root) }
// AddToKb adds element K to global Jacobian matrix Kb func (o *ElemU) AddToKb(Kb *la.Triplet, sol *Solution, firstIt bool) (err error) { // zero K matrix la.MatFill(o.K, 0) // for each integration point nverts := o.Cell.Shp.Nverts for idx, ip := range o.IpsElem { // interpolation functions, gradients and variables @ ip err = o.ipvars(idx, sol) if err != nil { return } // check Jacobian if o.Cell.Shp.J < 0 { return chk.Err("ElemU: eid=%d: Jacobian is negative = %g\n", o.Id(), o.Cell.Shp.J) } // auxiliary coef := o.Cell.Shp.J * ip[3] * o.Thickness S := o.Cell.Shp.S G := o.Cell.Shp.G // consistent tangent model matrix err = o.MdlSmall.CalcD(o.D, o.States[idx], firstIt) if err != nil { return } // add contribution to consistent tangent matrix if o.UseB { radius := 1.0 if sol.Axisym { radius = o.Cell.Shp.AxisymGetRadius(o.X) coef *= radius } IpBmatrix(o.B, o.Ndim, nverts, G, radius, S, sol.Axisym) la.MatTrMulAdd3(o.K, coef, o.B, o.D, o.B) // K += coef * tr(B) * D * B } else { IpAddToKt(o.K, nverts, o.Ndim, coef, G, o.D) } // dynamic term if !sol.Steady { α1 := sol.DynCfs.α1 α4 := sol.DynCfs.α4 for m := 0; m < nverts; m++ { for i := 0; i < o.Ndim; i++ { r := i + m*o.Ndim for n := 0; n < nverts; n++ { c := i + n*o.Ndim o.K[r][c] += coef * S[m] * S[n] * (o.Rho*α1 + o.Cdam*α4) } } } } } // add Ks to sparse matrix Kb switch { case o.HasContact: err = o.contact_add_to_jac(Kb, sol) case o.Xfem: err = o.xfem_add_to_jac(Kb, sol) default: for i, I := range o.Umap { for j, J := range o.Umap { Kb.Put(I, J, o.K[i][j]) } } } return }