wx

package
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 6, 2025 License: GPL-3.0 Imports: 25 Imported by: 0

Documentation

Index

Constants

View Source
const NumSampleLevels = 40

This is fairly specialized to our needs we ingest from: at each lat-long, we store a vertical stack of 40 levels with samples from the source HRRR files (wind direction, speed, temperature, dewpoint, height). The vertical indexing of is low to high where LevelIndexFromId and IdFromLevelIndex perform the indexing and its inverse.

Variables

View Source
var AtmosTRACONs = []string{
	"A80", "A90", "AAC", "ABE", "ABQ", "AGS", "ALB", "ASE", "AUS", "AVL", "BGR",
	"BHM", "BIL", "BNA", "BOI", "BTV", "BUF", "C90", "CHS", "CID", "CLE", "CLT", "COS",
	"CPR", "D01", "D10", "D21", "DAB", "EWR", "F11", "GSO", "GSP", "GTF", "I90", "IND",
	"JAX", "L30", "M98", "MCI", "MDT", "MIA", "MKE", "N90", "NCT", "OKC", "P31", "P50",
	"P80", "PCT", "PHL", "PIT", "PVD", "PWM", "R90", "RDU", "S46", "S56", "SAV", "SBA",
	"SBN", "SCT", "SDF", "SGF", "SYR", "TPA", "Y90",
}

NOTE: PANC (A11) is not included: we only process the conus dataset for now and giving that -small_grib with the PANC lat-longs generates a ~1.4GB grib file, for reasons unknown.

vice -listscenarios 2>/dev/null | cut -d / -f 1 | grep -v A11 | uniq

Functions

func CheckAtmosConversion added in v0.13.0

func CheckAtmosConversion(at AtmosByPoint, soa AtmosByPointSOA) error

func CheckMETARSOA added in v0.13.0

func CheckMETARSOA(soa METARSOA, orig []METAR) error

func FetchRadarImage

func FetchRadarImage(center math.Point2LL, radius float32, resolution int) (image.Image, math.Extent2D, error)

func FullDataDays added in v0.13.0

func FullDataDays(metar, precip, atmos []time.Time) []util.TimeInterval

func IdFromLevelIndex added in v0.13.0

func IdFromLevelIndex(i int) string

func LevelIndexFromId added in v0.13.0

func LevelIndexFromId(b []byte) int

func PressureFromLevelIndex added in v0.13.0

func PressureFromLevelIndex(i int) float32

PressureFromLevelIndex returns pressure in millibars at the level.

func RadarImageToDBZ

func RadarImageToDBZ(img image.Image) []byte

Types

type AtmosByPoint added in v0.13.0

type AtmosByPoint struct {
	// Lat-longs to stack of levels
	SampleStacks map[math.Point2LL]*AtmosSampleStack
}

func MakeAtmosByPoint added in v0.13.0

func MakeAtmosByPoint() AtmosByPoint

func (*AtmosByPoint) Average added in v0.13.0

func (ap *AtmosByPoint) Average() (math.Point2LL, *AtmosSampleStack)

Average returns the averaged location and atmospheric data across all sample stacks

func (AtmosByPoint) GetGrid added in v0.13.0

func (ap AtmosByPoint) GetGrid() *AtmosGrid

func (AtmosByPoint) ToSOA added in v0.13.0

func (ap AtmosByPoint) ToSOA() (AtmosByPointSOA, error)

type AtmosByPointSOA added in v0.13.0

type AtmosByPointSOA struct {
	Lat, Long []float32
	Levels    [NumSampleLevels]AtmosLevelsSOA
}

For storage, this information is encoded in structure-of-arrays format, which makes it more compressible.

func (AtmosByPointSOA) ToAOS added in v0.13.0

func (atsoa AtmosByPointSOA) ToAOS() AtmosByPoint

type AtmosByTime added in v0.13.0

type AtmosByTime struct {
	SampleStacks map[time.Time]*AtmosSampleStack
}

func (AtmosByTime) ToSOA added in v0.13.0

func (at AtmosByTime) ToSOA() (AtmosByTimeSOA, error)

type AtmosByTimeSOA added in v0.13.0

type AtmosByTimeSOA struct {
	Times  []int64 // Delta-encoded Unix timestamps
	Levels [NumSampleLevels]AtmosLevelsSOA
}

AtmosByTimeSOA stores atmospheric data for multiple time points at a single location (used for offline weather packaging)

func (AtmosByTimeSOA) ToAOS added in v0.13.0

func (atsoa AtmosByTimeSOA) ToAOS() AtmosByTime

