Accept Merge Request #61: (api -> master)

Merge Request: Merge many apis

Created By: @王琼钰
Accepted By: @王琼钰
URL: https://tjwater.coding.net/p/tjwatercloud/d/TJWaterServer/git/merge/61
This commit is contained in:
王琼钰
2022-10-26 18:39:12 +08:00
41 changed files with 1588 additions and 201 deletions

7
.gitignore vendored
View File

@@ -1,3 +1,6 @@
# vscode
.vscode/
# python cache
__pycache__/
@@ -7,4 +10,6 @@ __pycache__/
# epanet
*.rpt
*.opt
.vscode/
# dev_demo
dev_demo.py

View File

@@ -13,7 +13,7 @@ from .operation import pick_operation, sync_with_server
from .command import execute_batch_commands
from .s0_base import JUNCTION, RESERVOIR, TANK, PIPE, PUMP, VALVE
from .s0_base import JUNCTION, RESERVOIR, TANK, PIPE, PUMP, VALVE, PATTERN, CURVE
from .s0_base import is_node, is_junction, is_reservoir, is_tank
from .s0_base import is_link, is_pipe, is_pump, is_valve
from .s0_base import is_curve
@@ -38,4 +38,25 @@ from .s6_pumps import get_pump_schema, add_pump, get_pump, set_pump, delete_pump
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, delete_valve
from .s9_demands import get_demand_schema, get_demand, set_demand
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
from .s12_curves import get_curve_schema, get_curve, set_curve
from .s16_emitters import get_emitter_schema, get_emitter, set_emitter
from .s21_times import TIME_STATISTIC_NONE, TIME_STATISTIC_AVERAGED, TIME_STATISTIC_MINIMUM, TIME_STATISTIC_MAXIMUM, TIME_STATISTIC_RANGE
from .s21_times import get_time_schema, get_time, set_time
from .s23_options import OPTION_UNITS_CFS, OPTION_UNITS_GPM, OPTION_UNITS_MGD, OPTION_UNITS_IMGD, OPTION_UNITS_AFD, OPTION_UNITS_LPS, OPTION_UNITS_LPM, OPTION_UNITS_MLD, OPTION_UNITS_CMH, OPTION_UNITS_CMD
from .s23_options import OPTION_HEADLOSS_HW, OPTION_HEADLOSS_DW, OPTION_HEADLOSS_CM
from .s23_options import OPTION_UNBALANCED_STOP, OPTION_UNBALANCED_CONTINUE
from .s23_options import OPTION_DEMAND_MODEL_DDA, OPTION_DEMAND_MODEL_PDA
from .s23_options import OPTION_QUALITY_NONE, OPTION_QUALITY_CHEMICAL, OPTION_QUALITY_AGE, OPTION_QUALITY_TRACE
from .s23_options import get_option_schema, get_option, set_option
from .s24_coordinates import get_node_coord

View File

@@ -5,6 +5,13 @@ from .s4_tanks import *
from .s5_pipes import *
from .s6_pumps import *
from .s7_valves import *
from .s9_demands import *
from .s10_status import *
from .s11_patterns import *
from .s12_curves import *
from .s16_emitters import *
from .s21_times import *
from .s23_options import *
def execute_add_command(name: str, cs: ChangeSet) -> ChangeSet:
@@ -43,6 +50,20 @@ def execute_update_command(name: str, cs: ChangeSet) -> ChangeSet:
return set_pump(name, cs)
elif type == VALVE:
return set_valve(name, cs)
elif type == 'demand':
return set_demand(name, cs)
elif type == 'status':
return set_status(name, cs)
elif type == PATTERN:
return set_pattern(name, cs)
elif type == CURVE:
return set_curve(name, cs)
elif type == 'emitter':
return set_emitter(name, cs)
elif type == 'time':
return set_time(name, cs)
elif type == 'option':
return set_option(name, cs)
return ChangeSet()

View File

@@ -51,6 +51,18 @@ def read(name: str, sql: str) -> Row:
return row
def read_all(name: str, sql: str) -> list[Row]:
with conn[name].cursor(row_factory=dict_row) as cur:
cur.execute(sql)
return cur.fetchall()
def try_read(name: str, sql: str) -> Row | None:
with conn[name].cursor(row_factory=dict_row) as cur:
cur.execute(sql)
return cur.fetchone()
def write(name: str, sql: str) -> None:
with conn[name].cursor() as cur:
cur.execute(sql)

View File

@@ -7,6 +7,14 @@ from .s4_tanks import *
from .s5_pipes import *
from .s6_pumps import *
from .s7_valves import *
from .s9_demands import *
from .s10_status import *
from .s11_patterns import *
from .s12_curves import *
from .s16_emitters import *
from .s21_times import *
from .s23_options import *
def read_inp(name: str, inp: str):
if is_project_open(name):
@@ -18,19 +26,30 @@ def read_inp(name: str, inp: str):
create_project(name)
open_project(name)
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]] = {}
section = ''
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] = {}
for line in open(inp):
line = line.lstrip()
line = line.strip()
if line.startswith(';'):
continue
if line.endswith(';'):
line = line.removesuffix(';')
if line.startswith('[TITLE'):
section = 'title'
@@ -53,6 +72,27 @@ def read_inp(name: str, inp: str):
if line.startswith('[VALVE'):
section = VALVE
continue
if line.startswith('[DEMAND'):
section = 'demand'
continue
if line.startswith('[STATUS'):
section = 'status'
continue
if line.startswith('[PATTERN'):
section = PATTERN
continue
if line.startswith('[CURVE'):
section = CURVE
continue
if line.startswith('[EMITTER'):
section = 'emitter'
continue
if line.startswith('[TIME'):
section = 'time'
continue
if line.startswith('[OPTION'):
section = 'option'
continue
if line.startswith('[COORDINATE'):
section = 'coordinate'
continue
@@ -60,38 +100,98 @@ def read_inp(name: str, inp: str):
section = ''
continue
tokens = line.split()
if len(tokens) == 0:
tokens = []
if section == 'time' or section == 'option':
tokens = line.upper().split()
else:
tokens = line.split()
tokens_len = len(tokens)
if tokens_len == 0:
continue
if section == 'title':
# set_title(name, ChangeSet({'value': tokens[0]}))
if title == '':
title += '\n'
title += line
continue
elif section == JUNCTION:
if tokens[0] not in junctions:
junctions[tokens[0]] = {}
junctions[tokens[0]] |= {'id': tokens[0], 'elevation': tokens[1]}
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}
continue
elif section == RESERVOIR:
if tokens[0] not in reservoirs:
reservoirs[tokens[0]] = {}
reservoirs[tokens[0]] |= {'id': tokens[0], 'head': tokens[1]}
reservoir_pattern = tokens[2] if tokens_len == 3 else None
reservoirs[tokens[0]] = {'id': tokens[0], 'head': tokens[1], 'pattern': reservoir_pattern}
continue
elif section == TANK:
if tokens[0] not in tanks:
tanks[tokens[0]] = {}
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]}
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}
continue
elif section == PIPE:
if len(tokens) == 7:
tokens.append(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': tokens[7].lower()}
# 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}
continue
elif section == PUMP:
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] }
continue
elif section == VALVE:
valves[tokens[0]] = {'id': tokens[0], 'node1': tokens[1], 'node2': tokens[2], 'diameter': tokens[3], 'v_type': tokens[4].lower(), 'setting': tokens[5], 'minor_loss': tokens[6]}
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})
continue
elif section == 'status':
if tokens[0] not in status:
status[tokens[0]] = {}
setting = None
try:
setting = float(tokens[1])
except:
setting = None
if setting != None:
status[tokens[0]]['setting'] = setting
else:
status[tokens[0]]['status'] = tokens[1].upper()
continue
elif section == PATTERN:
if tokens[0] not in patterns:
patterns[tokens[0]] = []
for i in range(1, tokens_len):
patterns[tokens[0]].append(float(tokens[i]))
continue
elif section == CURVE:
if tokens[0] not in curves:
curves[tokens[0]] = []
for i in range(1, tokens_len, 2):
curves[tokens[0]].append({ 'x': float(tokens[i]), 'y': float(tokens[i + 1]) })
continue
elif section == 'emitter':
emitters[tokens[0]] = float(tokens[1])
continue
elif section == 'time':
if tokens_len == 2:
times[tokens[0]] = tokens[1]
elif tokens_len == 3:
times[tokens[0] + ' ' + tokens[1]] = tokens[2]
elif tokens_len == 4:
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]
elif tokens_len == 3:
if tokens[0] == 'UNBALANCED' or tokens[0] == 'QUALITY':
options[tokens[0]] = tokens[1] + ' ' + tokens[2]
else:
options[tokens[0] + ' ' + tokens[1]] = tokens[2]
continue
elif section == 'coordinate':
if tokens[0] in junctions:
@@ -102,27 +202,69 @@ def read_inp(name: str, inp: str):
tanks[tokens[0]] |= {'x': tokens[1], 'y': tokens[2]}
continue
# title
set_title(name, ChangeSet({ 'value': title }))
# pattern
for key, value in patterns.items():
set_pattern(name, ChangeSet({'id': key, 'factors': value}))
# curve
for key, value in curves.items():
set_curve(name, ChangeSet({'id': key, 'coords': value}))
# junction
for value in junctions.values():
if 'x' not in value:
value['x'] = 0.0
if 'y' not in value:
value['y'] = 0.0
add_junction(name, ChangeSet(value))
# reservoir
for value in reservoirs.values():
if 'x' not in value:
value['x'] = 0.0
if 'y' not in value:
value['y'] = 0.0
add_reservoir(name, ChangeSet(value))
# tank
for value in tanks.values():
if 'x' not in value:
value['x'] = 0.0
if 'y' not in value:
value['y'] = 0.0
add_tank(name, ChangeSet(value))
# pipe
for value in pipes.values():
add_pipe(name, ChangeSet(value))
# pump
for value in pumps.values():
add_pump(name, ChangeSet(value))
# valve
for value in valves.values():
add_valve(name, ChangeSet(value))
# demand
for key, value in demands.items():
set_demand(name, ChangeSet({'junction': key, 'demands': value}))
# status
for key, value in status.items():
set_status(name, ChangeSet({'link': key} | value))
# emitter
for key, value in emitters.items():
set_emitter(name, ChangeSet({'junction': key, 'coefficient': value}))
# time
set_time(name, ChangeSet(times))
# option
set_option(name, ChangeSet(options))
close_project(name)

