Integrate SBAS workflows and redesign task center
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
from backend.app.services.sbas_insar_production_service import SbasInsarProductionService
|
||||
|
||||
|
||||
def _scene(date, lon, lat, name=None, has_orbit=True):
|
||||
width = 1.0
|
||||
height = 1.0
|
||||
return {
|
||||
"scene_name": name or f"LT1B_MONO_SYC_STRIP1_000000_E{lon:.1f}_N{lat:.1f}_{date}_SLC_HH",
|
||||
"date": date,
|
||||
"satellite": "LT1B",
|
||||
"satellite_mode": "MONO",
|
||||
"receiving_station": "SYC",
|
||||
"relative_orbit": "114",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"center_lon": lon,
|
||||
"center_lat": lat,
|
||||
"center_bucket": f"E{lon:.1f}_N{lat:.1f}",
|
||||
"has_orbit": has_orbit,
|
||||
"bbox": {
|
||||
"min_lon": lon - width / 2,
|
||||
"min_lat": lat - height / 2,
|
||||
"max_lon": lon + width / 2,
|
||||
"max_lat": lat + height / 2,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_common_overlap_subgroups_preserve_viable_date_keyed_stack():
|
||||
service = SbasInsarProductionService()
|
||||
viable = [
|
||||
_scene("20240101", 129.20, 44.10),
|
||||
_scene("20240201", 129.22, 44.08),
|
||||
_scene("20240301", 129.18, 44.11),
|
||||
_scene("20240401", 129.21, 44.09),
|
||||
]
|
||||
distractors = [
|
||||
_scene("20240501", 129.80, 44.80),
|
||||
_scene("20240601", 129.85, 44.78),
|
||||
_scene("20240701", 129.82, 44.82),
|
||||
]
|
||||
|
||||
groups = service._build_discovery_scene_groups(
|
||||
observation_key="LT1B|MONO|SYC|114|DESCENDING|STRIP1|HH|E129.2_N44.1",
|
||||
group_scenes=viable + distractors,
|
||||
discovery_mode="strict",
|
||||
require_orbits=True,
|
||||
min_scenes=3,
|
||||
min_common_overlap_ratio=0.30,
|
||||
cluster_source="footprint_common_overlap",
|
||||
)
|
||||
candidates = [
|
||||
service._build_stack_candidate(
|
||||
group["scenes"],
|
||||
min_scenes=3,
|
||||
require_orbits=True,
|
||||
discovery_mode="strict",
|
||||
min_common_overlap_ratio=0.30,
|
||||
)
|
||||
for group in groups
|
||||
]
|
||||
ready = [candidate for candidate in candidates if candidate["status"] == "READY"]
|
||||
|
||||
assert ready
|
||||
assert any(
|
||||
set(candidate["dates"]) == {scene["date"] for scene in viable}
|
||||
and candidate["common_overlap_ratio"] >= 0.30
|
||||
for candidate in ready
|
||||
)
|
||||
|
||||
|
||||
def test_common_overlap_subgroups_do_not_drop_same_date_viable_branch():
|
||||
service = SbasInsarProductionService()
|
||||
viable = [
|
||||
_scene("20240101", 129.20, 44.10, name="viable_a"),
|
||||
_scene("20240201", 129.22, 44.08, name="viable_b"),
|
||||
_scene("20240301", 129.18, 44.11, name="viable_c"),
|
||||
]
|
||||
same_date_distractors = [
|
||||
_scene("20240101", 130.00, 44.90, name="distractor_a"),
|
||||
_scene("20240201", 130.02, 44.88, name="distractor_b"),
|
||||
_scene("20240301", 129.98, 44.91, name="distractor_c"),
|
||||
]
|
||||
|
||||
groups = service._build_discovery_scene_groups(
|
||||
observation_key="LT1B|MONO|SYC|114|DESCENDING|STRIP1|HH|E129.2_N44.1",
|
||||
group_scenes=viable + same_date_distractors,
|
||||
discovery_mode="strict",
|
||||
require_orbits=True,
|
||||
min_scenes=3,
|
||||
min_common_overlap_ratio=0.30,
|
||||
cluster_source="footprint_common_overlap",
|
||||
)
|
||||
|
||||
assert any(
|
||||
{scene["scene_name"] for scene in group["scenes"]} == {"viable_a", "viable_b", "viable_c"}
|
||||
for group in groups
|
||||
)
|
||||
|
||||
|
||||
def test_candidate_identity_marks_same_dates_with_different_scene_names():
|
||||
service = SbasInsarProductionService()
|
||||
first = [
|
||||
_scene("20240101", 129.20, 44.10, name="frame_a_20240101"),
|
||||
_scene("20240201", 129.22, 44.08, name="frame_a_20240201"),
|
||||
_scene("20240301", 129.18, 44.11, name="frame_a_20240301"),
|
||||
]
|
||||
second = [
|
||||
_scene("20240101", 129.70, 44.60, name="frame_b_20240101"),
|
||||
_scene("20240201", 129.72, 44.58, name="frame_b_20240201"),
|
||||
_scene("20240301", 129.68, 44.61, name="frame_b_20240301"),
|
||||
]
|
||||
candidates = [
|
||||
service._build_stack_candidate(
|
||||
scenes,
|
||||
min_scenes=3,
|
||||
require_orbits=True,
|
||||
discovery_mode="strict",
|
||||
min_common_overlap_ratio=0.30,
|
||||
)
|
||||
for scenes in (first, second)
|
||||
]
|
||||
|
||||
service._annotate_stack_candidate_identity(candidates, existing_run_index={})
|
||||
|
||||
assert candidates[0]["date_sequence_hash"] == candidates[1]["date_sequence_hash"]
|
||||
assert candidates[0]["scene_identity_hash"] != candidates[1]["scene_identity_hash"]
|
||||
assert all(candidate["same_date_sequence_candidate_count"] == 2 for candidate in candidates)
|
||||
assert all(candidate["same_date_sequence_distinct_scene_group_count"] == 2 for candidate in candidates)
|
||||
assert all(candidate["same_date_sequence_has_different_scene_groups"] is True for candidate in candidates)
|
||||
|
||||
|
||||
def test_candidate_identity_matches_existing_same_scene_run():
|
||||
service = SbasInsarProductionService()
|
||||
scenes = [
|
||||
_scene("20240101", 129.20, 44.10, name="same_a"),
|
||||
_scene("20240201", 129.22, 44.08, name="same_b"),
|
||||
_scene("20240301", 129.18, 44.11, name="same_c"),
|
||||
]
|
||||
candidate = service._build_stack_candidate(
|
||||
scenes,
|
||||
min_scenes=3,
|
||||
require_orbits=True,
|
||||
discovery_mode="strict",
|
||||
min_common_overlap_ratio=0.30,
|
||||
)
|
||||
scene_hash = service._scene_identity_summary(scenes)["scene_identity_hash"]
|
||||
|
||||
service._annotate_stack_candidate_identity(
|
||||
[candidate],
|
||||
existing_run_index={
|
||||
scene_hash: [
|
||||
{
|
||||
"run_id": "sbas_existing",
|
||||
"status": "WORKFLOW_COMPLETED",
|
||||
"stack_id": candidate["stack_id"],
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
|
||||
assert candidate["scene_identity_hash"] == scene_hash
|
||||
assert candidate["existing_same_scene_runs"][0]["run_id"] == "sbas_existing"
|
||||
Reference in New Issue
Block a user