pyopenrivercam 0.8.10__py3-none-any.whl → 0.8.11__py3-none-any.whl
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.
- {pyopenrivercam-0.8.10.dist-info → pyopenrivercam-0.8.11.dist-info}/METADATA +1 -1
- {pyopenrivercam-0.8.10.dist-info → pyopenrivercam-0.8.11.dist-info}/RECORD +9 -9
- pyorc/__init__.py +1 -1
- pyorc/api/cross_section.py +28 -5
- pyorc/api/plot.py +4 -2
- pyorc/api/transect.py +65 -73
- {pyopenrivercam-0.8.10.dist-info → pyopenrivercam-0.8.11.dist-info}/WHEEL +0 -0
- {pyopenrivercam-0.8.10.dist-info → pyopenrivercam-0.8.11.dist-info}/entry_points.txt +0 -0
- {pyopenrivercam-0.8.10.dist-info → pyopenrivercam-0.8.11.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
pyorc/__init__.py,sha256=
|
|
1
|
+
pyorc/__init__.py,sha256=5wLWixrMpcQEFTVDSFHd_K2iG-iNi3WxQydqTrq3xzU,524
|
|
2
2
|
pyorc/const.py,sha256=Ia0KRkm-E1lJk4NxQVPDIfN38EBB7BKvxmwIHJrGPUY,2597
|
|
3
3
|
pyorc/cv.py,sha256=CTv0TbbcKeSQmKsX8mdVDXpSkhKZmr8SgT20YXMvZ0s,49156
|
|
4
4
|
pyorc/helpers.py,sha256=90TDtka0ydAydv3g5Dfc8MgtuSt0_9D9-HOtffpcBds,30636
|
|
@@ -8,12 +8,12 @@ pyorc/pyorc.sh,sha256=-xOSUNnMAwVbdNkjKNKMZMaBljWsGLhadG-j0DNlJP4,5
|
|
|
8
8
|
pyorc/sample_data.py,sha256=53NVnVmEksDw8ilbfhFFCiFJiGAIpxdgREbA_xt8P3o,2508
|
|
9
9
|
pyorc/api/__init__.py,sha256=k2OQQH4NrtXTuVm23d0g_SX6H5DhnKC9_kDyzJ4dWdk,428
|
|
10
10
|
pyorc/api/cameraconfig.py,sha256=NP9F7LhPO3aO6FRWkrGl6XpX8O3K59zfTtaYR3Kujqw,65419
|
|
11
|
-
pyorc/api/cross_section.py,sha256=
|
|
11
|
+
pyorc/api/cross_section.py,sha256=60n9EPe3HYvJxsX4CKb2pz3pf6hDRzqDrPR6uQOdvD8,53047
|
|
12
12
|
pyorc/api/frames.py,sha256=Kls4mpU_4hoUaXs9DJf2S6RHyp2D5emXJkAQWvvT39U,24300
|
|
13
13
|
pyorc/api/mask.py,sha256=COsL4fxz-Rsn-wgpojpJ1se4FGA8CZ_R1jx3iVUYB30,16462
|
|
14
14
|
pyorc/api/orcbase.py,sha256=C23QTKOyxHUafyJsq_t7xn_BzAEvf4DDfzlYAopons8,4189
|
|
15
|
-
pyorc/api/plot.py,sha256
|
|
16
|
-
pyorc/api/transect.py,sha256=
|
|
15
|
+
pyorc/api/plot.py,sha256=WUgJ5CJAY6-tstB7wd1vMs-jrcqIQxCmUfEBITtJWMU,31078
|
|
16
|
+
pyorc/api/transect.py,sha256=wENKWt0u0lHtT0lPYv47faHf_iAN9Mmeev-vwWjnz6E,13382
|
|
17
17
|
pyorc/api/velocimetry.py,sha256=bfU_XPbUbrdBI2XGprzh_3YADbGHfy4OuS1oBlbLEEI,12047
|
|
18
18
|
pyorc/api/video.py,sha256=lGD6bcV6Uu2u3zuGF_m3KxX2Cyp9k-YHUiXA42TOE3E,22458
|
|
19
19
|
pyorc/cli/__init__.py,sha256=A7hOQV26vIccPnDc8L2KqoJOSpMpf2PiMOXS18pAsWg,32
|
|
@@ -27,8 +27,8 @@ pyorc/service/velocimetry.py,sha256=UFjxmq5Uhk8wnBLScAyTaVWTPTCnH9hJdKOYBFrGZ_Y,
|
|
|
27
27
|
pyorc/velocimetry/__init__.py,sha256=lYM7oJZWxgJ2SpE22xhy7pBYcgkKFHMBHYmDvvMbtZk,148
|
|
28
28
|
pyorc/velocimetry/ffpiv.py,sha256=CYUjgwnB5osQmJ83j3E00B9P0_hS-rFuhyvufxKXtag,17487
|
|
29
29
|
pyorc/velocimetry/openpiv.py,sha256=6BxsbXLzT4iEq7v08G4sOhVlYFodUpY6sIm3jdCxNMs,13149
|
|
30
|
-
pyopenrivercam-0.8.
|
|
31
|
-
pyopenrivercam-0.8.
|
|
32
|
-
pyopenrivercam-0.8.
|
|
33
|
-
pyopenrivercam-0.8.
|
|
34
|
-
pyopenrivercam-0.8.
|
|
30
|
+
pyopenrivercam-0.8.11.dist-info/entry_points.txt,sha256=Cv_WI2Y6QLnPiNCXGli0gS4WAOAeMoprha1rAR3vdRE,44
|
|
31
|
+
pyopenrivercam-0.8.11.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
32
|
+
pyopenrivercam-0.8.11.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
33
|
+
pyopenrivercam-0.8.11.dist-info/METADATA,sha256=hNo75nJNt8C2xbKpILV2gX_3jq6oLKEOkBgHpaRHLBE,11641
|
|
34
|
+
pyopenrivercam-0.8.11.dist-info/RECORD,,
|
pyorc/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""pyorc: free and open-source image-based surface velocity and discharge."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.8.
|
|
3
|
+
__version__ = "0.8.11"
|
|
4
4
|
|
|
5
5
|
from .api import CameraConfig, CrossSection, Frames, Transect, Velocimetry, Video, get_camera_config, load_camera_config # noqa
|
|
6
6
|
from .project import * # noqa
|
pyorc/api/cross_section.py
CHANGED
|
@@ -13,7 +13,7 @@ from matplotlib import patheffects
|
|
|
13
13
|
from scipy.interpolate import interp1d
|
|
14
14
|
from scipy.optimize import differential_evolution
|
|
15
15
|
from shapely import affinity, geometry
|
|
16
|
-
from shapely.ops import polygonize
|
|
16
|
+
from shapely.ops import polygonize, split
|
|
17
17
|
|
|
18
18
|
from pyorc import cv, plot_helpers
|
|
19
19
|
|
|
@@ -613,16 +613,21 @@ class CrossSection:
|
|
|
613
613
|
raise ValueError("Amount of water line crossings must be 2 for a planar surface estimate.")
|
|
614
614
|
return geometry.Polygon(list(wls[0].coords) + list(wls[1].coords[::-1]))
|
|
615
615
|
|
|
616
|
-
def get_wetted_surface_sz(self, h: float) -> geometry.
|
|
617
|
-
"""Retrieve a wetted surface perpendicular to flow direction (SZ) for a water level
|
|
616
|
+
def get_wetted_surface_sz(self, h: float, perimeter: bool = False) -> Union[geometry.MultiPolygon, geometry.MultiLineString]:
|
|
617
|
+
"""Retrieve a wetted surface or perimeter perpendicular to flow direction (SZ) for a water level.
|
|
618
618
|
|
|
619
|
-
This
|
|
620
|
-
|
|
619
|
+
This returns a `geometry.MultiPolygon` when a surface is requested (`perimeter=False`), and
|
|
620
|
+
`geometry.MultiLineString` when a perimeter is requested (`perimeter=True`).
|
|
621
|
+
|
|
622
|
+
This is a useful method for instance to estimate m2 wetted surface or m wetted perimeter length for a given
|
|
623
|
+
water level in the cross section.
|
|
621
624
|
|
|
622
625
|
Parameters
|
|
623
626
|
----------
|
|
624
627
|
h : float
|
|
625
628
|
water level [m]
|
|
629
|
+
perimeter : bool, optional
|
|
630
|
+
If set to True, return a linestring with the wetted perimeter instead.
|
|
626
631
|
|
|
627
632
|
Returns
|
|
628
633
|
-------
|
|
@@ -630,6 +635,12 @@ class CrossSection:
|
|
|
630
635
|
Wetted surface as a polygon, in Y-Z projection.
|
|
631
636
|
|
|
632
637
|
"""
|
|
638
|
+
|
|
639
|
+
def avg_y(line):
|
|
640
|
+
"""Compute average y-coordinate of a line."""
|
|
641
|
+
ys = [p[1] for p in line.coords]
|
|
642
|
+
return sum(ys) / len(ys)
|
|
643
|
+
|
|
633
644
|
wl = self.get_cs_waterlevel(
|
|
634
645
|
h=h, sz=True, extend_by=0.1
|
|
635
646
|
) # extend a small bit to guarantee crossing with the bottom coordinates
|
|
@@ -642,6 +653,18 @@ class CrossSection:
|
|
|
642
653
|
if bottom_points[-1].y < zl:
|
|
643
654
|
bottom_points.append(geometry.Point(bottom_points[-1].x, zl + 0.1))
|
|
644
655
|
bottom_line = geometry.LineString(bottom_points)
|
|
656
|
+
if perimeter:
|
|
657
|
+
wl_z = wl.coords[0][-1]
|
|
658
|
+
split_segments = split(bottom_line, wl)
|
|
659
|
+
filtered = []
|
|
660
|
+
for seg in split_segments.geoms:
|
|
661
|
+
seg_z = avg_y(seg)
|
|
662
|
+
if seg_z < wl_z:
|
|
663
|
+
# segment is below water level, add to perimeter
|
|
664
|
+
filtered.append(seg)
|
|
665
|
+
|
|
666
|
+
return geometry.MultiLineString(filtered)
|
|
667
|
+
# return wetted_perim
|
|
645
668
|
pol = list(polygonize(wl.union(bottom_line)))
|
|
646
669
|
if len(pol) == 0:
|
|
647
670
|
# create infinitely small polygon at lowest z coordinate
|
pyorc/api/plot.py
CHANGED
|
@@ -752,8 +752,10 @@ def plot_text(ax, ds, prefix, suffix):
|
|
|
752
752
|
yloc = 0.95
|
|
753
753
|
_ds.transect.get_river_flow(q_name="q")
|
|
754
754
|
Q = np.abs(_ds.river_flow)
|
|
755
|
+
v_surf = _ds.transect.get_v_surf()
|
|
756
|
+
v_bulk = _ds.transect.get_v_bulk()
|
|
755
757
|
string = prefix
|
|
756
|
-
string += "
|
|
758
|
+
string += f"$h_a$: {_ds.transect.h_a:1.2f} m | $v_{{surf}}$: {v_surf.values:1.2f} m/s | $\overline{{v}}$: {v_bulk.values:1.2f} m/s\n$Q$: {Q.values:1.2f} m3/s" # .format(_ds.transect.h_a, Q.values)
|
|
757
759
|
if "q_nofill" in ds:
|
|
758
760
|
_ds.transect.get_river_flow(q_name="q_nofill")
|
|
759
761
|
Q_nofill = np.abs(_ds.river_flow)
|
|
@@ -765,7 +767,7 @@ def plot_text(ax, ds, prefix, suffix):
|
|
|
765
767
|
xloc,
|
|
766
768
|
yloc,
|
|
767
769
|
string,
|
|
768
|
-
size=
|
|
770
|
+
size=18,
|
|
769
771
|
horizontalalignment="right",
|
|
770
772
|
verticalalignment="top",
|
|
771
773
|
path_effects=path_effects,
|
pyorc/api/transect.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import xarray as xr
|
|
5
|
+
from shapely import geometry
|
|
5
6
|
from xarray.core import utils
|
|
6
7
|
|
|
7
8
|
from pyorc import helpers
|
|
@@ -34,6 +35,26 @@ class Transect(ORCBase):
|
|
|
34
35
|
coords = [[_x, _y, _z] for _x, _y, _z in zip(self._obj.xcoords, self._obj.ycoords, self._obj.zcoords)]
|
|
35
36
|
return CrossSection(camera_config=self.camera_config, cross_section=coords)
|
|
36
37
|
|
|
38
|
+
@property
|
|
39
|
+
def wetted_surface_polygon(self) -> geometry.MultiPolygon:
|
|
40
|
+
"""Return wetted surface as `shapely.geometry.MultiPolygon` object."""
|
|
41
|
+
return self.cross_section.get_wetted_surface_sz(self.h_a)
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def wetted_perimeter_linestring(self) -> geometry.MultiLineString:
|
|
45
|
+
"""Return wetted perimeter as `shapely.geometry.MultiLineString` object."""
|
|
46
|
+
return self.cross_section.get_wetted_surface_sz(self.h_a, perimeter=True)
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def wetted_surface(self) -> float:
|
|
50
|
+
"""Return wetted surface as float."""
|
|
51
|
+
return self.wetted_surface_polygon.area
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def wetted_perimeter(self) -> float:
|
|
55
|
+
"""Return wetted perimeter as float."""
|
|
56
|
+
return self.wetted_perimeter_linestring.length
|
|
57
|
+
|
|
37
58
|
def vector_to_scalar(self, v_x="v_x", v_y="v_y"):
|
|
38
59
|
"""Set "v_eff" and "v_dir" variables as effective velocities over cross-section, and its angle.
|
|
39
60
|
|
|
@@ -129,30 +150,6 @@ class Transect(ORCBase):
|
|
|
129
150
|
points_proj = self.camera_config.project_points(points, within_image=within_image, swap_y_coords=True)
|
|
130
151
|
return points_proj
|
|
131
152
|
|
|
132
|
-
def get_wetted_perspective(self, h, sample_size=1000):
|
|
133
|
-
"""Get wetted polygon in camera perspective.
|
|
134
|
-
|
|
135
|
-
Parameters
|
|
136
|
-
----------
|
|
137
|
-
h : float
|
|
138
|
-
The water level value to calculate the surface perspective.
|
|
139
|
-
sample_size : int, optional
|
|
140
|
-
The number of points to densify the transect with, by default 1000
|
|
141
|
-
|
|
142
|
-
Returns
|
|
143
|
-
-------
|
|
144
|
-
ndarray
|
|
145
|
-
A numpy array containing the points forming the wetted polygon perspective.
|
|
146
|
-
|
|
147
|
-
"""
|
|
148
|
-
bottom_points, surface_points = self.get_bottom_surface_z_perspective(h=h, sample_size=sample_size)
|
|
149
|
-
# concatenate points reversing one set for preps of a polygon
|
|
150
|
-
pol_points = np.concatenate([bottom_points, np.flipud(surface_points)], axis=0)
|
|
151
|
-
|
|
152
|
-
# add the first point at the end to close the polygon
|
|
153
|
-
pol_points = np.concatenate([pol_points, pol_points[0:1]], axis=0)
|
|
154
|
-
return pol_points
|
|
155
|
-
|
|
156
153
|
def get_depth_perspective(self, h, sample_size=1000, interval=25):
|
|
157
154
|
"""Get line (x, y) pairs that show the depth over several intervals in the wetted part of the cross section.
|
|
158
155
|
|
|
@@ -177,64 +174,59 @@ class Transect(ORCBase):
|
|
|
177
174
|
# make line pairs
|
|
178
175
|
return list(zip(bottom_points, surface_points))
|
|
179
176
|
|
|
180
|
-
def
|
|
181
|
-
"""
|
|
177
|
+
def get_v_surf(self, v_name="v_eff"):
|
|
178
|
+
"""Compute mean surface velocity in locations that are below water level.
|
|
182
179
|
|
|
183
180
|
Parameters
|
|
184
181
|
----------
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
xs : np.array, optional
|
|
188
|
-
x-coordinates to transform, derived from self.x if not provided (Default value = None)
|
|
189
|
-
ys :
|
|
190
|
-
y-coordinates to transform, derived from self.y if not provided (Default value = None)
|
|
191
|
-
mask_outside :
|
|
192
|
-
values not fitting in the original camera frame are set to NaN (Default value = True)
|
|
182
|
+
v_name : str, optional
|
|
183
|
+
name of variable where surface velocities [m s-1] are stored (Default value = "v_eff")
|
|
193
184
|
|
|
194
185
|
Returns
|
|
195
186
|
-------
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
rows : list of ints
|
|
199
|
-
rows of locations in original camera perspective
|
|
200
|
-
|
|
187
|
+
xr.DataArray
|
|
188
|
+
mean surface velocities for all provided quantiles or time steps
|
|
201
189
|
|
|
202
190
|
"""
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
#
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if
|
|
215
|
-
|
|
191
|
+
## Mean velocity over entire profile
|
|
192
|
+
z_a = self.camera_config.h_to_z(self.h_a)
|
|
193
|
+
|
|
194
|
+
depth = z_a - self._obj.zcoords
|
|
195
|
+
depth[depth < 0] = 0.0
|
|
196
|
+
|
|
197
|
+
# ds.transect.camera_config.get_depth(ds.zcoords, ds.transect.h_a)
|
|
198
|
+
wet_scoords = self._obj.scoords[depth > 0].values
|
|
199
|
+
if len(wet_scoords) == 0:
|
|
200
|
+
# no wet points found. Velocity can only be missing
|
|
201
|
+
v_av = np.nan
|
|
202
|
+
if len(wet_scoords) > 1:
|
|
203
|
+
velocity_int = self._obj[v_name].fillna(0.0).integrate(coord="scoords") # m2/s
|
|
204
|
+
width = (wet_scoords[-1] + (wet_scoords[-1] - wet_scoords[-2]) * 0.5) - (
|
|
205
|
+
wet_scoords[0] - (wet_scoords[1] - wet_scoords[0]) * 0.5
|
|
206
|
+
)
|
|
207
|
+
v_av = velocity_int / width
|
|
216
208
|
else:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
]
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
return
|
|
209
|
+
v_av = self._obj[v_name][:, depth > 0]
|
|
210
|
+
return v_av
|
|
211
|
+
|
|
212
|
+
def get_v_bulk(self, q_name="q"):
|
|
213
|
+
"""Compute the bulk velocity.
|
|
214
|
+
|
|
215
|
+
Parameters
|
|
216
|
+
----------
|
|
217
|
+
q_name : str, optional
|
|
218
|
+
name of variable where depth integrated velocities [m2 s-1] are stored (Default value = "q")
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
xr.DataArray
|
|
223
|
+
bulk velocities for all provided quantiles or time steps
|
|
224
|
+
|
|
225
|
+
"""
|
|
226
|
+
discharge = self._obj[q_name].fillna(0.0).integrate(coord="scoords")
|
|
227
|
+
wet_surf = self.wetted_surface
|
|
228
|
+
v_bulk = discharge / wet_surf
|
|
229
|
+
return v_bulk
|
|
238
230
|
|
|
239
231
|
def get_river_flow(self, q_name="q", discharge_name="river_flow"):
|
|
240
232
|
"""Integrate time series of depth averaged velocities [m2 s-1] into cross-section integrated flow [m3 s-1].
|
|
File without changes
|
|
File without changes
|
|
File without changes
|