From f115c6ab314e681d66982a3821f189cd03336e66 Mon Sep 17 00:00:00 2001 From: James Douglass Date: Tue, 30 Apr 2024 16:24:16 -0700 Subject: [PATCH] Addressing viewshed numerical error issue on M1. RE:#1562 --- src/natcap/invest/scenic_quality/viewshed.pyx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/natcap/invest/scenic_quality/viewshed.pyx b/src/natcap/invest/scenic_quality/viewshed.pyx index 2f125a4077..5c0cdbfc78 100644 --- a/src/natcap/invest/scenic_quality/viewshed.pyx +++ b/src/natcap/invest/scenic_quality/viewshed.pyx @@ -815,8 +815,21 @@ def viewshed(dem_raster_path_band, if target_distance > max_visible_radius: break - z = (((previous_height-r_v)/slope_distance) * - target_distance + r_v) + # This is a weird platform-specific workaround addressing + # https://github.com/natcap/invest/issues/1562 + # On M1 macs, the all-in-one-line addition of _product and r_v + # would create small but noticeable numerical error. Breaking the + # calculation onto two lines eliminates the numerical error. This + # behavior is reproducible in C, outside of Cython on an M1 mac. + # So, this calculation would introduce error: + # z = (((previous_height-r_v)/slope_distance) * target_distance) + r_v + # while the formlation below does not. + # + # Some of this may be related to the fact that x86 chips have + # extended precision for FPU-based calculations while M1 ARM chips + # do not. Still, that doesn't explain why the error is introduced. + _product = (((previous_height-r_v)/slope_distance) * target_distance) + z = _product + r_v # add on refractivity/curvature-of-earth calculations. adjustment = 0.0 # increase in required height due to curvature