Skip to content

Commit

Permalink
Merge pull request #191 from wri/feature/arg
Browse files Browse the repository at this point in the history
Add analysis for Argentina, mainly overlapping with detailed WDPA categories
  • Loading branch information
danscales authored Oct 17, 2023
2 parents 607660c + 6ea6c01 commit f0f0a86
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 81 deletions.
4 changes: 4 additions & 0 deletions src/main/resources/raster-catalog-pro.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
"name":"wdpa_protected_areas",
"source_uri":"s3://gfw-data-lake/wdpa_protected_areas/v202208/raster/epsg-4326/{grid_size}/{row_count}/iucn_cat/gdal-geotiff/{tile_id}.tif"
},
{
"name":"detailed_wdpa_protected_areas",
"source_uri":"s3://gfw-data-lake/wdpa_protected_areas/v202308/raster/epsg-4326/{grid_size}/{row_count}/detailed_iucn_cat/gdal-geotiff/{tile_id}.tif"
},
{
"name":"gfw_oil_gas",
"source_uri":"s3://gfw-data-lake/gfw_oil_gas/v20221024/raster/epsg-4326/{grid_size}/{row_count}/is/gdal-geotiff/{tile_id}.tif"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.globalforestwatch.layers

import org.globalforestwatch.grids.GridTile

case class DetailedProtectedAreas(gridTile: GridTile, kwargs: Map[String, Any]) extends StringLayer with OptionalILayer {
val datasetName = "detailed_wdpa_protected_areas"
val uri: String = uriForGrid(gridTile, kwargs)

def lookup(value: Int): String = value match {
case 1 => "Category Ia"
case 2 => "Category Ib"
case 3 => "Category II"
case 4 => "Category III"
case 5 => "Category IV"
case 6 => "Category V"
case 7 => "Category VI"
case 8 => "UNESCO-MAB Biosphere Reserve"
case 9 => "World Heritage Site (natural or mixed)"
case 10 => "Ramsar Site, Wetland of International Importance"
case 11 => "Not Reported"
case 12 => "Not Applicable"
case 13 => "Not Assigned"
case _ => ""
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ object ForestChangeDiagnosticDF extends SummaryDF {
"protected_areas_area", // protectedAreasArea
"peat_area", // peatlandsArea
"arg_otbn_area", // argOTBNArea
"protected_areas_by_category_area", // protectedAreasByCategory
"landmark_by_category_area", // landmarkByCategory
"brazil_biomes", // braBiomesArea
"idn_legal_area", // idnForestAreaArea
"sea_landcover_area", // seAsiaLandCoverArea
Expand Down Expand Up @@ -149,4 +151,4 @@ object ForestChangeDiagnosticDF extends SummaryDF {
"plantation_in_protected_areas_area" //plantationInProtectedAreasArea
)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ case class ForestChangeDiagnosticData(
peat_area: ForestChangeDiagnosticDataDouble,
/** OTBN category area */
arg_otbn_area: ForestChangeDiagnosticDataDoubleCategory,
/** Detailed WDPA category area */
protected_areas_by_category_area: ForestChangeDiagnosticDataDoubleCategory,
/** Indigenous area (from Landmark dataset) */
landmark_by_category_area: ForestChangeDiagnosticDataDoubleCategory,
brazil_biomes: ForestChangeDiagnosticDataDoubleCategory,
/** IDN Forest Area */
idn_legal_area: ForestChangeDiagnosticDataDoubleCategory,
Expand Down Expand Up @@ -135,6 +139,8 @@ case class ForestChangeDiagnosticData(
protected_areas_area.merge(other.protected_areas_area),
peat_area.merge(other.peat_area),
arg_otbn_area.merge(other.arg_otbn_area),
protected_areas_by_category_area.merge(other.protected_areas_by_category_area),
landmark_by_category_area.merge(other.landmark_by_category_area),
brazil_biomes.merge(other.brazil_biomes),
idn_legal_area.merge(other.idn_legal_area),
sea_landcover_area.merge(other.sea_landcover_area),
Expand Down Expand Up @@ -310,6 +316,8 @@ object ForestChangeDiagnosticData {
ForestChangeDiagnosticDataDoubleCategory.empty,
ForestChangeDiagnosticDataDoubleCategory.empty,
ForestChangeDiagnosticDataDoubleCategory.empty,
ForestChangeDiagnosticDataDoubleCategory.empty,
ForestChangeDiagnosticDataDoubleCategory.empty,
ForestChangeDiagnosticDataDouble.empty,
ForestChangeDiagnosticDataBoolean.empty,
ForestChangeDiagnosticDataBoolean.empty,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ case class ForestChangeDiagnosticGridSources(gridTile: GridTile, kwargs: Map[Str
val isPrimaryForest: PrimaryForest = PrimaryForest(gridTile, kwargs)
val isPeatlands: Peatlands = Peatlands(gridTile, kwargs)
val isIntactForestLandscapes2000: IntactForestLandscapes2000 = IntactForestLandscapes2000(gridTile, kwargs)
val protectedAreas: ProtectedAreas = ProtectedAreas(gridTile, kwargs)
val seAsiaLandCover: SEAsiaLandCover = SEAsiaLandCover(gridTile, kwargs)
val idnLandCover: IndonesiaLandCover = IndonesiaLandCover(gridTile, kwargs)
val isSoyPlantedArea: SoyPlantedAreas = SoyPlantedAreas(gridTile, kwargs)
Expand All @@ -28,65 +27,19 @@ case class ForestChangeDiagnosticGridSources(gridTile: GridTile, kwargs: Map[Str
val isPlantation: PlantedForestsBool = PlantedForestsBool(gridTile, kwargs)
val gfwProCoverage: GFWProCoverage = GFWProCoverage(gridTile, kwargs)
val argOTBN: ArgOTBN = ArgOTBN(gridTile, kwargs)
val protectedAreasByCategory: DetailedProtectedAreas = DetailedProtectedAreas(gridTile, kwargs)
val landmark: Landmark = Landmark(gridTile, kwargs)


def readWindow(
windowKey: SpatialKey,
windowLayout: LayoutDefinition
): Either[Throwable, Raster[ForestChangeDiagnosticTile]] = {

for {
// Failure for any of these reads will result in function returning Left[Throwable]
// These are effectively required fields without which we can't make sense of the analysis
lossTile <- Either
.catchNonFatal(treeCoverLoss.fetchWindow(windowKey, windowLayout))
.right
tcd2000Tile <- Either
.catchNonFatal(
treeCoverDensity2000.fetchWindow(windowKey, windowLayout)
)
.right

} yield {
// Failure for these will be converted to optional result and propagated with ForestChangeDiagnosticTile
val isPrimaryForestTile = isPrimaryForest.fetchWindow(windowKey, windowLayout)
val isPeatlandsTile = isPeatlands.fetchWindow(windowKey, windowLayout)
val isIntactForestLandscapes2000Tile =
isIntactForestLandscapes2000.fetchWindow(windowKey, windowLayout)
val wdpaTile = protectedAreas.fetchWindow(windowKey, windowLayout)
val seAsiaLandCoverTile = seAsiaLandCover.fetchWindow(windowKey, windowLayout)
val idnLandCoverTile = idnLandCover.fetchWindow(windowKey, windowLayout)
val isSoyPlantedAreasTile = isSoyPlantedArea.fetchWindow(windowKey, windowLayout)
val idnForestAreaTile = idnForestArea.fetchWindow(windowKey, windowLayout)
val isINDForestMoratoriumTile = isIDNForestMoratorium.fetchWindow(windowKey, windowLayout)
val prodesLossYearTile = prodesLossYear.fetchWindow(windowKey, windowLayout)
val braBiomesTile = braBiomes.fetchWindow(windowKey, windowLayout)
val isPlantationTile = isPlantation.fetchWindow(windowKey, windowLayout)
val gfwProCoverageTile = gfwProCoverage.fetchWindow(windowKey, windowLayout)
val argOTBNTile = argOTBN.fetchWindow(windowKey, windowLayout)


val tile = ForestChangeDiagnosticTile(
lossTile,
tcd2000Tile,
isPrimaryForestTile,
isPeatlandsTile,
isIntactForestLandscapes2000Tile,
wdpaTile,
seAsiaLandCoverTile,
idnLandCoverTile,
isSoyPlantedAreasTile,
idnForestAreaTile,
isINDForestMoratoriumTile,
prodesLossYearTile,
braBiomesTile,
isPlantationTile,
gfwProCoverageTile,
argOTBNTile
)

Raster(tile, windowKey.extent(windowLayout))
}
val tile = ForestChangeDiagnosticTile(
windowKey, windowLayout, this
)
Right(Raster(tile, windowKey.extent(windowLayout)))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,14 @@ case class ForestChangeDiagnosticRawDataGroup(umdTreeCoverLossYear: Int,
cerradoBiomesPresence: Boolean,
seAsiaPresence: Boolean,
idnPresence: Boolean,
argPresence: Boolean) {
argPresence: Boolean,
protectedAreaByCategory: String,
landmarkByCategory: String,
) {

/** Produce a partial ForestChangeDiagnosticData only for the loss year in this data group */
def toForestChangeDiagnosticData(totalArea: Double): ForestChangeDiagnosticData = ForestChangeDiagnosticData(
def toForestChangeDiagnosticData(totalArea: Double): ForestChangeDiagnosticData = {
ForestChangeDiagnosticData(
tree_cover_loss_total_yearly = ForestChangeDiagnosticDataLossYearly.fill(
umdTreeCoverLossYear,
totalArea,
Expand Down Expand Up @@ -154,6 +158,9 @@ case class ForestChangeDiagnosticRawDataGroup(umdTreeCoverLossYear: Int,
.fill(totalArea, isPeatlands),
arg_otbn_area = ForestChangeDiagnosticDataDoubleCategory
.fill(argOTBN, totalArea),
protected_areas_by_category_area = ForestChangeDiagnosticDataDoubleCategory
.fill(protectedAreaByCategory, totalArea),
landmark_by_category_area = ForestChangeDiagnosticDataDoubleCategory.fill(landmarkByCategory, totalArea),
brazil_biomes = ForestChangeDiagnosticDataDoubleCategory
.fill(braBiomes, totalArea),
idn_legal_area = ForestChangeDiagnosticDataDoubleCategory
Expand Down Expand Up @@ -223,5 +230,4 @@ case class ForestChangeDiagnosticRawDataGroup(umdTreeCoverLossYear: Int,
commodity_threat_fires = ForestChangeDiagnosticDataLossYearly.empty
)
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ object ForestChangeDiagnosticSummary {
val isPeatlands: Boolean = raster.tile.isPeatlands.getData(col, row)
val isIntactForestLandscapes2000: Boolean =
raster.tile.isIntactForestLandscapes2000.getData(col, row)
val wdpa: String = raster.tile.wdpaProtectedAreas.getData(col, row)
val prodesLossYear: Int = {
val loss = raster.tile.prodesLossYear.getData(col, row)
if (loss != null) {
Expand All @@ -102,7 +101,6 @@ object ForestChangeDiagnosticSummary {
val isTreeCoverExtent30: Boolean = tcd2000 > 30
val isTreeCoverExtent90: Boolean = tcd2000 > 90
val isUMDLoss: Boolean = isTreeCoverExtent30 && umdTreeCoverLossYear > 0
val isProtectedArea: Boolean = wdpa != ""
val isProdesLoss: Boolean = prodesLossYear > 0

val southAmericaPresence =
Expand All @@ -116,6 +114,26 @@ object ForestChangeDiagnosticSummary {
val idnPresence = gfwProCoverage.getOrElse("Indonesia", false)
val argPresence = gfwProCoverage.getOrElse("Argentina", false)

val protectedAreaCategory = raster.tile.protectedAreasByCategory.getData(col, row)
val isProtectedArea = (protectedAreaCategory != "")

// Currently, only do the area intersection with the detailed WDPA categories
// if location is in Argentina. Similarly, only do area intersection with
// Landmark (indigenous territories) if in Argentina.
// With lazy tile loading, the landmark tiles are only loaded if
// argPresence is true.
val detailedWdpa = if (argPresence)
protectedAreaCategory
else
""
// We will likely have different Landmark categories for other countries, but
// there is no distinction currently for Argentina, so we put all of the
// indigenous area into the "Not Reported" category.
val landmarkCategory = if (argPresence)
(if (raster.tile.landmark.getData(col, row)) "Not Reported" else "")
else
""

val groupKey = ForestChangeDiagnosticRawDataGroup(
umdTreeCoverLossYear,
isUMDLoss,
Expand All @@ -141,7 +159,9 @@ object ForestChangeDiagnosticSummary {
cerradoBiomesPresence,
seAsiaPresence,
idnPresence,
argPresence
argPresence,
detailedWdpa,
landmarkCategory,
)

val summaryData: ForestChangeDiagnosticRawData =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
package org.globalforestwatch.summarystats.forest_change_diagnostic

import geotrellis.raster.{CellGrid, CellType}
import org.globalforestwatch.layers._
import geotrellis.layer.{LayoutDefinition, SpatialKey}

/**
*
* Tile-like structure to hold tiles from datasets required for our summary.
* We can not use GeoTrellis MultibandTile because it requires all bands share a CellType.
*/
case class ForestChangeDiagnosticTile(
loss: TreeCoverLoss#ITile,
tcd2000: TreeCoverDensityPercent2000#ITile,
isPrimaryForest: PrimaryForest#OptionalITile,
isPeatlands: Peatlands#OptionalITile,
isIntactForestLandscapes2000: IntactForestLandscapes2000#OptionalITile,
wdpaProtectedAreas: ProtectedAreas#OptionalITile,
seAsiaLandCover: SEAsiaLandCover#OptionalITile,
idnLandCover: IndonesiaLandCover#OptionalITile,
isSoyPlantedArea: SoyPlantedAreas#OptionalITile,
idnForestArea: IndonesiaForestArea#OptionalITile,
isIDNForestMoratorium: IndonesiaForestMoratorium#OptionalITile,
prodesLossYear: ProdesLossYear#OptionalITile,
braBiomes: BrazilBiomes#OptionalITile,
isPlantation: PlantedForestsBool#OptionalITile,
gfwProCoverage: GFWProCoverage#OptionalITile,
argOTBN: ArgOTBN#OptionalITile
) extends CellGrid[Int] {
windowKey: SpatialKey,
windowLayout: LayoutDefinition,
sources: ForestChangeDiagnosticGridSources,
) extends CellGrid[Int] {

lazy val loss = sources.treeCoverLoss.fetchWindow(windowKey, windowLayout)
lazy val tcd2000 = sources.treeCoverDensity2000.fetchWindow(windowKey, windowLayout)
lazy val isPrimaryForest = sources.isPrimaryForest.fetchWindow(windowKey, windowLayout)
lazy val isPeatlands = sources.isPeatlands.fetchWindow(windowKey, windowLayout)
lazy val isIntactForestLandscapes2000 =
sources.isIntactForestLandscapes2000.fetchWindow(windowKey, windowLayout)
lazy val seAsiaLandCover = sources.seAsiaLandCover.fetchWindow(windowKey, windowLayout)
lazy val idnLandCover = sources.idnLandCover.fetchWindow(windowKey, windowLayout)
lazy val isSoyPlantedArea = sources.isSoyPlantedArea.fetchWindow(windowKey, windowLayout)
lazy val idnForestArea = sources.idnForestArea.fetchWindow(windowKey, windowLayout)
lazy val isIDNForestMoratorium = sources.isIDNForestMoratorium.fetchWindow(windowKey, windowLayout)
lazy val prodesLossYear = sources.prodesLossYear.fetchWindow(windowKey, windowLayout)
lazy val braBiomes = sources.braBiomes.fetchWindow(windowKey, windowLayout)
lazy val isPlantation = sources.isPlantation.fetchWindow(windowKey, windowLayout)
lazy val gfwProCoverage = sources.gfwProCoverage.fetchWindow(windowKey, windowLayout)
lazy val argOTBN = sources.argOTBN.fetchWindow(windowKey, windowLayout)

lazy val protectedAreasByCategory = sources.protectedAreasByCategory.fetchWindow(windowKey, windowLayout)
lazy val landmark = sources.landmark.fetchWindow(windowKey, windowLayout)

def cellType: CellType = loss.cellType

Expand Down
Loading

0 comments on commit f0f0a86

Please sign in to comment.