0

I am trying to do a couple of emissions calculations using functions that reduce imagery over a large number of features. I imported a land cover image collection and reclassified it into 4 classes. Then I mapped the reducer functions over the reclassified land cover images, assigning the resulting values as properties to an empty feature collection that I can then export as a CSV.

I've run this code before and exported successfully. Now, I have a new updated land cover image collection I would like to map over. However, I'm now running into memory issues; specifically: "Error: Execution failed; out of memory. (Error code: 8)". I want to retain the highest accuracy possible, so changing the output resolution isn't an option. Is there something I can change in my code that is causing a memory problem? How can I change it? Would I need to break up my area of interest, or is there another way? Here is my code, also available here: (https://code.earthengine.google.com/dc47ba6c9b8862196b28f633ba3fbaba). Note that it grabs the land cover images from another script (using 'require'), rather than from my assets.

// INPUTS // Load boundary datasets var chiangrai = provinces.filter(ee.Filter.eq('ADM1_EN', 'Chiang Rai')); var chiangmai = provinces.filter(ee.Filter.eq('ADM1_EN', 'Chiang Mai')); var both = provinces.filter(ee.Filter.or(ee.Filter.eq('ADM1_EN', 'Chiang Rai'), ee.Filter.eq('ADM1_EN', 'Chiang Mai'))); // Choose ROI var roi = chiangrai; //Get total area of roi var prov_AreaSqKm = roi.geometry().area().divide(1e6); //print("Province Area (km sq):", prov_AreaSqKm); // Choose Carbon fraction var cf = 0.47; // Choose BA year to test/map var ba_yr = ba_2003.filterBounds(roi); // Choose LC year to test var lc_yr = 2002; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Map.setCenter(99.8, 19.7, 9); var roi_ln = ee.Image().byte().paint({featureCollection:roi,width:2}); var scar_ln = ee.Image().byte().paint({featureCollection:ba_yr,width:1}); // Get pre-processed land cover data var lc_mod = require('users/kaw0055/servir_sea:eia_smokewatch/burnedAreas_RLCMS_annual_simple'); var lc = lc_mod.LCimages; // RLCMS Classes: // *NOTE: Forest Plantation (8) was moved to the category of Forest for emission calculation. // ** Grassland class (9) was eliminated, since IPCC guidelines say that the net emissions is zero over the course of a year. // 1 - forest: 5, 6, 7, 10, 11, 8 // 2 - ag: 1, 3, 4, 12, 13, 14 // 3 - other veg: 15, 18 (grass, shrub, wetland) // 4 - urban: 16 // 5 - other/na: (water, snow, barren) 17, 21, 2 // By Forest type: // 1 -Deciduous forest: 5 // 2- Evergreen forest: 6 // 3- Mangrove: 10 // 4- others: 7, 8, 11, 15 // Remap each image in the LC image collectionby Forest Type var lc_list = lc.toList(lc.size()); // Goes from 2002 to 2022; 21 images var remapLC = lc.map(function(img){ // Define new aggregate classes var fromRLCMS = [5, 6, 10, 7,8,11,15]; // original RLCMS classes var toNewClass = [1, 2, 3, 4,4,4,4]; // Get JUST Forest and Non-Forest Veg var reclass = img.remap(fromRLCMS, toNewClass).clip(roi); return reclass; }); //print("Forest and Veg LC Zones", remapLC); Map.addLayer(remapLC.first().randomVisualizer(), {}, 'Forest and Veg LC Zone 2002'); //.clip(roi) ///////////////////////////////////////////////////////////////////////////////////////////////// // Create Proxy AGB datasets // AGB values: // Deciduous: 59.389 metric tons/ha (FREL) // Evergreen: 123.674 metric tons/ha (FREL) // Mangrove: 109.569 metric tons/ha (FREL) // Other forest: 83.9 metric tons/ha (IPCC, for "Primary tropical Forest") // Deciduous: var d_agb = ee.Image(59.389).toFloat(); // Evergreen: var e_agb = ee.Image(123.674).toFloat(); // Mangrove: var m_agb = ee.Image(109.569).toFloat(); // Other forest: var o_agb = ee.Image(83.9).toFloat(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function for estimating forest area and % forest cover function fstat(img,res,aoi) { // Area of provinces = var Roi = ee.Number(ee.FeatureCollection(roi).geometry().area().divide(1000000)); var f_stat = ee.Number(img.select('remapped').multiply(ee.Image.pixelArea()).reduceRegion({ geometry: aoi.geometry(), reducer: ee.Reducer.sum(), scale: res, maxPixels: 1e18, tileScale: 16}).get('remapped')).divide(1000000); return f_stat; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Function for extracting biomass statistics from AGB datasets function agb_stat(img,res,aoi,SRC) { var AGB_mean = ee.Number(img.clip(aoi).reduceRegion({ geometry: aoi.geometry(), reducer: ee.Reducer.mean(), scale: res, maxPixels: 1e18, tileScale: 16}).get('constant')); var AGB_tot = ee.Number(img.clip(aoi).multiply(ee.Image.pixelArea()).divide(10000).reduceRegion({ geometry: aoi.geometry(), reducer: ee.Reducer.sum(), scale: res, maxPixels: 1e18}).get('constant')); var CO2_tot = AGB_tot.multiply(cf).multiply(44).divide(12); return ee.Dictionary({'AGB_per_ha': AGB_mean, 'AGB_total': AGB_tot, 'Emissions_tons_CO2': CO2_tot}); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Prepare Bunred Area vector data //Make list of BA vector feature collections var list_ba = ee.List([ ba_2003, ba_2004, ba_2005, ba_2006, ba_2007, ba_2008, ba_2009, ba_2010, ba_2011, ba_2012, ba_2013, ba_2014, ba_2015, ba_2016, ba_2017, ba_2018, ba_2019, ba_2020, ba_2021, ba_2022, ba_2023 ]); //Make sure all individual features have a 'year' property (right now, each FC has the year, but not each feature.) // Map over a list equal to the amount of geometries var flat_ba = ee.FeatureCollection(ee.List.sequence(0, list_ba.length().subtract(1), 1).map(function(i){ // Get the FC corresponding to the index i var grabFC = ee.FeatureCollection(list_ba.get(ee.Number(i))); // Map over the collection to assign the year var new_feat = grabFC.map(function(feat){ return feat.set('year', ee.Number(i).add(2003)); }); return new_feat; })).flatten(); //print('Test adding year property to each feature', flat_ba.limit(10)); // TEST var burnVectors = flat_ba.filter(ee.Filter.eq('year', 2008)).filterBounds(roi); //print("burn vectors (test)", burnVectors); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Calculate stats and emissions for all years by LC type var yearlyEmit = remapLC.map(function(img) { var LCyear = img.get('year'); //we need to have set 'year' property to the LC for this to work var BAyear = ee.Number(LCyear).add(1); //to get the BA year, get the LC year and add 1. (LC should be 1 year behind BA) // Filter BA vectors to match the LC image of the previous year var burnVectors = flat_ba.filter(ee.Filter.eq('year', BAyear)).filterBounds(roi); // Apply functions to calculate emissions and stats // Deciduous: var dmsk = img.select('remapped').eq(1); // Deciduous var d_emit = agb_stat(d_agb.updateMask(dmsk), 500, burnVectors, 'Deciduous'); var d_province = fstat(img.updateMask(dmsk),500, roi); var d_burned = fstat(img.clip(burnVectors).updateMask(dmsk),500, burnVectors); // Evergreen: var emsk = img.select('remapped').eq(2); // Evergreen var e_emit = agb_stat(e_agb.updateMask(emsk), 500, burnVectors, 'Evergreen'); var e_province = fstat(img.updateMask(emsk),500, roi); var e_burned = fstat(img.clip(burnVectors).updateMask(emsk),500, burnVectors); // Mangrove: var mmsk = img.select('remapped').eq(3); // Mangrove var m_emit = agb_stat(m_agb.updateMask(mmsk), 500, burnVectors, 'Mangrove'); var m_province = fstat(img.updateMask(mmsk),500, roi); var m_burned = fstat(img.clip(burnVectors).updateMask(mmsk),500, burnVectors); // Other: var omsk = img.select('remapped').eq(4); // Other forest var o_emit = agb_stat(o_agb.updateMask(omsk), 500, burnVectors, 'Other'); var o_province = fstat(img.updateMask(omsk),500, roi); var o_burned = fstat(img.clip(burnVectors).updateMask(omsk),500, burnVectors); // Total burned area (all LC classes) var bas = fstat(img.clip(burnVectors),500, burnVectors); //Return the info: var f = ee.Feature(null, { 'year': BAyear, 'total_burnedArea': bas, // D 'D_Forest_Area': d_province, 'D_Forest_Area_burned': d_burned, 'D_AGB_per_ha': d_emit.get('AGB_per_ha'), 'D_AGB_total': d_emit.get('AGB_total'), 'D_Emissions_tons_CO2': d_emit.get('Emissions_tons_CO2'), 'D_Emit_per_SqKm': ee.Number(d_emit.get('Emissions_tons_CO2')).divide(prov_AreaSqKm), // E 'E_Forest_Area': e_province, 'E_Forest_Area_burned': e_burned, 'E_AGB_per_ha': e_emit.get('AGB_per_ha'), 'E_AGB_total': e_emit.get('AGB_total'), 'E_Emissions_tons_CO2': e_emit.get('Emissions_tons_CO2'), 'E_Emit_per_SqKm': ee.Number(e_emit.get('Emissions_tons_CO2')).divide(prov_AreaSqKm), // M 'M_Forest_Area': m_province, 'M_Forest_Area_burned': m_burned, 'M_AGB_per_ha': m_emit.get('AGB_per_ha'), 'M_AGB_total': m_emit.get('AGB_total'), 'M_Emissions_tons_CO2': m_emit.get('Emissions_tons_CO2'), 'M_Emit_per_SqKm': ee.Number(m_emit.get('Emissions_tons_CO2')).divide(prov_AreaSqKm), // O 'O_Forest_Area': o_province, 'O_Forest_Area_burned': o_burned, 'O_AGB_per_ha': o_emit.get('AGB_per_ha'), 'O_AGB_total': o_emit.get('AGB_total'), 'O_Emissions_tons_CO2': o_emit.get('Emissions_tons_CO2'), 'O_Emit_per_SqKm': ee.Number(o_emit.get('Emissions_tons_CO2')).divide(prov_AreaSqKm) }); return f; });//.flatten(); //Only use 'flatten' if returning the very flattened list (2) // Print to see output. This is memory heavy, so it may result in 'user memory limit exceeded.' //print("Emissions", yearlyEmit); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // EXPORT TO DRIVE Export.table.toDrive({ collection: yearlyEmit, description: 'Annual_Emissions_allYears_CR_V6correction1', // Change based on province folder: 'Stats_Corrected_rlcmsV6', fileNamePrefix: 'Annual_Emissions_allYears_CR_V6correction1', // change based on province fileFormat: 'CSV', }); 

1 Answer 1

1

Not guaranteed to solve the problem, but might help move things in the right direction:

  1. avoid using .clip(feature) and instead try to use .updateMask(binary image of AOI). Assuming your AOI doesn't change as you're mapping over your image collection, a mask can be generated on the fly using var mask=ee.Image(1).clip(aoi). Consequently the code only needs to clip once rather than for every image which is very memory intensive.

  2. You haven't set tilescale for your agb_tot reducer

  3. If GEE still runs out of memory after all that then consider breaking the code up into steps where you can output the intermediate steps to an asset which can then be called.

There's also other tips and tricks that might be useful here: https://developers.google.com/earth-engine/guides/best_practices

Good luck!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.