refactor(backend)!: separate algorithm and data layers

Reorganize algorithm packages by business responsibility, move orchestration into services, and keep database access behind pooled repositories.

Harden analysis API validation, remove unsafe legacy simulation endpoints, and add regression and architecture boundary coverage.

BREAKING CHANGE: legacy algorithm module paths and obsolete simulation endpoints are removed.
This commit is contained in:
2026-09-04 17:30:55 +08:00
parent 9b095c7439
commit 5966d039de
91 changed files with 1418 additions and 4020 deletions
@@ -0,0 +1,36 @@
"""Pipe-length-weighted demand allocation.
This module deliberately accepts plain topology data and performs no database
or file access. Application services are responsible for loading topology.
"""
from typing import Any, Mapping
def allocate_demand_by_pipe_length(
demand: float,
topology_nodes: Mapping[str, Mapping[str, Any]],
topology_links: Mapping[str, Mapping[str, Any]],
) -> dict[str, float]:
"""Allocate total demand to junctions by half of each incident link length."""
if not topology_nodes or not topology_links or demand == 0.0:
return {}
total_link_length = sum(
abs(float(link["length"])) for link in topology_links.values()
)
if total_link_length <= 0.0:
return {}
demand_per_length = demand / total_link_length
result: dict[str, float] = {}
for node_id, node in topology_nodes.items():
if node["type"] != "junction":
continue
incident_length = sum(
abs(float(topology_links[link_id]["length"]))
for link_id in node["links"]
)
result[node_id] = incident_length * demand_per_length * 0.5
return result