Documentation
¶
Overview ¶
Package squall provides a high-performance Go library for reading GRIB2 (GRIdded Binary 2nd edition) meteorological data files.
squall offers:
- Pure Go implementation (no CGo)
- 9.4x faster parallel decoding
- Streaming API with io.ReadSeeker
- 99.9% exact match with wgrib2 reference
- Flexible filtering options
- Comprehensive test coverage (157 tests)
Basic usage:
f, err := os.Open("forecast.grib2")
if err != nil {
log.Fatal(err)
}
defer f.Close()
messages, err := squall.Read(f)
if err != nil {
log.Fatal(err)
}
for _, msg := range messages {
fmt.Printf("%s at %s: %d points\n",
msg.Parameter, msg.Level, len(msg.Values))
}
Filtering by parameter:
messages, err := squall.ReadWithOptions(f,
squall.WithParameterFilter("Temperature", "Relative Humidity"))
Filtering by level:
messages, err := squall.ReadWithOptions(f,
squall.WithLevelFilter("500 mb", "Surface"))
Context support:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() messages, err := squall.ReadWithOptions(f, squall.WithContext(ctx))
Performance:
squall processes GRIB2 messages in parallel using goroutines, achieving 9.4x speedup on large files with 708 messages. The parallel processing is optimized to use 2×NumCPU workers to balance speed and memory usage.
Example (Basic) ¶
Example_basic demonstrates basic usage of squall, the GRIB2 library, with streaming.
package main
import (
"bytes"
"fmt"
"log"
"github.com/mmp/squall"
)
func main() {
// Open GRIB2 file (not shown: error handling for demonstration)
// file, _ := os.Open("forecast.grib2")
// defer file.Close()
// For this example, we'll use a placeholder
// In real code, you would use: fields, err := squall.Read(file)
data := []byte{} // placeholder
fields, err := squall.Read(bytes.NewReader(data))
if err != nil {
log.Fatal(err)
}
// Process each field
for _, field := range fields {
fmt.Printf("Parameter: %s\n", field.Parameter.String())
fmt.Printf("Center: %s\n", field.Center)
fmt.Printf("Time: %s\n", field.ReferenceTime)
fmt.Printf("Grid points: %d\n", field.NumPoints)
fmt.Printf("Data range: %.2f to %.2f\n", field.MinValue(), field.MaxValue())
fmt.Println()
}
}
Example (Context) ¶
Example_context demonstrates using context for timeout/cancellation.
package main
import (
"bytes"
"context"
"fmt"
"log"
"time"
"github.com/mmp/squall"
)
func main() {
data := []byte{} // placeholder
// Set a timeout for parsing
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
fields, err := squall.ReadWithOptions(bytes.NewReader(data),
squall.WithContext(ctx),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d fields within timeout\n", len(fields))
}
Example (Coordinates) ¶
Example_coordinates demonstrates accessing lat/lon coordinates.
package main
import (
"bytes"
"fmt"
"log"
"github.com/mmp/squall"
)
func main() {
data := []byte{} // placeholder
fields, err := squall.Read(bytes.NewReader(data))
if err != nil {
log.Fatal(err)
}
if len(fields) == 0 {
return
}
field := fields[0]
// Access coordinates for each grid point
for i := range field.NumPoints {
lat := field.Latitudes[i]
lon := field.Longitudes[i]
value := field.Data[i]
// Skip missing values
if squall.IsMissing(value) {
continue
}
fmt.Printf("Point %d: %.2f°N, %.2f°E = %.2f\n", i, lat, lon, value)
// Only show first few points
if i >= 5 {
break
}
}
}
Example (CustomFilter) ¶
Example_customFilter demonstrates using a custom filter function.
package main
import (
"bytes"
"fmt"
"log"
"github.com/mmp/squall"
)
func main() {
data := []byte{} // placeholder
// Custom filter: only operational forecasts from NCEP
filter := func(msg *squall.Message) bool {
if msg.Section1 == nil {
return false
}
// Center 7 = NCEP
if msg.Section1.OriginatingCenter != 7 {
return false
}
// Production status 0 = Operational
if msg.Section1.ProductionStatus != 0 {
return false
}
return true
}
fields, err := squall.ReadWithOptions(bytes.NewReader(data),
squall.WithFilter(filter),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d operational NCEP fields\n", len(fields))
}
Example (Filtering) ¶
Example_filtering demonstrates filtering messages by parameter.
package main
import (
"bytes"
"fmt"
"log"
"github.com/mmp/squall"
)
func main() {
data := []byte{} // placeholder
// Only read temperature fields (category 0)
fields, err := squall.ReadWithOptions(bytes.NewReader(data),
squall.WithParameterCategory(0),
)
if err != nil {
log.Fatal(err)
}
for _, field := range fields {
fmt.Printf("Temperature field: %s\n", field.Parameter.String())
}
}
Example (MultipleOptions) ¶
Example_multipleOptions demonstrates combining multiple options.
package main
import (
"bytes"
"context"
"fmt"
"log"
"time"
"github.com/mmp/squall"
)
func main() {
data := []byte{} // placeholder
// Combine parallelism, filtering, and context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
fields, err := squall.ReadWithOptions(bytes.NewReader(data),
squall.WithWorkers(8),
squall.WithContext(ctx),
squall.WithParameterCategory(0), // Temperature
squall.WithDiscipline(0), // Meteorological
squall.WithCenter(7), // NCEP
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d temperature fields from NCEP\n", len(fields))
}
Example (Parallel) ¶
Example_parallel demonstrates parallel parsing with custom worker count.
package main
import (
"bytes"
"fmt"
"log"
"github.com/mmp/squall"
)
func main() {
data := []byte{} // placeholder
// Use 4 workers for parallel parsing
fields, err := squall.ReadWithOptions(bytes.NewReader(data),
squall.WithWorkers(4),
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d fields with 4 workers\n", len(fields))
}
Example (Streaming) ¶
Example_streaming demonstrates reading from a file without loading it all into memory.
package main
import (
"fmt"
"log"
"os"
"github.com/mmp/squall"
)
func main() {
// Open GRIB2 file (using os.File which implements io.ReadSeeker)
file, err := os.Open("forecast.grib2")
if err != nil {
log.Fatal(err)
}
defer func() {
_ = file.Close()
}()
// Parse messages directly from the file stream
// Individual messages are read into memory as needed, but not the entire file
fields, err := squall.Read(file)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Parsed %d fields from stream\n", len(fields))
}
Index ¶
- func IsMissing(v float32) bool
- func SplitMessages(data []byte) ([][]byte, error)
- func ValidateMessageStructure(data []byte) error
- type GRIB2
- type InvalidFormatError
- type Message
- func ParseMessage(data []byte) (*Message, error)
- func ParseMessages(data []byte) ([]*Message, error)
- func ParseMessagesFromStream(r io.ReadSeeker) ([]*Message, error)
- func ParseMessagesFromStreamSequential(r io.ReadSeeker) ([]*Message, error)
- func ParseMessagesFromStreamSequentialSkipErrors(r io.ReadSeeker) ([]*Message, error)
- func ParseMessagesFromStreamWithContext(ctx context.Context, r io.ReadSeeker, workers int) ([]*Message, error)
- func ParseMessagesFromStreamWithWorkers(r io.ReadSeeker, workers int) ([]*Message, error)
- func ParseMessagesSequential(data []byte) ([]*Message, error)
- func ParseMessagesSequentialSkipErrors(data []byte) ([]*Message, error)
- func ParseMessagesWithContext(ctx context.Context, data []byte, workers int) ([]*Message, error)
- func ParseMessagesWithWorkers(data []byte, workers int) ([]*Message, error)
- type MessageBoundary
- type ParameterID
- type ParseError
- type ReadOption
- func WithCenter(center uint16) ReadOption
- func WithContext(ctx context.Context) ReadOption
- func WithDiscipline(discipline uint8) ReadOption
- func WithFilter(filter func(*Message) bool) ReadOption
- func WithParameterCategory(category uint8) ReadOption
- func WithParameterNumber(number uint8) ReadOption
- func WithSequential() ReadOption
- func WithSkipErrors() ReadOption
- func WithWorkers(workers int) ReadOption
- type UnsupportedTemplateError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func IsMissing ¶
IsMissing returns true if the value represents missing/undefined GRIB2 data.
GRIB2 uses 9.999e20 as a sentinel value for missing data points (when bitmap indicates undefined values). This function uses a range check (9.9989e20 to 9.9991e20) to account for floating-point precision and handle GRIB2 files from various sources, matching wgrib2's defensive approach.
func SplitMessages ¶
SplitMessages splits the data into individual GRIB2 messages.
This is a convenience function that calls FindMessages and then extracts the actual message data for each boundary.
Returns a slice of byte slices, where each inner slice is a complete GRIB2 message.
func ValidateMessageStructure ¶
ValidateMessageStructure performs a basic validation of a GRIB2 message structure.
This function checks that:
- The message starts with "GRIB"
- Section 0 is valid
- The message ends with "7777"
- The message length matches the data length
It does NOT parse the full message content or validate all sections.
Types ¶
type GRIB2 ¶
type GRIB2 struct {
// Data values in grid scan order
Data []float32
// Latitudes for each grid point (same length as Data)
Latitudes []float32
// Longitudes for each grid point (same length as Data)
Longitudes []float32
// Metadata from the message
Discipline string // Meteorological, Hydrological, etc.
Center string // Originating center (NCEP, ECMWF, etc.)
ReferenceTime time.Time // Reference time of the data
ProductionStatus string // Operational, Test, etc.
DataType string // Forecast, Analysis, etc.
// Parameter information
Parameter ParameterID // WMO standard parameter identifier (D.C.P)
// Level/surface information
Level string // Type of level (isobaric, surface, etc.)
LevelValue float32 // Value of the level (e.g., 500 for 500 hPa)
// Grid information
GridType string // Lat/Lon, Gaussian, Lambert, etc.
GridNi int // Number of points in i direction
GridNj int // Number of points in j direction
NumPoints int // Total number of grid points
// contains filtered or unexported fields
}
GRIB2 represents a single meteorological field from a GRIB2 message.
This is the main public type returned by the Read function. It contains all the information needed to work with GRIB2 data: values, coordinates, and metadata.
func Read ¶
func Read(r io.ReadSeeker) ([]*GRIB2, error)
Read parses GRIB2 messages from an io.ReadSeeker.
This is the main entry point for the library. It parses all GRIB2 messages in the input stream and returns them as GRIB2 structs with decoded data and coordinates.
Messages are parsed in parallel for performance. Individual messages are read into memory as needed, but the entire file is not loaded at once. Use ReadWithOptions to control parallelism or apply filters.
Example:
file, _ := os.Open("forecast.grib2")
defer file.Close()
fields, err := grib.Read(file)
if err != nil {
log.Fatal(err)
}
for _, field := range fields {
fmt.Printf("%s at %s: %d points\n",
field.Parameter, field.Level, field.NumPoints)
}
func ReadWithOptions ¶
func ReadWithOptions(r io.ReadSeeker, opts ...ReadOption) ([]*GRIB2, error)
ReadWithOptions parses GRIB2 messages with configuration options.
Options can control parallelism, apply filters, or configure other behavior. See ReadOption for available options.
Example:
file, _ := os.Open("forecast.grib2")
defer file.Close()
fields, err := grib.ReadWithOptions(file,
WithWorkers(4),
WithParameter("Temperature"),
)
func (*GRIB2) CountValid ¶
CountValid returns the number of valid (non-missing) data values.
func (*GRIB2) GetMessage ¶
GetMessage returns the underlying parsed message for advanced users.
This provides access to the raw section data and allows for custom processing beyond what the GRIB2 struct provides.
type InvalidFormatError ¶
type InvalidFormatError struct {
Message string // Description of what's invalid
Offset int // Byte offset where the invalid data was found
}
InvalidFormatError indicates that the data is not a valid GRIB2 file.
func (*InvalidFormatError) Error ¶
func (e *InvalidFormatError) Error() string
Error implements the error interface.
type Message ¶
type Message struct {
// Section0 contains the indicator section with discipline and message length
Section0 *section.Section0
// Section1 contains identification information (center, time, etc.)
Section1 *section.Section1
// Section2 contains local use data (optional, may be nil)
Section2 *section.Section2
// Section3 contains the grid definition
Section3 *section.Section3
// Section4 contains the product definition
Section4 *section.Section4
// Section5 contains the data representation template
Section5 *section.Section5
// Section6 contains the bitmap (optional, may be nil if all points valid)
Section6 *section.Section6
// Section7 contains the packed data
Section7 *section.Section7
// RawData is the original message bytes (for debugging/analysis)
RawData []byte
}
Message represents a complete parsed GRIB2 message.
A GRIB2 message contains all the information needed to describe and decode a single meteorological field, including metadata, grid definition, product description, and the packed data values.
func ParseMessage ¶
ParseMessage parses a complete GRIB2 message from raw bytes.
The input data should contain a single complete GRIB2 message starting with "GRIB" and ending with "7777".
This function parses all 8 sections of the message:
- Section 0: Indicator (discipline, message length)
- Section 1: Identification (center, reference time, etc.)
- Section 2: Local use (optional)
- Section 3: Grid definition
- Section 4: Product definition
- Section 5: Data representation
- Section 6: Bitmap
- Section 7: Data
- Section 8: End marker "7777"
Note: Currently assumes one field per message. Multi-field messages (where sections 3-7 repeat) are not yet supported.
func ParseMessages ¶
ParseMessages parses multiple GRIB2 messages from a byte slice in parallel.
This function first scans the data to find message boundaries (sequential), then parses each message concurrently using a worker pool (parallel).
The number of workers defaults to runtime.NumCPU(). Messages are returned in their original order, even though they may be parsed out of order.
Returns a slice of parsed messages and an error if any message fails to parse. On error, all parsing stops and the first error is returned.
func ParseMessagesFromStream ¶
func ParseMessagesFromStream(r io.ReadSeeker) ([]*Message, error)
ParseMessagesFromStream parses multiple GRIB2 messages from an io.ReadSeeker in parallel.
This function first scans the stream to find message boundaries (sequential), then reads and parses each message concurrently using a worker pool (parallel).
Messages are read into memory one at a time before parsing to avoid holding the entire file in memory. The stream must support seeking.
The number of workers defaults to runtime.NumCPU(). Messages are returned in their original order, even though they may be parsed out of order.
Returns a slice of parsed messages and an error if any message fails to parse. On error, all parsing stops and the first error is returned.
func ParseMessagesFromStreamSequential ¶
func ParseMessagesFromStreamSequential(r io.ReadSeeker) ([]*Message, error)
ParseMessagesFromStreamSequential parses messages from a stream one at a time without parallelism.
This is useful for comparison/benchmarking or when you want deterministic single-threaded behavior.
func ParseMessagesFromStreamSequentialSkipErrors ¶
func ParseMessagesFromStreamSequentialSkipErrors(r io.ReadSeeker) ([]*Message, error)
ParseMessagesFromStreamSequentialSkipErrors parses messages from a stream sequentially, skipping any that fail.
This is useful when a GRIB2 file contains messages with unsupported templates. Successfully parsed messages are returned; errors are silently skipped.
func ParseMessagesFromStreamWithContext ¶
func ParseMessagesFromStreamWithContext(ctx context.Context, r io.ReadSeeker, workers int) ([]*Message, error)
ParseMessagesFromStreamWithContext parses messages from a stream with context support for cancellation.
The context can be used to cancel the parsing operation. If cancelled, parsing stops and the context error is returned.
If workers <= 0, defaults to runtime.NumCPU().
func ParseMessagesFromStreamWithWorkers ¶
func ParseMessagesFromStreamWithWorkers(r io.ReadSeeker, workers int) ([]*Message, error)
ParseMessagesFromStreamWithWorkers parses messages from a stream with a specific number of workers.
If workers <= 0, defaults to runtime.NumCPU().
func ParseMessagesSequential ¶
ParseMessagesSequential parses messages one at a time without parallelism.
This is useful for comparison/benchmarking or when you want deterministic single-threaded behavior.
func ParseMessagesSequentialSkipErrors ¶
ParseMessagesSequentialSkipErrors parses messages sequentially, skipping any that fail.
This is useful when a GRIB2 file contains messages with unsupported templates. Successfully parsed messages are returned; errors are silently skipped.
func ParseMessagesWithContext ¶
ParseMessagesWithContext parses messages with context support for cancellation.
The context can be used to cancel the parsing operation. If cancelled, parsing stops and the context error is returned.
If workers <= 0, defaults to runtime.NumCPU().
func ParseMessagesWithWorkers ¶
ParseMessagesWithWorkers parses messages with a specific number of workers.
If workers <= 0, defaults to runtime.NumCPU().
func (*Message) Coordinates ¶
Coordinates returns the lat/lon coordinates for this message's grid.
Returns two slices (latitudes and longitudes) in grid scan order, matching the order of values returned by DecodeData().
Currently only supports LatLonGrid (Template 3.0). Returns an error for other grid types.
func (*Message) DecodeData ¶
DecodeData decodes the data values from this message.
Returns a slice of float32 values in grid scan order. Missing/undefined values are represented as 9.999e20.
This method combines the data representation (Section 5), bitmap (Section 6), and packed data (Section 7) to produce the final decoded values.
type MessageBoundary ¶
type MessageBoundary struct {
Start int // Byte offset where the message starts
Length uint64 // Length of the message in bytes
Index int // Sequential index of this message in the file (0-based)
}
MessageBoundary represents the location and size of a GRIB2 message within a file.
func FindMessages ¶
func FindMessages(data []byte) ([]MessageBoundary, error)
FindMessages scans the data for GRIB2 message boundaries.
This function performs a quick scan of the input data to locate all GRIB2 messages by finding "GRIB" magic numbers and reading their lengths from Section 0. It does not parse the full message content.
Returns a slice of MessageBoundary structs indicating where each message starts and how long it is. The boundaries preserve the original order of messages in the file.
This function is designed to be fast so that message boundaries can be found quickly before parallel decoding begins.
func FindMessagesInStream ¶
func FindMessagesInStream(r io.ReadSeeker) ([]MessageBoundary, error)
FindMessagesInStream scans an io.ReadSeeker for GRIB2 message boundaries.
This function performs a quick scan of the input stream to locate all GRIB2 messages by finding "GRIB" magic numbers and reading their lengths from Section 0. It does not parse the full message content.
The stream position is restored to its original position after scanning.
Returns a slice of MessageBoundary structs indicating where each message starts and how long it is. The boundaries preserve the original order of messages in the stream.
type ParameterID ¶
type ParameterID struct {
Discipline uint8 // WMO Code Table 0.0
Category uint8 // WMO Code Table 4.1 (discipline-specific)
Number uint8 // WMO Code Table 4.2 (category-specific within discipline)
}
ParameterID uniquely identifies a GRIB2 parameter using WMO standard codes.
GRIB2 parameters are defined by a three-number tuple:
- Discipline: Product discipline (0=Meteorological, 1=Hydrological, etc.)
- Category: Parameter category within the discipline
- Number: Specific parameter within the category
This matches the GRIB2 specification (WMO Manual 306, Tables 4.1 and 4.2).
func (ParameterID) CategoryName ¶
func (p ParameterID) CategoryName() string
CategoryName returns the parameter category name.
func (ParameterID) ShortName ¶
func (p ParameterID) ShortName() string
ShortName returns a standardized short name for the parameter.
This matches common meteorological abbreviations used in tools like wgrib2. Returns empty string if no standard abbreviation exists.
func (ParameterID) String ¶
func (p ParameterID) String() string
String returns the full parameter name from WMO tables.
Example: "Temperature", "Geopotential Height", "Relative Humidity"
type ParseError ¶
type ParseError struct {
Section int // Which section (0-7), or -1 if file-level
Offset int // Byte offset in file where error occurred
Message string // Description of the error
Underlying error // Wrapped error, if any
}
ParseError represents an error during GRIB2 parsing. It includes context about where in the file the error occurred.
func (*ParseError) Error ¶
func (e *ParseError) Error() string
Error implements the error interface.
func (*ParseError) Unwrap ¶
func (e *ParseError) Unwrap() error
Unwrap returns the underlying error, if any. This allows errors.Is and errors.As to work correctly.
type ReadOption ¶
type ReadOption func(*readConfig)
ReadOption configures the behavior of Read operations.
func WithCenter ¶
func WithCenter(center uint16) ReadOption
WithCenter filters messages by originating center.
Example:
// Only NCEP data (center 7) fields, _ := grib.ReadWithOptions(data, WithCenter(7))
func WithContext ¶
func WithContext(ctx context.Context) ReadOption
WithContext sets a context for cancellation and timeout support.
The context can be used to cancel parsing operations or set timeouts.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() fields, _ := grib.ReadWithOptions(data, WithContext(ctx))
func WithDiscipline ¶
func WithDiscipline(discipline uint8) ReadOption
WithDiscipline filters messages by discipline.
Example:
// Only meteorological products (discipline 0) fields, _ := grib.ReadWithOptions(data, WithDiscipline(0))
func WithFilter ¶
func WithFilter(filter func(*Message) bool) ReadOption
WithFilter applies a custom filter to select which messages to parse.
The filter function receives each message and returns true to include it or false to skip it. This can be used to filter by parameter, level, etc.
Note: The message is partially parsed to extract metadata for filtering.
Example:
// Only temperature fields
filter := func(msg *Message) bool {
return msg.Section4.Product.GetParameterCategory() == 0
}
fields, _ := grib.ReadWithOptions(data, WithFilter(filter))
func WithParameterCategory ¶
func WithParameterCategory(category uint8) ReadOption
WithParameterCategory filters messages by parameter category.
This is a convenience wrapper around WithFilter for common filtering needs.
Example:
// Only temperature parameters (category 0) fields, _ := grib.ReadWithOptions(data, WithParameterCategory(0))
func WithParameterNumber ¶
func WithParameterNumber(number uint8) ReadOption
WithParameterNumber filters messages by parameter number within a category.
Example:
// Temperature (category 0, number 0)
fields, _ := grib.ReadWithOptions(data,
WithParameterCategory(0),
WithParameterNumber(0))
func WithSequential ¶
func WithSequential() ReadOption
WithSequential disables parallel processing and parses messages sequentially.
This can be useful for debugging or when deterministic single-threaded behavior is desired.
Example:
fields, _ := grib.ReadWithOptions(data, WithSequential())
func WithSkipErrors ¶
func WithSkipErrors() ReadOption
WithSkipErrors continues parsing even if some messages fail.
By default, the first error stops parsing and is returned. With this option, failing messages are skipped and parsing continues.
Example:
fields, _ := grib.ReadWithOptions(data, WithSkipErrors())
func WithWorkers ¶
func WithWorkers(workers int) ReadOption
WithWorkers sets the number of concurrent workers for parallel parsing.
If workers <= 0, defaults to runtime.NumCPU().
Example:
fields, _ := grib.ReadWithOptions(data, WithWorkers(4))
type UnsupportedTemplateError ¶
type UnsupportedTemplateError struct {
Section int // Which section (3=grid, 4=product, 5=data)
TemplateNumber int // The unsupported template number
}
UnsupportedTemplateError indicates a template number that isn't implemented yet.
func (*UnsupportedTemplateError) Error ¶
func (e *UnsupportedTemplateError) Error() string
Error implements the error interface.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
benchmark
command
Package main provides a benchmarking tool for GRIB2 file parsing performance.
|
Package main provides a benchmarking tool for GRIB2 file parsing performance. |
|
gribinfo
command
Package main provides a command-line tool for examining GRIB2 files.
|
Package main provides a command-line tool for examining GRIB2 files. |
|
gribvalidate
command
Package main provides a command-line tool for validating GRIB2 files.
|
Package main provides a command-line tool for validating GRIB2 files. |
|
Package data provides data representation types and decoders for GRIB2.
|
Package data provides data representation types and decoders for GRIB2. |
|
Package grid provides grid definition types and parsers for GRIB2.
|
Package grid provides grid definition types and parsers for GRIB2. |
|
Package internal provides internal utilities for squall.
|
Package internal provides internal utilities for squall. |
|
testutil
Package testutil provides utilities for testing GRIB2 parsing against reference implementations.
|
Package testutil provides utilities for testing GRIB2 parsing against reference implementations. |
|
Package product provides product definition types and parsers for GRIB2.
|
Package product provides product definition types and parsers for GRIB2. |
|
Package section provides parsers for GRIB2 message sections.
|
Package section provides parsers for GRIB2 message sections. |
|
Package tables provides WMO code table lookups for GRIB2 metadata.
|
Package tables provides WMO code table lookups for GRIB2 metadata. |