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', });