changeset 4343:63c25eb9c07c

FA: be optimistic about missing data. According to clarification, missing data has to be interpreted as the best case, this is, because the services do not provide data for bottlenecks, which are not considered a limitating factor on the water way at a given time.
author Sascha Wilde <wilde@intevation.de>
date Fri, 06 Sep 2019 17:22:42 +0200
parents 6a1fef54d49f
children 6ac94171a994
files pkg/controllers/bottlenecks.go pkg/controllers/stretches.go
diffstat 2 files changed, 63 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/controllers/bottlenecks.go	Fri Sep 06 16:17:36 2019 +0200
+++ b/pkg/controllers/bottlenecks.go	Fri Sep 06 17:22:42 2019 +0200
@@ -10,6 +10,7 @@
 //
 // Author(s):
 //  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+//  * Sascha Wilde <wilde@intevation.de>
 
 package controllers
 
@@ -131,6 +132,42 @@
 	}
 }
 
+// According to clarification, it has to be assumed, that at times
+// with no data, the best case (which by convention is the highest
+// class created by classify()) should be assumed.  That is due to the
+// fact, that at times where bottlenecks are ot a limiting factor on
+// the waterway, services don't brovide any data for the bottleneck in
+// question.
+//
+// FIXME: A potentional improvement could be to intercest the time
+// ranges with the time ranges where bottlenecks were "active" (this
+// _might_ be derivable fromt the validity periods in the bottleneck
+// data.  So it _might_ be possible do detect actual missing data (BN
+// valid, but no data from FA service).  Anyway, this is left out for
+// now, as many clarification regarding the base assumtions would bee
+// needed and the results still might be unrelyable.
+func optimisticPadClassification(
+	from, to time.Time,
+	classified []time.Duration,
+) []time.Duration {
+	var actualDuration time.Duration
+	maxDuration := to.Sub(from)
+
+	for i := 0; i < len(classified); i++ {
+		actualDuration += classified[i]
+	}
+
+	delta := maxDuration - actualDuration
+	if delta > 0 {
+		log.Printf("info: time interval: (%v - %v)\n", from, to)
+		log.Printf("info: found only data for %.2f hours, padding by %.2f hours\n",
+			actualDuration.Hours(), delta.Hours())
+		classified[len(classified)-1] = classified[len(classified)-1] + delta
+	}
+	
+	return classified
+}
+
 func (measurements availMeasurements) classify(
 	from, to time.Time,
 	breaks []float64,
@@ -158,7 +195,7 @@
 	})
 
 	if idx >= len(measurements) {
-		return result
+		return optimisticPadClassification(from, to, result)
 	}
 
 	// Be safe for interpolation.
@@ -173,7 +210,7 @@
 		p2 := &measurements[i+1]
 
 		if p1.when.After(to) {
-			return result
+			return optimisticPadClassification(from, to, result)
 		}
 
 		if p2.when.Before(from) {
@@ -214,7 +251,7 @@
 		}
 	}
 
-	return result
+	return optimisticPadClassification(from, to, result)
 }
 
 func orderTime(a, b time.Time) (time.Time, time.Time) {
@@ -482,7 +519,13 @@
 
 	interval := intervals[mode](from, to)
 
+	now := time.Now()
 	for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() {
+		// Don't interpolate for the future
+		if now.Sub(pto) < 0 {
+			pto = now
+		}
+
 		lnwl := ms.classify(
 			pfrom, pto,
 			ldcRefs,
@@ -638,7 +681,12 @@
 
 	interval := intervals[mode](from, to)
 
+	now := time.Now()
 	for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() {
+		// Don't interpolate for the future
+		if now.Sub(pto) < 0 {
+			pto = now
+		}
 
 		ldc := ms.classify(
 			pfrom, pto,
--- a/pkg/controllers/stretches.go	Fri Sep 06 16:17:36 2019 +0200
+++ b/pkg/controllers/stretches.go	Fri Sep 06 17:22:42 2019 +0200
@@ -279,7 +279,13 @@
 
 				var ldc, breaks []time.Duration
 
+				now := time.Now()
 				for _, bn := range loaded {
+					// Don't interpolate for the future
+					if now.Sub(res.to) < 0 {
+						res.to = now
+					}
+
 					l := bn.measurements.classify(
 						res.from, res.to,
 						bn.ldc,
@@ -539,7 +545,13 @@
 			for res := range jobCh {
 				var ldc, breaks []time.Duration
 
+				now := time.Now()
 				for _, bn := range loaded {
+					// Don't interpolate for the future
+					if now.Sub(res.to) < 0 {
+						res.to = now
+					}
+
 					l := bn.measurements.classify(
 						res.from, res.to,
 						bn.ldc,