@@ -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 ==========================================
6777CONTAINS
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
0 commit comments