View File

@@ -3,17 +3,20 @@ from .connection import g_conn_dict as conn
from .operation import *
_NODE = "_node"
_LINK = "_link"
_CURVE = "_curve"
_PATTERN = "_pattern"
_NODE = '_node'
_LINK = '_link'
_CURVE = '_curve'
_PATTERN = '_pattern'
JUNCTION = "junction"
RESERVOIR = "reservoir"
TANK = "tank"
PIPE = "pipe"
PUMP = "pump"
VALVE = "valve"
JUNCTION = 'junction'
RESERVOIR = 'reservoir'
TANK = 'tank'
PIPE = 'pipe'
PUMP = 'pump'
VALVE = 'valve'
PATTERN = 'pattern'
CURVE = 'curve'
def _get_from(name: str, id: str, base_type: str) -> Row | None:

64
api/s10_status.py Normal file
View File

@@ -0,0 +1,64 @@
from .operation import *
LINK_STATUS_OPEN = 'OPEN'
LINK_STATUS_CLOSED = 'CLOSED'
LINK_STATUS_ACTIVE = 'ACTIVE'
def get_status_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'link' : {'type': 'str' , 'optional': False , 'readonly': True },
'status' : {'type': 'str' , 'optional': True , 'readonly': False},
'setting' : {'type': 'float' , 'optional': True , 'readonly': False} }
def get_status(name: str, link: str) -> dict[str, Any]:
s = try_read(name, f"select * from status where link = '{link}'")
if s == None:
return { 'link': link, 'status': None, 'setting': None }
d = {}
d['link'] = str(s['link'])
d['status'] = str(s['status']) if s['status'] != None else None
d['setting'] = float(s['setting']) if s['setting'] != None else None
return d
class Status(object):
def __init__(self, input: dict[str, Any]) -> None:
self.type = 'status'
self.link = str(input['link'])
self.status = str(input['status']) if 'status' in input and input['status'] != None else None
self.setting = float(input['setting']) if 'setting' in input and input['setting'] != None else None
self.f_type = f"'{self.type}'"
self.f_link = f"'{self.link}'"
self.f_status = f"'{self.status}'" if self.status != None else 'null'
self.f_setting = self.setting if self.setting != None else 'null'
def as_dict(self) -> dict[str, Any]:
return { 'type': self.type, 'link': self.link, 'status': self.status, 'setting': self.setting }
def set_status(name: str, cs: ChangeSet) -> ChangeSet:
old = Status(get_status(name, cs.operations[0]['link']))
raw_new = get_status(name, cs.operations[0]['link'])
new_dict = cs.operations[0]
schema = get_status_schema(name)
for key, value in schema.items():
if key in new_dict and not value['readonly']:
raw_new[key] = new_dict[key]
new = Status(raw_new)
redo_sql = f"delete from status where link = {new.f_link};"
if new.status != None or new.setting != None:
redo_sql += f"\ninsert into status (link, status, setting) values ({new.f_link}, {new.f_status}, {new.f_setting});"
undo_sql = f"delete from status where link = {old.f_link};"
if old.status != None or old.setting != None:
undo_sql += f"\ninsert into status (link, status, setting) values ({old.f_link}, {old.f_status}, {old.f_setting});"
redo_cs = g_update_prefix | new.as_dict()
undo_cs = g_update_prefix | old.as_dict()
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

45
api/s11_patterns.py Normal file
View File

@@ -0,0 +1,45 @@
from .operation import *
def get_pattern_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'factors' : {'type': 'float_list' , 'optional': False , 'readonly': False } }
def get_pattern(name: str, id: str) -> dict[str, Any]:
pas = read_all(name, f"select * from patterns where id = '{id}'")
ps = []
for r in pas:
ps.append(float(r['factor']))
return { 'id': id, 'factors': ps }
def set_pattern(name: str, cs: ChangeSet) -> ChangeSet:
id = cs.operations[0]['id']
old = get_pattern(name, id)
new = { 'id': id, 'factors': [] }
f_id = f"'{id}'"
# TODO: transaction ?
redo_sql = f"delete from patterns where id = {f_id};"
redo_sql += f"\ndelete from _pattern where id = {f_id};"
if len(cs.operations[0]['factors']) > 0:
redo_sql += f"\ninsert into _pattern (id) values ({f_id});"
for factor in cs.operations[0]['factors']:
f_factor = float(factor)
redo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});"
new['factors'].append(factor)
undo_sql = f"delete from patterns where id = {f_id};"
undo_sql += f"\ndelete from _pattern where id = {f_id};"
if len(old['factors']) > 0:
undo_sql += f"\ninsert into _pattern (id) values ({f_id});"
for f_factor in old['factors']:
undo_sql += f"\ninsert into patterns (id, factor) values ({f_id}, {f_factor});"
redo_cs = g_update_prefix | { 'type': 'pattern' } | new
undo_cs = g_update_prefix | { 'type': 'pattern' } | old
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

49
api/s12_curves.py Normal file
View File

@@ -0,0 +1,49 @@
from .operation import *
def get_curve_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'coords' : {'type': 'list' , 'optional': False , 'readonly': False,
'element': { 'x' : {'type': 'float' , 'optional': False , 'readonly': False },
'y' : {'type': 'float' , 'optional': False , 'readonly': False } }}}
def get_curve(name: str, id: str) -> dict[str, Any]:
cus = read_all(name, f"select * from curves where id = '{id}'")
cs = []
for r in cus:
cs.append({ 'x': float(r['x']), 'y': float(r['y']) })
return { 'id': id, 'coords': cs }
def set_curve(name: str, cs: ChangeSet) -> ChangeSet:
id = cs.operations[0]['id']
old = get_curve(name, id)
new = { 'id': id, 'coords': [] }
f_id = f"'{id}'"
# TODO: transaction ?
redo_sql = f"delete from curves where id = {f_id};"
redo_sql += f"\ndelete from _curve where id = {f_id};"
if len(cs.operations[0]['coords']) > 0:
redo_sql += f"\ninsert into _curve (id) values ({f_id});"
for xy in cs.operations[0]['coords']:
x, y = float(xy['x']), float(xy['y'])
f_x, f_y = x, y
redo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});"
new['coords'].append({ 'x': x, 'y': y })
undo_sql = f"delete from curves where id = {f_id};"
undo_sql += f"\ndelete from _curve where id = {f_id};"
if len(old['coords']) > 0:
undo_sql += f"\ninsert into _curve (id) values ({f_id});"
for xy in old['coords']:
f_x, f_y = xy['x'], xy['y']
undo_sql += f"\ninsert into curves (id, x, y) values ({f_id}, {f_x}, {f_y});"
redo_cs = g_update_prefix | { 'type': 'curve' } | new
undo_cs = g_update_prefix | { 'type': 'curve' } | old
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

55
api/s16_emitters.py Normal file
View File

@@ -0,0 +1,55 @@
from .operation import *
def get_emitter_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'junction' : {'type': 'str' , 'optional': False , 'readonly': True },
'coefficient' : {'type': 'float' , 'optional': True , 'readonly': False} }
def get_emitter(name: str, junction: str) -> dict[str, Any]:
e = try_read(name, f"select * from emitters where junction = '{junction}'")
if e == None:
return { 'junction': junction, 'coefficient': None }
d = {}
d['junction'] = str(e['junction'])
d['coefficient'] = float(e['coefficient']) if e['coefficient'] != None else None
return d
class Emitter(object):
def __init__(self, input: dict[str, Any]) -> None:
self.type = 'emitter'
self.junction = str(input['junction'])
self.coefficient = float(input['coefficient']) if 'coefficient' in input and input['coefficient'] != None else None
self.f_type = f"'{self.type}'"
self.f_junction = f"'{self.junction}'"
self.f_coefficient = self.coefficient if self.coefficient != None else 'null'
def as_dict(self) -> dict[str, Any]:
return { 'type': self.type, 'junction': self.junction, 'coefficient': self.coefficient }
def set_emitter(name: str, cs: ChangeSet) -> ChangeSet:
old = Emitter(get_emitter(name, cs.operations[0]['junction']))
raw_new = get_emitter(name, cs.operations[0]['junction'])
new_dict = cs.operations[0]
schema = get_emitter_schema(name)
for key, value in schema.items():
if key in new_dict and not value['readonly']:
raw_new[key] = new_dict[key]
new = Emitter(raw_new)
redo_sql = f"delete from emitters where junction = {new.f_junction};"
if new.coefficient != None:
redo_sql += f"\ninsert into emitters (junction, coefficient) values ({new.f_junction}, {new.f_coefficient});"
undo_sql = f"delete from emitters where junction = {old.f_junction};"
if old.coefficient != None:
undo_sql += f"\ninsert into emitters (junction, coefficient) values ({old.f_junction}, {old.f_coefficient});"
redo_cs = g_update_prefix | new.as_dict()
undo_cs = g_update_prefix | old.as_dict()
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

63
api/s21_times.py Normal file
View File

