Accept Merge Request #221: (region -> master)

Merge Request: Support region

Created By: @王琼钰
Accepted By: @王琼钰
URL: https://tjwater.coding.net/p/tjwatercloud/d/TJWaterServer/git/merge/221?initial=true
This commit is contained in:
王琼钰
2023-05-02 17:48:41 +08:00
55 changed files with 1938 additions and 664 deletions

BIN
api/CClipper2.dll Normal file

Binary file not shown.

BIN
api/CMetis.dll Normal file

Binary file not shown.

View File

@@ -18,8 +18,9 @@ from .database import get_operation_by_snapshot, get_snapshot_by_operation
from .database import pick_snapshot
from .database import pick_operation, sync_with_server
from .database import get_restore_operation, set_restore_operation, set_restore_operation_to_current, restore
from .database import read, try_read, read_all, write
from .batch_cmds import execute_batch_commands, execute_batch_command
from .batch_exe import execute_batch_commands, execute_batch_command
from .s0_base import JUNCTION, RESERVOIR, TANK, PIPE, PUMP, VALVE, PATTERN, CURVE
from .s0_base import is_node, is_junction, is_reservoir, is_tank
@@ -32,25 +33,25 @@ from .s0_base import get_node_links
from .s1_title import get_title_schema, get_title, set_title
from .s2_junctions import get_junction_schema, add_junction, get_junction, set_junction
from .del_cmd import delete_junction_cascade
from .batch_api import delete_junction_cascade
from .s3_reservoirs import get_reservoir_schema, add_reservoir, get_reservoir, set_reservoir
from .del_cmd import delete_reservoir_cascade
from .batch_api import delete_reservoir_cascade
from .s4_tanks import OVERFLOW_YES, OVERFLOW_NO
from .s4_tanks import get_tank_schema, add_tank, get_tank, set_tank
from .del_cmd import delete_tank_cascade
from .batch_api import delete_tank_cascade
from .s5_pipes import PIPE_STATUS_OPEN, PIPE_STATUS_CLOSED, PIPE_STATUS_CV
from .s5_pipes import get_pipe_schema, add_pipe, get_pipe, set_pipe
from .del_cmd import delete_pipe_cascade
from .batch_api import delete_pipe_cascade
from .s6_pumps import get_pump_schema, add_pump, get_pump, set_pump
from .del_cmd import delete_pump_cascade
from .batch_api import delete_pump_cascade
from .s7_valves import VALVES_TYPE_PRV, VALVES_TYPE_PSV, VALVES_TYPE_PBV, VALVES_TYPE_FCV, VALVES_TYPE_TCV, VALVES_TYPE_GPV
from .s7_valves import get_valve_schema, add_valve, get_valve, set_valve
from .del_cmd import delete_valve_cascade
from .batch_api import delete_valve_cascade
from .s8_tags import TAG_TYPE_NODE, TAG_TYPE_LINK
from .s8_tags import get_tag_schema, get_tags, get_tag, set_tag
@@ -61,11 +62,11 @@ from .s10_status import LINK_STATUS_OPEN, LINK_STATUS_CLOSED, LINK_STATUS_ACTIVE
from .s10_status import get_status_schema, get_status, set_status
from .s11_patterns import get_pattern_schema, get_pattern, set_pattern, add_pattern
from .del_cmd import delete_pattern_cascade
from .batch_api import delete_pattern_cascade
from .s12_curves import CURVE_TYPE_PUMP, CURVE_TYPE_EFFICIENCY, CURVE_TYPE_VOLUME, CURVE_TYPE_HEADLOSS
from .s12_curves import get_curve_schema, get_curve, set_curve, add_curve
from .del_cmd import delete_curve_cascade
from .batch_api import delete_curve_cascade
from .s13_controls import get_control_schema, get_control, set_control
@@ -98,7 +99,7 @@ from .s23_options_util import OPTION_UNBALANCED_STOP, OPTION_UNBALANCED_CONTINUE
from .s23_options_util import OPTION_DEMAND_MODEL_DDA, OPTION_DEMAND_MODEL_PDA
from .s23_options_util import OPTION_QUALITY_NONE, OPTION_QUALITY_CHEMICAL, OPTION_QUALITY_AGE, OPTION_QUALITY_TRACE
from .s23_options_util import get_option_schema, get_option
from .s23_options import set_option
from .batch_api import set_option_ex
from .s23_options_util import OPTION_V3_FLOW_UNITS_CFS, OPTION_V3_FLOW_UNITS_GPM, OPTION_V3_FLOW_UNITS_MGD, OPTION_V3_FLOW_UNITS_IMGD, OPTION_V3_FLOW_UNITS_AFD, OPTION_V3_FLOW_UNITS_LPS, OPTION_V3_FLOW_UNITS_LPM, OPTION_V3_FLOW_UNITS_MLD, OPTION_V3_FLOW_UNITS_CMH, OPTION_V3_FLOW_UNITS_CMD
from .s23_options_util import OPTION_V3_PRESSURE_UNITS_PSI, OPTION_V3_PRESSURE_UNITS_KPA, OPTION_V3_PRESSURE_UNITS_M
@@ -110,7 +111,7 @@ from .s23_options_util import OPTION_V3_LEAKAGE_MODEL_NONE, OPTION_V3_LEAKAGE_MO
from .s23_options_util import OPTION_V3_QUALITY_MODEL_NONE, OPTION_V3_QUALITY_MODEL_CHEMICAL, OPTION_V3_QUALITY_MODEL_AGE, OPTION_V3_QUALITY_MODEL_TRACE
from .s23_options_util import OPTION_V3_QUALITY_UNITS_HRS, OPTION_V3_QUALITY_UNITS_PCNT, OPTION_V3_QUALITY_UNITS_MGL, OPTION_V3_QUALITY_UNITS_UGL
from .s23_options_util import get_option_v3_schema, get_option_v3
from .s23_options_v3 import set_option_v3
from .batch_api import set_option_v3_ex
from .s24_coordinates import get_node_coord
@@ -122,12 +123,26 @@ from .s27_backdrop import get_backdrop_schema, get_backdrop, set_backdrop
from .s29_scada_device import SCADA_DEVICE_TYPE_PRESSURE, SCADA_DEVICE_TYPE_DEMAND, SCADA_DEVICE_TYPE_QUALITY, SCADA_DEVICE_TYPE_LEVEL, SCADA_DEVICE_TYPE_FLOW
from .s29_scada_device import get_scada_device_schema, get_scada_devices, get_scada_device, set_scada_device, add_scada_device, delete_scada_device
from .del_cmd import clean_scada_device
from .clean_api import clean_scada_device
from .s30_scada_device_data import get_scada_device_data_schema, get_scada_device_data, set_scada_device_data, add_scada_device_data, delete_scada_device_data
from .del_cmd import clean_scada_device_data
from .clean_api import clean_scada_device_data
from .s31_scada_element import SCADA_MODEL_TYPE_JUNCTION, SCADA_MODEL_TYPE_RESERVOIR, SCADA_MODEL_TYPE_TANK, SCADA_MODEL_TYPE_PIPE, SCADA_MODEL_TYPE_PUMP, SCADA_MODEL_TYPE_VALVE
from .s31_scada_element import SCADA_ELEMENT_STATUS_OFFLINE, SCADA_ELEMENT_STATUS_ONLINE
from .s31_scada_element import get_scada_element_schema, get_scada_elements, get_scada_element, set_scada_element, add_scada_element, delete_scada_element
from .del_cmd import clean_scada_element
from .clean_api import clean_scada_element
from .s32_region_util import get_nodes_in_boundary, get_nodes_in_region, calculate_convex_hull, calculate_boundary, inflate_boundary, inflate_region
from .s33_region import get_region_schema, get_region, set_region, add_region, delete_region
from .s34_water_distribution import DISTRIBUTION_TYPE_ADD, DISTRIBUTION_TYPE_OVERRIDE
from .s34_water_distribution import distribute_demand_to_nodes, distribute_demand_to_region
from .s35_district_metering_area import PARTITION_TYPE_RB, PARTITION_TYPE_KWAY
from .s35_district_metering_area import calculate_district_metering_area
from .s36_service_area import calculate_service_area
from .s37_virtual_district import calculate_virtual_district

53
api/batch_api.py Normal file
View File

@@ -0,0 +1,53 @@
from .sections import *
from .database import ChangeSet, API_DELETE, API_UPDATE
from .batch_exe import execute_batch_command
def delete_junction_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s2_junction }
return execute_batch_command(name, cs)
def delete_reservoir_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s3_reservoir }
return execute_batch_command(name, cs)
def delete_tank_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s4_tank }
return execute_batch_command(name, cs)
def delete_pipe_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s5_pipe }
return execute_batch_command(name, cs)
def delete_pump_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s6_pump }
return execute_batch_command(name, cs)
def delete_valve_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s7_valve }
return execute_batch_command(name, cs)
def delete_pattern_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s11_pattern }
return execute_batch_command(name, cs)
def delete_curve_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : s12_curve }
return execute_batch_command(name, cs)
def set_option_ex(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_UPDATE, 'type' : s23_option }
return execute_batch_command(name, cs)
def set_option_v3_ex(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_UPDATE, 'type' : s23_option_v3 }
return execute_batch_command(name, cs)

View File

@@ -18,8 +18,10 @@ from .s20_mixing import delete_mixing_by_tank
from .s25_vertices import delete_vertex_by_link
from .s26_labels import unset_label_by_node
from .s23_options_util import generate_v2, generate_v3
def delete_junction_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_junction_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -31,11 +33,11 @@ def delete_junction_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
for link in links:
if is_pipe(name, link):
result.merge(delete_pipe_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
if is_pump(name, link):
result.merge(delete_pump_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
if is_valve(name, link):
result.merge(delete_valve_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))
result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))
result.merge(delete_tag_by_node(name, id))
result.merge(delete_demand_by_junction(name, id))
@@ -48,7 +50,7 @@ def delete_junction_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_reservoir_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_reservoir_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -60,11 +62,11 @@ def delete_reservoir_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
for link in links:
if is_pipe(name, link):
result.merge(delete_pipe_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
if is_pump(name, link):
result.merge(delete_pump_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
if is_valve(name, link):
result.merge(delete_valve_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))
result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))
result.merge(delete_tag_by_node(name, id))
result.merge(delete_quality_by_node(name, id))
@@ -75,7 +77,7 @@ def delete_reservoir_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_tank_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_tank_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -87,11 +89,11 @@ def delete_tank_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
for link in links:
if is_pipe(name, link):
result.merge(delete_pipe_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
result.merge(delete_pipe_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pipe', 'id': link})))
if is_pump(name, link):
result.merge(delete_pump_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
result.merge(delete_pump_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'pump', 'id': link})))
if is_valve(name, link):
result.merge(delete_valve_cascade_batch_cmd(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))
result.merge(delete_valve_cascade_batch_cs(name, ChangeSet(g_delete_prefix | {'type': 'valve', 'id': link})))
result.merge(delete_tag_by_node(name, id))
result.merge(delete_quality_by_node(name, id))
@@ -104,7 +106,7 @@ def delete_tank_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_pipe_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_pipe_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -121,7 +123,7 @@ def delete_pipe_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_pump_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_pump_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -138,7 +140,7 @@ def delete_pump_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_valve_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_valve_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -155,7 +157,7 @@ def delete_valve_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_pattern_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_pattern_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -173,7 +175,7 @@ def delete_pattern_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def delete_curve_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
def delete_curve_cascade_batch_cs(name: str, cs: ChangeSet) -> ChangeSet:
result = ChangeSet()
id = cs.operations[0]['id']
@@ -189,24 +191,48 @@ def delete_curve_cascade_batch_cmd(name: str, cs: ChangeSet) -> ChangeSet:
return result
def del_cascade_cmd(name: str, cs: ChangeSet) -> ChangeSet:
type = cs.operations[0]['type']
def set_option_cs(cs: ChangeSet) -> ChangeSet:
cs.operations[0]['operation'] = API_UPDATE
cs.operations[0]['type'] = 'option'
new_cs = cs
new_cs.merge(generate_v3(cs))
return new_cs
if type == s2_junction:
return delete_junction_cascade_batch_cmd(name, cs)
elif type == s3_reservoir:
return delete_reservoir_cascade_batch_cmd(name, cs)
elif type == s4_tank:
return delete_tank_cascade_batch_cmd(name, cs)
elif type == s5_pipe:
return delete_pipe_cascade_batch_cmd(name, cs)
elif type == s6_pump:
return delete_pump_cascade_batch_cmd(name, cs)
elif type == s7_valve:
return delete_valve_cascade_batch_cmd(name, cs)
elif type == s11_pattern:
return delete_pattern_cascade_batch_cmd(name, cs)
elif type == s12_curve:
return delete_curve_cascade_batch_cmd(name, cs)
def set_option_v3_cs(cs: ChangeSet) -> ChangeSet:
cs.operations[0]['operation'] = API_UPDATE
cs.operations[0]['type'] = 'option_v3'
new_cs = cs
new_cs.merge(generate_v2(cs))
return new_cs
def rewrite_batch_api(name: str, cs: ChangeSet) -> ChangeSet:
op = cs.operations[0]
api = op['operation']
type = op['type']
if api == API_DELETE:
if type == s2_junction:
return delete_junction_cascade_batch_cs(name, cs)
elif type == s3_reservoir:
return delete_reservoir_cascade_batch_cs(name, cs)
elif type == s4_tank:
return delete_tank_cascade_batch_cs(name, cs)
elif type == s5_pipe:
return delete_pipe_cascade_batch_cs(name, cs)
elif type == s6_pump:
return delete_pump_cascade_batch_cs(name, cs)
elif type == s7_valve:
return delete_valve_cascade_batch_cs(name, cs)
elif type == s11_pattern:
return delete_pattern_cascade_batch_cs(name, cs)
elif type == s12_curve:
return delete_curve_cascade_batch_cs(name, cs)
elif api == API_UPDATE:
if type == s23_option:
return set_option_cs(cs)
elif type == s23_option_v3:
return set_option_v3_cs(cs)
return cs

