-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial commit - really rough calculations based on temp & relative h…
…umidity
- Loading branch information
0 parents
commit 8baef24
Showing
9 changed files
with
593 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package crust | ||
|
||
import ( | ||
"github.com/babattles/snoqualmie-crust-calculator/inversion" | ||
"github.com/babattles/snoqualmie-crust-calculator/models" | ||
"github.com/babattles/snoqualmie-crust-calculator/sun" | ||
) | ||
|
||
type CrustConfidence string | ||
|
||
const ( | ||
CrustYes CrustConfidence = "yes" | ||
CrustNo CrustConfidence = "no" | ||
CrustMaybe CrustConfidence = "maybe" | ||
) | ||
|
||
// returns an array of bools where the index is true when there likely | ||
// exists a sun crust based on temperature inversions & sun effect | ||
func FindSunCrust(data []models.WeatherStationData) []CrustConfidence { | ||
res := make([]CrustConfidence, len(data)) | ||
inversionsBelow := inversion.FindInversionsBelow(data) | ||
sunExposures := sun.FindSunEffect(data) | ||
for i, layer := range(data) { | ||
gotSun := sunExposures[i] | ||
inversionBelow := inversionsBelow[i] | ||
|
||
// if there was a temperature inversion detected below | ||
// AND this layer might have recieved sun exposure | ||
// AND the temperature is above freezing | ||
// there is very likely a sun crust | ||
// NOTE: this assumption is likely to upset many people | ||
if inversionBelow && | ||
gotSun && | ||
!layer.BelowFreezing() { | ||
res[i] = CrustYes | ||
continue | ||
} | ||
|
||
// because our sun exposure estimate isn't perfect, we provide a maybe if we can't | ||
// guess more precisely because we detected an inversion | ||
// so if the layer might have received sun exposure | ||
// AND is above freezing, it might have a crust | ||
// NOTE: this check assumes mid-winter conditions that will return this layer to freezing at some point | ||
// YMMV | ||
if gotSun && !layer.BelowFreezing() { | ||
res[i] = CrustMaybe | ||
continue | ||
} | ||
|
||
res[i] = CrustNo | ||
} | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package crust_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/babattles/snoqualmie-crust-calculator/crust" | ||
"github.com/babattles/snoqualmie-crust-calculator/models" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestFindSunCrust(t *testing.T) { | ||
t.Parallel() | ||
|
||
tests := []struct { | ||
name string | ||
data []models.WeatherStationData | ||
expected []crust.CrustConfidence | ||
}{ | ||
{ | ||
name: "no inversions - no clouds - all above freezing - all maybes", | ||
data: []models.WeatherStationData{ | ||
{ | ||
ElevationFt: 0, | ||
TemperatureF: 36, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 500, | ||
TemperatureF: 34, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 1000, | ||
TemperatureF: 32, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
}, | ||
expected: []crust.CrustConfidence{crust.CrustMaybe, crust.CrustMaybe, crust.CrustMaybe}, | ||
}, | ||
{ | ||
name: "no inversions - all clouds - all above freezing - all nos", | ||
data: []models.WeatherStationData{ | ||
{ | ||
ElevationFt: 0, | ||
TemperatureF: 36, | ||
RelativeHumidityPercent: 100, | ||
}, | ||
{ | ||
ElevationFt: 500, | ||
TemperatureF: 34, | ||
RelativeHumidityPercent: 100, | ||
}, | ||
{ | ||
ElevationFt: 1000, | ||
TemperatureF: 32, | ||
RelativeHumidityPercent: 100, | ||
}, | ||
}, | ||
expected: []crust.CrustConfidence{crust.CrustNo, crust.CrustNo, crust.CrustNo}, | ||
}, | ||
{ | ||
name: "no inversions - no clouds - all below freezing - all nos", | ||
data: []models.WeatherStationData{ | ||
{ | ||
ElevationFt: 0, | ||
TemperatureF: 28, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 500, | ||
TemperatureF: 26, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 1000, | ||
TemperatureF: 24, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
}, | ||
expected: []crust.CrustConfidence{crust.CrustNo, crust.CrustNo, crust.CrustNo}, | ||
}, | ||
{ | ||
name: "all inversions & all clouds - no crusts", | ||
data: []models.WeatherStationData{ | ||
{ | ||
ElevationFt: 0, | ||
TemperatureF: 30, | ||
RelativeHumidityPercent: 100, | ||
}, | ||
{ | ||
ElevationFt: 500, | ||
TemperatureF: 32, | ||
RelativeHumidityPercent: 100, | ||
}, | ||
{ | ||
ElevationFt: 1000, | ||
TemperatureF: 34, | ||
RelativeHumidityPercent: 100, | ||
}, | ||
}, | ||
expected: []crust.CrustConfidence{crust.CrustNo, crust.CrustNo, crust.CrustNo}, | ||
}, | ||
{ | ||
name: "all inversions - no clouds - all below freezing - no crusts", | ||
data: []models.WeatherStationData{ | ||
{ | ||
ElevationFt: 0, | ||
TemperatureF: 12, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 500, | ||
TemperatureF: 20, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 1000, | ||
TemperatureF: 30, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
}, | ||
expected: []crust.CrustConfidence{crust.CrustNo, crust.CrustNo, crust.CrustNo}, | ||
}, | ||
{ | ||
name: "all inversions - no clouds - one below freezing - two crusts", | ||
data: []models.WeatherStationData{ | ||
{ | ||
ElevationFt: 0, | ||
TemperatureF: 30, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 500, | ||
TemperatureF: 32, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
{ | ||
ElevationFt: 1000, | ||
TemperatureF: 34, | ||
RelativeHumidityPercent: 0, | ||
}, | ||
}, | ||
expected: []crust.CrustConfidence{crust.CrustNo, crust.CrustYes, crust.CrustYes}, | ||
}, | ||
} | ||
|
||
for _, tc := range tests { | ||
t.Run(tc.name, func(t *testing.T) { | ||
t.Parallel() | ||
tc := tc | ||
res := crust.FindSunCrust(tc.data) | ||
assert.Equal(t, tc.expected, res) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
module github.com/babattles/snoqualmie-crust-calculator | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
github.com/stretchr/testify v1.8.1 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | ||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | ||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | ||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | ||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package inversion | ||
|
||
import ( | ||
"errors" | ||
|
||
"github.com/babattles/snoqualmie-crust-calculator/models" | ||
) | ||
|
||
var ( | ||
ErrImproperElevationOrdering = errors.New("improper elevation ordering") | ||
) | ||
|
||
type InversionData struct { | ||
LowerElevationFt int | ||
HigherElevationFt int | ||
InversionPresent bool | ||
} | ||
|
||
// for each elevation band, return if there was an inversion between it and the above elevation band | ||
// (the uppermost elevation band will always be false) | ||
func FindInversionsAbove(data []models.WeatherStationData) []bool { | ||
// sort first for peace of mind | ||
models.SortByElevation(data) | ||
|
||
res := make([]bool, len(data)) | ||
for i, layer := range(data) { | ||
// uppermost layer | ||
if i == len(data) - 1 { | ||
res[i] = false | ||
return res | ||
} | ||
|
||
res[i] = temperatureInversionExists(layer, data[i+1]) | ||
} | ||
|
||
return res | ||
} | ||
|
||
// for each elevation band, return if there was an inversion between it and the elevation band below | ||
// (the lowest elevation band will always be false) | ||
func FindInversionsBelow(data []models.WeatherStationData) []bool { | ||
// sort first for peace of mind | ||
models.SortByElevation(data) | ||
|
||
res := make([]bool, len(data)) | ||
for i := len(data)-1; i >= 0; i-- { | ||
// lowest layer | ||
if i == 0 { | ||
res[i] = false | ||
return res | ||
} | ||
|
||
res[i] = temperatureInversionExists(data[i-1], data[i]) | ||
} | ||
|
||
return res | ||
} | ||
|
||
// calculates if there was a temperature inversion between two elevation bands | ||
func temperatureInversionExists( | ||
lowerBand models.WeatherStationData, higherBand models.WeatherStationData, | ||
) bool { | ||
return higherBand.TemperatureF > lowerBand.TemperatureF | ||
} |
Oops, something went wrong.