func benchmarkComputationStep(stepName string, prepareIntegration computationStep, implementations []namedImplementation) { const TIME string = "Time" const NORMALIZED_TIME string = "Time/n" var resultTables = make([]util.Table, 0, len(problemVariants)) for i_problem := range problemVariants { prob := problemVariants[i_problem] var result = util.Table{ Title: fmt.Sprintf("%v - %v", stepName, prob.Name), RowHeaders: make([]string, 0, len(implementations)), ColHeaders: make([]string, 0, len(sizeVariants)), Data: map[string][][]float64{ TIME: util.MakeRectangular(uint(len(implementations)), uint(len(sizeVariants))), NORMALIZED_TIME: util.MakeRectangular(uint(len(implementations)), uint(len(sizeVariants))), }, } for j_size := range sizeVariants { s := sizeVariants[j_size] pConfig := prob.Constructor(s) for k_impl := range implementations { variant := implementations[k_impl] p, in, _ := setupBenchmark(pConfig) prepareIntegration(p, &in) if k_impl == 0 { result.ColHeaders = append(result.ColHeaders, strconv.Itoa(int(in.n))) } if j_size == 0 { result.RowHeaders = append(result.RowHeaders, variant.Name) } benchResult := testing.Benchmark( func(b *testing.B) { for i := 0; i < b.N; i++ { variant.Impl(p, &in) } }) time := benchResult.NsPerOp() result.Data[TIME][k_impl][j_size] = float64(time) result.Data[NORMALIZED_TIME][k_impl][j_size] = float64(time) / float64(in.n) } } resultTables = append(resultTables, result) } util.WriteTablesFile(resultTables, fmt.Sprintf("%s.html", stepName)) }
func (p *peer) setupIntegration(t, tEnd float64, yT []float64, c *Config) (i integration) { i.n = uint(len(yT)) // set default parameters if necessary if c.MaxStepSize <= 0.0 { c.MaxStepSize = tEnd - t } if c.MinStepSize <= 0.0 { c.MinStepSize = 1e-10 } if c.MaxStepCount == 0 { c.MaxStepCount = 1000000 } if c.AbsoluteTolerance <= 0.0 { c.AbsoluteTolerance = 1e-4 } if c.RelativeTolerance <= 0.0 { c.RelativeTolerance = c.AbsoluteTolerance } i.Config = *c // allocate temp matrices i.errorFactors = make([]float64, i.n) i.pa = util.MakeSquare(p.Stages) i.yNew = util.MakeRectangular(p.Stages, i.n) i.yOld = util.MakeRectangular(p.Stages, i.n) i.fNew = util.MakeRectangular(p.Stages, i.n) i.fOld = util.MakeRectangular(p.Stages, i.n) copy(i.yOld[p.indexMinNode], yT) i.stepRatioMin = 0.2 return }
//-- performs Runge-Kutta integration func (r *rk) Integrate(t, tEnd float64, yT []float64, c *Config) (stat Statistics, err error) { var n uint = uint(len(yT)) err = c.ValidateAndPrepare(n) if err != nil { return } // set default parameters if necessary if c.MaxStepSize <= 0.0 { c.MaxStepSize = tEnd - t } if c.MinStepSize <= 0.0 { c.MinStepSize = 1e-10 } if c.MaxStepCount == 0 { c.MaxStepCount = 1000000 } if c.AbsoluteTolerance <= 0.0 { c.AbsoluteTolerance = 1e-4 } if c.RelativeTolerance <= 0.0 { c.RelativeTolerance = c.AbsoluteTolerance } if r.a == nil || r.b == nil || r.c == nil { err = errors.New("RK Method coefficients not initialized") return } // allocate temp matrices fcnValue := make([]float64, n) yCurrent := make([]float64, n) yError := make([]float64, n) ks := util.MakeRectangular(r.Stages, uint(n)) c.Fcn(t, yT, fcnValue) stat.EvaluationCount = 1 // compute initial step size if not set stepEstimate := c.InitialStepSize if stepEstimate <= 0.0 { stepEstimate = EstimateStepSize(t, yT, fcnValue, c, r.Order) } var stepNext float64 // repeat until tend for t < tEnd && err == nil { // Set new step size stepNext = stepEstimate stat.StepCount++ if t+stepNext > tEnd { stepNext = tEnd - t } // compute stages var stg, id, ic uint for stg = 1; stg < r.Stages; stg++ { tCurrent := t + stepNext*r.c[stg] for id = 0; id < n; id++ { yCurrent[id] = yT[id] + stepNext*r.a[stg][0]*fcnValue[id] } for ic = 1; ic < stg; ic++ { for id = 0; id < n; id++ { yCurrent[id] = yCurrent[id] + stepNext*r.a[stg][ic]*ks[ic][id] } } var block uint for block = 0; block < n; block += c.BlockSize { c.FcnBlocked(block, c.BlockSize, tCurrent, yCurrent, ks[stg]) } stat.EvaluationCount++ } // compute error estimate: for id = 0; id < n; id++ { yError[id] = stepNext * r.e[0] * fcnValue[id] } for stg = 1; stg < r.Stages; stg++ { for id = 0; id < n; id++ { yError[id] = yError[id] + stepNext*r.e[stg]*ks[stg][id] } } // compute error quotient relativeError := 0.0 for id = 0; id < n; id++ { currentTolerance := c.AbsoluteTolerance + c.RelativeTolerance*math.Abs(yT[id]) relativeError = relativeError + math.Pow(yError[id]/currentTolerance, 2.0) } relativeError = math.Sqrt(relativeError / float64(n)) // new stepsize estimate stepEstimate = 0.9 * math.Exp(-math.Log(1.0e-8+relativeError)/float64(r.Order)) stepEstimate = stepNext * math.Max(0.2, math.Min(stepEstimate, 2.0)) // safety interval // reject step if relativeError > 1.0 { stat.RejectedCount++ // report failure, step size too small if stepEstimate < c.MinStepSize { err = errors.New("stepsize too small") break } } else { // accept step and compute new solution t += stepNext for id = 0; id < n; id++ { yT[id] = yT[id] + stepNext*r.b[0]*fcnValue[id] } for stg = 1; stg < r.Stages; stg++ { for id = 0; id < n; id++ { yT[id] = yT[id] + stepNext*r.b[stg]*ks[stg][id] } } // cancel after first step if c.OneStepOnly { break } else { if r.firstStageAsLast { copy(fcnValue, ks[r.Stages-1]) } else { c.Fcn(t, yT, fcnValue) stat.EvaluationCount++ } } } // failure, too many steps if stat.StepCount > c.MaxStepCount { err = errors.New("maximum step count exceeded") break } } stat.CurrentTime = t stat.LastStepSize = stepNext stat.NextStepSize = stepEstimate return }