@@ -0,0 +1,63 @@
from .operation import *
TIME_STATISTIC_NONE = 'NONE'
TIME_STATISTIC_AVERAGED = 'AVERAGED'
TIME_STATISTIC_MINIMUM = 'MINIMUM'
TIME_STATISTIC_MAXIMUM = 'MAXIMUM'
TIME_STATISTIC_RANGE = 'RANGE'
element_schema = {'type': 'str' , 'optional': True , 'readonly': False}
def get_time_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'DURATION' : element_schema,
'HYDRAULIC TIMESTEP' : element_schema,
'QUALITY TIMESTEP' : element_schema,
'RULE TIMESTEP' : element_schema,
'PATTERN TIMESTEP' : element_schema,
'PATTERN START' : element_schema,
'REPORT TIMESTEP' : element_schema,
'REPORT START' : element_schema,
'START CLOCKTIME' : element_schema,
'STATISTIC' : element_schema}
def get_time(name: str) -> dict[str, Any]:
ts = read_all(name, f"select * from times")
d = {}
for e in ts:
d[e['key']] = str(e['value'])
return d
def set_time(name: str, cs: ChangeSet) -> ChangeSet:
raw_old = get_time(name)
old = {}
new = {}
new_dict = cs.operations[0]
schema = get_time_schema(name)
for key in schema.keys():
if key in new_dict:
old[key] = str(raw_old[key])
new[key] = str(new_dict[key])
redo_cs = g_update_prefix | { 'type' : 'time' }
redo_sql = ''
for key, value in new.items():
if redo_sql != '':
redo_sql += '\n'
redo_sql += f"update times set value = '{value}' where key = '{key}';"
redo_cs |= { key: value }
undo_cs = g_update_prefix | { 'type' : 'time' }
undo_sql = ''
for key, value in old.items():
if undo_sql != '':
undo_sql += '\n'
undo_sql += f"update times set value = '{value}' where key = '{key}';"
undo_cs |= { key: value }
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

101
api/s23_options.py Normal file
View File

@@ -0,0 +1,101 @@
from .operation import *
OPTION_UNITS_CFS = 'CFS'
OPTION_UNITS_GPM = 'GPM'
OPTION_UNITS_MGD = 'MGD'
OPTION_UNITS_IMGD = 'IMGD'
OPTION_UNITS_AFD = 'AFD'
OPTION_UNITS_LPS = 'LPS'
OPTION_UNITS_LPM = 'LPM'
OPTION_UNITS_MLD = 'MLD'
OPTION_UNITS_CMH = 'CMH'
OPTION_UNITS_CMD = 'CMD'
OPTION_HEADLOSS_HW = 'H-W'
OPTION_HEADLOSS_DW = 'D-W'
OPTION_HEADLOSS_CM = 'C-M'
#OPTION_HYDRAULICS_USE = 'USE'
#OPTION_HYDRAULICS_SAVE = 'SAVE'
OPTION_UNBALANCED_STOP = 'STOP'
OPTION_UNBALANCED_CONTINUE = 'CONTINUE'
OPTION_DEMAND_MODEL_DDA = 'DDA'
OPTION_DEMAND_MODEL_PDA = 'PDA'
OPTION_QUALITY_NONE = 'NONE'
OPTION_QUALITY_CHEMICAL = 'CHEMICAL'
OPTION_QUALITY_AGE = 'AGE'
OPTION_QUALITY_TRACE = 'TRACE'
element_schema = {'type': 'str' , 'optional': True , 'readonly': False}
def get_option_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'UNITS' : element_schema,
'HEADLOSS' : element_schema,
#'HYDRAULICS' : element_schema,
'VISCOSITY' : element_schema,
'SPECIFIC GRAVITY' : element_schema,
'TRIALS' : element_schema,
'ACCURACY' : element_schema,
'FLOWCHANGE' : element_schema,
'HEADERROR' : element_schema,
'CHECKFREQ' : element_schema,
'MAXCHECK' : element_schema,
'DAMPLIMIT' : element_schema,
'UNBALANCED' : element_schema,
'DEMAND MODEL' : element_schema,
'MINIMUM PRESSURE' : element_schema,
'REQUIRED PRESSURE' : element_schema,
'PRESSURE EXPONENT' : element_schema,
'PATTERN' : element_schema,
'DEMAND MULTIPLIER' : element_schema,
'EMITTER EXPONENT' : element_schema,
'QUALITY' : element_schema,
'DIFFUSIVITY' : element_schema,
'TOLERANCE' : element_schema,
#'QUALITY' : element_schema,
}
def get_option(name: str) -> dict[str, Any]:
ts = read_all(name, f"select * from options")
d = {}
for e in ts:
d[e['key']] = str(e['value'])
return d
def set_option(name: str, cs: ChangeSet) -> ChangeSet:
raw_old = get_option(name)
old = {}
new = {}
new_dict = cs.operations[0]
schema = get_option_schema(name)
for key in schema.keys():
if key in new_dict:
old[key] = str(raw_old[key])
new[key] = str(new_dict[key])
redo_cs = g_update_prefix | { 'type' : 'option' }
redo_sql = ''
for key, value in new.items():
if redo_sql != '':
redo_sql += '\n'
redo_sql += f"update options set value = '{value}' where key = '{key}';"
redo_cs |= { key: value }
undo_cs = g_update_prefix | { 'type' : 'option' }
undo_sql = ''
for key, value in old.items():
if undo_sql != '':
undo_sql += '\n'
undo_sql += f"update options set value = '{value}' where key = '{key}';"
undo_cs |= { key: value }
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

View File

@@ -7,10 +7,10 @@ def get_junction_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'x' : {'type': 'float' , 'optional': False , 'readonly': False},
'y' : {'type': 'float' , 'optional': False , 'readonly': False},
'elevation' : {'type': "float" , 'optional': False , 'readonly': False},
'demand' : {'type': "float" , 'optional': True , 'readonly': False},
'pattern' : {'type': "str" , 'optional': True , 'readonly': False},
'links' : {'type': "str_list" , 'optional': False , 'readonly': True } }
'elevation' : {'type': 'float' , 'optional': False , 'readonly': False},
'demand' : {'type': 'float' , 'optional': True , 'readonly': False},
'pattern' : {'type': 'str' , 'optional': True , 'readonly': False},
'links' : {'type': 'str_list' , 'optional': False , 'readonly': True } }
def get_junction(name: str, id: str) -> dict[str, Any]:

View File

@@ -7,9 +7,9 @@ def get_reservoir_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'x' : {'type': 'float' , 'optional': False , 'readonly': False},
'y' : {'type': 'float' , 'optional': False , 'readonly': False},
'head' : {'type': "float" , 'optional': False , 'readonly': False},
'pattern' : {'type': "str" , 'optional': True , 'readonly': False},
'links' : {'type': "str_list" , 'optional': False , 'readonly': True } }
'head' : {'type': 'float' , 'optional': False , 'readonly': False},
'pattern' : {'type': 'str' , 'optional': True , 'readonly': False},
'links' : {'type': 'str_list' , 'optional': False , 'readonly': True } }
def get_reservoir(name: str, id: str) -> dict[str, Any]:

View File

@@ -3,23 +3,23 @@ from .s0_base import *
from .s24_coordinates import *
OVERFLOW_YES = 'yes'
OVERFLOW_NO = 'no'
OVERFLOW_YES = 'YES'
OVERFLOW_NO = 'NO'
def get_tank_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'x' : {'type': 'float' , 'optional': False , 'readonly': False},
'y' : {'type': 'float' , 'optional': False , 'readonly': False},
'elevation' : {'type': "float" , 'optional': False , 'readonly': False},
'init_level' : {'type': "float" , 'optional': False , 'readonly': False},
'min_level' : {'type': "float" , 'optional': False , 'readonly': False},
'max_level' : {'type': "float" , 'optional': False , 'readonly': False},
'diameter' : {'type': "float" , 'optional': False , 'readonly': False},
'min_vol' : {'type': "float" , 'optional': False , 'readonly': False},
'vol_curve' : {'type': "str" , 'optional': True , 'readonly': False},
'overflow' : {'type': "str" , 'optional': True , 'readonly': False},
'links' : {'type': "str_list" , 'optional': False , 'readonly': True } }
'elevation' : {'type': 'float' , 'optional': False , 'readonly': False},
'init_level' : {'type': 'float' , 'optional': False , 'readonly': False},
'min_level' : {'type': 'float' , 'optional': False , 'readonly': False},
'max_level' : {'type': 'float' , 'optional': False , 'readonly': False},
'diameter' : {'type': 'float' , 'optional': False , 'readonly': False},
'min_vol' : {'type': 'float' , 'optional': False , 'readonly': False},
'vol_curve' : {'type': 'str' , 'optional': True , 'readonly': False},
'overflow' : {'type': 'str' , 'optional': True , 'readonly': False},
'links' : {'type': 'str_list' , 'optional': False , 'readonly': True } }
def get_tank(name: str, id: str) -> dict[str, Any]:

View File

@@ -2,20 +2,20 @@ from .operation import *
from .s0_base import *
PIPE_STATUS_OPEN = 'open'
PIPE_STATUS_CLOSED = 'closed'
PIPE_STATUS_CV = 'cv'
PIPE_STATUS_OPEN = 'OPEN'
PIPE_STATUS_CLOSED = 'CLOSED'
PIPE_STATUS_CV = 'CV'
def get_pipe_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'node1' : {'type': "str" , 'optional': False , 'readonly': False},
'node2' : {'type': "str" , 'optional': False , 'readonly': False},
'length' : {'type': "float" , 'optional': False , 'readonly': False},
'diameter' : {'type': "float" , 'optional': False , 'readonly': False},
'roughness' : {'type': "float" , 'optional': False , 'readonly': False},
'minor_loss' : {'type': "float" , 'optional': False , 'readonly': False},
'status' : {'type': "str" , 'optional': False , 'readonly': False} }
'node1' : {'type': 'str' , 'optional': False , 'readonly': False},
'node2' : {'type': 'str' , 'optional': False , 'readonly': False},
'length' : {'type': 'float' , 'optional': False , 'readonly': False},
'diameter' : {'type': 'float' , 'optional': False , 'readonly': False},
'roughness' : {'type': 'float' , 'optional': False , 'readonly': False},
'minor_loss' : {'type': 'float' , 'optional': False , 'readonly': False},
'status' : {'type': 'str' , 'optional': False , 'readonly': False} }
def get_pipe(name: str, id: str) -> dict[str, Any]:

View File