type AtmosGrid added in v0.13.0

type AtmosGrid struct {
	Extent   math.Extent2D
	Res      [3]int
	AltRange [2]float32
	Points   []Sample
}

func MakeAtmosGrid added in v0.13.0

func MakeAtmosGrid(sampleStacks map[math.Point2LL]*AtmosSampleStack) *AtmosGrid

func (*AtmosGrid) AltitudeForIndex added in v0.13.0

func (g *AtmosGrid) AltitudeForIndex(idx int) float32

func (*AtmosGrid) Lookup added in v0.13.0

func (g *AtmosGrid) Lookup(p math.Point2LL, alt float32) (Sample, bool)

func (*AtmosGrid) SamplesAtLevel added in v0.13.0

func (g *AtmosGrid) SamplesAtLevel(level, step int) iter.Seq2[math.Point2LL, Sample]

type AtmosLevelsSOA added in v0.13.0

type AtmosLevelsSOA struct {
	// All of the following are delta encoded
	Heading     []uint8 // degrees/2
	Speed       []uint8 // knots
	Temperature []int8  // Temperature in Celsius
	Dewpoint    []int8  // Dewpoint in Celsius
	Height      []uint8 // geopotential height (MSL) + windHeightOffset in meters
}

type AtmosResult added in v0.13.0

type AtmosResult struct {
	AtmosByPointSOA *AtmosByPointSOA
	Time            time.Time
	NextTime        time.Time
	Err             error
}

type AtmosSample added in v0.13.0

type AtmosSample struct {
	UComponent  float32 // eastward velocity m/s
	VComponent  float32 // northward velocity m/s
	Temperature float32 // Kelvin
	Dewpoint    float32 // Kelvin
	Height      float32 // geopotential height (meters)
}

AtmosSample stores wind as velocity vectors (direction the air mass is moving). UComponent is the eastward wind velocity in m/s (positive = moving east). VComponent is the northward wind velocity in m/s (positive = moving north). These match the standard GRIB2 UGRD/VGRD convention.

type AtmosSampleStack added in v0.13.0

type AtmosSampleStack struct {
	Levels [NumSampleLevels]AtmosSample
}

type METAR

type METAR struct {
	ICAO        string `json:"icaoId"`
	Time        time.Time
	Temperature float32 `json:"temp"`
	Dewpoint    float32 `json:"dewp"`
	Altimeter   float32 `json:"altim"`
	WindDir     *int    `json:"-"` // nil for variable winds, otherwise heading 0-360
	WindSpeed   int     `json:"wspd"`
	WindGust    *int    `json:"wgst"`
	Raw         string  `json:"rawOb"`

	// WindDirRaw and ReportTime are used for JSON unmarshaling only
	WindDirRaw any    `json:"wdir"` // nil or string "VRB" for variable, else number for heading
	ReportTime string `json:"reportTime"`
}

This is as much of the METAR as we need at runtime.

func DecodeMETARSOA added in v0.13.0

func DecodeMETARSOA(soa METARSOA) []METAR

func METARForTime added in v0.13.0

func METARForTime(metar []METAR, t time.Time) METAR

func SampleMETAR added in v0.13.0

func SampleMETAR(metar []METAR, intervals []util.TimeInterval, avgHdg float32) *METAR

Given an average headings (e.g. runway directions) and a slice of valid time intervals, randomly sample a METAR entry with wind that is compatible with the headings.

func SampleMETARWithSpec added in v0.13.0

func SampleMETARWithSpec(metar []METAR, intervals []util.TimeInterval, spec *WindSpecifier, magVar float32) *METAR

SampleMETARWithSpec randomly samples a METAR that matches the wind specifier

func SampleMatchingMETAR added in v0.13.0

func SampleMatchingMETAR(metar []METAR, intervals []util.TimeInterval, match func(METAR) bool) *METAR

SampleMatchingMETAR randomly samples from METARs that match a predicate using reservoir sampling

func (METAR) Altimeter_inHg

func (m METAR) Altimeter_inHg() float32

func (METAR) Ceiling added in v0.13.0

func (m METAR) Ceiling() (int, error)

Ceiling returns ceiling in feet AGL (above ground level)

func (METAR) IsVMC added in v0.13.0

func (m METAR) IsVMC() bool

IsVMC returns true if Visual Meteorological Conditions apply VMC requires >= 3 miles visibility and >= 1000' ceiling AGL

func (*METAR) UnmarshalJSON added in v0.13.0

func (m *METAR) UnmarshalJSON(data []byte) error

UnmarshalJSON handles converting WindDirRaw to WindDir

