Expand description
§Unofficial high-level safe Rust bindings to ecCodes library
This crate contains (mostly) safe high-level bindings for ecCodes library. Bindings can be considered safe mainly because all crate structures will take ownership of the data in memory before passing the raw pointer to ecCodes.
Currently only reading of GRIB files is supported.
Because of the ecCodes library API characteristics theses bindings are rather thick wrapper to make this crate safe and convenient to use.
This crate officially supports mainly Linux platforms same as the ecCodes library.
But it is possible to install ecCodes on MacOS
and this crate successfully compiles and all tests pass.
If you want to see more features released quicker do not hesitate to contribute and check out Github repository.
ecCodes is an open-source library for reading and writing GRIB and BUFR files developed by European Centre for Medium-Range Weather Forecasts.
§Errors and panics
This crate aims to return error whenever possible, even if the error is caused by implementation bug. As ecCodes is often used in scientific applications with long and extensive jobs, this allows the user to handle the error in the way that suits them best and not risk crashes.
All error descriptions are provided in the errors
module.
Destructors, which cannot panic, report errors through the log
crate.
None of the functions in this crate explicitly panics. However, users should be aware that dependencies might panic in some edge cases.
§Safety
This crate aims to be as safe as possible and a lot of effort has been put into testing its safety. Moreover, pointers are always checked for null before being dereferenced.
That said, neither main developer nor contributors have expertise in unsafe Rust and bugs might have slipped through. We are also not responsible for bugs in the ecCodes library.
If you find a bug or have a suggestion, feel free to discuss it on Github.
§Features
-
message_ndarray
- enables support for convertingKeyedMessage
tondarray::Array
. This feature is enabled by default. It is currently tested only with simple lat-lon grids. -
experimental_index
- enables support for creating and using index files for GRIB files. This feature is experimental and disabled by default. If you want to use it, please read the information provided incodes_index
documentation. -
docs
- builds the crate without linking ecCodes, particularly useful when building the documentation on docs.rs. For more details check documentation of eccodes-sys.
To build your own crate with this crate as dependency on docs.rs without linking ecCodes add following lines to your Cargo.toml
[package.metadata.docs.rs]
features = ["eccodes/docs"]
§Usage
To access a GRIB file you need to create CodesHandle
with one of provided constructors.
GRIB files consist of messages which represent data fields at specific time and level.
Messages are represented by the KeyedMessage
structure.
CodesHandle
implements FallibleStreamingIterator
which allows you to iterate over messages in the file. The iterator returns &KeyedMessage
which valid is until next iteration.
KeyedMessage
implements several methods to access the data as needed, most of those can be called directly on &KeyedMessage
.
You can also use try_clone()
to clone the message and prolong its lifetime.
Data contained by KeyedMessage
is represented as keys (like in dictionary).
Keys can be read with static types using read_key()
or with dynamic types
using read_key_dynamic()
. To discover what keys are present in a message use KeysIterator
.
You can use CodesNearest
to get the data values of four nearest gridpoints for given coordinates.
You can also modify the message with write_key()
and write
it to a new file with write_to_file()
.
§Example 1 - Reading GRIB file
// We are reading the mean sea level pressure for 4 gridpoints
// nearest to Reykjavik (64.13N, -21.89E) for 1st June 2021 00:00 UTC
// from ERA5 Climate Reanalysis
use eccodes::{ProductKind, CodesHandle, KeyRead};
use eccodes::FallibleStreamingIterator;
// Open the GRIB file and create the CodesHandle
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesHandle::new_from_file(file_path, product_kind)?;
// Use iterator to find a message with shortName "msl" and typeOfLevel "surface"
// We can use while let or for_each() to iterate over the messages
while let Some(msg) = handle.next()? {
// We need to specify the type of key we read
let short_name: String = msg.read_key("shortName")?;
let type_of_level: String = msg.read_key("typeOfLevel")?;
if short_name == "msl" && type_of_level == "surface" {
// Create CodesNearest for given message
let nearest_gridpoints = msg.codes_nearest()?
// Find the nearest gridpoints to Reykjavik
.find_nearest(64.13, -21.89)?;
// Print value and distance of the nearest gridpoint
println!("value: {}, distance: {}",
nearest_gridpoints[3].value,
nearest_gridpoints[3].distance);
}
}
§Example 2 - Writing GRIB files
// The crate provides basic support for setting `KeyedMessage` keys
// and writing GRIB files. The easiests (and safest) way to create a
// new custom message is to copy exisitng one from other GRIB file,
// modify the keys and write to new file.
// Here we are computing the temperature at 850hPa as an average
// of 900hPa and 800hPa and writing it to a new file.
use eccodes::FallibleStreamingIterator;
use eccodes::{CodesHandle, KeyRead, KeyWrite, ProductKind};
// Start by opening the file and creating CodesHandle
let file_path = Path::new("./data/iceland-levels.grib");
let mut handle = CodesHandle::new_from_file(file_path, ProductKind::GRIB)?;
// We need a message to edit, in this case we can use
// temperature at 700hPa, which is similar to our result
let mut new_msg = vec![];
// Get data values of temperatures at 800hPa and 900hPa
let mut t800: Vec<f64> = vec![];
let mut t900: Vec<f64> = vec![];
// Iterate over the messages and collect the data to defined vectors
while let Some(msg) = handle.next()? {
let short_name: String = msg.read_key("shortName")?;
if short_name == "t" {
let level: i64 = msg.read_key("level")?;
if level == 700 {
// To use message outside of the iterator we need to clone it
new_msg.push(msg.try_clone()?);
}
if level == 800 {
t800 = msg.read_key("values")?;
}
if level == 900 {
t900 = msg.read_key("values")?;
}
}
}
// This converts the vector to a single message
let mut new_msg = new_msg.remove(0);
// Compute temperature at 850hPa
let t850: Vec<f64> = t800
.iter()
.zip(t900.iter())
.map(|t| (t.0 + t.1) / 2.0)
.collect();
// Edit appropriate keys in the editable message
new_msg.write_key("level", 850)?;
new_msg.write_key("values", &t850)?;
// Save the message to a new file without appending
new_msg.write_to_file(Path::new("iceland-850.grib"), false)?;
Re-exports§
pub use codes_handle::CodesHandle;
pub use codes_handle::ProductKind;
pub use codes_index::CodesIndex;
experimental_index
pub use codes_nearest::CodesNearest;
pub use codes_nearest::NearestGridpoint;
pub use errors::CodesError;
pub use keyed_message::DynamicKeyType;
pub use keyed_message::KeyRead;
pub use keyed_message::KeyWrite;
pub use keyed_message::KeyedMessage;
pub use keys_iterator::KeysIterator;
pub use keys_iterator::KeysIteratorFlags;
Modules§
- codes_
handle - Definition and constructors of
CodesHandle
used for accessing GRIB files - codes_
index experimental_index
- ⚠️ EXPERIMENTAL FEATURE - POSSIBLY UNSAFE ⚠️
Definition ofCodesIndex
and associated functions used for efficient selection of messages from GRIB file - codes_
nearest - Definition and associated functions of
CodesNearest
used for finding nearest gridpoints inKeyedMessage
- errors
- Definition of errors returned by this crate
- keyed_
message - Definition of
KeyedMessage
and its associated functions used for reading and writing data of given variable from GRIB file - keys_
iterator - Definition of
KeysIterator
used for iterating through keys inKeyedMessage
- message_
ndarray message_ndarray
- Definitions for converting a
KeyedMessage
to ndarray
Traits§
- Fallible
Iterator - An
Iterator
-like trait that allows for calculation of items to fail. - Fallible
Streaming Iterator - A fallible, streaming iterator.
- Into
Fallible Iterator - Conversion into a
FallibleIterator
.