From 1a0fef2c8e1b56f1f147eaa45995f4d1975eb786 Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 10:41:53 -0700 Subject: [PATCH 1/8] Point ASA map to pmtiles and change property references --- api/app/routers/fba.py | 18 ++++++------ api/app/schemas/fba.py | 16 +++++------ web/src/api/fbaAPI.ts | 10 +++---- .../fba/components/ZoneSummaryPanel.tsx | 8 +++--- .../features/fba/components/map/FBAMap.tsx | 28 +++++++++---------- .../fba/components/map/featureStylers.ts | 22 +++++++-------- .../fba/components/viz/CombustibleAreaViz.tsx | 4 +-- .../fba/components/viz/ElevationInfoViz.tsx | 4 +-- .../fba/components/viz/FuelTypesBreakdown.tsx | 8 +++--- .../fba/pages/FireBehaviourAdvisoryPage.tsx | 8 +++--- .../features/fba/slices/fireZoneAreasSlice.ts | 4 +-- 11 files changed, 65 insertions(+), 65 deletions(-) diff --git a/api/app/routers/fba.py b/api/app/routers/fba.py index d02e543b9..35514d942 100644 --- a/api/app/routers/fba.py +++ b/api/app/routers/fba.py @@ -14,8 +14,8 @@ get_run_datetimes, get_zonal_elevation_stats) from app.db.models.auto_spatial_advisory import RunTypeEnum -from app.schemas.fba import (ClassifiedHfiThresholdFuelTypeArea, FireCenterListResponse, FireZoneAreaListResponse, - FireZoneArea, FireZoneElevationStats, FireZoneElevationStatsByThreshold, +from app.schemas.fba import (ClassifiedHfiThresholdFuelTypeArea, FireCenterListResponse, FireShapeAreaListResponse, + FireShapeArea, FireZoneElevationStats, FireZoneElevationStatsByThreshold, FireZoneElevationStatsListResponse, SFMSFuelType, HfiThreshold) from app.auth import authentication_required, audit from app.wildfire_one.wfwx_api import (get_auth_header, get_fire_centers) @@ -39,10 +39,10 @@ async def get_all_fire_centers(_=Depends(authentication_required)): return FireCenterListResponse(fire_centers=fire_centers) -@router.get('/fire-zone-areas/{run_type}/{run_datetime}/{for_date}', - response_model=FireZoneAreaListResponse) -async def get_zones(run_type: RunType, run_datetime: datetime, for_date: date, _=Depends(authentication_required)): - """ Return area of each zone, and percentage of area of zone with high hfi. """ +@router.get('/fire-shape-areas/{run_type}/{run_datetime}/{for_date}', + response_model=FireShapeAreaListResponse) +async def get_shapes(run_type: RunType, run_datetime: datetime, for_date: date, _=Depends(authentication_required)): + """ Return area of each zone unit shape, and percentage of area of zone unit shape with high hfi. """ async with get_async_read_session_scope() as session: zones = [] @@ -55,13 +55,13 @@ async def get_zones(run_type: RunType, run_datetime: datetime, for_date: date, _ for row in rows: combustible_area = row.combustible_area # type: ignore hfi_area = row.hfi_area # type: ignore - zones.append(FireZoneArea( - mof_fire_zone_id=row.source_identifier, # type: ignore + zones.append(FireShapeArea( + fire_shape_id=row.source_identifier, # type: ignore threshold=row.threshold, # type: ignore combustible_area=row.combustible_area, # type: ignore elevated_hfi_area=row.hfi_area, # type: ignore elevated_hfi_percentage=hfi_area / combustible_area * 100)) - return FireZoneAreaListResponse(zones=zones) + return FireShapeAreaListResponse(zones=zones) @router.get('/hfi-fuels/{run_type}/{for_date}/{run_datetime}/{zone_id}', diff --git a/api/app/schemas/fba.py b/api/app/schemas/fba.py index f09c310a7..56545c824 100644 --- a/api/app/schemas/fba.py +++ b/api/app/schemas/fba.py @@ -24,30 +24,30 @@ class FireCenterListResponse(BaseModel): fire_centers: List[FireCentre] -class FireZoneArea(BaseModel): +class FireShapeArea(BaseModel): """ A zone is a grouping of planning areas within a fire centre. """ - mof_fire_zone_id: int + fire_shape_id: int threshold: int combustible_area: float elevated_hfi_area: float elevated_hfi_percentage: float -class FireZoneAreaListResponse(BaseModel): +class FireShapeAreaListResponse(BaseModel): """ Response for all planning areas, in a list """ - zones: List[FireZoneArea] + zones: List[FireShapeArea] -class FireZoneHighHfiAreas(BaseModel): +class FireShapeHighHfiAreas(BaseModel): """ A fire zone and the area exceeding HFI thresholds. """ - mof_fire_zone_id: int + fire_shape_id: int advisory_area: float warn_area: float -class FireZoneHighHfiAreasListResponse(BaseModel): +class FireShapeHighHfiAreasListResponse(BaseModel): """ Response for all fire zones and their areas exceeding high HFI thresholds. """ - zones: List[FireZoneHighHfiAreas] + zones: List[FireShapeHighHfiAreas] class HfiThresholdAreaByFuelType(BaseModel): diff --git a/web/src/api/fbaAPI.ts b/web/src/api/fbaAPI.ts index 2346edcb2..c11a9dc1b 100644 --- a/web/src/api/fbaAPI.ts +++ b/web/src/api/fbaAPI.ts @@ -14,8 +14,8 @@ export interface FireCenter { stations: FireCenterStation[] } -export interface FireZone { - mof_fire_zone_id: number +export interface FireShape { + fire_shape_id: number mof_fire_zone_name: string mof_fire_centre_name?: string area_sqm?: number @@ -31,8 +31,8 @@ export interface FireZoneThresholdFuelTypeArea { area: number } -export interface FireZoneArea { - mof_fire_zone_id: number +export interface FireShapeArea { + fire_shape_id: number threshold: number combustible_area: number elevated_hfi_area: number @@ -57,7 +57,7 @@ export interface FireZoneElevationInfoResponse { } export interface ZoneAreaListResponse { - zones: FireZoneArea[] + zones: FireShapeArea[] } export interface HfiThresholdFuelTypeArea { diff --git a/web/src/features/fba/components/ZoneSummaryPanel.tsx b/web/src/features/fba/components/ZoneSummaryPanel.tsx index f9918a079..73ba4a39c 100644 --- a/web/src/features/fba/components/ZoneSummaryPanel.tsx +++ b/web/src/features/fba/components/ZoneSummaryPanel.tsx @@ -3,7 +3,7 @@ import { styled } from '@mui/material/styles' import CombustibleAreaViz from 'features/fba/components/viz/CombustibleAreaViz' import { Grid, IconButton, Typography } from '@mui/material' import { isUndefined } from 'lodash' -import { ElevationInfoByThreshold, FireZone, FireZoneArea, FireZoneThresholdFuelTypeArea } from 'api/fbaAPI' +import { ElevationInfoByThreshold, FireShape, FireShapeArea, FireZoneThresholdFuelTypeArea } from 'api/fbaAPI' import ElevationInfoViz from 'features/fba/components/viz/ElevationInfoViz' import FuelTypesBreakdown from 'features/fba/components/viz/FuelTypesBreakdown' import CloseIcon from '@mui/icons-material/Close' @@ -29,10 +29,10 @@ const CentreName = styled(Typography)({ }) interface Props { - selectedFireZone: FireZone | undefined + selectedFireZone: FireShape | undefined fuelTypeInfo: Record hfiElevationInfo: ElevationInfoByThreshold[] - fireZoneAreas: FireZoneArea[] + fireZoneAreas: FireShapeArea[] showSummaryPanel: boolean setShowSummaryPanel: React.Dispatch> } @@ -64,7 +64,7 @@ const ZoneSummaryPanel = React.forwardRef((props: Props, ref: React.ForwardedRef area.mof_fire_zone_id == props.selectedFireZone?.mof_fire_zone_id + area => area.fire_shape_id == props.selectedFireZone?.fire_shape_id )} /> diff --git a/web/src/features/fba/components/map/FBAMap.tsx b/web/src/features/fba/components/map/FBAMap.tsx index 4ba49f9f5..8e3e32ff5 100644 --- a/web/src/features/fba/components/map/FBAMap.tsx +++ b/web/src/features/fba/components/map/FBAMap.tsx @@ -14,13 +14,13 @@ import { ErrorBoundary } from 'components' import { selectFireWeatherStations, selectRunDates } from 'app/rootReducer' import { source as baseMapSource } from 'features/fireWeather/components/maps/constants' import Tile from 'ol/layer/Tile' -import { FireCenter, FireZone, FireZoneArea } from 'api/fbaAPI' +import { FireCenter, FireShape, FireShapeArea } from 'api/fbaAPI' import { extentsMap } from 'features/fba/fireCentreExtents' import { fireCentreStyler, fireCentreLabelStyler, fireZoneStyler, - fireZoneLabelStyler, + fireShapeLabelStyler, stationStyler, hfiStyler } from 'features/fba/components/map/featureStylers' @@ -40,10 +40,10 @@ const zoom = 6 export interface FBAMapProps { testId?: string selectedFireCenter: FireCenter | undefined - selectedFireZone: FireZone | undefined + selectedFireZone: FireShape | undefined forDate: DateTime - setSelectedFireZone: React.Dispatch> - fireZoneAreas: FireZoneArea[] + setSelectedFireZone: React.Dispatch> + fireZoneAreas: FireShapeArea[] runType: RunType advisoryThreshold: number showSummaryPanel: boolean @@ -72,13 +72,13 @@ const FBAMap = (props: FBAMapProps) => { url: `${PMTILES_BUCKET}fireCentres.pmtiles` }) const fireZoneVectorSource = new olpmtiles.PMTilesVectorSource({ - url: `${PMTILES_BUCKET}fireZones.pmtiles` + url: `${PMTILES_BUCKET}fireZoneUnits.pmtiles` }) const fireCentreLabelVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireCentreLabels.pmtiles` }) const fireZoneLabelVectorSource = new olpmtiles.PMTilesVectorSource({ - url: `${PMTILES_BUCKET}fireZoneLabels.pmtiles` + url: `${PMTILES_BUCKET}fireZoneUnitLabels.pmtiles` }) const handleToggleLayer = (layerName: string, isVisible: boolean) => { @@ -132,7 +132,7 @@ const FBAMap = (props: FBAMapProps) => { new VectorTileLayer({ declutter: true, source: fireZoneLabelVectorSource, - style: fireZoneLabelStyler(props.selectedFireZone), + style: fireShapeLabelStyler(props.selectedFireZone), zIndex: 99, minZoom: 6 }) @@ -154,11 +154,11 @@ const FBAMap = (props: FBAMapProps) => { if (!isUndefined(zoneExtent)) { map.getView().fit(zoneExtent, { duration: 400, padding: [50, 50, 50, 50], maxZoom: 7.4 }) } - const fireZone: FireZone = { - mof_fire_zone_id: feature.get('MOF_FIRE_ZONE_ID'), - mof_fire_zone_name: feature.get('MOF_FIRE_ZONE_NAME'), - mof_fire_centre_name: feature.get('MOF_FIRE_CENTRE_NAME'), - area_sqm: feature.get('FEATURE_AREA_SQM') + const fireZone: FireShape = { + fire_shape_id: feature.getProperties().OBJECTID, + mof_fire_zone_name: feature.getProperties().OBJECTID.FIRE_ZONE, + mof_fire_centre_name: feature.getProperties().FIRE_CENTR, + area_sqm: feature.getProperties().Shape_Area } props.setShowSummaryPanel(true) props.setSelectedFireZone(fireZone) @@ -196,7 +196,7 @@ const FBAMap = (props: FBAMapProps) => { fireZoneVTL.setStyle( fireZoneStyler(cloneDeep(props.fireZoneAreas), props.advisoryThreshold, props.selectedFireZone, showZoneStatus) ) - fireZoneLabelVTL.setStyle(fireZoneLabelStyler(props.selectedFireZone)) + fireZoneLabelVTL.setStyle(fireShapeLabelStyler(props.selectedFireZone)) fireZoneVTL.changed() fireZoneLabelVTL.changed() // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/web/src/features/fba/components/map/featureStylers.ts b/web/src/features/fba/components/map/featureStylers.ts index 2c244db6c..1e62fe164 100644 --- a/web/src/features/fba/components/map/featureStylers.ts +++ b/web/src/features/fba/components/map/featureStylers.ts @@ -5,7 +5,7 @@ import CircleStyle from 'ol/style/Circle' import { Fill, Stroke, Text } from 'ol/style' import Style from 'ol/style/Style' import { range, startCase, lowerCase, isUndefined } from 'lodash' -import { FireZone, FireZoneArea } from 'api/fbaAPI' +import { FireShape, FireShapeArea } from 'api/fbaAPI' const EMPTY_FILL = 'rgba(0, 0, 0, 0.0)' export const ADVISORY_ORANGE_FILL = 'rgba(255, 147, 38, 0.4)' @@ -41,15 +41,15 @@ export const fireCentreStyler = (): Style => { } export const fireZoneStyler = ( - fireZoneAreas: FireZoneArea[], + fireZoneAreas: FireShapeArea[], advisoryThreshold: number, - selectedFireZone: FireZone | undefined, + selectedFireZone: FireShape | undefined, showZoneStatus: boolean ) => { const a = (feature: RenderFeature | ol.Feature): Style => { - const mof_fire_zone_id = feature.get('MOF_FIRE_ZONE_ID') - const fireZoneAreaByThreshold = fireZoneAreas.filter(f => f.mof_fire_zone_id === mof_fire_zone_id) - const selected = !!(selectedFireZone?.mof_fire_zone_id && selectedFireZone.mof_fire_zone_id === mof_fire_zone_id) + const fire_shape_id = feature.getProperties().OBJECTID + const fireZoneAreaByThreshold = fireZoneAreas.filter(f => f.fire_shape_id === fire_shape_id) + const selected = !!(selectedFireZone?.fire_shape_id && selectedFireZone.fire_shape_id === fire_shape_id) let strokeValue = 'black' if (selected) { strokeValue = 'green' @@ -68,7 +68,7 @@ export const fireZoneStyler = ( return a } -export const getAdvisoryColors = (advisoryThreshold: number, fireZoneArea?: FireZoneArea[]) => { +export const getAdvisoryColors = (advisoryThreshold: number, fireZoneArea?: FireShapeArea[]) => { let fill = new Fill({ color: EMPTY_FILL }) if (isUndefined(fireZoneArea) || fireZoneArea.length === 0) { return fill @@ -92,12 +92,12 @@ export const getAdvisoryColors = (advisoryThreshold: number, fireZoneArea?: Fire return fill } -export const fireZoneLabelStyler = (selectedFireZone: FireZone | undefined) => { +export const fireShapeLabelStyler = (selectedFireShape: FireShape | undefined) => { const a = (feature: RenderFeature | ol.Feature): Style => { - const text = feature.get('mof_fire_zone_name').replace(' Fire Zone', '\nFire Zone') - const feature_mof_fire_zone_id = feature.get('mof_fire_zone_id') + const text = feature.getProperties().FIRE_ZONE.replace(' Fire Zone', '\nFire Zone') + const feature_fire_shape_id = feature.getProperties().OBJECTID const selected = - !isUndefined(selectedFireZone) && feature_mof_fire_zone_id === selectedFireZone.mof_fire_zone_id ? true : false + !isUndefined(selectedFireShape) && feature_fire_shape_id === selectedFireShape.fire_shape_id ? true : false return new Style({ text: new Text({ overflow: true, diff --git a/web/src/features/fba/components/viz/CombustibleAreaViz.tsx b/web/src/features/fba/components/viz/CombustibleAreaViz.tsx index 660991e03..d3f95b77a 100644 --- a/web/src/features/fba/components/viz/CombustibleAreaViz.tsx +++ b/web/src/features/fba/components/viz/CombustibleAreaViz.tsx @@ -1,6 +1,6 @@ import React from 'react' import { styled } from '@mui/material/styles' -import { FireZoneArea } from 'api/fbaAPI' +import { FireShapeArea } from 'api/fbaAPI' import { BarChart, CartesianGrid, XAxis, YAxis, Bar, Tooltip, ResponsiveContainer } from 'recharts' import { Typography } from '@mui/material' const PREFIX = 'CombustibleAreaViz' @@ -15,7 +15,7 @@ const StyledTypography = styled(Typography, { export interface AdvisoryMetadataProps { testId?: string - fireZoneAreas: FireZoneArea[] + fireZoneAreas: FireShapeArea[] } const CombustibleAreaViz = ({ fireZoneAreas }: AdvisoryMetadataProps) => { diff --git a/web/src/features/fba/components/viz/ElevationInfoViz.tsx b/web/src/features/fba/components/viz/ElevationInfoViz.tsx index 4d1c4726f..65ca80f4a 100644 --- a/web/src/features/fba/components/viz/ElevationInfoViz.tsx +++ b/web/src/features/fba/components/viz/ElevationInfoViz.tsx @@ -8,7 +8,7 @@ import TableContainer from '@mui/material/TableContainer' import TableHead from '@mui/material/TableHead' import TableRow from '@mui/material/TableRow' import { isUndefined } from 'lodash' -import { ElevationInfoByThreshold, FireZone } from 'api/fbaAPI' +import { ElevationInfoByThreshold, FireShape } from 'api/fbaAPI' const PREFIX = 'ElevationInfoViz' @@ -30,7 +30,7 @@ const Root = styled('div')({ interface Props { className?: string - selectedFireZone: FireZone | undefined + selectedFireZone: FireShape | undefined hfiElevationInfo: ElevationInfoByThreshold[] } diff --git a/web/src/features/fba/components/viz/FuelTypesBreakdown.tsx b/web/src/features/fba/components/viz/FuelTypesBreakdown.tsx index fd4b25463..2798398d6 100644 --- a/web/src/features/fba/components/viz/FuelTypesBreakdown.tsx +++ b/web/src/features/fba/components/viz/FuelTypesBreakdown.tsx @@ -2,7 +2,7 @@ import React from 'react' import { styled } from '@mui/material/styles' import { Typography } from '@mui/material' import { isUndefined } from 'lodash' -import { FireZone, FireZoneThresholdFuelTypeArea } from 'api/fbaAPI' +import { FireShape, FireZoneThresholdFuelTypeArea } from 'api/fbaAPI' import { PieChart, Pie, ResponsiveContainer, Cell } from 'recharts' const PREFIX = 'FuelTypesBreakdown' @@ -25,7 +25,7 @@ const PieChartHeader = styled(Typography, { interface Props { className?: string - selectedFireZone: FireZone | undefined + selectedFireZone: FireShape | undefined fuelTypeInfo: Record } @@ -90,12 +90,12 @@ const FuelTypesBreakdown = (props: Props) => { ) } - if (isUndefined(props.selectedFireZone) || isUndefined(props.fuelTypeInfo[props.selectedFireZone.mof_fire_zone_id])) { + if (isUndefined(props.selectedFireZone) || isUndefined(props.fuelTypeInfo[props.selectedFireZone.fire_shape_id])) { return
} else { const advisories: FuelTypeDataForPieChart[] = [] const warnings: FuelTypeDataForPieChart[] = [] - props.fuelTypeInfo[props.selectedFireZone?.mof_fire_zone_id].forEach(record => { + props.fuelTypeInfo[props.selectedFireZone?.fire_shape_id].forEach(record => { if (record.threshold.id === 1) { advisories.push({ area: record.area, fuel_type_code: record.fuel_type.fuel_type_code }) } else if (record.threshold.id === 2) { diff --git a/web/src/features/fba/pages/FireBehaviourAdvisoryPage.tsx b/web/src/features/fba/pages/FireBehaviourAdvisoryPage.tsx index d699c05cb..8f2f2f939 100644 --- a/web/src/features/fba/pages/FireBehaviourAdvisoryPage.tsx +++ b/web/src/features/fba/pages/FireBehaviourAdvisoryPage.tsx @@ -16,7 +16,7 @@ import { fetchFireCenters } from 'commonSlices/fireCentersSlice' import { theme } from 'app/theme' import { fetchWxStations } from 'features/stations/slices/stationsSlice' import { getStations, StationSource } from 'api/stationAPI' -import { FireCenter, FireZone } from 'api/fbaAPI' +import { FireCenter, FireShape } from 'api/fbaAPI' import { ASA_DOC_TITLE, FIRE_BEHAVIOUR_ADVISORY_NAME, PST_UTC_OFFSET } from 'utils/constants' import WPSDatePicker from 'components/WPSDatePicker' import { AppDispatch } from 'app/store' @@ -53,7 +53,7 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { const [fireCenter, setFireCenter] = useState(undefined) const [advisoryThreshold, setAdvisoryThreshold] = useState(20) - const [selectedFireZone, setSelectedFireZone] = useState(undefined) + const [selectedFireZone, setSelectedFireZone] = useState(undefined) const [dateOfInterest, setDateOfInterest] = useState( DateTime.now().setZone(`UTC${PST_UTC_OFFSET}`).hour < 13 ? DateTime.now().setZone(`UTC${PST_UTC_OFFSET}`) @@ -114,9 +114,9 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { !isUndefined(mostRecentRunDate) && !isUndefined(selectedFireZone) ) { - dispatch(fetchHighHFIFuels(runType, doiISODate, mostRecentRunDate.toString(), selectedFireZone.mof_fire_zone_id)) + dispatch(fetchHighHFIFuels(runType, doiISODate, mostRecentRunDate.toString(), selectedFireZone.fire_shape_id)) dispatch( - fetchfireZoneElevationInfo(selectedFireZone.mof_fire_zone_id, runType, doiISODate, mostRecentRunDate.toString()) + fetchfireZoneElevationInfo(selectedFireZone.fire_shape_id, runType, doiISODate, mostRecentRunDate.toString()) ) } }, [mostRecentRunDate, selectedFireZone]) // eslint-disable-line react-hooks/exhaustive-deps diff --git a/web/src/features/fba/slices/fireZoneAreasSlice.ts b/web/src/features/fba/slices/fireZoneAreasSlice.ts index c6f2f296d..44d5f53c7 100644 --- a/web/src/features/fba/slices/fireZoneAreasSlice.ts +++ b/web/src/features/fba/slices/fireZoneAreasSlice.ts @@ -2,13 +2,13 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { AppThunk } from 'app/store' import { logError } from 'utils/error' -import { FireZoneArea, ZoneAreaListResponse, getFireZoneAreas } from 'api/fbaAPI' +import { FireShapeArea, ZoneAreaListResponse, getFireZoneAreas } from 'api/fbaAPI' import { RunType } from 'features/fba/pages/FireBehaviourAdvisoryPage' interface State { loading: boolean error: string | null - fireZoneAreas: FireZoneArea[] + fireZoneAreas: FireShapeArea[] } const initialState: State = { From 26bc25f35db821c82f5b605a658b3d4fb93c2830 Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 10:58:11 -0700 Subject: [PATCH 2/8] Fix test --- api/app/tests/fba/test_fba_endpoint.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/app/tests/fba/test_fba_endpoint.py b/api/app/tests/fba/test_fba_endpoint.py index fc82f809d..93bb4c55a 100644 --- a/api/app/tests/fba/test_fba_endpoint.py +++ b/api/app/tests/fba/test_fba_endpoint.py @@ -5,7 +5,7 @@ from app.tests.utils.mock_jwt_decode_role import MockJWTDecodeWithRole get_fire_centres_url = '/api/fba/fire-centers' -get_fire_zone_areas_url = '/api/fba/fire-zone-areas/forecast/2022-09-27/2022-09-27' +get_fire_zone_areas_url = '/api/fba/fire-shape-areas/forecast/2022-09-27/2022-09-27' decode_fn = "jwt.decode" From 687562db539afc701364c9b3802ae5144e02a73c Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 11:15:19 -0700 Subject: [PATCH 3/8] Front frontend endpoint --- web/src/api/fbaAPI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/api/fbaAPI.ts b/web/src/api/fbaAPI.ts index c11a9dc1b..159ca3c7e 100644 --- a/web/src/api/fbaAPI.ts +++ b/web/src/api/fbaAPI.ts @@ -90,7 +90,7 @@ export async function getFireZoneAreas( run_datetime: string, for_date: string ): Promise { - const url = `/fba/fire-zone-areas/${run_type.toLowerCase()}/${encodeURI(run_datetime)}/${for_date}` + const url = `/fba/fire-shape-areas/${run_type.toLowerCase()}/${encodeURI(run_datetime)}/${for_date}` const { data } = await axios.get(url, {}) return data } From a6b7065efc77472bcc61e5bde4fc70f87a8f8fd1 Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 12:12:33 -0700 Subject: [PATCH 4/8] Renaming zones to shapes --- api/app/routers/fba.py | 6 +- api/app/schemas/fba.py | 2 +- web/src/api/fbaAPI.ts | 8 +- web/src/app/rootReducer.ts | 6 +- .../features/fba/components/map/FBAMap.tsx | 73 ++++++++++--------- .../features/fba/components/map/Legend.tsx | 6 +- .../fba/components/map/fbaMap.test.tsx | 6 +- .../fba/components/map/featureStylers.ts | 22 +++--- .../fba/components/map/legend.test.tsx | 4 +- .../fba/pages/FireBehaviourAdvisoryPage.tsx | 16 ++-- .../features/fba/slices/fireZoneAreasSlice.ts | 38 +++++----- 11 files changed, 95 insertions(+), 92 deletions(-) diff --git a/api/app/routers/fba.py b/api/app/routers/fba.py index 35514d942..c539569fb 100644 --- a/api/app/routers/fba.py +++ b/api/app/routers/fba.py @@ -44,7 +44,7 @@ async def get_all_fire_centers(_=Depends(authentication_required)): async def get_shapes(run_type: RunType, run_datetime: datetime, for_date: date, _=Depends(authentication_required)): """ Return area of each zone unit shape, and percentage of area of zone unit shape with high hfi. """ async with get_async_read_session_scope() as session: - zones = [] + shapes = [] rows = await get_hfi_area(session, RunTypeEnum(run_type.value), @@ -55,13 +55,13 @@ async def get_shapes(run_type: RunType, run_datetime: datetime, for_date: date, for row in rows: combustible_area = row.combustible_area # type: ignore hfi_area = row.hfi_area # type: ignore - zones.append(FireShapeArea( + shapes.append(FireShapeArea( fire_shape_id=row.source_identifier, # type: ignore threshold=row.threshold, # type: ignore combustible_area=row.combustible_area, # type: ignore elevated_hfi_area=row.hfi_area, # type: ignore elevated_hfi_percentage=hfi_area / combustible_area * 100)) - return FireShapeAreaListResponse(zones=zones) + return FireShapeAreaListResponse(shapes=shapes) @router.get('/hfi-fuels/{run_type}/{for_date}/{run_datetime}/{zone_id}', diff --git a/api/app/schemas/fba.py b/api/app/schemas/fba.py index 56545c824..fee05bd32 100644 --- a/api/app/schemas/fba.py +++ b/api/app/schemas/fba.py @@ -35,7 +35,7 @@ class FireShapeArea(BaseModel): class FireShapeAreaListResponse(BaseModel): """ Response for all planning areas, in a list """ - zones: List[FireShapeArea] + shapes: List[FireShapeArea] class FireShapeHighHfiAreas(BaseModel): diff --git a/web/src/api/fbaAPI.ts b/web/src/api/fbaAPI.ts index 159ca3c7e..3d30ac5b5 100644 --- a/web/src/api/fbaAPI.ts +++ b/web/src/api/fbaAPI.ts @@ -56,8 +56,8 @@ export interface FireZoneElevationInfoResponse { hfi_elevation_info: ElevationInfoByThreshold[] } -export interface ZoneAreaListResponse { - zones: FireShapeArea[] +export interface FireShapeAreaListResponse { + shapes: FireShapeArea[] } export interface HfiThresholdFuelTypeArea { @@ -85,11 +85,11 @@ export async function getFBAFireCenters(): Promise { return data } -export async function getFireZoneAreas( +export async function getFireShapeAreas( run_type: RunType, run_datetime: string, for_date: string -): Promise { +): Promise { const url = `/fba/fire-shape-areas/${run_type.toLowerCase()}/${encodeURI(run_datetime)}/${for_date}` const { data } = await axios.get(url, {}) return data diff --git a/web/src/app/rootReducer.ts b/web/src/app/rootReducer.ts index 0619fd491..cd0b8c18f 100644 --- a/web/src/app/rootReducer.ts +++ b/web/src/app/rootReducer.ts @@ -11,7 +11,7 @@ import hfiStationsReducer from 'features/hfiCalculator/slices/stationsSlice' import hfiReadyReducer, { HFIReadyState } from 'features/hfiCalculator/slices/hfiReadySlice' import fbaCalculatorSlice from 'features/fbaCalculator/slices/fbaCalculatorSlice' import fireCentersSlice from 'commonSlices/fireCentersSlice' -import fireZoneAreasSlice from 'features/fba/slices/fireZoneAreasSlice' +import fireShapeAreasSlice from 'features/fba/slices/fireZoneAreasSlice' import valueAtCoordinateSlice from 'features/fba/slices/valueAtCoordinateSlice' import runDatesSlice from 'features/fba/slices/runDatesSlice' import hfiFuelTypesSlice from 'features/fba/slices/hfiFuelTypesSlice' @@ -34,7 +34,7 @@ const rootReducer = combineReducers({ hfiReady: hfiReadyReducer, fbaCalculatorResults: fbaCalculatorSlice, fireCenters: fireCentersSlice, - fireZoneAreas: fireZoneAreasSlice, + fireShapeAreas: fireShapeAreasSlice, runDates: runDatesSlice, valueAtCoordinate: valueAtCoordinateSlice, hfiFuelTypes: hfiFuelTypesSlice, @@ -63,7 +63,7 @@ export const selectToken = (state: RootState) => state.authentication.token export const selectFireBehaviourCalcResult = (state: RootState) => state.fbaCalculatorResults export const selectHFIStations = (state: RootState) => state.hfiStations export const selectFireCenters = (state: RootState) => state.fireCenters -export const selectFireZoneAreas = (state: RootState) => state.fireZoneAreas +export const selectFireShapeAreas = (state: RootState) => state.fireShapeAreas export const selectRunDates = (state: RootState) => state.runDates export const selectValueAtCoordinate = (state: RootState) => state.valueAtCoordinate export const selectHFIFuelTypes = (state: RootState) => state.hfiFuelTypes diff --git a/web/src/features/fba/components/map/FBAMap.tsx b/web/src/features/fba/components/map/FBAMap.tsx index 8e3e32ff5..95665701d 100644 --- a/web/src/features/fba/components/map/FBAMap.tsx +++ b/web/src/features/fba/components/map/FBAMap.tsx @@ -19,7 +19,7 @@ import { extentsMap } from 'features/fba/fireCentreExtents' import { fireCentreStyler, fireCentreLabelStyler, - fireZoneStyler, + fireShapeStyler, fireShapeLabelStyler, stationStyler, hfiStyler @@ -40,10 +40,10 @@ const zoom = 6 export interface FBAMapProps { testId?: string selectedFireCenter: FireCenter | undefined - selectedFireZone: FireShape | undefined + selectedFireShape: FireShape | undefined forDate: DateTime - setSelectedFireZone: React.Dispatch> - fireZoneAreas: FireShapeArea[] + setSelectedFireShape: React.Dispatch> + fireShapeAreas: FireShapeArea[] runType: RunType advisoryThreshold: number showSummaryPanel: boolean @@ -62,7 +62,7 @@ const removeLayerByName = (map: ol.Map, layerName: string) => { const FBAMap = (props: FBAMapProps) => { const { stations } = useSelector(selectFireWeatherStations) - const [showZoneStatus, setShowZoneStatus] = useState(true) + const [showShapeStatus, setShowShapeStatus] = useState(true) const [showHFI, setShowHFI] = React.useState(false) const [map, setMap] = useState(null) const mapRef = useRef(null) @@ -71,13 +71,13 @@ const FBAMap = (props: FBAMapProps) => { const fireCentreVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireCentres.pmtiles` }) - const fireZoneVectorSource = new olpmtiles.PMTilesVectorSource({ + const fireShapeVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireZoneUnits.pmtiles` }) const fireCentreLabelVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireCentreLabels.pmtiles` }) - const fireZoneLabelVectorSource = new olpmtiles.PMTilesVectorSource({ + const fireShapeLabelVectorSource = new olpmtiles.PMTilesVectorSource({ url: `${PMTILES_BUCKET}fireZoneUnitLabels.pmtiles` }) @@ -88,9 +88,9 @@ const FBAMap = (props: FBAMapProps) => { .getArray() .find(l => l.getProperties()?.name === layerName) - if (layerName === 'fireZoneVector') { - fireZoneVTL.setStyle( - fireZoneStyler(cloneDeep(props.fireZoneAreas), props.advisoryThreshold, props.selectedFireZone, isVisible) + if (layerName === 'fireShapeVector') { + fireShapeVTL.setStyle( + fireShapeStyler(cloneDeep(props.fireShapeAreas), props.advisoryThreshold, props.selectedFireShape, isVisible) ) } else if (layer) { layer.setVisible(isVisible) @@ -105,17 +105,17 @@ const FBAMap = (props: FBAMapProps) => { zIndex: 50 }) ) - const [fireZoneVTL] = useState( + const [fireShapeVTL] = useState( new VectorTileLayer({ - source: fireZoneVectorSource, - style: fireZoneStyler( - cloneDeep(props.fireZoneAreas), + source: fireShapeVectorSource, + style: fireShapeStyler( + cloneDeep(props.fireShapeAreas), props.advisoryThreshold, - props.selectedFireZone, - showZoneStatus + props.selectedFireShape, + showShapeStatus ), zIndex: 49, - properties: { name: 'fireZoneVector' } + properties: { name: 'fireShapeVector' } }) ) // Seperate layer for polygons and for labels, to avoid duplicate labels. @@ -128,11 +128,11 @@ const FBAMap = (props: FBAMapProps) => { }) ) // Seperate layer for polygons and for labels, to avoid duplicate labels. - const [fireZoneLabelVTL] = useState( + const [fireShapeLabelVTL] = useState( new VectorTileLayer({ declutter: true, - source: fireZoneLabelVectorSource, - style: fireShapeLabelStyler(props.selectedFireZone), + source: fireShapeLabelVectorSource, + style: fireShapeLabelStyler(props.selectedFireShape), zIndex: 99, minZoom: 6 }) @@ -141,9 +141,9 @@ const FBAMap = (props: FBAMapProps) => { useEffect(() => { if (map) { map.on('click', event => { - fireZoneVTL.getFeatures(event.pixel).then(features => { + fireShapeVTL.getFeatures(event.pixel).then(features => { if (!features.length) { - props.setSelectedFireZone(undefined) + props.setSelectedFireShape(undefined) return } const feature = features[0] @@ -161,7 +161,7 @@ const FBAMap = (props: FBAMapProps) => { area_sqm: feature.getProperties().Shape_Area } props.setShowSummaryPanel(true) - props.setSelectedFireZone(fireZone) + props.setSelectedFireShape(fireZone) }) }) } @@ -171,7 +171,7 @@ const FBAMap = (props: FBAMapProps) => { if (!map) return if (!props.showSummaryPanel) { - props.setSelectedFireZone(undefined) + props.setSelectedFireShape(undefined) } }, [props.showSummaryPanel]) // eslint-disable-line react-hooks/exhaustive-deps @@ -193,14 +193,19 @@ const FBAMap = (props: FBAMapProps) => { useEffect(() => { if (!map) return - fireZoneVTL.setStyle( - fireZoneStyler(cloneDeep(props.fireZoneAreas), props.advisoryThreshold, props.selectedFireZone, showZoneStatus) + fireShapeVTL.setStyle( + fireShapeStyler( + cloneDeep(props.fireShapeAreas), + props.advisoryThreshold, + props.selectedFireShape, + showShapeStatus + ) ) - fireZoneLabelVTL.setStyle(fireShapeLabelStyler(props.selectedFireZone)) - fireZoneVTL.changed() - fireZoneLabelVTL.changed() + fireShapeLabelVTL.setStyle(fireShapeLabelStyler(props.selectedFireShape)) + fireShapeVTL.changed() + fireShapeLabelVTL.changed() // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.selectedFireZone, props.fireZoneAreas, props.advisoryThreshold]) + }, [props.selectedFireShape, props.fireShapeAreas, props.advisoryThreshold]) useEffect(() => { if (!map) return @@ -246,9 +251,9 @@ const FBAMap = (props: FBAMapProps) => { source: baseMapSource }), fireCentreVTL, - fireZoneVTL, + fireShapeVTL, fireCentreLabelVTL, - fireZoneLabelVTL + fireShapeLabelVTL ], overlays: [], controls: defaultControls().extend([new FullScreen()]) @@ -299,8 +304,8 @@ const FBAMap = (props: FBAMapProps) => { diff --git a/web/src/features/fba/components/map/Legend.tsx b/web/src/features/fba/components/map/Legend.tsx index 486fb551e..08d66c85c 100644 --- a/web/src/features/fba/components/map/Legend.tsx +++ b/web/src/features/fba/components/map/Legend.tsx @@ -76,12 +76,12 @@ const LegendItem: React.FC = ({ label, checked, onChange, subIt interface LegendProps { onToggleLayer: (layerName: string, isVisible: boolean) => void showZoneStatus: boolean - setShowZoneStatus: React.Dispatch> + setShowShapeStatus: React.Dispatch> showHFI: boolean setShowHFI: React.Dispatch> } -const Legend = ({ onToggleLayer, showZoneStatus, setShowZoneStatus, showHFI, setShowHFI }: LegendProps) => { +const Legend = ({ onToggleLayer, showZoneStatus, setShowShapeStatus, showHFI, setShowHFI }: LegendProps) => { const handleLayerChange = ( layerName: string, isVisible: boolean, @@ -108,7 +108,7 @@ const Legend = ({ onToggleLayer, showZoneStatus, setShowZoneStatus, showHFI, set handleLayerChange('fireZoneVector', showZoneStatus, setShowZoneStatus)} + onChange={() => handleLayerChange('fireShapeVector', showZoneStatus, setShowShapeStatus)} subItems={zoneStatusSubItems} /> { forDate={DateTime.fromISO('2016-05-25')} advisoryThreshold={0} selectedFireCenter={undefined} - selectedFireZone={undefined} - fireZoneAreas={[]} + selectedFireShape={undefined} + fireShapeAreas={[]} runType={RunType.FORECAST} - setSelectedFireZone={function (): void { + setSelectedFireShape={function (): void { throw new Error('Function not implemented.') }} showSummaryPanel={true} diff --git a/web/src/features/fba/components/map/featureStylers.ts b/web/src/features/fba/components/map/featureStylers.ts index 1e62fe164..5d0de1e9e 100644 --- a/web/src/features/fba/components/map/featureStylers.ts +++ b/web/src/features/fba/components/map/featureStylers.ts @@ -40,16 +40,16 @@ export const fireCentreStyler = (): Style => { }) } -export const fireZoneStyler = ( - fireZoneAreas: FireShapeArea[], +export const fireShapeStyler = ( + fireShapeAreas: FireShapeArea[], advisoryThreshold: number, - selectedFireZone: FireShape | undefined, + selectedFireShape: FireShape | undefined, showZoneStatus: boolean ) => { const a = (feature: RenderFeature | ol.Feature): Style => { const fire_shape_id = feature.getProperties().OBJECTID - const fireZoneAreaByThreshold = fireZoneAreas.filter(f => f.fire_shape_id === fire_shape_id) - const selected = !!(selectedFireZone?.fire_shape_id && selectedFireZone.fire_shape_id === fire_shape_id) + const fireShapes = fireShapeAreas.filter(f => f.fire_shape_id === fire_shape_id) + const selected = !!(selectedFireShape?.fire_shape_id && selectedFireShape.fire_shape_id === fire_shape_id) let strokeValue = 'black' if (selected) { strokeValue = 'green' @@ -60,22 +60,20 @@ export const fireZoneStyler = ( color: strokeValue, width: selected ? 8 : 1 }), - fill: showZoneStatus - ? getAdvisoryColors(advisoryThreshold, fireZoneAreaByThreshold) - : new Fill({ color: EMPTY_FILL }) + fill: showZoneStatus ? getAdvisoryColors(advisoryThreshold, fireShapes) : new Fill({ color: EMPTY_FILL }) }) } return a } -export const getAdvisoryColors = (advisoryThreshold: number, fireZoneArea?: FireShapeArea[]) => { +export const getAdvisoryColors = (advisoryThreshold: number, fireShapeArea?: FireShapeArea[]) => { let fill = new Fill({ color: EMPTY_FILL }) - if (isUndefined(fireZoneArea) || fireZoneArea.length === 0) { + if (isUndefined(fireShapeArea) || fireShapeArea.length === 0) { return fill } - const advisoryThresholdArea = fireZoneArea.find(area => area.threshold == 1) - const warningThresholdArea = fireZoneArea.find(area => area.threshold == 2) + const advisoryThresholdArea = fireShapeArea.find(area => area.threshold == 1) + const warningThresholdArea = fireShapeArea.find(area => area.threshold == 2) const advisoryPercentage = advisoryThresholdArea?.elevated_hfi_percentage ?? 0 const warningPercentage = warningThresholdArea?.elevated_hfi_percentage ?? 0 diff --git a/web/src/features/fba/components/map/legend.test.tsx b/web/src/features/fba/components/map/legend.test.tsx index 8cefcedca..7cef4228c 100644 --- a/web/src/features/fba/components/map/legend.test.tsx +++ b/web/src/features/fba/components/map/legend.test.tsx @@ -11,7 +11,7 @@ describe('Legend', () => { const { getByTestId } = render( { const { getByTestId } = render( { const [runType, setRunType] = useState(RunType.FORECAST) const [showSummaryPanel, setShowSummaryPanel] = useState(true) const { mostRecentRunDate } = useSelector(selectRunDates) - const { fireZoneAreas } = useSelector(selectFireZoneAreas) + const { fireShapeAreas } = useSelector(selectFireShapeAreas) useEffect(() => { const findCenter = (id: string | null): FireCenter | undefined => { @@ -124,7 +124,7 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { useEffect(() => { const doiISODate = dateOfInterest.toISODate() if (!isNull(mostRecentRunDate) && !isNull(doiISODate) && !isUndefined(mostRecentRunDate)) { - dispatch(fetchFireZoneAreas(runType, mostRecentRunDate.toString(), doiISODate)) + dispatch(fetchFireShapeAreas(runType, mostRecentRunDate.toString(), doiISODate)) } }, [mostRecentRunDate]) // eslint-disable-line react-hooks/exhaustive-deps @@ -225,7 +225,7 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { selectedFireZone={selectedFireZone} fuelTypeInfo={hfiThresholdsFuelTypes} hfiElevationInfo={fireZoneElevationInfo} - fireZoneAreas={fireZoneAreas} + fireZoneAreas={fireShapeAreas} showSummaryPanel={showSummaryPanel} setShowSummaryPanel={setShowSummaryPanel} /> @@ -234,11 +234,11 @@ const FireBehaviourAdvisoryPage: React.FunctionComponent = () => { diff --git a/web/src/features/fba/slices/fireZoneAreasSlice.ts b/web/src/features/fba/slices/fireZoneAreasSlice.ts index 44d5f53c7..043d1490e 100644 --- a/web/src/features/fba/slices/fireZoneAreasSlice.ts +++ b/web/src/features/fba/slices/fireZoneAreasSlice.ts @@ -2,63 +2,63 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { AppThunk } from 'app/store' import { logError } from 'utils/error' -import { FireShapeArea, ZoneAreaListResponse, getFireZoneAreas } from 'api/fbaAPI' +import { FireShapeArea, FireShapeAreaListResponse, getFireShapeAreas } from 'api/fbaAPI' import { RunType } from 'features/fba/pages/FireBehaviourAdvisoryPage' interface State { loading: boolean error: string | null - fireZoneAreas: FireShapeArea[] + fireShapeAreas: FireShapeArea[] } const initialState: State = { loading: false, error: null, - fireZoneAreas: [] + fireShapeAreas: [] } -const fireZoneAreasSlice = createSlice({ - name: 'fireZoneAreas', +const fireShapeAreasSlice = createSlice({ + name: 'fireShapeAreas', initialState, reducers: { - getFireZoneAreasStart(state: State) { + getFireShapeAreasStart(state: State) { state.error = null state.loading = true - state.fireZoneAreas = [] + state.fireShapeAreas = [] }, - getFireZoneAreasFailed(state: State, action: PayloadAction) { + getFireShapeAreasFailed(state: State, action: PayloadAction) { state.error = action.payload state.loading = false }, - getFireZoneAreasSuccess(state: State, action: PayloadAction) { + getFireShapeAreasSuccess(state: State, action: PayloadAction) { state.error = null - state.fireZoneAreas = action.payload.zones + state.fireShapeAreas = action.payload.shapes state.loading = false } } }) -export const { getFireZoneAreasStart, getFireZoneAreasFailed, getFireZoneAreasSuccess } = fireZoneAreasSlice.actions +export const { getFireShapeAreasStart, getFireShapeAreasFailed, getFireShapeAreasSuccess } = fireShapeAreasSlice.actions -export default fireZoneAreasSlice.reducer +export default fireShapeAreasSlice.reducer -export const fetchFireZoneAreas = +export const fetchFireShapeAreas = (runType: RunType, run_datetime: string, for_date: string): AppThunk => async dispatch => { if (run_datetime != undefined && run_datetime !== ``) { try { - dispatch(getFireZoneAreasStart()) - const fireZoneAreas = await getFireZoneAreas(runType, run_datetime, for_date) - dispatch(getFireZoneAreasSuccess(fireZoneAreas)) + dispatch(getFireShapeAreasStart()) + const fireShapeAreas = await getFireShapeAreas(runType, run_datetime, for_date) + dispatch(getFireShapeAreasSuccess(fireShapeAreas)) } catch (err) { - dispatch(getFireZoneAreasFailed((err as Error).toString())) + dispatch(getFireShapeAreasFailed((err as Error).toString())) logError(err) } } else { try { - dispatch(getFireZoneAreasFailed('run_datetime cannot be undefined!')) + dispatch(getFireShapeAreasFailed('run_datetime cannot be undefined!')) } catch (err) { - dispatch(getFireZoneAreasFailed((err as Error).toString())) + dispatch(getFireShapeAreasFailed((err as Error).toString())) logError(err) } } From f7af506578356e12d4f52a53f5530225999cc06c Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 15:03:53 -0700 Subject: [PATCH 5/8] Trigger Build From a03eb75aabd11914a1ed5a9a889a526e792a565b Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Wed, 25 Oct 2023 15:30:28 -0700 Subject: [PATCH 6/8] Trigger Build From fa947bfd2aacfc3361312945bcad5e9407144da8 Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Tue, 31 Oct 2023 11:35:39 -0700 Subject: [PATCH 7/8] Bump dev database cpu limits for sfms processing of zone units --- .github/workflows/deployment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 3be0c7aa4..b22f446c1 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -22,7 +22,7 @@ jobs: shell: bash run: | oc login "${{ secrets.OPENSHIFT_CLUSTER }}" --token="${{ secrets.OC4_DEV_TOKEN }}" - EPHEMERAL_STORAGE=True bash openshift/scripts/oc_provision_db.sh ${SUFFIX} apply + EPHEMERAL_STORAGE=True CPU_REQUEST=75m CPU_LIMIT=2000m bash openshift/scripts/oc_provision_db.sh ${SUFFIX} apply prepare-dev-database-backups: name: Prepare Dev Database Backups From 21b2031047c193e73a3f05754343f388460edcc5 Mon Sep 17 00:00:00 2001 From: Conor Brady Date: Tue, 31 Oct 2023 12:34:19 -0700 Subject: [PATCH 8/8] Migration to compute combustible area of zone units --- ...1e39_compute_zone_unit_combustible_area.py | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 api/alembic/versions/d5115b761e39_compute_zone_unit_combustible_area.py diff --git a/api/alembic/versions/d5115b761e39_compute_zone_unit_combustible_area.py b/api/alembic/versions/d5115b761e39_compute_zone_unit_combustible_area.py new file mode 100644 index 000000000..7788e25c5 --- /dev/null +++ b/api/alembic/versions/d5115b761e39_compute_zone_unit_combustible_area.py @@ -0,0 +1,66 @@ +"""compute zone unit combustible area + +Revision ID: d5115b761e39 +Revises: 5b745fe0bd7a +Create Date: 2023-10-31 12:24:36.889483 + +""" +from alembic import op +import sqlalchemy as sa +import geoalchemy2 +from sqlalchemy.orm.session import Session +from app.auto_spatial_advisory.calculate_combustible_land_area import calculate_combustible_area_by_fire_zone, get_fuel_types_from_object_store + +# revision identifiers, used by Alembic. +revision = 'd5115b761e39' +down_revision = '5b745fe0bd7a' +branch_labels = None +depends_on = None + +shape_type_table = sa.Table('advisory_shape_types', sa.MetaData(), + sa.Column('id', sa.Integer), + sa.Column('name', sa.String)) + +shape_table = sa.Table('advisory_shapes', sa.MetaData(), + sa.Column('id', sa.Integer), + sa.Column('source_identifier', sa.String), + sa.Column('shape_type', sa.Integer), + sa.Column('geom', geoalchemy2.Geometry)) + + +def get_fire_zone_unit_shape_type_id(session: Session): + statement = shape_type_table.select().where(shape_type_table.c.name == 'fire_zone_unit') + result = session.execute(statement).fetchone() + return result.id + + +def get_fire_zone_units(session: Session, fire_zone_type_id: int): + statement = shape_table.select().where(shape_table.c.shape_type == fire_zone_type_id) + result = session.execute(statement).fetchall() + return result + + +def upgrade(): + session = Session(bind=op.get_bind()) + + with get_fuel_types_from_object_store() as fuel_types: + # fetch all fire zones from DB + fire_zone_shape_type_id = get_fire_zone_unit_shape_type_id(session) + zone_units = get_fire_zone_units(session, fire_zone_shape_type_id) + + zone_areas = calculate_combustible_area_by_fire_zone(fuel_types, zone_units) + for tuple in zone_areas: + op.execute('UPDATE advisory_shapes SET combustible_area={} WHERE source_identifier LIKE \'{}\''.format( + tuple[1], tuple[0]) + ) + + +def downgrade(): + session = Session(bind=op.get_bind()) + fire_zone_shape_id = get_fire_zone_unit_shape_type_id(session) + zones = get_fire_zone_units(session, fire_zone_shape_id) + + for zone in zones: + op.execute('UPDATE advisory_shapes SET combustible_area = NULL WHERE source_identifier LIKE \'{}\''.format( + str(zone.source_identifier) + ))