Mercurial > gemma
diff pkg/controllers/bottlenecks.go @ 3367:ecb4baa2be1a
Simplified waterlevel classification.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Wed, 22 May 2019 10:47:04 +0200 |
parents | 146bf3a1752c |
children | ac630f0f5dbf |
line wrap: on
line diff
--- a/pkg/controllers/bottlenecks.go Wed May 22 09:33:40 2019 +0200 +++ b/pkg/controllers/bottlenecks.go Wed May 22 10:47:04 2019 +0200 @@ -124,130 +124,70 @@ return float64(measurement.value) } -func (measurements availMeasurements) classifyAvailMeasurements( +func (measurements availMeasurements) classify( from, to time.Time, - classes []referenceValue, + breaks []referenceValue, access func(*availMeasurement) float64, ) []time.Duration { - type classValues struct { - when time.Time - kind common.ValueRangeKind - } - - //var invalid time.Duration - result := make([]time.Duration, len(classes)+1) - - if len(measurements) == 0 || - to.Before(measurements[0].when) || - from.After(measurements[len(measurements)-1].when) { - return result + if len(breaks) == 0 { + return []time.Duration{} } - cvs := make([]classValues, len(classes)) + result := make([]time.Duration, len(breaks)+1) + classes := make([]float64, len(breaks)+2) + values := make([]time.Time, len(classes)) - classify := func(v func(float64) (time.Time, common.ValueRangeKind)) { - for i := range classes { - cvs[i].when, cvs[i].kind = v(classes[i].value) - } + // Add sentinels + classes[0] = breaks[0].value - 9999 + classes[len(classes)-1] = breaks[len(breaks)-1].value + 9999 + for i := range breaks { + classes[i+1] = breaks[i].value } - vbt := func(p1, p2 *availMeasurement) func(time.Time) (float64, common.ValueRangeKind) { - return common.InterpolateValueByTime(p1.when, access(p1), p2.when, access(p2)) - } - - // var total time.Duration - -pairs: for i := 0; i < len(measurements)-1; i++ { p1 := &measurements[i] p2 := &measurements[i+1] - var start, end time.Time - - switch { - case !p2.when.After(p1.when): - // Segment invalid - // log.Println("invalid") - continue pairs + if p1.when.After(to) { + return result + } - case p1.when.After(to) || p2.when.Before(from): - // Segment complete outside. - // log.Println("complete outside") - continue pairs - - case (p1.when.Before(from) || p1.when.Equal(from)) && (to.Before(p2.when) || to.Equal(p2.when)): - // log.Println("(from, to) complete inside current interval") - v := vbt(p1, p2) - f, _ := v(from) - t, _ := v(to) - classify(common.InterpolateTimeByValue(from, f, to, t)) - start, end = from, to + if p2.when.Before(from) { + continue + } - case (from.Before(p1.when) || from.Equal(p1.when)) && (p2.when.Before(to) || p2.when.Equal(to)): - //log.Println("current interval complete inside (from, to)") - classify(common.InterpolateTimeByValue( - p1.when, access(p1), - p2.when, access(p2), - )) - start, end = p1.when, p2.when + f := common.InterpolateTime( + p1.when, access(p1), + p2.when, access(p2), + ) - case p1.when.After(from): - // log.Println("p1 > from") - pt := minTime(to, p2.when) - t, _ := vbt(p1, p2)(pt) - classify(common.InterpolateTimeByValue( - p1.when, access(p1), - pt, t, - )) - start, end = p1.when, pt - - case p2.when.Before(to): - // log.Println("p2 < to") - pf := maxTime(from, p1.when) - f, _ := vbt(p1, p2)(pf) - classify(common.InterpolateTimeByValue( - pf, f, - p2.when, access(p2), - )) - start, end = pf, p2.when - - default: - log.Printf("warn: unexpected case. That should not happen. %v - %v, %v - %v\n", - p1.when, p2.when, from, to) - continue pairs + for j, c := range classes { + values[j] = f(c) } - // total += end.Sub(start) + for j := 0; j < len(values)-1; j++ { + start, end := orderTime(values[j], values[j+1]) - for i := len(cvs) - 1; i >= 0; i-- { - switch cvs[i].kind { - case common.ValueAbove: - result[i+1] += end.Sub(start) - continue pairs + lo, hi := maxTime(p1.when, from), minTime(p2.when, to) - case common.ValueInside: - // -> split - if access(p1) < classes[i].value { - // started below -> second part above - diff := absDuration(end.Sub(cvs[i].when)) - result[i+1] += diff - end = cvs[i].when - } else { - // started above -> first part above - diff := absDuration(cvs[i].when.Sub(start)) - result[i+1] += diff - start = cvs[i].when - } + if start.After(hi) || end.Before(lo) { + continue } + + start, end = maxTime(start, lo), minTime(end, hi) + result[j] += end.Sub(start) } - result[0] += end.Sub(start) } - // log.Printf("total all: %f\n", to.Sub(from).Hours()) - // log.Printf("total: %f\n", total.Hours()) + return result +} - return result +func orderTime(a, b time.Time) (time.Time, time.Time) { + if a.Before(b) { + return a, b + } + return b, a } func minTime(a, b time.Time) time.Time { @@ -264,14 +204,6 @@ return b } -func absDuration(x time.Duration) time.Duration { - if x < 0 { - log.Printf("warn: negative duration %v\n", x) - return -x - } - return x -} - func durationsToPercentage(from, to time.Time, classes []time.Duration) []float64 { percents := make([]float64, len(classes)) total := 100 / to.Sub(from).Seconds() @@ -353,6 +285,7 @@ case err != nil: return nil, err } + log.Printf("info: LDC = %.2f\n", value) return []referenceValue{{0, value}}, nil } @@ -486,13 +419,13 @@ return } - lnwl := ms.classifyAvailMeasurements( + lnwl := ms.classify( from, to, lnwlRefs, (*availMeasurement).getValue, ) - afd := ms.classifyAvailMeasurements( + afd := ms.classify( from, to, afdRefs, (*availMeasurement).getDepth, @@ -667,41 +600,29 @@ return } - // log.Println(len(ms)) + //log.Println(len(ms)) //for i := range ms { // log.Println(ms[i].when, ms[i].depth) //} - interval := intervals[mode](from, to) + log.Printf("info: measurements: %d\n", len(ms)) + if len(ms) > 1 { + log.Printf("info: first: %v\n", ms[0].when) + log.Printf("info: last: %v\n", ms[len(ms)-1].when) + log.Printf("info: interval: %.2f [h]\n", ms[len(ms)-1].when.Sub(ms[0].when).Hours()) + } - //log.Printf("first: %v\n", ms[0].when) - //log.Printf("last: %v\n", ms[len(ms)-1].when) + interval := intervals[mode](from, to) for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { - samples := ms - - /* - //log.Printf("pfrom: %v\n", pfrom) - - // Find good starting point - idx := sort.Search(len(ms), func(i int) bool { - return !ms[i].when.Before(pfrom) - }) - //log.Printf("%d\n", idx) - if idx > 0 { - idx-- - } - samples := ms[idx:] - */ - - ranges := samples.classifyAvailMeasurements( + ranges := ms.classify( pfrom, pto, afdRefs, (*availMeasurement).getDepth, ) - ldc := samples.classifyAvailMeasurements( + ldc := ms.classify( pfrom, pto, ldcRefs, (*availMeasurement).getDepth,