squall

package module
v0.0.0-...-473aad9 Latest Latest
Warning

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

Go to latest
Published: Nov 15, 2025 License: MIT Imports: 11 Imported by: 1

README

squall - GRIB2 Parser for Go

Go Reference Go Report Card

squall is a Go library for reading GRIB2 (GRIdded Binary 2nd edition) meteorological data files. It provides high-performance parallel decoding of GRIB2 files with a simple API.

Motivation: there are a few Go libraries for reading GRIB files, though none seems to be actively maintained and all seem to be incomplete. I spent some time using Claude to extend go-grib2 for my needs, though it is more or less a transpilation of the C wgrib2 library, which is somewhat baroque. Claude did well enough that I was curious whether it could implement a library more to my aesthetic from scratch.

I gave it a general description of what I wanted:

  • That the external API should generally follow go-grib2, which provides a Read() entrypoint and returns an array of GRIB2 objects, one for each record in the file.
  • That, unlike wgrib2, it should try to be data-driven and should encode things like offsets that depend on the type of object being parsed in tables, rather than through complex control flow in code.
  • That it should read records in parallel.

Claude generated the plan in docs/ and the code followed from that; the implementation is 100% due to Claude Code; I intentionally have not directly edited any of the code myself, though I did give Claude specific guidance on a few points along the way:

  • To take an io.ReadCloser in the Read() method (admittedly, contrary to my original direction to follow go-grib2's public API.)
  • When we started looking at performance, after Claude suggested optimizing the lat-long coordinate decoding kernel, which was 75% of the runtime, I instead suggested that many records would likely have the same coordinate specifications and that it would be worth finding the unique specifications, decoding those once, and sharing the results. That led to 221f7b146e, which was a significant speedup.
  • There were, of course, other points of guidance and correction along the way, though all directional advice rather than specific directions about how the implementation should be done.

Overall, I'm impressed with how far Claude has been able to go with this.

Installation

go get github.com/mmp/squall

Quick Start

package main

import (
    "fmt"
    "log"
    "os"

    grib "github.com/mmp/squall"
)

func main() {
    // Open GRIB2 file
    f, err := os.Open("forecast.grib2")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()

    // Parse all messages
    messages, err := grib.Read(f)
    if err != nil {
        log.Fatal(err)
    }

    // Print summary
    for _, msg := range messages {
        fmt.Printf("%s at %s: %s (%d points)\n",
            msg.Parameter, msg.Level, msg.RefTime.Format("2006-01-02 15:04"),
            len(msg.Values))
    }
}

Usage Examples

Filtering by Parameter
// Only read temperature and humidity
messages, err := grib.ReadWithOptions(f,
    grib.WithParameterFilter("Temperature", "Relative Humidity"))
Filtering by Level
// Only 500 mb and surface data
messages, err := grib.ReadWithOptions(f,
    grib.WithLevelFilter("500 mb", "Surface"))
Combined Filters
// Temperature at 2m above ground
messages, err := grib.ReadWithOptions(f,
    grib.WithParameterFilter("Temperature"),
    grib.WithLevelFilter("2 m above ground"))
Context and Cancellation
import "context"
import "time"

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

messages, err := grib.ReadWithOptions(f,
    grib.WithContext(ctx))
Accessing Data
for _, msg := range messages {
    fmt.Printf("Parameter: %s\n", msg.Parameter)
    fmt.Printf("Level: %s\n", msg.Level)
    fmt.Printf("Reference Time: %s\n", msg.RefTime)
    fmt.Printf("Forecast Time: %s\n", msg.ForecastTime)

    // Access grid values
    for _, val := range msg.Values {
        fmt.Printf("  Lat: %.4f, Lon: %.4f, Value: %.2f\n",
            val.Latitude, val.Longitude, val.Value)
    }
}

Performance

Benchmarked on a 357MB HRRR CONUS file (708 messages, 16M grid points), squall loads the entire file in 0.9s on an M4 MacBook Pro. Speed is due to both algorithmic optimizations and parallel decoding of coordinates and messages.

Command-Line Tool

The gribinfo tool provides quick inspection of GRIB2 files:

go install github.com/mmp/squall/cmd/gribinfo@latest

gribinfo forecast.grib2

Output:

Message 1:
  Parameter: Temperature
  Level: 2 m above ground
  Reference Time: 2025-10-15 11:00:00 UTC
  Grid: 184x123 points
  Range: 250.5 to 305.2 K

Supported Features

Note that squall's support for GRIB files is not complete, though it suffices for my own needs so far with NOAA HRRR files.

Grid Types
  • Latitude/Longitude regular grids (Template 3.0)
  • Lambert Conformal (Template 3.30)
Data Packing
  • Simple packing (Template 5.0)
  • Complex packing with spatial differencing (Template 5.3)
Validation

Output for a number of grib files has been validated against wgrib2 (NOAA's reference implementation).

Contributing

I would like this repository to remain purely written by Claude Code. If you have a grib file that it cannot handle, please open an issue and provide the grib file or a pointer to it. I will happily put Claude on the job.

Testing

# Run all tests
go test ./...

# Run with coverage
go test -cover ./...

# Run integration tests (requires test files)
go test -v -run TestIntegration

# Benchmark
go test -bench=. -benchmem

License

MIT License - See LICENSE for details

References

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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsMissing

func IsMissing(v float32) bool

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

func SplitMessages(data []byte) ([][]byte, error)

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

func ValidateMessageStructure(data []byte) error

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

func (g *GRIB2) CountValid() int

CountValid returns the number of valid (non-missing) data values.

func (*GRIB2) GetMessage

func (g *GRIB2) GetMessage() *Message

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.

func (*GRIB2) MaxValue

func (g *GRIB2) MaxValue() float32

MaxValue returns the maximum data value in the field.

func (*GRIB2) MinValue

func (g *GRIB2) MinValue() float32

MinValue returns the minimum data value in the field.

func (*GRIB2) String

func (g *GRIB2) String() string

String returns a human-readable summary of the field.

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

func ParseMessage(data []byte) (*Message, error)

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

func ParseMessages(data []byte) ([]*Message, error)

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

func ParseMessagesSequential(data []byte) ([]*Message, error)

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

func ParseMessagesSequentialSkipErrors(data []byte) ([]*Message, error)

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

func ParseMessagesWithContext(ctx context.Context, data []byte, workers int) ([]*Message, error)

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

func ParseMessagesWithWorkers(data []byte, workers int) ([]*Message, error)

ParseMessagesWithWorkers parses messages with a specific number of workers.

If workers <= 0, defaults to runtime.NumCPU().

func (*Message) Coordinates

func (m *Message) Coordinates() (latitudes, longitudes []float32, err error)

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

func (m *Message) DecodeData() ([]float32, error)

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.

func (*Message) String

func (m *Message) String() string

String returns a human-readable summary of the message.

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.

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.

Jump to

Keyboard shortcuts

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