Skip to content

Commit

Permalink
SW-6191 Create 1-plot permanent clusters (#2547)
Browse files Browse the repository at this point in the history
Remove the code that creates clusters of 4 monitoring permanent monitoring plots
and instead start creating one-plot "clusters" at observation start time and when
plot replacement is requested.
  • Loading branch information
sgrimm authored Nov 1, 2024
1 parent f849a38 commit 6673e84
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 238 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ import com.terraformation.backend.tracking.model.PlantingZoneModel
import com.terraformation.backend.tracking.model.ReplacementResult
import com.terraformation.backend.tracking.model.UpdatedPlantingSeasonModel
import com.terraformation.backend.util.calculateAreaHectares
import com.terraformation.backend.util.createRectangle
import com.terraformation.backend.util.equalsOrBothNull
import com.terraformation.backend.util.toInstant
import jakarta.inject.Named
Expand Down Expand Up @@ -951,15 +950,14 @@ class PlantingSiteStore(
private fun setMonitoringPlotCluster(
monitoringPlotId: MonitoringPlotId,
permanentCluster: Int,
permanentClusterSubplot: Int
) {
with(MONITORING_PLOTS) {
dslContext
.update(MONITORING_PLOTS)
.set(MODIFIED_BY, currentUser().userId)
.set(MODIFIED_TIME, clock.instant())
.set(PERMANENT_CLUSTER, permanentCluster)
.set(PERMANENT_CLUSTER_SUBPLOT, permanentClusterSubplot)
.set(PERMANENT_CLUSTER_SUBPLOT, 1)
.where(ID.eq(monitoringPlotId))
.execute()
}
Expand Down Expand Up @@ -1374,8 +1372,6 @@ class PlantingSiteStore(
throw IllegalStateException("Planting site ${plantingSite.id} has no grid origin")
}

val geometryFactory = plantingSite.gridOrigin.factory

// List of [boundary, cluster number]
val clusterBoundaries: List<Pair<Polygon, Int>> =
plantingZone
Expand All @@ -1385,65 +1381,46 @@ class PlantingSiteStore(
exclusion = plantingSite.exclusion,
gridOrigin = plantingSite.gridOrigin,
searchBoundary = searchBoundary,
sizeMeters = MONITORING_PLOT_SIZE * 2,
sizeMeters = MONITORING_PLOT_SIZE,
)
.zip(clusterNumbers)

return clusterBoundaries.flatMap { (clusterBoundary, clusterNumber) ->
val westX = clusterBoundary.coordinates[0].x
val eastX = clusterBoundary.coordinates[2].x
val southY = clusterBoundary.coordinates[0].y
val northY = clusterBoundary.coordinates[2].y
val middleX = clusterBoundary.centroid.x
val middleY = clusterBoundary.centroid.y
val clusterPlots =
listOf(
// The order is important here: southwest, southeast, northeast, northwest
// (the position in this list turns into the cluster subplot number).
geometryFactory.createRectangle(westX, southY, middleX, middleY),
geometryFactory.createRectangle(middleX, southY, eastX, middleY),
geometryFactory.createRectangle(middleX, middleY, eastX, northY),
geometryFactory.createRectangle(westX, middleY, middleX, northY),
)
return clusterBoundaries.map { (plotBoundary, clusterNumber) ->
val existingPlot = plantingZone.findMonitoringPlot(plotBoundary)

clusterPlots.mapIndexed { plotIndex, plotBoundary ->
val existingPlot = plantingZone.findMonitoringPlot(plotBoundary.centroid)
if (existingPlot != null) {
if (existingPlot.permanentCluster != null) {
throw IllegalStateException("Cannot place new permanent cluster over existing one")
}

if (existingPlot != null) {
if (existingPlot.permanentCluster != null) {
throw IllegalStateException("Cannot place new permanent cluster over existing one")
}
setMonitoringPlotCluster(existingPlot.id, clusterNumber)

setMonitoringPlotCluster(existingPlot.id, clusterNumber, plotIndex + 1)
existingPlot.id
} else {
val subzone =
plantingZone.findPlantingSubzone(plotBoundary)
?: throw IllegalStateException(
"Planting zone ${plantingZone.id} not fully covered by subzones")
val plotNumber = nextPlotNumber++

existingPlot.id
} else {
val subzone =
plantingZone.findPlantingSubzone(plotBoundary)
?: throw IllegalStateException(
"Planting zone ${plantingZone.id} not fully covered by subzones",
)
val plotNumber = nextPlotNumber++

val monitoringPlotsRow =
MonitoringPlotsRow(
boundary = plotBoundary,
createdBy = userId,
createdTime = now,
fullName = "${subzone.fullName}-$plotNumber",
modifiedBy = userId,
modifiedTime = now,
name = "$plotNumber",
permanentCluster = clusterNumber,
permanentClusterSubplot = plotIndex + 1,
plantingSubzoneId = subzone.id,
sizeMeters = MONITORING_PLOT_SIZE_INT,
)
val monitoringPlotsRow =
MonitoringPlotsRow(
boundary = plotBoundary,
createdBy = userId,
createdTime = now,
fullName = "${subzone.fullName}-$plotNumber",
modifiedBy = userId,
modifiedTime = now,
name = "$plotNumber",
permanentCluster = clusterNumber,
permanentClusterSubplot = 1,
plantingSubzoneId = subzone.id,
sizeMeters = MONITORING_PLOT_SIZE_INT,
)

monitoringPlotsDao.insert(monitoringPlotsRow)
monitoringPlotsDao.insert(monitoringPlotsRow)

monitoringPlotsRow.id!!
}
monitoringPlotsRow.id!!
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,10 @@ data class PlantingZoneModel<PZID : PlantingZoneId?, PSZID : PlantingSubzoneId?>
exclusion: MultiPolygon? = null,
requestedSubzoneIds: Set<PlantingSubzoneId> = emptySet(),
): Collection<Polygon> {
val permanentPlotIds = choosePermanentPlots(plantedSubzoneIds, requestedSubzoneIds)
if (plantingSubzones.isEmpty()) {
throw IllegalArgumentException("No subzones found for planting zone $id (wrong fetch depth?)")
}

val eligibleSubzoneIds = getEligibleSubzoneIds(plantedSubzoneIds, requestedSubzoneIds)

// We will assign as many plots as possible evenly across all subzones, eligible or not.
Expand All @@ -129,7 +132,9 @@ data class PlantingZoneModel<PZID : PlantingZoneId?, PSZID : PlantingSubzoneId?>
return plantingSubzones
.sortedWith(
compareBy { subzone: PlantingSubzoneModel<PSZID> ->
subzone.monitoringPlots.count { it.id in permanentPlotIds }
subzone.monitoringPlots.count { plot ->
plot.permanentCluster != null && plot.permanentCluster <= numPermanentClusters
}
}
.thenBy { if (it.id != null && it.id in eligibleSubzoneIds) 0 else 1 }
.thenBy { it.id?.value ?: 0L })
Expand Down
Loading

0 comments on commit 6673e84

Please sign in to comment.