View File

@@ -1,304 +0,0 @@
from .sections import *
from .database import API_ADD, API_UPDATE, API_DELETE, ChangeSet, DbChangeSet, execute_command
from .s1_title import set_title_cmd
from .s2_junctions import set_junction_cmd, add_junction_cmd, delete_junction_cmd
from .s3_reservoirs import set_reservoir_cmd, add_reservoir_cmd, delete_reservoir_cmd
from .s4_tanks import set_tank_cmd, add_tank_cmd, delete_tank_cmd
from .s5_pipes import set_pipe_cmd, add_pipe_cmd, delete_pipe_cmd
from .s6_pumps import set_pump_cmd, add_pump_cmd, delete_pump_cmd
from .s7_valves import set_valve_cmd, add_valve_cmd, delete_valve_cmd
from .s8_tags import set_tag_cmd
from .s9_demands import set_demand_cmd
from .s10_status import set_status_cmd
from .s11_patterns import set_pattern_cmd, add_pattern_cmd, delete_pattern_cmd
from .s12_curves import set_curve_cmd, add_curve_cmd, delete_curve_cmd
from .s13_controls import set_control_cmd
from .s14_rules import set_rule_cmd
from .s15_energy import set_energy_cmd, set_pump_energy_cmd
from .s16_emitters import set_emitter_cmd
from .s17_quality import set_quality_cmd
from .s18_sources import set_source_cmd, add_source_cmd, delete_source_cmd
from .s19_reactions import set_reaction_cmd, set_pipe_reaction_cmd, set_tank_reaction_cmd
from .s20_mixing import set_mixing_cmd, add_mixing_cmd, delete_mixing_cmd
from .s21_times import set_time_cmd
#from .s22_report import *
from .s23_options_util import set_option_cmd, set_option_v3_cmd
#from .s24_coordinates import *
from .s25_vertices import set_vertex_cmd, add_vertex_cmd, delete_vertex_cmd
from .s26_labels import set_label_cmd, add_label_cmd, delete_label_cmd
from .s27_backdrop import set_backdrop_cmd
# from .s28_end import *
from .s29_scada_device import set_scada_device_cmd, add_scada_device_cmd, delete_scada_device_cmd
from .s30_scada_device_data import set_scada_device_data_cmd, add_scada_device_data_cmd, delete_scada_device_data_cmd
from .s31_scada_element import set_scada_element_cmd, add_scada_element_cmd, delete_scada_element_cmd
from .del_cmd_raw import del_cascade_cmd
def add_cmd(name: str, cs: ChangeSet) -> DbChangeSet | None:
type = cs.operations[0]['type']
if type == s1_title:
return None
if type == s2_junction:
return add_junction_cmd(name, cs)
elif type == s3_reservoir:
return add_reservoir_cmd(name, cs)
elif type == s4_tank:
return add_tank_cmd(name, cs)
elif type == s5_pipe:
return add_pipe_cmd(name, cs)
elif type == s6_pump:
return add_pump_cmd(name, cs)
elif type == s7_valve:
return add_valve_cmd(name, cs)
elif type == s8_tag:
return None
elif type == s9_demand:
return None
elif type == s10_status:
return None
elif type == s11_pattern:
return add_pattern_cmd(name, cs)
elif type == s12_curve:
return add_curve_cmd(name, cs)
elif type == s13_control:
return None
elif type == s14_rule:
return None
elif type == s15_energy:
return None
elif type == s15_pump_energy:
return None
elif type == s16_emitter:
return None
elif type == s17_quality:
return None
elif type == s18_source:
return add_source_cmd(name, cs)
elif type == s19_reaction:
return None
elif type == s19_pipe_reaction:
return None
elif type == s19_tank_reaction:
return None
elif type == s20_mixing:
return add_mixing_cmd(name, cs)
elif type == s21_time:
return None
elif type == s22_report:
return None
elif type == s23_option:
return None
elif type == s23_option_v3:
return None
elif type == s24_coordinate:
return None
elif type == s25_vertex:
return add_vertex_cmd(name, cs)
elif type == s26_label:
return add_label_cmd(name, cs)
elif type == s27_backdrop:
return None
elif type == s28_end:
return None
elif type == s29_scada_device:
return add_scada_device_cmd(name, cs)
elif type == s30_scada_device_data:
return add_scada_device_data_cmd(name, cs)
elif type == s31_scada_element:
return add_scada_element_cmd(name, cs)
return None
def set_cmd(name: str, cs: ChangeSet) -> DbChangeSet | None:
type = cs.operations[0]['type']
if type == s1_title:
return set_title_cmd(name, cs)
if type == s2_junction:
return set_junction_cmd(name, cs)
elif type == s3_reservoir:
return set_reservoir_cmd(name, cs)
elif type == s4_tank:
return set_tank_cmd(name, cs)
elif type == s5_pipe:
return set_pipe_cmd(name, cs)
elif type == s6_pump:
return set_pump_cmd(name, cs)
elif type == s7_valve:
return set_valve_cmd(name, cs)
elif type == s8_tag:
return set_tag_cmd(name, cs)
elif type == s9_demand:
return set_demand_cmd(name, cs)
elif type == s10_status:
return set_status_cmd(name, cs)
elif type == s11_pattern:
return set_pattern_cmd(name, cs)
elif type == s12_curve:
return set_curve_cmd(name, cs)
elif type == s13_control:
return set_control_cmd(name, cs)
elif type == s14_rule:
return set_rule_cmd(name, cs)
elif type == s15_energy:
return set_energy_cmd(name, cs)
elif type == s15_pump_energy:
return set_pump_energy_cmd(name, cs)
elif type == s16_emitter:
return set_emitter_cmd(name, cs)
elif type == s17_quality:
return set_quality_cmd(name, cs)
elif type == s18_source:
return set_source_cmd(name, cs)
elif type == s19_reaction:
return set_reaction_cmd(name, cs)
elif type == s19_pipe_reaction:
return set_pipe_reaction_cmd(name, cs)
elif type == s19_tank_reaction:
return set_tank_reaction_cmd(name, cs)
elif type == s20_mixing:
return set_mixing_cmd(name, cs)
elif type == s21_time:
return set_time_cmd(name, cs)
elif type == s22_report: # no api now
return None
elif type == s23_option:
return set_option_cmd(name, cs)
elif type == s23_option_v3:
return set_option_v3_cmd(name, cs)
elif type == s24_coordinate: # do not support update here
return None
elif type == s25_vertex:
return set_vertex_cmd(name, cs)
elif type == s26_label:
return set_label_cmd(name, cs)
elif type == s27_backdrop:
return set_backdrop_cmd(name, cs)
elif type == s28_end: # end
return None
elif type == s29_scada_device:
return set_scada_device_cmd(name, cs)
elif type == s30_scada_device_data:
return set_scada_device_data_cmd(name, cs)
elif type == s31_scada_element:
return set_scada_element_cmd(name, cs)
return None
def del_cmd(name: str, cs: ChangeSet) -> DbChangeSet | None:
type = cs.operations[0]['type']
if type == s1_title:
return None
if type == s2_junction:
return delete_junction_cmd(name, cs)
elif type == s3_reservoir:
return delete_reservoir_cmd(name, cs)
elif type == s4_tank:
return delete_tank_cmd(name, cs)
elif type == s5_pipe:
return delete_pipe_cmd(name, cs)
elif type == s6_pump:
return delete_pump_cmd(name, cs)
elif type == s7_valve:
return delete_valve_cmd(name, cs)
elif type == s8_tag:
return None
elif type == s9_demand:
return None
elif type == s10_status:
return None
elif type == s11_pattern:
return delete_pattern_cmd(name, cs)
elif type == s12_curve:
return delete_curve_cmd(name, cs)
elif type == s13_control:
return None
elif type == s14_rule:
return None
elif type == s15_energy:
return None
elif type == s15_pump_energy:
return None
elif type == s16_emitter:
return None
elif type == s17_quality:
return None
elif type == s18_source:
return delete_source_cmd(name, cs)
elif type == s19_reaction:
return None
elif type == s19_pipe_reaction:
return None
elif type == s19_tank_reaction:
return None
elif type == s20_mixing:
return delete_mixing_cmd(name, cs)
elif type == s21_time:
return None
elif type == s22_report:
return None
elif type == s23_option:
return None
elif type == s23_option_v3:
return None
elif type == s24_coordinate:
return None
elif type == s25_vertex:
return delete_vertex_cmd(name, cs)
elif type == s26_label:
return delete_label_cmd(name, cs)
elif type == s27_backdrop:
return None
elif type == s28_end:
return None
elif type == s29_scada_device:
return delete_scada_device_cmd(name, cs)
elif type == s30_scada_device_data:
return delete_scada_device_data_cmd(name, cs)
elif type == s31_scada_element:
return delete_scada_element_cmd(name, cs)
return None
def execute_batch_command(name: str, cs: ChangeSet) -> ChangeSet:
css: list[DbChangeSet] = []
# for delete, generate cascade command
new_cs = ChangeSet()
for op in cs.operations:
if op['operation'] == API_DELETE:
new_cs.merge(del_cascade_cmd(name, ChangeSet(op)))
else:
new_cs.merge(ChangeSet(op))
try:
for op in new_cs.operations:
operation = op['operation']
r = None
if operation == API_ADD:
r = add_cmd(name, ChangeSet(op))
elif operation == API_UPDATE:
r = set_cmd(name, ChangeSet(op))
elif operation == API_DELETE:
r = del_cmd(name, ChangeSet(op))
if r == None:
print(f'ERROR: Build [{op}] returns None')
return ChangeSet()
css.append(r)
except:
return ChangeSet()
try:
return execute_command(name, DbChangeSet.from_list(css))
except:
return ChangeSet()

View File

