// fxy or z must be nil func (g *Grid2D) Contour(dirout, fnkey string, fxy Cb_fxy, z []float64, nlevels int, show bool) { // write buffer var b bytes.Buffer io.Ff(&b, "from gosl import *\n") io.Ff(&b, "XYZ = array([") for j := 0; j < g.Ny; j++ { for i := 0; i < g.Nx; i++ { x := float64(i) * g.Dx y := float64(j) * g.Dy if fxy == nil { io.Ff(&b, "(%g, %g, %g),", x, y, z[i+j*g.Nx]) } else { io.Ff(&b, "(%g, %g, %g),", x, y, fxy(x, y)) } } } io.Ff(&b, "],dtype=float)\n") io.Ff(&b, "X = XYZ[:,0].reshape(%d,%d)\n", g.Ny, g.Nx) io.Ff(&b, "Y = XYZ[:,1].reshape(%d,%d)\n", g.Ny, g.Nx) io.Ff(&b, "Z = XYZ[:,2].reshape(%d,%d)\n", g.Ny, g.Nx) io.Ff(&b, "Contour(X,Y,Z, nlevels=%d)\n", nlevels) io.Ff(&b, "axis('equal')\n") io.Ff(&b, "show()\n") // save file io.WriteFileD(dirout, fnkey+".py", &b) if show { _, err := exec.Command("python", dirout+"/"+fnkey+".py").Output() if err != nil { chk.Panic("Grid2D:Draw failed when calling python\n%v", err) } } }
func (g *Grid2D) Draw(dirout, fnkey string, show bool) { // write buffer var b bytes.Buffer io.Ff(&b, "from gosl import *\n") io.Ff(&b, "XY = array([") for j := 0; j < g.Ny; j++ { for i := 0; i < g.Nx; i++ { x := float64(i) * g.Dx y := float64(j) * g.Dy io.Ff(&b, "(%g, %g),", x, y) } } io.Ff(&b, "],dtype=float)\n") io.Ff(&b, "L = %v\n", utl.IntPy(g.L)) io.Ff(&b, "R = %v\n", utl.IntPy(g.R)) io.Ff(&b, "B = %v\n", utl.IntPy(g.B)) io.Ff(&b, "T = %v\n", utl.IntPy(g.T)) io.Ff(&b, "plot(XY[:,0], XY[:,1], 'ko', clip_on=False)\n") io.Ff(&b, "plot(XY[L,0], XY[L,1], 'rs', ms=15, clip_on=False)\n") io.Ff(&b, "plot(XY[R,0], XY[R,1], 'bs', ms=15, clip_on=False)\n") io.Ff(&b, "plot(XY[B,0], XY[B,1], 'yo', ms=12, clip_on=False)\n") io.Ff(&b, "plot(XY[T,0], XY[T,1], 'go', ms=12, clip_on=False)\n") io.Ff(&b, "axis('equal')\n") io.Ff(&b, "grid()\n") io.Ff(&b, "show()\n") // save file io.WriteFileD(dirout, fnkey+".py", &b) if show { _, err := exec.Command("python", dirout+"/"+fnkey+".py").Output() if err != nil { chk.Panic("Grid2D:Draw failed when calling python\n%v", err) } } }
func TestDiffusion1D(tst *testing.T) { //verbose() chk.PrintTitle("Test Diffusion 1D (cooling)") // solution parameters silent := false fixstp := true //fixstp := false //method := "FwEuler" method := "BwEuler" //method := "Dopri5" //method := "Radau5" //numjac := true numjac := false rtol := 1e-4 atol := rtol // timestep t0, tf, dt := 0.0, 0.2, 0.03 // problem data kx := 1.0 // conductivity N := 6 // number of nodes //Nb := N + 2 // augmented system dimension xmax := 1.0 // length dx := xmax / float64(N-1) // spatial step size dxx := dx * dx mol := []float64{kx / dxx, -2.0 * kx / dxx, kx / dxx} // function fcn := func(f []float64, t float64, y []float64, args ...interface{}) error { for i := 0; i < N; i++ { f[i] = 0 if i == 0 || i == N-1 { continue // skip presc node } for p, j := range []int{i - 1, i, i + 1} { if j < 0 { j = i + 1 } // left boundary if j == N { j = i - 1 } // right boundary f[i] += mol[p] * y[j] } } //io.Pfgrey("y = %v\n", y) //io.Pfcyan("f = %v\n", f) return nil } // Jacobian jac := func(dfdy *la.Triplet, t float64, y []float64, args ...interface{}) error { //chk.Panic("jac is not available") if dfdy.Max() == 0 { //dfdy.Init(Nb, Nb, 3*N) dfdy.Init(N, N, 3*N) } dfdy.Start() for i := 0; i < N; i++ { if i == 0 || i == N-1 { dfdy.Put(i, i, 0.0) continue } for p, j := range []int{i - 1, i, i + 1} { if j < 0 { j = i + 1 } // left boundary if j == N { j = i - 1 } // right boundary dfdy.Put(i, j, mol[p]) } } return nil } // initial values x := utl.LinSpace(0.0, xmax, N) y := make([]float64, N) //y := make([]float64, Nb) for i := 0; i < N; i++ { y[i] = 4.0*x[i] - 4.0*x[i]*x[i] } // debug f0 := make([]float64, N) //f0 := make([]float64, Nb) fcn(f0, 0, y) if false { io.Pforan("y0 = %v\n", y) io.Pforan("f0 = %v\n", f0) var J la.Triplet jac(&J, 0, y) la.PrintMat("J", J.ToMatrix(nil).ToDense(), "%8.3f", false) } //chk.Panic("stop") /* // constraints var A la.Triplet A.Init(2, N, 2) A.Put(0, 0, 1.0) A.Put(1, N-1, 1.0) io.Pfcyan("A = %+v\n", A) Am := A.ToMatrix(nil) c := make([]float64, 2) la.SpMatVecMul(c, 1, Am, y) // c := Am*y la.PrintMat("A", Am.ToDense(), "%3g", false) io.Pfcyan("c = %v ([0, 0] => consistent)\n", c) */ /* // mass matrix var M la.Triplet M.Init(Nb, Nb, N + 4) for i := 0; i < N; i++ { M.Put(i, i, 1.0) } M.PutMatAndMatT(&A) Mm := M.ToMatrix(nil) la.PrintMat("M", Mm.ToDense(), "%3g", false) */ // output var b0, b1, b2 bytes.Buffer fmt.Fprintf(&b0, "from gosl import *\n") fmt.Fprintf(&b1, "T = array([") fmt.Fprintf(&b2, "U = array([") out := func(first bool, dt, t float64, y []float64, args ...interface{}) error { fmt.Fprintf(&b1, "%23.15E,", t) fmt.Fprintf(&b2, "[") for i := 0; i < N; i++ { fmt.Fprintf(&b2, "%23.15E,", y[i]) } fmt.Fprintf(&b2, "],") return nil } defer func() { fmt.Fprintf(&b1, "])\n") fmt.Fprintf(&b2, "])\n") fmt.Fprintf(&b2, "X = linspace(0.0, %g, %d)\n", xmax, N) fmt.Fprintf(&b2, "tt, xx = meshgrid(T, X)\n") fmt.Fprintf(&b2, "ax = PlotSurf(tt, xx, vstack(transpose(U)), 't', 'x', 'u', 0.0, 1.0)\n") fmt.Fprintf(&b2, "ax.view_init(20.0, 30.0)\n") fmt.Fprintf(&b2, "show()\n") io.WriteFileD("/tmp/gosl", "plot_diffusion_1d.py", &b0, &b1, &b2) }() // ode solver var Jfcn Cb_jac var osol ODE if !numjac { Jfcn = jac } osol.Init(method, N, fcn, Jfcn, nil, out, silent) //osol.Init(method, Nb, fcn, Jfcn, &M, out, silent) osol.SetTol(atol, rtol) // constant Jacobian if method == "BwEuler" { osol.CteTg = true osol.Verbose = true } // run wallt0 := time.Now() if !fixstp { dt = tf - t0 } osol.Solve(y, t0, tf, dt, fixstp) io.Pfmag("elapsed time = %v\n", time.Now().Sub(wallt0)) }
func tex_results(dirout, fnkey, title, label string, dat *FemData, A, B, C, D, E *goga.Solution, document, compact bool) { if len(A.Flt) != 10 { chk.Panic("tex_results works with len(Areas)==10 only\n") return } buf := new(bytes.Buffer) if document { io.Ff(buf, `\documentclass[a4paper]{article} \usepackage{amsmath} \usepackage{amssymb} \usepackage{booktabs} \usepackage[margin=1.5cm,footskip=0.5cm]{geometry} \title{GOGA Report} \author{Dorival Pedroso} \begin{document} `) } io.Ff(buf, `\begin{table} \centering \caption{%s} `, title) if compact { io.Ff(buf, `\begin{tabular}[c]{cccccccc} \toprule point & weight & deflection & $A_0$ & $A_1$ & $A_2$ & $A_3$ & $A_4$ \\ & & & $A_5$ & $A_6$ & $A_7$ & $A_8$ & $A_9$ \\ \hline `) } else { io.Ff(buf, `\begin{tabular}[c]{ccccccccccccc} \toprule point & weight & deflection & $A_0$ & $A_1$ & $A_2$ & $A_3$ & $A_4$ & $A_5$ & $A_6$ & $A_7$ & $A_8$ & $A_9$ \\ \hline `) } writeline := func(pt string, E []int, A []float64) { _, _, weight, deflection, _, _, _ := dat.RunFEM(E, A, 0, false) if compact { io.Ff(buf, "%s & $%.2f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ \\\\\n", pt, weight, deflection, A[0], A[1], A[2], A[3], A[4]) io.Ff(buf, " & & & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ \\\\\n", A[5], A[6], A[7], A[8], A[9]) } else { io.Ff(buf, "%s & $%.2f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ & $%.6f$ \\\\\n", pt, weight, deflection, A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[8], A[9]) } } writeline("A", A.Int, A.Flt) writeline("B", B.Int, B.Flt) writeline("C", C.Int, C.Flt) writeline("D", D.Int, D.Flt) writeline("E", E.Int, E.Flt) io.Ff(buf, ` \bottomrule \end{tabular} \label{tab:%s} \end{table} `, label) if document { io.Ff(buf, ` \end{document}`) } tex := fnkey + ".tex" if document { io.WriteFileD(dirout, tex, buf) _, err := io.RunCmd(true, "pdflatex", "-interaction=batchmode", "-halt-on-error", "-output-directory=/tmp/goga/", tex) if err != nil { chk.Panic("%v", err) } io.PfBlue("file <%s/%s.pdf> generated\n", dirout, fnkey) } else { io.WriteFileVD(dirout, tex, buf) } }
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)) } }
// work/correctness analysis func WcAnalysis(dirout, fnkey, method string, fcn Cb_fcn, jac Cb_jac, M *la.Triplet, ycfcn Cb_ycorr, ya []float64, xa, xb float64, orders []float64, show bool) { // structure holding error data type RmsErr struct { value float64 count int } // output function => calculate error indicator ndim := len(ya) yc := make([]float64, ndim) out := func(first bool, dx, x float64, y []float64, args ...interface{}) error { ycfcn(yc, x) for i := 0; i < ndim; i++ { args[0].(*RmsErr).value += math.Pow(math.Abs(y[i]-yc[i])/(1.0+y[i]), 2.0) } args[0].(*RmsErr).count += 1 return nil } // initialise ode var o Solver o.Init(method, ndim, fcn, jac, M, out, true) o.PredCtrl = true // for python script var b0, b1, b2, b3 bytes.Buffer io.Ff(&b0, "from gosl import *\n") io.Ff(&b0, "tols = array([") io.Ff(&b1, "errs = array([") io.Ff(&b2, "nfev = array([") // run for a number of tolerances nt := 13 tols := make([]float64, nt) for i := 1; i < nt+1; i++ { tols[i-1] = math.Pow(10.0, -float64(i)) } io.Pf("tols = %v\n", tols) y := make([]float64, ndim) for i, tol := range tols { // set tolerances o.Atol, o.Rtol = tol, tol //o.Atol, o.Rtol = 1.0e-9, tol o.NmaxSS = 10000 // run copy(y, ya) var re RmsErr o.Solve(y, xa, xb, xb-xa, false, &re) re.value = math.Sqrt(re.value / float64(re.count)) io.Pf("tol = %e => err = %e => feval = %d\n", tol, re.value, o.nfeval) // python script if i == len(tols)-1 { io.Ff(&b0, "%g", tol) io.Ff(&b1, "%g", re.value) io.Ff(&b2, "%d", o.nfeval) } else { io.Ff(&b0, "%g,", tol) io.Ff(&b1, "%g,", re.value) io.Ff(&b2, "%d,", o.nfeval) } } io.Ff(&b0, "])\n") io.Ff(&b1, "])\n") io.Ff(&b2, "], dtype=float)\n") // python script io.Ff(&b3, "X, Y = -log10(errs), log10(nfev)\n") io.Ff(&b3, "plot(X, Y, clip_on=0)\n") if len(orders) > 0 { io.Ff(&b3, "dX = X[-1] - X[0]\n") } for _, ord := range orders { io.Ff(&b3, "plot([X[0], X[0]+dX], [Y[0], Y[0] + dX/float(%g)], 'k--', clip_on=0)\n", ord) } io.Ff(&b3, "Gll('correctness = -log10(error)', 'work = log10(nfev)', leg=0)\n") io.Ff(&b3, "show()\n") // write file fnpath := io.Sf("%s/%s_wc.py", dirout, fnkey) io.WriteFileD(dirout, fnkey+"_wc.py", &b0, &b1, &b2, &b3) // run script if show { _, err := exec.Command("python", fnpath).Output() if err != nil { chk.Panic("failed when calling python %s\n%v", fnpath, err) } } }
// Generate generates report func (o *TexReport) Generate() { // functions o.col4 = "error" o.col5 = io.Sf("histogram ($N_{samples}=%d$)", o.nsamples) addHeader := o.normalTableHeader addRow := o.oneNormalAddRow switch o.Type { case 1: o.col4 = "objective" case 2: o.col5 = "spread" addRow = o.twoAddRow case 3: addRow = o.multiAddRow case 4: addHeader = o.compactTableHeader addRow = o.oneCompactAddRow } // number of rows per table nRowPerTab := o.NRowPerTab if nRowPerTab < 1 { nRowPerTab = len(o.Opts) } if o.RefLabel == "" { o.RefLabel = o.Fnkey } // input and xres tables o.inputHeader() o.xResHeader() // add rows idxtab := 0 contd := "" for i, opt := range o.Opts { if i%nRowPerTab == 0 { if i > 0 { o.tableFooter(idxtab) // end previous table io.Ff(o.buf, "\n\n\n") contd = " (contd.)" idxtab++ } addHeader(contd) // begin new table } else { if i > 0 { if o.Type != 4 { io.Ff(o.buf, "\\hline\n") } //io.Ff(o.bxres, "\n\\hline\n") io.Ff(o.buf, "\n") } } addRow(opt) o.inputRow(opt) o.xResRow(opt) } // close tables o.inputFooter() io.Ff(o.binp, "\n\n\n") o.xResFooter() o.tableFooter(idxtab) // end previous table io.Ff(o.buf, "\n\n\n") // write table tex := o.Fnkey + ".tex" io.WriteFileVD(o.DirOut, tex, o.buf, o.binp, o.bxres) // generate PDF if o.RunPDF { header := new(bytes.Buffer) footer := new(bytes.Buffer) str := "" if o.UseGeom { str = `\usepackage[margin=1.5cm,footskip=0.5cm]{geometry}` } io.Ff(header, `\documentclass[a4paper]{article} \usepackage{amsmath} \usepackage{amssymb} \usepackage{booktabs} %s \title{GOGA Report} \author{Dorival Pedroso} \begin{document} `, str) io.Ff(footer, ` \end{document}`) // write temporary TeX file tex = "tmp_" + tex io.WriteFileD(o.DirOut, tex, header, o.buf, o.binp, o.bxres, footer) // run pdflatex _, err := io.RunCmd(false, "pdflatex", "-interaction=batchmode", "-halt-on-error", "-output-directory="+o.DirOut, tex) if err != nil { io.PfRed("pdflatex failed: %v\n", err) return } io.PfBlue("file <%s/tmp_%s.pdf> generated\n", o.DirOut, o.Fnkey) } }
// plot results corresponding to one run func Plot(dirout, fnkey, method string, bres *bytes.Buffer, ycps []int, ndim int, ycfcn Cb_ycorr, xa, xb float64, withdx, show bool, extra string) { // save file with results os.MkdirAll(dirout, 0777) if bres != nil { io.WriteFileD(dirout, fnkey+".res", bres) } // new python script var b bytes.Buffer fmt.Fprintf(&b, "from gosl import *\n") fmt.Fprintf(&b, "d = Read('%s/%s.res')\n", dirout, fnkey) // closed-form solution var xc []float64 if ycfcn != nil { np := 101 dx := (xb - xa) / float64(np-1) fmt.Fprintf(&b, "yc = array([\n") xc = make([]float64, np) yc := make([]float64, ndim) for i := 0; i < np; i++ { xc[i] = xa + dx*float64(i) ycfcn(yc, xc[i]) fmt.Fprintf(&b, "[") for j := 0; j < ndim; j++ { if j == ndim-1 { fmt.Fprintf(&b, "%g", yc[j]) } else { fmt.Fprintf(&b, "%g,", yc[j]) } } if i == np-1 { fmt.Fprintf(&b, "]") } else { fmt.Fprintf(&b, "],\n") } } fmt.Fprintf(&b, "])\n") fmt.Fprintf(&b, "xc = array([") for i := 0; i < np; i++ { if i == np-1 { fmt.Fprintf(&b, "%g", xc[i]) } else { fmt.Fprintf(&b, "%g,", xc[i]) } } fmt.Fprintf(&b, "])\n") } // number of subplots nplt := len(ycps) if withdx { nplt += 1 } // plot for i, cp := range ycps { fmt.Fprintf(&b, "subplot(%d,1,%d)\n", nplt, i+1) if ycfcn != nil { fmt.Fprintf(&b, "plot(xc, yc[:,%d], 'y-', lw=6, clip_on=0, label='solution')\n", cp) } fmt.Fprintf(&b, "plot(d['x'], d['y%d'], 'b-', marker='.', lw=1, clip_on=0, label='%s')\n", cp, method) fmt.Fprintf(&b, "Gll('x', 'y%d')\n", cp) } if withdx { fmt.Fprintf(&b, "subplot(%d,1,%d)\n", nplt, len(ycps)+1) fmt.Fprintf(&b, "plot(d['x'], d['dx'], 'b-', marker='.', lw=1, clip_on=0, label='%s')\n", method) fmt.Fprintf(&b, "gca().set_yscale('log')\n") fmt.Fprintf(&b, "Gll('x', 'step size')\n") } fmt.Fprintf(&b, extra) fmt.Fprintf(&b, "show()\n") // write file fn := fmt.Sprintf("%s/%s.py", dirout, fnkey) io.WriteFile(fn, &b) // run script if show { _, err := exec.Command("python", fn).Output() if err != nil { chk.Panic("failed when calling python %s\n%v", fn, err) } } }