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

hi, this is how we got it working- using the wonderful contribution from @figurski above as the basis.

Worth saying this is for the data on the ECMWF website- our interest in in the forecast products only. e.g. https://data.ecmwf.int/forecasts/20250528/00z/ifs/0p25/oper/

Source code change
The source code changes are in the rd_grib.F file in WPS (in WPS/ungrib/src), so swap that out for the one provided by @figurski and recompile WPS.

Prepare new Vtable
The new Vtable to read the data is also provided by @figurski above- rename that to whatever you want before linking to it and running ungrib.

Install eccodes
You need this to access the grib_set tool which decompresses the grib data first. I found this easiest to do in a conda environment like so:

# Make the conda environment
conda create -n eccodes_env python=3.9
conda activate eccodes_env
conda install -c conda-forge eccodes

Step 5: decompress the grib files
# Activate the conda environment
conda activate eccodes_env

then run the grib_set commands, passing in the grib2 files and setting the desired output names e.g.
View attachment 18205
This example shows the command for 4 IFS grib files from the link above, the output file has ecmwf_ prepended to the beginning of the filename.

The output files above are what you need to link to with the link_grib.csh step in WPS.

Step 6: namelist.wps settings
I set my namelist.wps like this to account for the 14 vertical levels in the IFS and the 4 soil levels.
View attachment 18206

I think that’s all I did- massive thanks to Mariusz/@figurski for providing the solution. Hope my small contribution helps someone!
I am very pleased that my changes to the ungrib.exe software helped solve the problem of reading grib2 data from ECMWF.
Mariusz Figurski
 
Hello everyone,
Since we see that there is a lot of information in this discussion and I personally got a little confused, I would like someone to write exactly what we need to do to run WRF with data from the European model – that is, everything that is needed. Step by step, which works and which data to use
Thank you!
 
Hello everyone,
First of all, many thanks to @figurski for sharing such an interesting workflow. It's the first time I've been able to run WRF with IFS open data (with WRF v.7.1).
Since this data requires modifying the rd_grib2.F file, is this new version compatible with other types of data? I run daily WRF models using GFS as input, and I’d like to make sure I don’t break my current WRF configuration by updating the rd_grib2.F file.
Thanks.
 
Hello,
In the rd_grib2.F file I made an extension for the ECMWF IFS model, other models e.g. GFS, ICON work correctly.

Mariusz Figurski
 
Hello again,
I tried to apply the same workflow to IFS HRES analysis data. However, after converting grib1 files to grib2 files using ecCodes, g2print.exe output shows something strange with deeper soil level.
"Lvl two" column is filled with ****, which unables ungrib to detect SM100289 or ST100289 variables. I tried using 255 in the Vtable, but it didn't work. Any help on that?

Thanks a lot.
1761743654629.png
 
Hi,
Please describe where you're getting your IFS HRES data from. Is it operational data provided by ECMWF? Or open data? Are your files encoded, for example, M1D... and A1S...? This is very important because ECMWF has introduced a new encoding for the soil moisture field in the new grib2 format.
Regards
Mariusz
 
Hi,
Please describe where you're getting your IFS HRES data from. Is it operational data provided by ECMWF? Or open data? Are your files encoded, for example, M1D... and A1S...? This is very important because ECMWF has introduced a new encoding for the soil moisture field in the new grib2 format.
Regards
Mariusz
Hello,
Thanks for your reply. Yes, I'm using operational data from ECMWF. However I don't think my test files were encoded, is there a fast way to check which encoding is being used?
After trying multiple options, I managed to change second level from deeper soil layer with "grib_set -r" for "scaledValueOfSecondFixedSurface=289" variable, and it worked.
 
Hi Ana,
I checked your METGRID.TBL file and it is ok. I inserted it into my system and it worked, everything was calculated without errors. I am sending my Vtable file and rd_grib2.F file for WRF 4.6.1 model just in case. Please check the calculations with these files. It must work. It works in my case.
Mariusz
@islas was this implemented in 4.7.1?
 
Hi Ana,
I checked your METGRID.TBL file and it is ok. I inserted it into my system and it worked, everything was calculated without errors. I am sending my Vtable file and rd_grib2.F file for WRF 4.6.1 model just in case. Please check the calculations with these files. It must work. It works in my case.
Mariusz
Hi Ana,
I checked your METGRID.TBL file and it is ok. I inserted it into my system and it worked, everything was calculated without errors. I am sending my Vtable file and rd_grib2.F file for WRF 4.6.1 model just in case. Please check the calculations with these files. It must work. It works in my case.
Mariusz
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?
 
Diff:
-      integer :: glevel1, glevel2
+      real :: glevel1, glevel2

I also think this section needs to remain integer to fix the issue with Intel OneAPI compilers, otherwise real does a round off
 
Hi,

I've been trying to run it using @figurski’s solution, but unfortunately it doesn’t work for me.
The versión of WRF I'm using is 4.6
  1. I downloaded the data from ECMWF Free & Open Data Portal
  2. I decompressed the GRIB files with ecCodes v2.26.0 using: grib_set -r -s packingType=grid_simple {input_file.grib2} {output_file.grib2}
  3. I copied rd_grib2.F into WPS/ungrib/src/ and also added the corresponding Vtable.
  4. Then I run ungrib.exe, it completes successfully, but I suspect there’s a problem. I get this message:

    INFORM: Rd_grib2 does not know about level code 151.

  5. Later, I generated the met_em files.
  6. Finally, I ran real.exe with mpirun, but it failed.

Using the g2print.exe with the file ifs downloaded I get:
reading from grib file = 20251030000000-0h-oper-fc.grib2
getdrstemplate: DRS Template 42 not defined.
ECMWF
---------------------------------------------------------------------------------------
rec Prod Cat Param Lvl Lvl Lvl Prod Name Time Fcst
num Disc num code one two Templ hour
---------------------------------------------------------------------------------------
getdrstemplate: DRS Template 42 not defined.
ERROR extracting field gf_getfld = 12
getdrstemplate: DRS Template 42 not defined.
ERROR extracting field gf_getfld = 12





Thanks
 

Attachments

  • ungrib.log.txt
    47.3 KB · Views: 0
  • rsl.error.txt.0000
    1.5 KB · Views: 0
Top