diff --git a/api/__init__.py b/api/__init__.py index 21e3621..e179134 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -2,7 +2,7 @@ from .project import list_project, have_project, create_project, delete_project from .project import is_project_open, get_project_open_count, open_project, close_project from .project import copy_project -from .parser import read_inp +from .api_parser import read_inp from .operation import API_ADD, API_UPDATE, API_DELETE from .operation import ChangeSet diff --git a/api/parser.py b/api/api_parser.py similarity index 51% rename from api/parser.py rename to api/api_parser.py index 0f68d45..e8bcb91 100644 --- a/api/parser.py +++ b/api/api_parser.py @@ -7,13 +7,66 @@ from .s4_tanks import * from .s5_pipes import * from .s6_pumps import * from .s7_valves import * +from .s8_tags import * from .s9_demands import * from .s10_status import * from .s11_patterns import * from .s12_curves import * +from .s13_controls import * +from .s14_rules import * +from .s15_energy import * from .s16_emitters import * +from .s17_quality import * +from .s18_sources import * +from .s19_reactions import * +from .s20_mixing import * from .s21_times import * +from .s22_report import * from .s23_options import * +from .s24_coordinates import * +from .s25_vertices import * +from .s26_labels import * +from .s27_backdrop import * +from .s28_end import * + + + +def parse_inp(inp: str) -> dict[str, list[str]]: + section_name = ['TITLE', 'JUNCTIONS', 'RESERVOIRS', 'TANKS', 'PIPES', + 'PUMPS', 'VALVES', 'TAGS', 'DEMANDS', 'STATUS', + 'PATTERNS', 'CURVES', 'CONTROLS', 'RULES', 'ENERGY', + 'EMITTERS', 'QUALITY', 'SOURCES', 'REACTIONS', 'MIXING', + 'TIMES', 'REPORT', 'OPTIONS', 'COORDINATES', 'VERTICES', + 'LABELS', 'BACKDROP', 'END'] + + file: dict[str, list[str]] = {} + for s in section_name: + file[s] = [] + + section = '' + + for line in open(inp): + line = line.strip() + if line == '': + section = '' + continue + + if line.startswith('['): + is_section = False + for s in section_name: + if line.startswith(f'[{s}'): + section = s + is_section = True + break + if is_section: + continue + + if section != '': + file[section].append(line) + + return file + + def read_inp(name: str, inp: str): @@ -28,25 +81,27 @@ def read_inp(name: str, inp: str): section = '' - title : str = '' - junctions : dict[str, dict[str, Any]] = {} - reservoirs : dict[str, dict[str, Any]] = {} - tanks : dict[str, dict[str, Any]] = {} - pipes : dict[str, dict[str, Any]] = {} - pumps : dict[str, dict[str, Any]] = {} - valves : dict[str, dict[str, Any]] = {} - demands : dict[str, list[dict[str, Any]]] = {} - status : dict[str, dict[str, Any]] = {} - patterns : dict[str, list[float]] = {} - curves : dict[str, list[dict[str, float]]] = {} - emitters : dict[str, float] = {} - times : dict[str, str] = {} - options : dict[str, str] = {} + file: dict[str, list[str]] = {} + + _1_title : str = '' + _2_junctions : dict[str, dict[str, Any]] = {} + _3_reservoirs : dict[str, dict[str, Any]] = {} + _4_tanks : dict[str, dict[str, Any]] = {} + _5_pipes : dict[str, dict[str, Any]] = {} + _6_pumps : dict[str, dict[str, Any]] = {} + _7_valves : dict[str, dict[str, Any]] = {} + _9_demands : dict[str, list[dict[str, Any]]] = {} + _10_status : dict[str, dict[str, Any]] = {} + _11_patterns : dict[str, list[float]] = {} + _12_curves : dict[str, list[dict[str, float]]] = {} + _16_emitters : dict[str, float] = {} + _21_times : dict[str, str] = {} + _22_options : dict[str, str] = {} for line in open(inp): line = line.strip() - if line.startswith(';'): + if line.startswith(';') and not line.endswith(':'): continue if line.endswith(';'): line = line.removesuffix(';') @@ -110,111 +165,111 @@ def read_inp(name: str, inp: str): continue if section == 'title': - if title == '': - title += '\n' - title += line + if _1_title == '': + _1_title += '\n' + _1_title += line continue elif section == JUNCTION: junction_demand = float(tokens[2]) if tokens_len >= 3 else None junction_pattern = tokens[3] if tokens_len == 4 else None - junctions[tokens[0]] = {'id': tokens[0], 'elevation': tokens[1], 'demand': junction_demand, 'pattern': junction_pattern} + _2_junctions[tokens[0]] = {'id': tokens[0], 'elevation': tokens[1], 'demand': junction_demand, 'pattern': junction_pattern} continue elif section == RESERVOIR: reservoir_pattern = tokens[2] if tokens_len == 3 else None - reservoirs[tokens[0]] = {'id': tokens[0], 'head': tokens[1], 'pattern': reservoir_pattern} + _3_reservoirs[tokens[0]] = {'id': tokens[0], 'head': tokens[1], 'pattern': reservoir_pattern} continue elif section == TANK: tank_vol_curve = tokens[7] if tokens_len >= 8 else None tank_overflow = tokens[8].upper() if tokens_len == 9 else None - tanks[tokens[0]] = {'id': tokens[0], 'elevation': tokens[1], 'init_level': tokens[2], 'min_level': tokens[3], 'max_level': tokens[4], 'diameter': tokens[5], 'min_vol': tokens[6], 'vol_curve': tank_vol_curve, 'overflow': tank_overflow} + _4_tanks[tokens[0]] = {'id': tokens[0], 'elevation': tokens[1], 'init_level': tokens[2], 'min_level': tokens[3], 'max_level': tokens[4], 'diameter': tokens[5], 'min_vol': tokens[6], 'vol_curve': tank_vol_curve, 'overflow': tank_overflow} continue elif section == PIPE: # status is must-have, here fix input pipe_status = tokens[7].upper() if tokens_len == 8 else PIPE_STATUS_OPEN - pipes[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'length': tokens[3], 'diameter': tokens[4], 'roughness': tokens[5], 'minor_loss': tokens[6], 'status': pipe_status} + _5_pipes[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'length': tokens[3], 'diameter': tokens[4], 'roughness': tokens[5], 'minor_loss': tokens[6], 'status': pipe_status} continue elif section == PUMP: - pumps[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2]} + _6_pumps[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2]} for i in range(3, tokens_len, 2): - pumps[tokens[0]] |= { tokens[i].lower(): tokens[i + 1] } + _6_pumps[tokens[0]] |= { tokens[i].lower(): tokens[i + 1] } continue elif section == VALVE: - valves[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'diameter': tokens[3], 'v_type': tokens[4], 'setting': tokens[5], 'minor_loss': tokens[6]} + _7_valves[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'diameter': tokens[3], 'v_type': tokens[4], 'setting': tokens[5], 'minor_loss': tokens[6]} continue elif section == 'demand': demand_pattern = tokens[2] if tokens_len >= 3 else None demand_category = tokens[3] if tokens_len == 4 else None - demands[tokens[0]].append({'demand': tokens[1], 'pattern': demand_pattern, 'category': demand_category}) + _9_demands[tokens[0]].append({'demand': tokens[1], 'pattern': demand_pattern, 'category': demand_category}) continue elif section == 'status': - if tokens[0] not in status: - status[tokens[0]] = {} + if tokens[0] not in _10_status: + _10_status[tokens[0]] = {} setting = None try: setting = float(tokens[1]) except: setting = None if setting != None: - status[tokens[0]]['setting'] = setting + _10_status[tokens[0]]['setting'] = setting else: - status[tokens[0]]['status'] = tokens[1].upper() + _10_status[tokens[0]]['status'] = tokens[1].upper() continue elif section == PATTERN: - if tokens[0] not in patterns: - patterns[tokens[0]] = [] + if tokens[0] not in _11_patterns: + _11_patterns[tokens[0]] = [] for i in range(1, tokens_len): - patterns[tokens[0]].append(float(tokens[i])) + _11_patterns[tokens[0]].append(float(tokens[i])) continue elif section == CURVE: - if tokens[0] not in curves: - curves[tokens[0]] = [] + if tokens[0] not in _12_curves: + _12_curves[tokens[0]] = [] for i in range(1, tokens_len, 2): - curves[tokens[0]].append({ 'x': float(tokens[i]), 'y': float(tokens[i + 1]) }) + _12_curves[tokens[0]].append({ 'x': float(tokens[i]), 'y': float(tokens[i + 1]) }) continue elif section == 'emitter': - emitters[tokens[0]] = float(tokens[1]) + _16_emitters[tokens[0]] = float(tokens[1]) continue elif section == 'time': if tokens_len == 2: - times[tokens[0]] = tokens[1] + _21_times[tokens[0]] = tokens[1] elif tokens_len == 3: - times[tokens[0] + ' ' + tokens[1]] = tokens[2] + _21_times[tokens[0] + ' ' + tokens[1]] = tokens[2] elif tokens_len == 4: - times[tokens[0] + ' ' + tokens[1]] = tokens[2] + ' ' + tokens[3] + _21_times[tokens[0] + ' ' + tokens[1]] = tokens[2] + ' ' + tokens[3] continue elif section == 'option': if tokens[0] == 'HYDRAULICS' or tokens[0] == 'MAP': continue if tokens_len == 2: - options[tokens[0]] = tokens[1] + _22_options[tokens[0]] = tokens[1] elif tokens_len == 3: if tokens[0] == 'UNBALANCED' or tokens[0] == 'QUALITY': - options[tokens[0]] = tokens[1] + ' ' + tokens[2] + _22_options[tokens[0]] = tokens[1] + ' ' + tokens[2] else: - options[tokens[0] + ' ' + tokens[1]] = tokens[2] + _22_options[tokens[0] + ' ' + tokens[1]] = tokens[2] continue elif section == 'coordinate': - if tokens[0] in junctions: - junctions[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]} - elif tokens[0] in reservoirs: - reservoirs[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]} - elif tokens[0] in tanks: - tanks[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]} + if tokens[0] in _2_junctions: + _2_junctions[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]} + elif tokens[0] in _3_reservoirs: + _3_reservoirs[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]} + elif tokens[0] in _4_tanks: + _4_tanks[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]} continue # title - set_title(name, ChangeSet({ 'value': title })) + set_title(name, ChangeSet({ 'value': _1_title })) # pattern - for key, value in patterns.items(): + for key, value in _11_patterns.items(): set_pattern(name, ChangeSet({'id': key, 'factors': value})) # curve - for key, value in curves.items(): + for key, value in _12_curves.items(): set_curve(name, ChangeSet({'id': key, 'coords': value})) # junction - for value in junctions.values(): + for value in _2_junctions.values(): if 'x' not in value: value['x'] = 0.0 if 'y' not in value: @@ -222,7 +277,7 @@ def read_inp(name: str, inp: str): add_junction(name, ChangeSet(value)) # reservoir - for value in reservoirs.values(): + for value in _3_reservoirs.values(): if 'x' not in value: value['x'] = 0.0 if 'y' not in value: @@ -230,7 +285,7 @@ def read_inp(name: str, inp: str): add_reservoir(name, ChangeSet(value)) # tank - for value in tanks.values(): + for value in _4_tanks.values(): if 'x' not in value: value['x'] = 0.0 if 'y' not in value: @@ -238,33 +293,33 @@ def read_inp(name: str, inp: str): add_tank(name, ChangeSet(value)) # pipe - for value in pipes.values(): + for value in _5_pipes.values(): add_pipe(name, ChangeSet(value)) # pump - for value in pumps.values(): + for value in _6_pumps.values(): add_pump(name, ChangeSet(value)) # valve - for value in valves.values(): + for value in _7_valves.values(): add_valve(name, ChangeSet(value)) # demand - for key, value in demands.items(): + for key, value in _9_demands.items(): set_demand(name, ChangeSet({'junction': key, 'demands': value})) # status - for key, value in status.items(): + for key, value in _10_status.items(): set_status(name, ChangeSet({'link': key} | value)) # emitter - for key, value in emitters.items(): + for key, value in _16_emitters.items(): set_emitter(name, ChangeSet({'junction': key, 'coefficient': value})) # time - set_time(name, ChangeSet(times)) + set_time(name, ChangeSet(_21_times)) # option - set_option(name, ChangeSet(options)) + set_option(name, ChangeSet(_22_options)) close_project(name) diff --git a/api/command.py b/api/command.py index d74eab3..deed8b2 100644 --- a/api/command.py +++ b/api/command.py @@ -5,30 +5,127 @@ from .s4_tanks import * from .s5_pipes import * from .s6_pumps import * from .s7_valves import * +from .s8_tags import * from .s9_demands import * from .s10_status import * from .s11_patterns import * from .s12_curves import * +from .s13_controls import * +from .s14_rules import * +from .s15_energy import * from .s16_emitters import * +from .s17_quality import * +from .s18_sources import * +from .s19_reactions import * +from .s20_mixing import * from .s21_times import * +from .s22_report import * from .s23_options import * +from .s24_coordinates import * +from .s25_vertices import * +from .s26_labels import * +from .s27_backdrop import * +from .s28_end import * + + +_s1_title = 'title' +_s2_junction = 'junction' +_s3_reservoir = 'reservoir' +_s4_tank = 'tank' +_s5_pipe = 'pipe' +_s6_pump = 'pump' +_s7_valve = 'valve' +_s8_tag = 'tag' +_s9_demand = 'demand' +_s10_status = 'status' +_s11_pattern = 'patten' +_s12_curve = 'curve' +_s13_control = 'control' +_s14_rule = 'rule' +_s15_global_energy = 'global_energy' +_s15_pump_energy = 'pump_energy' +_s16_emitter = 'emitter' +_s17_quality = 'quality' +_s18_source = 'source' +_s19_global_reaction = 'global_reaction' +_s19_pipe_reaction = 'pipe_reaction' +_s19_tank_reaction = 'tank_reaction' +_s20_mixing = 'mixing' +_s21_time = 'time' +_s22_report = 'report' +_s23_option = 'option' +_s24_coordinate = 'coordinate' +_s25_vertex = 'vertex' +_s26_label = 'label' +_s27_backdrop = 'backdrop' +_s28_end = 'end' def execute_add_command(name: str, cs: ChangeSet) -> ChangeSet: type = cs.operations[0]['type'] - if type == JUNCTION: + if type == _s1_title: + return ChangeSet() + if type == _s2_junction: return add_junction(name, cs) - elif type == RESERVOIR: + elif type == _s3_reservoir: return add_reservoir(name, cs) - elif type == TANK: + elif type == _s4_tank: return add_tank(name, cs) - elif type == PIPE: + elif type == _s5_pipe: return add_pipe(name, cs) - elif type == PUMP: + elif type == _s6_pump: return add_pump(name, cs) - elif type == VALVE: + elif type == _s7_valve: return add_valve(name, cs) + elif type == _s8_tag: + return ChangeSet() + elif type == _s9_demand: + return ChangeSet() + elif type == _s10_status: + return ChangeSet() + elif type == _s11_pattern: + return add_pattern(name, cs) + elif type == _s12_curve: + return add_curve(name, cs) + elif type == _s13_control: + return ChangeSet() + elif type == _s14_rule: + return ChangeSet() + elif type == _s15_global_energy: + return ChangeSet() + elif type == _s15_pump_energy: + return ChangeSet() + elif type == _s16_emitter: + return ChangeSet() + elif type == _s17_quality: + return ChangeSet() + elif type == _s18_source: + return add_source(name, cs) + elif type == _s19_global_reaction: + return ChangeSet() + elif type == _s19_pipe_reaction: + return ChangeSet() + elif type == _s19_tank_reaction: + return ChangeSet() + elif type == _s20_mixing: + return add_mixing(name, cs) + elif type == _s21_time: + return ChangeSet() + elif type == _s22_report: + return ChangeSet() + elif type == _s23_option: + return ChangeSet() + elif type == _s24_coordinate: + return ChangeSet() + elif type == _s25_vertex: + return add_vertex(name, cs) + elif type == _s26_label: + return add_label(name, cs) + elif type == _s27_backdrop: + return ChangeSet() + elif type == _s28_end: + return ChangeSet() return ChangeSet() @@ -36,34 +133,68 @@ def execute_add_command(name: str, cs: ChangeSet) -> ChangeSet: def execute_update_command(name: str, cs: ChangeSet) -> ChangeSet: type = cs.operations[0]['type'] - if type == 'title': + if type == _s1_title: return set_title(name, cs) - if type == JUNCTION: + if type == _s2_junction: return set_junction(name, cs) - elif type == RESERVOIR: + elif type == _s3_reservoir: return set_reservoir(name, cs) - elif type == TANK: + elif type == _s4_tank: return set_tank(name, cs) - elif type == PIPE: + elif type == _s5_pipe: return set_pipe(name, cs) - elif type == PUMP: + elif type == _s6_pump: return set_pump(name, cs) - elif type == VALVE: + elif type == _s7_valve: return set_valve(name, cs) - elif type == 'demand': - return set_demand(name, cs) - elif type == 'status': + elif type == _s8_tag: + return set_tag(name, cs) + elif type == _s9_demand: # exception, batch command ... + return ChangeSet() + elif type == _s10_status: return set_status(name, cs) - elif type == PATTERN: + elif type == _s11_pattern: return set_pattern(name, cs) - elif type == CURVE: + elif type == _s12_curve: return set_curve(name, cs) - elif type == 'emitter': + elif type == _s13_control: + return set_control(name, cs) + elif type == _s14_rule: + return set_rule(name, cs) + elif type == _s15_global_energy: + return set_global_energy(name, cs) + elif type == _s15_pump_energy: + return set_pump_energy(name, cs) + elif type == _s16_emitter: return set_emitter(name, cs) - elif type == 'time': + elif type == _s17_quality: + return set_quality(name, cs) + elif type == _s18_source: + return set_source(name, cs) + elif type == _s19_global_reaction: + return set_global_reaction(name, cs) + elif type == _s19_pipe_reaction: + return set_pipe_reaction(name, cs) + elif type == _s19_tank_reaction: + return set_tank_reaction(name, cs) + elif type == _s20_mixing: + return set_mixing(name, cs) + elif type == _s21_time: return set_time(name, cs) - elif type == 'option': + elif type == _s22_report: # no api now + return ChangeSet() + elif type == _s23_option: return set_option(name, cs) + elif type == _s24_coordinate: # do not support update here + return ChangeSet() + elif type == _s25_vertex: + return set_vertex(name, cs) + elif type == _s26_label: + return set_label(name, cs) + elif type == _s27_backdrop: + return set_backdrop(name, cs) + elif type == _s28_end: # end + return ChangeSet() return ChangeSet() @@ -71,18 +202,68 @@ def execute_update_command(name: str, cs: ChangeSet) -> ChangeSet: def execute_delete_command(name: str, cs: ChangeSet) -> ChangeSet: type = cs.operations[0]['type'] - if type == JUNCTION: + if type == _s1_title: + return ChangeSet() + if type == _s2_junction: return delete_junction(name, cs) - elif type == RESERVOIR: + elif type == _s3_reservoir: return delete_reservoir(name, cs) - elif type == TANK: + elif type == _s4_tank: return delete_tank(name, cs) - elif type == PIPE: + elif type == _s5_pipe: return delete_pipe(name, cs) - elif type == PUMP: + elif type == _s6_pump: return delete_pump(name, cs) - elif type == VALVE: + elif type == _s7_valve: return delete_valve(name, cs) + elif type == _s8_tag: + return ChangeSet() + elif type == _s9_demand: + return ChangeSet() + elif type == _s10_status: + return ChangeSet() + elif type == _s11_pattern: + return delete_pattern(name, cs) + elif type == _s12_curve: + return delete_curve(name, cs) + elif type == _s13_control: + return ChangeSet() + elif type == _s14_rule: + return ChangeSet() + elif type == _s15_global_energy: + return ChangeSet() + elif type == _s15_pump_energy: + return ChangeSet() + elif type == _s16_emitter: + return ChangeSet() + elif type == _s17_quality: + return ChangeSet() + elif type == _s18_source: + return delete_source(name, cs) + elif type == _s19_global_reaction: + return ChangeSet() + elif type == _s19_pipe_reaction: + return ChangeSet() + elif type == _s19_tank_reaction: + return ChangeSet() + elif type == _s20_mixing: + return delete_mixing(name, cs) + elif type == _s21_time: + return ChangeSet() + elif type == _s22_report: + return ChangeSet() + elif type == _s23_option: + return ChangeSet() + elif type == _s24_coordinate: + return ChangeSet() + elif type == _s25_vertex: + return delete_vertex(name, cs) + elif type == _s26_label: + return delete_label(name, cs) + elif type == _s27_backdrop: + return ChangeSet() + elif type == _s28_end: + return ChangeSet() return ChangeSet() @@ -108,18 +289,68 @@ def execute_batch_commands(name: str, cs: ChangeSet) -> ChangeSet: def cache_add_command(name: str, cs: ChangeSet) -> SqlChangeSet | None: type = cs.operations[0]['type'] - if type == JUNCTION: + if type == _s1_title: + return None + if type == _s2_junction: return add_junction_cache(name, cs) - elif type == RESERVOIR: + elif type == _s3_reservoir: return add_reservoir_cache(name, cs) - elif type == TANK: + elif type == _s4_tank: return add_tank_cache(name, cs) - elif type == PIPE: + elif type == _s5_pipe: return add_pipe_cache(name, cs) - elif type == PUMP: + elif type == _s6_pump: return add_pump_cache(name, cs) - elif type == VALVE: + elif type == _s7_valve: return add_valve_cache(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_cache(name, cs) + elif type == _s12_curve: + return add_curve_cache(name, cs) + elif type == _s13_control: + return None + elif type == _s14_rule: + return None + elif type == _s15_global_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_cache(name, cs) + elif type == _s19_global_reaction: + return None + elif type == _s19_pipe_reaction: + return None + elif type == _s19_tank_reaction: + return None + elif type == _s20_mixing: + return add_mixing_cache(name, cs) + elif type == _s21_time: + return None + elif type == _s22_report: + return None + elif type == _s23_option: + return None + elif type == _s24_coordinate: + return None + elif type == _s25_vertex: + return add_vertex_cache(name, cs) + elif type == _s26_label: + return add_label_cache(name, cs) + elif type == _s27_backdrop: + return None + elif type == _s28_end: + return None return None @@ -127,34 +358,68 @@ def cache_add_command(name: str, cs: ChangeSet) -> SqlChangeSet | None: def cache_update_command(name: str, cs: ChangeSet) -> SqlChangeSet | None: type = cs.operations[0]['type'] - if type == 'title': + if type == _s1_title: return set_title_cache(name, cs) - if type == JUNCTION: + if type == _s2_junction: return set_junction_cache(name, cs) - elif type == RESERVOIR: + elif type == _s3_reservoir: return set_reservoir_cache(name, cs) - elif type == TANK: + elif type == _s4_tank: return set_tank_cache(name, cs) - elif type == PIPE: + elif type == _s5_pipe: return set_pipe_cache(name, cs) - elif type == PUMP: + elif type == _s6_pump: return set_pump_cache(name, cs) - elif type == VALVE: + elif type == _s7_valve: return set_valve_cache(name, cs) - elif type == 'demand': - return set_demand_cache(name, cs) - elif type == 'status': + elif type == _s8_tag: + return set_tag_cache(name, cs) + elif type == _s9_demand: # exception, batch command ... + return None + elif type == _s10_status: return set_status_cache(name, cs) - elif type == PATTERN: + elif type == _s11_pattern: return set_pattern_cache(name, cs) - elif type == CURVE: + elif type == _s12_curve: return set_curve_cache(name, cs) - elif type == 'emitter': + elif type == _s13_control: + return set_control_cache(name, cs) + elif type == _s14_rule: + return set_rule_cache(name, cs) + elif type == _s15_global_energy: + return set_global_energy_cache(name, cs) + elif type == _s15_pump_energy: + return set_pump_energy_cache(name, cs) + elif type == _s16_emitter: return set_emitter_cache(name, cs) - elif type == 'time': + elif type == _s17_quality: + return set_quality_cache(name, cs) + elif type == _s18_source: + return set_source_cache(name, cs) + elif type == _s19_global_reaction: + return set_global_reaction_cache(name, cs) + elif type == _s19_pipe_reaction: + return set_pipe_reaction_cache(name, cs) + elif type == _s19_tank_reaction: + return set_tank_reaction_cache(name, cs) + elif type == _s20_mixing: + return set_mixing_cache(name, cs) + elif type == _s21_time: return set_time_cache(name, cs) - elif type == 'option': + elif type == _s22_report: # no api now + return None + elif type == _s23_option: return set_option_cache(name, cs) + elif type == _s24_coordinate: # do not support update here + return None + elif type == _s25_vertex: + return set_vertex_cache(name, cs) + elif type == _s26_label: + return set_label_cache(name, cs) + elif type == _s27_backdrop: + return set_backdrop_cache(name, cs) + elif type == _s28_end: # end + return None return None @@ -162,18 +427,68 @@ def cache_update_command(name: str, cs: ChangeSet) -> SqlChangeSet | None: def cache_delete_command(name: str, cs: ChangeSet) -> SqlChangeSet | None: type = cs.operations[0]['type'] - if type == JUNCTION: + if type == _s1_title: + return None + if type == _s2_junction: return delete_junction_cache(name, cs) - elif type == RESERVOIR: + elif type == _s3_reservoir: return delete_reservoir_cache(name, cs) - elif type == TANK: + elif type == _s4_tank: return delete_tank_cache(name, cs) - elif type == PIPE: + elif type == _s5_pipe: return delete_pipe_cache(name, cs) - elif type == PUMP: + elif type == _s6_pump: return delete_pump_cache(name, cs) - elif type == VALVE: + elif type == _s7_valve: return delete_valve_cache(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_cache(name, cs) + elif type == _s12_curve: + return delete_curve_cache(name, cs) + elif type == _s13_control: + return None + elif type == _s14_rule: + return None + elif type == _s15_global_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_cache(name, cs) + elif type == _s19_global_reaction: + return None + elif type == _s19_pipe_reaction: + return None + elif type == _s19_tank_reaction: + return None + elif type == _s20_mixing: + return delete_mixing_cache(name, cs) + elif type == _s21_time: + return None + elif type == _s22_report: + return None + elif type == _s23_option: + return None + elif type == _s24_coordinate: + return None + elif type == _s25_vertex: + return delete_vertex_cache(name, cs) + elif type == _s26_label: + return delete_label_cache(name, cs) + elif type == _s27_backdrop: + return None + elif type == _s28_end: + return None return None @@ -189,21 +504,33 @@ def execute_batch_command(name: str, cs: ChangeSet) -> ChangeSet: operation = op['operation'] r = None + demand = None if operation == API_ADD: r = cache_add_command(name, ChangeSet(op)) elif operation == API_UPDATE: r = cache_update_command(name, ChangeSet(op)) + if op['type'] == 'demand': + r = set_demand_cache(name, ChangeSet(op)) elif operation == API_DELETE: r = cache_delete_command(name, ChangeSet(op)) if r == None: return ChangeSet() - redo_sql_s.append(r.redo_sql) - undo_sql_s.append(r.undo_sql) - redo_cs_s.append(r.redo_cs) - undo_cs_s.append(r.undo_cs) + if op['type'] == 'demand': + redo_sql_s.append(r.redo_sql) + undo_sql_s.append(r.undo_sql) + for d in r.redo_cs: + redo_cs_s.append(d) + for d in r.undo_cs.reverse(): # need reverse again... + undo_cs_s.append(r.undo_cs) + else: + redo_sql_s.append(r.redo_sql) + undo_sql_s.append(r.undo_sql) + redo_cs_s.append(r.redo_cs) + undo_cs_s.append(r.undo_cs) + except: pass diff --git a/api/operation.py b/api/operation.py index cf0293e..39d2f22 100644 --- a/api/operation.py +++ b/api/operation.py @@ -43,14 +43,14 @@ class ChangeSet: class SqlChangeSet: - def __init__(self, redo_sql: str, undo_sql: str, redo_cs: dict[str, str], undo_cs: dict[str, str]) -> None: + def __init__(self, redo_sql: str, undo_sql: str, redo_cs: dict[str, Any], undo_cs: dict[str, Any]) -> None: self.redo_sql = redo_sql self.undo_sql = undo_sql self.redo_cs = redo_cs self.undo_cs = undo_cs class BatchSqlChangeSet: - def __init__(self, redo_sql: str, undo_sql: str, redo_cs: list[dict[str, str]], undo_cs: list[dict[str, str]]) -> None: + def __init__(self, redo_sql: str, undo_sql: str, redo_cs: list[dict[str, Any]], undo_cs: list[dict[str, Any]]) -> None: self.redo_sql = redo_sql self.undo_sql = undo_sql self.redo_cs = redo_cs diff --git a/api/s10_status.py b/api/s10_status.py index fbe2aec..823b232 100644 --- a/api/s10_status.py +++ b/api/s10_status.py @@ -66,3 +66,58 @@ def set_status_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def set_status(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, set_status_cache(name, cs)) + + +class InpStatus: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.link = str(tokens[0]) + self.value = tokens[1] + self.is_status = True + if self.value == LINK_STATUS_OPEN or self.value == LINK_STATUS_CLOSED or self.value == LINK_STATUS_ACTIVE: + self.status = str(self.value) + else: + self.setting = float(self.value) + self.is_status = False + + +def inp_in_status(section: list[str]) -> ChangeSet: + objs: dict[str, list[InpStatus]] = {} + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpStatus(s) + if obj.link not in objs: + objs[obj.link] = [] + objs[obj.link].append(obj) + + cs = ChangeSet() + for link, values in objs.items(): + obj_cs = {'operation': API_UPDATE, 'type': 'status', 'link' : link, 'status': None, 'setting': None} + for obj in values: + if obj.is_status: + obj_cs['status'] = obj.status + else: + obj_cs['setting'] = obj.setting + cs.append(obj_cs) + return cs + + +def inp_out_status(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from status') + for obj in objs: + link = obj['link'] + status = obj['status'] if obj['status'] != None else '' + setting = obj['setting'] if obj['setting'] != None else '' + if status != '': + lines.append(f'{link} {status}') + if setting != '': + lines.append(f'{link} {setting}') + return lines diff --git a/api/s11_patterns.py b/api/s11_patterns.py index 7b4a6d3..f53e3ab 100644 --- a/api/s11_patterns.py +++ b/api/s11_patterns.py @@ -91,3 +91,39 @@ def delete_pattern_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_pattern(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_pattern_cache(name, cs)) + + +def inp_in_pattern(section: list[str]) -> ChangeSet: + descs = {} + patterns: dict[str, list[float]] = {} + + count = len(section) + for i in range(0, count): + if section[i].startswith(';'): + # this is description + next = i + 1 + if next < count and section[next].startswith(';') == False: + next_tokens = section[next].split() + descs[next_tokens[0]] = section[i].removeprefix(';') + continue + + tokens = section[i].split() + if tokens[0] not in patterns: + patterns[tokens[0]] = [] + for token in tokens[1:]: + patterns[tokens[0]].append(float(token)) + + cs = ChangeSet() + for id, factors in patterns.items(): + cs.append({'operation': API_ADD, 'type': 'pattern', 'id' : id, 'factors' : factors}) + return cs + + +def inp_out_pattern(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from patterns order by _order") + for obj in objs: + id = obj['id'] + factor = obj['factor'] + lines.append(f'{id} {factor}') + return lines diff --git a/api/s12_curves.py b/api/s12_curves.py index eb8010d..e429061 100644 --- a/api/s12_curves.py +++ b/api/s12_curves.py @@ -119,3 +119,50 @@ def delete_curve_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_curve(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_curve_cache(name, cs)) + + +def inp_in_curve(section: list[str]) -> ChangeSet: + types = {} + descs = {} + curves: dict[str, list[dict[str, float]]] = {} + + count = len(section) + for i in range(0, count): + if section[i].startswith(';'): + # this is description + type_plus_desc = section[i].removeprefix(';') + type_plus_desc_tokens = type_plus_desc.split(':') + next = i + 1 + if next < count and section[next].startswith(';') == False: + next_tokens = section[next].split() + types[next_tokens[0]] = type_plus_desc_tokens[0].strip() + if len(type_plus_desc_tokens) > 1: + descs[next_tokens[0]] = type_plus_desc_tokens[1].strip() + continue + + tokens = section[i].split() + if tokens[0] not in curves: + curves[tokens[0]] = [] + curves[tokens[0]].append({'x': float(tokens[1]), 'y': float(tokens[2])}) + + cs = ChangeSet() + for id, coords in curves.items(): + c_type = types[id] if id in types else CURVE_TYPE_PUMP + cs.append({'operation': API_ADD, 'type': 'curve', 'id' : id, 'c_type': c_type, 'coords' : coords}) + return cs + + +def inp_out_curve(name: str) -> list[str]: + lines = [] + types = read_all(name, f"select * from _curve") + for type in types: + id = type['id'] + # ;type: desc + lines.append(f";{type['type']}:") + objs = read_all(name, f"select * from curves where id = '{id}' order by _order") + for obj in objs: + id = obj['id'] + x = obj['x'] + y = obj['y'] + lines.append(f'{id} {x} {y}') + return lines diff --git a/api/s13_controls.py b/api/s13_controls.py index 1deda79..6173167 100644 --- a/api/s13_controls.py +++ b/api/s13_controls.py @@ -24,3 +24,19 @@ def set_control_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def set_control(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, set_control_cache(name, cs)) + + +class InpControl: + def __init__(self, section) -> None: + self.control = '\n'.join(section) + + +def inp_in_control(section: list[str]) -> ChangeSet: + obj = InpControl(section) + cs = ChangeSet({'operation' : API_UPDATE, 'type': 'control', 'control' : obj.control}) + return cs + + +def inp_out_control(name: str) -> list[str]: + obj = str(get_control(name)['control']) + return obj.split('\n') diff --git a/api/s14_rules.py b/api/s14_rules.py index f8bed6c..e5d1834 100644 --- a/api/s14_rules.py +++ b/api/s14_rules.py @@ -24,3 +24,19 @@ def set_rule_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def set_rule(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, set_rule_cache(name, cs)) + + +class InpRule: + def __init__(self, section) -> None: + self.rule = '\n'.join(section) + + +def inp_in_rule(section: list[str]) -> ChangeSet: + obj = InpRule(section) + cs = ChangeSet({'operation' : API_UPDATE, 'type': 'rule', 'rule' : obj.rule}) + return cs + + +def inp_out_rule(name: str) -> list[str]: + obj = str(get_rule(name)['rule']) + return obj.split('\n') diff --git a/api/s1_title.py b/api/s1_title.py index dbf86ed..4a74810 100644 --- a/api/s1_title.py +++ b/api/s1_title.py @@ -25,3 +25,19 @@ def set_title_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def set_title(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, set_title_cache(name ,cs)) + + +class InpTitle: + def __init__(self, section) -> None: + self.value = '\n'.join(section) + + +def inp_in_title(section: list[str]) -> ChangeSet: + obj = InpTitle(section) + cs = ChangeSet({'operation' : API_ADD, 'type': 'title', 'value' : obj.value}) + return cs + + +def inp_out_title(name: str) -> list[str]: + obj = str(get_title(name)['value']) + return obj.split('\n') diff --git a/api/s21_times.py b/api/s21_times.py index e3c38c6..848ba9c 100644 --- a/api/s21_times.py +++ b/api/s21_times.py @@ -65,3 +65,24 @@ def set_time_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def set_time(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, set_time_cache(name, cs)) + + +def inp_in_time(section: list[str]) -> ChangeSet: + cs = g_update_prefix | { 'type' : 'time' } + for s in section: + line = s.upper().strip() + for key in get_time_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + cs |= { key : value } + return ChangeSet(cs) + + +def inp_out_time(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from times") + for obj in objs: + key = obj['key'] + value = obj['value'] + lines.append(f'{key} {value}') + return lines diff --git a/api/s23_options.py b/api/s23_options.py index 928379e..5d77569 100644 --- a/api/s23_options.py +++ b/api/s23_options.py @@ -103,3 +103,24 @@ def set_option_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def set_option(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, set_option_cache(name, cs)) + + +def inp_in_option(section: list[str]) -> ChangeSet: + cs = g_update_prefix | { 'type' : 'option' } + for s in section: + line = s.upper().strip() + for key in get_option_schema('').keys(): + if line.startswith(key): + value = line.removeprefix(key).strip() + cs |= { key : value } + return ChangeSet(cs) + + +def inp_out_option(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from options") + for obj in objs: + key = obj['key'] + value = obj['value'] + lines.append(f'{key} {value}') + return lines diff --git a/api/s24_coordinates.py b/api/s24_coordinates.py index 0e201cb..e28b48f 100644 --- a/api/s24_coordinates.py +++ b/api/s24_coordinates.py @@ -1,4 +1,4 @@ -from .operation import read +from .operation import * def _to_client_point(coord: str) -> dict[str, float]: @@ -9,3 +9,26 @@ def _to_client_point(coord: str) -> dict[str, float]: def get_node_coord(name: str, id: str) -> dict[str, float]: row = read(name, f"select * from coordinates where node = '{id}'") return _to_client_point(row['coord']) + +# exception ! need merge to node change set ! +def inp_in_coord(section: list[str]) -> dict[str, dict[str, float]]: + coords = {} + for s in section: + # skip comment + if s.startswith(';'): + continue + tokens = s.split() + coords[tokens[0]] = { 'x': tokens[1], 'y': tokens[2] } + return coords + + +def inp_out_junction(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from coordinates') + for obj in objs: + node = obj['node'] + coord = _to_client_point(obj['coord']) + x = coord['x'] + y = coord['y'] + lines.append(f'{node} {x} {y}') + return lines diff --git a/api/s25_vertices.py b/api/s25_vertices.py index c668af0..f9a5cc7 100644 --- a/api/s25_vertices.py +++ b/api/s25_vertices.py @@ -43,6 +43,21 @@ def set_vertex_cache(name: str, cs: ChangeSet) -> SqlChangeSet: return SqlChangeSet(redo_sql, undo_sql, redo_cs, undo_cs) +def add_vertex_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + result = set_vertex_cache(name, cs) + result.redo_cs |= g_add_prefix + result.undo_cs |= g_delete_prefix + return result + + +def delete_vertex_cache(name: str, cs: ChangeSet) -> SqlChangeSet: + cs.operations[0]['coords'] = [] + result = set_vertex_cache(name, cs) + result.redo_cs |= g_delete_prefix + result.undo_cs |= g_add_prefix + return result + + def set_vertex(name: str, cs: ChangeSet) -> ChangeSet: result = set_vertex_cache(name, cs) result.redo_cs |= g_update_prefix diff --git a/api/s2_junctions.py b/api/s2_junctions.py index cbcef1e..40a5bd7 100644 --- a/api/s2_junctions.py +++ b/api/s2_junctions.py @@ -118,3 +118,42 @@ def delete_junction_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_junction(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_junction_cache(name, cs)) + + +class InpJunction: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.id = str(tokens[0]) + self.elevation = float(tokens[1]) + self.demand = float(tokens[2]) if num_without_desc >= 3 else None + self.pattern = str(tokens[3]) if num_without_desc >= 4 else None + self.desc = str(tokens[-1]) if has_desc else None + + +def inp_in_junction(section: list[str]) -> ChangeSet: + cs = ChangeSet() + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpJunction(s) + cs.append({'operation': API_ADD, 'type': 'junction', 'id': obj.id, 'elevation': obj.elevation, 'demand': obj.demand, 'pattern': obj.pattern}) + return cs + + +def inp_out_junction(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from junctions') + for obj in objs: + id = obj['id'] + elev = obj['elevation'] + demand = obj['demand'] if obj['demand'] != None else '' + pattern = obj['pattern'] if obj['pattern'] != None else '' + desc = ';' + lines.append(f'{id} {elev} {demand} {pattern} {desc}') + return lines diff --git a/api/s3_reservoirs.py b/api/s3_reservoirs.py index 541af9d..d8422f5 100644 --- a/api/s3_reservoirs.py +++ b/api/s3_reservoirs.py @@ -114,3 +114,40 @@ def delete_reservoir_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_reservoir(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_reservoir_cache(name, cs)) + + +class InpReservoir: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.id = str(tokens[0]) + self.head = float(tokens[1]) + self.pattern = str(tokens[2]) if num_without_desc >= 3 else None + self.desc = str(tokens[-1]) if has_desc else None + + +def inp_in_reservoir(section: list[str]) -> ChangeSet: + cs = ChangeSet() + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpReservoir(s) + cs.append({'operation': API_ADD, 'type': 'reservoir', 'id': obj.id, 'head': obj.head, 'pattern': obj.pattern}) + return cs + + +def inp_out_reservoir(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from reservoirs') + for obj in objs: + id = obj['id'] + head = obj['head'] + pattern = obj['pattern'] if obj['pattern'] != None else '' + desc = ';' + lines.append(f'{id} {head} {pattern} {desc}') + return lines diff --git a/api/s4_tanks.py b/api/s4_tanks.py index cc57cb9..401b1ba 100644 --- a/api/s4_tanks.py +++ b/api/s4_tanks.py @@ -142,3 +142,52 @@ def delete_tank_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_tank(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_tank_cache(name, cs)) + + +class InpTank: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.id = str(tokens[0]) + self.elevation = float(tokens[1]) + self.init_level = float(tokens[2]) + self.min_level = float(tokens[3]) + self.max_level = float(tokens[4]) + self.diameter = float(tokens[5]) + self.min_vol = float(tokens[6]) + self.vol_curve = str(tokens[7]) if num_without_desc >= 8 else None + self.overflow = str(tokens[8]) if num_without_desc >= 9 else None + self.desc = str(tokens[-1]) if has_desc else None + + +def inp_in_tank(section: list[str]) -> ChangeSet: + cs = ChangeSet() + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpTank(s) + cs.append({'operation': API_ADD, 'type': 'tank', 'id': obj.id, 'elevation': obj.elevation, 'init_level': obj.init_level, 'min_level': obj.min_level, 'max_level': obj.max_level, 'diameter': obj.diameter, 'min_vol': obj.min_vol, 'vol_curve': obj.vol_curve, 'overflow': obj.overflow}) + return cs + + +def inp_out_tank(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from tanks') + for obj in objs: + id = obj['id'] + elevation = obj['elevation'] + init_level = obj['init_level'] + min_level = obj['min_level'] + max_level = obj['max_level'] + diameter = obj['diameter'] + min_vol = obj['min_vol'] + vol_curve = obj['vol_curve'] if obj['vol_curve'] != None else '' + overflow = obj['overflow'] if obj['overflow'] != None else '' + desc = ';' + lines.append(f'{id} {elevation} {init_level} {min_level} {max_level} {diameter} {min_vol} {vol_curve} {overflow} {desc}') + return lines diff --git a/api/s5_pipes.py b/api/s5_pipes.py index bb85194..8b7a482 100644 --- a/api/s5_pipes.py +++ b/api/s5_pipes.py @@ -121,3 +121,51 @@ def delete_pipe_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_pipe(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_pipe_cache(name, cs)) + + +class InpPipe: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.id = str(tokens[0]) + self.node1 = str(tokens[1]) + self.node2 = str(tokens[2]) + self.length = float(tokens[3]) + self.diameter = float(tokens[4]) + self.roughness = float(tokens[5]) + self.minor_loss = float(tokens[6]) + # status is must-have, here fix input + self.status = str(tokens[7]) if num_without_desc >= 8 else PIPE_STATUS_OPEN + self.desc = str(tokens[-1]) if has_desc else None + + +def inp_in_pipe(section: list[str]) -> ChangeSet: + cs = ChangeSet() + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpPipe(s) + cs.append({'operation': API_ADD, 'type': 'pipe', 'id': obj.id, 'node1': obj.node1, 'node2': obj.node2, 'length': obj.length, 'diameter': obj.diameter, 'roughness': obj.roughness, 'minor_loss': obj.minor_loss, 'status': obj.status}) + return cs + + +def inp_out_pipe(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from pipes') + for obj in objs: + id = obj['id'] + node1 = obj['node1'] + node2 = obj['node2'] + length = obj['length'] + diameter = obj['diameter'] + roughness = obj['roughness'] + minor_loss = obj['minor_loss'] + status = obj['vol_curve'] + desc = ';' + lines.append(f'{id} {node1} {node2} {length} {diameter} {roughness} {minor_loss} {status} {desc}') + return lines diff --git a/api/s6_pumps.py b/api/s6_pumps.py index 3fc4bb8..04781d2 100644 --- a/api/s6_pumps.py +++ b/api/s6_pumps.py @@ -112,3 +112,51 @@ def delete_pump_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_pump(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_pump_cache(name, cs)) + + +class InpPump: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.id = str(tokens[0]) + self.node1 = str(tokens[1]) + self.node2 = str(tokens[2]) + self.props = {} + for i in range(3, num_without_desc, 2): + self.props |= { tokens[i].lower(): tokens[i + 1] } + self.power = float(self.props['power']) if 'power' in self.props else None + self.head = str(self.props['head']) if 'head' in self.props else None + self.speed = float(self.props['speed']) if 'speed' in self.props else None + self.pattern = str(self.props['pattern']) if 'pattern' in self.props else None + self.desc = str(tokens[-1]) if has_desc else None + + +def inp_in_pump(section: list[str]) -> ChangeSet: + cs = ChangeSet() + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpPump(s) + cs.append({'operation': API_ADD, 'type': 'pump', 'id': obj.id, 'node1': obj.node1, 'node2': obj.node2, 'power': obj.power, 'head': obj.head, 'speed': obj.speed, 'pattern': obj.pattern}) + return cs + + +def inp_out_pump(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from pumps') + for obj in objs: + id = obj['id'] + node1 = obj['node1'] + node2 = obj['node2'] + power = f"POWER {obj['power']}" if obj['power'] != None else '' + head = f"HEAD {obj['head']}" if obj['head'] != None else '' + speed = f"SPEED {obj['speed']}" if obj['speed'] != None else '' + pattern = f"PATTERN {obj['pattern']}" if obj['pattern'] != None else '' + desc = ';' + lines.append(f'{id} {node1} {node2} {power} {head} {speed} {pattern} {desc}') + return lines diff --git a/api/s7_valves.py b/api/s7_valves.py index 4a24b1a..b9cbe22 100644 --- a/api/s7_valves.py +++ b/api/s7_valves.py @@ -120,3 +120,48 @@ def delete_valve_cache(name: str, cs: ChangeSet) -> SqlChangeSet: def delete_valve(name: str, cs: ChangeSet) -> ChangeSet: return execute_command(name, delete_valve_cache(name, cs)) + + +class InpValve: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.id = str(tokens[0]) + self.node1 = str(tokens[1]) + self.node2 = str(tokens[2]) + self.diameter = float(tokens[3]) + self.v_type = str(tokens[4]) + self.setting = float(tokens[5]) + self.minor_loss = float(tokens[6]) + self.desc = str(tokens[-1]) if has_desc else None + + +def inp_in_valve(section: list[str]) -> ChangeSet: + cs = ChangeSet() + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpValve(s) + cs.append({'operation': API_ADD, 'type': 'valve', 'id': obj.id, 'node1': obj.node1, 'node2': obj.node2, 'diameter': obj.diameter, 'v_type': obj.v_type, 'setting': obj.setting, 'minor_loss': obj.minor_loss}) + return cs + + +def inp_out_valve(name: str) -> list[str]: + lines = [] + objs = read_all(name, 'select * from valves') + for obj in objs: + id = obj['id'] + node1 = obj['node1'] + node2 = obj['node2'] + diameter = obj['diameter'] + v_type = obj['type'] + setting = obj['setting'] + minor_loss = obj['minor_loss'] + desc = ';' + lines.append(f'{id} {node1} {node2} {diameter} {v_type} {setting} {minor_loss} {desc}') + return lines diff --git a/api/s9_demands.py b/api/s9_demands.py index 399e77d..13fc0d7 100644 --- a/api/s9_demands.py +++ b/api/s9_demands.py @@ -84,3 +84,49 @@ def set_demand_cache(name: str, cs: ChangeSet) -> BatchSqlChangeSet: def set_demand(name: str, cs: ChangeSet) -> ChangeSet: css = set_demand_cache(name, cs) return execute_batch(name, css.redo_sql, css.undo_sql, css.redo_cs, css.undo_cs) + + +class InpDemand: + def __init__(self, line: str) -> None: + tokens = line.split() + + num = len(tokens) + has_desc = tokens[-1].startswith(';') + num_without_desc = (num - 1) if has_desc else num + + self.junction = str(tokens[0]) + self.demand = float(tokens[1]) + self.pattern = str(tokens[2]) if num_without_desc >= 3 else None + self.category = str(tokens[3]) if num_without_desc >= 4 else None + + +def inp_in_demand(section: list[str]) -> ChangeSet: + objs: dict[str, list[InpDemand]] = {} + for s in section: + # skip comment + if s.startswith(';'): + continue + obj = InpDemand(s) + if obj.junction not in objs: + objs[obj.junction] = [] + objs[obj.junction].append(obj) + + cs = ChangeSet() + for junction, demands in objs.items(): + obj_cs = {'operation': API_UPDATE, 'type': 'demand', 'junction' : junction, 'demands' : []} + for obj in demands: + obj_cs['demands'].append({'demand': obj.demand, 'pattern' : obj.pattern, 'category': obj.category}) + cs.append(obj_cs) + return cs + + +def inp_out_demand(name: str) -> list[str]: + lines = [] + objs = read_all(name, f"select * from demands order by _order") + for obj in objs: + junction = obj['junction'] + demand = obj['demand'] + patten = obj['patten'] if obj['patten'] != None else '' + category = f";{obj['category']}" if obj['category'] != None else ';' + lines.append(f'{junction} {demand} {patten} {category}') + return lines