Quick start — Copernicus Marine via the EarthLens facade¶
This notebook walks through a minimal Copernicus Marine download via the
unified EarthLens facade. The target is OSTIA L4 SST — the smallest,
surface-only dataset in the curated catalog, so the request takes seconds and
the returned NetCDF is tens of kilobytes.
It also shows two common follow-on patterns:
- bypassing the facade with
CMEMS(...)directly; - post-processing the returned NetCDF through
pyramids.netcdf.NetCDF(the project's standard GIS reader).
The notebook reads Copernicus Marine portal credentials from
COPERNICUSMARINE_SERVICE_USERNAME and COPERNICUSMARINE_SERVICE_PASSWORD
environment variables. See
Authentication for the full
credential-source ladder.
Install¶
pip install earthlens[cmems]
If you want to follow the post-process step, also install
pyramids (already a runtime
dependency of earthlens).
Register a free portal account once at https://marine.copernicus.eu/register. On a workstation, the easiest path is one shell command:
copernicusmarine login
which prompts for username + password and writes
~/.copernicusmarine/.copernicusmarine-credentials. All subsequent
EarthLens(data_source="cmems", ...) calls — including this notebook — read
that file automatically.
Setup¶
Consolidate the imports up front: EarthLens is the unified entry point and
earthlens.cmems.Catalog is the offline catalog reader. We also create the
output directory the downloads will land in.
import datetime as dt
import os
from pathlib import Path
from earthlens import EarthLens
from earthlens.cmems import Catalog
OUT_DIR = Path('data/cmems-quickstart')
OUT_DIR.mkdir(parents=True, exist_ok=True)
Credentials¶
Read the portal username and password from the environment. Leaving them as
None is fine if you logged in once with copernicusmarine login — the
backend then falls back to the cached credentials file.
SERVICE_USERNAME = os.environ.get('COPERNICUSMARINE_SERVICE_USERNAME')
SERVICE_PASSWORD = os.environ.get('COPERNICUSMARINE_SERVICE_PASSWORD')
Pick a recent date window¶
OSTIA NRT is a rolling near-real-time product, so we pick a window ~30 days back from today; that keeps the request inside the dataset's moving coverage bounds (a hardcoded date eventually falls off the back).
_recent = dt.datetime.now(dt.timezone.utc) - dt.timedelta(days=30)
START = _recent.strftime('%Y-%m-%d')
END = (_recent + dt.timedelta(days=6)).strftime('%Y-%m-%d')
Browse the curated catalog (no network, no auth)¶
earthlens.cmems.Catalog() parses the bundled catalog/ directory
once per process (~ms warm). Use it to discover what's curated and look
up a variable's units before issuing a download. Uncurated dataset ids
still work — pass any id that copernicusmarine.describe() recognises.
cat = Catalog()
print(f'available_datasets: {len(cat.available_datasets)}')
print(f'curated datasets: {len(cat.datasets)}')
ds = cat.get_dataset('METOFFICE-GLO-SST-L4-NRT-OBS-SST-V2')
print('\nMETOFFICE-GLO-SST-L4-NRT-OBS-SST-V2:')
print(f' cadence: {ds.cadence}')
print(f' domain: {ds.domain}')
for name, var in sorted(ds.variables.items()):
print(f' {name}: units={var.units!r}, long_name={var.long_name!r}')
Download — one regional 7-day OSTIA SST subset via the facade¶
The smallest meaningful CMEMS request: one variable, surface only, a 6° box off Iberia, one week. The toolbox returns a single NetCDF tens of kilobytes in size; it completes in seconds.
The facade EarthLens(data_source="cmems", ...) forwards every extra kwarg
(service_username, service_password, credentials_file, file_format,
minimum_depth, maximum_depth, overwrite) to the backend constructor
verbatim.
Build the request object first so the configuration is easy to read and tweak before any network call.
earthlens = EarthLens(
data_source='cmems',
start=START,
end=END,
cadence='daily',
dataset='METOFFICE-GLO-SST-L4-NRT-OBS-SST-V2',
variables=['analysed_sst'],
aoi=[-10.0, 30.0, -4.0, 36.0],
path=str(OUT_DIR),
service_username=SERVICE_USERNAME,
service_password=SERVICE_PASSWORD,
)
download() issues the subset request and returns the list of written
NetCDF paths.
paths = earthlens.download()
for p in paths:
print(p)
Same call without the facade¶
Useful if you want to introspect the catalog row on cmems.cat, or to type-
check against the CMEMS class directly.
Same request as above, with overwrite=True so it re-writes the file. Build
the object first.
cmems = EarthLens(
data_source="cmems",
start=START,
end=END,
cadence='daily',
dataset='METOFFICE-GLO-SST-L4-NRT-OBS-SST-V2',
variables=['analysed_sst'],
aoi=[-10.0, 30.0, -4.0, 36.0],
path=str(OUT_DIR),
service_username=SERVICE_USERNAME,
service_password=SERVICE_PASSWORD,
overwrite=True,
)
Then download and print the returned paths.
paths = cmems.download()
print(paths)
Open the downloaded NetCDF read-only and list its variables to confirm the subset landed as expected.
from pyramids.netcdf import NetCDF
nc = NetCDF.read_file(str(paths[0]), read_only=True)
print('variables:', list(nc.meta_data.variables.keys()))
Inspect the analysed_sst variable metadata, read its array, and close the
handle. The shape is (time, lat, lon).
sst = nc.meta_data.variables['analysed_sst']
print(
f'analysed_sst: long_name={getattr(sst, "long_name", None)!r} unit={getattr(sst, "unit", None)!r}'
)
arr = nc.read_array('analysed_sst')
print(f'shape (time, lat, lon): {arr.shape}')
nc.close()
Next steps¶
- GLORYS — thermocline time-series: the
4-D depth-axis pattern (
thetaoat fixed depths). - PISCES — chlorophyll seasonal cycle:
multi-variable subset + monthly
groupby('time.month').mean(). - Altimetry — coastal SLA signal: multi-mission L4 sea-level anomaly along a coastal box.