// Update updates pc and sl for given Δpc. An implicit ODE solver is used. func Update(mdl Model, pc0, sl0, Δpc float64) (slNew float64, err error) { // wetting flag wet := Δpc < 0 // callback functions // x = [0.0, 1.0] // pc = pc0 + x * Δpc // y[0] = sl // f(x,y) = dy/dx = dsl/dpc * dpc/dx = Cc * Δpc // J(x,y) = df/dy = DCcDsl * Δpc fcn := func(f []float64, x float64, y []float64, args ...interface{}) (e error) { f[0], e = mdl.Cc(pc0+x*Δpc, y[0], wet) f[0] *= Δpc return nil } jac := func(dfdy *la.Triplet, x float64, y []float64, args ...interface{}) (e error) { if dfdy.Max() == 0 { dfdy.Init(1, 1, 1) } J, e := mdl.J(pc0+x*Δpc, y[0], wet) dfdy.Start() dfdy.Put(0, 0, J) return } // ode solver var odesol ode.ODE odesol.Init("Radau5", 1, fcn, jac, nil, nil, true) odesol.SetTol(1e-10, 1e-7) odesol.Distr = false // this is important to avoid problems with MPI runs // solve y := []float64{sl0} err = odesol.Solve(y, 0, 1, 1, false) slNew = y[0] return }
func main() { mpi.Start(false) defer func() { mpi.Stop(false) }() if mpi.Rank() == 0 { chk.PrintTitle("Test ODE 02b") io.Pfcyan("Hairer-Wanner VII-p5 Eq.(1.5) Van der Pol's Equation (MPI)\n") } if mpi.Size() != 2 { chk.Panic(">> error: this test requires 2 MPI processors\n") return } eps := 1.0e-6 w := make([]float64, 2) // workspace fcn := func(f []float64, x float64, y []float64, args ...interface{}) error { f[0], f[1] = 0, 0 switch mpi.Rank() { case 0: f[0] = y[1] case 1: f[1] = ((1.0-y[0]*y[0])*y[1] - y[0]) / eps } // join all f mpi.AllReduceSum(f, w) return nil } jac := func(dfdy *la.Triplet, x float64, y []float64, args ...interface{}) error { if dfdy.Max() == 0 { dfdy.Init(2, 2, 4) } dfdy.Start() if false { // per column switch mpi.Rank() { case 0: dfdy.Put(0, 0, 0.0) dfdy.Put(1, 0, (-2.0*y[0]*y[1]-1.0)/eps) case 1: dfdy.Put(0, 1, 1.0) dfdy.Put(1, 1, (1.0-y[0]*y[0])/eps) } } else { // per row switch mpi.Rank() { case 0: dfdy.Put(0, 0, 0.0) dfdy.Put(0, 1, 1.0) case 1: dfdy.Put(1, 0, (-2.0*y[0]*y[1]-1.0)/eps) dfdy.Put(1, 1, (1.0-y[0]*y[0])/eps) } } return nil } // data silent := false fixstp := false //method := "Dopri5" method := "Radau5" xa, xb := 0.0, 2.0 ya := []float64{2.0, -0.6} ndim := len(ya) // output 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, "%23s %23s %23s %23s\n", "dx", "x", "y0", "y1") } fmt.Fprintf(&b, "%23.15E %23.15E %23.15E %23.15E\n", dx, x, y[0], y[1]) } return nil } defer func() { if mpi.Rank() == 0 { extra := "d2 = Read('data/vdpol_radau5_for.dat')\n" + "subplot(3,1,1)\n" + "plot(d2['x'],d2['y0'],'k+',label='res',ms=10)\n" + "subplot(3,1,2)\n" + "plot(d2['x'],d2['y1'],'k+',label='res',ms=10)\n" ode.Plot("/tmp/gosl", "vdpolB", method, &b, []int{0, 1}, ndim, nil, xa, xb, true, false, extra) } }() // one run var o ode.ODE o.Distr = true //numjac := true numjac := false if numjac { o.Init(method, ndim, fcn, nil, nil, out, silent) } else { o.Init(method, ndim, fcn, jac, nil, out, silent) } // tolerances and initial step size rtol := 1e-4 atol := rtol o.SetTol(atol, rtol) o.IniH = 1.0e-4 //o.NmaxSS = 2 y := make([]float64, ndim) copy(y, ya) t0 := time.Now() if fixstp { o.Solve(y, xa, xb, 0.05, fixstp) } else { o.Solve(y, xa, xb, xb-xa, fixstp) } if mpi.Rank() == 0 { io.Pfmag("elapsed time = %v\n", time.Now().Sub(t0)) } }
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)) } }