Core API¶
The user-facing facade lives in earthcatalog.facade; earthcatalog.catalog
re-exports it, so from earthcatalog import EarthCatalog keeps working.
earthcatalog.facade.EarthCatalog
¶
Simplified facade for querying an EarthCatalog.
Combines PyIceberg catalog, table, and CatalogInfo into a single interface for spatial/temporal queries with automatic file pruning.
Example::
from earthcatalog import open as ec_open
from obstore.store import S3Store
from shapely.geometry import Point
store = S3Store(bucket='my-bucket', region='us-west-2')
ec = ec_open(store=store, base='s3://my-bucket/catalog')
point = Point(-133.99, 58.74)
paths = ec.search_files(point, start_datetime='2020-01-01')
Source code in earthcatalog/facade.py
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 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 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 | |
Attributes¶
catalog
property
¶
The underlying PyIceberg catalog.
table
property
writable
¶
The underlying Iceberg stac_items table.
info
property
¶
Grid metadata + pruning for this catalog.
store
property
¶
The backing object store (bucket-level for S3 warehouses).
catalog_key
property
¶
Key of earthcatalog.db within :attr:store.
grid_type
property
¶
Return the grid partitioning system type.
grid_resolution
property
¶
Return the grid resolution (None for grids without one).
Functions¶
__init__(catalog, table, info, store=None, *, catalog_key=None)
¶
Initialize an EarthCatalog facade.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
catalog
|
SqlCatalog
|
PyIceberg SqlCatalog instance |
required |
table
|
Table
|
PyIceberg Table instance |
required |
info
|
CatalogInfo
|
CatalogInfo with grid metadata |
required |
store
|
ObjectStore | None
|
obstore Store instance (for reading hash index from S3) |
None
|
catalog_key
|
str | None
|
Key within store where catalog.db is persisted. Required for ingest() which needs to upload changes. |
None
|
Source code in earthcatalog/facade.py
search_files(geom, start_datetime=None, end_datetime=None)
¶
Return Parquet file paths for partitions intersecting geom.
Source code in earthcatalog/facade.py
search(**kwargs)
¶
Search across the catalog, returning a deferred EarthCatalogItemSearch.
Accepts the same kwargs as :func:rustac.search:
intersects, bbox, datetime, filter (CQL2 JSON),
ids, collections, max_items, limit, sortby,
include, exclude, query, etc.
Use the top-level datetime kwarg for temporal filtering. Do
not reference datetime inside the CQL2 filter —
rustac generates broken SQL when datetime appears in a CQL2
expression.
Performance¶
For fastest results use :func:earthcatalog.search.duck_search
(DuckDB parallel I/O, ~2× faster across all query types).
search() and search_to_arrow() use rustac (sequential per-file)
and have comparable speed. See :doc:/operations/search_performance
for detailed benchmarks.
Returns¶
EarthCatalogItemSearch
A lazy, pystac_client-compatible search result. No I/O until
items(), item_collection(), or pages() is called.
Source code in earthcatalog/facade.py
search_to_arrow(**kwargs)
¶
Search across the catalog, returning a PyArrow table.
Source code in earthcatalog/facade.py
ingest_inventory(inventory_path, *, mode='auto', config=None)
¶
Ingest an inventory using a (optionally distributed) Dask cluster.
Delegates to :class:earthcatalog.pipeline.IngestPipeline. config
(a :class:earthcatalog.ingest_config.IngestConfig) holds the tuning
knobs (chunk size, compact rows, stage, resume flags, create_client).
There is one ingest operation: mode only controls table handling —
"full" drops and rebuilds the Iceberg table, "delta" appends,
"auto" appends iff the table has rows. Input scope (complete
inventory vs. newer snapshot vs. precomputed delta parquet) is simply
which inventory_path you pass; the unified index dedups source
keys, so every run is resumable and idempotent.
With stage="ndjson" (default) items are staged to per-(cell,
year) NDJSON before a memory-bounded compaction to GeoParquet;
skip_fetch resumes from the staged NDJSON. Distributed runs
shard the inventory by part file where possible — workers stream
their own files and only the head node commits.
Returns the run summary dict ({"items": …, "rows": …}).
Source code in earthcatalog/facade.py
download_catalog(local_path)
¶
Download catalog.db from the backing store to local_path.
upload_catalog(local_path)
¶
Upload catalog.db from local_path to the backing store.
garbage_collect(inventory_path, *, dry_run=False)
¶
Remove orphaned STAC items whose source objects left the S3 Inventory.
Thin wrapper over :func:earthcatalog.gc.garbage_collect_for_catalog
using this catalog's store, unified index, and warehouse path: Bloom
detection, targeted GeoParquet rewrites, an Iceberg rebuild so
searches reflect the changes, and a stats-snapshot refresh.
Parameters¶
inventory_path:
Path or s3:// URI to the current S3 Inventory.
dry_run:
When True, detect and report orphans but make no changes.
Returns¶
Summary dict: candidates, confirmed, orphaned,
files_rewritten, rows_removed, partitions_affected,
copies_outside_index, residual_copies.
Source code in earthcatalog/facade.py
earthcatalog.catalog
¶
Catalog lifecycle and grid metadata.
- :class:
CatalogInfo— grid metadata read from Iceberg table properties, owning the read-side partitioner (spatial prune + temporal bin). open()/get_or_create()/download_catalog/upload_catalog— the catalog db lifecycle (open, create, persist).- :class:
EarthCatalog— re-exported from :mod:earthcatalog.facade, where the user-facing facade lives.
Classes¶
CatalogInfo
dataclass
¶
Grid metadata read from Iceberg table properties.
The query-side partitioner is built lazily from these properties (same factory the ingest side uses) and cached — one partitioner per catalog, so every search prunes with exactly the grid the data was written with.
Source code in earthcatalog/catalog.py
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 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 232 233 234 235 236 237 | |
Functions¶
partitioner()
¶
The cached read-side partitioner (spatial keys + temporal bin).
Source code in earthcatalog/catalog.py
cells_for_geometry(geom)
¶
cell_list_sql(geom)
¶
Return a SQL fragment suitable for WHERE grid_partition IN (...).
Source code in earthcatalog/catalog.py
file_paths(table, geom, start_datetime=None, end_datetime=None, year_lookback=2)
¶
Return Parquet file paths for partitions overlapping geom and the temporal range.
Overlap semantics: items carry a temporal extent
(start_datetime..end_datetime — velocity pairs span ~500
days and routinely cross year boundaries), so a partition is
relevant when the item's start is not after the query end and its
end is not before the query start. The partition-year window is
widened by year_lookback on the start side to reach midpoints that
fall before the query interval.
Source code in earthcatalog/catalog.py
stats(table)
¶
top_cells(table, limit=5)
¶
Top partitions by row count (cached alongside :meth:stats).
total_files(table)
¶
unique_item_count(table, store, default_index_path=None)
¶
Number of active (non-deleted) items in the unified index.
Source code in earthcatalog/catalog.py
Functions¶
open_sqlite(db_path, warehouse_path)
¶
Open a PyIceberg SqlCatalog over a local SQLite db for warehouse_path.
Part of the catalog lifecycle surface (used by the CLI, run.py, rebuild
and the GC entry script). Credentials come from
:func:earthcatalog.inventory.sql_catalog_props — this is the
writer configuration; the read-mostly catalog built by :func:open
configures anonymous/region properties itself.
Source code in earthcatalog/catalog.py
download_catalog(local_path, store=None, catalog_key=None)
¶
Pull catalog.db from store to local_path before a job starts.
Source code in earthcatalog/catalog.py
upload_catalog(local_path, store=None, catalog_key=None)
¶
Push the updated catalog.db to store after all writes.
Source code in earthcatalog/catalog.py
get_or_create(catalog, grid_config=None)
¶
Return the stac_items table, creating it (and the namespace) if needed.
Parameters¶
catalog:
Open SqlCatalog instance.
grid_config:
Optional :class:earthcatalog.config.GridConfig. When provided, grid
metadata (type, resolution, boundaries_path, id_field) is stored as
Iceberg table properties so that :class:CatalogInfo
can reconstruct the grid system without any external configuration.
Source code in earthcatalog/catalog.py
open(store, base, *, anonymous=None)
¶
Open an EarthCatalog backed by store at base.
Parameters¶
store:
An obstore-compatible store (S3Store, LocalStore, etc.).
All catalog I/O (download, upload) and warehouse file operations
flow through this store.
base:
Base path containing:
- earthcatalog.db (SQLite Iceberg catalog)
- warehouse/ (GeoParquet files)
Optionally:
- warehouse_index.parquet (unified index)
anonymous:
Force anonymous S3 access when the warehouse path is s3://.
Auto-detected for stores with skip_signature=True.
Returns¶
EarthCatalog Facade combining PyIceberg catalog, table, and grid metadata.
Source code in earthcatalog/catalog.py
earthcatalog.catalog.ICEBERG_SCHEMA = Schema(NestedField(1, 'id', StringType(), required=False), NestedField(2, 'grid_partition', StringType(), required=False), NestedField(3, 'geometry', BinaryType(), required=False), NestedField(4, 'datetime', TimestamptzType(), required=False), NestedField(5, 'platform', StringType(), required=False), NestedField(6, 'percent_valid_pixels', LongType(), required=False), NestedField(7, 'date_dt', LongType(), required=False), NestedField(8, 'proj:code', StringType(), required=False), NestedField(9, 'assets', StringType(), required=False), NestedField(10, 'links', StringType(), required=False), NestedField(11, 'stac_version', StringType(), required=False), NestedField(12, 'type', StringType(), required=False), NestedField(13, 'start_datetime', TimestamptzType(), required=False), NestedField(14, 'version', StringType(), required=False), NestedField(15, 'sat:orbit_state', StringType(), required=False), NestedField(16, 'scene_1_id', StringType(), required=False), NestedField(17, 'scene_2_id', StringType(), required=False), NestedField(18, 'scene_1_frame', StringType(), required=False), NestedField(19, 'scene_2_frame', StringType(), required=False), NestedField(20, 'mid_datetime', StringType(), required=False), NestedField(21, 'created', TimestamptzType(), required=False), NestedField(22, 'updated', TimestamptzType(), required=False), NestedField(23, 'end_datetime', TimestamptzType(), required=False), NestedField(24, 'stac_extensions', StringType(), required=False), NestedField(25, 'collection', StringType(), required=False), NestedField(26, 'latitude', DoubleType(), required=False), NestedField(27, 'longitude', DoubleType(), required=False), NestedField(28, 'bbox', StringType(), required=False))
module-attribute
¶
earthcatalog.catalog.PARTITION_SPEC = build_partition_spec('year')
module-attribute
¶
Search extras¶
DuckDB-backed searches are module-level functions (the facade only keeps
search, search_to_arrow and search_files):
earthcatalog.search.duck_search(catalog, **kwargs)
¶
Search using DuckDB, returning results as a pandas.DataFrame.
Accepts the same kwargs as :meth:EarthCatalog.search (intersects,
bbox, datetime, filter, max_items, etc.). DuckDB reads
Parquet files in parallel internally, making this ~2x faster than
:meth:EarthCatalog.search across all query types. Returns a DataFrame
with flat columns — no pystac conversion overhead.
Examples::
from earthcatalog.search import duck_search
df = duck_search(
catalog,
intersects={"type": "Point", "coordinates": [-45, 70]},
datetime="1980-01-01/2015-12-31",
max_items=100,
)
Source code in earthcatalog/search.py
earthcatalog.search.search_uris(catalog, **kwargs)
¶
Return asset URIs as a DataFrame with (id, uri) columns.
Accepts the same kwargs as :meth:EarthCatalog.search. Uses Iceberg
pruning + DuckDB, reading only the id and assets columns —
the fastest way to get download URLs for thousands of items.
Examples::
from earthcatalog.search import search_uris
df = search_uris(
catalog,
intersects={"type": "Point", "coordinates": [-45, 70]},
datetime="2020-01-01/2020-12-31",
max_items=100,
)
for _, row in df.iterrows():
print(row.id, row.uri)
Source code in earthcatalog/search.py
earthcatalog.transform
¶
STAC item transformation: H3 fan-out + stac-geoparquet writing via rustac.
Public functions¶
fan_out(items, partitioner)
Produce one synthetic STAC item per (source_item × grid_cell) pair.
Injects grid_partition into each item's properties.
group_by_partition(fan_out_items)
Group the output of fan_out() by (grid_partition, year) so that
each group can be written to exactly one Parquet file. This is required
for Iceberg IdentityTransform + YearTransform partition pruning.
write_geoparquet(fan_out_items, path)
Write a single-partition list of synthetic items to a GeoParquet file
using rustac.write(). rustac writes proper stac-geoparquet with:
- assets as struct column
- links as list column
- properties promoted to top-level columns
- geoarrow.wkb extension on geometry column
Spatial predicate pushdown¶
The correct usage pattern for spatial queries:
- Convert the query geometry to grid cell IDs (e.g. H3 cells at resolution 1): candidate_cells = h3.geo_to_cells(mapping(query_geom), resolution=1)
- Filter the Iceberg table via:
WHERE grid_partition IN (
) Iceberg's IdentityTransform partition pruning will skip all files whose grid_partitionvalue is not in the candidate set.
Classes¶
FileMetadata
dataclass
¶
Lightweight record describing one GeoParquet file written to a store.
Designed to be trivially serialisable by Dask (no PyArrow, no Iceberg imports) so it crosses the network from worker to head node at ~200 B/file.
Attributes¶
s3_key:
Key relative to the warehouse store root — e.g.
"grid_partition=81003ffffffffff/year=2025/part_000000_abc1.parquet".
The caller that knows the store root appends this to construct the full
URI used in table.add_files().
grid_partition:
H3 cell string (or "__none__" for unlocated items).
year:
4-digit calendar year from the datetime property, or None for
items without a parseable datetime.
row_count:
Number of rows in the file.
file_size_bytes:
Byte size of the written Parquet file.
Source code in earthcatalog/transform.py
Functions¶
fan_out(stac_items, partitioner)
¶
Produce one synthetic STAC item per (source_item × grid_cell) pair.
Each synthetic item is the original STAC item with grid_partition
injected into its properties. All original fields (assets, links,
collection, …) are preserved as-is so that rustac.write() can emit a
complete stac-geoparquet file with the native rustac schema.
Items with unparseable or empty geometry are silently skipped.
Source code in earthcatalog/transform.py
group_by_partition(fan_out_items, partitioner)
¶
Group fan-out items by (grid_partition, temporal bin) and sort
each group by (platform, datetime).
The partitioner supplies the temporal bin for each item
(partitioner.bin_value(props["datetime"])) — it owns temporal
binning, so the grouping follows whatever time_bin the partitioner
was configured with.
Each resulting group satisfies both Iceberg partition constraints:
IdentityTransformongrid_partition— every item in the group has the samegrid_partitionvalue, so Parquet column statistics give a single min == max thatadd_files()can use unambiguously.- the temporal transform on
datetime(year/month/day per the partitioner's time_bin) — every item in the group has the same bin value, so the partition-level Parquet statistics are also unambiguous.
The within-group sort by (platform, datetime) maximises Parquet
row-group min/max statistics for predicate pushdown on those columns.
Parameters¶
fan_out_items:
Output of :func:fan_out — each item has exactly one
grid_partition value in its properties.
partitioner:
The partitioner whose get_intersecting_keys produced the fan-out;
its time_bin must match the table's partition spec.
Returns¶
dict mapping (cell_id, bin_value) → sorted list of synthetic STAC
items. bin_value is the formatted hive value ("2025",
"2025-12", "2025-12-20") or "unknown" for items that carry
no datetime property.
Source code in earthcatalog/transform.py
write_geoparquet(fan_out_items, path)
¶
Write fan-out STAC items to a GeoParquet file using rustac.
Caller's responsibility¶
Pass items for a single (grid_partition, year) group — i.e. the output
of one iteration over :func:group_by_partition. If items span multiple
partitions the resulting file will violate the Iceberg IdentityTransform
constraint and table.add_files() will raise a ValueError.
rustac writes the full stac-geoparquet schema. A post-processing step
casts struct/list columns (assets, links) to JSON strings and drops null-
typed columns (collection) so the file is compatible with PyIceberg V2
add_files().
Returns the number of rows written (0 if the input list is empty).
Source code in earthcatalog/transform.py
write_geoparquet_s3(fan_out_items, store, s3_key)
¶
Write a single-partition list of fan-out items as GeoParquet to a store.
Writes to a local temporary file (via :func:write_geoparquet) then
uploads the bytes via obstore.put. The temporary file is always
deleted, even on error.
This is the S3-capable counterpart to :func:write_geoparquet. Workers
on a Dask cluster call this function directly; the store is injected so
the function is testable with any obstore-compatible backend
(MemoryStore, LocalStore, S3Store).
Parameters¶
fan_out_items:
Output of one group_by_partition() iteration — all items must
belong to the same (grid_partition, year) group.
store:
An obstore-compatible store (S3Store, LocalStore, or
MemoryStore).
s3_key:
Key within the store, e.g.
"grid_partition=81003ffffffffff/year=2025/part_000000_abc1.parquet".
Returns¶
(row_count, byte_count) — both zero if fan_out_items is empty (no
file is uploaded in that case).
Source code in earthcatalog/transform.py
earthcatalog.lock
¶
S3 atomic lockfile using conditional writes (If-None-Match: *).
Prevents concurrent writes to the SQLite catalog.db.
Uses the store configured in earthcatalog.store_config (defaults to LocalStore for zero-config local development and testing). Override the store before running a job:
from earthcatalog import store_config
from obstore.store import S3Store
store_config.set_store(S3Store(bucket="my-bucket", region="us-west-2"))
store_config.set_lock_key("catalog/.lock")
Usage
from earthcatalog.lock import S3Lock
with S3Lock(owner="incremental"): download_catalog(...) ... do work ... upload_catalog(...)
Classes¶
CatalogLocked
¶
S3Lock
¶
Atomic lockfile using obstore conditional writes (If-None-Match: *).
When store and key are provided explicitly they are used directly;
otherwise falls back to the global :mod:earthcatalog.store_config
(deprecated path).
Stale locks (older than ttl_hours) are automatically overridden.
Source code in earthcatalog/lock.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | |
Functions¶
__init__(owner, ttl_hours=12, store=None, key=None)
¶
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
owner
|
str
|
Human-readable name for the lock holder (e.g. "backfill"). |
required |
ttl_hours
|
int
|
Age after which a lock is considered stale and overridable. |
12
|
store
|
ObjectStore | None
|
Optional explicit obstore store (avoids store_config globals). |
None
|
key
|
str | None
|
Optional explicit lock key (avoids store_config globals). |
None
|
Source code in earthcatalog/lock.py
acquire()
¶
Atomically acquire the lock via mode='create' (If-None-Match: *).
Succeeds only if the key does not exist. On conflict, reads the existing lock; if stale, deletes and retries. Raises CatalogLocked if a fresh lock is held by another process.
Source code in earthcatalog/lock.py
earthcatalog.store_config
¶
Global store configuration for earthcatalog.
Defaults to a LocalStore rooted at /tmp/earthcatalog_store for zero-config local development and testing. Override before running any job:
from earthcatalog import store_config
from obstore.store import S3Store
store_config.set_store(S3Store(bucket="my-bucket", region="us-west-2"))
store_config.set_catalog_key("catalog/catalog.db")
store_config.set_lock_key("catalog/.lock")
earthcatalog.partitioner
¶
Spatial + temporal partitioning.
A partitioner owns BOTH halves of the hive partition key:
- the spatial cell keys from a WKB geometry (:meth:
AbstractPartitioner.get_intersecting_keys) - the temporal bin value from an item datetime (:meth:
AbstractPartitioner.bin_value)
Together they form the warehouse path segment
grid=<type>/level=<res>/tile=<cell>/<time_bin>=<value>/. The
boundary-inclusive contract means that a geometry touching a cell boundary
is assigned to that cell, preventing coverage gaps along shared edges.
Built-in implementations¶
- :class:
~earthcatalog.grids.h3_partitioner.H3Partitioner— Uber H3 hexagonal grid - :class:
~earthcatalog.grids.s2_partitioner.S2Partitioner— Google S2 cells - :class:
~earthcatalog.grids.utm_partitioner.UTMPartitioner— UTM zones - :class:
~earthcatalog.grids.geojson_partitioner.GeoJSONPartitioner— arbitrary polygon regions
Custom partitioners¶
Subclass :class:AbstractPartitioner, implement
:meth:get_intersecting_keys, accept time_bin in __init__ and
forward it to super().__init__, then register the builder with
:func:~earthcatalog.grids.register_grid (or add it to the built-in
registry in earthcatalog.grids).
Classes¶
AbstractPartitioner
¶
Bases: ABC
Maps an item to its partition keys — spatial cells AND temporal bin.
Given a WKB geometry, :meth:get_intersecting_keys returns the set of
grid cell keys whose boundaries intersect that geometry (a single item
may map to multiple keys — the Overlap Multiplier). Given an item
datetime, :meth:bin_value returns the formatted temporal bin for this
partitioner's configured time_bin.
Source code in earthcatalog/partitioner.py
Functions¶
bin_value(value, time_bin='year')
¶
Format a temporal value for the hive path: 2025 / 2025-12 /
2025-12-20.
Accepts the ISO strings STAC items carry or a datetime. Missing or
unparseable values map to "unknown" — files without a datetime live
in the unknown partition and index rows must agree.
Source code in earthcatalog/partitioner.py
earthcatalog.grids
¶
Partitioner factory and grid registry.
Usage
from earthcatalog.config import GridConfig from earthcatalog.grids import build_partitioner
cfg = GridConfig(type="h3", resolution=3, time_bin="month") partitioner = build_partitioner(cfg)
The factory passes cfg.time_bin into every partitioner — the built
object owns both the spatial keys and the temporal bin. New grids are
added by registering a builder (no factory edits needed):
from earthcatalog.grids import register_grid
register_grid("my_grid", lambda cfg, **kw: MyPartitioner(resolution=cfg.resolution, **kw))
Classes¶
Functions¶
register_grid(grid_type, builder)
¶
Register (or replace) the builder for grid_type.
builder is called as builder(cfg, time_bin=cfg.time_bin) and
returns an :class:~earthcatalog.partitioner.AbstractPartitioner.
Source code in earthcatalog/grids/__init__.py
build_partitioner(cfg)
¶
Instantiate the partitioner for a GridConfig (grid + temporal bin).