Mercurial > gemma
comparison pkg/common/nashsutcliffe.go @ 3099:f516ac26f4db direct-match-nash-sutcliffe
"Sharp" match for predicted and measured values in nash sutcliffe.
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Wed, 24 Apr 2019 22:26:16 +0200 |
parents | 8f2ac24b0cb3 |
children | 247e78ba2bf7 |
comparison
equal
deleted
inserted
replaced
3098:8f2ac24b0cb3 | 3099:f516ac26f4db |
---|---|
30 sort.Slice(mvs, func(i, j int) bool { | 30 sort.Slice(mvs, func(i, j int) bool { |
31 return mvs[i].When.Before(mvs[j].When) | 31 return mvs[i].When.Before(mvs[j].When) |
32 }) | 32 }) |
33 } | 33 } |
34 | 34 |
35 var utc0 = time.Unix(0, 0).UTC() | 35 func epsEquals(a, b time.Time) bool { |
36 d := a.Sub(b) | |
37 return -10*time.Millisecond < d && d < 10*time.Millisecond | |
38 } | |
36 | 39 |
37 func (mvs TimedValues) Interpolate(when time.Time) (float64, bool) { | 40 func (mvs TimedValues) Find(when time.Time) (float64, bool) { |
38 | 41 for i := range mvs { |
39 for lo, hi := 0, len(mvs)-2; lo <= hi; { | 42 if epsEquals(when, mvs[i].When) { |
40 mid := lo + (hi-lo)/2 | 43 return mvs[i].Value, true |
41 m1 := &mvs[mid] | |
42 m2 := &mvs[mid+1] | |
43 if m2.When.Before(when) { | |
44 hi = mid - 1 | |
45 continue | |
46 } | |
47 if m1.When.After(when) { | |
48 lo = mid + 1 | |
49 continue | |
50 } | |
51 if m1.When.Equal(when) { | |
52 //log.Printf("matches first: %f\n", m1.Value) | |
53 return m1.Value, true | |
54 } | |
55 if m2.When.Equal(when) { | |
56 //log.Printf("matches second: %f\n", m1.Value) | |
57 return m2.Value, true | |
58 } | |
59 | |
60 // f(m1.When) = m1.Value | |
61 // f(m2.When) = m2.Value | |
62 // m1.Value = m1.When*a + b <=> b = m1.Value - m1.When*a | |
63 // m2.Value = m2.When*a + b | |
64 // m1.Value - m2.Value = a*(m1.When - m2-When) | |
65 // a = (m1.Value - m2.Value)/(m1.When - m2.When) for m1.When != m2.When | |
66 | |
67 if m1.When.Equal(m2.When) { | |
68 return (m1.Value + m2.Value) * 0.5, true | |
69 } | |
70 | |
71 a := (m1.Value - m2.Value) / m1.When.Sub(m2.When).Seconds() | |
72 b := m1.Value - m1.When.Sub(utc0).Seconds()*a | |
73 m := when.Sub(utc0).Seconds()*a + b | |
74 | |
75 //log.Printf("%f %f %f\n", m1.Value, m, m2.Value) | |
76 return m, true | |
77 } | |
78 | |
79 if l := len(mvs); l > 0 { | |
80 if when.Equal(mvs[0].When) { | |
81 //log.Printf("at start\n") | |
82 return mvs[0].Value, true | |
83 } | |
84 if !when.Before(mvs[l-1].When) { | |
85 //log.Printf("after end\n") | |
86 return mvs[l-1].Value, true | |
87 } | 44 } |
88 } | 45 } |
89 | |
90 //if len(mvs) > 0 { | |
91 // log.Printf("does not match %v %v %v\n", | |
92 // mvs[0].When, mvs[len(mvs)-1].When.Sub(mvs[0].When), when) | |
93 //} | |
94 | |
95 return 0, false | 46 return 0, false |
96 } | 47 } |
97 | 48 |
98 func NashSutcliffe(predicted, observed []float64) float64 { | 49 func NashSutcliffe(predicted, observed []float64) float64 { |
99 | 50 |