Mercurial > gemma
comparison pkg/controllers/bottlenecks.go @ 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 | f543f9d4a0b5 |
children | 6ac94171a994 |
comparison
equal
deleted
inserted
replaced
4342:6a1fef54d49f | 4343:63c25eb9c07c |
---|---|
8 // – Österreichische Wasserstraßen-Gesellschaft mbH | 8 // – Österreichische Wasserstraßen-Gesellschaft mbH |
9 // Software engineering by Intevation GmbH | 9 // Software engineering by Intevation GmbH |
10 // | 10 // |
11 // Author(s): | 11 // Author(s): |
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de> | 12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de> |
13 // * Sascha Wilde <wilde@intevation.de> | |
13 | 14 |
14 package controllers | 15 package controllers |
15 | 16 |
16 import ( | 17 import ( |
17 "context" | 18 "context" |
129 log.Printf("warn: unknown limitation '%s'. default to 'depth'\n", limiting) | 130 log.Printf("warn: unknown limitation '%s'. default to 'depth'\n", limiting) |
130 return (*availMeasurement).getDepth | 131 return (*availMeasurement).getDepth |
131 } | 132 } |
132 } | 133 } |
133 | 134 |
135 // According to clarification, it has to be assumed, that at times | |
136 // with no data, the best case (which by convention is the highest | |
137 // class created by classify()) should be assumed. That is due to the | |
138 // fact, that at times where bottlenecks are ot a limiting factor on | |
139 // the waterway, services don't brovide any data for the bottleneck in | |
140 // question. | |
141 // | |
142 // FIXME: A potentional improvement could be to intercest the time | |
143 // ranges with the time ranges where bottlenecks were "active" (this | |
144 // _might_ be derivable fromt the validity periods in the bottleneck | |
145 // data. So it _might_ be possible do detect actual missing data (BN | |
146 // valid, but no data from FA service). Anyway, this is left out for | |
147 // now, as many clarification regarding the base assumtions would bee | |
148 // needed and the results still might be unrelyable. | |
149 func optimisticPadClassification( | |
150 from, to time.Time, | |
151 classified []time.Duration, | |
152 ) []time.Duration { | |
153 var actualDuration time.Duration | |
154 maxDuration := to.Sub(from) | |
155 | |
156 for i := 0; i < len(classified); i++ { | |
157 actualDuration += classified[i] | |
158 } | |
159 | |
160 delta := maxDuration - actualDuration | |
161 if delta > 0 { | |
162 log.Printf("info: time interval: (%v - %v)\n", from, to) | |
163 log.Printf("info: found only data for %.2f hours, padding by %.2f hours\n", | |
164 actualDuration.Hours(), delta.Hours()) | |
165 classified[len(classified)-1] = classified[len(classified)-1] + delta | |
166 } | |
167 | |
168 return classified | |
169 } | |
170 | |
134 func (measurements availMeasurements) classify( | 171 func (measurements availMeasurements) classify( |
135 from, to time.Time, | 172 from, to time.Time, |
136 breaks []float64, | 173 breaks []float64, |
137 access func(*availMeasurement) float64, | 174 access func(*availMeasurement) float64, |
138 ) []time.Duration { | 175 ) []time.Duration { |
156 // All values before from can be ignored. | 193 // All values before from can be ignored. |
157 return !measurements[i].when.Before(from) | 194 return !measurements[i].when.Before(from) |
158 }) | 195 }) |
159 | 196 |
160 if idx >= len(measurements) { | 197 if idx >= len(measurements) { |
161 return result | 198 return optimisticPadClassification(from, to, result) |
162 } | 199 } |
163 | 200 |
164 // Be safe for interpolation. | 201 // Be safe for interpolation. |
165 if idx > 0 { | 202 if idx > 0 { |
166 idx-- | 203 idx-- |
171 for i := 0; i < len(measurements)-1; i++ { | 208 for i := 0; i < len(measurements)-1; i++ { |
172 p1 := &measurements[i] | 209 p1 := &measurements[i] |
173 p2 := &measurements[i+1] | 210 p2 := &measurements[i+1] |
174 | 211 |
175 if p1.when.After(to) { | 212 if p1.when.After(to) { |
176 return result | 213 return optimisticPadClassification(from, to, result) |
177 } | 214 } |
178 | 215 |
179 if p2.when.Before(from) { | 216 if p2.when.Before(from) { |
180 continue | 217 continue |
181 } | 218 } |
212 start, end = maxTime(start, lo), minTime(end, hi) | 249 start, end = maxTime(start, lo), minTime(end, hi) |
213 result[j] += end.Sub(start) | 250 result[j] += end.Sub(start) |
214 } | 251 } |
215 } | 252 } |
216 | 253 |
217 return result | 254 return optimisticPadClassification(from, to, result) |
218 } | 255 } |
219 | 256 |
220 func orderTime(a, b time.Time) (time.Time, time.Time) { | 257 func orderTime(a, b time.Time) (time.Time, time.Time) { |
221 if a.Before(b) { | 258 if a.Before(b) { |
222 return a, b | 259 return a, b |
480 return | 517 return |
481 } | 518 } |
482 | 519 |
483 interval := intervals[mode](from, to) | 520 interval := intervals[mode](from, to) |
484 | 521 |
522 now := time.Now() | |
485 for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { | 523 for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { |
524 // Don't interpolate for the future | |
525 if now.Sub(pto) < 0 { | |
526 pto = now | |
527 } | |
528 | |
486 lnwl := ms.classify( | 529 lnwl := ms.classify( |
487 pfrom, pto, | 530 pfrom, pto, |
488 ldcRefs, | 531 ldcRefs, |
489 (*availMeasurement).getValue, | 532 (*availMeasurement).getValue, |
490 ) | 533 ) |
636 log.Printf("info: interval: %.2f [h]\n", ms[len(ms)-1].when.Sub(ms[0].when).Hours()) | 679 log.Printf("info: interval: %.2f [h]\n", ms[len(ms)-1].when.Sub(ms[0].when).Hours()) |
637 } | 680 } |
638 | 681 |
639 interval := intervals[mode](from, to) | 682 interval := intervals[mode](from, to) |
640 | 683 |
684 now := time.Now() | |
641 for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { | 685 for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { |
686 // Don't interpolate for the future | |
687 if now.Sub(pto) < 0 { | |
688 pto = now | |
689 } | |
642 | 690 |
643 ldc := ms.classify( | 691 ldc := ms.classify( |
644 pfrom, pto, | 692 pfrom, pto, |
645 ldcRefs, | 693 ldcRefs, |
646 access, | 694 access, |