rastafari 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rastafari-0.2.3/.pre-commit-config.yaml +28 -0
- rastafari-0.2.3/CHANGES.md +12 -0
- rastafari-0.2.3/LICENSE +19 -0
- rastafari-0.2.3/MANIFEST.in +5 -0
- rastafari-0.2.3/PKG-INFO +85 -0
- rastafari-0.2.3/README.md +68 -0
- rastafari-0.2.3/pyproject.toml +20 -0
- rastafari-0.2.3/setup.cfg +57 -0
- rastafari-0.2.3/setup.py +17 -0
- rastafari-0.2.3/src/rastafari/__init__.py +137 -0
- rastafari-0.2.3/src/rastafari/core.c +32209 -0
- rastafari-0.2.3/src/rastafari/core.pyi +24 -0
- rastafari-0.2.3/src/rastafari/core.pyx +377 -0
- rastafari-0.2.3/src/rastafari/py.typed +0 -0
- rastafari-0.2.3/src/rastafari.egg-info/PKG-INFO +85 -0
- rastafari-0.2.3/src/rastafari.egg-info/SOURCES.txt +22 -0
- rastafari-0.2.3/src/rastafari.egg-info/dependency_links.txt +1 -0
- rastafari-0.2.3/src/rastafari.egg-info/not-zip-safe +1 -0
- rastafari-0.2.3/src/rastafari.egg-info/requires.txt +7 -0
- rastafari-0.2.3/src/rastafari.egg-info/top_level.txt +1 -0
- rastafari-0.2.3/test-requirements.txt +36 -0
- rastafari-0.2.3/tests/test_core.py +278 -0
- rastafari-0.2.3/tests/test_rastafari.py +71 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/ambv/black
|
|
3
|
+
rev: "23.7.0"
|
|
4
|
+
hooks:
|
|
5
|
+
- id: black
|
|
6
|
+
- repo: https://github.com/pycqa/isort
|
|
7
|
+
rev: "5.12.0"
|
|
8
|
+
hooks:
|
|
9
|
+
- id: isort
|
|
10
|
+
- repo: https://github.com/pycqa/flake8
|
|
11
|
+
rev: "6.1.0"
|
|
12
|
+
hooks:
|
|
13
|
+
- id: flake8
|
|
14
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
15
|
+
rev: "v4.4.0"
|
|
16
|
+
hooks:
|
|
17
|
+
- id: check-added-large-files
|
|
18
|
+
args: ["--enforce-all"]
|
|
19
|
+
- id: check-merge-conflict
|
|
20
|
+
- id: check-symlinks
|
|
21
|
+
- id: check-toml
|
|
22
|
+
- id: debug-statements
|
|
23
|
+
- id: end-of-file-fixer
|
|
24
|
+
- id: fix-encoding-pragma
|
|
25
|
+
args: [--remove]
|
|
26
|
+
- id: mixed-line-ending
|
|
27
|
+
args: [--fix, lf]
|
|
28
|
+
- id: trailing-whitespace
|
rastafari-0.2.3/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2023 David Segersson
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
19
|
+
SOFTWARE.
|
rastafari-0.2.3/PKG-INFO
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: rastafari
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: Rasterize vector features to grids
|
|
5
|
+
Home-page: https://gitlab.com/foclair/rastafari
|
|
6
|
+
Author: David Segersson, Eef van Dongen
|
|
7
|
+
Author-email: david.segersson@smhi.se
|
|
8
|
+
License: "see LICENSE file"
|
|
9
|
+
Project-URL: Bug Tracker, https://gitlab.com/foclair/rastafari/-/issues
|
|
10
|
+
Keywords: rasterize,DDA,resample
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Requires-Python: >=3.9
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
|
|
18
|
+
# Rastafari
|
|
19
|
+
|
|
20
|
+
Rasterize vector features. This library is built to rasterize emission sources in the CLAIR air quality modelling system. In contrast to most available libraries used to rasterize vector features, this library produces rasters with weights proportional to the fraction of each cell that is covered by a feature.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Features:
|
|
24
|
+
|
|
25
|
+
* line rasterization using DDA algorithm, producing weights proportional to fraction of line intersected by each cell
|
|
26
|
+
* polygon rasterization using even-odd rule, producing weights proportional to fraction of polygon included in each cell
|
|
27
|
+
* mass-consistent resampling of a raster using inverse nearest neighbour algorithm, allowing for different projections in source and target
|
|
28
|
+
|
|
29
|
+
See rastafari/tests for examples.
|
|
30
|
+
|
|
31
|
+
## Install
|
|
32
|
+
|
|
33
|
+
Use pip to install Rastafari:
|
|
34
|
+
|
|
35
|
+
```console
|
|
36
|
+
python -m pip install rastafari
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## Development
|
|
41
|
+
|
|
42
|
+
To install Rastafari in a local venv for development, run:
|
|
43
|
+
```console
|
|
44
|
+
git clone https://gitlab.com/foclair/rastafari.git
|
|
45
|
+
cd rastafari
|
|
46
|
+
python -m venv .venv
|
|
47
|
+
. .venv/bin/activate
|
|
48
|
+
python -m pip install -U pip
|
|
49
|
+
python -m pip install cython wheel
|
|
50
|
+
RASTAFARI_USE_CYTHON=1 python -m pip install --no-build-isolation -e .[test]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Rastafari uses [pre-commit][]. Install it and run `pre-commit
|
|
54
|
+
install` to run its checks every time you commit. Run the checks
|
|
55
|
+
manually with
|
|
56
|
+
|
|
57
|
+
```console
|
|
58
|
+
pre-commit run -a
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
[pytest][] is used as a test runner:
|
|
62
|
+
|
|
63
|
+
```console
|
|
64
|
+
pytest
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Rastafari comes fully typed. Use [mypy][] to check the type annotations:
|
|
68
|
+
|
|
69
|
+
```console
|
|
70
|
+
mypy .
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
All these tools will be run in CI in case you forget.
|
|
74
|
+
|
|
75
|
+
[mypy]: https://www.mypy-lang.org/
|
|
76
|
+
[pre-commit]: https://pre-commit.com/
|
|
77
|
+
[pytest]: https://pytest.org/
|
|
78
|
+
[pip-tools]: https://github.com/jazzband/pip-tools/
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
## Maintenance
|
|
82
|
+
|
|
83
|
+
This package is maintained by [David Segersson][] at SMHI.
|
|
84
|
+
|
|
85
|
+
[David Segersson]: mailto:david.segersson@smhi.se
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Rastafari
|
|
2
|
+
|
|
3
|
+
Rasterize vector features. This library is built to rasterize emission sources in the CLAIR air quality modelling system. In contrast to most available libraries used to rasterize vector features, this library produces rasters with weights proportional to the fraction of each cell that is covered by a feature.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features:
|
|
7
|
+
|
|
8
|
+
* line rasterization using DDA algorithm, producing weights proportional to fraction of line intersected by each cell
|
|
9
|
+
* polygon rasterization using even-odd rule, producing weights proportional to fraction of polygon included in each cell
|
|
10
|
+
* mass-consistent resampling of a raster using inverse nearest neighbour algorithm, allowing for different projections in source and target
|
|
11
|
+
|
|
12
|
+
See rastafari/tests for examples.
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
Use pip to install Rastafari:
|
|
17
|
+
|
|
18
|
+
```console
|
|
19
|
+
python -m pip install rastafari
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Development
|
|
24
|
+
|
|
25
|
+
To install Rastafari in a local venv for development, run:
|
|
26
|
+
```console
|
|
27
|
+
git clone https://gitlab.com/foclair/rastafari.git
|
|
28
|
+
cd rastafari
|
|
29
|
+
python -m venv .venv
|
|
30
|
+
. .venv/bin/activate
|
|
31
|
+
python -m pip install -U pip
|
|
32
|
+
python -m pip install cython wheel
|
|
33
|
+
RASTAFARI_USE_CYTHON=1 python -m pip install --no-build-isolation -e .[test]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Rastafari uses [pre-commit][]. Install it and run `pre-commit
|
|
37
|
+
install` to run its checks every time you commit. Run the checks
|
|
38
|
+
manually with
|
|
39
|
+
|
|
40
|
+
```console
|
|
41
|
+
pre-commit run -a
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
[pytest][] is used as a test runner:
|
|
45
|
+
|
|
46
|
+
```console
|
|
47
|
+
pytest
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Rastafari comes fully typed. Use [mypy][] to check the type annotations:
|
|
51
|
+
|
|
52
|
+
```console
|
|
53
|
+
mypy .
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
All these tools will be run in CI in case you forget.
|
|
57
|
+
|
|
58
|
+
[mypy]: https://www.mypy-lang.org/
|
|
59
|
+
[pre-commit]: https://pre-commit.com/
|
|
60
|
+
[pytest]: https://pytest.org/
|
|
61
|
+
[pip-tools]: https://github.com/jazzband/pip-tools/
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
## Maintenance
|
|
65
|
+
|
|
66
|
+
This package is maintained by [David Segersson][] at SMHI.
|
|
67
|
+
|
|
68
|
+
[David Segersson]: mailto:david.segersson@smhi.se
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "Cython", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.check-manifest]
|
|
6
|
+
ignore = [
|
|
7
|
+
".gitlab-ci.yml",
|
|
8
|
+
"src/rastafari/*.c",
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
[tool.coverage.run]
|
|
12
|
+
source = ["rastafari"]
|
|
13
|
+
branch = true
|
|
14
|
+
|
|
15
|
+
[tool.mypy]
|
|
16
|
+
strict = true
|
|
17
|
+
exclude = ['^setup\.py$']
|
|
18
|
+
|
|
19
|
+
[tool.pytest.ini_options]
|
|
20
|
+
filterwarnings = ["error"]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = rastafari
|
|
3
|
+
version = attr: rastafari.__version__
|
|
4
|
+
author = David Segersson, Eef van Dongen
|
|
5
|
+
author_email = david.segersson@smhi.se
|
|
6
|
+
description = Rasterize vector features to grids
|
|
7
|
+
long_description = file: README.md
|
|
8
|
+
long_description_content_type = text/markdown
|
|
9
|
+
keywords = rasterize, DDA, resample
|
|
10
|
+
classifiers =
|
|
11
|
+
License :: OSI Approved :: MIT License
|
|
12
|
+
Programming Language :: Python :: 3
|
|
13
|
+
license = "see LICENSE file"
|
|
14
|
+
url = https://gitlab.com/foclair/rastafari
|
|
15
|
+
project_urls =
|
|
16
|
+
Bug Tracker = https://gitlab.com/foclair/rastafari/-/issues
|
|
17
|
+
|
|
18
|
+
[options]
|
|
19
|
+
package_dir =
|
|
20
|
+
= src
|
|
21
|
+
packages = find:
|
|
22
|
+
python_requires = >=3.9
|
|
23
|
+
zip_safe = False
|
|
24
|
+
install_requires =
|
|
25
|
+
numpy
|
|
26
|
+
pyproj
|
|
27
|
+
|
|
28
|
+
[options.extras_require]
|
|
29
|
+
test =
|
|
30
|
+
mypy
|
|
31
|
+
pytest
|
|
32
|
+
pytest-cov
|
|
33
|
+
|
|
34
|
+
[options.packages.find]
|
|
35
|
+
where = src
|
|
36
|
+
|
|
37
|
+
[options.package_data]
|
|
38
|
+
rastafari =
|
|
39
|
+
core.pyi
|
|
40
|
+
py.typed
|
|
41
|
+
|
|
42
|
+
[flake8]
|
|
43
|
+
exclude =
|
|
44
|
+
.direnv,
|
|
45
|
+
.venv
|
|
46
|
+
extend-ignore = E203
|
|
47
|
+
max-line-length = 88
|
|
48
|
+
|
|
49
|
+
[black]
|
|
50
|
+
exclude =
|
|
51
|
+
.direnv,
|
|
52
|
+
.venv
|
|
53
|
+
|
|
54
|
+
[egg_info]
|
|
55
|
+
tag_build =
|
|
56
|
+
tag_date = 0
|
|
57
|
+
|
rastafari-0.2.3/setup.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Build and install Rastafari."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from setuptools import Extension, setup
|
|
6
|
+
USE_CYTHON = os.environ.get("RASTAFARI_USE_CYTHON", False)
|
|
7
|
+
print(f"USE_CYTHON: {USE_CYTHON}")
|
|
8
|
+
ext = "pyx" if USE_CYTHON else "c"
|
|
9
|
+
extensions = [
|
|
10
|
+
Extension("rastafari.core", [f"src/rastafari/core.{ext}"]),
|
|
11
|
+
]
|
|
12
|
+
if USE_CYTHON:
|
|
13
|
+
from Cython.Build import cythonize
|
|
14
|
+
|
|
15
|
+
extensions = cythonize(extensions, compiler_directives={"language_level": "3"})
|
|
16
|
+
|
|
17
|
+
setup(ext_modules=extensions)
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""Rasterize vector features to grids."""
|
|
2
|
+
|
|
3
|
+
import math
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import numpy.typing as npt
|
|
7
|
+
import pyproj
|
|
8
|
+
|
|
9
|
+
from .core import ddaf_line_subpixel, even_odd_polygon_fill
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"ddaf_line_subpixel",
|
|
13
|
+
"even_odd_polygon_fill",
|
|
14
|
+
"resample_band",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
__version__ = "0.2.3"
|
|
18
|
+
|
|
19
|
+
ExtentType = tuple[float, float, float, float]
|
|
20
|
+
WeightsDict = dict[tuple[int, int], float]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def resample_band(
|
|
24
|
+
source_grid: npt.NDArray[np.float_],
|
|
25
|
+
source_extent: ExtentType,
|
|
26
|
+
source_nodata: float,
|
|
27
|
+
target_extent: ExtentType,
|
|
28
|
+
target_nx: int,
|
|
29
|
+
target_ny: int,
|
|
30
|
+
source_srid: int,
|
|
31
|
+
target_srid: int,
|
|
32
|
+
subgridcells: int = 2,
|
|
33
|
+
) -> tuple[tuple[npt.NDArray[np.intp], ...], npt.NDArray[np.float_]]:
|
|
34
|
+
"""Resample raster using inverse nearest neighbour algorithm.
|
|
35
|
+
|
|
36
|
+
The original raster is refined and each pixel is sorted into the
|
|
37
|
+
target grid.
|
|
38
|
+
|
|
39
|
+
args:
|
|
40
|
+
source_grid: original raster as a numpy array ((X, Y))
|
|
41
|
+
source_extent: extent of the original raster
|
|
42
|
+
source_nodata: nodata value of source raster
|
|
43
|
+
target_extent: target extent coordinates as (x1, y1, x2, y2)
|
|
44
|
+
target_nx: number of cells in x-direction of target grid
|
|
45
|
+
target_ny: number of cells in y-direction of target grid
|
|
46
|
+
source_srid: srid of source raster as integer
|
|
47
|
+
target_srid: srid of target raster as integer
|
|
48
|
+
kwargs:
|
|
49
|
+
subgridcells: divide each cell side by this factor to
|
|
50
|
+
increase accuracy in resampling
|
|
51
|
+
"""
|
|
52
|
+
# target extent
|
|
53
|
+
tx0, ty0, tx1, ty1 = target_extent
|
|
54
|
+
|
|
55
|
+
# source extent
|
|
56
|
+
sx0, sy0, sx1, sy1 = source_extent
|
|
57
|
+
|
|
58
|
+
sny = source_grid.shape[0]
|
|
59
|
+
snx = source_grid.shape[1]
|
|
60
|
+
|
|
61
|
+
# calculate grid cell-size
|
|
62
|
+
target_dy = (ty1 - ty0) / target_ny
|
|
63
|
+
target_dx = (tx1 - tx0) / target_nx
|
|
64
|
+
|
|
65
|
+
source_dy = (sy1 - sy0) / sny
|
|
66
|
+
source_dx = (sx1 - sx0) / snx
|
|
67
|
+
|
|
68
|
+
# refinement factor < 0 means sorting into a coarser target grid
|
|
69
|
+
refinement_factor = max(
|
|
70
|
+
source_dx * subgridcells / target_dx, source_dy * subgridcells / target_dy
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
target_grid = np.zeros((target_ny, target_nx), dtype=float)
|
|
74
|
+
|
|
75
|
+
# set nodata values to zero (if added by ST_Clip in emission query)
|
|
76
|
+
source_grid[source_grid == source_nodata] = 0
|
|
77
|
+
# upsample the source grid for improved accuracy
|
|
78
|
+
if refinement_factor > 1 and subgridcells > 1:
|
|
79
|
+
refinement_factor = math.ceil(refinement_factor)
|
|
80
|
+
# values are divided to maintain raster sum after upsampling
|
|
81
|
+
source_grid = (
|
|
82
|
+
(source_grid / (refinement_factor * refinement_factor))
|
|
83
|
+
.repeat(refinement_factor, axis=0)
|
|
84
|
+
.repeat(refinement_factor, axis=1)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# adjust cell size to upsampled grid
|
|
88
|
+
source_dx /= refinement_factor
|
|
89
|
+
source_dy /= refinement_factor
|
|
90
|
+
|
|
91
|
+
# get row and col indices of nonzero cells
|
|
92
|
+
source_rows, source_cols = np.nonzero(source_grid)
|
|
93
|
+
|
|
94
|
+
# get cell centre coordinates of non-zero cells
|
|
95
|
+
ccx = sx0 + (source_cols + 0.5) * source_dx
|
|
96
|
+
ccy = sy1 - (source_rows + 0.5) * source_dy
|
|
97
|
+
cell_centers = np.vstack((ccx, ccy)).T
|
|
98
|
+
if cell_centers.size == 0:
|
|
99
|
+
# all cells are zero in source grid
|
|
100
|
+
return ((), np.array([]))
|
|
101
|
+
|
|
102
|
+
# if target srid is different from source srid,
|
|
103
|
+
# transform cell centers to target srid
|
|
104
|
+
if source_srid != target_srid:
|
|
105
|
+
transformer = pyproj.Transformer.from_crs(
|
|
106
|
+
source_srid, target_srid, always_xy=True
|
|
107
|
+
)
|
|
108
|
+
transformer.transform(cell_centers[:, 0], cell_centers[:, 1], inplace=True)
|
|
109
|
+
|
|
110
|
+
# get indices within output bounds
|
|
111
|
+
target_cols = ((cell_centers[:, 0] - tx0) / target_dx).astype(int)
|
|
112
|
+
target_rows = target_ny - (np.ceil((cell_centers[:, 1] - ty0) / target_dy)).astype(
|
|
113
|
+
int
|
|
114
|
+
)
|
|
115
|
+
# handle edge case (row or col = ny or ny)
|
|
116
|
+
target_cols = np.clip(target_cols, 0, target_nx - 1, target_cols)
|
|
117
|
+
target_rows = np.clip(target_rows, 0, target_ny - 1, target_rows)
|
|
118
|
+
|
|
119
|
+
# create mask array for cells within target extent
|
|
120
|
+
cells_within_target_extent = (
|
|
121
|
+
(cell_centers[:, 0] >= tx0)
|
|
122
|
+
& (cell_centers[:, 0] < tx1)
|
|
123
|
+
& (cell_centers[:, 1] >= ty0)
|
|
124
|
+
& (cell_centers[:, 1] < ty1)
|
|
125
|
+
)
|
|
126
|
+
np.add.at(
|
|
127
|
+
target_grid,
|
|
128
|
+
(
|
|
129
|
+
target_rows[cells_within_target_extent],
|
|
130
|
+
target_cols[cells_within_target_extent],
|
|
131
|
+
),
|
|
132
|
+
source_grid[
|
|
133
|
+
source_rows[cells_within_target_extent],
|
|
134
|
+
source_cols[cells_within_target_extent],
|
|
135
|
+
],
|
|
136
|
+
)
|
|
137
|
+
return (target_grid.nonzero(), target_grid[target_grid > 0].ravel())
|