comparison pkg/controllers/bottlenecks.go @ 3076:e0daeb05bf50

Display Available Fairway Depths vs. LNWL: Completed backend (untested).
author Sascha L. Teichmann <teichmann@intevation.de>
date Wed, 17 Apr 2019 15:04:28 +0200
parents a661e9b8f3b6
children c68cef0346b7
comparison
equal deleted inserted replaced
3075:3cf7189fa93e 3076:e0daeb05bf50
79 ) 79 )
80 ` 80 `
81 ) 81 )
82 82
83 type ( 83 type (
84 availReferenceValue struct { 84 referenceValue struct {
85 level int 85 level int
86 value float64 86 value float64
87 } 87 }
88 88
89 availMeasurement struct { 89 availMeasurement struct {
94 ) 94 )
95 95
96 func classifyAvailMeasurements( 96 func classifyAvailMeasurements(
97 from, to time.Time, 97 from, to time.Time,
98 measurements []availMeasurement, 98 measurements []availMeasurement,
99 classes []availReferenceValue, 99 classes []referenceValue,
100 access func(*availMeasurement) float64, 100 access func(*availMeasurement) float64,
101 ) []time.Duration { 101 ) []time.Duration {
102 102
103 type classValues struct { 103 type classValues struct {
104 when time.Time 104 when time.Time
201 } 201 }
202 202
203 return result 203 return result
204 } 204 }
205 205
206 func durationsToPercentage(from, to time.Time, classes []time.Duration) []float64 {
207 percents := make([]float64, len(classes))
208 total := 100 / to.Sub(from).Seconds()
209 for i, v := range classes {
210 percents[i] = v.Seconds() * total
211 }
212 return percents
213 }
214
206 func bottleneckAvailabilty( 215 func bottleneckAvailabilty(
207 _ interface{}, 216 _ interface{},
208 req *http.Request, 217 req *http.Request,
209 conn *sql.Conn, 218 conn *sql.Conn,
210 ) (jr JSONResult, err error) { 219 ) (jr JSONResult, err error) {
216 Message: "Missing objnam of bottleneck", 225 Message: "Missing objnam of bottleneck",
217 } 226 }
218 return 227 return
219 } 228 }
220 229
230 var from, to time.Time
231
232 if f := req.FormValue("from"); f != "" {
233 if from, err = time.Parse(common.TimeFormat, f); err != nil {
234 err = JSONError{
235 Code: http.StatusBadRequest,
236 Message: fmt.Sprintf("Invalid time format for 'from' field: %v", err),
237 }
238 return
239 }
240 from = from.UTC()
241 } else {
242 from = time.Now().AddDate(-1, 0, 0).UTC()
243 }
244
245 if t := req.FormValue("to"); t != "" {
246 if to, err = time.Parse(common.TimeFormat, t); err != nil {
247 err = JSONError{
248 Code: http.StatusBadRequest,
249 Message: fmt.Sprintf("Invalid time format for 'from' field: %v", err),
250 }
251 return
252 }
253 to = to.UTC()
254 } else {
255 to = from.AddDate(1, 0, 0).UTC()
256 }
257
258 if to.Before(from) {
259 to, from = from, to
260 }
261
262 log.Printf("info: time interval: (%v - %v)\n", from, to)
263
264 var los int
265 if l := req.FormValue("los"); l != "" {
266 if los, err = strconv.Atoi(l); err != nil {
267 err = JSONError{
268 Code: http.StatusBadRequest,
269 Message: fmt.Sprintf("Invalid value for field 'los': %v", err),
270 }
271 return
272 }
273 } else {
274 los = 1
275 }
276
221 ctx := req.Context() 277 ctx := req.Context()
222 278
223 loadReferenceValues := func() ([]availReferenceValue, error) { 279 loadLNWLReferenceValues := func() ([]referenceValue, error) {
224 rows, err := conn.QueryContext(ctx, selectGaugeLevelsSQL, bn) 280 rows, err := conn.QueryContext(ctx, selectGaugeLevelsSQL, bn)
225 if err != nil { 281 if err != nil {
226 return nil, err 282 return nil, err
227 } 283 }
228 defer rows.Close() 284 defer rows.Close()
229 285
230 var levels []availReferenceValue 286 var levels []referenceValue
231 287
232 loop: 288 loop:
233 for rows.Next() { 289 for rows.Next() {
234 var what string 290 var what string
235 var value int 291 var value int
251 if levels[i].level == level { 307 if levels[i].level == level {
252 levels[i].value = float64(value) 308 levels[i].value = float64(value)
253 continue loop 309 continue loop
254 } 310 }
255 } 311 }
256 levels = append(levels, availReferenceValue{ 312 levels = append(levels, referenceValue{
257 level: level, 313 level: level,
258 value: float64(value), 314 value: float64(value),
259 }) 315 })
260 } 316 }
261 317
266 sort.Slice(levels, func(i, j int) bool { return levels[i].level < levels[j].level }) 322 sort.Slice(levels, func(i, j int) bool { return levels[i].level < levels[j].level })
267 323
268 return levels, nil 324 return levels, nil
269 } 325 }
270 326
271 var refVals []availReferenceValue 327 var lnwlRefs []referenceValue
272 if refVals, err = loadReferenceValues(); err != nil { 328 if lnwlRefs, err = loadLNWLReferenceValues(); err != nil {
273 return 329 return
274 } 330 }
275 331
276 if len(refVals) == 0 { 332 if len(lnwlRefs) == 0 {
277 err = JSONError{ 333 err = JSONError{
278 Code: http.StatusNotFound, 334 Code: http.StatusNotFound,
279 Message: "No gauge reference values found for bottleneck", 335 Message: "No gauge reference values found for bottleneck",
280 } 336 }
281 }
282
283 var from, to time.Time
284
285 if f := req.FormValue("from"); f != "" {
286 if from, err = time.Parse(common.TimeFormat, f); err != nil {
287 err = JSONError{
288 Code: http.StatusBadRequest,
289 Message: fmt.Sprintf("Invalid time format for 'from' field: %v", err),
290 }
291 return
292 }
293 from = from.UTC()
294 } else {
295 from = time.Now().AddDate(-1, 0, 0).UTC()
296 }
297
298 if t := req.FormValue("to"); t != "" {
299 if to, err = time.Parse(common.TimeFormat, t); err != nil {
300 err = JSONError{
301 Code: http.StatusBadRequest,
302 Message: fmt.Sprintf("Invalid time format for 'from' field: %v", err),
303 }
304 return
305 }
306 to = to.UTC()
307 } else {
308 to = from.AddDate(1, 0, 0).UTC()
309 }
310
311 if to.Before(from) {
312 to, from = from, to
313 }
314
315 log.Printf("info: time interval: (%v - %v)\n", from, to)
316
317 var los int
318 if l := req.FormValue("los"); l != "" {
319 if los, err = strconv.Atoi(l); err != nil {
320 err = JSONError{
321 Code: http.StatusBadRequest,
322 Message: fmt.Sprintf("Invalid value for field 'los': %v", err),
323 }
324 return
325 }
326 } else {
327 los = 1
328 } 337 }
329 338
330 loadDepthValues := func() ([]availMeasurement, error) { 339 loadDepthValues := func() ([]availMeasurement, error) {
331 340
332 rows, err := conn.QueryContext( 341 rows, err := conn.QueryContext(
353 362
354 return ms, nil 363 return ms, nil
355 } 364 }
356 365
357 var ms []availMeasurement 366 var ms []availMeasurement
358
359 if ms, err = loadDepthValues(); err != nil { 367 if ms, err = loadDepthValues(); err != nil {
360 return 368 return
361 } 369 }
362 370
363 if len(ms) == 0 { 371 if len(ms) == 0 {
366 Message: "No available fairway depth values found", 374 Message: "No available fairway depth values found",
367 } 375 }
368 return 376 return
369 } 377 }
370 378
371 results := classifyAvailMeasurements( 379 lnwl := classifyAvailMeasurements(
372 from, to, 380 from, to,
373 ms, 381 ms,
374 refVals, 382 lnwlRefs,
375 func(m *availMeasurement) float64 { return float64(m.value) }, 383 func(m *availMeasurement) float64 { return float64(m.value) },
376 ) 384 )
377 385
378 classes := make([]float64, len(results)) 386 afdRefs := []referenceValue{
379 total := 100 / to.Sub(from).Seconds() 387 {0, 200},
380 for i, v := range results { 388 {1, 230},
381 classes[i] = v.Seconds() * total 389 {2, 250},
382 } 390 }
383 391
384 type outputLevel struct { 392 afd := classifyAvailMeasurements(
385 Level string `json:"level"` 393 from, to,
386 Value float64 `json:"value"` 394 ms,
395 afdRefs,
396 func(m *availMeasurement) float64 { return float64(m.depth) },
397 )
398
399 lnwlPercents := durationsToPercentage(from, to, lnwl)
400 afdPercents := durationsToPercentage(from, to, afd)
401
402 type lnwlOutput struct {
403 Level string `json:"level"`
404 Value float64 `json:"value"`
405 Percent float64 `json:"percent"`
406 }
407
408 type afdOutput struct {
409 Value float64 `json:"value"`
410 Percent float64 `json:"percent"`
387 } 411 }
388 412
389 type output struct { 413 type output struct {
390 Levels []outputLevel `json:"levels"` 414 LNWL []lnwlOutput `json:"lnwl"`
391 Classes []float64 `json:"classes"` 415 AFD []afdOutput `json:"afd"`
392 } 416 }
393 417
394 out := output{Classes: classes} 418 out := output{}
395 419
396 for i := range refVals { 420 for i := range lnwlRefs {
397 var level string 421 var level string
398 switch refVals[i].level { 422 switch lnwlRefs[i].level {
399 case 0: 423 case 0:
400 level = "LDC" 424 level = "LDC"
401 case 1: 425 case 1:
402 level = "MW" 426 level = "MW"
403 case 2: 427 case 2:
404 level = "HDC" 428 level = "HDC"
405 } 429 }
406 out.Levels = append(out.Levels, outputLevel{ 430 out.LNWL = append(out.LNWL, lnwlOutput{
407 Level: level, 431 Level: level,
408 Value: refVals[i].value, 432 Value: lnwlRefs[i].value,
433 Percent: lnwlPercents[i],
434 })
435 }
436
437 for i := range afdRefs {
438 out.AFD = append(out.AFD, afdOutput{
439 Value: afdRefs[i].value,
440 Percent: afdPercents[i],
409 }) 441 })
410 } 442 }
411 443
412 jr = JSONResult{Result: &out} 444 jr = JSONResult{Result: &out}
413 445