1

I have written a code for calculating GDD(Growing Degree Days) using the ERA-5 hourly 2m temperature data in Google Earth Engine. The code uses the max and min temperature of that day to calculate the average temperature which is then subtracted by the base temperature (which is a constant value). The code works fine for a single date data, however when I try to replicate it for a month, I either get a single value for all days or hourly values which is incorrect. I have to carry out this analysis day wise for an entire year, hence I cannot run the code for each day individually. I have tried many methods to replicate the code for a longer time period but none of them are giving me results.

To summarize following are the objectives I wish to achieve with my code:

  1. Replicate the GDD formula for each day in a month
  2. Extract GDD value and export in .csv format with the date and GDD value

How can I achieve these objectives?

// Create a geometry representing an export region.
    var StudyArea = ee.Geometry.Rectangle([76.134,28.7472,76.394, 28.486]);
    Map.addLayer(StudyArea)
    Map.centerObject(StudyArea)
    var roi = ee.Geometry.Rectangle([76.302,28.602,76.317,28.593]);
    Map.addLayer(roi)
    //////////Adding Data///////////////////////////////////////////////////////////
    var image = ee.ImageCollection("ECMWF/ERA5_LAND/HOURLY")
            .filter(ee.Filter.date('2021-01-01','2021-01-02'))
            //.filter(ee.Filter.eq('hour', 17))
            .filterBounds(StudyArea)
            .select('temperature_2m');
            
   ///////////////////////Calculation of GDD///////////////////////////////////////
   var cgdd = function(image){
          var min = image.min()
          var min1 = min.clip(StudyArea)
          Map.addLayer(min1)
          var max = image.max()
          var max1 = max.clip(StudyArea)
          Map.addLayer(max1)
          var a = ee.Image(2)
          var sum = max1.add(min1)
          var avg = sum.divide(a)
          var b = ee.Image(273)
         var celcius= avg.subtract(b)
         Map.addLayer(avg)
         Map.addLayer(celcius)
         var c = ee.Image(17.9)
         var gdd = celcius.subtract(c).rename('GDD');
  //Map.addLayer(gdd)
  return gdd;
  };

 // Test the function on a single image.
 var test = cgdd(image);
 Map.addLayer(test)
 print(test)

// Extracting the values for ROI
var extract = test.reduceRegions({
   collection: roi,
   reducer: ee.Reducer.mean(),
   scale: 10,
});
        
print(extract)   




    

2 Answers 2

3

You need to create a list with the dates and run a server-side mapping (run your calculation for every object in that list). I would than filter the collection taking the date that was passed to the function from the list and advancing it by one day: var image = ic.filterDate(date, ee.Date(date).advance(1, "day"))

Something like this:

  var dates = ee.List.sequence(1, 365).map(function(day){
    return ee.Date('2021-01-01').advance(day, "day")
  })
  print(dates)
  
  var ic =   ee.ImageCollection("ECMWF/ERA5_LAND/HOURLY")
            .filterBounds(StudyArea)
            .select('temperature_2m');
  var res = dates.map(function(date){
          var image = ic.filterDate(date, ee.Date(date).advance(1, "day"))
          var min = image.min()
          var min1 = min.clip(StudyArea)
          var max = image.max()
          var max1 = max.clip(StudyArea)
          var a = ee.Image(2)
          var sum = max1.add(min1)
          var avg = sum.divide(a)
          var b = ee.Image(273)
          var celcius= avg.subtract(b)
          var c = ee.Image(17.9)
          var gdd = celcius.subtract(c).rename('GDD');
          var gdd_reduced = gdd.reduceRegion({
               geometry: roi,
               reducer: ee.Reducer.mean(),
               scale: 10
              }).get("GDD")
        
        return ee.Feature(null).set(ee.Dictionary({"date": date, "GDD": gdd_reduced}))
        }).flatten()
  
  print("calculation result per day", res)
  Export.table.toDrive(ee.FeatureCollection(res))

The link to the edited script is here: https://code.earthengine.google.com/8e95d8eb6e71baca6c26e851744b393b

Alternatively, you could also create the list with starting and ending dates and map the function over that list.

Also, the scale of the data is >10km, no need for you to use 10m scale.

2

The approach of accepted answer produces cgd values that begins with -2.6887802124023423 value instead your only produced value for cgd of -6.731283569335936. For this reason, I used a very different approach for obtaining daily values, by ussing a 24 images list in a function, to find out this apparently anomaly. My code looks as follows.

// Create a geometry representing an export region.
var StudyArea = ee.Geometry.Rectangle([76.134,28.7472,76.394, 28.486]);

Map.centerObject(StudyArea);

var roi = ee.Geometry.Rectangle([76.302,28.602,76.317,28.593]);
//////////Adding Data///////////////////////////////////////////////////////////
var col = ee.ImageCollection("ECMWF/ERA5_LAND/HOURLY")
            .filter(ee.Filter.date('2021-01-01','2022-01-01'))
            .filterBounds(StudyArea)
            .select('temperature_2m');

print('scale', col.first().projection().nominalScale());

Map.addLayer(StudyArea, {}, 'StudyArea');
Map.addLayer(roi, {}, 'roi');

var col_lst = col.toList(col.size());
var len = col.size();

print(col_lst);

var list = ee.List.sequence(0, len.subtract(1), 24);

var new_list = list.map(function(img){

  var start = ee.Number(img).int(); 
  var end = ee.Number(img).add(24).int(); 

  var new_list = ee.List([]);
  var element = ee.List(col_lst.slice(start, end));
  
  new_list = new_list.add(element);
  
  var min = ee.ImageCollection(new_list.flatten()).min();
  var max = ee.ImageCollection(new_list.flatten()).max();
  
  var gdd = ee.Image().expression(
    '(((min + max)/2) - 273) - 17.9', {
      'min': min,
      'max': max,
  }).rename('GDD');

// Extracting the values for ROI
  var value = gdd.reduceRegion(ee.Reducer.mean(), roi, 10000).get('GDD');

  return value;

});

print(new_list);

var allDates = ee.List(col.aggregate_array('system:time_start'));

var allDatesSimple = allDates.map(function(date){
  return ee.Date(date).format().slice(0,10);
  }).distinct();

//print(allDatesSimple);

var paired = allDatesSimple.zip(new_list);

//print (paired);

var myFeatures = ee.FeatureCollection(paired.map(function(el){
  el = ee.List(el); // cast every element of the list

  return ee.Feature(null, {
    'date': ee.String(el.get(0)),
    'gdd value':ee.Number(el.get(1))
  });
}));

//print(myFeatures);

// Export features, specifying corresponding names.
Export.table.toDrive(myFeatures,
"cgd", //my task
"GEE_Folder", //my export folder
"dayly_gdd_values",  //file name
"CSV");

After running both codes in GEE code editor and obtaining both CSV files, I could corroborate that mi code produces expected first value for cgd (first date; red rectangle in below picture). On the other hand, the other values are the same but, strangely, another code doesn't produce the first one. It can be corroborated in below image.

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.