@@ -22,21 +22,17 @@ from .s18_sources import set_source, add_source, delete_source
from .s19_reactions import set_reaction, set_pipe_reaction, set_tank_reaction
from .s20_mixing import set_mixing, add_mixing, delete_mixing
from .s21_times import set_time
#from .s22_report import *
from .s23_options import set_option
from .s23_options_v3 import set_option_v3
#from .s24_coordinates import *
from .s23_options_util import set_option, set_option_v3
from .s25_vertices import set_vertex, add_vertex, delete_vertex
from .s26_labels import set_label, add_label, delete_label
from .s27_backdrop import set_backdrop
# from .s28_end import *
from .s29_scada_device import set_scada_device, add_scada_device, delete_scada_device
from .s30_scada_device_data import set_scada_device_data, add_scada_device_data, delete_scada_device_data
from .s31_scada_element import set_scada_element, add_scada_element, delete_scada_element
from .del_cmd_raw import del_cascade_cmd
from .batch_api_cs import rewrite_batch_api
def execute_add_command(name: str, cs: ChangeSet) -> ChangeSet:
def _execute_add_command(name: str, cs: ChangeSet) -> ChangeSet:
type = cs.operations[0]['type']
if type == s1_title:
@@ -113,7 +109,7 @@ def execute_add_command(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
def execute_update_command(name: str, cs: ChangeSet) -> ChangeSet:
def _execute_update_command(name: str, cs: ChangeSet) -> ChangeSet:
type = cs.operations[0]['type']
if type == s1_title:
@@ -190,7 +186,7 @@ def execute_update_command(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
def execute_delete_command(name: str, cs: ChangeSet) -> ChangeSet:
def _execute_delete_command(name: str, cs: ChangeSet) -> ChangeSet:
type = cs.operations[0]['type']
if type == s1_title:
@@ -268,13 +264,9 @@ def execute_delete_command(name: str, cs: ChangeSet) -> ChangeSet:
def execute_batch_commands(name: str, cs: ChangeSet) -> ChangeSet:
# for delete, generate cascade command
new_cs = ChangeSet()
for op in cs.operations:
if op['operation'] == API_DELETE:
new_cs.merge(del_cascade_cmd(name, ChangeSet(op)))
else:
new_cs.merge(ChangeSet(op))
new_cs.merge(rewrite_batch_api(name, ChangeSet(op)))
result = ChangeSet()
@@ -285,11 +277,11 @@ def execute_batch_commands(name: str, cs: ChangeSet) -> ChangeSet:
todo = op
operation = op['operation']
if operation == API_ADD:
result.merge(execute_add_command(name, ChangeSet(op)))
result.merge(_execute_add_command(name, ChangeSet(op)))
elif operation == API_UPDATE:
result.merge(execute_update_command(name, ChangeSet(op)))
result.merge(_execute_update_command(name, ChangeSet(op)))
elif operation == API_DELETE:
result.merge(execute_delete_command(name, ChangeSet(op)))
result.merge(_execute_delete_command(name, ChangeSet(op)))
except:
print(f'ERROR: Fail to execute {todo}')
@@ -300,13 +292,9 @@ def execute_batch_command(name: str, cs: ChangeSet) -> ChangeSet:
write(name, 'delete from batch_operation where id > 0')
write(name, "update operation_table set option = 'batch_operation' where option = 'operation'")
# for delete, generate cascade command
new_cs = ChangeSet()
for op in cs.operations:
if op['operation'] == API_DELETE:
new_cs.merge(del_cascade_cmd(name, ChangeSet(op)))
else:
new_cs.merge(ChangeSet(op))
new_cs.merge(rewrite_batch_api(name, ChangeSet(op)))
result = ChangeSet()
@@ -317,11 +305,11 @@ def execute_batch_command(name: str, cs: ChangeSet) -> ChangeSet:
todo = op
operation = op['operation']
if operation == API_ADD:
result.merge(execute_add_command(name, ChangeSet(op)))
result.merge(_execute_add_command(name, ChangeSet(op)))
elif operation == API_UPDATE:
result.merge(execute_update_command(name, ChangeSet(op)))
result.merge(_execute_update_command(name, ChangeSet(op)))
elif operation == API_DELETE:
result.merge(execute_delete_command(name, ChangeSet(op)))
result.merge(_execute_delete_command(name, ChangeSet(op)))
except:
print(f'ERROR: Fail to execute {todo}')

45
api/clean_api.py Normal file
View File

@@ -0,0 +1,45 @@
from .database import ChangeSet, read_all
from .batch_exe import execute_batch_command
# TODO: merge to batch_api
def clean_scada_device_cs(name: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, 'select id from scada_device acs')
for row in rows:
cs.delete({ 'type': 'scada_device', 'id': row['id'] })
return cs
def clean_scada_device_data_cs(name: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, 'select distinct device_id from scada_device_data acs')
for row in rows:
cs.update({ 'type': 'scada_device_data', 'device_id': row['device_id'], 'data': [] })
return cs
def clean_scada_element_cs(name: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, 'select id from scada_element acs')
for row in rows:
cs.delete({ 'type': 'scada_element', 'id': row['id'] })
return cs
def clean_scada_device(name: str) -> ChangeSet:
return execute_batch_command(name, clean_scada_device_cs(name))
def clean_scada_device_data(name: str) -> ChangeSet:
return execute_batch_command(name, clean_scada_device_data_cs(name))
def clean_scada_element(name: str) -> ChangeSet:
return execute_batch_command(name, clean_scada_element_cs(name))

View File

@@ -1,65 +0,0 @@
from .del_cmd_raw import *
from .batch_cmd import execute_batch_command
from .s29_scada_device import clean_scada_device_cmd
from .s30_scada_device_data import clean_scada_device_data_cmd
from .s31_scada_element import clean_scada_element_cmd
def delete_junction_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'junction' }
#raw_cmd = delete_junction_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_reservoir_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'reservoir' }
#raw_cmd = delete_reservoir_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_tank_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'tank' }
#raw_cmd = delete_tank_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_pipe_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'pipe' }
#raw_cmd = delete_pipe_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_pump_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'pump' }
#raw_cmd = delete_pump_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_valve_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'valve' }
#raw_cmd = delete_valve_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_pattern_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'pattern' }
#raw_cmd = delete_pattern_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def delete_curve_cascade(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0] |= { 'operation' : API_DELETE, 'type' : 'curve' }
#raw_cmd = delete_curve_cascade_batch_cmd(name, cs)
return execute_batch_command(name, cs)
def clean_scada_device(name: str) -> ChangeSet:
return execute_batch_command(name, clean_scada_device_cmd(name))
def clean_scada_device_data(name: str) -> ChangeSet:
return execute_batch_command(name, clean_scada_device_data_cmd(name))
def clean_scada_element(name: str) -> ChangeSet:
return execute_batch_command(name, clean_scada_element_cmd(name))

View File

@@ -40,7 +40,9 @@ def dump_inp(project: str, inp: str, version: str = '3'):
if not have_project(project):
return
if not is_project_open(project):
project_open = is_project_open(project)
if not project_open:
open_project(project)
dir = os.getcwd()
@@ -154,7 +156,8 @@ def dump_inp(project: str, inp: str, version: str = '3'):
file.close()
close_project(project)
if not project_open:
close_project(project)
def export_inp(project: str, version: str = '3') -> ChangeSet:

View File

@@ -1,5 +1,6 @@
from psycopg.rows import dict_row, Row
from .connection import g_conn_dict as conn
from .database import read
_NODE = '_node'
@@ -105,3 +106,14 @@ def get_node_links(name: str, id: str) -> list[str]:
for p in cur.execute(f"select id from valves where node1 = '{id}' or node2 = '{id}'").fetchall():
links.append(p['id'])
return links
def get_link_nodes(name: str, id: str) -> list[str]:
row = {}
if is_pipe(name, id):
row = read(name, f"select node1, node2 from pipes where id = '{id}'")
elif is_pump(name, id):
row = read(name, f"select node1, node2 from pumps where id = '{id}'")
elif is_valve(name, id):
row = read(name, f"select node1, node2 from valves where id = '{id}'")
return [str(row['node1']), str(row['node2'])]

View File

@@ -39,7 +39,7 @@ class Status(object):
return { 'type': self.type, 'link': self.link, 'status': self.status, 'setting': self.setting }
def set_status_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_status(name: str, cs: ChangeSet) -> DbChangeSet:
old = Status(get_status(name, cs.operations[0]['link']))
raw_new = get_status(name, cs.operations[0]['link'])
@@ -65,7 +65,7 @@ def set_status_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_status(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_status_cmd(name, cs))
return execute_command(name, _set_status(name, cs))
#--------------------------------------------------------------

View File

@@ -21,7 +21,7 @@ def get_pattern(name: str, id: str) -> dict[str, Any]:
return { 'id': id, 'factors': ps }
def set_pattern_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_pattern(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
f_id = f"'{id}'"
@@ -53,10 +53,10 @@ def set_pattern(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pattern(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_pattern_cmd(name, cs))
return execute_command(name, _set_pattern(name, cs))
def add_pattern_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_pattern(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
f_id = f"'{id}'"
@@ -81,10 +81,10 @@ def add_pattern(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pattern(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_pattern_cmd(name, cs))
return execute_command(name, _add_pattern(name, cs))
def delete_pattern_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_pattern(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
f_id = f"'{id}'"
@@ -109,7 +109,7 @@ def delete_pattern(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pattern(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_pattern_cmd(name, cs))
return execute_command(name, _delete_pattern(name, cs))
#--------------------------------------------------------------

View File

@@ -30,7 +30,7 @@ def get_curve(name: str, id: str) -> dict[str, Any]:
return d
def set_curve_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_curve(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
f_id = f"'{id}'"
@@ -72,10 +72,10 @@ def set_curve(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_curve(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_curve_cmd(name, cs))
return execute_command(name, _set_curve(name, cs))
def add_curve_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_curve(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
f_id = f"'{id}'"
@@ -104,10 +104,10 @@ def add_curve(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_curve(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_curve_cmd(name, cs))
return execute_command(name, _add_curve(name, cs))
def delete_curve_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_curve(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
f_id = f"'{id}'"
@@ -134,7 +134,7 @@ def delete_curve(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_curve(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_curve_cmd(name, cs))
return execute_command(name, _delete_curve(name, cs))
#--------------------------------------------------------------

View File

@@ -13,7 +13,7 @@ def get_control(name: str) -> dict[str, Any]:
return { 'controls': ds }
def set_control_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_control(name: str, cs: ChangeSet) -> DbChangeSet:
old = get_control(name)
redo_sql = 'delete from controls;'
@@ -31,7 +31,7 @@ def set_control_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_control(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_control_cmd(name, cs))
return execute_command(name, _set_control(name, cs))
#--------------------------------------------------------------

View File

@@ -13,7 +13,7 @@ def get_rule(name: str) -> dict[str, Any]:
return { 'rules': ds }
def set_rule_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_rule(name: str, cs: ChangeSet) -> DbChangeSet:
old = get_rule(name)
redo_sql = 'delete from rules;'
@@ -31,7 +31,7 @@ def set_rule_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_rule(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_rule_cmd(name, cs))
return execute_command(name, _set_rule(name, cs))
#--------------------------------------------------------------

View File

@@ -19,7 +19,7 @@ def get_energy(name: str) -> dict[str, Any]:
return d
def set_energy_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_energy(name: str, cs: ChangeSet) -> DbChangeSet:
raw_old = get_energy(name)
old = {}
@@ -54,7 +54,7 @@ def set_energy_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_energy(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_energy_cmd(name, cs))
return execute_command(name, _set_energy(name, cs))
def get_pump_energy_schema(name: str) -> dict[str, dict[str, Any]]:
@@ -94,7 +94,7 @@ class PumpEnergy(object):
return { 'type': self.type, 'pump': self.pump, 'price': self.price, 'pattern': self.pattern, 'effic': self.effic }
def set_pump_energy_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_pump_energy(name: str, cs: ChangeSet) -> DbChangeSet:
old = PumpEnergy(get_pump_energy(name, cs.operations[0]['pump']))
raw_new = get_pump_energy(name, cs.operations[0]['pump'])
@@ -128,7 +128,7 @@ def set_pump_energy_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_pump_energy(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_pump_energy_cmd(name, cs))
return execute_command(name, _set_pump_energy(name, cs))
#--------------------------------------------------------------

View File

@@ -30,7 +30,7 @@ class Emitter(object):
return { 'type': self.type, 'junction': self.junction, 'coefficient': self.coefficient }
def set_emitter_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_emitter(name: str, cs: ChangeSet) -> DbChangeSet:
old = Emitter(get_emitter(name, cs.operations[0]['junction']))
raw_new = get_emitter(name, cs.operations[0]['junction'])
@@ -56,7 +56,7 @@ def set_emitter_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_emitter(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_emitter_cmd(name, cs))
return execute_command(name, _set_emitter(name, cs))
#--------------------------------------------------------------

View File

@@ -30,7 +30,7 @@ class Quality(object):
return { 'type': self.type, 'node': self.node, 'quality': self.quality }
def set_quality_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_quality(name: str, cs: ChangeSet) -> DbChangeSet:
old = Quality(get_quality(name, cs.operations[0]['node']))
raw_new = get_quality(name, cs.operations[0]['node'])
@@ -56,7 +56,7 @@ def set_quality_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_quality(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_quality_cmd(name, cs))
return execute_command(name, _set_quality(name, cs))
#--------------------------------------------------------------

View File

@@ -46,7 +46,7 @@ class Source(object):
return { 'type': self.type, 'node': self.node }
def set_source_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_source(name: str, cs: ChangeSet) -> DbChangeSet:
old = Source(get_source(name, cs.operations[0]['node']))
raw_new = get_source(name, cs.operations[0]['node'])
@@ -67,10 +67,10 @@ def set_source_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_source(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_source_cmd(name, cs))
return execute_command(name, _set_source(name, cs))
def add_source_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_source(name: str, cs: ChangeSet) -> DbChangeSet:
new = Source(cs.operations[0])
redo_sql = f"insert into sources (node, type, strength, pattern) values ({new.f_node}, {new.f_s_type}, {new.f_strength}, {new.f_pattern});"
@@ -83,10 +83,10 @@ def add_source_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def add_source(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, add_source_cmd(name, cs))
return execute_command(name, _add_source(name, cs))
def delete_source_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_source(name: str, cs: ChangeSet) -> DbChangeSet:
old = Source(get_source(name, cs.operations[0]['node']))
redo_sql = f"delete from sources where node = {old.f_node};"
@@ -99,7 +99,7 @@ def delete_source_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def delete_source(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, delete_source_cmd(name, cs))
return execute_command(name, _delete_source(name, cs))
#--------------------------------------------------------------

View File

@@ -22,7 +22,7 @@ def get_reaction(name: str) -> dict[str, Any]:
return d
def set_reaction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_reaction(name: str, cs: ChangeSet) -> DbChangeSet:
raw_old = get_reaction(name)
old = {}
@@ -57,7 +57,7 @@ def set_reaction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_reaction(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_reaction_cmd(name, cs))
return execute_command(name, _set_reaction(name, cs))
def get_pipe_reaction_schema(name: str) -> dict[str, dict[str, Any]]:
@@ -92,7 +92,7 @@ class PipeReaction(object):
return { 'type': self.type, 'pipe': self.pipe, 'bulk': self.bulk, 'wall': self.wall }
def set_pipe_reaction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_pipe_reaction(name: str, cs: ChangeSet) -> DbChangeSet:
old = PipeReaction(get_pipe_reaction(name, cs.operations[0]['pipe']))
raw_new = get_pipe_reaction(name, cs.operations[0]['pipe'])
@@ -122,7 +122,7 @@ def set_pipe_reaction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_pipe_reaction(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_pipe_reaction_cmd(name, cs))
return execute_command(name, _set_pipe_reaction(name, cs))
def get_tank_reaction_schema(name: str) -> dict[str, dict[str, Any]]:
@@ -152,7 +152,7 @@ class TankReaction(object):
return { 'type': self.type, 'tank': self.tank, 'value': self.value }
def set_tank_reaction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_tank_reaction(name: str, cs: ChangeSet) -> DbChangeSet:
old = TankReaction(get_tank_reaction(name, cs.operations[0]['tank']))
raw_new = get_tank_reaction(name, cs.operations[0]['tank'])
@@ -178,7 +178,7 @@ def set_tank_reaction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_tank_reaction(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_tank_reaction_cmd(name, cs))
return execute_command(name, _set_tank_reaction(name, cs))
#--------------------------------------------------------------

View File

@@ -10,7 +10,7 @@ def get_title(name: str) -> dict[str, Any]:
return { 'value': title['value'] }
def set_title_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_title(name: str, cs: ChangeSet) -> DbChangeSet:
new = cs.operations[0]['value']
old = get_title(name)['value']
@@ -24,7 +24,7 @@ def set_title_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_title(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_title_cmd(name ,cs))
return execute_command(name, _set_title(name ,cs))
def inp_in_title(section: list[str]) -> str:

View File

@@ -42,7 +42,7 @@ class Mixing(object):
return { 'type': self.type, 'tank': self.tank }
def set_mixing_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_mixing(name: str, cs: ChangeSet) -> DbChangeSet:
old = Mixing(get_mixing(name, cs.operations[0]['tank']))
raw_new = get_mixing(name, cs.operations[0]['tank'])
@@ -67,10 +67,10 @@ def set_mixing(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_mixing(name, cs.operations[0]['tank']) == {}:
return ChangeSet()
return execute_command(name, set_mixing_cmd(name, cs))
return execute_command(name, _set_mixing(name, cs))
def add_mixing_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_mixing(name: str, cs: ChangeSet) -> DbChangeSet:
new = Mixing(cs.operations[0])
redo_sql = f"insert into mixing (tank, model, value) values ({new.f_tank}, {new.f_model}, {new.f_value});"
@@ -87,10 +87,10 @@ def add_mixing(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_mixing(name, cs.operations[0]['tank']) != {}:
return ChangeSet()
return execute_command(name, add_mixing_cmd(name, cs))
return execute_command(name, _add_mixing(name, cs))
def delete_mixing_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_mixing(name: str, cs: ChangeSet) -> DbChangeSet:
old = Mixing(get_mixing(name, cs.operations[0]['tank']))
redo_sql = f"delete from mixing where tank = {old.f_tank};"
@@ -107,7 +107,7 @@ def delete_mixing(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_mixing(name, cs.operations[0]['tank']) == {}:
return ChangeSet()
return execute_command(name, delete_mixing_cmd(name, cs))
return execute_command(name, _delete_mixing(name, cs))
#--------------------------------------------------------------

View File

@@ -29,7 +29,7 @@ def get_time(name: str) -> dict[str, Any]:
return d
def set_time_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_time(name: str, cs: ChangeSet) -> DbChangeSet:
raw_old = get_time(name)
old = {}
@@ -64,7 +64,7 @@ def set_time_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_time(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_time_cmd(name, cs))
return execute_command(name, _set_time(name, cs))
#--------------------------------------------------------------

View File

@@ -1,14 +1,5 @@
from .database import *
from .s23_options_util import get_option_schema, generate_v3
from .batch_cmd import execute_batch_command
def set_option(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0]['operation'] = API_UPDATE
cs.operations[0]['type'] = 'option'
new_cs = cs
new_cs.merge(generate_v3(cs))
return execute_batch_command(name, new_cs)
def _inp_in_option(section: list[str]) -> ChangeSet:

View File

@@ -106,7 +106,7 @@ def get_option(name: str) -> dict[str, Any]:
return d
def set_option_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_option(name: str, cs: ChangeSet) -> DbChangeSet:
raw_old = get_option(name)
old = {}
@@ -140,9 +140,8 @@ def set_option_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs])
def set_option_only(name: str, cs: ChangeSet) -> ChangeSet:
v2_cmd = set_option_cmd(name, cs)
return execute_command(name, v2_cmd)
def set_option(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, _set_option(name, cs))
OPTION_V3_FLOW_UNITS_CFS = OPTION_UNITS_CFS
@@ -231,7 +230,7 @@ def get_option_v3(name: str) -> dict[str, Any]:
return d
def set_option_v3_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_option_v3(name: str, cs: ChangeSet) -> DbChangeSet:
raw_old = get_option_v3(name)
old = {}
@@ -265,9 +264,8 @@ def set_option_v3_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs])
def set_option_v3_only(name: str, cs: ChangeSet) -> ChangeSet:
v3_cmd = set_option_v3_cmd(name, cs)
return execute_command(name, v3_cmd)
def set_option_v3(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, _set_option_v3(name, cs))
_key_map_23 = {

View File

@@ -1,14 +1,5 @@
from .database import *
from .s23_options_util import get_option_schema, get_option_v3_schema, generate_v2, generate_v3
from .batch_cmd import execute_batch_command
def set_option_v3(name: str, cs: ChangeSet) -> ChangeSet:
cs.operations[0]['operation'] = API_UPDATE
cs.operations[0]['type'] = 'option_v3'
new_cs = cs
new_cs.merge(generate_v2(cs))
return execute_batch_command(name, new_cs)
def _parse_v2(v2_lines: list[str]) -> dict[str, str]:

View File

@@ -1,17 +1,35 @@
from .database import *
def _to_client_point(coord: str) -> dict[str, float]:
xy = coord.removeprefix('(').removesuffix(')').split(',')
def sql_update_coord(node: str, x: float, y: float) -> str:
coord = f"st_geomfromtext('point({x} {y})')"
return f"update coordinates set coord = {coord} where node = '{node}';"
def sql_insert_coord(node: str, x: float, y: float) -> str:
coord = f"st_geomfromtext('point({x} {y})')"
return f"insert into coordinates (node, coord) values ('{node}', {coord});"
def sql_delete_coord(node: str) -> str:
return f"delete from coordinates where node = '{node}';"
def from_postgis_point(coord: str) -> dict[str, float]:
xy = coord.lower().removeprefix('point(').removesuffix(')').split(' ')
return { 'x': float(xy[0]), 'y': float(xy[1]) }
def get_node_coord(name: str, id: str) -> dict[str, float]:
row = try_read(name, f"select * from coordinates where node = '{id}'")
def get_node_coord(name: str, node: str) -> dict[str, float]:
row = try_read(name, f"select st_astext(coord) as coord_geom from coordinates where node = '{node}'")
if row == None:
write(name, f"insert into coordinates (node, coord) values ('{id}', '(0.0,0.0)');")
write(name, sql_insert_coord(node, 0.0, 0.0))
return {'x': 0.0, 'y': 0.0}
return _to_client_point(row['coord'])
return from_postgis_point(row['coord_geom'])
def node_has_coord(name: str, node: str) -> bool:
return try_read(name, f"select node from coordinates where node = '{node}'") != None
#--------------------------------------------------------------
@@ -24,16 +42,16 @@ def get_node_coord(name: str, id: str) -> dict[str, float]:
def inp_in_coord(line: str) -> str:
tokens = line.split()
node = tokens[0]
coord = f"'({tokens[1]}, {tokens[2]})'"
coord = f"st_geomfromtext('point({tokens[1]} {tokens[2]})')"
return f"insert into coordinates (node, coord) values ('{node}', {coord});"
def inp_out_coord(name: str) -> list[str]:
lines = []
objs = read_all(name, 'select * from coordinates')
objs = read_all(name, 'select node, st_astext(coord) as coord_geom from coordinates')
for obj in objs:
node = obj['node']
coord = _to_client_point(obj['coord'])
coord = from_postgis_point(obj['coord_geom'])
x = coord['x']
y = coord['y']
lines.append(f'{node} {x} {y}')

View File

@@ -16,7 +16,7 @@ def get_vertex(name: str, link: str) -> dict[str, Any]:
return { 'link': link, 'coords': cs }
def set_vertex_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_vertex(name: str, cs: ChangeSet) -> DbChangeSet:
link = cs.operations[0]['link']
old = get_vertex(name, link)
@@ -44,34 +44,34 @@ def set_vertex_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_vertex(name: str, cs: ChangeSet) -> ChangeSet:
result = set_vertex_cmd(name, cs)
result = _set_vertex(name, cs)
result.redo_cs[0] |= g_update_prefix
result.undo_cs[0] |= g_update_prefix
return execute_command(name, result)
def add_vertex_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
result = set_vertex_cmd(name, cs)
def _add_vertex(name: str, cs: ChangeSet) -> DbChangeSet:
result = _set_vertex(name, cs)
result.redo_cs[0] |= g_add_prefix
result.undo_cs[0] |= g_delete_prefix
return result
def delete_vertex_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_vertex(name: str, cs: ChangeSet) -> DbChangeSet:
cs.operations[0]['coords'] = []
result = set_vertex_cmd(name, cs)
result = _set_vertex(name, cs)
result.redo_cs[0] |= g_delete_prefix
result.undo_cs[0] |= g_add_prefix
return result
def add_vertex(name: str, cs: ChangeSet) -> ChangeSet:
result = add_vertex_cmd(name, cs)
result = _add_vertex(name, cs)
return execute_command(name, result)
def delete_vertex(name: str, cs: ChangeSet) -> ChangeSet:
result = delete_vertex_cmd(name, cs)
result = _delete_vertex(name, cs)
return execute_command(name, result)

View File

@@ -43,7 +43,7 @@ class Label(object):
return { 'type': self.type, 'x': self.x, 'y': self.y }
def set_label_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_label(name: str, cs: ChangeSet) -> DbChangeSet:
old = Label(get_label(name, cs.operations[0]['x'], cs.operations[0]['y']))
raw_new = get_label(name, cs.operations[0]['x'], cs.operations[0]['y'])
@@ -64,10 +64,10 @@ def set_label_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_label(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_label_cmd(name, cs))
return execute_command(name, _set_label(name, cs))
def add_label_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_label(name: str, cs: ChangeSet) -> DbChangeSet:
new = Label(cs.operations[0])
redo_sql = f"insert into labels (x, y, label, node) values ({new.f_x}, {new.f_y}, {new.f_label}, {new.f_node});"
@@ -80,10 +80,10 @@ def add_label_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def add_label(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, add_label_cmd(name, cs))
return execute_command(name, _add_label(name, cs))
def delete_label_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_label(name: str, cs: ChangeSet) -> DbChangeSet:
old = Label(get_label(name, cs.operations[0]['x'], cs.operations[0]['y']))
redo_sql = f"delete from labels where x = {old.f_x} and y = {old.f_y};"
@@ -96,7 +96,7 @@ def delete_label_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def delete_label(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, delete_label_cmd(name, cs))
return execute_command(name, _delete_label(name, cs))
def inp_in_label(line: str) -> str:

View File

@@ -10,7 +10,7 @@ def get_backdrop(name: str) -> dict[str, Any]:
return { 'content': e['content'] }
def set_backdrop_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_backdrop(name: str, cs: ChangeSet) -> DbChangeSet:
old = get_backdrop(name)
redo_sql = f"update backdrop set content = '{cs.operations[0]['content']}' where content = '{old['content']}';"
@@ -23,7 +23,7 @@ def set_backdrop_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_backdrop(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_backdrop_cmd(name, cs))
return execute_command(name, _set_backdrop(name, cs))
def inp_in_backdrop(section: list[str]) -> str:

View File

@@ -56,7 +56,7 @@ class ScadaDevice(object):
return { 'type': self.type, 'id': self.id }
def set_scada_device_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_scada_device(name: str, cs: ChangeSet) -> DbChangeSet:
old = ScadaDevice(get_scada_device(name, cs.operations[0]['id']))
raw_new = get_scada_device(name, cs.operations[0]['id'])
@@ -79,10 +79,10 @@ def set_scada_device_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_scada_device(name: str, cs: ChangeSet) -> ChangeSet:
if get_scada_device(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_scada_device_cmd(name, cs))
return execute_command(name, _set_scada_device(name, cs))
def add_scada_device_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_scada_device(name: str, cs: ChangeSet) -> DbChangeSet:
new = ScadaDevice(cs.operations[0])
redo_sql = f"insert into scada_device (id, name, address, type) values ({new.f_id}, {new.f_name}, {new.f_address}, {new.f_sd_type});"
@@ -97,10 +97,10 @@ def add_scada_device_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def add_scada_device(name: str, cs: ChangeSet) -> ChangeSet:
if get_scada_device(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_scada_device_cmd(name, cs))
return execute_command(name, _add_scada_device(name, cs))
def delete_scada_device_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_scada_device(name: str, cs: ChangeSet) -> DbChangeSet:
old = ScadaDevice(get_scada_device(name, cs.operations[0]['id']))
redo_sql = f"delete from scada_device where id = {old.f_id};"
@@ -115,14 +115,4 @@ def delete_scada_device_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def delete_scada_device(name: str, cs: ChangeSet) -> ChangeSet:
if get_scada_device(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_scada_device_cmd(name, cs))
def clean_scada_device_cmd(name: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, 'select id from scada_device acs')
for row in rows:
cs.delete({ 'type': 'scada_device', 'id': row['id'] })
return cs
return execute_command(name, _delete_scada_device(name, cs))

View File

@@ -35,7 +35,6 @@ class Junction(object):
self.f_type = f"'{self.type}'"
self.f_id = f"'{self.id}'"
self.f_coord = f"'({self.x}, {self.y})'"
self.f_elevation = self.elevation
def as_dict(self) -> dict[str, Any]:
@@ -45,7 +44,7 @@ class Junction(object):
return { 'type': self.type, 'id': self.id }
def set_junction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_junction(name: str, cs: ChangeSet) -> DbChangeSet:
old = Junction(get_junction(name, cs.operations[0]['id']))
raw_new = get_junction(name, cs.operations[0]['id'])
@@ -57,9 +56,9 @@ def set_junction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
new = Junction(raw_new)
redo_sql = f"update junctions set elevation = {new.f_elevation} where id = {new.f_id};"
redo_sql += f"\nupdate coordinates set coord = {new.f_coord} where node = {new.f_id};"
redo_sql += f"\n{sql_update_coord(new.id, new.x, new.y)}"
undo_sql = f"update coordinates set coord = {old.f_coord} where node = {old.f_id};"
undo_sql = sql_update_coord(old.id, old.x, old.y)
undo_sql += f"\nupdate junctions set elevation = {old.f_elevation} where id = {old.f_id};"
redo_cs = g_update_prefix | new.as_dict()
@@ -73,17 +72,17 @@ def set_junction(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_junction(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_junction_cmd(name, cs))
return execute_command(name, _set_junction(name, cs))
def add_junction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_junction(name: str, cs: ChangeSet) -> DbChangeSet:
new = Junction(cs.operations[0])
redo_sql = f"insert into _node (id, type) values ({new.f_id}, {new.f_type});"
redo_sql += f"\ninsert into junctions (id, elevation) values ({new.f_id}, {new.f_elevation});"
redo_sql += f"\ninsert into coordinates (node, coord) values ({new.f_id}, {new.f_coord});"
redo_sql += f"\n{sql_insert_coord(new.id, new.x, new.y)}"
undo_sql = f"delete from coordinates where node = {new.f_id};"
undo_sql = sql_delete_coord(new.id)
undo_sql += f"\ndelete from junctions where id = {new.f_id};"
undo_sql += f"\ndelete from _node where id = {new.f_id};"
@@ -98,19 +97,19 @@ def add_junction(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_junction(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_junction_cmd(name, cs))
return execute_command(name, _add_junction(name, cs))
def delete_junction_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_junction(name: str, cs: ChangeSet) -> DbChangeSet:
old = Junction(get_junction(name, cs.operations[0]['id']))
redo_sql = f"delete from coordinates where node = {old.f_id};"
redo_sql = sql_delete_coord(old.id)
redo_sql += f"\ndelete from junctions where id = {old.f_id};"
redo_sql += f"\ndelete from _node where id = {old.f_id};"
undo_sql = f"insert into _node (id, type) values ({old.f_id}, {old.f_type});"
undo_sql += f"\ninsert into junctions (id, elevation) values ({old.f_id}, {old.f_elevation});"
undo_sql += f"\ninsert into coordinates (node, coord) values ({old.f_id}, {old.f_coord});"
undo_sql += f"\n{sql_insert_coord(old.id, old.x, old.y)}"
redo_cs = g_delete_prefix | old.as_id_dict()
undo_cs = g_add_prefix | old.as_dict()
@@ -123,7 +122,7 @@ def delete_junction(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_junction(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_junction_cmd(name, cs))
return execute_command(name, _delete_junction(name, cs))
#--------------------------------------------------------------

View File

@@ -16,7 +16,7 @@ def get_scada_device_data(name: str, device_id: str) -> dict[str, Any]:
return { 'device_id': device_id, 'data': ds }
def set_scada_device_data_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_scada_device_data(name: str, cs: ChangeSet) -> DbChangeSet:
device_id = cs.operations[0]['device_id']
old = get_scada_device_data(name, device_id)
@@ -45,10 +45,10 @@ def set_scada_device_data_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_scada_device_data(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_scada_device_data_cmd(name, cs))
return execute_command(name, _set_scada_device_data(name, cs))
def add_scada_device_data_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_scada_device_data(name: str, cs: ChangeSet) -> DbChangeSet:
values = cs.operations[0]
device_id = values['device_id']
time = values['time']
@@ -66,10 +66,10 @@ def add_scada_device_data(name: str, cs: ChangeSet) -> ChangeSet:
row = try_read(name, f"select * from scada_device_data where device_id = '{cs.operations[0]['device_id']}' and time = '{cs.operations[0]['time']}'")
if row != None:
return ChangeSet()
return execute_command(name, add_scada_device_data_cmd(name, cs))
return execute_command(name, _add_scada_device_data(name, cs))
def delete_scada_device_data_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_scada_device_data(name: str, cs: ChangeSet) -> DbChangeSet:
values = cs.operations[0]
device_id = values['device_id']
time = values['time']
@@ -87,14 +87,4 @@ def delete_scada_device_data(name: str, cs: ChangeSet) -> ChangeSet:
row = try_read(name, f"select * from scada_device_data where device_id = '{cs.operations[0]['device_id']}' and time = '{cs.operations[0]['time']}'")
if row == None:
return ChangeSet()
return execute_command(name, delete_scada_device_data_cmd(name, cs))
def clean_scada_device_data_cmd(name: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, 'select distinct device_id from scada_device_data acs')
for row in rows:
cs.update({ 'type': 'scada_device_data', 'device_id': row['device_id'], 'data': [] })
return cs
return execute_command(name, _delete_scada_device_data(name, cs))

View File

@@ -114,7 +114,7 @@ class ScadaModel(object):
return { 'type': self.type, 'id': self.id }
def set_scada_element_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_scada_element(name: str, cs: ChangeSet) -> DbChangeSet:
old = ScadaModel(get_scada_element(name, cs.operations[0]['id']))
raw_new = get_scada_element(name, cs.operations[0]['id'])
@@ -139,10 +139,10 @@ def set_scada_element(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if _check_model(name, cs) == False:
return ChangeSet()
return execute_command(name, set_scada_element_cmd(name, cs))
return execute_command(name, _set_scada_element(name, cs))
def add_scada_element_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_scada_element(name: str, cs: ChangeSet) -> DbChangeSet:
new = ScadaModel(cs.operations[0])
redo_sql = f"insert into scada_element (id, x, y, device_id, model_id, model_type, status) values ({new.f_id}, {new.f_x}, {new.f_y}, {new.f_device_id}, {new.f_model_id}, {new.f_model_type}, {new.f_status});"
@@ -159,10 +159,10 @@ def add_scada_element(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if _check_model(name, cs) == False:
return ChangeSet()
return execute_command(name, add_scada_element_cmd(name, cs))
return execute_command(name, _add_scada_element(name, cs))
def delete_scada_element_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_scada_element(name: str, cs: ChangeSet) -> DbChangeSet:
old = ScadaModel(get_scada_element(name, cs.operations[0]['id']))
redo_sql = f"delete from scada_element where id = {old.f_id};"
@@ -177,14 +177,4 @@ def delete_scada_element_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def delete_scada_element(name: str, cs: ChangeSet) -> ChangeSet:
if get_scada_element(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_scada_element_cmd(name, cs))
def clean_scada_element_cmd(name: str) -> ChangeSet:
cs = ChangeSet()
rows = read_all(name, 'select id from scada_element acs')
for row in rows:
cs.delete({ 'type': 'scada_element', 'id': row['id'] })
return cs
return execute_command(name, _delete_scada_element(name, cs))

248
api/s32_region_util.py Normal file
View File

@@ -0,0 +1,248 @@
import ctypes
import platform
import os
import math
from typing import Any
from .s0_base import get_node_links, get_link_nodes, is_pipe
from .s5_pipes import get_pipe
from .database import read, try_read, read_all, write
from .s24_coordinates import node_has_coord, get_node_coord
def from_postgis_polygon(polygon: str) -> list[tuple[float, float]]:
boundary = polygon.lower().removeprefix('polygon((').removesuffix('))').split(',')
xys = []
for pt in boundary:
xy = pt.split(' ')
xys.append((float(xy[0]), float(xy[1])))
return xys
def to_postgis_polygon(boundary: list[tuple[float, float]]) -> str:
polygon = ''
for pt in boundary:
polygon += f'{pt[0]} {pt[1]},'
return f'polygon(({polygon[:-1]}))'
def get_nodes_in_boundary(name: str, boundary: list[tuple[float, float]]) -> list[str]:
api = 'get_nodes_in_boundary'
write(name, f"delete from temp_region where id = '{api}'")
write(name, f"insert into temp_region (id, boundary) values ('{api}', '{to_postgis_polygon(boundary)}')")
nodes: list[str] = []
for row in read_all(name, f"select c.node from coordinates as c, temp_region as r where ST_Intersects(c.coord, r.boundary) and r.id = '{api}'"):
nodes.append(row['node'])
write(name, f"delete from temp_region where id = '{api}'")
return nodes
def get_nodes_in_region(name: str, region_id: str) -> list[str]:
nodes: list[str] = []
for row in read_all(name, f"select c.node from coordinates as c, region as r where ST_Intersects(c.coord, r.boundary) and r.id = '{region_id}'"):
nodes.append(row['node'])
return nodes
def calculate_convex_hull(name: str, nodes: list[str]) -> list[tuple[float, float]]:
write(name, f'delete from temp_node')
for node in nodes:
write(name, f"insert into temp_node values ('{node}')")
# TODO: check none
polygon = read(name, f'select st_astext(st_convexhull(st_collect(array(select coord from coordinates where node in (select * from temp_node))))) as boundary' )['boundary']
write(name, f'delete from temp_node')
return from_postgis_polygon(polygon)
def _verify_platform():
_platform = platform.system()
if _platform != "Windows":
raise Exception(f'Platform {_platform} unsupported (not yet)')
def _normal(v: tuple[float, float]) -> tuple[float, float]:
l = math.sqrt(v[0] * v[0] + v[1] * v[1])
return (v[0] / l, v[1] / l)
def _angle(v: tuple[float, float]) -> float:
if v[0] >= 0 and v[1] >= 0:
return math.asin(v[1])
elif v[0] <= 0 and v[1] >= 0:
return math.pi - math.asin(v[1])
elif v[0] <= 0 and v[1] <= 0:
return math.asin(-v[1]) + math.pi
elif v[0] >= 0 and v[1] <= 0:
return math.pi * 2 - math.asin(-v[1])
return 0
def _angle_of_node_link(node: str, link: str, nodes, links) -> float:
n1 = node
n2 = links[link]['node1'] if n1 == links[link]['node2'] else links[link]['node2']
x1, y1 = nodes[n1]['x'], nodes[n1]['y']
x2, y2 = nodes[n2]['x'], nodes[n2]['y']
v = _normal((x2 - x1, y2 - y1))
return _angle(v)
class Topology:
def __init__(self, db: str, nodes: list[str]) -> None:
self._nodes: dict[str, Any] = {}
self._max_x_node = ''
self._node_list: list[str] = []
for node in nodes:
if not node_has_coord(db, node):
continue
if get_node_links(db, node) == 0:
continue
self._nodes[node] = get_node_coord(db, node) | { 'links': [] }
self._node_list.append(node)
if self._max_x_node == '' or self._nodes[node]['x'] > self._nodes[self._max_x_node]['x']:
self._max_x_node = node
self._links = {}
self._link_list: list[str] = []
for node in self._nodes:
for link in get_node_links(db, node):
candidate = True
link_nodes = get_link_nodes(db, link)
for link_node in link_nodes:
if link_node not in self._nodes:
candidate = False
break
if candidate:
length = get_pipe(db, link)['length'] if is_pipe(db, link) else 0.0
self._links[link] = { 'node1' : link_nodes[0], 'node2' : link_nodes[1], 'length' : length }
self._link_list.append(link)
if link not in self._nodes[link_nodes[0]]['links']:
self._nodes[link_nodes[0]]['links'].append(link)
if link not in self._nodes[link_nodes[1]]['links']:
self._nodes[link_nodes[1]]['links'].append(link)
def nodes(self):
return self._nodes
def node_list(self):
return self._node_list
def max_x_node(self):
return self._max_x_node
def links(self):
return self._links
def link_list(self):
return self._link_list
def calculate_boundary(name: str, nodes: list[str]) -> list[tuple[float, float]]:
topology = Topology(name, nodes)
t_nodes = topology.nodes()
t_links = topology.links()
cursor = topology.max_x_node()
in_angle = 0
paths: list[str] = []
while True:
#print(cursor)
paths.append(cursor)
sorted_links = []
overlapped_link = ''
for link in t_nodes[cursor]['links']:
angle = _angle_of_node_link(cursor, link, t_nodes, t_links)
if angle == in_angle:
overlapped_link = link
continue
sorted_links.append((angle, link))
# work into a branch, return
if len(sorted_links) == 0:
cursor = paths[-2]
in_angle = in_angle = _angle_of_node_link(cursor, overlapped_link, t_nodes, t_links)
continue
sorted_links = sorted(sorted_links, key=lambda s:s[0])
out_link = sorted_links[0][1]
for angle, link in sorted_links:
if angle > in_angle:
out_link = link
break
cursor = t_links[out_link]['node1'] if cursor == t_links[out_link]['node2'] else t_links[out_link]['node2']
# end up trip :)
if cursor == topology.max_x_node():
paths.append(cursor)
break
in_angle = _angle_of_node_link(cursor, out_link, t_nodes, t_links)
boundary: list[tuple[float, float]] = []
for node in paths:
boundary.append((t_nodes[node]['x'], t_nodes[node]['y']))
return boundary
'''
# CClipper2.dll
# int inflate_paths(double* path, size_t size, double delta, int jt, int et, double miter_limit, int precision, double arc_tolerance, double** out_path, size_t* out_size);
# int simplify_paths(double* path, size_t size, double epsilon, int is_closed_path, double** out_path, size_t* out_size);
# void free_paths(double** paths);
'''
def inflate_boundary(name: str, boundary: list[tuple[float, float]], delta: float = 0.5) -> list[tuple[float, float]]:
if boundary[0] == boundary[-1]:
del(boundary[-1])
lib = ctypes.CDLL(os.path.join(os.getcwd(), 'api', 'CClipper2.dll'))
c_size = ctypes.c_size_t(len(boundary) * 2)
c_path = (ctypes.c_double * c_size.value)()
i = 0
for xy in boundary:
c_path[i] = xy[0]
i += 1
c_path[i] = xy[1]
i += 1
c_delta = ctypes.c_double(delta)
JoinType_Square, JoinType_Round, JoinType_Miter = 0, 1, 2
c_jt = ctypes.c_int(JoinType_Square)
EndType_Polygon, EndType_Joined, EndType_Butt, EndType_Square, EndType_Round = 0, 1, 2, 3, 4
c_et = ctypes.c_int(EndType_Polygon)
c_miter_limit = ctypes.c_double(2.0)
c_precision = ctypes.c_int(2)
c_arc_tolerance = ctypes.c_double(0.0)
c_out_path = ctypes.POINTER(ctypes.c_double)()
c_out_size = ctypes.c_size_t(0)
lib.inflate_paths(c_path, c_size, c_delta, c_jt, c_et, c_miter_limit, c_precision, c_arc_tolerance, ctypes.byref(c_out_path), ctypes.byref(c_out_size))
if c_out_size.value == 0:
lib.free_paths(ctypes.byref(c_out_path))
return []
# TODO: simplify_paths :)
result: list[tuple[float, float]] = []
for i in range(0, c_out_size.value, 2):
result.append((c_out_path[i], c_out_path[i + 1]))
result.append(result[0])
lib.free_paths(ctypes.byref(c_out_path))
return result
def inflate_region(name: str, region_id: str, delta: float = 0.5) -> list[tuple[float, float]]:
r = try_read(name, f"select id, st_astext(boundary) as boundary_geom from region where id = '{region_id}'")
if r == None:
return []
boundary = from_postgis_polygon(str(r['boundary_geom']))
return inflate_boundary(name, boundary, delta)
if __name__ == '__main__':
_verify_platform()

83
api/s33_region.py Normal file
View File

@@ -0,0 +1,83 @@
from .database import *
from .s32_region_util import from_postgis_polygon, to_postgis_polygon
def get_region_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False} }
def get_region(name: str, id: str) -> dict[str, Any]:
r = try_read(name, f"select id, st_astext(boundary) as boundary_geom from region where id = '{id}'")
if r == None:
return {}
d = {}
d['id'] = str(r['id'])
d['boundary'] = from_postgis_polygon(str(r['boundary_geom']))
return d
def _set_region(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
new = cs.operations[0]['boundary']
old = get_region(name, id)['boundary']
redo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(new)}') where id = '{id}';"
undo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(old)}') where id = '{id}';"
redo_cs = g_update_prefix | { 'type': 'region', 'id': id, 'boundary': new }
undo_cs = g_update_prefix | { 'type': 'region', 'id': id, 'boundary': old }
return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs])
def set_region(name: str, cs: ChangeSet) -> ChangeSet:
if 'id' not in cs.operations[0] or 'boundary' not in cs.operations[0]:
return ChangeSet()
b = cs.operations[0]['boundary']
if len(b) < 4 or b[0] != b[-1]:
return ChangeSet()
if get_region(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, _set_region(name, cs))
def _add_region(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
new = cs.operations[0]['boundary']
redo_sql = f"insert into region (id, boundary) values ('{id}', '{to_postgis_polygon(new)}');"
undo_sql = f"delete from region where id = '{id}';"
redo_cs = g_add_prefix | { 'type': 'region', 'id': id, 'boundary': new }
undo_cs = g_delete_prefix | { 'type': 'region', 'id': id }
return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs])
def add_region(name: str, cs: ChangeSet) -> ChangeSet:
if 'id' not in cs.operations[0] or 'boundary' not in cs.operations[0]:
return ChangeSet()
b = cs.operations[0]['boundary']
if len(b) < 4 or b[0] != b[-1]:
return ChangeSet()
if get_region(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, _add_region(name, cs))
def _delete_region(name: str, cs: ChangeSet) -> DbChangeSet:
id = cs.operations[0]['id']
old = get_region(name, id)['boundary']
redo_sql = f"delete from region where id = '{id}';"
undo_sql = f"insert into region (id, boundary) values ('{id}', '{to_postgis_polygon(old)}');"
redo_cs = g_delete_prefix | { 'type': 'region', 'id': id }
undo_cs = g_add_prefix | { 'type': 'region', 'id': id, 'boundary': old }
return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs])
def delete_region(name: str, cs: ChangeSet) -> ChangeSet:
if 'id' not in cs.operations[0]:
return ChangeSet()
if get_region(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, _delete_region(name, cs))

View File

@@ -0,0 +1,52 @@
from .database import ChangeSet
from .s0_base import is_junction
from .s9_demands import get_demand
from .s32_region_util import Topology, get_nodes_in_region
from .batch_exe import execute_batch_command
DISTRIBUTION_TYPE_ADD = 'ADD'
DISTRIBUTION_TYPE_OVERRIDE = 'OVERRIDE'
def distribute_demand_to_nodes(name: str, demand: float, nodes: list[str], type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet:
if len(nodes) == 0 or demand == 0.0:
return ChangeSet()
if type != DISTRIBUTION_TYPE_ADD and type != DISTRIBUTION_TYPE_OVERRIDE:
return ChangeSet()
topology = Topology(name, nodes)
t_nodes = topology.nodes()
t_links = topology.links()
length_sum = 0.0
for value in t_links.values():
length_sum += abs(value['length'])
if length_sum <= 0.0:
return ChangeSet()
demand_per_length = demand / length_sum
cs = ChangeSet()
for node, value in t_nodes.items():
if not is_junction(name, node):
continue
demand_per_node = 0.0
for link in value['links']:
demand_per_node += abs(t_links[link]['length']) * demand_per_length * 0.5
ds = get_demand(name, node)['demands']
if len(ds) == 0:
ds = [{'demand': demand_per_node, 'pattern': None, 'category': None}]
elif type == DISTRIBUTION_TYPE_ADD:
ds[0]['demand'] += demand_per_node
else:
ds[0]['demand'] = demand_per_node
cs.update({'type': 'demand', 'junction': node, 'demands': ds})
return execute_batch_command(name, cs)
def distribute_demand_to_region(name: str, demand: float, region: str, type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet:
nodes = get_nodes_in_region(name, region)
return distribute_demand_to_nodes(name, demand, nodes, type)

View File

@@ -0,0 +1,85 @@
import ctypes
import os
from .database import *
from .s32_region_util import Topology
PARTITION_TYPE_RB = 0
PARTITION_TYPE_KWAY = 1
def calculate_district_metering_area(name: str, nodes: list[str], part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]:
if part_type != PARTITION_TYPE_RB and part_type != PARTITION_TYPE_KWAY:
return []
if part_count <= 0:
return []
elif part_count == 1:
return [nodes]
lib = ctypes.CDLL(os.path.join(os.getcwd(), 'api', 'CMetis.dll'))
METIS_NOPTIONS = 40
c_options = (ctypes.c_int64 * METIS_NOPTIONS)()
METIS_OK = 1
result = lib.set_default_options(c_options)
if result != METIS_OK:
return []
METIS_OPTION_PTYPE , METIS_OPTION_CONTIG = 0, 13
c_options[METIS_OPTION_PTYPE] = part_type
c_options[METIS_OPTION_CONTIG] = 1
topology = Topology(name, nodes)
t_nodes = topology.nodes()
t_links = topology.links()
t_node_list = topology.node_list()
t_link_list = topology.link_list()
nedges = len(t_link_list) * 2
c_nvtxs = ctypes.c_int64(len(t_node_list))
c_ncon = ctypes.c_int64(1)
c_xadj = (ctypes.c_int64 * (c_nvtxs.value + 1))()
c_adjncy = (ctypes.c_int64 * nedges)()
c_vwgt = (ctypes.c_int64 * (c_ncon.value * c_nvtxs.value))()
c_adjwgt = (ctypes.c_int64 * nedges)()
c_vsize = (ctypes.c_int64 * c_nvtxs.value)()
c_xadj[0] = 0
l, n = 0, 0
c_xadj_i = 1
for node in t_node_list:
links = t_nodes[node]['links']
for link in links:
node1 = t_links[link]['node1']
node2 = t_links[link]['node2']
c_adjncy[l] = t_node_list.index(node2) if node2 != node else t_node_list.index(node1)
c_adjwgt[l] = 1
l += 1
if len(links) > 0:
c_xadj[c_xadj_i] = l # adjncy.size()
c_xadj_i += 1
c_vwgt[n] = 1
c_vsize[n] = 1
n += 1
part_func = lib.part_graph_recursive if part_type == PARTITION_TYPE_RB else lib.part_graph_kway
c_nparts = ctypes.c_int64(part_count)
c_tpwgts = ctypes.POINTER(ctypes.c_double)()
c_ubvec = ctypes.POINTER(ctypes.c_double)()
c_out_edgecut = ctypes.c_int64(0)
c_out_part = (ctypes.c_int64 * c_nvtxs.value)()
result = part_func(ctypes.byref(c_nvtxs), ctypes.byref(c_ncon), c_xadj, c_adjncy, c_vwgt, c_vsize, c_adjwgt, ctypes.byref(c_nparts), c_tpwgts, c_ubvec, c_options, ctypes.byref(c_out_edgecut), c_out_part)
if result != METIS_OK:
return []
dmas : list[list[str]]= []
for i in range(part_count):
dmas.append([])
for i in range(c_nvtxs.value):
dmas[c_out_part[i]].append(t_node_list[i])
return dmas

119
api/s36_service_area.py Normal file
View File

@@ -0,0 +1,119 @@
import sys
import json
from queue import Queue
from .database import *
from .s0_base import get_node_links, get_link_nodes
sys.path.append('..')
from epanet.epanet import run_project
def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]:
inp = json.loads(run_project(name))
time_count = len(inp['node_results'][0]['result'])
if time_index >= time_count:
return {}
sources : dict[str, list[str]] = {}
for node_result in inp['node_results']:
result = node_result['result'][time_index]
if result['demand'] < 0:
sources[node_result['node']] = []
link_flows: dict[str, float] = {}
for link_result in inp['link_results']:
result = link_result['result'][time_index]
link_flows[link_result['link']] = float(result['flow'])
# build source to nodes map
for source in sources:
queue = Queue()
queue.put(source)
while not queue.empty():
cursor = queue.get()
if cursor not in sources[source]:
sources[source].append(cursor)
links = get_node_links(name, cursor)
for link in links:
node1, node2 = get_link_nodes(name, link)
if node1 == cursor and link_flows[link] > 0:
queue.put(node2)
elif node2 == cursor and link_flows[link] < 0:
queue.put(node1)
# calculation concentration
concentration_map: dict[str, dict[str, float]] = {}
node_wip: list[str] = []
for source, nodes in sources.items():
for node in nodes:
if node not in concentration_map:
concentration_map[node] = {}
concentration_map[node][source] = 0.0
if node not in node_wip:
node_wip.append(node)
# if only one source, done
for node, concentrations in concentration_map.items():
if len(concentrations) == 1:
node_wip.remove(node)
for key in concentrations.keys():
concentration_map[node][key] = 1.0
node_upstream : dict[str, list[tuple[str, str]]] = {}
for node in node_wip:
if node not in node_upstream:
node_upstream[node] = []
links = get_node_links(name, node)
for link in links:
node1, node2 = get_link_nodes(name, link)
if node2 == node and link_flows[link] > 0:
node_upstream[node].append((link, node1))
elif node1 == node and link_flows[link] < 0:
node_upstream[node].append((link, node2))
while len(node_wip) != 0:
done = []
for node in node_wip:
up_link_nodes = node_upstream[node]
ready = True
for link_node in up_link_nodes:
if link_node in node_wip:
ready = False
break
if ready:
for link_node in up_link_nodes:
for source, concentration in concentration_map[link_node[1]].items():
concentration_map[node][source] += concentration * abs(link_flows[link_node[0]])
# normalize
sum = 0.0
for source, concentration in concentration_map[node].items():
sum += concentration
for source in concentration_map[node].keys():
concentration_map[node][source] /= sum
done.append(node)
for node in done:
node_wip.remove(node)
source_to_main_node: dict[str, list[str]] = {}
for node, value in concentration_map.items():
max_source = ''
max_concentration = 0.0
for s, c in value.items():
if c > max_concentration:
max_concentration = c
max_source = s
if max_source not in source_to_main_node:
source_to_main_node[max_source] = []
source_to_main_node[max_source].append(node)
sas: list[dict[str, Any]] = []
for source, nodes in source_to_main_node.items():
sas.append({ 'source': source, 'nodes': nodes })
return { 'service_areas' : sas, 'concentrations': concentration_map }

View File

@@ -0,0 +1,66 @@
from .database import *
from .s0_base import get_node_links
def calculate_virtual_district(name: str, centers: list[str]) -> dict[str, list[Any]]:
write(name, 'delete from temp_vd_topology')
# map node name to index
i = 0
isolated_nodes = []
node_index: dict[str, int] = {}
for row in read_all(name, 'select id from _node'):
node = str(row['id'])
if get_node_links(name, node) == []:
isolated_nodes.append(node)
continue
i += 1
node_index[node] = i
# build topology graph
pipes = read_all(name, 'select node1, node2, length from pipes')
for pipe in pipes:
source = node_index[str(pipe['node1'])]
target = node_index[str(pipe['node2'])]
cost = float(pipe['length'])
write(name, f"insert into temp_vd_topology (source, target, cost) values ({source}, {target}, {cost})")
pumps = read_all(name, 'select node1, node2 from pumps')
for pump in pumps:
source = node_index[str(pump['node1'])]
target = node_index[str(pump['node2'])]
write(name, f"insert into temp_vd_topology (source, target, cost) values ({source}, {target}, 0.0)")
valves = read_all(name, 'select node1, node2 from valves')
for valve in valves:
source = node_index[str(valve['node1'])]
target = node_index[str(valve['node2'])]
write(name, f"insert into temp_vd_topology (source, target, cost) values ({source}, {target}, 0.0)")
# dijkstra distance
node_distance: dict[str, dict[str, Any]] = {}
for center in centers:
for node, index in node_index.items():
if node == center:
node_distance[node] = { 'center': center, 'distance' : 0.0 }
continue
# TODO: check none
distance = float(read(name, f"select max(agg_cost) as distance from pgr_dijkstraCost('select id, source, target, cost from temp_vd_topology', {index}, {node_index[center]}, false)")['distance'])
if node not in node_distance:
node_distance[node] = { 'center': center, 'distance' : distance }
elif distance < node_distance[node]['distance']:
node_distance[node] = { 'center': center, 'distance' : distance }
write(name, 'delete from temp_vd_topology')
# reorganize the distance result
center_node: dict[str, list[str]] = {}
for node, value in node_distance.items():
if value['center'] not in center_node:
center_node[value['center']] = []
center_node[value['center']].append(node)
vds: list[dict[str, Any]] = []
for center, value in center_node.items():
vds.append({ 'center': center, 'nodes': value })
return { 'virtual_districts': vds, 'isolated_nodes': isolated_nodes }

View File

@@ -38,7 +38,6 @@ class Reservoir(object):
self.f_type = f"'{self.type}'"
self.f_id = f"'{self.id}'"
self.f_coord = f"'({self.x}, {self.y})'"
self.f_head = self.head
self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null'
@@ -49,7 +48,7 @@ class Reservoir(object):
return { 'type': self.type, 'id': self.id }
def set_reservoir_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_reservoir(name: str, cs: ChangeSet) -> DbChangeSet:
old = Reservoir(get_reservoir(name, cs.operations[0]['id']))
raw_new = get_reservoir(name, cs.operations[0]['id'])
@@ -61,9 +60,9 @@ def set_reservoir_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
new = Reservoir(raw_new)
redo_sql = f"update reservoirs set head = {new.f_head}, pattern = {new.f_pattern} where id = {new.f_id};"
redo_sql += f"\nupdate coordinates set coord = {new.f_coord} where node = {new.f_id};"
redo_sql += f"\n{sql_update_coord(new.id, new.x, new.y)}"
undo_sql = f"update coordinates set coord = {old.f_coord} where node = {old.f_id};"
undo_sql = sql_update_coord(old.id, old.x, old.y)
undo_sql += f"\nupdate reservoirs set head = {old.f_head}, pattern = {old.f_pattern} where id = {old.f_id};"
redo_cs = g_update_prefix | new.as_dict()
@@ -77,17 +76,17 @@ def set_reservoir(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_reservoir(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_reservoir_cmd(name, cs))
return execute_command(name, _set_reservoir(name, cs))
def add_reservoir_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_reservoir(name: str, cs: ChangeSet) -> DbChangeSet:
new = Reservoir(cs.operations[0])
redo_sql = f"insert into _node (id, type) values ({new.f_id}, {new.f_type});"
redo_sql += f"\ninsert into reservoirs (id, head, pattern) values ({new.f_id}, {new.f_head}, {new.f_pattern});"
redo_sql += f"\ninsert into coordinates (node, coord) values ({new.f_id}, {new.f_coord});"
redo_sql += f"\n{sql_insert_coord(new.id, new.x, new.y)}"
undo_sql = f"delete from coordinates where node = {new.f_id};"
undo_sql = sql_delete_coord(new.id)
undo_sql += f"\ndelete from reservoirs where id = {new.f_id};"
undo_sql += f"\ndelete from _node where id = {new.f_id};"
@@ -102,19 +101,19 @@ def add_reservoir(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_reservoir(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_reservoir_cmd(name, cs))
return execute_command(name, _add_reservoir(name, cs))
def delete_reservoir_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_reservoir(name: str, cs: ChangeSet) -> DbChangeSet:
old = Reservoir(get_reservoir(name, cs.operations[0]['id']))
redo_sql = f"delete from coordinates where node = {old.f_id};"
redo_sql = sql_delete_coord(old.id)
redo_sql += f"\ndelete from reservoirs where id = {old.f_id};"
redo_sql += f"\ndelete from _node where id = {old.f_id};"
undo_sql = f"insert into _node (id, type) values ({old.f_id}, {old.f_type});"
undo_sql += f"\ninsert into reservoirs (id, head, pattern) values ({old.f_id}, {old.f_head}, {old.f_pattern});"
undo_sql += f"\ninsert into coordinates (node, coord) values ({old.f_id}, {old.f_coord});"
undo_sql += f"\n{sql_insert_coord(old.id, old.x, old.y)}"
redo_cs = g_delete_prefix | old.as_id_dict()
undo_cs = g_add_prefix | old.as_dict()
@@ -127,7 +126,7 @@ def delete_reservoir(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_reservoir(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_reservoir_cmd(name, cs))
return execute_command(name, _delete_reservoir(name, cs))
#--------------------------------------------------------------

View File

@@ -60,7 +60,6 @@ class Tank(object):
self.f_type = f"'{self.type}'"
self.f_id = f"'{self.id}'"
self.f_coord = f"'({self.x}, {self.y})'"
self.f_elevation = self.elevation
self.f_init_level = self.init_level
self.f_min_level = self.min_level
@@ -77,7 +76,7 @@ class Tank(object):
return { 'type': self.type, 'id': self.id }
def set_tank_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_tank(name: str, cs: ChangeSet) -> DbChangeSet:
old = Tank(get_tank(name, cs.operations[0]['id']))
raw_new = get_tank(name, cs.operations[0]['id'])
@@ -89,9 +88,9 @@ def set_tank_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
new = Tank(raw_new)
redo_sql = f"update tanks set elevation = {new.f_elevation}, init_level = {new.f_init_level}, min_level = {new.f_min_level}, max_level = {new.f_max_level}, diameter = {new.f_diameter}, min_vol = {new.f_min_vol}, vol_curve = {new.f_vol_curve}, overflow = {new.f_overflow} where id = {new.f_id};"
redo_sql += f"\nupdate coordinates set coord = {new.f_coord} where node = {new.f_id};"
redo_sql += f"\n{sql_update_coord(new.id, new.x, new.y)}"
undo_sql = f"update coordinates set coord = {old.f_coord} where node = {old.f_id};"
undo_sql = sql_update_coord(old.id, old.x, old.y)
undo_sql += f"\nupdate tanks set elevation = {old.f_elevation}, init_level = {old.f_init_level}, min_level = {old.f_min_level}, max_level = {old.f_max_level}, diameter = {old.f_diameter}, min_vol = {old.f_min_vol}, vol_curve = {old.f_vol_curve}, overflow = {old.f_overflow} where id = {old.f_id};"
redo_cs = g_update_prefix | new.as_dict()
@@ -105,17 +104,17 @@ def set_tank(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_tank(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_tank_cmd(name, cs))
return execute_command(name, _set_tank(name, cs))
def add_tank_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_tank(name: str, cs: ChangeSet) -> DbChangeSet:
new = Tank(cs.operations[0])
redo_sql = f"insert into _node (id, type) values ({new.f_id}, {new.f_type});"
redo_sql += f"\ninsert into tanks (id, elevation, init_level, min_level, max_level, diameter, min_vol, vol_curve, overflow) values ({new.f_id}, {new.f_elevation}, {new.f_init_level}, {new.f_min_level}, {new.f_max_level}, {new.f_diameter}, {new.f_min_vol}, {new.f_vol_curve}, {new.f_overflow});"
redo_sql += f"\ninsert into coordinates (node, coord) values ({new.f_id}, {new.f_coord});"
redo_sql += f"\n{sql_insert_coord(new.id, new.x, new.y)}"
undo_sql = f"delete from coordinates where node = {new.f_id};"
undo_sql = sql_delete_coord(new.id)
undo_sql += f"\ndelete from tanks where id = {new.f_id};"
undo_sql += f"\ndelete from _node where id = {new.f_id};"
@@ -130,19 +129,19 @@ def add_tank(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_tank(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_tank_cmd(name, cs))
return execute_command(name, _add_tank(name, cs))
def delete_tank_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_tank(name: str, cs: ChangeSet) -> DbChangeSet:
old = Tank(get_tank(name, cs.operations[0]['id']))
redo_sql = f"delete from coordinates where node = {old.f_id};"
redo_sql = sql_delete_coord(old.id)
redo_sql += f"\ndelete from tanks where id = {old.f_id};"
redo_sql += f"\ndelete from _node where id = {old.f_id};"
undo_sql = f"insert into _node (id, type) values ({old.f_id}, {old.f_type});"
undo_sql += f"\ninsert into tanks (id, elevation, init_level, min_level, max_level, diameter, min_vol, vol_curve, overflow) values ({old.f_id}, {old.f_elevation}, {old.f_init_level}, {old.f_min_level}, {old.f_max_level}, {old.f_diameter}, {old.f_min_vol}, {old.f_vol_curve}, {old.f_overflow});"
undo_sql += f"\ninsert into coordinates (node, coord) values ({old.f_id}, {old.f_coord});"
undo_sql += f"\n{sql_insert_coord(old.id, old.x, old.y)}"
redo_cs = g_delete_prefix | old.as_id_dict()
undo_cs = g_add_prefix | old.as_dict()
@@ -155,7 +154,7 @@ def delete_tank(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_tank(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_tank_cmd(name, cs))
return execute_command(name, _delete_tank(name, cs))
#--------------------------------------------------------------

View File

@@ -63,7 +63,7 @@ class Pipe(object):
return { 'type': self.type, 'id': self.id }
def set_pipe_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_pipe(name: str, cs: ChangeSet) -> DbChangeSet:
old = Pipe(get_pipe(name, cs.operations[0]['id']))
raw_new = get_pipe(name, cs.operations[0]['id'])
@@ -88,10 +88,10 @@ def set_pipe(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pipe(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_pipe_cmd(name, cs))
return execute_command(name, _set_pipe(name, cs))
def add_pipe_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_pipe(name: str, cs: ChangeSet) -> DbChangeSet:
new = Pipe(cs.operations[0])
redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});"
@@ -111,10 +111,10 @@ def add_pipe(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pipe(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_pipe_cmd(name, cs))
return execute_command(name, _add_pipe(name, cs))
def delete_pipe_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_pipe(name: str, cs: ChangeSet) -> DbChangeSet:
old = Pipe(get_pipe(name, cs.operations[0]['id']))
redo_sql = f"delete from pipes where id = {old.f_id};"
@@ -134,7 +134,7 @@ def delete_pipe(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pipe(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_pipe_cmd(name, cs))
return execute_command(name, _delete_pipe(name, cs))
#--------------------------------------------------------------

View File

@@ -54,7 +54,7 @@ class Pump(object):
return { 'type': self.type, 'id': self.id }
def set_pump_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_pump(name: str, cs: ChangeSet) -> DbChangeSet:
old = Pump(get_pump(name, cs.operations[0]['id']))
raw_new = get_pump(name, cs.operations[0]['id'])
@@ -79,10 +79,10 @@ def set_pump(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pump(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_pump_cmd(name, cs))
return execute_command(name, _set_pump(name, cs))
def add_pump_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_pump(name: str, cs: ChangeSet) -> DbChangeSet:
new = Pump(cs.operations[0])
redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});"
@@ -102,10 +102,10 @@ def add_pump(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pump(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_pump_cmd(name, cs))
return execute_command(name, _add_pump(name, cs))
def delete_pump_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_pump(name: str, cs: ChangeSet) -> DbChangeSet:
old = Pump(get_pump(name, cs.operations[0]['id']))
redo_sql = f"delete from pumps where id = {old.f_id};"
@@ -125,7 +125,7 @@ def delete_pump(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_pump(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_pump_cmd(name, cs))
return execute_command(name, _delete_pump(name, cs))
#--------------------------------------------------------------

View File

@@ -62,7 +62,7 @@ class Valve(object):
return { 'type': self.type, 'id': self.id }
def set_valve_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_valve(name: str, cs: ChangeSet) -> DbChangeSet:
old = Valve(get_valve(name, cs.operations[0]['id']))
raw_new = get_valve(name, cs.operations[0]['id'])
@@ -87,10 +87,10 @@ def set_valve(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_valve(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, set_valve_cmd(name, cs))
return execute_command(name, _set_valve(name, cs))
def add_valve_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _add_valve(name: str, cs: ChangeSet) -> DbChangeSet:
new = Valve(cs.operations[0])
redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});"
@@ -110,10 +110,10 @@ def add_valve(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_valve(name, cs.operations[0]['id']) != {}:
return ChangeSet()
return execute_command(name, add_valve_cmd(name, cs))
return execute_command(name, _add_valve(name, cs))
def delete_valve_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _delete_valve(name: str, cs: ChangeSet) -> DbChangeSet:
old = Valve(get_valve(name, cs.operations[0]['id']))
redo_sql = f"delete from valves where id = {old.f_id};"
@@ -133,7 +133,7 @@ def delete_valve(name: str, cs: ChangeSet) -> ChangeSet:
return ChangeSet()
if get_valve(name, cs.operations[0]['id']) == {}:
return ChangeSet()
return execute_command(name, delete_valve_cmd(name, cs))
return execute_command(name, _delete_valve(name, cs))
#--------------------------------------------------------------

View File

@@ -53,7 +53,7 @@ class Tag(object):
return { 'type': self.type, 't_type': self.t_type, 'id': self.id, 'tag': self.tag }
def set_tag_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_tag(name: str, cs: ChangeSet) -> DbChangeSet:
old = Tag(get_tag(name, cs.operations[0]['t_type'], cs.operations[0]['id']))
raw_new = get_tag(name, cs.operations[0]['t_type'], cs.operations[0]['id'])
@@ -89,7 +89,7 @@ def set_tag_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_tag(name: str, cs: ChangeSet) -> ChangeSet:
if 't_type' not in cs.operations[0] or 'id' not in cs.operations[0] or 'tag' not in cs.operations[0]:
return ChangeSet()
return execute_command(name, set_tag_cmd(name, cs))
return execute_command(name, _set_tag(name, cs))
def inp_in_tag(line: str) -> str:

View File

@@ -20,7 +20,7 @@ def get_demand(name: str, junction: str) -> dict[str, Any]:
return { 'junction': junction, 'demands': ds }
def set_demand_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def _set_demand(name: str, cs: ChangeSet) -> DbChangeSet:
junction = cs.operations[0]['junction']
old = get_demand(name, junction)
new = { 'junction': junction, 'demands': [] }
@@ -56,7 +56,7 @@ def set_demand_cmd(name: str, cs: ChangeSet) -> DbChangeSet:
def set_demand(name: str, cs: ChangeSet) -> ChangeSet:
return execute_command(name, set_demand_cmd(name, cs))
return execute_command(name, _set_demand(name, cs))
#--------------------------------------------------------------

View File

@@ -33,11 +33,13 @@ sql_create = [
"script/sql/create/29.scada_device.sql",
"script/sql/create/30.scada_device_data.sql",
"script/sql/create/31.scada_element.sql",
"script/sql/create/32.region.sql",
"script/sql/create/operation.sql"
]
sql_drop = [
"script/sql/drop/operation.sql",
"script/sql/drop/32.region.sql",
"script/sql/drop/31.scada_element.sql",
"script/sql/drop/30.scada_device_data.sql",
"script/sql/drop/29.scada_device.sql",
@@ -78,6 +80,8 @@ def create_template():
cur.execute("create database project")
with pg.connect(conninfo="dbname=project host=127.0.0.1") as conn:
with conn.cursor() as cur:
cur.execute('create extension postgis cascade')
cur.execute('create extension pgrouting cascade')
for sql in sql_create:
with open(sql, "r") as f:
cur.execute(f.read())

View File

@@ -3,10 +3,9 @@
create table coordinates
(
node varchar(32) primary key references _node(id)
, coord point not null
, coord geometry
);
-- delete when delete node
create index coordinates_spgist on coordinates using spgist(coord);
create index coordinates_gist on coordinates using gist(coord);

View File

@@ -0,0 +1,37 @@
create table region
(
id text primary key
, boundary geometry not null unique
);
create index region_gist on region using gist(boundary);
create table temp_region
(
id text primary key
, boundary geometry not null unique
);
create index temp_region_gist on temp_region using gist(boundary);
create table temp_node
(
node varchar(32) primary key references _node(id)
);
create table temp_link
(
link varchar(32) primary key references _link(id)
);
create table temp_vd_topology
(
id serial
, source integer
, target integer
, cost numeric
);

View File

@@ -2,6 +2,4 @@
drop index if exists coordinates_gist;
drop index if exists coordinates_spgist;
drop table if exists coordinates;

View File

@@ -0,0 +1,13 @@
drop table if exists temp_vd_topology;
drop table if exists temp_link;
drop table if exists temp_node;
drop index if exists temp_region_gist;
drop table if exists temp_region;
drop index if exists region_gist;
drop table if exists region;

File diff suppressed because one or more lines are too long

View File

@@ -151,18 +151,26 @@ SCADA_DEVICE_TYPE_LEVEL = api.SCADA_DEVICE_TYPE_LEVEL
SCADA_DEVICE_TYPE_FLOW = api.SCADA_DEVICE_TYPE_FLOW
SCADA_MODEL_TYPE_JUNCTION = api.SCADA_MODEL_TYPE_JUNCTION
SCADA_MODEL_TYPE_JUNCTION = api.SCADA_MODEL_TYPE_JUNCTION
SCADA_MODEL_TYPE_RESERVOIR = api.SCADA_MODEL_TYPE_RESERVOIR
SCADA_MODEL_TYPE_TANK = api.SCADA_MODEL_TYPE_TANK
SCADA_MODEL_TYPE_PIPE = api.SCADA_MODEL_TYPE_PIPE
SCADA_MODEL_TYPE_PUMP = api.SCADA_MODEL_TYPE_PUMP
SCADA_MODEL_TYPE_VALVE = api.SCADA_MODEL_TYPE_VALVE
SCADA_MODEL_TYPE_TANK = api.SCADA_MODEL_TYPE_TANK
SCADA_MODEL_TYPE_PIPE = api.SCADA_MODEL_TYPE_PIPE
SCADA_MODEL_TYPE_PUMP = api.SCADA_MODEL_TYPE_PUMP
SCADA_MODEL_TYPE_VALVE = api.SCADA_MODEL_TYPE_VALVE
SCADA_ELEMENT_STATUS_ONLINE = api.SCADA_ELEMENT_STATUS_ONLINE
SCADA_ELEMENT_STATUS_OFFLINE = api.SCADA_ELEMENT_STATUS_OFFLINE
DISTRIBUTION_TYPE_ADD = api.DISTRIBUTION_TYPE_ADD
DISTRIBUTION_TYPE_OVERRIDE = api.DISTRIBUTION_TYPE_OVERRIDE
PARTITION_TYPE_RB = api.PARTITION_TYPE_RB
PARTITION_TYPE_KWAY = api.PARTITION_TYPE_KWAY
############################################################
# project
############################################################
@@ -300,6 +308,18 @@ def set_restore_operation_to_current(name: str) -> None:
def restore(name: str, discard: bool = False) -> ChangeSet:
return api.restore(name, discard)
def read(name: str, sql: str):
return api.read(name, sql)
def try_read(name: str, sql: str):
return api.try_read(name, sql)
def read_all(name: str, sql: str):
return api.read_all(name, sql)
def write(name: str, sql: str):
return api.write(name, sql)
############################################################
# type
@@ -772,7 +792,7 @@ def get_option(name: str) -> dict[str, Any]:
return api.get_option(name)
def set_option(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_option(name, cs)
return api.set_option_ex(name, cs)
############################################################
@@ -786,7 +806,7 @@ def get_option_v3(name: str) -> dict[str, Any]:
return api.get_option_v3(name)
def set_option_v3(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_option_v3(name, cs)
return api.set_option_v3_ex(name, cs)
############################################################
@@ -933,3 +953,82 @@ def delete_scada_element(name: str, cs: ChangeSet) -> ChangeSet:
def clean_scada_element(name: str) -> ChangeSet:
return api.clean_scada_element(name)
############################################################
# region_util 32
############################################################
def get_nodes_in_boundary(name: str, boundary: list[tuple[float, float]]) -> list[str]:
return api.get_nodes_in_boundary(name, boundary)
def get_nodes_in_region(name: str, region_id: str) -> list[str]:
return api.get_nodes_in_region(name, region_id)
def calculate_convex_hull(name: str, nodes: list[str]) -> list[tuple[float, float]]:
return api.calculate_convex_hull(name, nodes)
def calculate_boundary(name: str, nodes: list[str]) -> list[tuple[float, float]]:
return api.calculate_boundary(name, nodes)
def inflate_boundary(name: str, boundary: list[tuple[float, float]], delta: float = 0.5) -> list[tuple[float, float]]:
return api.inflate_boundary(name, boundary, delta)
def inflate_region(name: str, region_id: str, delta: float = 0.5) -> list[tuple[float, float]]:
return api.inflate_region(name, region_id, delta)
############################################################
# general_region 33
############################################################
def get_region_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_region_schema(name)
def get_region(name: str, id: str) -> dict[str, Any]:
return api.get_region(name, id)
def set_region(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_region(name, cs)
# example: add_region(p, ChangeSet({'id': 'r', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)]}))
def add_region(name: str, cs: ChangeSet) -> ChangeSet:
return api.add_region(name, cs)
def delete_region(name: str, cs: ChangeSet) -> ChangeSet:
return api.delete_region(name, cs)
############################################################
# water_distribution 34
############################################################
def distribute_demand_to_nodes(name: str, demand: float, nodes: list[str], type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet:
return api.distribute_demand_to_nodes(name, demand, nodes, type)
def distribute_demand_to_region(name: str, demand: float, region: str, type: str = DISTRIBUTION_TYPE_ADD) -> ChangeSet:
return api.distribute_demand_to_region(name, demand, region, type)
############################################################
# district_metering_area 35
############################################################
def calculate_district_metering_area(name: str, nodes: list[str], part_count: int = 1, part_type: int = PARTITION_TYPE_RB) -> list[list[str]]:
return api.calculate_district_metering_area(name, nodes, part_count, part_type)
############################################################
# service_area 36
############################################################
def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]:
return api.calculate_service_area(name, time_index)
############################################################
# virtual_district 37
############################################################
def calculate_virtual_district(name: str, centers: list[str]) -> dict[str, list[Any]]:
return api.calculate_virtual_district(name, centers)