Describe the bug
_helmert14_point in xrspatial/reproject/_itrf.py converts the scale parameter with
s_e = 1.0 + (s + ds * dt) * 1e-9 # ppb -> scale factor
but the parameters come from PROJ's ITRF data files, and PROJ's helmert operation defines +s / +ds in ppm, not ppb. The file values are ppb magnitudes written in ppm units, e.g. ITRF2014 -> ITRF2000 carries +s=0.00212 (ppm) = 2.12 ppb. Multiplying by 1e-9 makes the scale term 1000x too small, which effectively drops it.
Against a pyproj 4D helmert pipeline built from the same parameters, itrf_transform(-74.0, 40.7, 100.0, src='ITRF2014', tgt='ITRF2000', epoch=2024.0) is off by about 23 mm in height. With the factor corrected to 1e-6 the pure-Python port matches pyproj to better than 0.01 mm:
pyproj 4D: -73.99999996763594 40.69999965079892 99.98748955968767
ppm interp: -73.99999996763596 40.699999650798915 99.98748955968767
ppb (code): -73.99999996763594 40.69999965149493 99.96420177258551
A 2-3 cm error is negligible for raster reprojection but this function's stated purpose is mm-level frame transforms ("relevant for precision geodesy", module docstring), so the result is wrong at the scale the API advertises.
Expected behavior
itrf_transform matches a PROJ helmert pipeline built from the same parameter file entry at the same epoch, to sub-mm.
Additional context
Found by /sweep-accuracy against the reproject module. Note pyproj only applies the rate terms when given 4D coordinates (transform(lon, lat, h, epoch)); a 3D transform silently uses the static parameters, which is worth remembering when writing the regression test.
Describe the bug
_helmert14_pointinxrspatial/reproject/_itrf.pyconverts the scale parameter withbut the parameters come from PROJ's ITRF data files, and PROJ's
helmertoperation defines+s/+dsin ppm, not ppb. The file values are ppb magnitudes written in ppm units, e.g.ITRF2014 -> ITRF2000carries+s=0.00212(ppm) = 2.12 ppb. Multiplying by 1e-9 makes the scale term 1000x too small, which effectively drops it.Against a pyproj 4D helmert pipeline built from the same parameters,
itrf_transform(-74.0, 40.7, 100.0, src='ITRF2014', tgt='ITRF2000', epoch=2024.0)is off by about 23 mm in height. With the factor corrected to 1e-6 the pure-Python port matches pyproj to better than 0.01 mm:A 2-3 cm error is negligible for raster reprojection but this function's stated purpose is mm-level frame transforms ("relevant for precision geodesy", module docstring), so the result is wrong at the scale the API advertises.
Expected behavior
itrf_transformmatches a PROJ helmert pipeline built from the same parameter file entry at the same epoch, to sub-mm.Additional context
Found by /sweep-accuracy against the reproject module. Note pyproj only applies the rate terms when given 4D coordinates (
transform(lon, lat, h, epoch)); a 3D transform silently uses the static parameters, which is worth remembering when writing the regression test.