|
@@ -1,10 +1,8 @@
|
|
|
package spoptim
|
|
package spoptim
|
|
|
|
|
|
|
|
import (
|
|
import (
|
|
|
- "fmt"
|
|
|
|
|
"math"
|
|
"math"
|
|
|
"sort"
|
|
"sort"
|
|
|
- "strconv"
|
|
|
|
|
"encoding/json"
|
|
"encoding/json"
|
|
|
|
|
|
|
|
"gem-spaas-coding-challenge/models"
|
|
"gem-spaas-coding-challenge/models"
|
|
@@ -26,27 +24,30 @@ func ProductionPlanner(payload *models.Payload) []interface{} {
|
|
|
return make([]interface{}, 0)
|
|
return make([]interface{}, 0)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // cast the fuels to map and validate
|
|
|
|
|
+ fuels, _ := payload.Fuels.(map[string]interface{})
|
|
|
|
|
+ for k := range powerplantFuel {
|
|
|
|
|
+ if _, ok := fuels[powerplantFuel[k]]; !ok {
|
|
|
|
|
+ res := make([]interface{}, 0)
|
|
|
|
|
+ res = append(res, powerplantFuel[k] + " missing in Fuels")
|
|
|
|
|
+ return res
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// format wind plants for consistency with other types of plants
|
|
// format wind plants for consistency with other types of plants
|
|
|
- wind, _ := payload.Fuels.(map[string]interface{})["wind(%)"].(json.Number).Float64()
|
|
|
|
|
|
|
+ wind, _ := fuels["wind(%)"].(json.Number).Float64()
|
|
|
for _, plant := range payload.Powerplants {
|
|
for _, plant := range payload.Powerplants {
|
|
|
- plant_typed := plant.(map[string]interface{})
|
|
|
|
|
- if plant_typed["type"] == "windturbine" {
|
|
|
|
|
- pmax, _ := plant_typed["pmax"].(json.Number).Float64()
|
|
|
|
|
- plant_typed["pmax"] = json.Number(strconv.FormatFloat((pmax * wind / 100), 'f', 20, 64))
|
|
|
|
|
|
|
+ if *plant.Type == "windturbine" {
|
|
|
|
|
+ *plant.Pmax = *plant.Pmax * wind / 100
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- payload.Fuels.(map[string]interface{})["wind(%)"] = json.Number(0)
|
|
|
|
|
|
|
+ fuels["wind(%)"] = json.Number(0)
|
|
|
|
|
|
|
|
// order plants by merit
|
|
// order plants by merit
|
|
|
sort.SliceStable(payload.Powerplants, func(i, j int) bool {
|
|
sort.SliceStable(payload.Powerplants, func(i, j int) bool {
|
|
|
- planti, _ := payload.Powerplants[i].(map[string]interface{})
|
|
|
|
|
- plantj, _ := payload.Powerplants[j].(map[string]interface{})
|
|
|
|
|
- fuels, _ := payload.Fuels.(map[string]interface{})
|
|
|
|
|
- fueli, _ := fuels[powerplantFuel[planti["type"].(string)]].(json.Number).Float64()
|
|
|
|
|
- fuelj, _ := fuels[powerplantFuel[plantj["type"].(string)]].(json.Number).Float64()
|
|
|
|
|
- effi, _ := planti["efficiency"].(json.Number).Float64()
|
|
|
|
|
- effj, _ := plantj["efficiency"].(json.Number).Float64()
|
|
|
|
|
- return fueli / effi < fuelj / effj
|
|
|
|
|
|
|
+ fueli, _ := fuels[powerplantFuel[*payload.Powerplants[i].Type]].(json.Number).Float64()
|
|
|
|
|
+ fuelj, _ := fuels[powerplantFuel[*payload.Powerplants[j].Type]].(json.Number).Float64()
|
|
|
|
|
+ return fueli / *payload.Powerplants[i].Efficiency < fuelj / *payload.Powerplants[j].Efficiency
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// Naively assign production by merit-order (with one check
|
|
// Naively assign production by merit-order (with one check
|
|
@@ -57,21 +58,17 @@ func ProductionPlanner(payload *models.Payload) []interface{} {
|
|
|
costToCompare := make([]interface{}, 0)
|
|
costToCompare := make([]interface{}, 0)
|
|
|
resToCompare := make([][]interface{}, 0)
|
|
resToCompare := make([][]interface{}, 0)
|
|
|
for _, plant := range payload.Powerplants {
|
|
for _, plant := range payload.Powerplants {
|
|
|
- plant_typed := plant.(map[string]interface{})
|
|
|
|
|
remainingLoad := *payload.Load - load
|
|
remainingLoad := *payload.Load - load
|
|
|
if remainingLoad == 0 {
|
|
if remainingLoad == 0 {
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
- pmin, _ := plant_typed["pmin"].(json.Number).Float64()
|
|
|
|
|
- pmax, _ := plant_typed["pmax"].(json.Number).Float64()
|
|
|
|
|
- eff, _ := plant_typed["efficiency"].(json.Number).Float64()
|
|
|
|
|
- fuel, _ := payload.Fuels.(map[string]interface{})[powerplantFuel[plant_typed["type"].(string)]].(json.Number).Float64()
|
|
|
|
|
- if pmin < remainingLoad {
|
|
|
|
|
- usedP := math.Min(remainingLoad, pmax)
|
|
|
|
|
|
|
+ fuel, _ := fuels[powerplantFuel[*plant.Type]].(json.Number).Float64()
|
|
|
|
|
+ if *plant.Pmin < remainingLoad {
|
|
|
|
|
+ usedP := math.Min(remainingLoad, *plant.Pmax)
|
|
|
load += usedP
|
|
load += usedP
|
|
|
- cost = append(cost, usedP / eff * fuel)
|
|
|
|
|
|
|
+ cost = append(cost, usedP / *plant.Efficiency * fuel)
|
|
|
res = append(res, map[string]interface{}{
|
|
res = append(res, map[string]interface{}{
|
|
|
- "name": plant_typed["name"].(string),
|
|
|
|
|
|
|
+ "name": plant.Name,
|
|
|
"p": usedP,
|
|
"p": usedP,
|
|
|
})
|
|
})
|
|
|
} else {
|
|
} else {
|
|
@@ -79,7 +76,7 @@ func ProductionPlanner(payload *models.Payload) []interface{} {
|
|
|
altCost := make([]float64, 0)
|
|
altCost := make([]float64, 0)
|
|
|
copy(altRes, res)
|
|
copy(altRes, res)
|
|
|
copy(altCost, cost)
|
|
copy(altCost, cost)
|
|
|
- loadToRemove := pmin - remainingLoad
|
|
|
|
|
|
|
+ loadToRemove := *plant.Pmin - remainingLoad
|
|
|
for loadToRemove > 0 {
|
|
for loadToRemove > 0 {
|
|
|
if altRes[len(altRes)-1].(map[string]interface{})["p"].(float64) > loadToRemove {
|
|
if altRes[len(altRes)-1].(map[string]interface{})["p"].(float64) > loadToRemove {
|
|
|
altCost[len(altCost)-1] = altCost[len(altCost)-1] * (1 - loadToRemove / altRes[len(altRes)-1].(map[string]interface{})["p"].(float64))
|
|
altCost[len(altCost)-1] = altCost[len(altCost)-1] * (1 - loadToRemove / altRes[len(altRes)-1].(map[string]interface{})["p"].(float64))
|
|
@@ -92,10 +89,10 @@ func ProductionPlanner(payload *models.Payload) []interface{} {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
altRes = append(altRes, map[string]interface{}{
|
|
altRes = append(altRes, map[string]interface{}{
|
|
|
- "name": plant_typed["name"].(string),
|
|
|
|
|
- "p": pmax,
|
|
|
|
|
|
|
+ "name": *plant.Name,
|
|
|
|
|
+ "p": *plant.Pmax,
|
|
|
})
|
|
})
|
|
|
- altCost = append(altCost, pmax / eff * fuel)
|
|
|
|
|
|
|
+ altCost = append(altCost, *plant.Pmax / *plant.Efficiency * fuel)
|
|
|
resToCompare = append(resToCompare, altRes)
|
|
resToCompare = append(resToCompare, altRes)
|
|
|
costToCompare = append(costToCompare, altCost)
|
|
costToCompare = append(costToCompare, altCost)
|
|
|
}
|
|
}
|