func main() { // catch errors defer func() { if err := recover(); err != nil { if mpi.Rank() == 0 { chk.Verbose = true for i := 8; i > 3; i-- { chk.CallerInfo(i) } io.PfRed("ERROR: %v\n", err) } } mpi.Stop(false) }() mpi.Start(false) // default input parameters // read input parameters fnamepath, _ := io.ArgToFilename(0, "", ".sim", true) verbose := io.ArgToBool(1, true) erasePrev := io.ArgToBool(2, true) saveSummary := io.ArgToBool(3, true) allowParallel := io.ArgToBool(4, true) alias := io.ArgToString(5, "") // message if mpi.Rank() == 0 && verbose { io.PfWhite("\nGofem v3 -- Go Finite Element Method\n\n") io.Pf("Copyright 2015 Dorival Pedroso and Raul Durand. All rights reserved.\n") io.Pf("Use of this source code is governed by a BSD-style\n") io.Pf("license that can be found in the LICENSE file.\n\n") io.Pf("\n%v\n", io.ArgsTable( "filename path", "fnamepath", fnamepath, "show messages", "verbose", verbose, "erase previous results", "erasePrev", erasePrev, "save summary", "saveSummary", saveSummary, "allow parallel run", "allowParallel", allowParallel, "word to add to results", "alias", alias, )) } // profiling? defer utl.DoProf(false)() // analysis data readSummary := false analysis := fem.NewFEM(fnamepath, alias, erasePrev, saveSummary, readSummary, allowParallel, verbose, 0) // run simulation err := analysis.Run() if err != nil { chk.Panic("Run failed:\n%v", err) } }
func run_pareto_test(U, V, Φ []float64, ntrials int) (zu, zv []float64) { io.Pforan("\nu = %v\n", U) io.Pforan("v = %v\n", V) io.PfWhite("%5s%13s%13s\n", "φ", "u wins", "v wins") zu = make([]float64, len(Φ)) zv = make([]float64, len(Φ)) for i, φ := range Φ { u_wins := 0 v_wins := 0 for j := 0; j < ntrials; j++ { u_dominates := DblsParetoMinProb(U, V, φ) if u_dominates { u_wins++ } else { v_wins++ } } zu[i] = 100 * float64(u_wins) / float64(ntrials) zv[i] = 100 * float64(v_wins) / float64(ntrials) io.Pf("%5.2f%12.2f%%%12.2f%%\n", φ, zu[i], zv[i]) } return }
// Run runs FE simulation func Run() (runisok bool) { // plot functions if Global.Sim.PlotF != nil && Global.Root { Global.Sim.Functions.PlotAll(Global.Sim.PlotF, Global.Dirout, Global.Fnkey) } // alloc domains var domains []*Domain for _, reg := range Global.Sim.Regions { dom := NewDomain(reg, Global.Distr) if dom == nil { break } domains = append(domains, dom) } if Stop() { return } // make sure to call linear solver clean up routines upon exit defer func() { for _, d := range domains { if !d.InitLSol { d.LinSol.Clean() } } }() // current time and output time t := 0.0 tout := 0.0 tidx := 0 // summary of outputs; e.g. with output times cputime := time.Now() var sum Summary sum.OutTimes = []float64{t} defer func() { sum.Save() if Global.Verbose && !Global.Debug { io.Pf("\nfinal t = %v\n", t) io.Pfblue2("cpu time = %v\n", time.Now().Sub(cputime)) } }() // loop over stages for stgidx, stg := range Global.Sim.Stages { // time incrementers Dt := stg.Control.DtFunc DtOut := stg.Control.DtoFunc tf := stg.Control.Tf tout = t + DtOut.F(t, nil) // set stage for _, d := range domains { if LogErrCond(!d.SetStage(stgidx, Global.Sim.Stages[stgidx], Global.Distr), "SetStage failed") { break } d.Sol.T = t if !d.Out(tidx) { break } } if Stop() { return } tidx += 1 // log models mconduct.LogModels() mreten.LogModels() mporous.LogModels() msolid.LogModels() // skip stage? if stg.Skip { continue } // time loop using Richardson's extrapolation // TODO: works with only one domain for now if Global.Sim.Solver.RE { var re RichardsonExtrap re.Init(domains[0], Dt) if !re.Run(domains[0], &sum, DtOut, &t, tf, tout, &tidx) { return } continue } // time loop ndiverg := 0 // number of steps diverging md := 1.0 // time step multiplier if divergence control is on var Δt, Δtout float64 var lasttimestep bool for t < tf { // check for continued divergence if LogErrCond(ndiverg >= Global.Sim.Solver.NdvgMax, "continuous divergence after %d steps reached", ndiverg) { return } // time increment Δt = Dt.F(t, nil) * md if t+Δt >= tf { Δt = tf - t lasttimestep = true } if Δt < Global.Sim.Solver.DtMin { if md < 1 { LogErrCond(true, "Δt increment is too small: %g < %g", Δt, Global.Sim.Solver.DtMin) return false } return true } // dynamic coefficients if LogErr(Global.DynCoefs.CalcBoth(Δt), "cannot compute dynamic coefficients") { return } // time update t += Δt for _, d := range domains { d.Sol.T = t } Δtout = DtOut.F(t, nil) // message if Global.Verbose { if !Global.Sim.Data.ShowR && !Global.Debug { io.PfWhite("%30.15f\r", t) } } // for all domains docontinue := false for _, d := range domains { // backup solution if divergence control is on if Global.Sim.Solver.DvgCtrl { d.backup() } // run iterations diverging, ok := run_iterations(t, Δt, d, &sum) if !ok { return } // restore solution and reduce time step if divergence control is on if Global.Sim.Solver.DvgCtrl { if diverging { if Global.Verbose { io.Pfred(". . . iterations diverging (%2d) . . .\n", ndiverg+1) } d.restore() t -= Δt d.Sol.T = t md *= 0.5 ndiverg += 1 docontinue = true break } ndiverg = 0 md = 1.0 } } if docontinue { continue } // perform output if t >= tout || lasttimestep { sum.OutTimes = append(sum.OutTimes, t) for _, d := range domains { //if true { if false { debug_print_p_results(d) } if false { debug_print_up_results(d) } if !d.Out(tidx) { break } } if Stop() { return } tout += Δtout tidx += 1 } } } return true }
func main() { // catch errors defer func() { if err := recover(); err != nil { io.PfRed("ERROR: %v\n", err) } }() // input data simfn, _ := io.ArgToFilename(0, "data/twoqua4", ".sim", true) exnwl := io.ArgToBool(1, false) stgidx := io.ArgToInt(2, 0) io.Pf("\n%s\n", io.ArgsTable( "simulation filename", "simfn", simfn, "extrapolate nwl", "exnwl", exnwl, "stage index", "stgidx", stgidx, )) // start analysis process out.Start(simfn, stgidx, 0) // global variables ndim = out.Dom.Msh.Ndim verts = out.Dom.Msh.Verts cells = out.Dom.Msh.Cells nodes = out.Dom.Nodes elems = out.Dom.Elems dirout = out.Dom.Sim.DirOut fnkey = out.Dom.Sim.Key steady = out.Dom.Sim.Data.Steady // flags has_u := out.Dom.YandC["ux"] has_pl := out.Dom.YandC["pl"] has_pg := out.Dom.YandC["pg"] has_sig := out.Ipkeys["sx"] has_nwl := out.Ipkeys["nwlx"] has_p := has_pl || has_pg lbb := has_u && has_p if out.Dom.Sim.Data.NoLBB { lbb = false } // buffers pvd := make(map[string]*bytes.Buffer) geo := make(map[string]*bytes.Buffer) vtu := make(map[string]*bytes.Buffer) if _, ok := out.Dom.YandC["ux"]; ok { pvd["u"] = new(bytes.Buffer) geo["u"] = new(bytes.Buffer) vtu["u"] = new(bytes.Buffer) } for ykey, _ := range out.Dom.Dof2Tnum { if ykey == "ux" || ykey == "uy" || ykey == "uz" { continue } pvd[ykey] = new(bytes.Buffer) geo[ykey] = new(bytes.Buffer) vtu[ykey] = new(bytes.Buffer) label2keys[ykey] = []string{ykey} } if len(out.Ipkeys) > 0 { pvd["ips"] = new(bytes.Buffer) geo["ips"] = new(bytes.Buffer) vtu["ips"] = new(bytes.Buffer) } if exnwl { pvd["ex_nwl"] = new(bytes.Buffer) geo["ex_nwl"] = new(bytes.Buffer) vtu["ex_nwl"] = new(bytes.Buffer) } // extrapolated values keys extrap_keys := []string{"nwlx", "nwly"} if ndim == 3 { extrap_keys = []string{"nwlx", "nwly", "nwlz"} } // headers for _, b := range pvd { pvd_header(b) } // process results for tidx, t := range out.Sum.OutTimes { // input results into domain err := out.Dom.Read(out.Sum, tidx, 0, true) if err != nil { chk.Panic("cannot load results into domain\n%v", err) } // message io.PfWhite("time = %g\r", t) // generate topology if tidx == 0 { for label, b := range geo { topology(b, label == "ips", lbb) } // allocate integration points values ipvals = make([]map[string]float64, len(out.Ipoints)) for i, _ := range out.Ipoints { ipvals[i] = make(map[string]float64) } } // get integration points values @ time t for i, p := range out.Ipoints { vals := p.Calc(out.Dom.Sol) for key, val := range vals { ipvals[i][key] = val } } // compute extrapolated values if exnwl { out.ComputeExtrapolatedValues(extrap_keys) } // for each data buffer for label, b := range vtu { // reset buffer b.Reset() // points data if label == "ips" { pdata_open(b) if has_sig { pdata_write(b, "sig", skeys, true) } if has_nwl { pdata_write(b, "nwl", nwlkeys, true) } for key, _ := range out.Ipkeys { if !is_sig[key] && !is_nwl[key] { pdata_write(b, key, []string{key}, true) } } pdata_close(b) } else { pdata_open(b) pdata_write(b, label, label2keys[label], false) pdata_close(b) } // cells data cdata_write(b, label == "ips") // write vtu file vtu_write(geo[label], b, tidx, label) } // pvd for label, b := range pvd { pvd_line(b, tidx, t, label) } } // write pvd files for label, b := range pvd { pvd_write(b, label) } }
func main() { // catch errors defer func() { if err := recover(); err != nil { if mpi.Rank() == 0 { chk.Verbose = true for i := 8; i > 3; i-- { chk.CallerInfo(i) } io.PfRed("ERROR: %v\n", err) } } mpi.Stop(false) }() mpi.Start(false) // message if mpi.Rank() == 0 { io.PfWhite("\nGofem v3 -- Go Finite Element Method\n\n") io.Pf("Copyright 2015 Dorival Pedroso and Raul Durand. All rights reserved.\n") io.Pf("Use of this source code is governed by a BSD-style\n") io.Pf("license that can be found in the LICENSE file.\n\n") } // simulation filenamepath flag.Parse() var fnamepath string if len(flag.Args()) > 0 { fnamepath = flag.Arg(0) } else { chk.Panic("Please, provide a filename. Ex.: cylinder.sim") } // check extension if io.FnExt(fnamepath) == "" { fnamepath += ".sim" } // other options erasefiles := true verbose := true if len(flag.Args()) > 1 { erasefiles = io.Atob(flag.Arg(1)) } if len(flag.Args()) > 2 { verbose = io.Atob(flag.Arg(2)) } // profiling? defer utl.DoProf(false)() // start global variables and log if !fem.Start(fnamepath, erasefiles, verbose) { chk.Panic("Start failed\n") return } // make sure to flush log defer fem.End() // run simulation if !fem.Run() { io.PfRed("ERROR: cannot run simulation\n") } }
func (o *RichardsonExtrap) Run(d *Domain, s *Summary, DtOut fun.Func, time *float64, tf, tout float64, tidx *int) (ok bool) { // stat defer func() { if Global.Root { log.Printf("total number of steps = %d\n", o.nsteps) log.Printf("number of accepted steps = %d\n", o.naccept) log.Printf("number of rejected steps = %d\n", o.nreject) log.Printf("number of Gustaffson's corrections = %d\n", o.ngustaf) } }() // constants atol := Global.Sim.Solver.REatol rtol := Global.Sim.Solver.RErtol mmin := Global.Sim.Solver.REmmin mmax := Global.Sim.Solver.REmmax mfac := Global.Sim.Solver.REmfac // time loop t := *time defer func() { *time = t }() var ΔtOld, rerrOld float64 for t < tf { // check for continued divergence if LogErrCond(o.ndiverg >= Global.Sim.Solver.NdvgMax, "continuous divergence after %d steps reached", o.ndiverg) { return } // check time increment if LogErrCond(o.Δt < Global.Sim.Solver.DtMin, "Δt increment is too small: %g < %g", o.Δt, Global.Sim.Solver.DtMin) { return } // compute dynamic coefficients if LogErr(Global.DynCoefs.CalcBoth(o.Δt), "cannot compute dynamic coefficients") { return } // check for maximum number of substeps o.nsteps += 1 if LogErrCond(o.nsteps >= Global.Sim.Solver.REnssmax, "RE: max number of steps reached: %d", o.nsteps) { return } // backup domain d.backup() // single step with Δt d.Sol.T = t + o.Δt o.diverging, ok = run_iterations(t+o.Δt, o.Δt, d, s) if !ok { return } if Global.Sim.Solver.DvgCtrl { if o.divergence_control(d, "big step") { continue } } // save intermediate state for i := 0; i < d.Ny; i++ { o.Y_big[i] = d.Sol.Y[i] } // restore initial state d.restore() // 1st halved step d.Sol.T = t + o.Δt/2.0 o.diverging, ok = run_iterations(t+o.Δt/2.0, o.Δt/2.0, d, s) if !ok { break } if Global.Sim.Solver.DvgCtrl { if o.divergence_control(d, "1st half step") { continue } } // 2nd halved step d.Sol.T = t + o.Δt o.diverging, ok = run_iterations(t+o.Δt, o.Δt/2.0, d, s) if !ok { break } if Global.Sim.Solver.DvgCtrl { if o.divergence_control(d, "2nd half step") { continue } } // Richardson's extrapolation error rerr := la.VecRmsError(d.Sol.Y, o.Y_big, atol, rtol, d.Sol.Y) / 3.0 // step size change m := min(mmax, max(mmin, mfac*math.Pow(1.0/rerr, 1.0/2.0))) ΔtNew := m * o.Δt // accepted if rerr < 1.0 { // update variables o.naccept += 1 t += o.Δt d.Sol.T = t // output if Global.Verbose { if !Global.Sim.Data.ShowR && !Global.Debug { io.PfWhite("%30.15f\r", t) } } //if true { if t >= tout || o.laststep { s.OutTimes = append(s.OutTimes, t) if !d.Out(*tidx) { return } tout += DtOut.F(t, nil) *tidx += 1 } // reached final time if o.laststep { if Global.Verbose { io.Pfgreen("\n\nRichardson extrapolation succeeded\n") } return true } // predictive controller of Gustafsson if !Global.Sim.Solver.REnogus { if o.naccept > 1 { m = mfac * (o.Δt / ΔtOld) * math.Sqrt(1.0/rerr) * math.Sqrt(rerrOld/rerr) if m*o.Δt < ΔtNew { o.ngustaf += 1 } ΔtNew = min(ΔtNew, m*o.Δt) } ΔtOld = o.Δt rerrOld = max(0.9, rerr) // 1e-2 } // next step size if o.reject { // do not alow Δt to grow if previous was a reject ΔtNew = min(o.Δt, ΔtNew) } o.reject = false o.Δt = ΔtNew if t+ΔtNew-tf >= 0.0 { o.laststep = true o.Δt = tf - t } // rejected } else { // restore state d.restore() // set flags o.nreject += 1 o.reject = true o.laststep = false // next step size o.Δt = ΔtNew if t+o.Δt > tf { o.Δt = tf - t } } } return true }
func (o *RichardsonExtrap) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, dbgKb DebugKb_t) (err error) { // constants dat := o.doms[0].Sim.Solver atol := dat.REatol rtol := dat.RErtol mmin := dat.REmmin mmax := dat.REmmax mfac := dat.REmfac // control t := o.doms[0].Sol.T tout := t + dtoFunc.F(t, nil) steady := o.doms[0].Sim.Data.Steady // first output if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } // domain and variables d := o.doms[0] o.Y_big = make([]float64, d.Ny) // time loop o.Δt = dtFunc.F(t, nil) o.Δtcpy = o.Δt var ΔtOld, rerrOld float64 for t < tf { // check for continued divergence if o.ndiverg >= dat.NdvgMax { return chk.Err("continuous divergence after %d steps reached", o.ndiverg) } // check time increment if o.Δt < dat.DtMin { return chk.Err("Δt increment is too small: %g < %g", o.Δt, dat.DtMin) } // dynamic coefficients if !steady { err = o.dc.CalcBoth(o.Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients:\n%v", err) } } // check for maximum number of substeps o.nsteps += 1 if o.nsteps >= dat.REnssmax { return chk.Err("RE: max number of steps reached: %d", o.nsteps) } // backup domain d.backup() // single step with Δt d.Sol.T = t + o.Δt d.Sol.Dt = o.Δt o.diverging, err = run_iterations(t+o.Δt, o.Δt, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("single step with Δt: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "big step", verbose) { continue } } // save intermediate state for i := 0; i < d.Ny; i++ { o.Y_big[i] = d.Sol.Y[i] } // restore initial state d.restore() // 1st halved step d.Sol.T = t + o.Δt/2.0 d.Sol.Dt = o.Δt / 2.0 o.diverging, err = run_iterations(t+o.Δt/2.0, o.Δt/2.0, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("1st halved step: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "1st half step", verbose) { continue } } // 2nd halved step d.Sol.T = t + o.Δt d.Sol.Dt = o.Δt o.diverging, err = run_iterations(t+o.Δt, o.Δt/2.0, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("2nd halved step: run_iterations failed:\n%v", err) } if dat.DvgCtrl { if o.divergence_control(d, "2nd half step", verbose) { continue } } // Richardson's extrapolation error rerr := la.VecRmsError(d.Sol.Y, o.Y_big, atol, rtol, d.Sol.Y) / 3.0 // step size change m := utl.Min(mmax, utl.Max(mmin, mfac*math.Pow(1.0/rerr, 1.0/2.0))) ΔtNew := m * o.Δt // accepted if rerr < 1.0 { // update variables o.naccept += 1 t += o.Δt d.Sol.T = t // output if verbose { if !dat.ShowR { io.PfWhite("%30.15f\r", t) } } if t >= tout || o.laststep { if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } tout += dtoFunc.F(t, nil) } // reached final time if o.laststep { if verbose { io.Pfgreen("\n\nRichardson extrapolation succeeded\n") } return } // predictive controller of Gustafsson if !dat.REnogus { if o.naccept > 1 { m = mfac * (o.Δt / ΔtOld) * math.Sqrt(1.0/rerr) * math.Sqrt(rerrOld/rerr) if m*o.Δt < ΔtNew { o.ngustaf += 1 } ΔtNew = utl.Min(ΔtNew, m*o.Δt) } ΔtOld = o.Δt rerrOld = utl.Max(0.9, rerr) // 1e-2 } // next step size if o.reject { // do not alow Δt to grow if previous was a reject ΔtNew = utl.Min(o.Δt, ΔtNew) } o.reject = false o.Δt = ΔtNew if t+ΔtNew-tf >= 0.0 { o.laststep = true o.Δt = tf - t } // rejected } else { // restore state d.restore() // set flags o.nreject += 1 o.reject = true o.laststep = false // next step size o.Δt = ΔtNew if t+o.Δt > tf { o.Δt = tf - t } } } return }
func main() { // finalise analysis process and catch errors defer out.End() // input data simfn := "data/twoqua4.sim" exnwl := false stgidx := 0 // parse flags flag.Parse() if len(flag.Args()) > 0 { simfn = flag.Arg(0) } if len(flag.Args()) > 1 { exnwl = io.Atob(flag.Arg(1)) } if len(flag.Args()) > 2 { stgidx = io.Atoi(flag.Arg(2)) } // check extension if io.FnExt(simfn) == "" { simfn += ".sim" } // print input data io.Pf("\nInput data\n") io.Pf("==========\n") io.Pf(" simfn = %30s // simulation filename\n", simfn) io.Pf(" exnwl = %30v // extrapolate nwl\n", exnwl) io.Pf(" stgidx = %30v // stage index\n", stgidx) io.Pf("\n") // start analysis process out.Start(simfn, stgidx, 0) // global variables ndim = out.Dom.Msh.Ndim verts = out.Dom.Msh.Verts cells = out.Dom.Msh.Cells nodes = out.Dom.Nodes elems = out.Dom.Elems dirout = fem.Global.Sim.Data.DirOut fnkey = fem.Global.Sim.Data.FnameKey steady = fem.Global.Sim.Data.Steady // flags has_u := out.Dom.YandC["ux"] has_pl := out.Dom.YandC["pl"] has_pg := out.Dom.YandC["pg"] has_sig := out.Ipkeys["sx"] has_nwl := out.Ipkeys["nwlx"] has_p := has_pl || has_pg lbb := has_u && has_p if fem.Global.Sim.Data.NoLBB { lbb = false } // buffers pvd := make(map[string]*bytes.Buffer) geo := make(map[string]*bytes.Buffer) vtu := make(map[string]*bytes.Buffer) if _, ok := out.Dom.YandC["ux"]; ok { pvd["u"] = new(bytes.Buffer) geo["u"] = new(bytes.Buffer) vtu["u"] = new(bytes.Buffer) } if _, ok := out.Dom.YandC["fl"]; ok { pvd["fl"] = new(bytes.Buffer) geo["fl"] = new(bytes.Buffer) vtu["fl"] = new(bytes.Buffer) } if _, ok := out.Dom.YandC["pl"]; ok { pvd["pl"] = new(bytes.Buffer) geo["pl"] = new(bytes.Buffer) vtu["pl"] = new(bytes.Buffer) } if _, ok := out.Dom.YandC["pg"]; ok { pvd["pg"] = new(bytes.Buffer) geo["pg"] = new(bytes.Buffer) vtu["pg"] = new(bytes.Buffer) } if len(out.Ipkeys) > 0 { pvd["ips"] = new(bytes.Buffer) geo["ips"] = new(bytes.Buffer) vtu["ips"] = new(bytes.Buffer) } if exnwl { pvd["ex_nwl"] = new(bytes.Buffer) geo["ex_nwl"] = new(bytes.Buffer) vtu["ex_nwl"] = new(bytes.Buffer) } // extrapolated values keys extrap_keys := []string{"nwlx", "nwly"} if ndim == 3 { extrap_keys = []string{"nwlx", "nwly", "nwlz"} } // headers for _, b := range pvd { pvd_header(b) } // process results for tidx, t := range out.Sum.OutTimes { // input results into domain if !out.Dom.In(out.Sum, tidx, true) { chk.Panic("cannot load results into domain; please check log file") } // message io.PfWhite("time = %g\r", t) // generate topology if tidx == 0 { for label, b := range geo { topology(b, label == "ips", lbb) } // allocate integration points values ipvals = make([]map[string]float64, len(out.Ipoints)) for i, _ := range out.Ipoints { ipvals[i] = make(map[string]float64) } } // get integration points values @ time t for i, p := range out.Ipoints { vals := p.Calc(out.Dom.Sol) for key, val := range vals { ipvals[i][key] = val } } // compute extrapolated values if exnwl { out.ComputeExtrapolatedValues(extrap_keys) } // for each data buffer for label, b := range vtu { // reset buffer b.Reset() // points data if label == "ips" { pdata_open(b) if has_sig { pdata_write(b, "sig", skeys, true) } if has_nwl { pdata_write(b, "nwl", nwlkeys, true) } for key, _ := range out.Ipkeys { if !is_sig[key] && !is_nwl[key] { pdata_write(b, key, []string{key}, true) } } pdata_close(b) } else { pdata_open(b) pdata_write(b, label, label2keys[label], false) pdata_close(b) } // cells data cdata_write(b, label == "ips") // write vtu file vtu_write(geo[label], b, tidx, label) } // pvd for label, b := range pvd { pvd_line(b, tidx, t, label) } } // write pvd files for label, b := range pvd { pvd_write(b, label) } }
func (o *SolverImplicit) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, dbgKb DebugKb_t) (err error) { // auxiliary md := 1.0 // time step multiplier if divergence control is on ndiverg := 0 // number of steps diverging // control t := o.doms[0].Sol.T dat := o.doms[0].Sim.Solver tout := t + dtoFunc.F(t, nil) steady := o.doms[0].Sim.Data.Steady // first output if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } // time loop var Δt float64 var lasttimestep bool for t < tf { // check for continued divergence if ndiverg >= dat.NdvgMax { return chk.Err("continuous divergence after %d steps reached", ndiverg) } // time increment Δt = dtFunc.F(t, nil) * md if t+Δt >= tf { lasttimestep = true } if Δt < dat.DtMin { if md < 1 { return chk.Err("Δt increment is too small: %g < %g", Δt, dat.DtMin) } } t += Δt // dynamic coefficients if !steady { err = o.dc.CalcBoth(Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients") } } // message if verbose { if !dat.ShowR { io.PfWhite("%30.15f\r", t) } } // for all domains docontinue := false for _, d := range o.doms { // backup solution if divergence control is on if dat.DvgCtrl { d.backup() } // run iterations d.Sol.T = t d.Sol.Dt = Δt diverging, err := run_iterations(t, Δt, d, o.dc, o.sum, dbgKb) if err != nil { return chk.Err("run_iterations failed:\n%v", err) } // restore solution and reduce time step if divergence control is on if dat.DvgCtrl { if diverging { if verbose { io.Pfred(". . . iterations diverging (%2d) . . .\n", ndiverg+1) } d.restore() t -= Δt d.Sol.T = t md *= 0.5 ndiverg += 1 docontinue = true break } ndiverg = 0 md = 1.0 } } if docontinue { continue } // perform output if t >= tout || lasttimestep { if o.sum != nil { err = o.sum.SaveDomains(t, o.doms, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } tout += dtoFunc.F(t, nil) } } return }
func (o *SolverLinearImplicit) Run(tf float64, dtFunc, dtoFunc fun.Func, verbose bool, notused DebugKb_t) (err error) { // control t := o.dom.Sol.T tout := t + dtoFunc.F(t, nil) steady := o.dom.Sim.Data.Steady // first output if o.sum != nil { err = o.sum.SaveDomains(t, []*Domain{o.dom}, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } // auxiliary variables Y := o.dom.Sol.Y ψ := o.dom.Sol.Psi ζ := o.dom.Sol.Zet χ := o.dom.Sol.Chi dydt := o.dom.Sol.Dydt d2ydt2 := o.dom.Sol.D2ydt2 // time loop first := true var Δt float64 var lasttimestep bool for t < tf { // time increment Δt = dtFunc.F(t, nil) if t+Δt >= tf { lasttimestep = true } t += Δt // update time variable in solution array o.dom.Sol.T = t o.dom.Sol.Dt = Δt // dynamic coefficients if !steady { err = o.dc.CalcBoth(Δt) if err != nil { return chk.Err("cannot compute dynamic coefficients") } } // message if verbose { io.PfWhite("%30.15f\r", t) } // calculate global starred vectors and interpolate starred variables from nodes to integration points if !steady { // compute starred vectors for _, I := range o.dom.T1eqs { ψ[I] = Y[I] - o.dom.Sol.ΔY[I] } for _, I := range o.dom.T2eqs { ζ[I] = Y[I] χ[I] = Y[I] } // set internal starred variables for _, e := range o.dom.Elems { err = e.InterpStarVars(o.dom.Sol) if err != nil { err = chk.Err("cannot compute starred variables:\n%v", err) return } } } // solve linear problem err := solve_linear_problem(t, o.dom, o.dc, o.sum, first) if err != nil { return chk.Err("solve_linear_problem failed:\n%v", err) } first = false // update velocity and acceleration if !steady { for _, I := range o.dom.T1eqs { dydt[I] = Y[I] - ψ[I] } for _, I := range o.dom.T2eqs { dydt[I] = o.dc.α4*Y[I] - χ[I] d2ydt2[I] = o.dc.α1*Y[I] - ζ[I] } } // perform output if t >= tout || lasttimestep { if o.sum != nil { err = o.sum.SaveDomains(t, []*Domain{o.dom}, false) if err != nil { return chk.Err("cannot save results:\n%v", err) } } tout += dtoFunc.F(t, nil) } } return }