@@ -3,9 +3,13 @@ from .s0_base import *
def get_pump_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'node1' : {'type': "str" , 'optional': False , 'readonly': False},
'node2' : {'type': "str" , 'optional': False , 'readonly': False} }
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'node1' : {'type': 'str' , 'optional': False , 'readonly': False},
'node2' : {'type': 'str' , 'optional': False , 'readonly': False},
'power' : {'type': 'float' , 'optional': True , 'readonly': False},
'head' : {'type': 'str' , 'optional': True , 'readonly': False},
'speed' : {'type': 'float' , 'optional': True , 'readonly': False},
'pattern' : {'type': 'str' , 'optional': True , 'readonly': False} }
def get_pump(name: str, id: str) -> dict[str, Any]:
@@ -14,6 +18,10 @@ def get_pump(name: str, id: str) -> dict[str, Any]:
d['id'] = str(p['id'])
d['node1'] = str(p['node1'])
d['node2'] = str(p['node2'])
d['power'] = float(p['power']) if p['power'] != None else None
d['head'] = str(p['head']) if p['head'] != None else None
d['speed'] = float(p['speed']) if p['speed'] != None else None
d['pattern'] = str(p['pattern']) if p['pattern'] != None else None
return d
@@ -23,14 +31,22 @@ class Pump(object):
self.id = str(input['id'])
self.node1 = str(input['node1'])
self.node2 = str(input['node2'])
self.power = float(input['power']) if 'power' in input and input['power'] != None else None
self.head = str(input['head']) if 'head' in input and input['head'] != None else None
self.speed = float(input['speed']) if 'speed' in input and input['speed'] != None else None
self.pattern = str(input['pattern']) if 'pattern' in input and input['pattern'] != None else None
self.f_type = f"'{self.type}'"
self.f_id = f"'{self.id}'"
self.f_node1 = f"'{self.node1}'"
self.f_node2 = f"'{self.node2}'"
self.f_power = self.power if self.power != None else 'null'
self.f_head = f"'{self.head}'" if self.head != None else 'null'
self.f_speed = self.speed if self.speed != None else 'null'
self.f_pattern = f"'{self.pattern}'" if self.pattern != None else 'null'
def as_dict(self) -> dict[str, Any]:
return { 'type': self.type, 'id': self.id, 'node1': self.node1, 'node2': self.node2 }
return { 'type': self.type, 'id': self.id, 'node1': self.node1, 'node2': self.node2, 'power': self.power, 'head': self.head, 'speed': self.speed, 'pattern': self.pattern }
def as_id_dict(self) -> dict[str, Any]:
return { 'type': self.type, 'id': self.id }
@@ -47,8 +63,8 @@ def set_pump(name: str, cs: ChangeSet) -> ChangeSet:
raw_new[key] = new_dict[key]
new = Pump(raw_new)
redo_sql = f"update pumps set node1 = {new.f_node1}, node2 = {new.f_node2} where id = {new.f_id};"
undo_sql = f"update pumps set node1 = {old.f_node1}, node2 = {old.f_node2} where id = {old.f_id};"
redo_sql = f"update pumps set node1 = {new.f_node1}, node2 = {new.f_node2}, power = {new.f_power}, head = {new.f_head}, speed = {new.f_speed}, pattern = {new.f_pattern} where id = {new.f_id};"
undo_sql = f"update pumps set node1 = {old.f_node1}, node2 = {old.f_node2}, power = {old.f_power}, head = {old.f_head}, speed = {old.f_speed}, pattern = {old.f_pattern} where id = {old.f_id};"
redo_cs = g_update_prefix | new.as_dict()
undo_cs = g_update_prefix | old.as_dict()
@@ -60,7 +76,7 @@ def add_pump(name: str, cs: ChangeSet) -> ChangeSet:
new = Pump(cs.operations[0])
redo_sql = f"insert into _link (id, type) values ({new.f_id}, {new.f_type});"
redo_sql += f"\ninsert into pumps (id, node1, node2) values ({new.f_id}, {new.f_node1}, {new.f_node2});"
redo_sql += f"\ninsert into pumps (id, node1, node2, power, head, speed, pattern) values ({new.f_id}, {new.f_node1}, {new.f_node2}, {new.f_power}, {new.f_head}, {new.f_speed}, {new.f_pattern});"
undo_sql = f"delete from pumps where id = {new.f_id};"
undo_sql += f"\ndelete from _link where id = {new.f_id};"
@@ -78,7 +94,7 @@ def delete_pump(name: str, cs: ChangeSet) -> ChangeSet:
redo_sql += f"\ndelete from _link where id = {old.f_id};"
undo_sql = f"insert into _link (id, type) values ({old.f_id}, {old.f_type});"
undo_sql += f"\ninsert into pumps (id, node1, node2) values ({old.f_id}, {old.f_node1}, {old.f_node2});"
undo_sql += f"\ninsert into pumps (id, node1, node2, power, head, speed, pattern) values ({old.f_id}, {old.f_node1}, {old.f_node2}, {old.f_power}, {old.f_head}, {old.f_speed}, {old.f_pattern});"
redo_cs = g_delete_prefix | old.as_id_dict()
undo_cs = g_add_prefix | old.as_dict()

View File

@@ -2,22 +2,22 @@ from .operation import *
from .s0_base import *
VALVES_TYPE_PRV = 'prv'
VALVES_TYPE_PSV = 'psv'
VALVES_TYPE_PBV = 'pbv'
VALVES_TYPE_FCV = 'fcv'
VALVES_TYPE_TCV = 'tcv'
VALVES_TYPE_GPV = 'gpv'
VALVES_TYPE_PRV = 'PRV'
VALVES_TYPE_PSV = 'PSV'
VALVES_TYPE_PBV = 'PBV'
VALVES_TYPE_FCV = 'FCV'
VALVES_TYPE_TCV = 'TCV'
VALVES_TYPE_GPV = 'GPV'
def get_valve_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True },
'node1' : {'type': "str" , 'optional': False , 'readonly': False},
'node2' : {'type': "str" , 'optional': False , 'readonly': False},
'diameter' : {'type': "float" , 'optional': False , 'readonly': False},
'v_type' : {'type': "str" , 'optional': False , 'readonly': False},
'setting' : {'type': "float" , 'optional': False , 'readonly': False},
'minor_loss' : {'type': "float" , 'optional': False , 'readonly': False} }
'node1' : {'type': 'str' , 'optional': False , 'readonly': False},
'node2' : {'type': 'str' , 'optional': False , 'readonly': False},
'diameter' : {'type': 'float' , 'optional': False , 'readonly': False},
'v_type' : {'type': 'str' , 'optional': False , 'readonly': False},
'setting' : {'type': 'float' , 'optional': False , 'readonly': False},
'minor_loss' : {'type': 'float' , 'optional': False , 'readonly': False} }
def get_valve(name: str, id: str) -> dict[str, Any]:

56
api/s9_demands.py Normal file
View File

@@ -0,0 +1,56 @@
from .operation import *
def get_demand_schema(name: str) -> dict[str, dict[str, Any]]:
return { 'junction' : {'type': 'str' , 'optional': False , 'readonly': True },
'demands' : {'type': 'list' , 'optional': False , 'readonly': False,
'element': { 'demand' : {'type': 'float' , 'optional': False , 'readonly': False },
'patten' : {'type': 'str' , 'optional': True , 'readonly': False },
'category': {'type': 'str' , 'optional': True , 'readonly': False }}}}
def get_demand(name: str, junction: str) -> dict[str, Any]:
des = read_all(name, f"select * from demands where junction = '{junction}'")
ds = []
for r in des:
d = {}
d['demand'] = float(r['demand'])
d['pattern'] = str(r['pattern']) if r['pattern'] != None else None
d['category'] = str(r['category']) if r['category'] != None else None
ds.append(d)
return { 'junction': junction, 'demands': ds }
# { 'operation': 'update', 'type': 'demand', 'junction': 'j1', 'demands': [{'demand': 0.0, 'patten': None, 'category': None}] }
def set_demand(name: str, cs: ChangeSet) -> ChangeSet:
junction = cs.operations[0]['junction']
old = get_demand(name, junction)
new = { 'junction': junction, 'demands': [] }
f_junction = f"'{junction}'"
# TODO: transaction ?
redo_sql = f"delete from demands where junction = {f_junction};"
for r in cs.operations[0]['demands']:
demand = float(r['demand'])
pattern = str(r['pattern']) if 'pattern' in r and r['pattern'] != None else None
category = str(r['category']) if 'category' in r and r['category'] != None else None
f_demand = demand
f_pattern = f"'{pattern}'" if pattern != None else 'null'
f_category = f"'{category}'" if category != None else 'null'
redo_sql += f"\ninsert into demands (junction, demand, pattern, category) values ({f_junction}, {f_demand}, {f_pattern}, {f_category});"
new['demands'].append({ 'demand': demand, 'pattern': pattern, 'category': category })
undo_sql = f"delete from demands where junction = {f_junction};"
for r in old['demands']:
demand = float(r['demand'])
pattern = str(r['pattern'])
category = str(r['category'])
f_demand = demand
f_pattern = f"'{pattern}'" if pattern != None else 'null'
f_category = f"'{category}'" if category != None else 'null'
undo_sql += f"\ninsert into demands (junction, demand, pattern, category) values ({f_junction}, {f_demand}, {f_pattern}, {f_category});"
redo_cs = g_update_prefix | { 'type': 'demand' } | new
undo_cs = g_update_prefix | { 'type': 'demand' } | old
return execute_command(name, redo_sql, undo_sql, redo_cs, undo_cs)

View File

@@ -1,7 +1,7 @@
from tjnetwork import *
def inp2db():
read_inp('changshu', './inp/v-16常熟模型.inp')
read_inp('net3', './inp/net3.inp')
if __name__ == '__main__':
inp2db()

View File

@@ -1,29 +1,11 @@
-- [STATUS]
create type status_pipe_pump_status as enum ('open', 'closed');
create type link_status as enum ('OPEN', 'CLOSED', 'ACTIVE');
create table status_pipe
create table status
(
id varchar(32) primary key references pipes(id)
, status status_pipe_pump_status not null
);
create table status_pump
(
id varchar(32) primary key references pumps(id)
, status status_pipe_pump_status not null
);
create type status_valve_status as enum ('open', 'closed', 'active');
create table status_valve
(
id varchar(32) primary key references valves(id)
, status status_valve_status not null
);
create table status_link
(
id varchar(32) primary key references _link(id)
, setting numeric not null
link varchar(32) primary key references _link(id)
, status link_status
, setting numeric
, check (status is not null or setting is not null)
);

View File

