參考 https://www.ecmwf.int/assets/elearning/eccodes/eccodes2/story_html5.html
https://confluence.ecmwf.int/display/OPTR/ecCodes%3A+GRIB+data+decoding+and+encoding+software+2018
基本解碼流程
1. 指定打開方式(“讀”或“寫”),打開一個或多個GRIB文件;
2. 根據不同加載方式,加載一個或多個GRIB messages到內存:
有兩種函數:codes_grib_new_from_file 和 codes_new_from_index。調用后會返回一個唯一的identifier,用於對已加載的GRIB messages進行操縱。
3. 調用codes_get函數對已加載的GRIB messages進行解碼; (可以解碼需要的數據)
4. 釋放已經加載的GRIB messages:
codes_release
5. 關閉打開的 GRIB 文件.
此外,eccodes還有以下功能:
eccodes的主要目的是提供一個高水平的方法,用以從一個加載的GRIB messages對象去提取和計算出更多額外的信息:
· 返回平均,最小,最大,特定的經緯度等的關鍵字;
· 計算經緯度和值:codes_grib_get_data;
· 提取值的子例程:
codes_grib_find_nearest 去提取出距離給定地理點最近位置的點的值
codes_get_element 從列表中提取值
· 基於索引訪問(indexed access)的子例程:這些是隨機訪問的方法,通常比順序訪問更快。
-----------------------------------------------------------------
順序訪問方式:
大致思路:
-> codes_open_file
-> codes_grib_new_from_file -> codes_get -> codes_release
…
-> codes_grib_new_from_file -> codes_get-> codes_release
-> codes_close_file
示例代碼:
索引訪問方式(通常比順序訪問快):
注意,eccodes中的index文件(后綴為.idx)與GrADS中后綴為.idx的文件不能通用!
大致思路:
-> codes_index_create(從grib文件創建index) 或 codes_index_read(讀取已有index)
-> codes_index_select 選取鍵值
-> codes_new_from_index -> codes_get -> codes_release
…
-> codes_new_from_index -> codes_get -> codes_release
-> codes_index_release
示例代碼:
-----------------------------------------------------------------
一些ecCodes命令行工具:
參考 https://confluence.ecmwf.int/display/GRIB/GRIB+tools
grib_filter 篩選
grib_filter [options] rules_file grib_file gribfile ...
options
-f 強制執行
-o 輸出index文件。如果沒指定輸出文件,那么輸出GRIB文件寫在filtered.out
-M 關閉多場支持。關閉在單GRIB message中多要素場的支持。
-V 版本
-g 復制GTS頭
-G 兼容GRIBEX模式
-T T|B message類型。T -> GTS, B -> BUFR, 輸入文件類型根據messgae解釋
-7 當message長度錯誤時候不報錯
-v verbose模式
例子
1. grib_filter程序對於輸入文件中的所有GRIB message順序處理,對其中各項均應用rules。輸入消息可以使用“write”聲明寫入輸出文件。write語句可以parameterised以便輸出發送到多個文件,根據鍵值定義輸出文件的名字。如果我們寫一個rules_file包含唯一的聲明:
write "../data/split/[centre]_[dataDate]_[dataType]_[levelType].grib[edition]";
將這個rules_file應用到 "../data/tigge_pf_ecmwf.grib2"文件將會在 ../data/split 目錄下得到幾個文件,包含根據鍵值分割的字段
> grib_filter rules_file ../data/tigge_pf_ecmwf.grib2 > ls ../data/split ecmf_20060619_pf_sfc.grib2 ecmf_20060630_pf_sfc.grib2 ecmf_20070122_pf_pl.grib2 ecmf_20070122_pf_pt.grib2 ecmf_20070122_pf_pv.grib2 ecmf_20070122_pf_sfc.grib2
2. 通過明確指示冒號后所需的類型,也可以以不同的格式獲取文件名中的鍵值。
- :s 整型
- :d 雙精度
- :s 字符串
以下語句的工作方式與前一個示例略有不同,包括輸出文件名中的center和dataType的整數值。
write "../data/split/[centre:i]_[dataDate]_[dataType:i]_[levelType].grib[edition]";
再次運行相同的命令,我們獲得了不同的文件列表。
> grib_filter rules_file ../data/tigge_pf_ecmwf.grib2 > ls ../data/split 98_20060619_4_sfc.grib2 98_20060630_4_sfc.grib2 98_20070122_4_pl.grib2 98_20070122_4_pt.grib2 98_20070122_4_pv.grib2 98_20070122_4_sfc.grib2
3. grib_filter語法中允許使用其他語句:
- 以#開頭的注釋
- print "string to print also with key values like in the file name"
- transient keyname1 = keyname2;
- set keyname = keyvalue;
- 定義(keyname)以檢查message中是否定義了關鍵字
- 缺少(keyname)來檢查關鍵字的值是否設置為MISSING
- 要將鍵值設置為MISSING,請使用“set key = MISSING;” (見示例)
- if(condition){block of rules} else {block of rules}
條件可以使用==,!=,並使用||和&& 連接單個塊條件
語句可以是任何有效語句也是另一個嵌套條件 - 您也可以使用“assert(condition)”進行斷言。如果condition為false,它將中止filter。
例如:assert(edition == 1);
grib_filter規則的一個復雜示例如下是在GRIB版本1文件中更改溫度。
# This filter should only be run on GRIB edition 1; abort otherwise assert( edition == 1 ); # Temperature if ( level == 850 && indicatorOfParameter == 11 ) { print "found indicatorOfParameter=[indicatorOfParameter] level=[level] date=[dataDate]"; transient oldtype = type ; set identificationOfOriginatingGeneratingSubCentre=98; set gribTablesVersionNo = 128; set indicatorOfParameter = 130; set localDefinitionNumber=1; set marsClass="od"; set marsStream="kwbc"; # Negatively/Positively Perturbed Forecast if ( oldtype == 2 || oldtype == 3 ) { set marsType="pf"; set experimentVersionNumber="4001"; } # Control Forecast if ( oldtype == 1 ) { set marsType="cf"; set experimentVersionNumber="0001"; } set numberOfForecastsInEnsemble=11; write; print "indicatorOfParameter=[indicatorOfParameter] level=[level] date=[dataDate]"; print; }
4. 以下是將鍵與字符串進行比較的IF語句示例。注意,必須對字符串使用“is”關鍵字而不是“==”。並且,為了否定,您需要在整個條件之前添加“!”:
# Select Geopotential Height messages which are not on a Reduced Gaussian Grid if (shortName is "gh" && !(gridType is "reduced_gg" )) { set step = 72; }
5. switch語句是if語句的替代版本。其語法如下:
switch (key1) { case val1: # block of rules; case val2: # block of rules; default: # [ block of rules ] }
作為switch語句的參數給出的鍵的每個值都與case語句中指定的值匹配。如果存在匹配,則執行與匹配的case語句對應的塊或規則。否則,執行默認情況。如果case聲明沒有包含所有可能性,則默認情況是強制性的。“〜”運算符可用於匹配“任何”。
以下示例顯示了switch語句的用法:
processing paramId=[paramId] [shortName] [stepType] switch (shortName) { case "tp": set stepType="accum"; case "10u" : set typeOfLevel="surface"; default: }
grib_get 獲取數據
Get values of some keys from a GRIB file. It is similar to grib_ls, but fails returning an error code when an error occurs (e.g. key not found).
grib_get [options] grib_file grib_file ...
options
-f 強制執行
-p key[:{s/d/i}],key[:{s/d/i}],...
聲明打印的關鍵字。可以要求字符串型(keys:s),雙精度(keys:d)或者整型(keys:i)的關鍵字。默認類型是字符串
-F format C樣式格式的浮點值。
-l Latitude,Longitude[,MODE,file]
接近的緯度/經度點的值。允許的MODE有:
- 4 默認 (打印距離點最近四個點的值)
- 1 打印距離點最近的值
- file 文件被用於mask。打印距離mask值>=0.5時候,最近的點的值
-P key[:{s/d/i}],key[:{s/d/i}],... As -p adding the declared keys to the default list.
-w key[:{s/d/i}]{=/!=}value,key[:{s/d/i }]{=/!=}value,...
只有滿足所有設置鍵/值約束的GRIB message才會被處理。一個有效的鍵值約束類似於key=value或者key!=value。對於任意一個關鍵字,可以是字符串型(keys:s),雙精度型(keys:d)或者一個長整型(keys:l)。默認類型為字符串型。在值中同樣可以使用上斜杠“/"去指定一個 或 條件。(即一個邏輯析取)
-n namespace 打印所有屬於namespace的關鍵字。一些有用的namespace是:“time”,“parameter”,“geography”和“statistics”。
-s key[:{s/d/i}]=value,key[:{s/d/i}]=value,...
需要設置的關鍵字數值。對於每一個關鍵字,可以定義為字符串(key:s)、雙精度(key:d)或者整型(key:i)這些類型。默認情況是設置為native type
-V Version.
-W width 輸出行的最小寬度。默認是10
-M 關閉多場支持。關閉在單GRIB message中多要素場的支持。
-g 復制GTS頭
-G 兼容GRIBEX模式
-T T|B message類型。T -> GTS, B -> BUFR, 輸入文件類型根據messgae解釋
-7 當message長度錯誤時候不報錯
-i index 打印對應於給定index的值。注意這個index是從零開始的,所以第一個值是在索引0。
例子
1. 如果關鍵字沒有找到,grib_get 失敗
> grib_get -p gribname ../data/tigge_pf_ecmwf.grib2
2. 為了獲取文件中第一個GRIB message中step的值
> grib_get -w count=1 -p step ../data/tigge_pf_ecmwf.grib2
grib_index_build 創建索引
grib_index_build [options] grib_file grib_file ...
options
-f 強制執行
-o 輸出index文件。如果沒指定輸出文件,那么輸出文件寫成“gribidx”
-k keys1,keys2... 給定需要索引的關鍵字。默認輸入文件將用MARS關鍵字索引。可以要求字符串型(keys:s),雙精度(keys:d)或者整型(keys:i)的關鍵字。
-V 版本號
-M 多變量場支持關閉。關閉單獨GRIB message中多變量場的支持
-N 不要壓縮索引。默認情況下,索引移除了只有一個值的關鍵字,用以壓縮。
例子
1. 默認情況下,grib_index將會用MARS關鍵字進行索引
> grib_index_build ../data/reduced*.grib1 ../data/regular*.grib1 ../data/reduced*.grib2
2. 如果要給索引設置默認的關鍵字,使用-k選項。
> grib_index_build ../data/reduced*.grib1 ../data/regular*.grib1 ../data/reduced*.grib2
注意!因為並非所有keys都會被保存在grib文件中,一些keys是通過其它keys計算得到的。而在利用grib_index_build命令時候,默認只存儲部分keys,如果需要在index中保存額外的keys,還需要打開-N選項:
$ grib_index_build -k time,name,level,longitude,latitude,month,day,year,shortName -N *.grb -o outindex --- grib_index_build: processing t.20180831.grb --- grib_index_build: keys included in the index file outindex: --- time, name, level, longitude, latitude, month, day, year, shortName --- time = { 0, 600, 1200, 1800 } --- name = { Temperature } --- level = { 1000, 975, 950, 925, 900, 875, 850, 825, 800, 775, 750, 700, 650, 600, 550, 500, 450, 400, 350, 300, 250, 225, 200, 175, 150, 125, 100, 70 } --- longitude = { undef } --- latitude = { undef } --- month = { 8 } --- day = { 31 } --- year = { 2018 } --- shortName = { t } --- 112 messages indexed
如果不加-N選項,那么一些用戶定義的keys就沒有保存到index文件中
$ grib_index_build -k time,name,level,longitude,latitude,month,day,year,shortName *.grb -o outindex --- grib_index_build: processing t.20180831.grb --- grib_index_build: keys included in the index file outindex: --- time, level --- time = { 0, 600, 1200, 1800 } --- level = { 1000, 975, 950, 925, 900, 875, 850, 825, 800, 775, 750, 700, 650, 600, 550, 500, 450, 400, 350, 300, 250, 225, 200, 175, 150, 125, 100, 70 } --- 112 messages indexed
如上圖,一些變量就沒有保存到index文件中。
grib_dump 顯示一個索引文件的內容
grib_dump [options] grib_file grib_file ...
options
-O Octet(八進制?)模式。WMO文檔形式的輸出
-D 調試模式
-d 僅在C模式下可用。打印所有數據值。
-C C編碼模式。一個C編碼程序生成的GRIB message被輸出
-t 打印類型信息
-H 以十六位格式打印八位內容
-a 打印別名(aliases)
-w key[:{s/d/l}]{=/!=}value,key[:{s/d/l}]{=/!=}value,...
只有滿足所有設置鍵/值約束的GRIB message才會被處理。一個有效的鍵值約束類似於key=value或者key!=value。對於任意一個關鍵字,可以是字符串型(keys:s),雙精度型(keys:d)或者一個長整型(keys:l)。默認類型為字符串型。
-s key[:{s/d/i}]=value,key[:{s/d/i}]=value,...
需要設置的關鍵字數值。對於每一個關鍵字,可以定義為字符串(key:s)、雙精度(key:d)或者整型(key:i)這些類型。默認情況是設置為native type
-M 關閉多場支持。關閉在單GRIB message中多要素場的支持。
-T T|B|A message類型。T -> GTS, B -> BUFR, A -> Any (Experimental). 輸入文件類型根據messgae解釋
-7 當message長度錯誤時候不報錯
-V 版本
-X offset 輸入文件offset量(單位字節)。處理輸入文件將從“offset”開始。
例子
1. 用hexadecimal octet的方式(-H),用WMO文檔的形式輸出。
> grib_dump -OH ../data/reduced_gaussian_model_level.grib1
2. 添加關鍵字別名和類型信息
> grib_dump -OtaH ../data/reduced_gaussian_model_level.grib
3. 獲得一個grib文件中所有的關鍵字名稱(包括已經計算得到的關鍵字)
> grib_dump -D ../data/regular_latlon_surface.grib1
grib_copy 復制GRIB文件的內容打印一些鍵的值
grib_copy [options] grib_file grib_file ... output_grib_file
options
-f 強制執行
-r 重新包裝數據。有時在設置一些涉及打包算法屬性的鍵之后,需要重新打包數據。執行此重新打包時,設置此-r選項
-p key[:{s/d/l}],key[:{s/d/l}],...
Declaration of keys to print. For each key a string (key:s) or a double (key:d) or a long (key:l) type can be requested. Default type is string.
-P key[:{s/d/l}],key[:{s/d/l}],...
As -p adding the declared keys to the default list.
-w key[:{s/d/l}]{=/!=}value,key[:{s/d/l}]=value,...
只有滿足所有設置鍵/值約束的GRIB message才會被處理。一個有效的鍵值約束類似於key=value或者key!=value。對於任意一個關鍵字,可以是字符串型(keys:s),雙精度型(keys:d)或者一個長整型(keys:l)。默認類型為字符串型。
Where clause. Only grib messages matching the key/value constraints are copied to the output_grib_file.
A valid constraint is of type key=value or key!=value.
For each key a string (key:s) or a double (key:d) or a long (key:l) type can be defined. Default type is string.
In the value you can also use the forward-slash character "/" to specify an OR condition (i.e. a logical disjunction)
-B order by directive
Order by. The output will be ordered according to the "order by" directive. For example: "step:i asc, centre desc" (step numeric ascending and centre descending)
-V 版本號
-W width
Minimum width of each column in output. Default is 10.
-M 多變量場支持關閉。關閉單獨GRIB message中多變量場的支持 Multi-field support off. Turn off support for multiple fields in single grib message.
-T T | B
Message type. T->GTS, B->BUFR. The input file is interpreted according to the message type.
-g
Copy GTS header.
-G
GRIBEX compatibility mode.
-7
Does not fail when the message has wrong length
-v
Verbose.
例子
1. To copy only the pressure levels from a file
> grib_copy -w levtype=pl ../data/tigge_pf_ecmwf.grib2 out.grib
2.To copy only the fields that are not on pressure levels from a file
> grib_copy -w levtype!=pl ../data/tigge_pf_ecmwf.grib2 out.grib
3.To copy only the first three fields from a file
> grib_copy -w count=
1
/
2
/
3
../data/tigge_pf_ecmwf.grib2 out.grib
4. A grib_file with multi field messages can be converted in single field messages with a simple grib_copy
> grib_copy multi.grib simple.grib
5. Use the square brackets to insert the value of a key in the name of the output file (This is a good way to split a large GRIB file)
Note: we need to quote the name of the output so the shell does not interpret the square brackets
> grib_copy in.grib
'out_[shortName].grib'
6. To copy fields whose typeOfLevel is either "surface" or "meanSea"
> grib_copy -w typeOfLevel=surface/meanSea orig.grib out.grib
7. To copy selected fields and apply sorting (sorted by level in ascending order)
Note: we need to specify the ":i
" to get a numerical sort. By default values are sorted as strings so a level of 100 would come before 20!
> grib_copy -w typeOfLevel=heightAboveGround -B
"level:i asc"
tigge_af_ecmwf.grib2 out.grib
-----------------------------------------------------------------
部分函數參考:
codes_get (msgid, key, value, status)
Get the value for a key from a grib message
從grib message中獲取鍵值。
輸入一個msgid和key,返回關鍵字的值。 在某些情況下,值可以是數組而不是標量。 作為數組鍵的示例,我們分別具有“values”,“pl”,“pv”數據值,簡化網格中每個緯度的點數列表以及垂直級別列表。 在這些情況下,值數組必須由調用者分配,並且可以使用codes_get_size獲取其所需的維度。值可以是整數(4),實數(4),實數(8),字符。 雖然每個鍵都有自己的本機類型,但是可以檢索整數類型的鍵(使用codes_get)作為real(4),real(8)或character。 盡可能提供類似的轉換。 對於任何其他類型,非法轉換對整數和字符都是真實的。msgid引用內存中加載的消息。
[in] msgid id of the message loaded in memory
[in] key key name
[out] value value can be a scalar or array of integer(4),real(4),real(8),character. Arrays must support the allocatable attribute.
[out] status CODES_SUCCESS if OK, integer value on error
codes_get_element (msgid, key, kindex, value, status)
Get a value of specified index from an array key
從一個關鍵字數組中獲取給定索引的值。給定 message id、關鍵字名稱、和索引,得到相應的值。 索引是從0開始的(即第一個元素的索引是0,第二個元素索引為1,依此類推)。 如果索引參數是數組,則返回與索引數組對應的所有值。
[in] id 加載到內存的ID。 ID of the message loaded in memory
[in] key 關鍵字名稱 key name
[in] index 可以是一個標量或者數組。單精度整型 index can be a scalar or array of integer(4)
[out] value 可以是一個標量或者數組。單精度整型,單精度或雙精度實型數組。 value can be a scalar or array of integer(4),real(4),real(8)
[out] status CODES_SUCCESS if OK, integer value on error
codes_get_error_string (error, error_message, status)
Get the error message given an error code.
輸入錯誤碼,返回錯誤消息
error 錯誤碼
error messages 錯誤消息
status 如果成功返回CODES_SUCCESS,錯誤返回整數值
codes_get_message_size (msgid, nbytes, status)
Get the size of a coded message
得到編碼message的大小
codes_get_size (msgid, key, size, status)
Get the size of an array key
得到鍵數組的大小
codes_grib_find_nearest_single (gribid, is_lsm, inlat, inlon, outlat, outlon, value, distance, kindex, status)
獲得距給定經緯度點最近的點的位置及值。
輸入gribid,邏輯值
返回最近的一個點 (或最近的四個點) 的值,基於零的索引 (可在 code_get_element中使用) ,及其與給定點的距離。使用以下公式: radius * acos( sin(lat1)*sin(lat2)+cos(lat1)*cos(lat2)*cos(lon1-lon2) ).
如果is_lsm flag是. true。輸入場網格被認為是land sea mask, 返回最近的陸地點。
在四個相鄰點中, 最近的陸地點是:
land sea mask值 > = 0.5 的最近點
如果這四個相鄰點的land sea mask 值都 < 0.5, 則在沒有任何其他條件的情況下最近的。
可以提供經緯度的數組 (real(8), 以便通過一個調用來查找數組中列出的所有 lat/lon 點的值、索引和距離。
如果提供了單個緯度/經度點, 並且outlat, outlon, value, 距離, 索引被定義為具有四個元素的數組, 返回四個最近點的 lat/lon 坐標和value、距離和索引。
如果出現錯誤, 如果未給出狀態參數 (可選), 程序將退出並顯示錯誤消息。否則, 可以使用codes_get_error_string 收集錯誤消息。
[in] gribid 加載到內存中的值
[in] is_lsm 邏輯值,如果要求最近的點,則為.true.,否則為.false.
[in] inlat 點的緯度
[in] inlon 點的經度
[out] outlat 最近點的緯度
[out] outlon 最近點的經度
[out] distance 給點和最近點的距離
[out] kindex 基於0的索引
[out] value 最近點的值
[out] status 狀態 CODES_SUCCESS if OK, integer value on error
codes_grib_get_data (gribid, lats, lons, values, status)
Get latitude/longitude and data values.
得到經緯度和數據值
codes_index_add_file (indexid, filename, status)
Add a file to an index.
將一個文件加入到索引文件中
codes_index_create (indexid, filename, keys, status)
to create the index of the content of a file 創建文件內容索引
indexid 新建索引文件的id
filename 被索引messages的文件的名稱
keys 用逗號分隔的關鍵字關鍵字的類型可以在后面追加(:l,表示長整型,:i短整型,:d雙精度,:s字符串)如果沒有顯式聲明類型,那么假設類型默認。
status 如果成功返回CODES_SUCCESS,錯誤返回整數值
codes_index_get (indexid, key, values, status)
Get the distinct values of the key in argument contained in the index.
得到包含在索引中聲明的特定關鍵字的特定值
codes_index_get_size (indexid, key, size, status)
to get the dimension of a key in the index
得到索引的關鍵字的維數
codes_index_read (indexid, filename, status)
Load an index file previously created with codes_index_write.
加載一個索引文件(該索引文件之前已由codes_index_write命令創建)
codes_index_release (indexid, status)
釋放index
indexid id of an index created from a file.
status CODES_SUCCESS if OK, integer value on erro
codes_index_select (indexid, key, value, status)
Select the message subset with key==value.
用key==valued選取消息子集
codes_index_write (indexid, filename, status)
Saves an index to a file for later reuse.
保存索引文件便於以后使用
codes_new_from_file (ifile, msgid, product_kind, status)
從該文件中加載一個message 到內存。輸入文件id、數據類型,並返回message id
可以通過msgid直接訪問該message,msgid一直可用,調用codes_release函數之前。
codes_new_from_index (indexid, msgid, status)
在選定key值后,從一個index創建一個新的handle。
在調用這個函數前,index的所有keys都比必須確定。 連續調用這個函數 將返回index keys中 所有符合定義的handles。當沒有更多的可用處理從索引中返回一個空指針變量,並且err變量值設置為CODES_END_OF_INDEX。
codes_new_from_message(msgid, message, status)
Create a new message in memory from an integer or character array containting the coded message. 在包含編碼消息的整型或字符型數組 中在內存中創建新消息
codes_grib_new_from_samples (gribid, samplename, status)
Create a new valid gribid from a GRIB sample contained in a samples directory pointed by the environment variable ECCODES_SAMPLES_PATH.
在ECCODES_SAMPLES_PATH環境變量指定的樣本路徑中的GRIB樣本,創建新的可用的gribid.(編碼時候用)
gribid id of the grib loaded in memory 輸出量,加載到內存中的message的id
samplename name of the sample to be used 輸入量,樣本名稱
status CODES_SUCCESS if OK, integer value on error 輸出量,是否成功
codes_open_file (ifile, filename, mode, status)
Open a file according to a mode. 根據模式打開文件
ifile id of the opened file to be used in all the file functions.
filename name of the file to be open
mode open mode can be 'r' (read only), 'w' (write only) or 'a' (append)
status 如果成功返回CODES_SUCCESS,錯誤返回整數值
codes_read_bytes (ifile, buffer, nbytes, status)
Reads nbytes bytes into the buffer from a file opened with codes_open_file
codes_read_from_file (ifile, buffer, nbytes, status)
Reads a message in the buffer array from the file opened with codes_open_file.
codes_release (msgid, status)
Free the memory for the message referred as msgid.
codes_set (msgid, key, value, status)
Set the value for a key in a message.
在message中設置鍵值
codes_write_bytes_int4 (ifile, buffer, nbytes, status)
Write nbytes bytes from the buffer in a file opened with codes_open_file.
注 :ERROR CODES列表參考 http://download.ecmwf.int/test-data/eccodes/html/group__errors.html
編譯示例
引用時候用-leccodes_f90這個庫
假設存放eccodes的頭文件和庫文件路徑的環境變量分別是ECCODES_INCLUDE和ECCODES_LIB
jlz@dell:~/test$ ifort test.f90 -I$ECCODES_INCLUDE -L$ECCODES_LIB -leccodes_f90 -o test.out