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))
}
예제 #2
0
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
}
예제 #3
0
//-- 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

}