@@ -3,5 +3,5 @@
create table patterns
(
id varchar(32) references _pattern(id) not null
, multipliers numeric not null
, factor numeric not null
);

View File

@@ -1,30 +1,6 @@
-- [CONTROLS]
create type controls_1_prep as enum ('above', 'below');
-- LINK linkID status IF NODE nodeID ABOVE / BELOW value
create table controls_1
create table controls
(
linkid varchar(32) primary key references _link(id)
, status text not null -- open / closed, a pump speed setting, or a control valve setting
, nodeid varchar(32) references _node(id) not null
, prep controls_1_prep not null
, value numeric not null
);
-- LINK linkID status AT TIME time
create table controls_2
(
linkid varchar(32) primary key references _link(id)
, status text not null -- open / closed, a pump speed setting, or a control valve setting
, time interval hour
);
-- LINK linkID status AT CLOCKTIME clocktime AM / PM
create table controls_3
(
linkid varchar(32) primary key references _link(id)
, status text not null -- open / closed, a pump speed setting, or a control valve setting
, clock_time_hour interval hour -- get am/pm from it
, clock_time_min interval minute
control text primary key
);

View File

@@ -2,5 +2,5 @@
create table rules
(
content text primary key
rule text primary key
);

View File

@@ -1,6 +1,6 @@
-- [ENERGY]
create type energy_param as enum ('price', 'pattern', 'effic');
create type energy_param as enum ('PRICE', 'PATTERN', 'EFFIC');
-- GLOBAL PRICE / PATTERN / EFFIC value
create table energy_global
@@ -22,3 +22,12 @@ create table energy_demand_charge
(
value numeric not null
);
insert into energy_global (param, value) values
('PRICE', 0.0)
, ('EFFIC', 75)
;
insert into energy_demand_charge values
(0.0)
;

View File

@@ -1,6 +1,6 @@
-- [SOURCES]
create type sources_type as enum ('concen', 'mass', 'flowpaced', 'setpoint');
create type sources_type as enum ('CONCEN', 'MASS', 'FLOWPACED', 'SETPOINT');
create table sources
(

View File

@@ -1,6 +1,6 @@
-- [REACTIONS]
create type reactions_order_param as enum ('bulk', 'wall', 'tank');
create type reactions_order_param as enum ('BULK', 'WALL', 'TANK');
create table reactions_order
(
@@ -8,7 +8,7 @@ create table reactions_order
, value numeric not null
);
create type reactions_global_param as enum ('bulk', 'wall');
create type reactions_global_param as enum ('BULK', 'WALL');
create table reactions_global
(
@@ -16,7 +16,7 @@ create table reactions_global
, value numeric not null
);
create type reactions_pipe_param as enum ('bulk', 'wall');
create type reactions_pipe_param as enum ('BULK', 'WALL');
create table reactions_pipe
(

View File

@@ -1,6 +1,6 @@
-- [MIXING]
create type mixing_model as enum ('mixed', '2comp', 'fifo', 'lifo');
create type mixing_model as enum ('MIXED', '2COMP', 'FIFO', 'LIFO');
create table mixing
(

View File

@@ -1,9 +1,20 @@
-- [TIMES]
-- TODO: constraint
create table times
(
key text not null
, value text not null
);
insert into times (key, value) values
('DURATION', '0:00')
, ('HYDRAULIC TIMESTEP', '1:00')
, ('QUALITY TIMESTEP', '0:05')
, ('RULE TIMESTEP', '0:05')
, ('PATTERN TIMESTEP', '1:00')
, ('PATTERN START', '0:00')
, ('REPORT TIMESTEP', '1:00')
, ('REPORT START', '0:00')
, ('START CLOCKTIME', '12:00 AM')
, ('STATISTIC', 'NONE') -- NONE / AVERAGED / MINIMUM / MAXIMUM / RANGE
;

View File

@@ -7,3 +7,14 @@ create table report
key text not null
, value text not null
);
insert into report (key, value) values
('PAGESIZE', '0')
--, ('FILE', '')
, ('STATUS', 'NO')
, ('SUMMARY', 'YES')
--, ('MESSAGES', 'NO')
, ('ENERY', 'NO')
, ('NODES', 'NONE')
, ('LINKS', 'NONE')
;

View File

@@ -7,3 +7,30 @@ create table options
key text not null
, value text not null
);
insert into options (key, value) values
('UNITS', 'GPM')
, ('HEADLOSS', 'H-W')
--, ('HYDRAULICS', '')
, ('VISCOSITY', '1.0')
, ('SPECIFIC GRAVITY', '1.0')
, ('TRIALS', '40')
, ('ACCURACY', '0.001')
, ('FLOWCHANGE', '0')
, ('HEADERROR', '0')
, ('CHECKFREQ', '2')
, ('MAXCHECK', '10')
, ('DAMPLIMIT', '0')
, ('UNBALANCED', 'STOP')
, ('DEMAND MODEL', 'DDA')
, ('MINIMUM PRESSURE', '0')
, ('REQUIRED PRESSURE', '0.1')
, ('PRESSURE EXPONENT', '0.5')
, ('PATTERN', '1')
, ('DEMAND MULTIPLIER', '1.0')
, ('EMITTER EXPONENT', '0.5')
, ('QUALITY', 'NONE')
, ('DIFFUSIVITY', '1.0')
, ('TOLERANCE', '0.01')
--, ('MAP', '')
;

View File

@@ -1,6 +1,6 @@
-- [TANKS]
create type tanks_overflow as enum ('yes', 'no');
create type tanks_overflow as enum ('YES', 'NO');
create table tanks
(

View File

@@ -1,6 +1,6 @@
-- [PIPES]
create type pipes_status as enum ('open', 'closed', 'cv');
create type pipes_status as enum ('OPEN', 'CLOSED', 'CV');
create table pipes
(

View File

@@ -5,28 +5,10 @@ create table pumps
id varchar(32) primary key references _link(id)
, node1 varchar(32) references _node(id) not null
, node2 varchar(32) references _node(id) not null
);
create table pumps_property_power
(
id varchar primary key references pumps(id)
, value varchar(32) not null
);
create table pumps_property_speed
(
id varchar primary key references pumps(id)
, value varchar(32) not null
);
create table pumps_property_head
(
id varchar primary key references pumps(id)
, head varchar(32) references _curve(id) not null
);
create table pumps_property_pattern
(
id varchar primary key references pumps(id)
, pattern varchar(32) references _pattern(id) not null
, power numeric
, head varchar(32) references _curve(id)
, speed numeric
, pattern varchar(32) references _pattern(id)
, check (power is not null or head is not null)
, check ((power is not null and head is not null) is false)
);

View File

@@ -1,6 +1,6 @@
-- [VALVES]
create type valves_type as enum ('prv', 'psv', 'pbv', 'fcv', 'tcv', 'gpv');
create type valves_type as enum ('PRV', 'PSV', 'PBV', 'FCV', 'TCV', 'GPV');
create table valves
(

View File

@@ -5,5 +5,5 @@ create table demands
junction varchar(32) references junctions(id) not null
, demand numeric not null
, pattern varchar(32) references _pattern(id)
, category text not null
, category text
);

View File

@@ -1,13 +1,5 @@
-- [STATUS]
drop table if exists status_link;
drop table if exists status;
drop table if exists status_valve;
drop type if exists status_valve_status;
drop table if exists status_pump;
drop table if exists status_pipe;
drop type if exists status_pipe_pump_status;
drop type if exists link_status;

View File

@@ -1,9 +1,3 @@
-- [CONTROLS]
drop table if exists controls_3;
drop table if exists controls_2;
drop table if exists controls_1;
drop type if exists controls_1_prep;
drop table if exists controls;

View File

@@ -1,11 +1,3 @@
-- [PUMPS]
drop table if exists pumps_property_pattern;
drop table if exists pumps_property_head;
drop table if exists pumps_property_speed;
drop table if exists pumps_property_power;
drop table if exists pumps;

View File

@@ -165,7 +165,7 @@ class TestApi:
add_junction(p, ChangeSet({'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j3', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_pipe(p, ChangeSet({'id': 'p1', 'node1': 'j1', 'node2': 'j2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
add_pump(p, ChangeSet({'id': 'p2', 'node1': 'j1', 'node2': 'j2'}))
add_pump(p, ChangeSet({'id': 'p2', 'node1': 'j1', 'node2': 'j2', 'power': 0.0}))
add_valve(p, ChangeSet({'id': 'v1', 'node1': 'j2', 'node2': 'j3', 'diameter': 10.0, 'v_type': VALVES_TYPE_FCV, 'setting': 0.1, 'minor_loss': 0.5 }))
assert get_junction(p, 'j1')['links'] == ['p1', 'p2']
assert get_junction(p, 'j2')['links'] == ['p1', 'p2', 'v1']
@@ -322,7 +322,7 @@ class TestApi:
add_reservoir(p, ChangeSet({'id': 'r2', 'x': 0.0, 'y': 10.0, 'head': 20.0}))
add_reservoir(p, ChangeSet({'id': 'r3', 'x': 0.0, 'y': 10.0, 'head': 20.0}))
add_pipe(p, ChangeSet({'id': 'p1', 'node1': 'r1', 'node2': 'r2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
add_pump(p, ChangeSet({'id': 'p2', 'node1': 'r1', 'node2': 'r2'}))
add_pump(p, ChangeSet({'id': 'p2', 'node1': 'r1', 'node2': 'r2', 'power': 0.0}))
add_valve(p, ChangeSet({'id': 'v1', 'node1': 'r2', 'node2': 'r3', 'diameter': 10.0, 'v_type': VALVES_TYPE_FCV, 'setting': 0.1, 'minor_loss': 0.5 }))
assert get_reservoir(p, 'r1')['links'] == ['p1', 'p2']
assert get_reservoir(p, 'r2')['links'] == ['p1', 'p2', 'v1']
@@ -497,7 +497,7 @@ class TestApi:
add_tank(p, ChangeSet({'id': 't2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0, 'init_level': 1.0, 'min_level': 0.0, 'max_level': 2.0, 'diameter': 10.0, 'min_vol': 100.0, 'vol_curve': None, 'overflow': OVERFLOW_NO}))
add_tank(p, ChangeSet({'id': 't3', 'x': 0.0, 'y': 10.0, 'elevation': 20.0, 'init_level': 1.0, 'min_level': 0.0, 'max_level': 2.0, 'diameter': 10.0, 'min_vol': 100.0, 'vol_curve': None, 'overflow': OVERFLOW_NO}))
add_pipe(p, ChangeSet({'id': 'p1', 'node1': 't1', 'node2': 't2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
add_pump(p, ChangeSet({'id': 'p2', 'node1': 't1', 'node2': 't2'}))
add_pump(p, ChangeSet({'id': 'p2', 'node1': 't1', 'node2': 't2', 'power': 0.0}))
add_valve(p, ChangeSet({'id': 'v1', 'node1': 't2', 'node2': 't3', 'diameter': 10.0, 'v_type': VALVES_TYPE_FCV, 'setting': 0.1, 'minor_loss': 0.5 }))
assert get_tank(p, 't1')['links'] == ['p1', 'p2']
assert get_tank(p, 't2')['links'] == ['p1', 'p2', 'v1']
@@ -846,17 +846,25 @@ class TestApi:
assert is_junction(p, 'j3')
assert is_junction(p, 'j4')
add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2'}))
add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'power': 0.0}))
p0 = get_pump(p, 'p0')
assert p0['node1'] == 'j1'
assert p0['node2'] == 'j2'
assert p0['power'] == 0.0
assert p0['head'] == None
assert p0['speed'] == None
assert p0['pattern'] == None
set_pump(p, ChangeSet({'id': 'p0', 'node1': 'j3', 'node2': 'j4'}))
p0 = get_pump(p, 'p0')
assert p0['node1'] == 'j3'
assert p0['node2'] == 'j4'
add_pump(p, ChangeSet({'id': 'p1', 'node1': 'j1', 'node2': 'j2'}))
set_pump(p, ChangeSet({'id': 'p0', 'power': 100.0}))
p0 = get_pump(p, 'p0')
assert p0['power'] == 100.0
add_pump(p, ChangeSet({'id': 'p1', 'node1': 'j1', 'node2': 'j2', 'power': 0.0}))
links = get_links(p)
assert len(links) == 2
assert links[0] == 'p0'
@@ -889,12 +897,13 @@ class TestApi:
assert is_junction(p, 'j3')
assert is_junction(p, 'j4')
cs = add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2'})).operations[0]
cs = add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'power': 0.0})).operations[0]
assert cs['operation'] == 'add'
assert cs['type'] == PUMP
assert cs['id'] == 'p0'
assert cs['node1'] == 'j1'
assert cs['node2'] == 'j2'
assert cs['power'] == 0.0
cs = execute_undo(p).operations[0]
assert cs['operation'] == 'delete'
@@ -919,7 +928,7 @@ class TestApi:
links = get_links(p)
assert len(links) == 0
add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2'}))
add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'power': 0.0}))
links = get_links(p)
assert len(links) == 1
@@ -968,6 +977,18 @@ class TestApi:
assert cs['node1'] == 'j1'
assert cs['node2'] == 'j2'
cs = set_pump(p, ChangeSet({'id': 'p0', 'power': 100.0})).operations[0]
assert cs['operation'] == 'update'
assert cs['type'] == PUMP
assert cs['id'] == 'p0'
assert cs['power'] == 100.0
cs = execute_undo(p).operations[0]
assert cs['operation'] == 'update'
assert cs['type'] == PUMP
assert cs['id'] == 'p0'
assert cs['power'] == 0.0
self.leave(p)
@@ -1153,6 +1174,596 @@ class TestApi:
self.leave(p)
def test_demand(self):
p = 'test_demand'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
assert is_junction(p, 'j1')
d = get_demand(p, 'j1')
assert d['junction'] == 'j1'
assert d['demands'] == []
set_demand(p, ChangeSet({'junction': 'j1', 'demands': [{'demand': 10.0, 'pattern': None, 'category': 'x'},
{'demand': 20.0, 'pattern': None, 'category': None}]}))
d = get_demand(p, 'j1')
assert d['junction'] == 'j1'
ds = d['demands']
assert len(ds) == 2
assert ds[0]['demand'] == 10.0
assert ds[0]['pattern'] == None
assert ds[0]['category'] == 'x'
assert ds[1]['demand'] == 20.0
assert ds[1]['pattern'] == None
assert ds[1]['category'] == None
set_demand(p, ChangeSet({'junction': 'j1', 'demands': []}))
d = get_demand(p, 'j1')
assert d['junction'] == 'j1'
assert d['demands'] == []
self.leave(p)
def test_demand_op(self):
p = 'test_demand_op'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
assert is_junction(p, 'j1')
cs = set_demand(p, ChangeSet({'junction': 'j1', 'demands': [{'demand': 10.0, 'pattern': None, 'category': 'x'},
{'demand': 20.0, 'pattern': None, 'category': None}]})).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'demand'
assert cs['junction'] == 'j1'
ds = cs['demands']
assert len(ds) == 2
assert ds[0]['demand'] == 10.0
assert ds[0]['pattern'] == None
assert ds[0]['category'] == 'x'
assert ds[1]['demand'] == 20.0
assert ds[1]['pattern'] == None
assert ds[1]['category'] == None
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'demand'
assert cs['junction'] == 'j1'
assert len(cs['demands']) == 0
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'demand'
assert cs['junction'] == 'j1'
ds = cs['demands']
assert len(ds) == 2
assert ds[0]['demand'] == 10.0
assert ds[0]['pattern'] == None
assert ds[0]['category'] == 'x'
assert ds[1]['demand'] == 20.0
assert ds[1]['pattern'] == None
assert ds[1]['category'] == None
self.leave(p)
def test_status(self):
p = 'test_status'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
assert is_junction(p, 'j1')
assert is_junction(p, 'j2')
add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
assert is_pipe(p, 'p0')
s = get_status(p, 'p0')
assert s['link'] == 'p0'
assert s['status'] == None
assert s['setting'] == None
set_status(p, ChangeSet({'link': 'p0', 'status': LINK_STATUS_OPEN, 'setting': 10.0}))
s = get_status(p, 'p0')
assert s['link'] == 'p0'
assert s['status'] == LINK_STATUS_OPEN
assert s['setting'] == 10.0
set_status(p, ChangeSet({'link': 'p0', 'status': None, 'setting': None}))
s = get_status(p, 'p0')
assert s['link'] == 'p0'
assert s['status'] == None
assert s['setting'] == None
self.leave(p)
def test_status_op(self):
p = 'test_status_op'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
add_junction(p, ChangeSet({'id': 'j2', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
assert is_junction(p, 'j1')
assert is_junction(p, 'j2')
add_pipe(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'length': 100.0, 'diameter': 10.0, 'roughness': 0.1, 'minor_loss': 0.5, 'status': PIPE_STATUS_OPEN }))
assert is_pipe(p, 'p0')
s = get_status(p, 'p0')
assert s['link'] == 'p0'
assert s['status'] == None
assert s['setting'] == None
cs = set_status(p, ChangeSet({'link': 'p0', 'status': LINK_STATUS_OPEN, 'setting': 10.0})).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'status'
assert cs['link'] == 'p0'
assert cs['status'] == LINK_STATUS_OPEN
assert cs['setting'] == 10.0
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'status'
assert cs['link'] == 'p0'
assert cs['status'] == None
assert cs['setting'] == None
s = get_status(p, 'p0')
assert s['link'] == 'p0'
assert s['status'] == None
assert s['setting'] == None
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'status'
assert cs['link'] == 'p0'
assert cs['status'] == LINK_STATUS_OPEN
assert cs['setting'] == 10.0
self.leave(p)
def test_pattern(self):
p = 'test_pattern'
self.enter(p)
assert is_pattern(p, 'p0') == False
p0 = get_pattern(p, 'p0')
assert p0['id'] == 'p0'
assert p0['factors'] == []
set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]}))
assert is_pattern(p, 'p0')
p0 = get_pattern(p, 'p0')
assert p0['id'] == 'p0'
assert p0['factors'] == [1.0, 2.0, 3.0]
set_pattern(p, ChangeSet({'id' : 'p0', 'factors': []}))
assert is_pattern(p, 'p0') == False
p0 = get_pattern(p, 'p0')
assert p0['id'] == 'p0'
assert p0['factors'] == []
self.leave(p)
def test_pattern_op(self):
p = 'test_pattern_op'
self.enter(p)
cs = set_pattern(p, ChangeSet({'id' : 'p0', 'factors': [1.0, 2.0, 3.0]})).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == PATTERN
assert cs['id'] == 'p0'
assert cs['factors'] == [1.0, 2.0, 3.0]
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == PATTERN
assert cs['id'] == 'p0'
assert cs['factors'] == []
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == PATTERN
assert cs['id'] == 'p0'
assert cs['factors'] == [1.0, 2.0, 3.0]
self.leave(p)
def test_curve(self):
p = 'test_curve'
self.enter(p)
assert is_curve(p, 'c0') == False
c0 = get_curve(p, 'c0')
assert c0['id'] == 'c0'
assert c0['coords'] == []
set_curve(p, ChangeSet({'id' : 'c0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]}))
assert is_curve(p, 'c0')
c0 = get_curve(p, 'c0')
assert c0['id'] == 'c0'
xys = c0['coords']
assert len(xys) == 2
assert xys[0]['x'] == 1.0
assert xys[0]['y'] == 2.0
assert xys[1]['x'] == 2.0
assert xys[1]['y'] == 1.0
set_curve(p, ChangeSet({'id' : 'c0', 'coords': []}))
assert is_curve(p, 'c0') == False
c0 = get_curve(p, 'c0')
assert c0['id'] == 'c0'
assert c0['coords'] == []
self.leave(p)
def test_curve_op(self):
p = 'test_curve_op'
self.enter(p)
cs = set_curve(p, ChangeSet({'id' : 'c0', 'coords': [{'x': 1.0, 'y': 2.0}, {'x': 2.0, 'y': 1.0}]})).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == CURVE
assert cs['id'] == 'c0'
xys = cs['coords']
assert len(xys) == 2
assert xys[0]['x'] == 1.0
assert xys[0]['y'] == 2.0
assert xys[1]['x'] == 2.0
assert xys[1]['y'] == 1.0
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == CURVE
assert cs['id'] == 'c0'
assert cs['coords'] == []
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == CURVE
assert cs['id'] == 'c0'
xys = cs['coords']
assert len(xys) == 2
assert xys[0]['x'] == 1.0
assert xys[0]['y'] == 2.0
assert xys[1]['x'] == 2.0
assert xys[1]['y'] == 1.0
self.leave(p)
def test_emitter(self):
p = 'test_emitter'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
assert is_junction(p, 'j1')
e = get_emitter(p, 'j1')
assert e['junction'] == 'j1'
assert e['coefficient'] == None
set_emitter(p, ChangeSet({'junction': 'j1', 'coefficient': 10.0}))
e = get_emitter(p, 'j1')
assert e['junction'] == 'j1'
assert e['coefficient'] == 10.0
set_emitter(p, ChangeSet({'junction': 'j1', 'coefficient': None}))
e = get_emitter(p, 'j1')
assert e['junction'] == 'j1'
assert e['coefficient'] == None
self.leave(p)
def test_emitter_op(self):
p = 'test_emitter_op'
self.enter(p)
add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0}))
assert is_junction(p, 'j1')
cs = set_emitter(p, ChangeSet({'junction': 'j1', 'coefficient': 10.0})).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'emitter'
assert cs['junction'] == 'j1'
assert cs['coefficient'] == 10.0
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'emitter'
assert cs['junction'] == 'j1'
assert cs['coefficient'] == None
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'emitter'
assert cs['junction'] == 'j1'
assert cs['coefficient'] == 10.0
self.leave(p)
def test_time(self):
p = 'test_time'
self.enter(p)
t = get_time(p)
assert t['DURATION'] == '0:00'
assert t['HYDRAULIC TIMESTEP'] == '1:00'
assert t['QUALITY TIMESTEP'] == '0:05'
assert t['RULE TIMESTEP'] == '0:05'
assert t['PATTERN TIMESTEP'] == '1:00'
assert t['PATTERN START'] == '0:00'
assert t['REPORT TIMESTEP'] == '1:00'
assert t['REPORT START'] == '0:00'
assert t['START CLOCKTIME'] == '12:00 AM'
assert t['STATISTIC'] == TIME_STATISTIC_NONE
t['STATISTIC'] = TIME_STATISTIC_AVERAGED
set_time(p, ChangeSet(t))
t = get_time(p)
assert t['DURATION'] == '0:00'
assert t['HYDRAULIC TIMESTEP'] == '1:00'
assert t['QUALITY TIMESTEP'] == '0:05'
assert t['RULE TIMESTEP'] == '0:05'
assert t['PATTERN TIMESTEP'] == '1:00'
assert t['PATTERN START'] == '0:00'
assert t['REPORT TIMESTEP'] == '1:00'
assert t['REPORT START'] == '0:00'
assert t['START CLOCKTIME'] == '12:00 AM'
assert t['STATISTIC'] == TIME_STATISTIC_AVERAGED
self.leave(p)
def test_time_op(self):
p = 'test_time_op'
self.enter(p)
t = get_time(p)
assert t['DURATION'] == '0:00'
assert t['HYDRAULIC TIMESTEP'] == '1:00'
assert t['QUALITY TIMESTEP'] == '0:05'
assert t['RULE TIMESTEP'] == '0:05'
assert t['PATTERN TIMESTEP'] == '1:00'
assert t['PATTERN START'] == '0:00'
assert t['REPORT TIMESTEP'] == '1:00'
assert t['REPORT START'] == '0:00'
assert t['START CLOCKTIME'] == '12:00 AM'
assert t['STATISTIC'] == TIME_STATISTIC_NONE
t['STATISTIC'] = TIME_STATISTIC_AVERAGED
cs = set_time(p, ChangeSet(t)).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'time'
assert cs['DURATION'] == '0:00'
assert cs['HYDRAULIC TIMESTEP'] == '1:00'
assert cs['QUALITY TIMESTEP'] == '0:05'
assert cs['RULE TIMESTEP'] == '0:05'
assert cs['PATTERN TIMESTEP'] == '1:00'
assert cs['PATTERN START'] == '0:00'
assert cs['REPORT TIMESTEP'] == '1:00'
assert cs['REPORT START'] == '0:00'
assert cs['START CLOCKTIME'] == '12:00 AM'
assert cs['STATISTIC'] == TIME_STATISTIC_AVERAGED
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'time'
assert cs['DURATION'] == '0:00'
assert cs['HYDRAULIC TIMESTEP'] == '1:00'
assert cs['QUALITY TIMESTEP'] == '0:05'
assert cs['RULE TIMESTEP'] == '0:05'
assert cs['PATTERN TIMESTEP'] == '1:00'
assert cs['PATTERN START'] == '0:00'
assert cs['REPORT TIMESTEP'] == '1:00'
assert cs['REPORT START'] == '0:00'
assert cs['START CLOCKTIME'] == '12:00 AM'
assert cs['STATISTIC'] == TIME_STATISTIC_NONE
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'time'
assert cs['DURATION'] == '0:00'
assert cs['HYDRAULIC TIMESTEP'] == '1:00'
assert cs['QUALITY TIMESTEP'] == '0:05'
assert cs['RULE TIMESTEP'] == '0:05'
assert cs['PATTERN TIMESTEP'] == '1:00'
assert cs['PATTERN START'] == '0:00'
assert cs['REPORT TIMESTEP'] == '1:00'
assert cs['REPORT START'] == '0:00'
assert cs['START CLOCKTIME'] == '12:00 AM'
assert cs['STATISTIC'] == TIME_STATISTIC_AVERAGED
self.leave(p)
def test_option(self):
p = 'test_option'
self.enter(p)
o = get_option(p)
assert o['UNITS'] == OPTION_UNITS_GPM
assert o['HEADLOSS'] == OPTION_HEADLOSS_HW
assert o['VISCOSITY'] == '1.0'
assert o['SPECIFIC GRAVITY'] == '1.0'
assert o['TRIALS'] == '40'
assert o['ACCURACY'] == '0.001'
assert o['FLOWCHANGE'] == '0'
assert o['HEADERROR'] == '0'
assert o['CHECKFREQ'] == '2'
assert o['MAXCHECK'] == '10'
assert o['DAMPLIMIT'] == '0'
assert o['UNBALANCED'] == OPTION_UNBALANCED_STOP
assert o['DEMAND MODEL'] == OPTION_DEMAND_MODEL_DDA
assert o['MINIMUM PRESSURE'] == '0'
assert o['REQUIRED PRESSURE'] == '0.1'
assert o['PRESSURE EXPONENT'] == '0.5'
assert o['PATTERN'] == '1'
assert o['DEMAND MULTIPLIER'] == '1.0'
assert o['EMITTER EXPONENT'] == '0.5'
assert o['QUALITY'] == OPTION_QUALITY_NONE
assert o['DIFFUSIVITY'] == '1.0'
assert o['TOLERANCE'] == '0.01'
o['UNITS'] = OPTION_UNITS_LPS
set_option(p, ChangeSet(o))
o = get_option(p)
assert o['UNITS'] == OPTION_UNITS_LPS
assert o['HEADLOSS'] == OPTION_HEADLOSS_HW
assert o['VISCOSITY'] == '1.0'
assert o['SPECIFIC GRAVITY'] == '1.0'
assert o['TRIALS'] == '40'
assert o['ACCURACY'] == '0.001'
assert o['FLOWCHANGE'] == '0'
assert o['HEADERROR'] == '0'
assert o['CHECKFREQ'] == '2'
assert o['MAXCHECK'] == '10'
assert o['DAMPLIMIT'] == '0'
assert o['UNBALANCED'] == OPTION_UNBALANCED_STOP
assert o['DEMAND MODEL'] == OPTION_DEMAND_MODEL_DDA
assert o['MINIMUM PRESSURE'] == '0'
assert o['REQUIRED PRESSURE'] == '0.1'
assert o['PRESSURE EXPONENT'] == '0.5'
assert o['PATTERN'] == '1'
assert o['DEMAND MULTIPLIER'] == '1.0'
assert o['EMITTER EXPONENT'] == '0.5'
assert o['QUALITY'] == OPTION_QUALITY_NONE
assert o['DIFFUSIVITY'] == '1.0'
assert o['TOLERANCE'] == '0.01'
self.leave(p)
def test_option_op(self):
p = 'test_option_op'
self.enter(p)
o = get_option(p)
assert o['UNITS'] == OPTION_UNITS_GPM
assert o['HEADLOSS'] == OPTION_HEADLOSS_HW
assert o['VISCOSITY'] == '1.0'
assert o['SPECIFIC GRAVITY'] == '1.0'
assert o['TRIALS'] == '40'
assert o['ACCURACY'] == '0.001'
assert o['FLOWCHANGE'] == '0'
assert o['HEADERROR'] == '0'
assert o['CHECKFREQ'] == '2'
assert o['MAXCHECK'] == '10'
assert o['DAMPLIMIT'] == '0'
assert o['UNBALANCED'] == OPTION_UNBALANCED_STOP
assert o['DEMAND MODEL'] == OPTION_DEMAND_MODEL_DDA
assert o['MINIMUM PRESSURE'] == '0'
assert o['REQUIRED PRESSURE'] == '0.1'
assert o['PRESSURE EXPONENT'] == '0.5'
assert o['PATTERN'] == '1'
assert o['DEMAND MULTIPLIER'] == '1.0'
assert o['EMITTER EXPONENT'] == '0.5'
assert o['QUALITY'] == OPTION_QUALITY_NONE
assert o['DIFFUSIVITY'] == '1.0'
assert o['TOLERANCE'] == '0.01'
o['UNITS'] = OPTION_UNITS_LPS
cs = set_option(p, ChangeSet(o)).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'option'
assert cs['UNITS'] == OPTION_UNITS_LPS
assert cs['HEADLOSS'] == OPTION_HEADLOSS_HW
assert cs['VISCOSITY'] == '1.0'
assert cs['SPECIFIC GRAVITY'] == '1.0'
assert cs['TRIALS'] == '40'
assert cs['ACCURACY'] == '0.001'
assert cs['FLOWCHANGE'] == '0'
assert cs['HEADERROR'] == '0'
assert cs['CHECKFREQ'] == '2'
assert cs['MAXCHECK'] == '10'
assert cs['DAMPLIMIT'] == '0'
assert cs['UNBALANCED'] == OPTION_UNBALANCED_STOP
assert cs['DEMAND MODEL'] == OPTION_DEMAND_MODEL_DDA
assert cs['MINIMUM PRESSURE'] == '0'
assert cs['REQUIRED PRESSURE'] == '0.1'
assert cs['PRESSURE EXPONENT'] == '0.5'
assert cs['PATTERN'] == '1'
assert cs['DEMAND MULTIPLIER'] == '1.0'
assert cs['EMITTER EXPONENT'] == '0.5'
assert cs['QUALITY'] == OPTION_QUALITY_NONE
assert cs['DIFFUSIVITY'] == '1.0'
assert cs['TOLERANCE'] == '0.01'
cs = execute_undo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'option'
assert cs['UNITS'] == OPTION_UNITS_GPM
assert cs['HEADLOSS'] == OPTION_HEADLOSS_HW
assert cs['VISCOSITY'] == '1.0'
assert cs['SPECIFIC GRAVITY'] == '1.0'
assert cs['TRIALS'] == '40'
assert cs['ACCURACY'] == '0.001'
assert cs['FLOWCHANGE'] == '0'
assert cs['HEADERROR'] == '0'
assert cs['CHECKFREQ'] == '2'
assert cs['MAXCHECK'] == '10'
assert cs['DAMPLIMIT'] == '0'
assert cs['UNBALANCED'] == OPTION_UNBALANCED_STOP
assert cs['DEMAND MODEL'] == OPTION_DEMAND_MODEL_DDA
assert cs['MINIMUM PRESSURE'] == '0'
assert cs['REQUIRED PRESSURE'] == '0.1'
assert cs['PRESSURE EXPONENT'] == '0.5'
assert cs['PATTERN'] == '1'
assert cs['DEMAND MULTIPLIER'] == '1.0'
assert cs['EMITTER EXPONENT'] == '0.5'
assert cs['QUALITY'] == OPTION_QUALITY_NONE
assert cs['DIFFUSIVITY'] == '1.0'
assert cs['TOLERANCE'] == '0.01'
cs = execute_redo(p).operations[0]
assert cs['operation'] == API_UPDATE
assert cs['type'] == 'option'
assert cs['UNITS'] == OPTION_UNITS_LPS
assert cs['HEADLOSS'] == OPTION_HEADLOSS_HW
assert cs['VISCOSITY'] == '1.0'
assert cs['SPECIFIC GRAVITY'] == '1.0'
assert cs['TRIALS'] == '40'
assert cs['ACCURACY'] == '0.001'
assert cs['FLOWCHANGE'] == '0'
assert cs['HEADERROR'] == '0'
assert cs['CHECKFREQ'] == '2'
assert cs['MAXCHECK'] == '10'
assert cs['DAMPLIMIT'] == '0'
assert cs['UNBALANCED'] == OPTION_UNBALANCED_STOP
assert cs['DEMAND MODEL'] == OPTION_DEMAND_MODEL_DDA
assert cs['MINIMUM PRESSURE'] == '0'
assert cs['REQUIRED PRESSURE'] == '0.1'
assert cs['PRESSURE EXPONENT'] == '0.5'
assert cs['PATTERN'] == '1'
assert cs['DEMAND MULTIPLIER'] == '1.0'
assert cs['EMITTER EXPONENT'] == '0.5'
assert cs['QUALITY'] == OPTION_QUALITY_NONE
assert cs['DIFFUSIVITY'] == '1.0'
assert cs['TOLERANCE'] == '0.01'
self.leave(p)
def test_snapshot(self):
p = "test_snapshot"
self.enter(p)
@@ -1199,7 +1810,7 @@ class TestApi:
def test_batch_commands(self):
p = 'test_valve_op'
p = 'test_batch_commands'
self.enter(p)
cs = ChangeSet()
@@ -1210,6 +1821,16 @@ class TestApi:
cs = execute_batch_commands(p, cs)
assert len(cs.operations) == 2
cs = ChangeSet()
cs.delete({'type': JUNCTION, 'id': 'j1'})
cs.delete({'type': JUNCTION, 'id': 'j2'})
cs = execute_batch_commands(p, cs)
assert len(cs.operations) == 2
cs = execute_undo(p)
assert len(cs.operations) == 1
self.leave(p)

View File

@@ -23,6 +23,8 @@ TANK = api.TANK
PIPE = api.PIPE
PUMP = api.PUMP
VALVE = api.VALVE
PATTERN = api.PATTERN
CURVE = api.CURVE
OVERFLOW_YES = api.OVERFLOW_YES
OVERFLOW_NO = api.OVERFLOW_NO
@@ -38,6 +40,42 @@ VALVES_TYPE_FCV = api.VALVES_TYPE_FCV
VALVES_TYPE_TCV = api.VALVES_TYPE_TCV
VALVES_TYPE_GPV = api.VALVES_TYPE_GPV
LINK_STATUS_OPEN = api.LINK_STATUS_OPEN
LINK_STATUS_CLOSED = api.LINK_STATUS_CLOSED
LINK_STATUS_ACTIVE = api.LINK_STATUS_ACTIVE
TIME_STATISTIC_NONE = api.TIME_STATISTIC_NONE
TIME_STATISTIC_AVERAGED = api.TIME_STATISTIC_AVERAGED
TIME_STATISTIC_MINIMUM = api.TIME_STATISTIC_MINIMUM
TIME_STATISTIC_MAXIMUM = api.TIME_STATISTIC_MAXIMUM
TIME_STATISTIC_RANGE = api.TIME_STATISTIC_RANGE
OPTION_UNITS_CFS = api.OPTION_UNITS_CFS
OPTION_UNITS_GPM = api.OPTION_UNITS_GPM
OPTION_UNITS_MGD = api.OPTION_UNITS_MGD
OPTION_UNITS_IMGD = api.OPTION_UNITS_IMGD
OPTION_UNITS_AFD = api.OPTION_UNITS_AFD
OPTION_UNITS_LPS = api.OPTION_UNITS_LPS
OPTION_UNITS_LPM = api.OPTION_UNITS_LPM
OPTION_UNITS_MLD = api.OPTION_UNITS_MLD
OPTION_UNITS_CMH = api.OPTION_UNITS_CMH
OPTION_UNITS_CMD = api.OPTION_UNITS_CMD
OPTION_HEADLOSS_HW = api.OPTION_HEADLOSS_HW
OPTION_HEADLOSS_DW = api.OPTION_HEADLOSS_DW
OPTION_HEADLOSS_CM = api.OPTION_HEADLOSS_CM
OPTION_UNBALANCED_STOP = api.OPTION_UNBALANCED_STOP
OPTION_UNBALANCED_CONTINUE = api.OPTION_UNBALANCED_CONTINUE
OPTION_DEMAND_MODEL_DDA = api.OPTION_DEMAND_MODEL_DDA
OPTION_DEMAND_MODEL_PDA = api.OPTION_DEMAND_MODEL_PDA
OPTION_QUALITY_NONE = api.OPTION_QUALITY_NONE
OPTION_QUALITY_CHEMICAL = api.OPTION_QUALITY_CHEMICAL
OPTION_QUALITY_AGE = api.OPTION_QUALITY_AGE
OPTION_QUALITY_TRACE = api.OPTION_QUALITY_TRACE
############################################################
# project
@@ -264,7 +302,7 @@ def get_pump(name: str, id: str) -> dict[str, Any]:
def set_pump(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_pump(name, cs)
# example: add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2'}))
# example: add_pump(p, ChangeSet({'id': 'p0', 'node1': 'j1', 'node2': 'j2', 'power': 0}))
def add_pump(name: str, cs: ChangeSet) -> ChangeSet:
return api.add_pump(name, cs)
@@ -293,6 +331,105 @@ def delete_valve(name: str, cs: ChangeSet) -> ChangeSet:
return api.delete_valve(name, cs)
############################################################
# demand 9.[DEMANDS]
############################################################
def get_demand_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_demand_schema(name)
def get_demand(name: str, junction: str) -> dict[str, Any]:
return api.get_demand(name, junction)
# { 'operation': 'update', 'type': 'demand', 'junction': 'j1', 'demands': [{'demand': 0.0, 'patten': None, 'category': None}] }
def set_demand(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_demand(name, cs)
############################################################
# status 10.[STATUS]
############################################################
def get_status_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_status_schema(name)
def get_status(name: str, link: str) -> dict[str, Any]:
return api.get_status(name, link)
def set_status(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_status(name, cs)
############################################################
# pattern 11.[PATTERNS]
############################################################
def get_pattern_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_pattern_schema(name)
def get_pattern(name: str, id: str) -> dict[str, Any]:
return api.get_pattern(name, id)
def set_pattern(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_pattern(name, cs)
############################################################
# curve 12.[CURVES]
############################################################
def get_curve_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_curve_schema(name)
def get_curve(name: str, id: str) -> dict[str, Any]:
return api.get_curve(name, id)
def set_curve(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_curve(name, cs)
############################################################
# emitter 16.[EMITTERS]
############################################################
def get_emitter_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_emitter_schema(name)
def get_emitter(name: str, junction: str) -> dict[str, Any]:
return api.get_emitter(name, junction)
def set_emitter(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_emitter(name, cs)
############################################################
# time 21.[EMITTERS]
############################################################
def get_time_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_time_schema(name)
def get_time(name: str) -> dict[str, Any]:
return api.get_time(name)
def set_time(name: str, cs: ChangeSet) -> ChangeSet:
return api.set_time(name, cs)
############################################################
# option 23.[OPTIONS]
############################################################
def get_option_schema(name: str) -> dict[str, dict[str, Any]]:
return api.get_option_schema(name)
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)
############################################################
# coord 24.[COORDINATES]
############################################################