From 6046cdf01a5bc8bc9f8a0d757ddad5c6da515e6f Mon Sep 17 00:00:00 2001 From: "WQY\\qiong" Date: Tue, 16 May 2023 21:30:23 +0800 Subject: [PATCH] Support SA --- api/__init__.py | 5 +- api/batch_exe.py | 7 ++ api/s33_dma.py | 4 +- api/s34_sa.py | 217 ++++++++++++++++++++++++++++++++ api/s34_sa_cal.py | 27 ++-- api/s34_sa_gen.py | 18 +++ api/sections.py | 1 + script/sql/create/32.region.sql | 2 +- test_tjnetwork.py | 167 ++++++++++++++++++++++-- tjnetwork.py | 20 +-- 10 files changed, 434 insertions(+), 34 deletions(-) create mode 100644 api/s34_sa.py create mode 100644 api/s34_sa_gen.py diff --git a/api/__init__.py b/api/__init__.py index 50dd7f3..7f680c6 100644 --- a/api/__init__.py +++ b/api/__init__.py @@ -139,18 +139,17 @@ from .s31_scada_element import get_all_scada_element_ids, get_all_scada_elements from .clean_api import clean_scada_element from .s32_region_util import get_nodes_in_boundary, get_nodes_in_region, calculate_convex_hull, calculate_boundary, inflate_boundary, inflate_region - from .s32_region import get_region_schema, get_region, set_region, add_region, delete_region from .s33_dma_cal import PARTITION_TYPE_RB, PARTITION_TYPE_KWAY from .s33_dma_cal import calculate_district_metering_area_for_nodes, calculate_district_metering_area_for_region, calculate_district_metering_area_for_network - from .s33_dma import get_district_metering_area_schema, get_district_metering_area, set_district_metering_area, add_district_metering_area, delete_district_metering_area from .s33_dma import get_all_district_metering_area_ids, get_all_district_metering_areas - from .s33_dma_gen import generate_district_metering_area, generate_sub_district_metering_area from .s34_sa_cal import calculate_service_area +from .s34_sa import get_service_area_schema, get_service_area, set_service_area, add_service_area, delete_service_area, get_all_service_area_ids, get_all_service_areas +from .s34_sa_gen import generate_service_area from .s35_vd import calculate_virtual_district diff --git a/api/batch_exe.py b/api/batch_exe.py index 49c5001..7675d7b 100644 --- a/api/batch_exe.py +++ b/api/batch_exe.py @@ -32,6 +32,7 @@ from .s30_scada_device_data import set_scada_device_data, add_scada_device_data, from .s31_scada_element import set_scada_element, add_scada_element, delete_scada_element from .s32_region import set_region, add_region, delete_region from .s33_dma import set_district_metering_area, add_district_metering_area, delete_district_metering_area +from .s34_sa import set_service_area, add_service_area, delete_service_area from .batch_api_cs import rewrite_batch_api @@ -112,6 +113,8 @@ def _execute_add_command(name: str, cs: ChangeSet) -> ChangeSet: return add_region(name, cs) elif type == s33_dma: return add_district_metering_area(name, cs) + elif type == s34_sa: + return add_service_area(name, cs) return ChangeSet() @@ -195,6 +198,8 @@ def _execute_update_command(name: str, cs: ChangeSet) -> ChangeSet: return set_region(name, cs) elif type == s33_dma: return set_district_metering_area(name, cs) + elif type == s34_sa: + return set_service_area(name, cs) return ChangeSet() @@ -276,6 +281,8 @@ def _execute_delete_command(name: str, cs: ChangeSet) -> ChangeSet: return delete_region(name, cs) elif type == s33_dma: return delete_district_metering_area(name, cs) + elif type == s34_sa: + return delete_service_area(name, cs) return ChangeSet() diff --git a/api/s33_dma.py b/api/s33_dma.py index 838ed0f..49198c9 100644 --- a/api/s33_dma.py +++ b/api/s33_dma.py @@ -7,7 +7,7 @@ def get_district_metering_area_schema(name: str) -> dict[str, dict[str, Any]]: return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, 'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False }, 'parent' : {'type': 'str' , 'optional': True , 'readonly': False }, - 'level' : {'type': 'str' , 'optional': False , 'readonly': True } } + 'level' : {'type': 'int' , 'optional': False , 'readonly': True } } def get_district_metering_area(name: str, id: str) -> dict[str, Any]: @@ -29,7 +29,7 @@ def get_district_metering_area(name: str, id: str) -> dict[str, Any]: return dma -# no update for nodes + def _set_district_metering_area(name: str, cs: ChangeSet) -> DbChangeSet: id = cs.operations[0]['id'] diff --git a/api/s34_sa.py b/api/s34_sa.py new file mode 100644 index 0000000..ec54c2c --- /dev/null +++ b/api/s34_sa.py @@ -0,0 +1,217 @@ +from .database import * +from .s0_base import is_node +from .s32_region_util import to_postgis_polygon +from .s32_region import get_region + +def get_service_area_schema(name: str) -> dict[str, dict[str, Any]]: + return { 'id' : {'type': 'str' , 'optional': False , 'readonly': True }, + 'boundary' : {'type': 'tuple_list' , 'optional': False , 'readonly': False }, + 'source' : {'type': 'str' , 'optional': False , 'readonly': False }, + 'time_index' : {'type': 'int' , 'optional': False , 'readonly': False } } + +def get_service_area(name: str, id: str) -> dict[str, Any]: + sa = get_region(name, id) + if sa == {}: + return {} + r = try_read(name, f"select * from region_sa where id = '{id}'") + if r == None: + return {} + sa['source'] = r['source'] + sa['nodes'] = list(eval(r['nodes'])) + sa['time_index'] = r['time_index'] + return sa + +def _set_service_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + new_boundary = cs.operations[0]['boundary'] + old_boundary = get_region(name, id)['boundary'] + + new_source = cs.operations[0]['source'] + f_new_source = f"'{new_source}'" + + new_nodes = cs.operations[0]['nodes'] + str_new_nodes = str(new_nodes).replace("'", "''") + + new_time_index = cs.operations[0]['time_index'] + + old = get_service_area(name, id) + old_source = old['source'] + f_old_source = f"'{old_source}'" + + old_nodes = old['nodes'] + str_old_nodes = str(old_nodes).replace("'", "''") + + old_time_index = old['time_index'] + + redo_sql = f"update region set boundary = st_geomfromtext('{to_postgis_polygon(new_boundary)}') where id = '{id}';" + redo_sql += f"update region_sa set time_index = {new_time_index}, source = {f_new_source}, nodes = '{str_new_nodes}' where id = '{id}';" + + undo_sql = f"update region_sa set time_index = {old_time_index}, source = {f_old_source}, nodes = '{str_old_nodes}' where id = '{id}';" + undo_sql += f"update region set boundary = st_geomfromtext('{to_postgis_polygon(old_boundary)}') where id = '{id}';" + + redo_cs = g_update_prefix | { 'type': 'service_area', 'id': id, 'boundary': new_boundary, 'time_index': new_time_index, 'source': new_source, 'nodes': new_nodes } + undo_cs = g_update_prefix | { 'type': 'service_area', 'id': id, 'boundary': old_boundary, 'time_index': old_time_index, 'source': old_source, 'nodes': old_nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def set_service_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + sa = get_service_area(name, op['id']) + if sa == {}: + return ChangeSet() + + if 'boundary' not in op: + op['boundary'] = sa['boundary'] + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'time_index' not in op: + op['time_index'] = sa['time_index'] + + if 'source' not in op: + op['source'] = sa['source'] + + if not is_node(name, op['source']): + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = sa['nodes'] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _set_service_area(name, cs)) + + +def _add_service_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + + boundary = cs.operations[0]['boundary'] + + time_index = cs.operations[0]['time_index'] + + source = cs.operations[0]['source'] + f_source = f"'{source}'" + + nodes = cs.operations[0]['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'SA');" + redo_sql += f"insert into region_sa (id, time_index, source, nodes) values ('{id}', {time_index}, {f_source}, '{str_nodes}');" + + undo_sql = f"delete from region_sa where id = '{id}';" + undo_sql += f"delete from region where id = '{id}';" + + redo_cs = g_add_prefix | { 'type': 'service_area', 'id': id, 'boundary': boundary, 'time_index': time_index, 'source': source, 'nodes': nodes } + undo_cs = g_delete_prefix | { 'type': 'service_area', 'id': id } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def add_service_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + sa = get_service_area(name, op['id']) + if sa != {}: + return ChangeSet() + + if 'boundary' not in op: + return ChangeSet() + else: + b = op['boundary'] + if len(b) < 4 or b[0] != b[-1]: + return ChangeSet() + + if 'time_index' not in op: + return ChangeSet() + + if 'source' not in op: + return ChangeSet() + + if not is_node(name, op['source']): + return ChangeSet() + + if 'nodes' not in op: + op['nodes'] = [] + else: + for node in op['nodes']: + if not is_node(name, node): + return ChangeSet() + + return execute_command(name, _add_service_area(name, cs)) + + +def _delete_service_area(name: str, cs: ChangeSet) -> DbChangeSet: + id = cs.operations[0]['id'] + sa = get_service_area(name, id) + boundary = sa['boundary'] + time_index = sa['time_index'] + source = sa['source'] + f_source = f"'{source}'" + nodes = sa['nodes'] + str_nodes = str(nodes).replace("'", "''") + + redo_sql = f"delete from region_sa where id = '{id}';" + redo_sql += f"delete from region where id = '{id}';" + + undo_sql = f"insert into region (id, boundary, r_type) values ('{id}', '{to_postgis_polygon(boundary)}', 'SA');" + undo_sql += f"insert into region_sa (id, time_index, source, nodes) values ('{id}', {time_index}, {f_source}, '{str_nodes}');" + + redo_cs = g_delete_prefix | { 'type': 'service_area', 'id': id } + undo_cs = g_add_prefix | { 'type': 'service_area', 'id': id, 'boundary': boundary, 'time_index': time_index, 'source': source, 'nodes': nodes } + + return DbChangeSet(redo_sql, undo_sql, [redo_cs], [undo_cs]) + + +def delete_service_area(name: str, cs: ChangeSet) -> ChangeSet: + ops = cs.operations + + if len(cs.operations) == 0: + return ChangeSet() + + op = ops[0] + + if 'id' not in op: + return ChangeSet() + + sa = get_service_area(name, op['id']) + if sa == {}: + return ChangeSet() + + return execute_command(name, _delete_service_area(name, cs)) + + +def get_all_service_area_ids(name: str) -> list[str]: + ids = [] + for row in read_all(name, f"select id from region_sa"): + ids.append(row['id']) + return ids + + +def get_all_service_areas(name: str) -> list[dict[str, Any]]: + result = [] + for id in get_all_service_area_ids(name): + result.append(get_service_area(name, id)) + return result diff --git a/api/s34_sa_cal.py b/api/s34_sa_cal.py index ec012e5..88705c5 100644 --- a/api/s34_sa_cal.py +++ b/api/s34_sa_cal.py @@ -2,18 +2,13 @@ import sys import json from queue import Queue from .database import * -from .s0_base import get_node_links, get_link_nodes +from .s0_base import get_node_links, get_link_nodes, get_nodes sys.path.append('..') from epanet.epanet import run_project -def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]: - inp = json.loads(run_project(name)) - - time_count = len(inp['node_results'][0]['result']) - if time_index >= time_count: - return {} +def _calculate_service_area(name: str, inp, time_index: int = 0) -> dict[str, list[str]]: sources : dict[str, list[str]] = {} for node_result in inp['node_results']: result = node_result['result'][time_index] @@ -43,6 +38,8 @@ def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]: elif node2 == cursor and link_flows[link] < 0: queue.put(node1) + return sources + # calculation concentration concentration_map: dict[str, dict[str, float]] = {} node_wip: list[str] = [] @@ -85,6 +82,8 @@ def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]: break if ready: for link_node in up_link_nodes: + if link_node[1] not in concentration_map.keys(): + continue for source, concentration in concentration_map[link_node[1]].items(): concentration_map[node][source] += concentration * abs(link_flows[link_node[0]]) @@ -117,3 +116,17 @@ def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]: sas.append({ 'source': source, 'nodes': nodes }) return { 'service_areas' : sas, 'concentrations': concentration_map } + + +def calculate_service_area(name: str) -> list[dict[str, list[str]]]: + inp = json.loads(run_project(name)) + + result: list[dict[str, list[str]]] = [] + + time_count = len(inp['node_results'][0]['result']) + + for i in range(time_count): + sas = _calculate_service_area(name, inp, i) + result.append(sas) + + return result diff --git a/api/s34_sa_gen.py b/api/s34_sa_gen.py new file mode 100644 index 0000000..4b5cd12 --- /dev/null +++ b/api/s34_sa_gen.py @@ -0,0 +1,18 @@ +from .s32_region_util import calculate_boundary, inflate_boundary +from .s34_sa_cal import * +from .batch_exe import execute_batch_command + +def generate_service_area(name: str) -> ChangeSet: + cs = ChangeSet() + + sass = calculate_service_area(name) + + time_index = 0 + for sas in sass: + for source, nodes in sas.items(): + boundary = calculate_boundary(name, nodes) + boundary = inflate_boundary(name, boundary) + cs.add({ 'type': 'service_area', 'id': f"SA_{source}_{time_index}", 'boundary': boundary, 'time_index': time_index, 'source': source, 'nodes': nodes }) + time_index += 1 + + return execute_batch_command(name, cs) diff --git a/api/sections.py b/api/sections.py index d64ca0c..130e882 100644 --- a/api/sections.py +++ b/api/sections.py @@ -35,6 +35,7 @@ s30_scada_device_data = 'scada_device_data' s31_scada_element = 'scada_element' s32_region = 'region' s33_dma = 'district_metering_area' +s34_sa = 'service_area' TITLE = 'TITLE' JUNCTIONS = 'JUNCTIONS' diff --git a/script/sql/create/32.region.sql b/script/sql/create/32.region.sql index 78e0bfd..9f52f6a 100644 --- a/script/sql/create/32.region.sql +++ b/script/sql/create/32.region.sql @@ -3,7 +3,7 @@ create type region_type as enum ('NONE', 'DMA', 'SA', 'VD', 'WDA'); create table region ( id text primary key -, boundary geometry not null unique +, boundary geometry not null --unique , r_type region_type not null default 'NONE' ); diff --git a/test_tjnetwork.py b/test_tjnetwork.py index 7360dba..2c8bc0c 100644 --- a/test_tjnetwork.py +++ b/test_tjnetwork.py @@ -6130,18 +6130,163 @@ class TestApi: read_inp(p, f'./inp/net3.inp', '3') open_project(p) - result = calculate_service_area(p, 1) - sas = result['service_areas'] - assert len(sas) == 3 - assert sas[0]['source'] == 'River' - assert sas[0]['nodes'] == ['River', '60', '61', '123', '601', '121', '120', '119', '125', '151', '157', '127', '153', '149', '159', '20', '129', '147', '161', '3', '131', '139', '145', '163', '195', '141', '164', '265', '143', '166', '169', '15', '167', '171', '269', '173', '271', '199', '181', '201', '273', '35', '177', '203', '275'] - assert sas[1]['source'] == 'Lake' - assert sas[1]['nodes'] == ['117', '115', '111', '113', '197', '193', '191', '267', '187', '189', '204', '183', '185', '179', '184', '40', '205', '1', '207', '206', '208', '209', '211', '213', '237', '215', '229', '239', '217', '231', '241', '249', '219', '225', '243', 'Lake', '10', '101', '103', '105', '109', '107', '263', '259', '261', '257'] - assert sas[2]['source'] == '2' - assert sas[2]['nodes'] == ['247', '2', '50', '255', '253', '251'] + sass = calculate_service_area(p) + assert len(sass) == 25 + assert sass[0] == {'River': ['River', '60', '61', '123', '601', '121', '120', '119', '125', '117', '257', '151', '157', '127', '153', '115', '261', '259', '149', '159', '20', '129', '111', '113', '107', '263', '147', '161', '3', '131', '139', '109', '197', '193', '105', '145', '163', '195', '141', '103', '191', '101', '164', '265', '143', '187', '166', '169', '267', '15', '204', '167', '171', '269', '189', '185', '173', '271', '183', '184', '199', '181', '179', '205', '201', '273', '35', '177', '40', '207', '203', '275', '1', '206', '208', '209', '211', '213', '237', '215', '229', '217', '231', '219', '225'], '2': ['2', '50', '255', '247', '253', '251', '241', '249', '239', '243', '237', '229', '231']} + assert sass[1] == {'River': ['River', '60', '61', '123', '601', '121', '120', '119', '125', '117', '151', '157', '127', '153', '115', '149', '159', '20', '129', '111', '113', '147', '161', '3', '131', '139', '197', '193', '145', '163', '195', '141', '191', '267', '164', '265', '143', '187', '189', '166', '169', '15', '204', '183', '167', '171', '269', '185', '179', '173', '271', '184', '40', '199', '181', '205', '1', '201', '273', '35', '177', '207', '203', '275', '206', '208', '209', '211', '213', '237', '215', '229', '239', '217', '231', '241', '249', '219', '225', '243', '247'], 'Lake': ['Lake', '10', '101', '103', '105', '109', '107', '263', '111', '115', '259', '261', '113', '197', '257', '117', '193', '191', '120', '267', '187', '119', '189', '265', '204', '151', '157', '183', '169', '185', '149', '159', '179', '167', '171', '269', '184', '147', '161', '40', '173', '271', '205', '145', '163', '195', '1', '199', '181', '207', '141', '164', '201', '273', '35', '177', '206', '143', '166', '203', '275', '208', '15', '209', '211', '213', '237', '215', '229', '239', '217', '231', '241', '249', '219', '225', '243', '247'], '2': ['2', '50', '255', '247', '253', '251', '249']} - nss = result['concentrations'] - assert nss == {'River': {'River': 1.0}, '60': {'River': 1.0}, '61': {'River': 1.0}, '123': {'River': 1.0}, '601': {'River': 1.0}, '121': {'River': 1.0}, '120': {'River': 0.8482133936739926, 'Lake': 0.15178660632600738}, '119': {'River': 0.9996314569097752, 'Lake': 0.0003685430902247304}, '125': {'River': 1.0}, '117': {'River': 0.3008743130788367, 'Lake': 0.6991256869211634}, '151': {'River': 0.9997011779067223, 'Lake': 0.00029882209327779035}, '157': {'River': 0.9996314569097753, 'Lake': 0.00036854309022473045}, '127': {'River': 1.0}, '153': {'River': 1.0}, '115': {'River': 0.1925947954811129, 'Lake': 0.8074052045188872}, '149': {'River': 0.9997011779067222, 'Lake': 0.0002988220932777903}, '159': {'River': 0.9996314569097753, 'Lake': 0.00036854309022473045}, '20': {'River': 1.0}, '129': {'River': 1.0}, '111': {'River': 0.05905486831242531, 'Lake': 0.9409451316875747}, '113': {'River': 0.0957651873908324, 'Lake': 0.9042348126091676}, '147': {'River': 0.9997011779067222, 'Lake': 0.0002988220932777903}, '161': {'River': 0.9996314569097752, 'Lake': 0.0003685430902247304}, '3': {'River': 1.0}, '131': {'River': 1.0}, '139': {'River': 1.0}, '197': {'River': 0.05905486831242531, 'Lake': 0.9409451316875747}, '193': {'River': 0.09576518739083238, 'Lake': 0.9042348126091676}, '145': {'River': 0.9997011779067223, 'Lake': 0.0002988220932777903}, '163': {'River': 0.9996314569097753, 'Lake': 0.00036854309022473045}, '195': {'River': 0.9996314569097754, 'Lake': 0.00036854309022473045}, '141': {'River': 0.9998401927344082, 'Lake': 0.00015980726559174143}, '191': {'River': 0.06331784947523231, 'Lake': 0.9366821505247677}, '267': {'River': 0.09576518739083238, 'Lake': 0.9042348126091676}, '164': {'River': 0.9996314569097753, 'Lake': 0.00036854309022473045}, '265': {'River': 0.9906312413668901, 'Lake': 0.00936875863310988}, '143': {'River': 0.9998401927344083, 'Lake': 0.00015980726559174143}, '187': {'River': 0.06331784947523231, 'Lake': 0.9366821505247677}, '189': {'River': 0.09256760501206042, 'Lake': 0.9074323949879396}, '166': {'River': 0.9996314569097753, 'Lake': 0.00036854309022473045}, '169': {'River': 0.9906312413668901, 'Lake': 0.00936875863310988}, '15': {'River': 0.9998401927344083, 'Lake': 0.00015980726559174143}, '204': {'River': 0.06331784947523231, 'Lake': 0.9366821505247677}, '183': {'River': 0.09256760501206042, 'Lake': 0.9074323949879396}, '167': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '171': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '269': {'River': 0.9906312413668901, 'Lake': 0.00936875863310988}, '185': {'River': 0.06961984624591949, 'Lake': 0.9303801537540806}, '179': {'River': 0.09256760501206042, 'Lake': 0.9074323949879396}, '173': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '271': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '184': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '40': {'River': 0.09256760501206042, 'Lake': 0.9074323949879396}, '199': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '181': {'River': 0.9906312413668901, 'Lake': 0.009368758633109882}, '205': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '1': {'River': 0.09256760501206042, 'Lake': 0.9074323949879396}, '201': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '273': {'River': 0.9906312413668902, 'Lake': 0.009368758633109882}, '35': {'River': 0.9906312413668901, 'Lake': 0.009368758633109882}, '177': {'River': 0.9906312413668901, 'Lake': 0.009368758633109882}, '207': {'River': 0.06961984624591949, 'Lake': 0.9303801537540806}, '203': {'River': 0.9906312413668901, 'Lake': 0.00936875863310988}, '275': {'River': 0.9906312413668901, 'Lake': 0.009368758633109882}, '206': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '208': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '209': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '211': {'River': 0.06961984624591948, 'Lake': 0.9303801537540806}, '213': {'River': 0.06961984624591948, 'Lake': 0.9303801537540806}, '237': {'River': 0.06961984624591948, 'Lake': 0.9303801537540806}, '215': {'River': 0.06961984624591948, 'Lake': 0.9303801537540806}, '229': {'River': 0.06961984624591946, 'Lake': 0.9303801537540805}, '239': {'River': 0.06961984624591946, 'Lake': 0.9303801537540805}, '217': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '231': {'River': 0.06961984624591948, 'Lake': 0.9303801537540806}, '241': {'River': 0.06961984624591946, 'Lake': 0.9303801537540805}, '249': {'River': 0.06794376025334521, 'Lake': 0.9079814093218103, '2': 0.024074830424844474}, '219': {'River': 0.06961984624591948, 'Lake': 0.9303801537540805}, '225': {'River': 0.06961984624591948, 'Lake': 0.9303801537540806}, '243': {'River': 0.06961984624591946, 'Lake': 0.9303801537540805}, '247': {'River': 0.030503133134582493, 'Lake': 0.40763534000762625, '2': 0.5618615268577912}, 'Lake': {'Lake': 1.0}, '10': {'Lake': 1.0}, '101': {'Lake': 1.0}, '103': {'Lake': 1.0}, '105': {'Lake': 1.0}, '109': {'Lake': 1.0}, '107': {'Lake': 1.0}, '263': {'Lake': 1.0}, '259': {'Lake': 1.0}, '261': {'Lake': 1.0}, '257': {'Lake': 1.0}, '2': {'2': 1.0}, '50': {'2': 1.0}, '255': {'2': 1.0}, '253': {'2': 1.0}, '251': {'2': 1.0}} + self.leave(p) + + + def test_service_area(self): + p = 'test_service_area' + self.enter(p) + + sa = get_service_area(p, 'sa') + assert sa == {} + + add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)]})) + sa = get_service_area(p, 'sa') + assert sa == {} + + add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0'})) + sa = get_service_area(p, 'sa') + assert sa == {} + + add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + + add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0'})) + sa = get_service_area(p, 'sa') + assert sa == {} + + add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0', 'nodes' : ['x']})) + sa = get_service_area(p, 'sa') + assert sa == {} + + add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0', 'time_index' : 0, 'nodes': ['j0']})) + sa = get_service_area(p, 'sa') + assert sa['id'] == 'sa' + assert sa['time_index'] == 0 + assert sa['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert sa['source'] == 'j0' + assert sa['nodes'] == ['j0'] + + add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + + set_service_area(p, ChangeSet({'id': 'sa', 'source': 'j1', 'time_index' : 1, 'nodes': ['j1']})) + sa = get_service_area(p, 'sa') + assert sa['id'] == 'sa' + assert sa['time_index'] == 1 + assert sa['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert sa['source'] == 'j1' + assert sa['nodes'] == ['j1'] + + delete_service_area(p, ChangeSet({'id': 'sa'})) + sa = get_service_area(p, 'sa') + assert sa == {} + + self.leave(p) + + + def test_service_area_op(self): + p = 'test_service_area_op' + self.enter(p) + + cs = add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0)]})).operations + assert len(cs) == 0 + + cs = add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0'})).operations + assert len(cs) == 0 + + add_junction(p, ChangeSet({'id': 'j0', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + + cs = add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0'})).operations + assert len(cs) == 0 + + cs = add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0', 'nodes' : ['x']})).operations + assert len(cs) == 0 + + cs = add_service_area(p, ChangeSet({'id': 'sa', 'boundary': [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)], 'source': 'j0', 'time_index' : 0, 'nodes': ['j0']})).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + assert cs['time_index'] == 0 + assert cs['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert cs['source'] == 'j0' + assert cs['nodes'] == ['j0'] + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + assert cs['time_index'] == 0 + assert cs['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert cs['source'] == 'j0' + assert cs['nodes'] == ['j0'] + + add_junction(p, ChangeSet({'id': 'j1', 'x': 0.0, 'y': 10.0, 'elevation': 20.0})) + + cs = set_service_area(p, ChangeSet({'id': 'sa', 'source': 'j1', 'time_index' : 1, 'nodes': ['j1']})).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + assert cs['time_index'] == 1 + assert cs['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert cs['source'] == 'j1' + assert cs['nodes'] == ['j1'] + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + assert cs['time_index'] == 0 + assert cs['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert cs['source'] == 'j0' + assert cs['nodes'] == ['j0'] + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_UPDATE + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + assert cs['time_index'] == 1 + assert cs['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert cs['source'] == 'j1' + assert cs['nodes'] == ['j1'] + + cs = delete_service_area(p, ChangeSet({'id': 'sa'})).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + + cs = execute_undo(p).operations[0] + assert cs['operation'] == API_ADD + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + assert cs['time_index'] == 1 + assert cs['boundary'] == [(0.0, 0.0), (1.0, 0.0), (1.0, 1.0), (0.0, 0.0)] + assert cs['source'] == 'j1' + assert cs['nodes'] == ['j1'] + + cs = execute_redo(p).operations[0] + assert cs['operation'] == API_DELETE + assert cs['type'] == 'service_area' + assert cs['id'] == 'sa' + + self.leave(p) + + + def test_service_area_gen(self): + p = 'test_service_area_gen' + read_inp(p, f'./inp/net3.inp', '3') + open_project(p) + + cs = generate_service_area(p).operations + assert len(cs) == 78 self.leave(p) diff --git a/tjnetwork.py b/tjnetwork.py index 6d7a618..8941c32 100644 --- a/tjnetwork.py +++ b/tjnetwork.py @@ -1068,32 +1068,32 @@ def generate_sub_district_metering_area(name: str, dma: str, part_count: int = 1 # service_area 34 ############################################################ -def calculate_service_area(name: str, time_index: int = 0) -> dict[str, Any]: - return api.calculate_service_area(name, time_index) +def calculate_service_area(name: str) -> list[dict[str, list[str]]]: + return api.calculate_service_area(name) def get_service_area_schema(name: str) -> dict[str, dict[str, Any]]: - return {} + return api.get_service_area_schema(name) def get_service_area(name: str, id: str) -> dict[str, Any]: - return {} + return api.get_service_area(name, id) def set_service_area(name: str, cs: ChangeSet) -> ChangeSet: - return ChangeSet() + return api.set_service_area(name, cs) def add_service_area(name: str, cs: ChangeSet) -> ChangeSet: - return ChangeSet() + return api.add_service_area(name, cs) def delete_service_area(name: str, cs: ChangeSet) -> ChangeSet: - return ChangeSet() + return api.delete_service_area(name, cs) def get_all_service_area_ids(name: str) -> list[str]: - return [] + return api.get_all_service_area_ids(name) def get_all_service_areas(name: str) -> list[dict[str, Any]]: - return [] + return api.get_all_service_areas(name) def generate_service_area(name: str) -> ChangeSet: - return ChangeSet() + return api.generate_service_area(name) ############################################################