Skip to content

Commit 607f866

Browse files
Merge pull request #243 from calvintr/fix-shape_avialability-efficiency
Improve memory load efficiency for shape_availability calculation
2 parents d369ee8 + a3d547f commit 607f866

File tree

2 files changed

+24
-16
lines changed

2 files changed

+24
-16
lines changed

RELEASE_NOTES.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Release Notes
2121
* Bugfix: Downsampling the availability matrix (high resolution to low resolution) failed. Only rasters with 0 or 1
2222
were produced. Expected are also floats between 0 and 1 (GH Issue #238). Changing the rasterio version solved this.
2323
See solution (https://github.com/PyPSA/atlite/pull/240).
24+
* Breaking Change: Due to better performance and memory efficiency the method of matrix summation, as well as the matrix dtpyes within `shape_availability()` in `atlite.gis`, have been changed.
25+
The returned object `masked` (numpy.array) is now dtype `bool` instead of `float64`. This can create broken workflows, if `masked` is not transformed ahead of certain operations (https://github.com/PyPSA/atlite/pull/243).
2426
* Bugfix: Avoid NaN values into the hydro inflows
2527

2628
Version 0.2.7

atlite/gis.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
from collections import OrderedDict
2222
from pathlib import Path
23-
from warnings import warn
23+
from warnings import warn, catch_warnings, simplefilter
2424
from pyproj import CRS, Transformer
2525
from shapely.ops import transform
2626
from rasterio.warp import reproject, transform_bounds
@@ -426,15 +426,14 @@ def shape_availability(geometry, excluder):
426426
Affine transform of the mask.
427427
428428
"""
429-
exclusions = []
430429
if not excluder.all_open:
431430
excluder.open_files()
432431
assert geometry.crs == excluder.crs
433432

434433
bounds = rio.features.bounds(geometry)
435434
transform, shape = padded_transform_and_shape(bounds, res=excluder.res)
436-
masked = geometry_mask(geometry, shape, transform).astype(int)
437-
exclusions.append(masked)
435+
masked = geometry_mask(geometry, shape, transform)
436+
exclusions = masked
438437

439438
# For the following: 0 is eligible, 1 in excluded
440439
raster = None
@@ -449,25 +448,28 @@ def shape_availability(geometry, excluder):
449448
)
450449
if d["codes"]:
451450
if callable(d["codes"]):
452-
masked_ = d["codes"](masked)
451+
masked_ = d["codes"](masked).astype(bool)
453452
else:
454453
masked_ = isin(masked, d["codes"])
455454
else:
456-
masked_ = masked
455+
masked_ = masked.astype(bool)
457456

458457
if d["invert"]:
459-
masked_ = ~(masked_).astype(bool)
458+
masked_ = ~masked_
460459
if d["buffer"]:
461460
iterations = int(d["buffer"] / excluder.res) + 1
462-
masked_ = dilation(masked_, iterations=iterations).astype(int)
461+
masked_ = dilation(masked_, iterations=iterations)
463462

464-
exclusions.append(masked_.astype(int))
463+
exclusions = exclusions | masked_
465464

466465
for d in excluder.geometries:
467466
masked = ~geometry_mask(d["geometry"], shape, transform, invert=d["invert"])
468-
exclusions.append(masked.astype(int))
467+
exclusions = exclusions | masked
469468

470-
return (sum(exclusions) == 0).astype(float), transform
469+
warn(
470+
"Output dtype of shape_availability changed from float to boolean.", UserWarning
471+
)
472+
return ~exclusions, transform
471473

472474

473475
def shape_availability_reprojected(
@@ -509,7 +511,7 @@ def shape_availability_reprojected(
509511
masked, transform, dst_transform, excluder.crs, dst_crs
510512
)
511513
return rio.warp.reproject(
512-
masked,
514+
masked.astype(np.uint8),
513515
empty(dst_shape),
514516
resampling=rio.warp.Resampling.average,
515517
src_transform=transform,
@@ -527,7 +529,9 @@ def _init_process(shapes_, excluder_, dst_transform_, dst_crs_, dst_shapes_):
527529

528530
def _process_func(i):
529531
args = (excluder, dst_transform, dst_crs, dst_shapes)
530-
return shape_availability_reprojected(shapes.loc[[i]], *args)[0]
532+
with catch_warnings():
533+
simplefilter("ignore")
534+
return shape_availability_reprojected(shapes.loc[[i]], *args)[0]
531535

532536

533537
def compute_availabilitymatrix(
@@ -586,9 +590,11 @@ def compute_availabilitymatrix(
586590
desc="Compute availability matrix",
587591
)
588592
if nprocesses is None:
589-
for i in tqdm(shapes.index, **tqdm_kwargs):
590-
_ = shape_availability_reprojected(shapes.loc[[i]], *args)[0]
591-
availability.append(_)
593+
with catch_warnings():
594+
simplefilter("ignore")
595+
for i in tqdm(shapes.index, **tqdm_kwargs):
596+
_ = shape_availability_reprojected(shapes.loc[[i]], *args)[0]
597+
availability.append(_)
592598
else:
593599
assert (
594600
excluder.all_closed

0 commit comments

Comments
 (0)