func (METAR) Visibility added in v0.13.0

func (m METAR) Visibility() (float32, error)

Visibility extracts visibility in statute miles from the raw METAR

type METARSOA added in v0.13.0

type METARSOA struct {
	// These are all delta coded
	ReportTime  [][]byte
	Temperature []int16 // fixed point, one decimal digit
	Dewpoint    []int16 // fixed point, one decimal digit
	Altimeter   []int16 // fixed point, one decimal digit
	WindDir     []int16
	WindSpeed   []int16
	WindGust    []int16

	// This is not; it's not worth delta encoding the raw METAR reports
	// since there's generally not much character alignment between
	// successive reports.
	Raw []string
}

Structure-of-arrays representation of an array of METAR objects for better compressability.

func MakeMETARSOA added in v0.13.0

func MakeMETARSOA(recs []METAR) (METARSOA, error)

type Model added in v0.13.0

type Model struct {
	// contains filtered or unexported fields
}

func MakeModel added in v0.13.0

func MakeModel(provider Provider, tracon string, startTime time.Time, lg *log.Logger) *Model

func (*Model) GetAtmosGrid added in v0.13.0

func (m *Model) GetAtmosGrid() *AtmosGrid

func (*Model) Lookup added in v0.13.0

func (m *Model) Lookup(p math.Point2LL, alt float32, t time.Time) Sample

type Precip added in v0.13.0

type Precip struct {
	DBZ        []byte
	Resolution int
	Latitude   float32
	Longitude  float32
}

Precip is the object type that is stored in GCS after wx ingest for precipitation.

func DecodePrecip added in v0.13.0

func DecodePrecip(r io.Reader) (*Precip, error)

func (Precip) BoundsLL added in v0.13.0

func (p Precip) BoundsLL() math.Extent2D

lat-long bounds

type Provider added in v0.13.0

type Provider interface {
	GetAvailableTimeIntervals() []util.TimeInterval

	// Best effort, may not have it for all airports, but no error is returned for that.
	GetMETAR(airports []string) (map[string]METARSOA, error)

	// Returns the item at-or-before the given time
	GetPrecipURL(tracon string, t time.Time) (string, time.Time, error)
	// Returns atmos, it's time, the time for the next one in the series.
	GetAtmosGrid(tracon string, t time.Time) (*AtmosByPointSOA, time.Time, time.Time, error)
}

type Sample

type Sample struct {
	WindSample
	Temperature float32 // Celsius
	Dewpoint    float32 // Celsius
	Pressure    float32 // millibars
}

func LerpSample added in v0.13.0

func LerpSample(x float32, s0, s1 Sample) Sample

func MakeStandardSampleForAltitude added in v0.13.0

func MakeStandardSampleForAltitude(alt float32) Sample

func (Sample) RelativeHumidity added in v0.13.0

func (s Sample) RelativeHumidity() float32

func (Sample) String added in v0.13.0

func (s Sample) String() string

type WindSample

type WindSample struct {
	// WindVec is the wind velocity vector (direction air mass is moving) in nm/s.
	// When added to aircraft velocity, it represents wind's effect on the aircraft.
	WindVec [2]float32 // nm / s
}

func (WindSample) Component added in v0.13.0

func (s WindSample) Component(course float32) float32

Component calculates the wind component along a given course in knots. Positive values indicate tailwind, negative values indicate headwind.

func (WindSample) Deflection added in v0.13.0

func (s WindSample) Deflection(v [2]float32) float32

Deflection calculates the heading correction needed to compensate for wind. Given a velocity vector v, it returns the deflection angle that should be subtracted from the heading to fly into the wind.

func (WindSample) WindDirection added in v0.13.0

func (s WindSample) WindDirection() float32

func (WindSample) WindSpeed added in v0.13.0

func (s WindSample) WindSpeed() float32

type WindSpecifier added in v0.13.0

type WindSpecifier struct {
	Direction   string `json:"direction,omitempty"`    // e.g., "30-90", "270", empty for any
	Speed       string `json:"speed,omitempty"`        // e.g., "5+", "5-", "5-15", empty for any
	FlightRules string `json:"flight_rules,omitempty"` // "VMC" or "IMC", empty defaults to "VMC"
}

WindSpecifier defines constraints for sampling weather data

func (*WindSpecifier) Matches added in v0.13.0

func (ws *WindSpecifier) Matches(metar METAR, magVar float32) bool

Matches checks if a METAR matches this wind specifier

func (*WindSpecifier) Validate added in v0.13.0

func (ws *WindSpecifier) Validate() error

Validate checks if the wind specifier is valid

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL