Mercurial > gemma
view pkg/common/nashsutcliffe.go @ 5081:89834f645de3 time-sliding
merge default into time-sliding branch
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Wed, 18 Mar 2020 10:01:01 +0100 |
parents | 8c5df0f3562e |
children | 6270951dda28 |
line wrap: on
line source
// This is Free Software under GNU Affero General Public License v >= 3.0 // without warranty, see README.md and license for details. // // SPDX-License-Identifier: AGPL-3.0-or-later // License-Filename: LICENSES/AGPL-3.0.txt // // Copyright (C) 2019 by via donau // – Österreichische Wasserstraßen-Gesellschaft mbH // Software engineering by Intevation GmbH // // Author(s): // * Sascha L. Teichmann <sascha.teichmann@intevation.de> package common import ( "fmt" "time" ) type ( // TimedValue is a tuple of a point in time and an associated value. TimedValue struct { When time.Time Value float64 } // TimedValues is a slice of TimedValue tuples. TimedValues []TimedValue ) func epsEquals(a, b time.Time) bool { d := a.Sub(b) return -10*time.Millisecond < d && d < 10*time.Millisecond } // Find scans to the tuples and compares the time with an // epsilon of ten micro seconds. If they are equals the associated // value is returned. The return bool flags indicated if the // search was successful. func (mvs TimedValues) Find(when time.Time) (float64, bool) { for i := range mvs { if epsEquals(when, mvs[i].When) { return mvs[i].Value, true } } return 0, false } // NashSutcliffe calculates the Nash-Sutcliffe coefficent for // given predicted and observed values. // See // https://en.wikipedia.org/wiki/Nash%E2%80%93Sutcliffe_model_efficiency_coefficient // for details. // The function panics if predicted and observed are of different lengths. func NashSutcliffe(predicted, observed []float64) float64 { if len(predicted) != len(observed) { panic(fmt.Sprintf( "NashSutcliffe: predicted and observed len differ: %d != %d", len(predicted), len(observed))) } if len(observed) == 0 { return 0 } var mo float64 for _, v := range observed { mo += v } mo /= float64(len(observed)) var num, denom float64 for i, o := range observed { d1 := predicted[i] - o num += d1 * d1 d2 := o - mo denom += d2 * d2 } return 1 - num/denom }