Summary
openpiv.gpu.process.gpu_piv(..., validation_method="s2n") fails with a PyCUDA shape mismatch during invalid-vector replacement.
Additionally, the GPU S2N validation logic appears to invalidate high-S2N vectors instead of low-S2N vectors.
This makes pure S2N validation unusable and may make combined validation modes such as {"median_velocity", "s2n"} misleading.
Environment
- Package:
openpiv-python-gpu
- Relevant files:
openpiv/gpu/process.py
openpiv/gpu/validation.py
- Python:
3.11
- Backend:
PyCUDA
Reproduction
from openpiv.gpu import process
params = {
"window_size_iters": ((32, 2), (16, 1)),
"overlap_ratio": 0.5,
"dt": 0.02,
"mask": mask,
"deform": True,
"smooth": True,
"num_validation_iters": 2,
"validation_method": "s2n",
"s2n_tol": 1.3,
"return_s2n": True,
}
x, y, u, v, mask_out, s2n = process.gpu_piv(
frame_a,
frame_b,
**params
)
Actual Behavior
Pure S2N validation fails with:
ValueError: shapes do not match
File ".../openpiv/gpu/process.py", line 1203, in _replace_invalid_vectors
u, v = self._validation_gpu.replace_vectors(*self._validation_gpu.median)
File ".../openpiv/gpu/validation.py", line 200, in <listcomp>
gpuarray.if_positive(self.val_locations, f_replace[i], self._f[i])
File ".../pycuda/gpuarray.py", line 1965, in if_positive
raise ValueError("shapes do not match")
Observed behavior:
validation_method="median_velocity" # OK
validation_method="mean_velocity" # OK
validation_method="rms_velocity" # OK
validation_method="s2n" # crashes
validation_method={"median_velocity","s2n"} # runs, but behavior suspicious
Suspected Cause 1: S2N Shape Mismatch
In process.py:
if "s2n" in self.validation_method:
s2n_ratio = self._corr_gpu.s2n_ratio
self._corr_gpu.s2n_ratio appears to be flattened. If S2N validation runs first, _local_validation() creates val_locations with the flattened shape, but replace_vectors() later expects 2D velocity-field shapes.
The existing PIV.s2n_ratio property already reshapes correctly:
shape = self._piv_fields[-1].shape
return self._corr_gpu.s2n_ratio.reshape(shape)
Possible fix:
if "s2n" in self.validation_method:
s2n_ratio = self._corr_gpu.s2n_ratio.reshape(u.shape)
Suspected Cause 2: S2N Threshold Logic Appears Inverted
In process.py:
s2n_ratio = cumath.log10(corr_peak1 / corr_peak2)
In validation.py:
s2n_tol = log10(self.s2n_tol)
sig2noise_tol = s2n_ratio / DTYPE_f(s2n_tol)
self.val_locations = _local_validation(
sig2noise_tol,
1,
self.val_locations,
)
_local_validation() marks vectors invalid where:
This invalidates vectors when:
s2n_ratio > log10(s2n_tol)
which corresponds to:
That appears backwards.
The CPU implementation instead does:
Expected Behavior
validation_method="s2n" should not crash.
- Low-S2N vectors should be invalidated.
- High-S2N vectors should remain valid.
Proposed Fix
def _s2n_validation(self, s2n_ratio):
if s2n_ratio is None:
return
s2n_tol = log10(self.s2n_tol)
self.val_locations = _local_validation(
DTYPE_f(s2n_tol) - s2n_ratio,
0,
self.val_locations,
)
Additional Notes
Combined validation such as:
validation_method = {"median_velocity", "s2n"}
does not crash, likely because median validation initializes val_locations with the correct 2D shape first.
However, if the threshold logic is inverted, combined validation may still invalidate the wrong vectors.
Summary
openpiv.gpu.process.gpu_piv(..., validation_method="s2n")fails with a PyCUDA shape mismatch during invalid-vector replacement.Additionally, the GPU S2N validation logic appears to invalidate high-S2N vectors instead of low-S2N vectors.
This makes pure S2N validation unusable and may make combined validation modes such as
{"median_velocity", "s2n"}misleading.Environment
openpiv-python-gpuopenpiv/gpu/process.pyopenpiv/gpu/validation.py3.11PyCUDAReproduction
Actual Behavior
Pure S2N validation fails with:
Observed behavior:
Suspected Cause 1: S2N Shape Mismatch
In
process.py:self._corr_gpu.s2n_ratioappears to be flattened. If S2N validation runs first,_local_validation()createsval_locationswith the flattened shape, butreplace_vectors()later expects 2D velocity-field shapes.The existing
PIV.s2n_ratioproperty already reshapes correctly:Possible fix:
Suspected Cause 2: S2N Threshold Logic Appears Inverted
In
process.py:In
validation.py:_local_validation()marks vectors invalid where:This invalidates vectors when:
which corresponds to:
That appears backwards.
The CPU implementation instead does:
Expected Behavior
validation_method="s2n"should not crash.Proposed Fix
Additional Notes
Combined validation such as:
does not crash, likely because median validation initializes
val_locationswith the correct 2D shape first.However, if the threshold logic is inverted, combined validation may still invalidate the wrong vectors.