Source code for shoot.profiles.download
#!/usr/bin/env python3
"""
Created on Thu Aug 19 10:21:12 2025
@author: jbroust
"""
import logging
import os
import numpy as np
import xarray as xr
from argopy import DataFetcher
from .. import meta as smeta
logger = logging.getLogger(__name__)
#### It requires the user to be already logged in the copernicus
#### marine toolbox
[docs]
class Download:
"""Download and manage Argo profile data
Fetches Argo profile data from ERDDAP for a specified spatiotemporal region.
Caches downloaded data by year to avoid repeated downloads.
Parameters
----------
time : xarray.DataArray
Time coordinate range for data download.
lat_min : float
Minimum latitude.
lat_max : float
Maximum latitude.
lon_min : float
Minimum longitude.
lon_max : float
Maximum longitude.
root_path : str
Root directory for caching downloaded data.
max_depth : float, default 1000
Maximum depth (m) for profile data.
Attributes
----------
profiles : xarray.Dataset
Downloaded Argo profiles concatenated across all years.
"""
[docs]
def __init__(
self,
time,
lat_min,
lat_max,
lon_min,
lon_max,
root_path,
max_depth=1000,
):
"""Initialize downloader and fetch data
Parameters
----------
time : xarray.DataArray
Time coordinate range for data download.
lat_min : float
Minimum latitude.
lat_max : float
Maximum latitude.
lon_min : float
Minimum longitude.
lon_max : float
Maximum longitude.
root_path : str
Root directory for caching downloaded data.
max_depth : float, default 1000
Maximum depth (m) for profile data.
"""
self.path = root_path
self.lon_min = lon_min
self.lon_max = lon_max
self.lat_min = lat_min
self.lat_max = lat_max
self.max_depth = max_depth
self.root_path = root_path
self.time = time
years = np.unique(self.time.dt.year.values)
self.profiles = None
for year in years:
path_tmp = os.path.join(self.root_path, f"argo_profile_{year}.nc")
if os.path.exists(path_tmp):
logger.info("Data already exists for year %s", year)
profiles_tmp = xr.open_dataset(path_tmp)
else:
tmin = str(time.sel(time=str(year)).min().dt.strftime("%Y-%m-%d").values)
tmax = str(time.sel(time=str(year)).max().dt.strftime("%Y-%m-%d").values)
print(tmin, tmax)
profiles_tmp = self._load(tmin, tmax)
profiles_tmp.to_netcdf(path_tmp)
if self.profiles:
self.profiles = xr.concat([self.profiles, profiles_tmp], dim="N_PROF")
else:
self.profiles = profiles_tmp
def _load(self, tmin, tmax):
"""Download Argo profiles from ERDDAP for a time range
Parameters
----------
tmin : str
Start date (YYYY-MM-DD format).
tmax : str
End date (YYYY-MM-DD format).
Returns
-------
xarray.Dataset
Downloaded Argo profiles.
"""
f = DataFetcher(src='erddap', mode='expert')
box = [self.lon_min, self.lon_max, self.lat_min, self.lat_max, 0, self.max_depth, tmin, tmax]
points = f.region(box).to_xarray()
profiles = points.argo.point2profile()
return profiles
[docs]
@classmethod
def from_ds(cls, ds, root_path, max_depth=1000):
"""Create Download instance from a dataset's spatiotemporal extent
Parameters
----------
ds : xarray.Dataset
Dataset with lat, lon, and time coordinates.
root_path : str
Root directory for caching downloaded data.
max_depth : float, default 1000
Maximum depth (m) for profile data.
Returns
-------
Download
New Download instance with data fetched for the dataset's extent.
"""
lat = smeta.get_lat(ds)
lon = smeta.get_lon(ds)
lon_min = float(lon.min().values)
lon_max = float(lon.max().values)
lat_min = float(lat.min().values)
lat_max = float(lat.max().values)
time = smeta.get_time(ds)
return cls(time, lat_min, lat_max, lon_min, lon_max, root_path, max_depth=max_depth)
[docs]
def load_from_ds(ds, root_path="/local/tmp/data", max_depth=1000):
"""Load Argo profiles for a dataset's spatiotemporal extent
Parameters
----------
ds : xarray.Dataset
Dataset with lat, lon, and time coordinates.
root_path : str, default "/local/tmp/data"
Root directory for caching downloaded data.
Returns
-------
xarray.Dataset
Downloaded Argo profiles.
"""
do = Download.from_ds(ds, root_path, max_depth=max_depth)
return do.profiles