pivtools 0.1.3__cp311-cp311-win_amd64.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.
Files changed (127) hide show
  1. pivtools-0.1.3.dist-info/METADATA +222 -0
  2. pivtools-0.1.3.dist-info/RECORD +127 -0
  3. pivtools-0.1.3.dist-info/WHEEL +5 -0
  4. pivtools-0.1.3.dist-info/entry_points.txt +3 -0
  5. pivtools-0.1.3.dist-info/top_level.txt +3 -0
  6. pivtools_cli/__init__.py +5 -0
  7. pivtools_cli/_build_marker.c +25 -0
  8. pivtools_cli/_build_marker.cp311-win_amd64.pyd +0 -0
  9. pivtools_cli/cli.py +225 -0
  10. pivtools_cli/example.py +139 -0
  11. pivtools_cli/lib/PIV_2d_cross_correlate.c +334 -0
  12. pivtools_cli/lib/PIV_2d_cross_correlate.h +22 -0
  13. pivtools_cli/lib/common.h +36 -0
  14. pivtools_cli/lib/interp2custom.c +146 -0
  15. pivtools_cli/lib/interp2custom.h +48 -0
  16. pivtools_cli/lib/peak_locate_gsl.c +711 -0
  17. pivtools_cli/lib/peak_locate_gsl.h +40 -0
  18. pivtools_cli/lib/peak_locate_gsl_print.c +736 -0
  19. pivtools_cli/lib/peak_locate_lm.c +751 -0
  20. pivtools_cli/lib/peak_locate_lm.h +27 -0
  21. pivtools_cli/lib/xcorr.c +342 -0
  22. pivtools_cli/lib/xcorr.h +31 -0
  23. pivtools_cli/lib/xcorr_cache.c +78 -0
  24. pivtools_cli/lib/xcorr_cache.h +26 -0
  25. pivtools_cli/piv/interp2custom/interp2custom.py +69 -0
  26. pivtools_cli/piv/piv.py +240 -0
  27. pivtools_cli/piv/piv_backend/base.py +825 -0
  28. pivtools_cli/piv/piv_backend/cpu_instantaneous.py +1005 -0
  29. pivtools_cli/piv/piv_backend/factory.py +28 -0
  30. pivtools_cli/piv/piv_backend/gpu_instantaneous.py +15 -0
  31. pivtools_cli/piv/piv_backend/infilling.py +445 -0
  32. pivtools_cli/piv/piv_backend/outlier_detection.py +306 -0
  33. pivtools_cli/piv/piv_backend/profile_cpu_instantaneous.py +230 -0
  34. pivtools_cli/piv/piv_result.py +40 -0
  35. pivtools_cli/piv/save_results.py +342 -0
  36. pivtools_cli/piv_cluster/cluster.py +108 -0
  37. pivtools_cli/preprocessing/filters.py +399 -0
  38. pivtools_cli/preprocessing/preprocess.py +79 -0
  39. pivtools_cli/tests/helpers.py +107 -0
  40. pivtools_cli/tests/instantaneous_piv/test_piv_integration.py +167 -0
  41. pivtools_cli/tests/instantaneous_piv/test_piv_integration_multi.py +553 -0
  42. pivtools_cli/tests/preprocessing/test_filters.py +41 -0
  43. pivtools_core/__init__.py +5 -0
  44. pivtools_core/config.py +703 -0
  45. pivtools_core/config.yaml +135 -0
  46. pivtools_core/image_handling/__init__.py +0 -0
  47. pivtools_core/image_handling/load_images.py +464 -0
  48. pivtools_core/image_handling/readers/__init__.py +53 -0
  49. pivtools_core/image_handling/readers/generic_readers.py +50 -0
  50. pivtools_core/image_handling/readers/lavision_reader.py +190 -0
  51. pivtools_core/image_handling/readers/registry.py +24 -0
  52. pivtools_core/paths.py +49 -0
  53. pivtools_core/vector_loading.py +248 -0
  54. pivtools_gui/__init__.py +3 -0
  55. pivtools_gui/app.py +687 -0
  56. pivtools_gui/calibration/__init__.py +0 -0
  57. pivtools_gui/calibration/app/__init__.py +0 -0
  58. pivtools_gui/calibration/app/views.py +1186 -0
  59. pivtools_gui/calibration/calibration_planar/planar_calibration_production.py +570 -0
  60. pivtools_gui/calibration/vector_calibration_production.py +544 -0
  61. pivtools_gui/config.py +703 -0
  62. pivtools_gui/image_handling/__init__.py +0 -0
  63. pivtools_gui/image_handling/load_images.py +464 -0
  64. pivtools_gui/image_handling/readers/__init__.py +53 -0
  65. pivtools_gui/image_handling/readers/generic_readers.py +50 -0
  66. pivtools_gui/image_handling/readers/lavision_reader.py +190 -0
  67. pivtools_gui/image_handling/readers/registry.py +24 -0
  68. pivtools_gui/masking/__init__.py +0 -0
  69. pivtools_gui/masking/app/__init__.py +0 -0
  70. pivtools_gui/masking/app/views.py +123 -0
  71. pivtools_gui/paths.py +49 -0
  72. pivtools_gui/piv_runner.py +261 -0
  73. pivtools_gui/pivtools.py +58 -0
  74. pivtools_gui/plotting/__init__.py +0 -0
  75. pivtools_gui/plotting/app/__init__.py +0 -0
  76. pivtools_gui/plotting/app/views.py +1671 -0
  77. pivtools_gui/plotting/plot_maker.py +220 -0
  78. pivtools_gui/post_processing/POD/__init__.py +0 -0
  79. pivtools_gui/post_processing/POD/app/__init__.py +0 -0
  80. pivtools_gui/post_processing/POD/app/views.py +647 -0
  81. pivtools_gui/post_processing/POD/pod_decompose.py +979 -0
  82. pivtools_gui/post_processing/POD/views.py +1096 -0
  83. pivtools_gui/post_processing/__init__.py +0 -0
  84. pivtools_gui/static/404.html +1 -0
  85. pivtools_gui/static/_next/static/chunks/117-d5793c8e79de5511.js +2 -0
  86. pivtools_gui/static/_next/static/chunks/484-cfa8b9348ce4f00e.js +1 -0
  87. pivtools_gui/static/_next/static/chunks/869-320a6b9bdafbb6d3.js +1 -0
  88. pivtools_gui/static/_next/static/chunks/app/_not-found/page-12f067ceb7415e55.js +1 -0
  89. pivtools_gui/static/_next/static/chunks/app/layout-b907d5f31ac82e9d.js +1 -0
  90. pivtools_gui/static/_next/static/chunks/app/page-334cc4e8444cde2f.js +1 -0
  91. pivtools_gui/static/_next/static/chunks/fd9d1056-ad15f396ddf9b7e5.js +1 -0
  92. pivtools_gui/static/_next/static/chunks/framework-f66176bb897dc684.js +1 -0
  93. pivtools_gui/static/_next/static/chunks/main-a1b3ced4d5f6d998.js +1 -0
  94. pivtools_gui/static/_next/static/chunks/main-app-8a63c6f5e7baee11.js +1 -0
  95. pivtools_gui/static/_next/static/chunks/pages/_app-72b849fbd24ac258.js +1 -0
  96. pivtools_gui/static/_next/static/chunks/pages/_error-7ba65e1336b92748.js +1 -0
  97. pivtools_gui/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  98. pivtools_gui/static/_next/static/chunks/webpack-4a8ca7c99e9bb3d8.js +1 -0
  99. pivtools_gui/static/_next/static/css/7d3f2337d7ea12a5.css +3 -0
  100. pivtools_gui/static/_next/static/vQeR20OUdSSKlK4vukC4q/_buildManifest.js +1 -0
  101. pivtools_gui/static/_next/static/vQeR20OUdSSKlK4vukC4q/_ssgManifest.js +1 -0
  102. pivtools_gui/static/file.svg +1 -0
  103. pivtools_gui/static/globe.svg +1 -0
  104. pivtools_gui/static/grid.svg +8 -0
  105. pivtools_gui/static/index.html +1 -0
  106. pivtools_gui/static/index.txt +8 -0
  107. pivtools_gui/static/next.svg +1 -0
  108. pivtools_gui/static/vercel.svg +1 -0
  109. pivtools_gui/static/window.svg +1 -0
  110. pivtools_gui/stereo_reconstruction/__init__.py +0 -0
  111. pivtools_gui/stereo_reconstruction/app/__init__.py +0 -0
  112. pivtools_gui/stereo_reconstruction/app/views.py +1985 -0
  113. pivtools_gui/stereo_reconstruction/stereo_calibration_production.py +606 -0
  114. pivtools_gui/stereo_reconstruction/stereo_reconstruction_production.py +544 -0
  115. pivtools_gui/utils.py +63 -0
  116. pivtools_gui/vector_loading.py +248 -0
  117. pivtools_gui/vector_merging/__init__.py +1 -0
  118. pivtools_gui/vector_merging/app/__init__.py +1 -0
  119. pivtools_gui/vector_merging/app/views.py +759 -0
  120. pivtools_gui/vector_statistics/app/__init__.py +1 -0
  121. pivtools_gui/vector_statistics/app/views.py +710 -0
  122. pivtools_gui/vector_statistics/ensemble_statistics.py +49 -0
  123. pivtools_gui/vector_statistics/instantaneous_statistics.py +311 -0
  124. pivtools_gui/video_maker/__init__.py +0 -0
  125. pivtools_gui/video_maker/app/__init__.py +0 -0
  126. pivtools_gui/video_maker/app/views.py +436 -0
  127. pivtools_gui/video_maker/video_maker.py +662 -0
@@ -0,0 +1,220 @@
1
+ from dataclasses import dataclass
2
+ from pathlib import Path
3
+
4
+ import matplotlib as mpl
5
+ import matplotlib.pyplot as plt
6
+ import numpy as np
7
+ from matplotlib.cm import ScalarMappable
8
+ from matplotlib.colors import Normalize, TwoSlopeNorm
9
+ from matplotlib.ticker import FixedFormatter, FixedLocator
10
+
11
+ from ..config import Config
12
+
13
+ mpl.use("Agg")
14
+ mpl.rcParams["xtick.direction"] = "in"
15
+ mpl.rcParams["ytick.direction"] = "in"
16
+ mpl.rcParams["xtick.major.size"] = 5
17
+ mpl.rcParams["ytick.major.size"] = 5
18
+ mpl.rcParams["xtick.minor.size"] = 3
19
+ mpl.rcParams["ytick.minor.size"] = 3
20
+ mpl.rcParams["xtick.minor.visible"] = True
21
+ mpl.rcParams["ytick.minor.visible"] = True
22
+ mpl.rcParams["xtick.major.pad"] = 6
23
+ mpl.rcParams["ytick.major.pad"] = 6
24
+
25
+
26
+ # Settings object to drive plot_scalar_field conveniently from Config
27
+ @dataclass
28
+ class Settings:
29
+ variableName: str
30
+ variableUnits: str = ""
31
+ length_units: str = "mm"
32
+ title: str = ""
33
+ levels: int | list = 500
34
+ cmap: str | None = None
35
+ corners: tuple | None = None
36
+ lower_limit: float | None = None
37
+ upper_limit: float | None = None
38
+ _xlabel: str = "x"
39
+ _ylabel: str = "y"
40
+ _fontsize: int = 12
41
+ _title_fontsize: int = 14
42
+ save_name: str | None = None
43
+ save_extension: str = ".png"
44
+ save_pickle: bool = False
45
+ # New: optional coordinates and symmetric scaling control
46
+ coords_x: np.ndarray | None = None
47
+ coords_y: np.ndarray | None = None
48
+ symmetric_around_zero: bool = True
49
+
50
+
51
+ def make_scalar_settings(
52
+ config: Config,
53
+ *,
54
+ variable: str,
55
+ run_label: int,
56
+ save_basepath: Path,
57
+ title: str | None = None,
58
+ variable_units: str = "",
59
+ length_units: str = "mm",
60
+ cmap: str | None = None,
61
+ levels: int | list = 100,
62
+ lower_limit: float | None = None,
63
+ upper_limit: float | None = None,
64
+ corners: tuple | None = None,
65
+ coords_x: np.ndarray | None = None,
66
+ coords_y: np.ndarray | None = None,
67
+ symmetric_around_zero: bool = True,
68
+ ) -> Settings:
69
+ return Settings(
70
+ variableName=variable,
71
+ variableUnits=variable_units,
72
+ length_units=length_units,
73
+ title=title or f"{variable} pass {run_label}",
74
+ levels=levels,
75
+ cmap=cmap,
76
+ corners=corners,
77
+ lower_limit=lower_limit,
78
+ upper_limit=upper_limit,
79
+ _xlabel="x",
80
+ _ylabel="y",
81
+ _fontsize=config.plot_fontsize,
82
+ _title_fontsize=config.plot_title_fontsize,
83
+ save_name=str(save_basepath),
84
+ save_extension=config.plot_save_extension,
85
+ save_pickle=config.plot_save_pickle,
86
+ coords_x=coords_x,
87
+ coords_y=coords_y,
88
+ symmetric_around_zero=symmetric_around_zero,
89
+ )
90
+
91
+ # Function to plot a scalar field with masking and customizable settings
92
+ def plot_scalar_field(variable, mask, settings): # efe
93
+ # Extract plot settings
94
+ plt.rcParams.update({"font.size": settings._fontsize})
95
+ plt.rcParams["axes.titlesize"] = settings._title_fontsize
96
+
97
+ cm_label = settings.variableName + " (" + settings.variableUnits + ")"
98
+
99
+ # Mask the variable array where mask is True
100
+ masked_var = np.ma.array(variable, mask=mask)
101
+
102
+ # Generate coordinate arrays: prefer provided coords_x/coords_y, else corners, else indices
103
+ X = Y = None
104
+ if settings.coords_x is not None and settings.coords_y is not None:
105
+ cx, cy = np.asarray(settings.coords_x), np.asarray(settings.coords_y)
106
+ # 2D grid case matching variable shape
107
+ if (
108
+ cx.ndim == 2
109
+ and cy.ndim == 2
110
+ and cx.shape == variable.shape
111
+ and cy.shape == variable.shape
112
+ ):
113
+ X, Y = cx, cy
114
+ # 1D axes case
115
+ elif cx.ndim == 1 and cy.ndim == 1:
116
+ ny, nx = variable.shape
117
+ if cx.size == nx and cy.size == ny:
118
+ X, Y = np.meshgrid(cx, cy)
119
+ if X is None or Y is None:
120
+ if settings.corners is not None and all(
121
+ c is not None for c in settings.corners
122
+ ):
123
+ x0, y0, x1, y1 = settings.corners
124
+ ny, nx = variable.shape
125
+ x = np.linspace(x0, x1, nx)
126
+ y = np.linspace(y0, y1, ny)
127
+ else:
128
+ ny, nx = variable.shape
129
+ x = np.arange(nx)
130
+ y = np.arange(ny-1, -1, -1)
131
+ X, Y = np.meshgrid(x, y)
132
+
133
+ # Create the plot (object-oriented API)
134
+ fig, ax = plt.subplots(figsize=(12, 7))
135
+ ax.set_facecolor("gray") # <-- gray shows through masked holes
136
+
137
+ # Determine limits
138
+ if settings.lower_limit is not None and settings.upper_limit is not None:
139
+ vmin, vmax = settings.lower_limit, settings.upper_limit
140
+ else:
141
+ # Use nanmin/nanmax to handle NaN values properly
142
+ valid_data = masked_var.compressed() # Get unmasked data
143
+ if len(valid_data) > 0:
144
+ vmin = float(np.nanmin(valid_data))
145
+ vmax = float(np.nanmax(valid_data))
146
+ # Check if min/max are still NaN (all valid data is NaN)
147
+ if np.isnan(vmin) or np.isnan(vmax) or np.isinf(vmin) or np.isinf(vmax):
148
+ # Fallback to sensible defaults
149
+ vmin, vmax = 0.0, 1.0
150
+ else:
151
+ # No valid data at all - use defaults
152
+ vmin, vmax = 0.0, 1.0
153
+
154
+ # Enforce symmetric scale around zero if data spans negative and positive
155
+ use_two_slope = False
156
+ actual_min = vmin
157
+ actual_max = vmax
158
+ if settings.symmetric_around_zero and vmin < 0 and vmax > 0:
159
+ vabs = max(abs(vmin), abs(vmax))
160
+ vmin, vmax = -vabs, vabs
161
+ use_two_slope = True
162
+
163
+ # Select colormap & norm
164
+ if settings.cmap is not None:
165
+ cmap = plt.get_cmap(settings.cmap)
166
+ norm = (
167
+ TwoSlopeNorm(vmin=vmin, vcenter=0, vmax=vmax)
168
+ if use_two_slope
169
+ else Normalize(vmin=vmin, vmax=vmax)
170
+ )
171
+ else:
172
+ if use_two_slope:
173
+ cmap = plt.get_cmap("bwr")
174
+ norm = TwoSlopeNorm(vmin=vmin, vcenter=0, vmax=vmax)
175
+ else:
176
+ bwr = plt.get_cmap("bwr")
177
+ if vmax <= 0:
178
+ colors = bwr(np.linspace(0.0, 0.5, 256))
179
+ cmap = mpl.colors.LinearSegmentedColormap.from_list("bwr_lower", colors)
180
+ norm = Normalize(vmin=vmin, vmax=vmax)
181
+ else:
182
+ colors = bwr(np.linspace(0.5, 1.0, 256))
183
+ cmap = mpl.colors.LinearSegmentedColormap.from_list("bwr_upper", colors)
184
+ norm = Normalize(vmin=vmin, vmax=vmax)
185
+
186
+ # Use ax.contourf (object-oriented)
187
+ im = ax.contourf(X, Y, masked_var, levels=settings.levels, cmap=cmap, norm=norm)
188
+
189
+ sm = ScalarMappable(norm=norm, cmap=cmap)
190
+ sm.set_array([]) # required for some Matplotlib versions
191
+
192
+ # Use object-oriented colorbar
193
+ cbar = fig.colorbar(sm, ax=ax, label=cm_label)
194
+
195
+ if isinstance(settings.levels, np.ndarray):
196
+ if isinstance(norm, TwoSlopeNorm):
197
+ ticks = [norm.vmin, 0.0, norm.vmax]
198
+ else:
199
+ ticks = np.linspace(norm.vmin, norm.vmax, 7)
200
+ else:
201
+ ticks = np.linspace(norm.vmin, norm.vmax, 7)
202
+
203
+ # Optional: nice fixed tick count
204
+ ticks = np.linspace(actual_min, actual_max, 7)
205
+ labels = [f"{t:.2f}" for t in ticks]
206
+ cbar.set_ticks(ticks)
207
+ cbar.set_ticklabels(labels)
208
+ cbar.ax.set_ylim(actual_min, actual_max)
209
+ cbar.ax.yaxis.set_major_locator(FixedLocator(ticks))
210
+ cbar.ax.yaxis.set_major_formatter(FixedFormatter(labels))
211
+
212
+ ax.set_title(f"{settings.title}")
213
+ if settings.length_units:
214
+ ax.set_xlabel(settings._xlabel + f" ({settings.length_units})")
215
+ ax.set_ylabel(settings._ylabel + f" ({settings.length_units})")
216
+ else:
217
+ ax.set_xlabel(settings._xlabel)
218
+ ax.set_ylabel(settings._ylabel)
219
+
220
+ return fig, ax, im
File without changes
File without changes