Skip to content
Snippets Groups Projects
Commit 1a8ed12c authored by Tucker Siegel's avatar Tucker Siegel
Browse files

add api

parent baa2d992
No related branches found
No related tags found
No related merge requests found
......@@ -85,3 +85,24 @@ func GetRMToMaturity(c *fiber.Ctx) error {
request := models.BuildCornRMMaturityRequest(ctx)
return c.Status(fiber.StatusOK).JSON(services.CalculateRMMaturity(ctx, request))
}
// Stages godoc
// @Summary Get stages
// @Tags Maturity
// @Description Get stages
// @Accept json
// @Produce json
// @Success 200 {object} map[string][]time.Time
// @Failure 400 {object} common.StandardError
// @Param latitude query number true "Latitude to search for"
// @Param longitude query number true "Longitude to search for"
// @Param plant_date query string true "Plant date, ISO8601 or RFC3339 format"
// @Param mode query string true "Mode, rm or gdds_to_maturity"
// @Param value query int true "Value of mode"
// @Router /gdd/stages [get]
func Stages(c *fiber.Ctx) error {
ctx := common.DawnCtx{FiberCtx: c}
request := models.BuildStageRequest(ctx)
return c.Status(fiber.StatusOK).JSON(services.CalculateStages(ctx, request))
}
......@@ -19,5 +19,7 @@ func GddRoutes(route fiber.Router) {
route.Get("gdd/maturity/corn", GetMaturity)
route.Get("gdd/maturity/corn/relative", GetRMToMaturity)
route.Get("gdd/maturity/corn/cultivars", GetCultivars)
route.Get("gdd/stages", Stages)
// route.Get("gdd/seeds", GetSeedList)
}
......@@ -896,6 +896,78 @@ var doc = `{
}
}
}
},
"/gdd/stages": {
"get": {
"description": "Get stages",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Maturity"
],
"summary": "Get stages",
"parameters": [
{
"type": "number",
"description": "Latitude to search for",
"name": "latitude",
"in": "query",
"required": true
},
{
"type": "number",
"description": "Longitude to search for",
"name": "longitude",
"in": "query",
"required": true
},
{
"type": "string",
"description": "Plant date, ISO8601 or RFC3339 format",
"name": "plant_date",
"in": "query",
"required": true
},
{
"type": "string",
"description": "Mode, rm or gdds_to_maturity",
"name": "mode",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "Value of mode",
"name": "value",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/common.StandardError"
}
}
}
}
}
},
"definitions": {
......
......@@ -879,6 +879,78 @@
}
}
}
},
"/gdd/stages": {
"get": {
"description": "Get stages",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Maturity"
],
"summary": "Get stages",
"parameters": [
{
"type": "number",
"description": "Latitude to search for",
"name": "latitude",
"in": "query",
"required": true
},
{
"type": "number",
"description": "Longitude to search for",
"name": "longitude",
"in": "query",
"required": true
},
{
"type": "string",
"description": "Plant date, ISO8601 or RFC3339 format",
"name": "plant_date",
"in": "query",
"required": true
},
{
"type": "string",
"description": "Mode, rm or gdds_to_maturity",
"name": "mode",
"in": "query",
"required": true
},
{
"type": "integer",
"description": "Value of mode",
"name": "value",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/common.StandardError"
}
}
}
}
}
},
"definitions": {
......
......@@ -780,4 +780,53 @@ paths:
summary: Get gdd normals
tags:
- Gdd
/gdd/stages:
get:
consumes:
- application/json
description: Get stages
parameters:
- description: Latitude to search for
in: query
name: latitude
required: true
type: number
- description: Longitude to search for
in: query
name: longitude
required: true
type: number
- description: Plant date, ISO8601 or RFC3339 format
in: query
name: plant_date
required: true
type: string
- description: Mode, rm or gdds_to_maturity
in: query
name: mode
required: true
type: string
- description: Value of mode
in: query
name: value
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
additionalProperties:
items:
type: string
type: array
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/common.StandardError'
summary: Get stages
tags:
- Maturity
swagger: "2.0"
package models
import (
"strconv"
"strings"
"time"
validation "github.com/go-ozzo/ozzo-validation"
"gitlab.cs.umd.edu/dawn/dawn-go-common/common"
"gitlab.cs.umd.edu/dawn/go-backend/dawn-gdd/config"
)
type StageRequest struct {
PlantDate time.Time `json:"plant_date"`
Mode string `json:"mode"`
Value int `json:"value"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
func BuildStageRequest(ctx common.DawnCtx) StageRequest {
plantDate := ctx.FiberCtx.Query("plant_date")
mode := ctx.FiberCtx.Query("mode")
value := ctx.FiberCtx.Query("value")
latitude := ctx.FiberCtx.Query("latitude")
longitude := ctx.FiberCtx.Query("longitude")
pd, err := time.Parse(time.RFC3339, plantDate)
if err != nil {
panic(config.BAD_REQUEST.PutDetail("reason", err.Error()))
}
modeLower := strings.ToLower(mode)
if modeLower != "rm" && modeLower != "gdds_to_maturity" {
panic(config.BAD_REQUEST.PutDetail("reason", "\""+mode+"\" is not valid"))
}
valueInt, err := strconv.Atoi(value)
if err != nil {
panic(config.BAD_REQUEST.PutDetail("reason", err.Error()))
}
latitudeFloat, err := strconv.ParseFloat(latitude, 64)
if err != nil {
panic(config.BAD_REQUEST.PutDetail("reason", err.Error()))
}
longitudeFloat, err := strconv.ParseFloat(longitude, 64)
if err != nil {
panic(config.BAD_REQUEST.PutDetail("reason", err.Error()))
}
stageRequest := StageRequest{
PlantDate: pd,
Mode: modeLower,
Value: valueInt,
Latitude: latitudeFloat,
Longitude: longitudeFloat,
}
e := stageRequest.Validate()
if e != nil {
panic(config.BAD_REQUEST.PutDetail("reason", e.Error()))
}
return stageRequest
}
func (r StageRequest) Validate() error {
return validation.ValidateStruct(&r,
validation.Field(&r.Latitude, validation.Required, validation.Min(-90.0), validation.Max(90.0)),
validation.Field(&r.Longitude, validation.Required, validation.Min(-180.0), validation.Max(180.0)),
)
}
type StageData struct {
MeanGdds []float64
MaxGdds []float64
MinGdds []float64
}
type StageMatches struct {
Harvest float64
R1Silk float64
}
type StageStateInner struct {
FoundMin int
FoundMax int
FoundMean int
MinDist float64
MaxDist float64
MeanDist float64
Done bool
}
func (s StageStateInner) AddToAllFound(val int) StageStateInner {
s.FoundMax += val
s.FoundMin += val
s.FoundMean += val
return s
}
func (s StageStateInner) ExtractDates(plantDate time.Time, start int) []time.Time {
minDate := plantDate.AddDate(0, 0, s.FoundMin-start)
meanDate := plantDate.AddDate(0, 0, s.FoundMean-start)
maxDate := plantDate.AddDate(0, 0, s.FoundMax-start)
return []time.Time{maxDate, meanDate, minDate}
}
func BuildStageMatches(mode string, value int) map[string]float64 {
var harvestVal float64
if mode == "rm" {
harvestVal = float64(((float64(value) - 95.0) * 22.0) + 2375.0)
} else {
harvestVal = float64(value)
}
return map[string]float64{
"silk": harvestVal * 0.545,
"blister": harvestVal * 0.66,
"milk": harvestVal * 0.725,
"dough": harvestVal * 0.795,
"dent": harvestVal * 0.87,
"harvest": harvestVal,
}
}
// type StageResponse struct {
// }
......@@ -188,3 +188,102 @@ func CalculateRMMaturity(ctx common.DawnCtx, request models.CornRMMaturityReques
}
}
func GetStageYearData(ctx common.DawnCtx, request models.GddRequest) models.StageData {
product := enums.GetProductFromString(request.Product)
gddData := persistence.CurrentGddFindFirstByYearAndLocation(ctx, request.BuildLocation())
gdds := utils.CalculateGddValues(gddData.MinTemps, gddData.MaxTemps, product, false)
cfsData := GetCfsGddValues(request)
request.Year = gddData.AnalogYear - 1
analogYearData := GetGddValues(ctx, request)
meanGdds := append(gdds, cfsData.GddValues...)
maxGdds := append(gdds, cfsData.UpperBound...)
minGdds := append(gdds, cfsData.LowerBound...)
if len(meanGdds) != len(analogYearData.GddValues) {
meanGdds = append(meanGdds, analogYearData.GddValues[len(meanGdds):]...)
minGdds = append(minGdds, analogYearData.GddValues[len(minGdds):]...)
maxGdds = append(maxGdds, analogYearData.GddValues[len(maxGdds):]...)
}
returnData := models.StageData{
MeanGdds: meanGdds,
MaxGdds: maxGdds,
MinGdds: minGdds,
}
return returnData
}
func CalculateStages(ctx common.DawnCtx, request models.StageRequest) map[string][]time.Time {
gddReq := models.GddRequest{
Year: request.PlantDate.Year(),
Latitude: request.Latitude,
Longitude: request.Longitude,
Accumulate: false,
Product: "corn",
}
fyData := GetStageYearData(ctx, gddReq)
start := request.PlantDate.YearDay()
year := request.PlantDate.Year()
if year%4 == 0 && year%100 != 0 || year%400 == 0 {
start -= 1
}
accMin := 0.0
accMax := 0.0
accMean := 0.0
state := map[string]models.StageStateInner{}
stageMatches := models.BuildStageMatches(request.Mode, request.Value)
for i := start; i < len(fyData.MaxGdds); i++ {
accMin += fyData.MinGdds[i]
accMax += fyData.MaxGdds[i]
accMean += fyData.MeanGdds[i]
for stage, stageVal := range stageMatches {
if val, ok := state[stage]; !ok {
state[stage] = models.StageStateInner{
MinDist: math.Abs(accMin - stageVal),
MaxDist: math.Abs(accMax - stageVal),
MeanDist: math.Abs(accMean - stageVal),
FoundMin: i,
FoundMax: i,
FoundMean: i,
}
} else {
if math.Abs(accMin-stageVal) < val.MinDist {
val.FoundMin = i
val.MinDist = math.Abs(accMin - stageVal)
state[stage] = val
}
if math.Abs(accMean-stageVal) < val.MeanDist {
val.FoundMean = i
val.MeanDist = math.Abs(accMean - stageVal)
state[stage] = val
}
if math.Abs(accMax-stageVal) < val.MaxDist {
val.FoundMax = i
val.MaxDist = math.Abs(accMax - stageVal)
state[stage] = val
}
}
}
}
ret := map[string][]time.Time{}
for stage := range stageMatches {
if year%4 == 0 && year%100 != 0 || year%400 == 0 {
state[stage] = state[stage].AddToAllFound(1)
}
ret[stage] = state[stage].ExtractDates(request.PlantDate, start)
}
return ret
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment