comparison pkg/common/nashsutcliffe.go @ 2741:87aed4f9b1b8

Added calculation of Nash Sutcliffe efficiency coefficents. GET /api/data/nash-sutcliffe/{gauge}?when={WHEN} 'when' is optional in form of "2006-01-02T15:04:05.000" and defaults to current server time. curl -H "X-Gemma-Auth:$KEY" http://${server}:${port}/api/data/nash-sutcliffe/${gauge} | jq . { "when": "2019-03-20T10:38:05.687", "coeffs": [ { "value": 0, "samples": 0, "hours": 24 }, { "value": 0, "samples": 0, "hours": 48 }, { "value": 0, "samples": 0, "hours": 72 } ] }
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 20 Mar 2019 10:47:01 +0100
parents
children 4f66a3ba424b
comparison
equal deleted inserted replaced
2740:85de42146bdb 2741:87aed4f9b1b8
1 // This is Free Software under GNU Affero General Public License v >= 3.0
2 // without warranty, see README.md and license for details.
3 //
4 // SPDX-License-Identifier: AGPL-3.0-or-later
5 // License-Filename: LICENSES/AGPL-3.0.txt
6 //
7 // Copyright (C) 2019 by via donau
8 // – Österreichische Wasserstraßen-Gesellschaft mbH
9 // Software engineering by Intevation GmbH
10 //
11 // Author(s):
12 // * Sascha L. Teichmann <sascha.teichmann@intevation.de>
13
14 package common
15
16 import (
17 "sort"
18 "time"
19 )
20
21 type NSMeasurement struct {
22 When time.Time
23 Predicted float64
24 Observed float64
25 }
26
27 func NashSutcliffeSort(measurements []NSMeasurement) {
28 sort.Slice(measurements, func(i, j int) bool {
29 return measurements[i].When.Before(measurements[j].When)
30 })
31 }
32
33 func NashSutcliffe(measurements []NSMeasurement, from, to time.Time) (float64, int) {
34
35 if len(measurements) == 0 {
36 return 0, 0
37 }
38
39 if to.Before(from) {
40 from, to = to, from
41 }
42
43 begin := sort.Search(len(measurements), func(i int) bool {
44 return !measurements[i].When.Before(from)
45 })
46 if begin >= len(measurements) {
47 return 0, 0
48 }
49
50 end := sort.Search(len(measurements), func(i int) bool {
51 return measurements[i].When.After(to)
52 })
53 if end >= len(measurements) {
54 end = len(measurements) - 1
55 }
56 if end <= begin {
57 return 0, 0
58 }
59 sample := measurements[begin:end]
60
61 if len(sample) == 0 {
62 return 0, 0
63 }
64
65 var mo float64
66 for i := range sample {
67 mo += sample[i].Observed
68 }
69
70 mo /= float64(len(sample))
71
72 var num, denom float64
73 for i := range sample {
74 d1 := sample[i].Predicted - sample[i].Observed
75 num += d1 * d1
76 d2 := sample[i].Observed - mo
77 denom += d2 * d2
78 }
79
80 return 1 - num/denom, len(sample)
81 }