changeset 3087:014be2194bd1

Prepare new Nash-Sutcliffe calculation.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Sun, 21 Apr 2019 11:14:20 +0200
parents a69a8deb56fe
children 09d1ffce3d00
files pkg/common/nashsutcliffe.go
diffstat 1 files changed, 60 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/pkg/common/nashsutcliffe.go	Thu Apr 18 15:29:09 2019 +0200
+++ b/pkg/common/nashsutcliffe.go	Sun Apr 21 11:14:20 2019 +0200
@@ -19,6 +19,66 @@
 	"time"
 )
 
+type TimedValue struct {
+	When  time.Time
+	Value float64
+}
+
+type TimedValues []TimedValue
+
+func (mvs TimedValues) Sort() {
+	sort.Slice(mvs, func(i, j int) bool {
+		return mvs[i].When.Before(mvs[j].When)
+	})
+}
+
+var utc0 = time.Unix(0, 0).UTC()
+
+func (mvs TimedValues) Interpolate(when time.Time) (float64, bool) {
+
+	for lo, hi := 0, len(mvs)-2; lo <= hi; {
+		mid := lo + (hi - lo) + 2
+		m1 := &mvs[mid]
+		m2 := &mvs[mid+1]
+		if m2.When.Before(when) {
+			hi = mid - 1
+			continue
+		}
+		if m1.When.After(when) {
+			lo = mid + 1
+			continue
+		}
+		if m1.When.Equal(when) {
+			return m1.Value, true
+		}
+		if m2.When.Equal(when) {
+			return m2.Value, true
+		}
+
+		// f(m1.When) = m1.Value
+		// f(m2.When) = m2.Value
+		// m1.Value = m1.When*a + b <=> b = m1.Value - m1.When*a
+		// m2.Value = m2.When*a + b
+		// m1.Value - m2.Value = a*(m1.When - m2-When)
+		// a = (m1.Value - m2.Value)/(m1.When - m2.When) for m1.When != m2.When
+
+		if m1.When.Equal(m2.When) {
+			return (m1.Value + m2.Value) * 0.5, true
+		}
+
+		a := (m1.Value - m2.Value) / m1.When.Sub(m2.When).Seconds()
+		b := m1.Value - m1.When.Sub(utc0).Seconds()*a
+		m := when.Sub(utc0).Seconds()*a + b
+		return m, true
+	}
+
+	if len(mvs) == 1 && when.Equal(mvs[0].When) {
+		return mvs[0].Value, true
+	}
+
+	return 0, false
+}
+
 type NSMeasurement struct {
 	When      time.Time
 	Predicted float64