From f00519d5ba74f0b22eb0f0edea1bf0c3696e268d Mon Sep 17 00:00:00 2001 From: "Andrew E. Torda" <torda@zbh.uni-hamburg.de> Date: Wed, 5 Jan 2022 22:01:53 +0100 Subject: [PATCH] If we expand the range, as we do, we have to fix up the range structure in GetTicks(). --- ackwork/ackwork_test.go | 13 +++--- ackwork/dorun.go | 31 +++++++++++++- ackwork/plot.go | 95 ++++++++++++++++++++++++++--------------- ackwork/set_suffix.go | 37 ++++++++++++++++ doc.go | 1 + go.mod | 2 + go.sum | 2 - main.go | 2 +- 8 files changed, 137 insertions(+), 46 deletions(-) create mode 100644 ackwork/set_suffix.go diff --git a/ackwork/ackwork_test.go b/ackwork/ackwork_test.go index 5e9a7af..9d4c3aa 100644 --- a/ackwork/ackwork_test.go +++ b/ackwork/ackwork_test.go @@ -118,13 +118,14 @@ func TestCsv(t *testing.T) { } var s1dplot = ` -ini_temp 1 -final_temp 0.05 -x_ini 15 -n_step 10000 +ini_temp 0.095 +final_temp 0.06 +x_ini 15,10,11,12,14,18,-12,-8,-9 +n_step 100000 n_output 5000 -fOutName testanneal1d -fPltName testplot.svg` +fOutName test9d +fPltName testplot.svg +xPltName testrajplt` var plotTest = []string{ s1dplot, diff --git a/ackwork/dorun.go b/ackwork/dorun.go index 7dd1289..af7290d 100644 --- a/ackwork/dorun.go +++ b/ackwork/dorun.go @@ -43,7 +43,7 @@ type cprm struct { // parameters calculated from input plotx []float64 // Why float 64 ? Because the plotting libraries plotf []float64 // Function values for plotting plotTmprtr []float64 // Temperature values for plotting - plotXtrj [][]float64 // for plotting trajectories + plotXtrj []float32 // for plotting trajectories } // setupRun does things like get the cooling rate, seed the random numbers. @@ -95,6 +95,20 @@ func setupRun(mcPrm *mcPrm, cprm *cprm) error { cprm.plotTmprtr = make([]float64, 0, n_alloc) } } + if mcPrm.xPltName != "" { + var err error + if mcPrm.xPltName, err = setSuffix(mcPrm.xPltName, ".png"); err != nil { + return fmt.Errorf("plot filename: %w", err) + } + if cprm.xPlt, err = os.Create(mcPrm.xPltName); err != nil { + return err + } + cprm.xplotme = true + n_alloc := mcPrm.nStep / 5 + n_dim := len(mcPrm.xIni) + cprm.plotXtrj = make([]float32, 0, int(n_alloc) * n_dim) + // Should check that cprm.plotx is allocated for the step number + } return nil } @@ -107,7 +121,6 @@ func newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float32) { xT[i] = x + t } } -func breaker() {} // plotFval adds a point to the data to be plotted. At the start, we check // if we have to plot at all. This is done here, to make the main loop @@ -150,6 +163,13 @@ func printfVal (fOut io.Writer, x []float32, n uint32, tmprtr float64, fOld floa fmt.Fprintln(fOut) } +// plotXtrj adds the next x coordinates to the pltXtrj for plotting at +// the end +func plotXtrj(n uint32, x []float32, pltXtrj *[]float32, xplotme bool) { + if ! xplotme { return } + *pltXtrj = append(*pltXtrj, x...) +} + // doRun does a Monte Carlo run. Although single precision is fine for the // coordinates and function, we use double precision for the temperature. func doRun(mcPrm *mcPrm) error { @@ -177,7 +197,9 @@ func doRun(mcPrm *mcPrm) error { nRunAcc := nRunAccAdj // Every nRunAccAdj, try adjusting the step size. const runMult = 0.99 xDlta := mcPrm.xDlta // Adaptable step size + // if either plot is running, save the step. plotFval(0, fOld, tmprtr, &cprm.plotx, &cprm.plotf, &cprm.plotTmprtr, cprm.fplotme) + plotXtrj(0, x, &cprm.plotXtrj, cprm.xplotme) for n := uint32(0); n < mcPrm.nStep; n++ { var acc bool nout-- @@ -209,6 +231,7 @@ func doRun(mcPrm *mcPrm) error { copy(x, xT) fOld = fTrial plotFval(n+1, fTrial, tmprtr, &cprm.plotx, &cprm.plotf, &cprm.plotTmprtr, cprm.fplotme) + plotXtrj(n+1, x, &cprm.plotXtrj, cprm.xplotme) } else { // update the running estimate of acceptance runAcc = runMult * runAcc } @@ -217,6 +240,10 @@ func doRun(mcPrm *mcPrm) error { } } err := plotfWrt(cprm.plotx, cprm.plotf, cprm.plotTmprtr, cprm.fPlt, cprm.fplotme) + if err != nil { + return err } + err = plotxWrt (&cprm, len(mcPrm.xIni)) + fmt.Println("n accepted:", nAcc, "of", mcPrm.nStep+1) return err } diff --git a/ackwork/plot.go b/ackwork/plot.go index d08b68c..3d1478c 100644 --- a/ackwork/plot.go +++ b/ackwork/plot.go @@ -13,48 +13,16 @@ package ackwork import ( - "errors" "fmt" "io" "math" "os" - "path/filepath" "github.com/wcharczuk/go-chart/v2" "github.com/wcharczuk/go-chart/v2/drawing" "gitlab.rrz.uni-hamburg.de/Bae5157/axticks" ) -// setSuffix takes a name and makes sure the desired suffix is at the end -// of the filename. -func setSuffix(fname, suffix string) (string, error) { - if len(fname) == 0 { - return "", errors.New("setSuffix given empty fname") - } - if suffix == "" { // no suffix might not be an error. Just - if fname[len(fname)-1] == '.' { // remove any trailing dot - fname = fname[0 : len(fname)-1] - } - if len(fname) > 0 { - return fname, nil - } - return "", errors.New("setSuffix got empty filename") - } - - if suffix[0] != '.' { - suffix = "." + suffix - } - oldExt := filepath.Ext(fname) - switch oldExt { - case suffix: - return fname, nil - case "": - return fname + suffix, nil - default: - return fname[0:len(fname)-len(oldExt)] + suffix, nil - } -} - // maketicks gives reasonable default tick locations func maketicks(axisDscrpt axticks.AxisDscrpt, prcsn int) []chart.Tick { xmin, delta, prcsn := axisDscrpt.Xmin, axisDscrpt.Delta, axisDscrpt.Prcsn @@ -85,6 +53,8 @@ func (rng *range2) GetTicks(r chart.Renderer, cs chart.Style, vf chart.ValueForm fmt.Fprintln(os.Stderr, "GetTicks error:", err) return nil } else { + rng.Min = a.Xmin + rng.Max = a.Xmax return maketicks(a, a.Prcsn) } } @@ -112,7 +82,7 @@ func plotfWrt(xdata, ydata []float64, tmprtrData []float64, tmprtrAxis := chart.YAxis{ Name: "temperature", - NameStyle: chart.Style{TextRotationDegrees: math.SmallestNonzeroFloat64}, + NameStyle: chart.Style{TextRotationDegrees: 360}, Range: &range2{}, } @@ -141,8 +111,8 @@ func plotfWrt(xdata, ydata []float64, tmprtrData []float64, Background: chart.Style{ Padding: chart.Box{ - Left: 75, - Right: 25, + Left: 50, + Right: 75, }, FillColor: drawing.ColorTransparent, }, @@ -153,3 +123,58 @@ func plotfWrt(xdata, ydata []float64, tmprtrData []float64, return nil } +func breaker() {} + +// plotxWrt +// For each dimension, allocate space. Copy elements over from the long array. +// Then call the plotter on each series in turn. I think I have to make a +// slice of continuous series and then add them into the chart structure. +func plotxWrt(cprm *cprm, ndim int) error { + if !cprm.xplotme { + return nil + } + + type f64 []float64 + len_used := len(cprm.plotx) + xdata := make([]f64, ndim) + fmt.Println("plotxWrt has", ndim, "dimensions and len_used is", len_used) + for i := 0; i < ndim; i++ { + xdata[i] = make([]float64, len_used) + } + breaker() + var n int + for i := 0; i < len_used; i++ { + for j := 0; j < ndim; j++ { + xdata[j][i] = float64(cprm.plotXtrj[n]) + n++ + } + } + series := make([]chart.Series, ndim) + for i := 0; i < ndim; i++ { + series[i] = chart.ContinuousSeries{ + Name: fmt.Sprintf("dimension %d", i), + XValues: cprm.plotx, + YValues: xdata[i], + } + } + graph := chart.Chart{ + Title: fmt.Sprintf("X trajectories %d dimension", ndim), + XAxis: chart.XAxis{Name: "step", Range: &range2{}}, + YAxis: chart.YAxis{ + Name: "x coord", + Range: &range2{}, + AxisType: chart.YAxisSecondary, + NameStyle: chart.Style{TextRotationDegrees: 360}, + }, + Series: series, + Background: chart.Style{ + Padding: chart.Box{ + Left: 75, + }, + }, + } + if err := graph.Render(chart.PNG, cprm.xPlt); err != nil { + return fmt.Errorf("plotting X trajectories: %w", err) + } + return nil +} diff --git a/ackwork/set_suffix.go b/ackwork/set_suffix.go new file mode 100644 index 0000000..d10f001 --- /dev/null +++ b/ackwork/set_suffix.go @@ -0,0 +1,37 @@ +// a utility +package ackwork + +import ( + "errors" + "path/filepath" +) + +// setSuffix takes a name and makes sure the desired suffix is at the end +// of the filename. +func setSuffix(fname, suffix string) (string, error) { + if len(fname) == 0 { + return "", errors.New("setSuffix given empty fname") + } + if suffix == "" { // no suffix might not be an error. Just + if fname[len(fname)-1] == '.' { // remove any trailing dot + fname = fname[0 : len(fname)-1] + } + if len(fname) > 0 { + return fname, nil + } + return "", errors.New("setSuffix got empty filename") + } + + if suffix[0] != '.' { + suffix = "." + suffix + } + oldExt := filepath.Ext(fname) + switch oldExt { + case suffix: + return fname, nil + case "": + return fname + suffix, nil + default: + return fname[0:len(fname)-len(oldExt)] + suffix, nil + } +} diff --git a/doc.go b/doc.go index fe74335..8f71b55 100644 --- a/doc.go +++ b/doc.go @@ -6,6 +6,7 @@ // Ackley input_file // where input_file is a set of name-value pairs. These are defined with defaults // in rdprm.go. At the moment, we have +package main /* {"ini_temp", "20"}, {"final_temp", "1"}, diff --git a/go.mod b/go.mod index b3e69c3..d9e56d6 100644 --- a/go.mod +++ b/go.mod @@ -6,3 +6,5 @@ require ( github.com/wcharczuk/go-chart/v2 v2.1.0 gitlab.rrz.uni-hamburg.de/Bae5157/axticks v0.0.0-20211227145643-dc5ef95d7dad ) + +replace gitlab.rrz.uni-hamburg.de/Bae5157/axticks => ../axticks diff --git a/go.sum b/go.sum index 520af54..7213416 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I= github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA= -gitlab.rrz.uni-hamburg.de/Bae5157/axticks v0.0.0-20211227145643-dc5ef95d7dad h1:IBCLghidSwZff0/3RuvTLDnHgK9SaZHZ/cXWSjimEt0= -gitlab.rrz.uni-hamburg.de/Bae5157/axticks v0.0.0-20211227145643-dc5ef95d7dad/go.mod h1:5CNHyqeidRypmIVTnQksGqnmP56Oshw1Zv1nlUezrpQ= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM= golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/main.go b/main.go index 60637ae..0eb00a0 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,7 @@ const ( func main() { if err := ackwork.MyMain (); err != nil { - fmt.Println (os.Stderr, err) + fmt.Fprintln (os.Stderr, err) os.Exit (exitFailure) } os.Exit (exitSuccess) -- GitLab