def progressive_height_and_costs(self, G, dikenodes, steps): for dike in dikenodes: node = G.nodes[dike] # Rescale according to step and tranform in meters for s in steps: node['DikeIncrease {}'.format(s)] *= self.dh # 1 Initialize fragility curve # 2 Shift it to the degree of dike heigthening: # 3 Calculate cumulative raising node['fnew {}'.format(s)] = deepcopy(node['f']) node['dikeh_cum {}'.format(s)] = 0 for ss in steps[steps <= s]: node['fnew {}'.format(s)][:, 0] += node['DikeIncrease {}'.format(ss)] node['dikeh_cum {}'.format(s)] += node['DikeIncrease {}'.format(ss)] # Calculate dike heigheting costs: if node['DikeIncrease {}'.format(s)] == 0: node['dikecosts {}'.format(s)] = 0 else: node['dikecosts {}'.format(s)] = cost_fun( node['traj_ratio'], node['c'], node['b'], node['lambda'], node['dikeh_cum {}'.format(s)], node['DikeIncrease {}'.format(s)])
def __call__(self, timestep=1, **kwargs): G = self.G Qpeaks = self.Qpeaks step = self.step dikelist = self.dikelist # Call RfR initialization: self._initialize_rfr_ooi(G, dikelist) # Load all kwargs into network. Kwargs are uncertainties and levers: for item in kwargs: # when item is 'discount rate': if item == 'discount rate': G.node[item]['value'] = kwargs[item] # the rest of the times you always get a string like {}_{}: else: # print(item) string1, string2 = item.split('_') if string2 == 'RfR': # string1: projectID # string2: rfr # Note: kwargs[item] in this case can be either 0 # (no project) or 1 (yes project) proj_node = G.node['RfR_projects'] # Cost of RfR project proj_node['cost'] += kwargs[item]*proj_node[string1][ 'costs_1e6']*1e6 # Iterate over the location affected by the project for key in proj_node[string1].keys(): if key != 'costs_1e6': # Change in rating curve due to the RfR project G.node[key]['rnew'][:, 1] -= kwargs[item]*proj_node[ string1][key] else: # string1: dikename or EWS # string2: name of uncertainty or lever G.node[string1][string2] = kwargs[item] if string2 == 'DikeIncrease': node = G.node[string1] # Rescale according to step and tranform in meters node[string2] = (kwargs[item] * step)/100.0 # Initialize fragility curve: node['fnew'] = deepcopy(node['f']) # Shift it to the degree of dike heigthening: node['fnew'][:,0] += node[string2] # Calculate dike heigheting costs: if node[string2] == 0: node['dikecosts'] = 0 else: node['dikecosts'] = cost_fun( node['traj_ratio'], node['c'], node['b'], node['lambda'], node['dikelevel'], node[string2]) # Percentage of people which cant be evacuated for a given warning time: G.node['EWS']['evacuation_percentage'] = G.node['EWS']['evacuees'][ G.node['EWS']['DaysToThreat']] # Dictionary storing outputs: data = {} for Qpeak in Qpeaks: node = G.node['A.0'] waveshape_id = node['ID flood wave shape'] time = np.arange(0, node['Qevents_shape'].loc[waveshape_id].shape[0], timestep) node['Qout'] = Qpeak*node['Qevents_shape'].loc[waveshape_id] # Initialize hydrological event: for key in dikelist: node = G.node[key] Q_0 = int(G.node['A.0']['Qout'][0]) self._initialize_hydroloads(node, time, Q_0) # Calculate critical water level: water above which failure occurs node['critWL'] = Lookuplin(node['fnew'], 1, 0, node['pfail']) # Run the simulation: # Run over the discharge wave: for t in range(1,len(time)): # Run over each node of the branch: for n in range(0, len(dikelist)): # Select current node: node = G.node[dikelist[n]] if node['type'] == 'dike': # Muskingum parameters: C1 = node['C1'] C2 = node['C2'] C3 = node['C3'] prec_node = G.node[node['prec_node']] # Evaluate Q coming in a given node at time t: node['Qin'][t] = Muskingum(C1, C2, C3, prec_node['Qout'][t], prec_node['Qout'][t-1], node['Qin'][t-1]) # Transform Q in water levels: node['wl'][t] = Lookuplin(node['rnew'], 0, 1, node['Qin'][t]) # Evaluate failure and, in case, Q in the floodplain and # Q left in the river: res = dikefailure(self.sb, node['Qin'][t], node['wl'][t], node['hbas'][t], node['hground'], node['status'][t-1], node['Bmax'], node['Brate'], time[t], node['tbreach'], node['critWL']) node['Qout'][t] = res[0] node['Qpol'][t] = res[1] node['status'][t] = res[2] node['tbreach'] = res[3] # Evaluate the volume inside the floodplain as the integral # of Q in time up to time t. node['cumVol'][t] = np.trapz(node['Qpol'])*self.timestepcorr Area = Lookuplin(node['table'], 4, 0, node['wl'][t]) node['hbas'][t] = node['cumVol'][t]/float(Area) elif node['type'] == 'downstream': node['Qin'] = G.node[dikelist[n-1]]['Qout'] # Iterate over the network and store outcomes of interest for a given event for dike in self.dikelist: node = G.node[dike] # If breaches occured: if node['status'][-1] == True: # Losses per event: node['losses'].append(Lookuplin(node['table'], 6, 4, np.max(node['wl']))) node['deaths'].append(Lookuplin(node['table'], 6, 3, np.max(node['wl']))*( 1-G.node['EWS']['evacuation_percentage'])) node['evacuation_costs'].append(cost_evacuation(Lookuplin( node['table'], 6, 5, np.max(node['wl']) )*G.node['EWS']['evacuation_percentage'], G.node['EWS']['DaysToThreat'])) else: node['losses'].append(0) node['deaths'].append(0) node['evacuation_costs'].append(0) EECosts = [] # Iterate over the network,compute and store ooi over all events for dike in dikelist: node = G.node[dike] # Expected Annual Damage: EAD = np.trapz(node['losses'], self.p_exc) # Discounted annual risk per dike ring: disc_EAD = np.sum(discount(EAD, rate=G.node['discount rate']['value'], n=self.n)) # Expected Annual number of deaths: END = np.trapz(node['deaths'], self.p_exc) # Expected Evacuation costs: depend on the event, the higher # the event, the more people you have got to evacuate: EECosts.append(np.trapz(node['evacuation_costs'], self.p_exc)) data.update({'{}_Expected Annual Damage'.format(dike): disc_EAD, '{}_Expected Number of Deaths'.format(dike): END, '{}_Dike Investment Costs'.format(dike): node['dikecosts']}) data.update({'RfR Total Costs': G.node['RfR_projects']['cost']}) data.update({'Expected Evacuation Costs': np.sum(EECosts)}) return data