Skip to content

Commit

Permalink
Merge pull request #201 from wri/feature/integ
Browse files Browse the repository at this point in the history
Replace glad with integrated alerts in gfwpro_dashboard.
  • Loading branch information
danscales authored Nov 15, 2023
2 parents 0abc076 + 46805aa commit 054a820
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 22 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 @@ -311,6 +311,10 @@
{
"name": "gfwpro_negligible_risk_analysis",
"source_uri": "s3://gfw-data-lake/gfwpro_negligible_risk_analysis/v20230726/raster/epsg-4326/{grid_size}/{row_count}/risk/geotiff/{tile_id}.tif"
},
{
"name":"gfw_integrated_alerts",
"source_uri": "s3://gfw-data-lake/gfw_integrated_alerts/latest/raster/epsg-4326/{grid_size}/{row_count}/date_conf/geotiff/{tile_id}.tif"
}
]
}
10 changes: 10 additions & 0 deletions src/main/scala/org/globalforestwatch/layers/IntegratedAlerts.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.globalforestwatch.layers

import org.globalforestwatch.grids.GridTile

case class IntegratedAlerts(gridTile: GridTile, kwargs: Map[String, Any]) extends DateConfLevelsLayer with OptionalILayer {
val datasetName = "gfw_integrated_alerts"

val uri: String =
uriForGrid(gridTile, kwargs)
}
26 changes: 26 additions & 0 deletions src/main/scala/org/globalforestwatch/layers/Layer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,8 @@ trait IntegerLayer extends ILayer {
def lookup(value: Int): Integer = value
}

// Encoding for RaddAlerts, GladAlerts, and GladAlertsS2 layers. Confidence boolean
// value of true means "high" confidence, else confidence is "nominal"/"low".
trait DateConfLayer extends ILayer {
type B = Option[(LocalDate, Boolean)]

Expand All @@ -437,6 +439,30 @@ trait DateConfLayer extends ILayer {
}
}

// Encoding for IntegratedAlerts. Confidence value of 2 means "highest", 1 means
// "high", and 0 means "nominal".
trait DateConfLevelsLayer extends ILayer {
type B = Option[(LocalDate, Int)]

val internalNoDataValue: Int = 0
val externalNoDataValue: B = None

val baseDate = LocalDate.of(2014,12,31)

override def lookup(value: Int): Option[(LocalDate, Int)] = {
val confidence = if (value >= 40000) 2 else if (value >= 30000) 1 else 0
val days: Int = if (value >= 40000) value - 40000
else if (value >= 30000) value - 30000
else value - 20000
if (days < 0) {
None
} else {
val date = baseDate.plusDays(days)
Some((date, confidence))
}
}
}

