Change in soil variables from ECMWF Cycle 49r1

Diff:
--- a/rd_grib2.F
+++ b/rd_grib2.F
@@
-      integer :: glevel1, glevel2
+      real :: glevel1, glevel2
@@
-!              if ( gfld%ipdtmpl(10) .eq. 106 ) then
-              if ( gfld%ipdtmpl(10) .eq. 106 ) then
+!              if ( gfld%ipdtmpl(10) .eq. 106 ) then
+              if (( gfld%ipdtmpl(10) .eq. 106 ) .or.
+     &           ( gfld%ipdtmpl(10) .eq. 151 )) then              !! Added by Prof. Mariusz Figurski, 20250110
                 if ( ( gfld%ipdtmpl(14) .EQ. -1*(2**07-1) ) .AND.
@@
-                   glevel1 = 100. * gfld%ipdtmpl(12)*
-     &                         (10.**(-1.*gfld%ipdtmpl(11)))
-                   glevel2 = 100. * gfld%ipdtmpl(15)*
-     &                         (10.**(-1.*gfld%ipdtmpl(14)))
+                   glevel1 = 100. * gfld%ipdtmpl(12)*
+     &                         (10.**(-1.*gfld%ipdtmpl(11)))
+                   glevel2 = 100. * gfld%ipdtmpl(15)*
+     &                         (10.**(-1.*gfld%ipdtmpl(14)))
+!The following if-block accounts for the 2024 changes to IFS soil fields. They use a local table. 10.01.2024
+!! Added by Prof. Mariusz Figurski, 20250110
+                  if (icenter .eq. 98 .and.
+     &                gfld%discipline .eq. 2 .and.
+     &                (gfld%ipdtmpl(1) .eq. 3 .or.
+     &                gfld%ipdtmpl(1) .eq. 0) .and.
+     &                gfld%ipdtmpl(10).eq. 151) then
+                      glevel1 = gfld%ipdtmpl(12)
+                      glevel2 = gfld%ipdtmpl(15)
+                      if ( gfld%ipdtmpl(12) .eq. 0) then
+                          glevel1 = 0
+                      elseif ( gfld%ipdtmpl(12) .eq. 1) then
+                          glevel1 = 7
+                      elseif ( gfld%ipdtmpl(12) .eq. 2) then
+                          glevel1 = 28
+                      elseif ( gfld%ipdtmpl(12) .eq. 3) then
+                          glevel1 = 100
+                      elseif ( gfld%ipdtmpl(12) .eq. 4) then
+                          glevel1 = 289
+                      endif
+
+                      if ( gfld%ipdtmpl(15) .eq. 0) then
+                          glevel2 = 0
+                      elseif ( gfld%ipdtmpl(15) .eq. 1) then
+                          glevel2 = 7
+                      elseif ( gfld%ipdtmpl(15) .eq. 2) then
+                          glevel2 = 28
+                      elseif ( gfld%ipdtmpl(15) .eq. 3) then
+                          glevel2 = 100
+                      elseif ( gfld%ipdtmpl(15) .eq. 4) then
+                          glevel2 = 289
+                      endif
+
+                      if ( glevel1 .eq. 100. .and.
+     &                     glevel2 .lt. -1.e+9 ) then
+                        glevel2 = 255.
+                      endif
+                  endif
                 end if
-                TMP8LOOP: do j = 1, maxvar
-                  if ((g2code(4,j) .eq. 106) .and.
-     &               (gfld%ipdtmpl(2) .eq. g2code(3,j)) .and.
+                TMP8LOOP: do j = 1, maxvar
+                  if (((g2code(4,j) .eq. 106) .or.
+     &               (g2code(4,j) .eq. 151)) .and.              !! NEW
+     &               (gfld%ipdtmpl(1) .eq. g2code(2,j)) .and.   !! NEW
+     &               (gfld%ipdtmpl(2) .eq. g2code(3,j)) .and.
      &               (glevel1 .eq. level1(j)) .and.
      &               ((glevel2 .eq. level2(j)) .or.
      &                                   (level2(j) .le. -88))) then
                     my_field = namvar(j)
                     exit TMP8LOOP
                   endif
                 enddo TMP8LOOP
@@
-              elseif(gfld%ipdtmpl(10).eq.106.or.
-     &               gfld%ipdtmpl(10).eq.1) then
+              elseif(gfld%ipdtmpl(10).eq.106 .or.
+     &               gfld%ipdtmpl(10).eq.151 .or.               !! NEW
+     &               gfld%ipdtmpl(10).eq.1) then
                  ! Misc near ground/surface levels
                  level=200100.


Suggestions (to make this change safer & future-proof)

Guard equality checks on floating depths
Now that glevel1/glevel2 are real, use tolerance or rounding before comparing to Vtable integers to avoid rare mismatches:
Code:
! replace exact equality with rounded compare
if ( nint(glevel1) == level1(j) .and.
     ( nint(glevel2) == level2(j) .or. level2(j) <= -88 ) ) then


or

Code:
real, parameter :: EPSC = 0.5
if ( abs(glevel1 - level1(j)) < EPSC .and.
     ( abs(glevel2 - level2(j)) < EPSC .or. level2(j) <= -88 ) ) then


Isolate the IFS (center=98) soil-layer mapping
Encapsulate the index→depth mapping in a tiny helper for readability and reuse:
Code:
integer function ifs_soil_cm(idx)
  integer, intent(in) :: idx
  integer, dimension(0:4) :: lut = (/0,7,28,100,289/)
  if (idx < 0 .or. idx > 4) then
     ifs_soil_cm = -2147483647  ! missing
  else
     ifs_soil_cm = lut(idx)
  end if
end function


Then:

Code:
glevel1 = ifs_soil_cm(gfld%ipdtmpl(12))
glevel2 = ifs_soil_cm(gfld%ipdtmpl(15))


Add a debug breadcrumb when 151-path is used
Behind a higher debug_level, log one line so users can verify the new logic is triggered:
Code:
if ( debug_level > 10 ) call mprintf(.true.,DEBUG,
 & "ECMWF soil(151) mapped: [%f,%f] cm", newline=.true., f1=glevel1, f2=glevel2)


Keep the category check consistent in Vtables
You added a match on ipdtmpl(1) (category). Ensure Vtables specify category for these soil entries; otherwise they won’t match. If you need backward-compatibility, guard it:
Code:
logical :: cat_ok
cat_ok = (g2code(2,j) .eq. -99) .or. (gfld%ipdtmpl(1) .eq. g2code(2,j))


Document the new level type
In your developer notes, record that level type 151 is treated like 106 for storage (level=200100. bucket) and that ECMWF local soil-layer indices are mapped to cm depths (0,7,28,100,289).


@figurski what are you thoughts on this above?
@figurski did you have a chance to look at this?
 
Back
Top