Skip to content

Commit 60b1c01

Browse files
authored
Merge pull request #591 from DataIntegrationGroup/water-elevation-layer
water-elevation-layer
2 parents d8b3f71 + 75f727d commit 60b1c01

2 files changed

Lines changed: 131 additions & 10 deletions

File tree

alembic/versions/n7a8b9c0d1e2_fix_water_elevation_units_to_feet.py

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,14 @@ def _create_water_elevation_view() -> str:
4040
fe.thing_id,
4141
o.id AS observation_id,
4242
o.observation_datetime,
43-
(o.value - COALESCE(o.measuring_point_height, 0))
44-
AS depth_to_water_below_ground_surface
43+
CASE
44+
WHEN lower(trim(o.unit)) IN ('m', 'meter', 'meters', 'metre', 'metres') THEN
45+
(o.value * {METERS_TO_FEET}) - COALESCE(o.measuring_point_height, 0)
46+
WHEN lower(trim(o.unit)) IN ('ft', 'foot', 'feet') THEN
47+
o.value - COALESCE(o.measuring_point_height, 0)
48+
ELSE
49+
NULL
50+
END AS depth_to_water_below_ground_surface
4551
FROM observation AS o
4652
JOIN sample AS s ON s.id = o.sample_id
4753
JOIN field_activity AS fa ON fa.id = s.field_activity_id
@@ -52,6 +58,16 @@ def _create_water_elevation_view() -> str:
5258
AND fa.activity_type = 'groundwater level'
5359
AND o.value IS NOT NULL
5460
AND o.observation_datetime IS NOT NULL
61+
AND lower(trim(o.unit)) IN (
62+
'm',
63+
'meter',
64+
'meters',
65+
'metre',
66+
'metres',
67+
'ft',
68+
'foot',
69+
'feet'
70+
)
5571
),
5672
latest_obs AS (
5773
SELECT
@@ -68,10 +84,10 @@ def _create_water_elevation_view() -> str:
6884
t.thing_type,
6985
lo.observation_id,
7086
lo.observation_datetime,
71-
l.elevation,
72-
lo.depth_to_water_below_ground_surface,
87+
l.elevation AS elevation_m,
88+
lo.depth_to_water_below_ground_surface AS depth_to_water_below_ground_surface_ft,
7389
((l.elevation * {METERS_TO_FEET}) - lo.depth_to_water_below_ground_surface)
74-
AS water_elevation,
90+
AS water_elevation_ft,
7591
l.point
7692
FROM latest_obs AS lo
7793
JOIN thing AS t ON t.id = lo.thing_id
@@ -81,6 +97,54 @@ def _create_water_elevation_view() -> str:
8197
"""
8298

8399

100+
def _create_water_elevation_view_m6() -> str:
101+
return f"""
102+
CREATE MATERIALIZED VIEW ogc_water_elevation_wells AS
103+
WITH latest_location AS (
104+
{LATEST_LOCATION_CTE}
105+
),
106+
ranked_obs AS (
107+
SELECT
108+
fe.thing_id,
109+
o.id AS observation_id,
110+
o.observation_datetime,
111+
(o.value - COALESCE(o.measuring_point_height, 0))
112+
AS depth_to_water_below_ground_surface,
113+
ROW_NUMBER() OVER (
114+
PARTITION BY fe.thing_id
115+
ORDER BY o.observation_datetime DESC, o.id DESC
116+
) AS rn
117+
FROM observation AS o
118+
JOIN sample AS s ON s.id = o.sample_id
119+
JOIN field_activity AS fa ON fa.id = s.field_activity_id
120+
JOIN field_event AS fe ON fe.id = fa.field_event_id
121+
JOIN thing AS t ON t.id = fe.thing_id
122+
WHERE
123+
t.thing_type = 'water well'
124+
AND fa.activity_type = 'groundwater level'
125+
AND o.value IS NOT NULL
126+
AND o.observation_datetime IS NOT NULL
127+
)
128+
SELECT
129+
t.id AS id,
130+
t.name,
131+
t.thing_type,
132+
ro.observation_id,
133+
ro.observation_datetime,
134+
l.elevation,
135+
ro.depth_to_water_below_ground_surface,
136+
(
137+
l.elevation - ro.depth_to_water_below_ground_surface
138+
) AS water_elevation,
139+
l.point
140+
FROM ranked_obs AS ro
141+
JOIN thing AS t ON t.id = ro.thing_id
142+
JOIN latest_location AS ll ON ll.thing_id = t.id
143+
JOIN location AS l ON l.id = ll.location_id
144+
WHERE ro.rn = 1
145+
"""
146+
147+
84148
def upgrade() -> None:
85149
bind = op.get_bind()
86150
inspector = inspect(bind)
@@ -107,7 +171,7 @@ def upgrade() -> None:
107171
op.execute(
108172
text(
109173
"COMMENT ON MATERIALIZED VIEW ogc_water_elevation_wells IS "
110-
"'Latest water elevation per well in feet; computed as (elevation_m * 3.28084) - depth_to_water_below_ground_surface_ft.'"
174+
"'Latest water elevation per well with explicit units: elevation_m, depth_to_water_below_ground_surface_ft, water_elevation_ft.'"
111175
)
112176
)
113177
op.execute(
@@ -120,3 +184,16 @@ def upgrade() -> None:
120184

121185
def downgrade() -> None:
122186
op.execute(text("DROP MATERIALIZED VIEW IF EXISTS ogc_water_elevation_wells"))
187+
op.execute(text(_create_water_elevation_view_m6()))
188+
op.execute(
189+
text(
190+
"COMMENT ON MATERIALIZED VIEW ogc_water_elevation_wells IS "
191+
"'Latest water elevation per well (elevation minus depth to water below ground surface).'"
192+
)
193+
)
194+
op.execute(
195+
text(
196+
"CREATE UNIQUE INDEX ux_ogc_water_elevation_wells_id "
197+
"ON ogc_water_elevation_wells (id)"
198+
)
199+
)

tests/test_ogc.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -336,16 +336,60 @@ def test_ogc_water_elevation_wells_computes_elevation_minus_depth_to_water(
336336

337337
row = session.execute(
338338
text(
339-
"SELECT elevation, depth_to_water_below_ground_surface, water_elevation "
339+
"SELECT elevation_m, depth_to_water_below_ground_surface_ft, water_elevation_ft "
340340
"FROM ogc_water_elevation_wells WHERE id = :thing_id"
341341
),
342342
{"thing_id": water_well_thing.id},
343343
).one()
344344

345-
assert float(row.depth_to_water_below_ground_surface) == 5.0
346-
assert float(row.elevation) == 2464.9
345+
assert float(row.depth_to_water_below_ground_surface_ft) == 5.0
346+
assert float(row.elevation_m) == 2464.9
347347
expected_water_elevation_ft = (2464.9 * 3.28084) - 5.0
348-
assert abs(float(row.water_elevation) - expected_water_elevation_ft) < 1e-9
348+
assert abs(float(row.water_elevation_ft) - expected_water_elevation_ft) < 1e-9
349+
350+
351+
def test_ogc_water_elevation_wells_normalizes_meter_observations_to_feet(
352+
water_well_thing, groundwater_level_observation
353+
):
354+
with session_ctx() as session:
355+
meter_observation = groundwater_level_observation.__class__(
356+
observation_datetime=datetime(2025, 1, 2, 0, 4, 0),
357+
sample_id=groundwater_level_observation.sample_id,
358+
sensor_id=groundwater_level_observation.sensor_id,
359+
parameter_id=groundwater_level_observation.parameter_id,
360+
release_status="draft",
361+
value=3.0,
362+
unit="m",
363+
measuring_point_height=2.0,
364+
groundwater_level_reason="Water level not affected",
365+
)
366+
session.add(meter_observation)
367+
session.commit()
368+
369+
session.execute(text("REFRESH MATERIALIZED VIEW ogc_water_elevation_wells"))
370+
session.commit()
371+
372+
row = session.execute(
373+
text(
374+
"SELECT depth_to_water_below_ground_surface_ft, water_elevation_ft "
375+
"FROM ogc_water_elevation_wells WHERE id = :thing_id"
376+
),
377+
{"thing_id": water_well_thing.id},
378+
).one()
379+
380+
expected_depth_ft = (3.0 * 3.28084) - 2.0
381+
expected_water_elevation_ft = (2464.9 * 3.28084) - expected_depth_ft
382+
383+
assert (
384+
abs(float(row.depth_to_water_below_ground_surface_ft) - expected_depth_ft)
385+
< 1e-9
386+
)
387+
assert abs(float(row.water_elevation_ft) - expected_water_elevation_ft) < 1e-9
388+
389+
session.delete(meter_observation)
390+
session.commit()
391+
session.execute(text("REFRESH MATERIALIZED VIEW ogc_water_elevation_wells"))
392+
session.commit()
349393

350394

351395
def test_ogc_collections():

0 commit comments

Comments
 (0)