Skip to content

Commit e5e0fe2

Browse files
committed
more aggressive nan check in the src
1 parent 845443b commit e5e0fe2

2 files changed

Lines changed: 58 additions & 14 deletions

File tree

src/gen_ic3d.F90

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,18 @@ MODULE g_ic3d
2020
USE g_comm_auto
2121
USE g_support
2222
USE g_config, only: dummy, ClimateDataPath, use_cavity
23+
USE, INTRINSIC :: ISO_C_BINDING, only: C_DOUBLE, C_INT
2324

2425
IMPLICIT NONE
26+
27+
! C-binding interface for isnan - immune to Fortran compiler flags like -ffast-math
28+
INTERFACE
29+
PURE FUNCTION c_isnan(x) BIND(C, name="isnan")
30+
IMPORT :: C_DOUBLE, C_INT
31+
REAL(C_DOUBLE), VALUE, INTENT(IN) :: x
32+
INTEGER(C_INT) :: c_isnan
33+
END FUNCTION c_isnan
34+
END INTERFACE
2535

2636
include 'netcdf.inc'
2737

@@ -65,6 +75,30 @@ MODULE g_ic3d
6575

6676
!============== NETCDF ==========================================
6777
CONTAINS
78+
! Helper function: returns .true. if x is NaN, using C library (immune to -ffast-math)
79+
PURE LOGICAL FUNCTION is_nan(x)
80+
REAL(KIND=8), INTENT(IN) :: x
81+
is_nan = (c_isnan(x) /= 0)
82+
END FUNCTION is_nan
83+
84+
! Check if any of the 4 corners at any depth has NaN
85+
LOGICAL FUNCTION corners_have_nan(arr, i1, i2, j1, j2, nk)
86+
REAL(KIND=8), INTENT(IN) :: arr(:,:,:)
87+
INTEGER, INTENT(IN) :: i1, i2, j1, j2, nk
88+
INTEGER :: ii, jj, kk
89+
corners_have_nan = .false.
90+
do kk = 1, nk
91+
do jj = j1, j2
92+
do ii = i1, i2
93+
if (is_nan(arr(ii,jj,kk))) then
94+
corners_have_nan = .true.
95+
return
96+
end if
97+
end do
98+
end do
99+
end do
100+
END FUNCTION corners_have_nan
101+
68102
SUBROUTINE nc_readGrid(partit)
69103
! Read time array and grid from nc file
70104
IMPLICIT NONE
@@ -380,11 +414,11 @@ SUBROUTINE getcoeffld(tracers, partit, mesh)
380414
ncdata(nc_Nlon,:,:)=ncdata(2,:,:)
381415

