Local Data Module¶
local ¶
Local precipitation data sources for pyCropWat.
This module lets you drive pycropwat.EffectivePrecipitation with your own
precipitation rasters instead of downloading precipitation from Google Earth Engine.
Two on-disk layouts are supported:
- Raster mode - a directory (or glob) of one GeoTIFF per month, where the file name
carries the year and month, e.g.
Precip_2005_07.tif. - NetCDF mode - one or more NetCDF/HDF5 files holding a precipitation variable with a
timecoordinate (or a single month per file, dated by file name).
Precipitation is returned as a 2-D xarray.DataArray with dims ('y', 'x'),
float32 values in millimetres, nodata as NaN, a north-up y coordinate and a CRS
attached via rioxarray. That is exactly what the rest of pyCropWat expects, so the
precipitation-only methods (cropwat, fao_aglw, fixed_percentage,
dependable_rainfall, farmwest) run with no Earth Engine involvement at all.
Classes:
| Name | Description |
|---|---|
LocalPrecipitationSource |
Indexed, lazily-opened reader for local monthly precipitation data. |
Functions:
| Name | Description |
|---|---|
parse_year_month |
Extract |
open_local_precipitation |
Convenience factory returning a |
Example
from pycropwat.local import LocalPrecipitationSource
# A directory of monthly WRF GeoTIFFs named Precip_YYYY_MM.tif
src = LocalPrecipitationSource(
'../pyCropWat_Data/Precip',
pattern='Precip_*.tif',
nodata=-9999,
)
print(src.kind, len(src), src.year_range, src.crs, src.shape)
da = src.get_month(2005, 7) # xr.DataArray, dims ('y', 'x'), mm
print(float(da.mean()))
NetCDF, with an explicit variable and a unit conversion (m -> mm):
See Also
pycropwat.core : Effective precipitation workflow that consumes these arrays. pycropwat.methods : Precipitation-only effective precipitation formulas.
LocalPrecipitationSource ¶
LocalPrecipitationSource(path: Union[str, Path], pattern: str = '*.tif', variable: Optional[str] = None, scale_factor: float = 1.0, nodata: Optional[Union[float, Sequence[float]]] = None, crs: Optional[Union[str, CRS]] = None, date_regex: Optional[str] = None, time_dim: str = 'time', x_dim: Optional[str] = None, y_dim: Optional[str] = None)
Reader for user-supplied local monthly precipitation data.
Wraps a directory of single-month rasters, or one/many NetCDF files, and exposes
them as analysis-ready monthly xarray.DataArray objects. Files are indexed
up front (cheap) and pixel data is only read when get_month is called.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or Path
|
A directory of rasters, a single raster/NetCDF file, or a glob string
(e.g. |
required |
pattern
|
str
|
Glob applied when |
'*.tif'
|
variable
|
str
|
NetCDF variable holding precipitation. Auto-detected when None. |
None
|
scale_factor
|
float
|
Constant multiplier applied to every returned array, for converting the source
units to millimetres per month: |
1.0
|
nodata
|
float or sequence of float
|
Extra nodata sentinel(s) to mask, in addition to the nodata declared in the
file metadata. Compared with |
None
|
crs
|
str or CRS
|
CRS to attach to the returned arrays (e.g. |
None
|
date_regex
|
str
|
Custom regex with named groups |
None
|
time_dim
|
str
|
Name of the NetCDF time coordinate. Falls back to |
'time'
|
x_dim
|
str
|
Name of the NetCDF X dimension. Auto-detected from |
None
|
y_dim
|
str
|
Name of the NetCDF Y dimension. Auto-detected from |
None
|
Attributes:
| Name | Type | Description |
|---|---|---|
path |
Path
|
The path/glob the source was constructed from. |
scale_factor |
float
|
Multiplier applied to returned data. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If |
ValueError
|
If no usable files are found, raster and NetCDF files are mixed, no file name could be dated, or the NetCDF precipitation variable is ambiguous. |
Notes
Raster layout limitation. Raster mode expects one file per month, dated by
file name. A single multi-band raster per year (12 bands = 12 months) is not
supported and raises a ValueError: split it into monthly files, or supply
a date_regex matching a one-file-per-month naming scheme. A raster that is
dated to a single month but happens to carry extra bands is accepted - the first
band is used and a warning is logged.
Every array returned by get_month has dims exactly ('y', 'x'), dtype
float32, a descending (north-up) y coordinate, nodata as NaN, the source
CRS written via rioxarray, and attrs
{'units', 'long_name', 'year', 'month', 'source'}.
One grid for every month. All months are stacked into a single time series
downstream, so every file must share one CRS, shape and affine transform. Raster
mode checks that up front from file metadata only (no pixels are read) and raises a
ValueError naming the first offending file and how it differs; NetCDF mode
catches a mismatched grid when the month is read. That check always compares the
CRSs the files declare with each other, never with the crs argument, so a
mixed-CRS directory is caught whether or not an override was supplied: without
crs it is one of the grid differences that raise, and with crs the override
still wins (that is what it is for) but the disagreement is logged as a WARNING,
since relabelling never reprojects. Hence shape, resolution, bounds and
native_bounds describe every month, and bounds / native_bounds are
always ordered (minx, miny, maxx, maxy), including for south-up files.
Curvilinear NetCDF coordinates. A file with 2-D coordinates (the WRF
XLAT / XLONG layout on south_north / west_east dims) is supported,
whether xarray has promoted them to coordinates (the file gives the precipitation
variable a CF coordinates = "XLONG XLAT" attribute) or they sit in the file as
plain 2-D data variables on the same dims, as hand-cut and post-processed subsets
often leave them. Either way the 2-D coordinates are collapsed to 1-D along the
middle row/column. Map-projected
model output is always mildly curvilinear in lon/lat, so the resulting displacement
is measured - beyond half a cell it is logged as a WARNING quantifying the error, and
beyond 20% of the axis span (or if the collapsed coordinate is not monotonic) it
raises rather than silently returning a wrong grid. A dimension with no usable
coordinate at all falls back to pixel indices with a WARNING: the shape survives but
the grid is not georeferenced.
Examples:
Directory of monthly GeoTIFFs:
from pycropwat.local import LocalPrecipitationSource
src = LocalPrecipitationSource('../pyCropWat_Data/Precip',
pattern='Precip_*.tif',
nodata=-9999)
print(src.kind, len(src), src.year_range) # raster 264 (2000, 2021)
da = src.get_month(2005, 7)
print(da.dims, da.shape) # ('y', 'x') (689, 799)
src.close()
NetCDF stack used as a context manager:
with LocalPrecipitationSource('precip.nc', variable='precip') as src:
print(src.available_months()[:3])
da = src.get_month(2005, 7)
Source code in pycropwat/local.py
bounds
property
¶
tuple : (minx, miny, maxx, maxy) in EPSG:4326 lon/lat degrees.
native_bounds
property
¶
tuple : (minx, miny, maxx, maxy) in the source CRS.
resolution
property
¶
tuple : (x_resolution, y_resolution) as positive values in CRS units.
shape
property
¶
tuple : (n_rows, n_cols) of every monthly grid.
In raster mode this is validated across all indexed files when the source is built; a file on a different grid raises rather than being read.
year_range
property
¶
tuple : (first_year, last_year) present in the source.
__enter__ ¶
__exit__ ¶
__len__ ¶
__repr__ ¶
Return a concise, informative representation.
Source code in pycropwat/local.py
available_months ¶
List every month present in the source.
Returns:
| Type | Description |
|---|---|
list
|
Sorted list of |
Examples:
Source code in pycropwat/local.py
close ¶
Release any open NetCDF file handles.
Safe to call more than once. Rasters are opened and closed per call to
get_month, so this is a no-op in raster mode.
Source code in pycropwat/local.py
get_month ¶
Read the precipitation grid for one month.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
year
|
int
|
Calendar year. |
required |
month
|
int
|
Calendar month (1-12). |
required |
Returns:
| Type | Description |
|---|---|
DataArray or None
|
2-D array with dims |
Examples:
Source code in pycropwat/local.py
has_month ¶
Check whether a given month is available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
year
|
int
|
Calendar year. |
required |
month
|
int
|
Calendar month (1-12). |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True when the month can be read. |
Source code in pycropwat/local.py
open_local_precipitation ¶
Open a local precipitation dataset.
Thin convenience factory around LocalPrecipitationSource; every keyword
argument is forwarded unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str or Path
|
A directory of monthly rasters, a single raster/NetCDF file, or a glob string. |
required |
**kwargs
|
Keyword arguments forwarded to |
{}
|
Returns:
| Type | Description |
|---|---|
LocalPrecipitationSource
|
An indexed, ready-to-read precipitation source. |
Examples:
from pycropwat.local import open_local_precipitation
src = open_local_precipitation('../pyCropWat_Data/Precip',
pattern='Precip_*.tif',
nodata=-9999)
da = src.get_month(2005, 7)
src.close()
Source code in pycropwat/local.py
parse_year_month ¶
parse_year_month(name: Union[str, Path], date_regex: Optional[str] = None) -> Optional[Tuple[int, int]]
Extract a (year, month) pair from a file name or arbitrary string.
Layouts are tried most-specific-first and the last match in the string wins, so
directory noise and prefixes such as Precip_ or effective_precip_ never
confuse the parser. Recognised layouts:
| Layout | Example |
|---|---|
YYYY_MM |
Precip_2005_07.tif |
YYYY-MM |
precip-2005-07.nc |
YYYYMM |
pr200507.tif |
YYYY.MM |
pr.2005.07.tif |
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str or Path
|
File name, file stem, full path or any other string to parse. |
required |
date_regex
|
str
|
Custom regular expression exposing named groups |
None
|
Returns:
| Type | Description |
|---|---|
tuple or None
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Examples:
from pycropwat.local import parse_year_month
parse_year_month('Precip_2005_07.tif') # (2005, 7)
parse_year_month('pr200507') # (2005, 7)
parse_year_month('/data/2019/x-2005-07.nc') # (2005, 7)
parse_year_month('no_date_here.tif') # None
# Custom layout: MM_YYYY
parse_year_month('rain_07_2005.tif',
date_regex=r'(?P<month>\d{2})_(?P<year>\d{4})') # (2005, 7)
Source code in pycropwat/local.py
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | |