feat: improve D-InSAR pairing and distribution

This commit is contained in:
2026-05-09 14:59:20 +08:00
parent 69d15bffcb
commit 5c73e2c1c2
28 changed files with 1480 additions and 86 deletions
+20 -2
View File
@@ -33,8 +33,17 @@ class RadarDataORM(Base):
scene_center_lat = Column(Float, nullable=True)
acquisition_time_utc = Column(String, nullable=True)
product_type = Column(String, nullable=True)
source_product_token = Column(String, nullable=True)
image_data_type = Column(String, nullable=True)
image_data_format = Column(String, nullable=True)
product_variant = Column(String, nullable=True)
product_level = Column(String, nullable=True)
product_unique_id = Column(String, nullable=True)
satellite_family = Column(String, index=True, nullable=True)
look_direction = Column(String, index=True, nullable=True)
geocoded_flag = Column(Boolean, nullable=True)
insar_source_ready = Column(Boolean, nullable=False, default=False, server_default="false")
insar_source_reason = Column(Text, nullable=True)
file_path = Column(String, unique=True)
has_orbit_data = Column(Boolean)
orbit_file_path = Column(String, nullable=True)
@@ -179,6 +188,7 @@ class DinsarProductProfileORM(Base):
orbit_direction = Column(String, index=True, nullable=True)
time_baseline_days = Column(Integer, index=True, nullable=True)
spatial_baseline_meters = Column(Float, index=True, nullable=True)
scene_center_distance_meters = Column(Float, index=True, nullable=True)
grid_size_m = Column(Float, nullable=True)
radar_wavelength = Column(Float, nullable=True)
@@ -287,7 +297,7 @@ class PairingCacheStateORM(Base):
id = Column(Integer, primary_key=True, autoincrement=True)
cache_scope = Column(String(32), unique=True, index=True, nullable=False, default="global")
metric_version = Column(String(32), nullable=False, default="2026.04.v1")
metric_version = Column(String(32), nullable=False, default="2026.05.raw.v1")
status = Column(String(16), index=True, nullable=False, default="DIRTY")
scene_count = Column(Integer, nullable=False, default=0)
pair_count = Column(Integer, nullable=False, default=0)
@@ -338,23 +348,30 @@ class PairingMetricCacheORM(Base):
master_scene_uid = Column(String, index=True, nullable=False)
slave_scene_uid = Column(String, index=True, nullable=False)
pair_uid = Column(String, index=True, nullable=False)
metric_version = Column(String(32), index=True, nullable=False, default="2026.04.v1")
metric_version = Column(String(32), index=True, nullable=False, default="2026.05.raw.v1")
orientation_rule_version = Column(String(32), nullable=False, default="date_then_scene_uid_v1")
time_baseline_days = Column(Integer, index=True, nullable=True)
spatial_baseline_meters = Column(Float, index=True, nullable=True)
scene_center_distance_meters = Column(Float, index=True, nullable=True)
scene_overlap_ratio = Column(Float, index=True, nullable=True)
orbit_direction = Column(String, index=True, nullable=True)
same_satellite = Column(Boolean, nullable=False, default=True)
same_satellite_family = Column(Boolean, nullable=False, default=True, server_default="true")
same_look_direction = Column(Boolean, nullable=False, default=True, server_default="true")
same_imaging_mode = Column(Boolean, nullable=False, default=True)
same_polarization = Column(Boolean, nullable=False, default=True)
master_imaging_date = Column(String(8), index=True, nullable=True)
slave_imaging_date = Column(String(8), index=True, nullable=True)
master_satellite = Column(String, index=True, nullable=True)
slave_satellite = Column(String, index=True, nullable=True)
master_satellite_family = Column(String, index=True, nullable=True)
slave_satellite_family = Column(String, index=True, nullable=True)
master_imaging_mode = Column(String, nullable=True)
slave_imaging_mode = Column(String, nullable=True)
master_polarization = Column(String, nullable=True)
slave_polarization = Column(String, nullable=True)
master_look_direction = Column(String, nullable=True)
slave_look_direction = Column(String, nullable=True)
master_file_path = Column(String, nullable=True)
slave_file_path = Column(String, nullable=True)
status = Column(String(16), index=True, nullable=False, default="READY")
@@ -927,6 +944,7 @@ class DinsarTaskItemORM(Base):
slave_polarization = Column(String, nullable=True)
time_baseline_days = Column(Integer, nullable=True)
spatial_baseline_meters = Column(Float, nullable=True)
scene_center_distance_meters = Column(Float, nullable=True)
status = Column(String, index=True, nullable=False, default="PENDING")
remark = Column(Text, nullable=True)
+30 -1
View File
@@ -5,7 +5,7 @@ Pydantic Schema 定义。
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple, Union
from pydantic import BaseModel, ConfigDict, Field, computed_field, field_validator
from pydantic import BaseModel, ConfigDict, Field, computed_field, field_validator, model_validator
from ..config import read_int_env
@@ -178,8 +178,17 @@ class RadarData(BaseModel):
scene_center_lat: Optional[float] = None
acquisition_time_utc: Optional[str] = None
product_type: Optional[str] = None
source_product_token: Optional[str] = None
image_data_type: Optional[str] = None
image_data_format: Optional[str] = None
product_variant: Optional[str] = None
product_level: Optional[str] = None
product_unique_id: Optional[str] = None
satellite_family: Optional[str] = None
look_direction: Optional[str] = None
geocoded_flag: Optional[bool] = None
insar_source_ready: bool = False
insar_source_reason: Optional[str] = None
file_path: str
has_orbit_data: bool
orbit_file_path: Optional[str] = None
@@ -242,6 +251,9 @@ class PairingRequest(BaseModel):
require_same_imaging_mode: bool = True
require_same_polarization: bool = True
aoi_overlap_threshold: Optional[float] = Field(default=None, ge=0.0, le=1.0)
max_temporal_baseline_days: Optional[int] = Field(default=None, ge=1, le=3650)
pair_footprint_overlap_min_ratio: Optional[float] = Field(default=None, ge=0.0, le=1.0)
footprint_center_distance_max_meters: Optional[int] = Field(default=None, ge=0, le=100000)
# === 双池日期(新增) ===
master_date_from: Optional[str] = Field(default=None, pattern=r'^\d{8}$|^$')
@@ -261,6 +273,20 @@ class PairingRequest(BaseModel):
# === 向后兼容(保留) ===
start_date: Optional[str] = Field(default=None, pattern=r'^\d{8}$|^$')
@model_validator(mode='before')
@classmethod
def _apply_aliases(cls, data):
if not isinstance(data, dict):
return data
normalized = dict(data)
if normalized.get('max_temporal_baseline_days') not in (None, ''):
normalized['time_baseline_max'] = normalized['max_temporal_baseline_days']
if normalized.get('pair_footprint_overlap_min_ratio') not in (None, ''):
normalized['overlap_threshold'] = normalized['pair_footprint_overlap_min_ratio']
if normalized.get('footprint_center_distance_max_meters') not in (None, ''):
normalized['spatial_baseline_max_meters'] = normalized['footprint_center_distance_max_meters']
return normalized
@field_validator(
'master_date_from',
'master_date_to',
@@ -336,6 +362,7 @@ class RadarPair(BaseModel):
selection_reason: Optional[str] = None
time_baseline_days: int
spatial_baseline_meters: float
scene_center_distance_meters: Optional[float] = None
class PairingResponse(BaseModel):
@@ -413,6 +440,7 @@ class TimeseriesStackPlanEdge(BaseModel):
slave_imaging_date: Optional[str] = None
temporal_baseline_days: Optional[int] = None
spatial_baseline_meters: Optional[float] = None
scene_center_distance_meters: Optional[float] = None
perpendicular_baseline_meters: Optional[float] = None
scene_overlap_ratio: Optional[float] = None
pair_aoi_overlap_ratio: Optional[float] = None
@@ -518,6 +546,7 @@ class DinsarTaskItem(BaseModel):
slave_polarization: Optional[str] = None
time_baseline_days: Optional[int] = None
spatial_baseline_meters: Optional[float] = None
scene_center_distance_meters: Optional[float] = None
status: str
remark: Optional[str] = None
created_at: datetime