382416
! replace nan (or fillvalue) by dummy value
383-
! Use x/=x test in addition to ieee_is_nan (ieee_is_nan fails with -ffast-math)
417+
! Use C library isnan() which is immune to Fortran -ffast-math optimizations
384418
do k=1,nc_Ndepth
385419
do j=1,nc_Nlat
386420
do i=1,nc_Nlon
387-
if (ncdata(i,j,k) /= ncdata(i,j,k) .or. ieee_is_nan(ncdata(i,j,k)) .or. (ncdata(i,j,k)==FILL_VALUE)) then
421+
if (is_nan(ncdata(i,j,k)) .or. (ncdata(i,j,k)==FILL_VALUE)) then
388422
ncdata(i,j,k) = dummy
389423
elseif (ncdata(i,j,k) < -0.99_WP*dummy .or. ncdata(i,j,k) > dummy) then
390424
! and in case the input data has other conventions on missing values:
@@ -422,9 +456,10 @@ SUBROUTINE getcoeffld(tracers, partit, mesh)
422456
if (x<0.) x=x+360.
423457
if (x>360.) x=x-360.
424458
if ( min(i,j)>0 ) then
425-
! Skip if any corner has dummy OR NaN (NaN comparisons are always FALSE, so check explicitly)
426-
if (any(ncdata(i:ip1,j:jp1,1) > dummy*0.99_WP) .or. &
427-
any(ncdata(i:ip1,j:jp1,1) /= ncdata(i:ip1,j:jp1,1))) cycle
459+
! Skip if any corner at ANY depth has dummy OR NaN
460+
! Use C library isnan() which is immune to Fortran -ffast-math optimizations
461+
if (any(ncdata(i:ip1,j:jp1,:) > dummy*0.99_WP) .or. &
462+
corners_have_nan(ncdata, i, ip1, j, jp1, nc_Ndepth)) cycle
428463
x1 = nc_lon(i)
429464
x2 = nc_lon(ip1)
430465
y1 = nc_lat(j)
@@ -438,9 +473,9 @@ SUBROUTINE getcoeffld(tracers, partit, mesh)
438473
ncdata(i,jp1,:) > 0.99_WP*dummy .OR. ncdata(ip1,jp1,:) > 0.99_WP*dummy)
439474
data1d(:)=dummy
440475
end where
441-
! Also catch any NaN using explicit loop (WHERE doesn't work with NaN due to compiler optimizations)
476+
! Also catch any NaN using C library isnan (immune to -ffast-math)
442477
do k=1, nc_Ndepth
443-
if (data1d(k) /= data1d(k)) data1d(k) = dummy
478+
if (is_nan(data1d(k))) data1d(k) = dummy
444479
end do
445480

446481
!___________________________________________________________________
@@ -557,11 +592,10 @@ SUBROUTINE do_ic3d(tracers, partit, mesh)
557592
end where
558593

559594
!_________________________________________________________________________
560-
! Sanitize NaN using explicit DO loop (WHERE doesn't work with NaN due to
561-
! compiler optimizations like -ffast-math). Uses x/=x test: only NaN satisfies this.
595+
! Sanitize NaN using C library isnan (immune to -ffast-math optimizations)
562596
do n=1, partit%myDim_nod2d + partit%eDim_nod2D
563597
do i=1, mesh%nl-1
564-
if (tracers%data(current_tracer)%values(i,n) /= tracers%data(current_tracer)%values(i,n)) then
598+
if (is_nan(tracers%data(current_tracer)%values(i,n))) then
565599
tracers%data(current_tracer)%values(i,n) = 0.0_WP
566600
end if
567601
end do

src/gen_support.F90

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@ module g_support
88
use g_comm_auto
99
use o_ARRAYS
1010
use g_config, only: dummy
11+
USE, INTRINSIC :: ISO_C_BINDING, only: C_DOUBLE, C_INT
1112
implicit none
13+
14+
! C-binding interface for isnan - immune to Fortran compiler flags like -ffast-math
15+
INTERFACE
16+
PURE FUNCTION c_isnan_support(x) BIND(C, name="isnan")
17+
IMPORT :: C_DOUBLE, C_INT
18+
REAL(C_DOUBLE), VALUE, INTENT(IN) :: x
19+
INTEGER(C_INT) :: c_isnan_support
20+
END FUNCTION c_isnan_support
21+
END INTERFACE
1222

1323
private
1424
public :: smooth_nod, smooth_elem, integrate_nod, integrate_elem, extrap_nod, omp_min_max_sum1, omp_min_max_sum2, point_in_polygon
@@ -419,10 +429,10 @@ subroutine extrap_nod3D(arr, partit, mesh)
419429
call exchange_nod(arr, partit)
420430

421431
!___________________________________________________________________________
422-
! First convert any NaN to dummy (NaN comparisons are always FALSE, breaks logic below)
432+
! First convert any NaN to dummy using C library isnan (immune to -ffast-math)
423433
do nz=1, nl-1
424434
do n=1, myDim_nod2D+eDim_nod2D
425-
if (arr(nz,n) /= arr(nz,n)) arr(nz,n) = dummy
435+
if (c_isnan_support(arr(nz,n)) /= 0) arr(nz,n) = dummy
426436
end do
427437
end do
428438

@@ -449,8 +459,8 @@ subroutine extrap_nod3D(arr, partit, mesh)
449459
! loop over local vertices n
450460
do n=1, myDim_nod2D!+eDim_nod2D
451461
! found node n that has to be extrapolated
452-
! Note: NaN comparisons are always FALSE, so also check x/=x
453-
if ( ((work_array(n)>0.99_WP*dummy) .or. (work_array(n)/=work_array(n))) .and. (nlevels_nod2D(n)>nz)) then
462+
! Use C library isnan (immune to -ffast-math)
463+
if ( ((work_array(n)>0.99_WP*dummy) .or. (c_isnan_support(work_array(n))/=0)) .and. (nlevels_nod2D(n)>nz)) then
454464
cnt=0
455465
val=0._WP
456466

0 commit comments

Comments
 (0)