Source code for relsad.network.components.ICTLine

import matplotlib.lines as mlines
import numpy as np

from relsad.StatDist import StatDist, StatDistType, UniformParameters
from relsad.Time import Time, TimeUnit
from relsad.utils import convert_yearly_fail_rate, random_choice

from .Component import Component
from .ICTNode import ICTNode


[docs]class ICTLine(Component): r""" A class used to represent an ICT Line ... Attributes ---------- name : str Name of the line fnode : ICTNode Sending ICT node tnode : ICTNode Receiving ICT node parent_network : ICTNetwork The parent ICT network of the line fail_rate_per_year : float Failure rate per year [fault/year/km] repair_time_dist : StatDist The repair time of the line [hours/fault] connected : bool Indicates if the line is connected or disconnected failed : bool Failure status of the line remaining_outage_time : Time The remaining outage time of the line history : dict Dictonary attribute that stores the historic variables Methods ------- disconnect() Disconnects a line and removes the line for the list of lines connect() Connects a line and append the line to the list of lines draw_repair_time(dt) Decides and returns the repair time of the line based on a statistical distribution fail(dt) Sets the fail status of the line to True and opens the connected disconnectors and the connected circuit breaker not_fail() Sets the fail status of the line to False and closes the connected disconnectors and connected circuit breaker change_direction() Changes the direction of the line update_fail_status(dt) Updates the fail status of the line print_status() Prints the line status add_parent_network(network) Adds the parent network to the line initialize_history() Initialize the history variables update_history(prev_time, curr_time, save_flag) Updates the history variables get_history(attribute) Returns the history variables of an attribute add_random_instance(random_gen) Adds global random seed reset_status() Resets and sets the status of the class parameters """ lineCount = 0 ## Visual attributes linestyle = "dotted" handle = mlines.Line2D([], [], linestyle=linestyle) ## Random instance ps_random: np.random.Generator = None def __init__( self, name: str, fnode: ICTNode, tnode: ICTNode, repair_time_dist: StatDist = StatDist( stat_dist_type=StatDistType.UNIFORM_FLOAT, parameters=UniformParameters( min_val=0.0, max_val=0.0, ), ), fail_rate_per_year: float = 0.0, # fails/year connected=True, ): # Verify input if fnode is None: raise Exception("Line must have a origin ICT node") if tnode is None: raise Exception("Line must have a target ICT node") if repair_time_dist is None: raise Exception("The line must have a repair time distribution") if fail_rate_per_year < 0: raise Exception("The failure rate per year must be positive") ## Informative attributes self.name = name ## Topological attributes self.fnode = fnode self.tnode = tnode fnode.connected_lines.append(self) tnode.connected_lines.append(self) tnode.toline = self tnode.toline_list.append(self) fnode.fromline = self fnode.fromline_list.append(self) self.parent_network = None ICTLine.lineCount += 1 ## Reliabilility attributes self.fail_rate_per_year = fail_rate_per_year self.repair_time_dist = repair_time_dist ## Status attribute self.connected = connected self.failed = False self.remaining_outage_time = Time(0) ## History self.history = {} self.initialize_history() def __str__(self): return self.name def __repr__(self): return f"ICTLine(name={self.name})" def __eq__(self, other): if hasattr(other, "name"): return self.name == other.name and isinstance(other, ICTLine) else: return False def __hash__(self): return hash(self.name)
[docs] def disconnect(self): """ Disconnects a line and removes the line from the list of lines Parameters ---------- None Returns ---------- None """ if self.connected: self.connected = False self.linestyle = "--" self.fnode.fromline_list.remove(self) if self.fnode.fromline == self: if len(self.fnode.fromline_list) > 0: self.fnode.fromline = next(iter(self.fnode.fromline_list)) else: self.fnode.fromline = None self.tnode.toline_list.remove(self) if self.tnode.toline == self: if len(self.tnode.toline_list) > 0: self.tnode.toline = next(iter(self.tnode.toline_list)) else: self.tnode.toline = None
[docs] def connect(self): """ Connects a line and append the line to the list of lines Parameters ---------- None Returns ---------- None """ if not self.connected: self.connected = True self.linestyle = "-" self.tnode.toline = self self.tnode.toline_list.append(self) self.fnode.fromline = self self.fnode.fromline_list.append(self)
[docs] def draw_repair_time(self, dt: Time): """ Decides and returns the repair time of the line based on a statistical distribution Parameters ---------- dt : Time The current time step Returns ---------- None """ return Time( self.repair_time_dist.draw( random_instance=self.ps_random, size=1, )[0], dt.unit, )
[docs] def fail(self, dt: Time): """ Sets the fail status of the line to False Parameters ---------- dt : Time The current time step Returns ---------- None """ self.failed = True self.parent_network.failed_line = True self.remaining_outage_time = self.draw_repair_time(dt) self.disconnect()
[docs] def not_fail(self): """ Sets the fail status of the line to False Parameters ---------- None Returns ---------- None """ if ( sum([line.failed for line in self.parent_network.lines]) == 1 and self.failed ): self.parent_network.failed_line = False self.failed = False self.connect()
[docs] def change_direction(self): """ Changes the direction of the line Parameters ---------- None Returns ---------- None """ self.fnode.fromline_list.remove(self) self.tnode.fromline_list.append(self) self.tnode.toline_list.remove(self) self.fnode.toline_list.append(self) if self.fnode.fromline == self: self.fnode.fromline = ( next(iter(self.fnode.fromline_list)) if len(self.fnode.fromline_list) > 0 else None ) if self.tnode.toline == self: self.tnode.toline = ( next(iter(self.tnode.toline_list)) if len(self.tnode.toline_list) > 0 else None ) self.fnode.toline = self self.tnode.fromline = self node = self.fnode self.fnode = self.tnode self.tnode = node
[docs] def update_fail_status(self, dt: Time): """ Updates the fail status of the line Parameters ---------- dt : Time The current time step Returns ---------- None """ if self.failed: self.remaining_outage_time -= dt if self.remaining_outage_time <= Time(0): self.not_fail() self.remaining_outage_time = Time(0) else: p_fail = convert_yearly_fail_rate(self.fail_rate_per_year, dt) if random_choice(self.ps_random, p_fail): self.fail(dt) else: self.not_fail()
[docs] def print_status(self): """ Prints the line status Parameters ---------- None Returns ---------- None """ print( "name: {:5s}, failed={}, connected={}".format( self.name, self.failed, self.connected ) )
[docs] def add_parent_network(self, network): """ Adds the parent network to the line Parameters ---------- network : PowerNetwork The parent network of the line Returns ---------- None """ self.parent_network = network
[docs] def initialize_history(self): """ Initializes the history variables Parameters ---------- None Returns ---------- None """ self.history["remaining_outage_time"] = {} self.history["failed"] = {}
[docs] def update_history( self, prev_time: Time, curr_time: Time, save_flag: bool ): """ Updates the history variables Parameters ---------- prev_time : Time The previous time curr_time : Time The vurrent time save_flag : bool Indicates if saving is on or off Returns ---------- None """ if save_flag: time = curr_time.get_unit_quantity(curr_time.unit) self.history["remaining_outage_time"][ time ] = self.remaining_outage_time.get_unit_quantity(curr_time.unit) self.history["failed"][time] = self.failed
[docs] def get_history(self, attribute: str): """ Returns the history variables of an attribute Parameters ---------- attribute : str System attribute Returns ---------- history[attribute] : dict Returns the history variables of an attribute """ return self.history[attribute]
[docs] def add_random_instance(self, random_gen): """ Adds global random seed Parameters ---------- random_gen : int Random number generator Returns ---------- None """ self.ps_random = random_gen
[docs] def reset_status(self, save_flag: bool): """ Resets and sets the status of the class parameters Parameters ---------- None Returns ---------- None """ self.remaining_outage_time = Time(0) self.not_fail() if save_flag: self.initialize_history()
if __name__ == "__main__": pass