trait DIntegerLayer extends DLayer {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,19 @@ import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder
* Note: This case class contains mutable values
*/
case class GfwProDashboardData(
/** Location intersects GLAD Alert tiles, GLAD alerts are possible */
/* NOTE: We are temporarily leaving the integrated_alerts_* fields named as
* glad_alerts_*, in order to reduce the number of moving pieces as we move from
* Glad alerts to integrated alerts in GFWPro. */

/** Location intersects Integrated Alert tiles, integrated alerts are possible */
glad_alerts_coverage: Boolean,
/** How many hacters of location geometry had tree cover extent > 30% in 2000 */
/** How many hectares of location geometry had tree cover extent > 30% in 2000 */
tree_cover_extent_total: ForestChangeDiagnosticDataDouble,
/** GLAD alert count within location geometry grouped by day */
/** Integrated alert count within location geometry grouped by day */
glad_alerts_daily: GfwProDashboardDataDateCount,
/** GLAD alert count within location geometry grouped by ISO year-week */
/** Integrated alert count within location geometry grouped by ISO year-week */
glad_alerts_weekly: GfwProDashboardDataDateCount,
/** GLAD alert count within location geometry grouped by year-month */
/** Integrated alert count within location geometry grouped by year-month */
glad_alerts_monthly: GfwProDashboardDataDateCount,
/** VIIRS alerts for location geometry grouped by day */
viirs_alerts_daily: GfwProDashboardDataDateCount,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package org.globalforestwatch.summarystats.gfwpro_dashboard

import geotrellis.vector.Extent
import org.globalforestwatch.grids.{GridTile, TenByTen30mGrid}
import org.globalforestwatch.grids.{GridTile, TenByTen10mGrid}

object GfwProDashboardGrid
extends TenByTen30mGrid[GfwProDashboardGridSources] {
extends TenByTen10mGrid[GfwProDashboardGridSources] {

val gridExtent: Extent = Extent(-180.0000, -90.0000, 180.0000, 90.0000)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import org.globalforestwatch.layers._
* @param gridTile top left corner, padded from east ex: "10N_010E"
*/
case class GfwProDashboardGridSources(gridTile: GridTile, kwargs: Map[String, Any]) extends GridSources {
val gladAlerts = GladAlerts(gridTile, kwargs)
val integratedAlerts = IntegratedAlerts(gridTile, kwargs)
val treeCoverDensity2000 = TreeCoverDensityPercent2000(gridTile, kwargs)

def readWindow(
Expand All @@ -19,15 +19,15 @@ case class GfwProDashboardGridSources(gridTile: GridTile, kwargs: Map[String, An
): Either[Throwable, Raster[GfwProDashboardTile]] = {

for {
// Glad alerts are Optional Tiles, but we keep it this way to avoid signature changes
gladAlertsTile <- Either
.catchNonFatal(gladAlerts.fetchWindow(windowKey, windowLayout))
// Integrated alerts are Optional Tiles, but we keep it this way to avoid signature changes
integratedAlertsTile <- Either
.catchNonFatal(integratedAlerts.fetchWindow(windowKey, windowLayout))
.right
tcd2000Tile <- Either
.catchNonFatal(treeCoverDensity2000.fetchWindow(windowKey, windowLayout))
.right
} yield {
val tile = GfwProDashboardTile(gladAlertsTile, tcd2000Tile)
val tile = GfwProDashboardTile(integratedAlertsTile, tcd2000Tile)
Raster(tile, windowKey.extent(windowLayout))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import java.time.LocalDate

case class GfwProDashboardRawDataGroup(
alertDate: Option[LocalDate],
gladAlertsCoverage: Boolean
integratedAlertsCoverage: Boolean
) {
def toGfwProDashboardData(alertCount: Int, totalArea: Double): GfwProDashboardData = {
GfwProDashboardData(
glad_alerts_coverage = gladAlertsCoverage,
glad_alerts_coverage = integratedAlertsCoverage,
glad_alerts_daily = GfwProDashboardDataDateCount.fillDaily(alertDate, alertCount),
glad_alerts_weekly = GfwProDashboardDataDateCount.fillWeekly(alertDate, alertCount),
glad_alerts_monthly = GfwProDashboardDataDateCount.fillMonthly(alertDate, alertCount),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,19 @@ object GfwProDashboardSummary {

def visit(raster: Raster[GfwProDashboardTile], col: Int, row: Int): Unit = {
val tcd2000: Integer = raster.tile.tcd2000.getData(col, row)
val gladAlertDate: Option[LocalDate] = raster.tile.gladAlerts.getData(col, row).map { case (date, _) => date }
val gladAlertCoverage = raster.tile.gladAlerts.t.isDefined
val integratedAlertDate: Option[LocalDate] = raster.tile.integratedAlerts.getData(col, row).map { case (date, _) => date }
val integratedAlertCoverage = raster.tile.integratedAlerts.t.isDefined
val isTreeCoverExtent30: Boolean = tcd2000 > 30

val groupKey = GfwProDashboardRawDataGroup(gladAlertDate, gladAlertsCoverage = gladAlertCoverage)
val groupKey = GfwProDashboardRawDataGroup(integratedAlertDate, integratedAlertsCoverage = integratedAlertCoverage)
val summaryData = acc.stats.getOrElse(groupKey, GfwProDashboardRawData(treeCoverExtentArea = 0.0, alertCount = 0))

if (isTreeCoverExtent30) {
val areaHa = Geodesy.pixelArea(lat = raster.rasterExtent.gridRowToMap(row), raster.cellSize) / 10000.0
summaryData.treeCoverExtentArea += areaHa
}

if (gladAlertDate.isDefined) {
if (integratedAlertDate.isDefined) {
summaryData.alertCount += 1
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ import org.globalforestwatch.layers._
* We can not use GeoTrellis MultibandTile because it requires all bands share a CellType.
*/
case class GfwProDashboardTile(
gladAlerts: GladAlerts#OptionalITile,
integratedAlerts: IntegratedAlerts#OptionalITile,
tcd2000: TreeCoverDensityPercent2000#ITile
) extends CellGrid[Int] {

def cellType: CellType = gladAlerts.cellType.getOrElse(IntCellType)
def cellType: CellType = integratedAlerts.cellType.getOrElse(IntCellType)

def cols: Int = gladAlerts.cols.getOrElse(GfwProDashboardGrid.blockSize)
def cols: Int = integratedAlerts.cols.getOrElse(GfwProDashboardGrid.blockSize)

def rows: Int = gladAlerts.rows.getOrElse(GfwProDashboardGrid.blockSize)
def rows: Int = integratedAlerts.rows.getOrElse(GfwProDashboardGrid.blockSize)
}

0 comments on commit 054a820

Please sign in to comment.