Mercurial > gemma
diff pkg/controllers/gauges.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 | 0d7a4fdb9e12 |
children | f95ec0bb565c |
line wrap: on
line diff
--- a/pkg/controllers/gauges.go Tue Mar 19 19:21:04 2019 +0100 +++ b/pkg/controllers/gauges.go Wed Mar 20 10:47:01 2019 +0100 @@ -14,6 +14,7 @@ package controllers import ( + "database/sql" "encoding/csv" "fmt" "log" @@ -23,11 +24,34 @@ "github.com/gorilla/mux" + "gemma.intevation.de/gemma/pkg/common" "gemma.intevation.de/gemma/pkg/middleware" "gemma.intevation.de/gemma/pkg/models" ) const ( + selectPredictedObserveredSQL = ` +SELECT + a.measure_date AS measure_date, + a.water_level AS predicted, + b.water_level AS observed +FROM waterway.gauge_measurements a JOIN waterway.gauge_measurements b + ON a.fk_gauge_id = b.fk_gauge_id AND + a.measure_date = b.measure_date AND + a.predicted AND NOT b.predicted +WHERE + a.fk_gauge_id = ( + $1::char(1), + $2::char(2), + $3::char(3), + $4::char(4), + $5::int + ) AND + a.measure_date BETWEEN + $6::timestamp AND $6::timestamp - '72hours'::interval +ORDER BY a.measure_date +` + selectWaterlevelsSQL = ` SELECT measure_date, @@ -38,6 +62,99 @@ ` ) +func nashSutcliffe( + _ interface{}, + req *http.Request, + conn *sql.Conn, +) (jr JSONResult, err error) { + gauge := mux.Vars(req)["gauge"] + + var isrs *models.Isrs + if isrs, err = models.IsrsFromString(gauge); err != nil { + err = JSONError{ + Code: http.StatusBadRequest, + Message: fmt.Sprintf("error: Invalid ISRS code: %v", err), + } + return + } + + var when time.Time + if w := req.FormValue("when"); w != "" { + if when, err = time.Parse(models.ImportTimeFormat, w); err != nil { + err = JSONError{ + Code: http.StatusBadRequest, + Message: fmt.Sprintf("error: wrong time format: %v", err), + } + return + } + } else { + when = time.Now() + } + + ctx := req.Context() + + var rows *sql.Rows + if rows, err = conn.QueryContext( + ctx, + selectPredictedObserveredSQL, + isrs.CountryCode, + isrs.LoCode, + isrs.FairwaySection, + isrs.Orc, + isrs.Hectometre, + when, + ); err != nil { + return + } + defer rows.Close() + + var measurements []common.NSMeasurement + + for rows.Next() { + var m common.NSMeasurement + if err = rows.Scan( + &m.When, + &m.Predicted, + &m.Observed, + ); err != nil { + return + } + measurements = append(measurements, m) + } + if err = rows.Err(); err != nil { + return + } + + type coeff struct { + Value float64 `json:"value"` + Samples int `json:"samples"` + Hours int `json:"hours"` + } + + type coeffs struct { + When models.ImportTime `json:"when"` + Coeffs []coeff `json:"coeffs"` + } + + cs := make([]coeff, 3) + for i := range cs { + cs[i].Hours = (i + 1) * 24 + cs[i].Value, cs[i].Samples = common.NashSutcliffe( + measurements, + when, + when.Add(time.Duration(-cs[i].Hours)*time.Hour), + ) + } + + jr = JSONResult{ + Result: &coeffs{ + When: models.ImportTime{when}, + Coeffs: cs, + }, + } + return +} + func waterlevels(rw http.ResponseWriter, req *http.Request) { gauge := mux.Vars(req)["gauge"]