From 6f9b667cbe28f81995418a865facea3085a8ac59 Mon Sep 17 00:00:00 2001 From: "Andrew E. Torda" <torda@zbh.uni-hamburg.de> Date: Fri, 18 Feb 2022 09:57:35 +0100 Subject: [PATCH] Boring changes to make data types simple int's and float64's so that I can use the binding function in fyne. It is otherwise too painful to have to do lots of casts. --- mc_work/dorun.go | 8 ++++---- mc_work/mc_work.go | 4 ++-- mc_work/rdprm.go | 22 +++++++--------------- mc_work/realmain_nogfx.go | 2 +- ui/output_tab.go | 29 +++++++++++++++++++---------- ui/param_tab.go | 30 ++++++++++++++++++++---------- 6 files changed, 53 insertions(+), 42 deletions(-) diff --git a/mc_work/dorun.go b/mc_work/dorun.go index 4c05d43..3a2d7ce 100644 --- a/mc_work/dorun.go +++ b/mc_work/dorun.go @@ -159,7 +159,7 @@ func newx(xold []float32, xT []float32, rand *rand.Rand, xDlta float64) { // printfVal is the loop to print out the function value and coordinates // probably for later plotting. -func printfVal(fOut io.Writer, x []float32, n uint32, tmprtr float64, fOld float64) { +func printfVal(fOut io.Writer, x []float32, n int, tmprtr float64, fOld float64) { fmt.Fprintf(fOut, "%d,%.4g,%.5g", n, tmprtr, fOld) for _, xx := range x { fmt.Fprintf(fOut, ",%.2g", xx) @@ -169,7 +169,7 @@ func printfVal(fOut io.Writer, x []float32, n uint32, tmprtr float64, fOld float // saveStep is called when we accept a change. It writes or saves for // later plotting. -func saveStep(cprm *cprm, n uint32, tmprtr float64, x []float32, fTrial float64) { +func saveStep(cprm *cprm, n int, tmprtr float64, x []float32, fTrial float64) { cprm.plotnstp = append(cprm.plotnstp, float64(n)) // num steps if cprm.fplotWrt != nil { // Function values // function values cprm.plotf = append(cprm.plotf, fTrial) @@ -184,7 +184,7 @@ func saveStep(cprm *cprm, n uint32, tmprtr float64, x []float32, fTrial float64) } // nRunAdj will try to adjust the step size, given our history of accept/reject. -func nRunAdj(mcPrm *McPrm, nstep uint32, runAcc float64, xDlta float64) float64 { +func nRunAdj(mcPrm *McPrm, nstep int, runAcc float64, xDlta float64) float64 { const step = "step" if runAcc < accRateIdeal-0.01 { // acceptance rate too low xDlta *= 0.9 @@ -236,7 +236,7 @@ func DoRun(mcPrm *McPrm) ([]byte, []byte, error) { xDlta := mcPrm.XDlta // Adaptable step size saveStep(&cprm, 0, tmprtr, x, fOld) - for n := uint32(0); n < mcPrm.NStep; n++ { + for n := 0; n < mcPrm.NStep; n++ { var accept bool nRunAcc-- if nRunAcc == 0 { // Do we want to try adjusting the step size ? diff --git a/mc_work/mc_work.go b/mc_work/mc_work.go index 476888a..b3ad67f 100644 --- a/mc_work/mc_work.go +++ b/mc_work/mc_work.go @@ -13,8 +13,8 @@ type McPrm struct { IniTmp, FnlTmp float64 // Initial and final temperatures XIni []float32 // initial x slice XDlta float64 // change x by up to +- xDlta in trial moves - NStep uint32 // number of steps - NRun uint32 // number of separate runs + NStep int // number of steps + NRun int // number of separate runs fOutName string // where we write output to fPltName string // where we plot to (function values) xPltName string // where we plot x trajectories to diff --git a/mc_work/rdprm.go b/mc_work/rdprm.go index e3b8ad2..c972a11 100644 --- a/mc_work/rdprm.go +++ b/mc_work/rdprm.go @@ -36,14 +36,6 @@ var cmdDflt = []struct { // digest digests the map, fills out our structure and sets the seed. func digest(prmMap map[string]string, mcPrm *McPrm) error { var err error -/* getf := func(s string) float32 { - if err != nil { - return 0.0 - } - var r float64 - r, err = strconv.ParseFloat(s, 32) - return float32(r) - } */ getf64 := func(s string) float64 { if err != nil { return 0.0 @@ -52,13 +44,13 @@ func digest(prmMap map[string]string, mcPrm *McPrm) error { r, err = strconv.ParseFloat(s, 64) return r } - getu := func(s string) uint32 { + geti := func(s string) int { if err != nil { return 0 } - var u uint64 - u, err = strconv.ParseUint(s, 10, 32) - return uint32(u) + var u int64 + u, err = strconv.ParseInt(s, 10, 32) + return int(u) } getx := func(s string) []float32 { if err != nil { @@ -83,13 +75,13 @@ func digest(prmMap map[string]string, mcPrm *McPrm) error { mcPrm.IniTmp = getf64(prmMap["ini_temp"]) mcPrm.FnlTmp = getf64(prmMap["final_temp"]) mcPrm.XDlta = getf64(prmMap["x_delta"]) - mcPrm.NStep = getu(prmMap["n_step"]) - mcPrm.NRun = getu(prmMap["n_run"]) + mcPrm.NStep = geti(prmMap["n_step"]) + mcPrm.NRun = geti(prmMap["n_run"]) mcPrm.XIni = getx(prmMap["x_ini"]) mcPrm.fOutName = prmMap["foutname"] mcPrm.fPltName = prmMap["fpltname"] mcPrm.xPltName = prmMap["xpltname"] - seed = int64(getu(prmMap["seed"])) + seed = int64(geti(prmMap["seed"])) if err != nil { // Only returns the first error encountered return err } diff --git a/mc_work/realmain_nogfx.go b/mc_work/realmain_nogfx.go index a63116e..8551c43 100644 --- a/mc_work/realmain_nogfx.go +++ b/mc_work/realmain_nogfx.go @@ -20,7 +20,7 @@ func realmain(fp io.Reader) error { if err := RdPrm(fp, &mcPrm); err != nil { return err } - if _, _, err := doRun(&mcPrm); err != nil { + if _, _, err := DoRun(&mcPrm); err != nil { return err } diff --git a/ui/output_tab.go b/ui/output_tab.go index f8dbdc7..41a44f4 100644 --- a/ui/output_tab.go +++ b/ui/output_tab.go @@ -30,35 +30,44 @@ type workstatus struct { status status } +// showIniTab is just a card to be shown before we have any calculations +// done. func showIniTab(cntr *fyne.Container) { cntr.Add(widget.NewCard("No results yet", "go back to the input", nil)) } -func showCalcTab(cntr *fyne.Container) { - for _, c := range cntr.Objects { - cntr.Remove(c) +// emptyContainer gets rid of any old contents +func emptyContainer (cntr *fyne.Container) { + for _, o := range cntr.Objects { + cntr.Remove(o) } +} + +// showCalcTab is shown while calculating. Have to check if the refresh() +// is actually necessary. +func showCalcTab(cntr *fyne.Container) { + emptyContainer (cntr) cntr.Add(widget.NewCard("calculating", "busy", nil)) cntr.Refresh() } // showResultsTab show the two plots - func showResultsTab(cntr *fyne.Container, fdata, xdata []byte) { - for _, c := range cntr.Objects { - cntr.Remove(c) - } + emptyContainer (cntr) + pictureSize := fyne.Size{Width: 500, Height: 250} fImage := canvas.NewImageFromReader(bytes.NewReader(fdata), "func.png") fImage.FillMode = canvas.ImageFillContain - fImage.SetMinSize( fyne.Size{500, 300}) + fImage.SetMinSize( pictureSize) xImage := canvas.NewImageFromReader(bytes.NewReader(xdata), "xdata.png") xImage.FillMode = canvas.ImageFillContain - xImage.SetMinSize( fyne.Size{500, 300}) + xImage.SetMinSize( pictureSize) content := container.NewGridWithRows(2, fImage, xImage) cntr.Add(content) - } +// outputTab is run as a background process. After showing the initial +// screen, it sits and waits on notifications. When it gets one, +// it redraws its tab. func outputTab(chn chan workstatus, cntr *fyne.Container) { showIniTab(cntr) for s := range chn { diff --git a/ui/param_tab.go b/ui/param_tab.go index 504f283..c38f127 100644 --- a/ui/param_tab.go +++ b/ui/param_tab.go @@ -50,17 +50,19 @@ func s2f32(s string) ([]float32, error) { return x, nil } +// validateXini checks if we can convert a string to a slice of float32's. +// Unfortunately, fyne calls this function every time the cursor is moved +// in the field. I think this is a little bug on their part. func validateXini(s string) error { - fmt.Println("validation called") _, err := s2f32(s) return err } -// paramScreen sets up a screen full of parameters we can adjust. It returns a the screen -// and a function to be called to refresh it if parameters are changed elsewhere, like -// reading from a file. +// paramScreen sets up a screen full of parameters we can adjust. +// It returns the screen and a function to be called to refresh it. +// This is necessary, since there is a button to read parameters from +// a file, which means all the values should be updated. func paramScreen(mcPrm *mcwork.McPrm) (*fyne.Container, func()) { - iniTmp := binding.BindFloat(&mcPrm.IniTmp) iniTmpEntry := widget.NewEntryWithData(binding.FloatToString(iniTmp)) iniTmpLabel := widget.NewLabel("initial temp") @@ -87,21 +89,30 @@ func paramScreen(mcPrm *mcwork.McPrm) (*fyne.Container, func()) { xIniEntry.Validator = validateXini xIniLabel := widget.NewLabel("X ini") + nStepBnd := binding.BindInt(&mcPrm.NStep) + nStepEntry := widget.NewEntryWithData(binding.IntToString(nStepBnd)) + nStepLabel := widget.NewLabel("num steps") + r := container.NewGridWithColumns(2, iniTmpLabel, iniTmpEntry, fnlTmpLabel, fnlTmpEntry, xDltaLabel, xDltaEntry, - xIniLabel, xIniEntry) + xIniLabel, xIniEntry, + nStepEntry, nStepLabel) refreshPScreen := func() { iniTmp.Reload() fnlTmp.Reload() xDlta.Reload() xIniEntry.SetText(fslicestrng(mcPrm.XIni)) + nStepBnd.Reload() } return r, refreshPScreen } -func checkok(c *fyne.Container, parent fyne.Window) error { + +// checkOk does a last pass over all fields and calls any validators +// it can find. A run can only be started if everything seems to be OK. +func checkOk(c *fyne.Container, parent fyne.Window) error { for _, obj := range c.Objects { if ent, ok := obj.(*widget.Entry); ok { if err := ent.Validate(); err != nil { @@ -133,7 +144,7 @@ func rdwork(mcPrm *mcwork.McPrm, parent fyne.Window, refreshme func()) error { } else { fmt.Println("I think mcprm is", mcPrm) refreshme() - dialog.NewInformation("OK confirmed", "read file, no errors", parent).Show() + dialog.NewInformation("OK", "read file, no errors", parent).Show() return } } @@ -160,11 +171,10 @@ func inputTab(mcPrm *mcwork.McPrm, parent fyne.Window, chn chan workstatus) (*fy } } startrun := func() { - if err := checkok(paramBinding, parent); err != nil { + if err := checkOk(paramBinding, parent); err != nil { dialog.NewError(err, parent).Show() return } - fmt.Println("I want to run with paremeters", mcPrm) chn <- workstatus{status: calculating} if fdata, xdata, err := mcwork.DoRun(mcPrm); err != nil { dialog.NewError(err, parent).Show() -- GitLab