Scheduled Downtime
On Friday 21 April 2023 @ 5pm MT, this website will be down for maintenance and expected to return online the morning of 24 April 2023 at the latest

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?
 
Top