fix(burst-location): use correct data sources
Simulation mode reads scheme data for both burst and normal observations. Monitoring mode reuses the burst window when no normal window is provided.
This commit is contained in:
@@ -190,7 +190,7 @@ def test_run_burst_location_uses_single_timerange_with_burst_source_split(monkey
|
||||
use_scada_flow=True,
|
||||
)
|
||||
|
||||
assert result["observed_source"] == "simulation_scheme_burst_realtime_normal_timerange"
|
||||
assert result["observed_source"] == "simulation_scheme_timerange"
|
||||
assert result["simulation_scheme"] == {
|
||||
"name": "BurstSchemeA",
|
||||
"type": "burst_analysis",
|
||||
@@ -199,22 +199,17 @@ def test_run_burst_location_uses_single_timerange_with_burst_source_split(monkey
|
||||
assert result["flow_samples"] == {"burst": 4, "normal": 4}
|
||||
assert list(captured["burst_pressure"].index) == ["J1"]
|
||||
assert captured["burst_pressure"]["J1"] == pytest.approx(15.0)
|
||||
assert captured["normal_pressure"]["J1"] == pytest.approx(11.0)
|
||||
assert captured["normal_pressure"]["J1"] == pytest.approx(15.0)
|
||||
assert captured["burst_flow"]["J2"] == pytest.approx(6.0)
|
||||
assert captured["burst_flow"]["P1"] == pytest.approx(8.0)
|
||||
assert captured["normal_flow"]["J2"] == pytest.approx(4.0)
|
||||
assert captured["normal_flow"]["P1"] == pytest.approx(5.0)
|
||||
assert captured["normal_flow"]["J2"] == pytest.approx(6.0)
|
||||
assert captured["normal_flow"]["P1"] == pytest.approx(8.0)
|
||||
assert all(call["scheme_name"] == "BurstSchemeA" for call in scheme_calls)
|
||||
assert len(scheme_calls) == 3
|
||||
assert len(scheme_calls) == 6
|
||||
assert any(call["element_type"] == "node" and call["field"] == "pressure" for call in scheme_calls)
|
||||
assert any(call["element_type"] == "link" and call["field"] == "flow" for call in scheme_calls)
|
||||
assert any(call["element_type"] == "node" and call["field"] == "actual_demand" for call in scheme_calls)
|
||||
assert len(realtime_calls) == 3
|
||||
assert all(datetime.fromisoformat(call["start_time"]).hour == 8 for call in realtime_calls)
|
||||
assert all(datetime.fromisoformat(call["end_time"]).hour == 9 for call in realtime_calls)
|
||||
assert any(call["element_type"] == "node" and call["field"] == "pressure" for call in realtime_calls)
|
||||
assert any(call["element_type"] == "link" and call["field"] == "flow" for call in realtime_calls)
|
||||
assert any(call["element_type"] == "node" and call["field"] == "actual_demand" for call in realtime_calls)
|
||||
assert realtime_calls == []
|
||||
assert result["scada_window"] == {
|
||||
"burst_start": "2025-01-01T08:00:00+00:00",
|
||||
"burst_end": "2025-01-01T09:00:00+00:00",
|
||||
@@ -296,7 +291,42 @@ def test_build_observed_series_from_simulation_normalizes_result_ids(monkeypatch
|
||||
assert series["100026"] == pytest.approx(12.0)
|
||||
|
||||
|
||||
def test_run_burst_location_monitoring_uses_scada_for_burst_and_realtime_for_normal(
|
||||
def test_build_observed_series_from_scada_uses_chinese_error_label(monkeypatch):
|
||||
module = _load_burst_location_module()
|
||||
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"get_all_scada_info",
|
||||
lambda network: [
|
||||
{
|
||||
"type": "pressure",
|
||||
"associated_element_id": "100026",
|
||||
"api_query_id": "pressure-query",
|
||||
}
|
||||
],
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
module.InternalQueries,
|
||||
"query_scada_by_ids_timerange",
|
||||
staticmethod(lambda **kwargs: {"pressure-query": []}),
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
module._build_observed_series_from_scada(
|
||||
network="tjwater",
|
||||
sensor_ids=["100026"],
|
||||
start_dt=datetime(2025, 1, 1, 0, 0, 0, tzinfo=timezone.utc),
|
||||
end_dt=datetime(2025, 1, 1, 1, 0, 0, tzinfo=timezone.utc),
|
||||
data_type="pressure",
|
||||
series_name="burst_pressure",
|
||||
)
|
||||
|
||||
message = str(exc_info.value)
|
||||
assert "爆管压力数据 在时间窗内无有效数据: 100026" in message
|
||||
assert "burst_pressure" not in message
|
||||
|
||||
|
||||
def test_run_burst_location_monitoring_uses_scada_for_burst_and_normal(
|
||||
monkeypatch, tmp_path
|
||||
):
|
||||
module = _load_burst_location_module()
|
||||
@@ -324,10 +354,12 @@ def test_run_burst_location_monitoring_uses_scada_for_burst_and_realtime_for_nor
|
||||
|
||||
def fake_scada_query(**kwargs):
|
||||
scada_calls.append(kwargs)
|
||||
start_hour = datetime.fromisoformat(kwargs["start_time"]).hour
|
||||
values = [20.0, 22.0] if start_hour == 8 else [10.0, 12.0]
|
||||
return {
|
||||
"pressure-query": [
|
||||
{"time": kwargs["start_time"], "value": 20.0},
|
||||
{"time": kwargs["end_time"], "value": 22.0},
|
||||
{"time": kwargs["start_time"], "value": values[0]},
|
||||
{"time": kwargs["end_time"], "value": values[1]},
|
||||
]
|
||||
}
|
||||
|
||||
@@ -358,10 +390,78 @@ def test_run_burst_location_monitoring_uses_scada_for_burst_and_realtime_for_nor
|
||||
burst_leakage=1.0,
|
||||
scada_burst_start=datetime(2025, 1, 1, 8, 0, 0),
|
||||
scada_burst_end=datetime(2025, 1, 1, 9, 0, 0),
|
||||
scada_normal_start=datetime(2025, 1, 1, 7, 0, 0),
|
||||
scada_normal_end=datetime(2025, 1, 1, 8, 0, 0),
|
||||
)
|
||||
|
||||
assert result["observed_source"] == "scada_burst_realtime_normal_timerange"
|
||||
assert len(scada_calls) == 1
|
||||
assert len(realtime_calls) == 1
|
||||
assert result["observed_source"] == "scada_burst_scada_normal_timerange"
|
||||
assert len(scada_calls) == 2
|
||||
assert len(realtime_calls) == 0
|
||||
assert captured["burst_pressure"]["J1"] == pytest.approx(21.0)
|
||||
assert captured["normal_pressure"]["J1"] == pytest.approx(11.0)
|
||||
assert result["scada_window"] == {
|
||||
"burst_start": "2025-01-01T08:00:00+00:00",
|
||||
"burst_end": "2025-01-01T09:00:00+00:00",
|
||||
"normal_start": "2025-01-01T07:00:00+00:00",
|
||||
"normal_end": "2025-01-01T08:00:00+00:00",
|
||||
}
|
||||
|
||||
|
||||
def test_run_burst_location_monitoring_reuses_burst_window_for_normal(
|
||||
monkeypatch, tmp_path
|
||||
):
|
||||
module = _load_burst_location_module()
|
||||
captured = {}
|
||||
scada_calls = []
|
||||
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"get_all_scada_info",
|
||||
lambda network: [
|
||||
{
|
||||
"type": "pressure",
|
||||
"associated_element_id": "J1",
|
||||
"api_query_id": "pressure-query",
|
||||
}
|
||||
],
|
||||
)
|
||||
monkeypatch.setattr(module, "_prepare_burst_inp", lambda network: str(tmp_path / "fake.inp"))
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"run_burst_location",
|
||||
lambda **kwargs: captured.update(kwargs) or {"located_pipe": "Pipe-001"},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
module.InternalQueries,
|
||||
"query_scada_by_ids_timerange",
|
||||
staticmethod(
|
||||
lambda **kwargs: scada_calls.append(kwargs)
|
||||
or {
|
||||
"pressure-query": [
|
||||
{"time": kwargs["start_time"], "value": 20.0},
|
||||
{"time": kwargs["end_time"], "value": 22.0},
|
||||
]
|
||||
}
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
module.InternalQueries,
|
||||
"query_realtime_simulation_by_ids_timerange",
|
||||
staticmethod(lambda **kwargs: pytest.fail("monitoring mode must not query realtime simulation")),
|
||||
)
|
||||
|
||||
result = module.run_burst_location_by_network(
|
||||
network="tjwater",
|
||||
username="testuser",
|
||||
data_source="monitoring",
|
||||
burst_leakage=1.0,
|
||||
scada_burst_start=datetime(2025, 1, 1, 8, 0, 0),
|
||||
scada_burst_end=datetime(2025, 1, 1, 9, 0, 0),
|
||||
)
|
||||
|
||||
assert result["observed_source"] == "scada_timerange"
|
||||
assert len(scada_calls) == 2
|
||||
assert scada_calls[0]["start_time"] == scada_calls[1]["start_time"]
|
||||
assert scada_calls[0]["end_time"] == scada_calls[1]["end_time"]
|
||||
assert captured["burst_pressure"]["J1"] == pytest.approx(21.0)
|
||||
assert captured["normal_pressure"]["J1"] == pytest.approx(21.0)
|
||||
|
||||
Reference in New Issue
Block a user