From 263dc202ebdd9463baf7f2274bd2b0d44edae0ac Mon Sep 17 00:00:00 2001 From: Sina Naeimi Date: Mon, 26 Aug 2024 17:28:06 -0700 Subject: [PATCH] PEP8 compatibility checked --- ...Copy.py => PyReCode-REWET-preprocessor.py} | 385 ++++++++++++------ .../performREC/pyrecodes/damage_convertor.py | 341 ++++++++++------ 2 files changed, 476 insertions(+), 250 deletions(-) rename modules/performREC/pyrecodes/{PyReCode-REWET-preprocessor - Copy.py => PyReCode-REWET-preprocessor.py} (58%) diff --git a/modules/performREC/pyrecodes/PyReCode-REWET-preprocessor - Copy.py b/modules/performREC/pyrecodes/PyReCode-REWET-preprocessor.py similarity index 58% rename from modules/performREC/pyrecodes/PyReCode-REWET-preprocessor - Copy.py rename to modules/performREC/pyrecodes/PyReCode-REWET-preprocessor.py index 135d20e85..6a097efdb 100644 --- a/modules/performREC/pyrecodes/PyReCode-REWET-preprocessor - Copy.py +++ b/modules/performREC/pyrecodes/PyReCode-REWET-preprocessor.py @@ -1,4 +1,39 @@ -# -*- coding: utf-8 -*- +# Copyright (c) 2024 The Regents of the University of California +# Copyright (c) 2024 Leland Stanford Junior University +# +# This file is part of whale. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# You should have received a copy of the BSD 3-Clause License along with +# whale. If not, see . +# +# Contributors: +# Sina Naeimi import random import json @@ -9,14 +44,13 @@ import pandas as pd from sklearn.cluster import KMeans from rewet.api import API -import rewet_helper as rh TEMP_DIR = "./" RESULT_DIR = "./rewet_result" INPUT_FILE_DIR = "./" -class REWETPyReCoDes(): +class REWETPyReCoDes: def __init__(self): self.wn = None self._clean_wn = None @@ -63,23 +97,37 @@ def system_state(self, state, damage, inp_file, damage_time=0): self.set_asset_data(state) # sets the damage state based on the initial damage (from pelicun) - self.set_initial_water_damage_state(damage, damage_time) + self.update_state_with_damages(damage, damage_time, state) # couple building to the demand nodes self.couple_buildings_to_demand_nodes(state) + def system_performance(self, state, damage, current_time, next_time): + """ + Assesses the system functionality. + Parameters + ---------- + state : dict. + The _det file content. + damage : dict + _i (realization) file content. + current_time : int + Current time in seconds. + next_time : int + Next time in seconds. - def system_performance(self, - state, - damage, - current_time, - next_time): + Returns + ------- + building_satisfaction : dict + The ratio of satiesfied water for each building. + + """ self.wn = copy.deepcopy(self._clean_wn) # sets the damage state based on the current (change of the network) # and saves the current time - self.save_damage(damage, current_time) + self.save_damage(state, current_time) # prepare rewet inputs self.make_rewet_inputs(current_time, next_time) @@ -91,7 +139,7 @@ def system_performance(self, self.set_new_demand(state) # apply_damages - ## self.apply_damage() + # self.apply_damage() # run WDN performance evaluation self.run_performance(current_time, next_time) @@ -101,7 +149,8 @@ def system_performance(self, # Get result building_satisfaction = self.get_building_data_satisfaction( - method="mean") + method="mean" + ) self.building_satisfaction = building_satisfaction return building_satisfaction @@ -139,12 +188,12 @@ def read_inp_file(self, inp_file): if node_name not in self.nodes: self.nodes[node_name] = {} - self.nodes[node_name]["initial_demand"] = \ - node_demand_base_value + self.nodes[node_name][ + "initial_demand" + ] = node_demand_base_value self.nodes[node_name]["coordinates"] = node.coordinates - def set_asset_data(self, state): wdn_state = state["WaterDistributionNetwork"] wdn_state = wdn_state.get("Pipe", []) @@ -162,13 +211,15 @@ def set_asset_data(self, state): for element_key, element_data in sub_asset_type_data.items(): asset_id = element_data["GeneralInformation"]["AIM_id"] if asset_id != element_key: - raise ValueError("The rationality behidn the workdflow" - "is that oth aim-id and keys be the" - "same") + raise ValueError( + "The rationality behidn the workdflow" + "is that oth aim-id and keys be the" + "same" + ) - self.asset_information[asset_type]\ - [sub_asset_type]\ - [asset_id] = element_data["GeneralInformation"] + self.asset_information[asset_type][sub_asset_type][ + asset_id + ] = element_data["GeneralInformation"] building_state = state["Buildings"]["Building"] @@ -189,28 +240,29 @@ def set_asset_data(self, state): self.buildings[building_id] = cur_building - - def set_rewet_damage(self, damage, damage_time): + def update_state_with_damages(self, damage, damage_time, state): damage = damage["WaterDistributionNetwork"] pipe_damage = damage.get("Pipe", []) - damage_list = [] for asset_id, damage_location in pipe_damage.items(): damage_location_info = damage_location["Damage"] - aggregate_keys =[ - key for key in damage_location_info - if "aggregate-" in key] + aggregate_keys = [ + key for key in damage_location_info if "aggregate-" in key + ] aggregate_keys.sort() - aggregate_results = [damage_location_info[key] - for key in aggregate_keys] + aggregate_results = [ + damage_location_info[key] for key in aggregate_keys + ] - segment_sizes = len(aggregate_results ) + segment_sizes = len(aggregate_results) segment_step = 1 / segment_sizes c = 0 + cur_pipe_damage_location_list = [] + cur_pipe_damage_location_type = [] for damage_val in aggregate_results: if damage_val > 0: if damage_val == 1: @@ -218,25 +270,76 @@ def set_rewet_damage(self, damage, damage_time): elif damage_val == 2: damage_type = "break" else: - raise ValueError("The damage type must be eother " - "1 or 2") + raise ValueError( + "The damage type must be eother " "1 or 2" + ) else: continue - cur_loc = c * segment_step + segment_step / 2 + cur_pipe_damage_location_list.append(cur_loc) + cur_pipe_damage_location_type.append(damage_type) + + wdn_state = state["WaterDistributionNetwork"] + pipe_state = wdn_state.get("Pipe") + + if "Damage" in pipe_state[asset_id]: + raise ValueError( + f"Damage is already exist for Pipe " f"{asset_id}" + ) + + pipe_state[asset_id]["Damage"] = dict() + pipe_state[asset_id]["Damage"][ + "Location" + ] = cur_pipe_damage_location_list - c += 1 + pipe_state[asset_id]["Damage"][ + "Type" + ] = cur_pipe_damage_location_type + + def set_rewet_damage_from_state(self, state, damage_time): + state = state["WaterDistributionNetwork"] + pipe_damage = state.get("Pipe", []) + + damage_list = [] + for asset_id, pipe_info in pipe_damage.items(): + damage_location_info = pipe_info["Damage"] + damage_location_list = damage_location_info["Location"] + damage_type_list = damage_location_info["Type"] + + if len(damage_location_list) != len(damage_type_list): + raise ValueError( + "The size of types and locationis not the" " same." + ) + + segment_sizes = len(damage_location_list) + + # if segment_sizes == 0: + # continue + + pipe_id = self.asset_information["WaterDistributionNetwork"][ + "Pipe" + ][asset_id]["InpID"] + + for c in range(segment_sizes): + cur_loc = damage_location_list[c] + damage_type = damage_type_list[c] + + damage_list.append( + { + "pipe_id": pipe_id, + "damage_loc": cur_loc, + "type": damage_type, + "Material": "CI", + } + ) - pipe_id = self.asset_information["WaterDistributionNetwork"]\ - ["Pipe"][asset_id]["InpID"] - damage_list.append( {"pipe_id": pipe_id, "damage_loc": cur_loc, - "type": damage_type, "Material": "CI"} - ) damage_list.reverse() - self.pipe_damage = pd.Series(data=damage_list, - index=[damage_time for val in - damage_list], dtype="O") + self.pipe_damage = pd.Series( + data=damage_list, + index=[damage_time for val in damage_list], + dtype="O", + ) self.node_damage = pd.Series(dtype="O") @@ -244,12 +347,26 @@ def set_rewet_damage(self, damage, damage_time): self.tank_damage = pd.Series(dtype="O") - - def set_initial_water_damage_state(self, damage, damage_time): - self.damage_state[damage_time] = damage - self.set_rewet_damage(self.damage_state[damage_time], damage_time) + if damage_time in self.damage_state: + raise ValueError( + f"Time {damage_time} still exists in" f" damage state." + ) def couple_buildings_to_demand_nodes(self, state): + """ + Couple building to the demand nodes based on their coordinates. + + Parameters + ---------- + state :dict + State file content. + + Returns + ------- + None. + + """ + building_state = state["Buildings"]["Building"] building_id_list = [] @@ -260,17 +377,18 @@ def couple_buildings_to_demand_nodes(self, state): self.building_coordinates.append(coordinate) + demand_node_coordinate_list = [ + val["coordinates"] for key, val in self.nodes.items() + ] - demand_node_coordinate_list = [val["coordinates"] for key, val in - self.nodes.items()] - - demand_node_name_list = [key for key, val in - self.nodes.items()] + demand_node_name_list = [key for key, val in self.nodes.items()] - kmeans = KMeans(n_clusters=len(demand_node_coordinate_list), - init=demand_node_coordinate_list, - n_init=1, - random_state=0) + kmeans = KMeans( + n_clusters=len(demand_node_coordinate_list), + init=demand_node_coordinate_list, + n_init=1, + random_state=0, + ) kmeans.fit(self.building_coordinates) @@ -288,11 +406,12 @@ def couple_buildings_to_demand_nodes(self, state): building_id = building_id_list[building_l] self.demand_node_to_building[node_name].append(building_id) - for node_name in self.demand_node_to_building: building_name_list = self.demand_node_to_building[node_name] - population_list = [self.buildings[bldg_id]["initial_population"] - for bldg_id in building_name_list] + population_list = [ + self.buildings[bldg_id]["initial_population"] + for bldg_id in building_name_list + ] total_initial_population = sum(population_list) @@ -300,25 +419,30 @@ def couple_buildings_to_demand_nodes(self, state): initial_node_demand = cur_node["initial_demand"] if initial_node_demand == 0 and total_initial_population > 0: - Warning(f"Initial demand for node {node_name} is 0." + - "Thus, the demand ratio in buildidng(s)" + - "{repr(building_name_list).strip('[').strip(']'))}" + - "is naturally ineffective and their demand is not met." - ) + Warning( + f"Initial demand for node {node_name} is 0." + f" Thus, the demand ratio in buildidng(s)" + f" {repr(building_name_list).strip('[').strip(']')}" + f" is naturally ineffective and their demand" + f" is not met." + ) if total_initial_population == 0: - Warning(f"The population assigned to {node_name} is 0." + - "Thus, the demand ratio in buildidng(s)" + - "{repr(building_name_list).strip('[').strip(']'))}" + - "is ignored." - ) + Warning( + f"The population assigned to {node_name} is 0." + f" Thus, the demand ratio in buildidng(s)" + f" {repr(building_name_list).strip('[').strip(']')}" + f" is ignored." + ) + # We assume that population in State does not change in teh course # of recovery. Thus, the population is intiial population. For more # clarity, we name the variable "initial_population". # It does not mean that there will be ffdifferent population in # the course of recovery - self.nodes[node_name]["initial_population"] = \ - total_initial_population + self.nodes[node_name][ + "initial_population" + ] = total_initial_population self.nodes[node_name]["initial_node_demand"] = initial_node_demand @@ -326,15 +450,17 @@ def couple_buildings_to_demand_nodes(self, state): pop = self.buildings[bldg_id]["initial_population"] if total_initial_population != 0: - cur_bldg_initial_demand = \ + cur_bldg_initial_demand = ( pop / total_initial_population * initial_node_demand + ) else: cur_bldg_initial_demand = None - self.buildings[bldg_id]["initial_demand"] = \ - cur_bldg_initial_demand + self.buildings[bldg_id][ + "initial_demand" + ] = cur_bldg_initial_demand - def save_damage(self, damage, current_time): + def save_damage(self, state, current_time): """ Convert and save the dmaages that are set before @@ -366,8 +492,20 @@ def save_damage(self, damage, current_time): tank_path = str(tank_path) pump_path = str(pump_path) - self.damage_state[current_time] = damage - self.set_rewet_damage(self.damage_state[current_time], current_time) + # self.damage_state[current_time] = damage + self.set_rewet_damage_from_state(state, current_time) + + if current_time in self.damage_state: + raise ValueError( + f"The time {current_time} is already in " f" damage state." + ) + + self.damage_state[current_time] = { + "Pipe": self.pipe_damage, + "Node": self.node_damage, + "Pump": self.pump_damage, + "Tank": self.tank_damage, + } self.pipe_damage.to_pickle(pipe_path) self.node_damage.to_pickle(node_path) @@ -375,8 +513,8 @@ def save_damage(self, damage, current_time): self.tank_damage.to_pickle(tank_path) scn_postfix_list = random.choices( - ["A","B","C","D","E","F","G","H","I","J","L","M"], - k=0) + ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "L", "M"], k=0 + ) scn_postfix = "" for p in scn_postfix_list: @@ -394,7 +532,6 @@ def save_damage(self, damage, current_time): self.list_path = list_path def run_performance(self, current_time, next_time): - """ Runs the performance model using a hydraic solver (REWET) @@ -419,11 +556,14 @@ def run_performance(self, current_time, next_time): """ if current_time > next_time: - raise ValueError("Current tiime cannot be bigger than the next" - "time") + raise ValueError( + "Current tiime cannot be bigger than the next" "time" + ) if abs(next_time - current_time) % self.hydraulic_time_step != 0: - raise ValueError("next_time - current_time must be a factor of " - "the hydraulci time step.") + raise ValueError( + "next_time - current_time must be a factor of " + "the hydraulci time step." + ) status = self.rewet.initiate(current_time=current_time, debug=True) if status != 0: @@ -436,23 +576,24 @@ def run_performance(self, current_time, next_time): if status != 0: raise ValueError(f"There is an error: {status}") - return dict def make_rewet_inputs(self, current_time, next_time): - settings = rh.get_rewet_hydraulic_basic_setting() + settings = get_rewet_hydraulic_basic_setting() run_time = next_time - current_time list_file_path = Path(self.list_path) list_file_path = list_file_path.resolve() if not list_file_path.exists(): - raise ValueError(f"The list file does not exists: " - f"{str(list_file_path)}") + raise ValueError( + f"The list file does not exists: " f"{str(list_file_path)}" + ) list_file_path = str(list_file_path) - temp_dir = Path(TEMP_DIR).resolve() + temp_dir = Path(TEMP_DIR).resolve() if not temp_dir.exists(): - raise ValueError(f"The temp directory does not exists: " - f"{str(temp_dir)}") + raise ValueError( + f"The temp directory does not exists: " f"{str(temp_dir)}" + ) temp_dir = str(temp_dir) settings["RUN_TIME"] = run_time @@ -460,10 +601,10 @@ def make_rewet_inputs(self, current_time, next_time): settings["result_directory"] = RESULT_DIR settings["temp_directory"] = temp_dir settings["WN_INP"] = self.inp_file_path - settings['pipe_damage_file_list'] = list_file_path - settings['pipe_damage_file_directory'] = temp_dir - settings['Restoration_on'] = False - settings['Pipe_damage_input_method'] = "pickle" + settings["pipe_damage_file_list"] = list_file_path + settings["pipe_damage_file_directory"] = temp_dir + settings["Restoration_on"] = False + settings["Pipe_damage_input_method"] = "pickle" input_file_path = Path(INPUT_FILE_DIR) / "rewet_input.json" input_file_path = input_file_path.resolve() @@ -490,24 +631,24 @@ def get_building_data_satisfaction(self, method): for node_name in self.demand_node_to_building: node_demand_ratio = demand_sat[node_name] building_names = self.demand_node_to_building[node_name] - cur_satisified_demand_building = dict(zip( - building_names, - [node_demand_ratio]*len(building_names))) + cur_satisified_demand_building = dict( + zip(building_names, [node_demand_ratio] * len(building_names)) + ) building_demand_satisfaction_ratio.update( - cur_satisified_demand_building) + cur_satisified_demand_building + ) return building_demand_satisfaction_ratio - - def set_new_demand(self, state): for node_name in self.demand_node_to_building: - cur_node = self.nodes[node_name] - total_initial_population = \ - self.nodes[node_name]["initial_population"] + # cur_node = self.nodes[node_name] + total_initial_population = self.nodes[node_name][ + "initial_population" + ] if not total_initial_population > 0: continue @@ -520,17 +661,19 @@ def set_new_demand(self, state): for bldg_id in building_name_list: - cur_bldg_initial_demand = \ - self.buildings[bldg_id]["initial_demand"] + cur_bldg_initial_demand = self.buildings[bldg_id][ + "initial_demand" + ] - cur_bldg_deamnd_ratio = \ - building[bldg_id]["GeneralInformation"]["Population_Ratio"] + cur_bldg_deamnd_ratio = building[bldg_id][ + "GeneralInformation" + ]["Population_Ratio"] - cur_bldg_new_deamnd = \ + cur_bldg_new_deamnd = ( cur_bldg_deamnd_ratio * cur_bldg_initial_demand + ) - self.buildings[bldg_id]["current_demand"] = \ - cur_bldg_new_deamnd + self.buildings[bldg_id]["current_demand"] = cur_bldg_new_deamnd node_new_demand += cur_bldg_new_deamnd @@ -539,8 +682,15 @@ def set_new_demand(self, state): node.demand_timeseries_list[0].base_value = node_new_demand +def get_rewet_hydraulic_basic_setting(): + settings = rewet.Input.Settings.Settings() + settings_dict = settings.process.settings + # settings_dict.update(settings.scenario.settings) + + return settings_dict -if __name__ == '__main__': + +if __name__ == "__main__": # raise RuntimeError("This file should not be run") with open("Results_det.json", "rt") as f: state = json.load(f) @@ -552,14 +702,9 @@ def set_new_demand(self, state): interface = REWETPyReCoDes() interface.system_state(state, damage, inp_file) - result = interface.system_performance(state, - damage, - 0, - 24*3600) + result = interface.system_performance(state, damage, 0, 24 * 3600) # = interface.system_performance(state, - #damage, - #1*24*3600, - #2*24*3600) - - + # damage, + # 1*24*3600, + # 2*24*3600) diff --git a/modules/performREC/pyrecodes/damage_convertor.py b/modules/performREC/pyrecodes/damage_convertor.py index d460bbbcb..3597f42ae 100644 --- a/modules/performREC/pyrecodes/damage_convertor.py +++ b/modules/performREC/pyrecodes/damage_convertor.py @@ -1,9 +1,39 @@ -# -*- coding: utf-8 -*- -""" -Created on Mon Jan 8 09:40:15 2024 - -@author: naeim -""" +# Copyright (c) 2024 The Regents of the University of California +# Copyright (c) 2024 Leland Stanford Junior University +# +# This file is part of whale. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors +# may be used to endorse or promote products derived from this software without +# specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# You should have received a copy of the BSD 3-Clause License along with +# whale. If not, see . +# +# Contributors: +# Sina Naeimi import os from pathlib import Path @@ -13,9 +43,9 @@ CBIG_int = int(1e9) - - -def createPipeDamageInputForREWET(pipe_damage_data, run_dir, event_time, sc_geojson): +def createPipeDamageInputForREWET( + pipe_damage_data, run_dir, event_time, sc_geojson +): """ Creates REWET-style piep damage file. @@ -38,36 +68,47 @@ def createPipeDamageInputForREWET(pipe_damage_data, run_dir, event_time, sc_geoj """ pipe_id_list = [key for key in pipe_damage_data] - + damage_list = [] damage_time = event_time sc_geojson_file = preprocessorIO.readJSONFile(sc_geojson) - pipe_data = [ss for ss in sc_geojson_file["features"] if ss["properties"]["type"]=="Pipe"] + pipe_data = [ + ss + for ss in sc_geojson_file["features"] + if ss["properties"]["type"] == "Pipe" + ] pipe_index = [str(ss["id"]) for ss in pipe_data] pipe_id = [ss["properties"]["InpID"] for ss in pipe_data] pipe_index_to_id = dict(zip(pipe_index, pipe_id)) - + for pipe_id in pipe_id_list: cur_data = pipe_damage_data[pipe_id] cur_damage = cur_data["Damage"] - cur_demand = cur_data["Demand"] - - aim_data = findAndReadAIMFile(pipe_id,os.path.join( - "Results", "WaterDistributionNetwork", "Pipe"), run_dir) - + # cur_demand = cur_data["Demand"] + + aim_data = findAndReadAIMFile( + pipe_id, + os.path.join("Results", "WaterDistributionNetwork", "Pipe"), + run_dir, + ) + material = aim_data["GeneralInformation"].get("Material", None) - - if material == None: - #raise ValueError("Material is none") + + if material is None: + # raise ValueError("Material is none") material = "CI" - - aggregates_list = [cur_agg for cur_agg in list( cur_damage.keys() ) if "aggregate" in cur_agg] - segment_sizes = len(aggregates_list ) + + aggregates_list = [ + cur_agg + for cur_agg in list(cur_damage.keys()) + if "aggregate" in cur_agg + ] + segment_sizes = len(aggregates_list) segment_step = 1 / segment_sizes c = 0 - - for cur_agg in aggregates_list: #cur_damage["aggregate"]: + + for cur_agg in aggregates_list: # cur_damage["aggregate"]: damage_val = cur_damage[cur_agg] if damage_val > 0: if damage_val == 1: @@ -78,24 +119,29 @@ def createPipeDamageInputForREWET(pipe_damage_data, run_dir, event_time, sc_geoj raise ValueError("The damage type must be eother 1 or 2") else: continue - cur_loc = c * segment_step + segment_step / 2 - #print(cur_loc) + # print(cur_loc) c += 1 - damage_list.append( {"pipe_id": pipe_index_to_id[pipe_id], "damage_loc": cur_loc, - "type": damage_type, "Material": material} - ) + damage_list.append( + { + "pipe_id": pipe_index_to_id[pipe_id], + "damage_loc": cur_loc, + "type": damage_type, + "Material": material, + } + ) damage_list.reverse() - pipe_damage_list = pd.Series(data=damage_list, - index=[damage_time for val in damage_list], dtype="O") - - #REWET_input_data["Pipe_damage_list"] = pipe_damage_list - #REWET_input_data["AIM"] = aim_data - - + pipe_damage_list = pd.Series( + data=damage_list, index=[damage_time for val in damage_list], dtype="O" + ) + + # REWET_input_data["Pipe_damage_list"] = pipe_damage_list + # REWET_input_data["AIM"] = aim_data + return pipe_damage_list + def createNodeDamageInputForREWET(node_damage_data, run_dir, event_time): """ Creates REWET-style node damage file. @@ -114,39 +160,50 @@ def createNodeDamageInputForREWET(node_damage_data, run_dir, event_time): """ node_id_list = [key for key in node_damage_data] - + damage_list = [] damage_time = event_time - + for node_id in node_id_list: cur_damage = node_damage_data[node_id] - aggregates_list = [cur_agg for cur_agg in list( cur_damage.keys() ) if "aggregate" in cur_agg] - + aggregates_list = [ + cur_agg + for cur_agg in list(cur_damage.keys()) + if "aggregate" in cur_agg + ] + if len(aggregates_list) == 0: continue - + cur_data = node_damage_data[node_id] cur_damage = cur_data["Damage"] - cur_demand = cur_data["Demand"] - - aim_data = findAndReadAIMFile(node_id,os.path.join( - "Results", "WaterDistributionNetwork", "Node"), - run_dir) - + # cur_demand = cur_data["Demand"] + + aim_data = findAndReadAIMFile( + node_id, + os.path.join("Results", "WaterDistributionNetwork", "Node"), + run_dir, + ) + total_length = aim_data["GeneralInformation"].get("Total_length", None) total_number_of_damages = cur_damage["aggregate"] - - damage_list.append( {"node_name": node_id, - "number_of_damages": total_number_of_damages, - "node_Pipe_Length": total_length} - ) - - node_damage_list = pd.Series(data=damage_list, - index=[damage_time for val in damage_list], dtype="O") - + + damage_list.append( + { + "node_name": node_id, + "number_of_damages": total_number_of_damages, + "node_Pipe_Length": total_length, + } + ) + + node_damage_list = pd.Series( + data=damage_list, index=[damage_time for val in damage_list], dtype="O" + ) + return node_damage_list - + + def createPumpDamageInputForREWET(pump_damage_data, REWET_input_data): """ Creates REWET-style pump damage file. @@ -165,36 +222,41 @@ def createPumpDamageInputForREWET(pump_damage_data, REWET_input_data): """ pump_id_list = [key for key in pump_damage_data] - + damage_list = [] damage_time = REWET_input_data["event_time"] - + for pump_id in pump_id_list: cur_data = pump_damage_data[pump_id] cur_damage = cur_data["Damage"] cur_repair_time = cur_data["Repair"] - + if cur_damage == 0: - continue # cur_damage_state = 0 means undamaged pump - + continue # cur_damage_state = 0 means undamaged pump + # I'm not sure if we need any data about the pump at this point - - #aim_data = findAndReadAIMFile(tank_id, os.path.join( - #"Results", "WaterDistributionNetwork", "Pump"), - #REWET_input_data["run_dir"]) - - #We are getting this data from PELICUN - #restore_time = getPumpRetsoreTime(cur_damage) - damage_list.append( {"pump_id": pump_id, - "time": damage_time, "Restore_time": cur_repair_time} - ) - pump_damage_list = pd.Series(index=[damage_time for val in damage_list], data=damage_list) - + + # aim_data = findAndReadAIMFile(tank_id, os.path.join( + # "Results", "WaterDistributionNetwork", "Pump"), + # REWET_input_data["run_dir"]) + + # We are getting this data from PELICUN + # restore_time = getPumpRetsoreTime(cur_damage) + damage_list.append( + { + "pump_id": pump_id, + "time": damage_time, + "Restore_time": cur_repair_time, + } + ) + pump_damage_list = pd.Series( + index=[damage_time for val in damage_list], data=damage_list + ) + return pump_damage_list - - - + + def createTankDamageInputForREWET(tank_damage_data, REWET_input_data): """ Creates REWET-style Tank damage file. @@ -212,38 +274,44 @@ def createTankDamageInputForREWET(tank_damage_data, REWET_input_data): REWET-style tank damage file. """ tank_id_list = [key for key in tank_damage_data] - + damage_list = [] damage_time = REWET_input_data["event_time"] - + for tank_id in tank_id_list: cur_data = tank_damage_data[tank_id] cur_damage = cur_data["Damage"] cur_repair_time = cur_data["Repair"] - + if cur_damage == 0: - continue # cur_damage_state = 0 meeans undamged tank - -# ============================================================================= -# # We are getting his data from REWET -# -# aim_data = findAndReadAIMFile(tank_id, os.path.join( -# "Results", "WaterDistributionNetwork", "Tank"), -# REWET_input_data["run_dir"]) -# tank_type = aim_data["GeneralInformation"].get("Type", None) -# restore_time = getTankRetsoreTime(tank_type, cur_damage) -# ============================================================================= - - damage_list.append( {"tank_id": tank_id, - "time": damage_time, "Restore_time": cur_repair_time} - ) - - tank_damage_list = pd.Series(index=[damage_time for val in damage_list], data=damage_list) - + continue # cur_damage_state = 0 meeans undamged tank + + # ============================================================================= + # # We are getting his data from REWET + # + # aim_data = findAndReadAIMFile(tank_id, os.path.join( + # "Results", "WaterDistributionNetwork", "Tank"), + # REWET_input_data["run_dir"]) + # tank_type = aim_data["GeneralInformation"].get("Type", None) + # restore_time = getTankRetsoreTime(tank_type, cur_damage) + # ============================================================================= + + damage_list.append( + { + "tank_id": tank_id, + "time": damage_time, + "Restore_time": cur_repair_time, + } + ) + + tank_damage_list = pd.Series( + index=[damage_time for val in damage_list], data=damage_list + ) + return tank_damage_list - - + + def findAndReadAIMFile(asset_id, asset_type, run_dir): """ Finds and read the AIM file for an asset. @@ -264,20 +332,27 @@ def findAndReadAIMFile(asset_id, asset_type, run_dir): """ - file_path = Path(run_dir, asset_type, str(asset_id), "templatedir", f"{asset_id}-AIM.json") - aim_file_data = preprocessorIO.readJSONFile(str(file_path) ) + file_path = Path( + run_dir, + asset_type, + str(asset_id), + "templatedir", + f"{asset_id}-AIM.json", + ) + aim_file_data = preprocessorIO.readJSONFile(str(file_path)) return aim_file_data - + + def getPumpRetsoreTime(damage_state): """ NOT USED! WE WILL GET IT FROM PELICUN - + Provides the restore time based on HAZUS repair time or any other approach available in the future. If damage state is slight, the restore time is 3 days (in seconds). If damage state is 2, the restore time is 7 days (in seconds). If damage state is 3 or 4, the restore time is indefinite (a big number). - + Parameters ---------- damage_state : Int @@ -287,29 +362,30 @@ def getPumpRetsoreTime(damage_state): Returns ------- Retstor time : int - + """ - + if damage_state == 1: restore_time = int(3 * 24 * 3600) elif damage_state == 2: restore_time = int(7 * 24 * 3600) else: restore_time = CBIG_int - + return restore_time + def getTankRetsoreTime(tank_type, damage_state): """ NOT USED! WE WILL GET IT FROM PELICUN - + Provides the restore time based on HAZUS repair time or any other approach available in the future. if damage state is slight, the restore time is 3 days (in seconds). If damage state is 2, the restore time is 7 days (in seconds). If damage state is 3 or 4, the restore time is indefinite (a big number). - + Parameters ---------- tank_type : STR @@ -321,19 +397,20 @@ def getTankRetsoreTime(tank_type, damage_state): Returns ------- Retstor time : int - + """ - + if damage_state == 1: restore_time = int(3 * 24 * 3600) elif damage_state == 2: restore_time = int(7 * 24 * 3600) else: restore_time = CBIG_int - + return restore_time + def readDamagefile(file_addr, run_dir, event_time, sc_geojson): """ Reads PELICUN damage files and create REWET-Style damage for all @@ -355,41 +432,45 @@ def readDamagefile(file_addr, run_dir, event_time, sc_geojson): """ # TODO: Make reading once for each scneario - - #wn = wntrfr.network.WaterNetworkModel(REWET_input_data["inp_file"] ) - + + # wn = wntrfr.network.WaterNetworkModel(REWET_input_data["inp_file"] ) + damage_data = preprocessorIO.readJSONFile(file_addr) - + wn_damage_data = damage_data["WaterDistributionNetwork"] if "Pipe" in wn_damage_data: pipe_damage_data = createPipeDamageInputForREWET( - wn_damage_data["Pipe"], run_dir, event_time, sc_geojson) + wn_damage_data["Pipe"], run_dir, event_time, sc_geojson + ) else: pipe_damage_data = pd.Series(dtype="O") - + if "Tank" in wn_damage_data: tank_damage_data = createTankDamageInputForREWET( - wn_damage_data["Tank"], run_dir, event_time) + wn_damage_data["Tank"], run_dir, event_time + ) else: tank_damage_data = pd.Series(dtype="O") - - if "Pump" in wn_damage_data: + + if "Pump" in wn_damage_data: pump_damage_data = createPumpDamageInputForREWET( - wn_damage_data["Pump"], run_dir, event_time) + wn_damage_data["Pump"], run_dir, event_time + ) else: pump_damage_data = pd.Series(dtype="O") - - if "Junction" in wn_damage_data: + + if "Junction" in wn_damage_data: node_damage_data = createNodeDamageInputForREWET( - wn_damage_data["Junction"], run_dir, event_time) + wn_damage_data["Junction"], run_dir, event_time + ) else: node_damage_data = pd.Series(dtype="O") - + damage_data = {} damage_data["Pipe"] = pipe_damage_data damage_data["Tank"] = tank_damage_data damage_data["Pump"] = pump_damage_data damage_data["Node"] = node_damage_data - - return damage_data \ No newline at end of file + + return damage_data