from enum import Enum
import matplotlib.lines as mlines
import numpy as np
from relsad.Time import Time, TimeUnit
from relsad.utils import convert_yearly_fail_rate, random_choice
from .Component import Component
from .Disconnector import Disconnector
from .ICTNode import ICTNode
[docs]class IntelligentSwitchState(Enum):
"""
Intelligent switch state
Attributes
----------
OK : int
The intelligent switch is up and running
FAILED : int
The intelligent switch has failed
REPAIR : int
The intelligent switch is being repaired
"""
OK = 1
FAILED = 2
REPAIR = 3
[docs]class IntelligentSwitch(Component):
"""
Common class for batteries
...
Attributes
----------
name : string
Name of the intelligent switch
disconnector : Disconnector
The disconnector the intelligent switch is connected to
ict_node : ICTNode
The ICT node connected to the intelligent switch
fail_rate_per_year : float
The failure rate per year for the intelligent switch
manual_repair_time : Time
The time it takes to manually repair the intelligent switch
state : IntelligentSwitchState
Which state the intelligent switch is in
remaining_repair_time : Time
The remaining repair time of the intelligent switch
history : dict
Dictonary attribute that stores the historic variables
monte_carlo_history : dict
Dictonary attribute that stores the historic variables from the Monte Carlo simulation
Methods
----------
fail()
Sets the intelligent switch state to FAILED
not_fail()
Sets the intelligent switch state to OK
draw_fail_status(dt)
Draws the state of the intelligent switch for a given time step
draw_status(prob)
Sets the state of the intelligent switch based on the probability of the state being FAILED
get_open_repair_time(dt)
Returns the time it takes to open the intelligent switch when it must be repaired
get_open_time(dt)
Returns the time it takes to open the intelligent switch based on the status
open()
Opens the disconnector
repair_close(dt)
Sets the remaining repair time of the intelligent switch
Closes the disconnector
Sets the state of the intelligent switch to repair
close(dt)
Closes the disconnector if the state of the intelligent switch is OK
update_fail_status(dt)
Updates the fail status of the intelligent switch
If the state of the intelligent switch is REPAIR, the remaining repair time is calculated
If the state of the intelligent switch is OK, the state of the intelligent switch is drawn
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 instance
print_status()
Prints the status
reset_status(save_flag)
Resets the status of the intelligent switch
initialize_history()
Initializes the history variables
"""
## Visual attributes
color = "seagreen"
marker = "x"
size = 2**2
handle = mlines.Line2D(
[],
[],
marker=marker,
markeredgewidth=1,
markersize=size,
color=color,
linestyle="None",
)
## Random instance
ps_random: np.random.Generator = None
def __init__(
self,
name: str,
disconnector: Disconnector,
ict_node: ICTNode = None,
fail_rate_per_year: float = 0.03,
manual_repair_time: Time = Time(2, TimeUnit.HOUR),
state: IntelligentSwitchState = IntelligentSwitchState.OK,
):
# Verify input
if disconnector is None:
raise Exception(
"IntelligentSwitch must be connected to a Disconnector"
)
if fail_rate_per_year < 0:
raise Exception("The failure rate per year must be positive")
self.name = name
self.disconnector = disconnector
disconnector.intelligent_switch = self
self.ict_node = ict_node
if ict_node is not None:
ict_node.coordinate = self.disconnector.coordinate
self.fail_rate_per_year = fail_rate_per_year
self.remaining_repair_time = Time(0)
self.manual_repair_time = manual_repair_time
self.state = state
## History
self.history = {}
self.monte_carlo_history = {}
self.initialize_history()
def __str__(self):
return self.name
def __repr__(self):
return f"IntelligentSwitch(name={self.name})"
def __eq__(self, other):
if hasattr(other, "name"):
return self.name == other.name and isinstance(
other, IntelligentSwitch
)
else:
return False
def __hash__(self):
return hash(self.name)
[docs] def fail(self):
"""
Sets the intelligent switch state to FAILED
Parameters
----------
None
Returns
----------
None
"""
self.state = IntelligentSwitchState.FAILED
[docs] def not_fail(self):
"""
Sets the intelligent switch state to OK
Parameters
----------
None
Returns
----------
None
"""
self.state = IntelligentSwitchState.OK
[docs] def draw_fail_status(self, dt: Time):
"""
Draws the state of the intelligent switch for a given time step
Parameters
----------
dt : Time
The current time step
Returns
----------
None
"""
p_fail = convert_yearly_fail_rate(self.fail_rate_per_year, dt)
self.draw_status(p_fail)
[docs] def draw_status(self, prob):
"""
Sets the state of the intelligent switch based on the probability of the state being FAILED
Parameters
----------
prob : float
The probability that the intelligent switch state is FAILED
Returns
----------
None
"""
if random_choice(self.ps_random, prob):
self.fail()
else:
self.not_fail()
[docs] def get_open_repair_time(self, dt: Time):
"""
Returns the time it takes to open the intelligent switch
when it must be repaired
Parameters
----------
dt : Time
The current time step
Returns
----------
open_repair_time: Time
The time it takes to open the intelligent switch
when it must be repaired
"""
self.remaining_repair_time = self.manual_repair_time
self.state = IntelligentSwitchState.REPAIR
open_repair_time = (
self.disconnector.line.parent_network.controller.manual_sectioning_time
)
return open_repair_time
[docs] def get_open_time(self, dt: Time):
"""
Returns the time it takes to open the intelligent switch
based on the status
Parameters
----------
dt : Time
The current time step
Returns
----------
open_time: Time
The time it takes to open the intelligent switch
based on the status
"""
open_time = None
if self.state == IntelligentSwitchState.REPAIR:
open_time = Time(0)
else:
if self.state == IntelligentSwitchState.OK:
open_time = Time(0)
elif self.state == IntelligentSwitchState.FAILED:
open_time = self.get_open_repair_time(dt)
return open_time
[docs] def open(self):
"""
Opens the disconnector
Parameters
----------
None
Returns
----------
None
"""
self.disconnector.open()
[docs] def repair_close(self, dt: Time):
"""
Sets the remaining repair time of the intelligent switch
Closes the disconnector
Sets the state of the intelligent switch to repair
Parameters
----------
dt : Time
The current time step
Returns
----------
None
"""
# Repair is started
self.remaining_repair_time = self.manual_repair_time
# Repair crew is assumed to be present repairing the line,
# they close the disconnector manually
self.disconnector.close()
self.state = IntelligentSwitchState.REPAIR
[docs] def close(self, dt: Time):
"""
Closes the disconnector if the state of the intelligent switch is OK
Parameters
----------
dt : Time
The current time step
Returns
----------
None
"""
if not self.state == IntelligentSwitchState.REPAIR:
if self.state == IntelligentSwitchState.OK:
self.disconnector.close()
elif self.state == IntelligentSwitchState.FAILED:
self.repair_close(dt)
[docs] def update_fail_status(self, dt: Time):
"""
Updates the fail status of the intelligent switch
If the state of the intelligent switch is REPAIR, the remaining repair time is calculated
If the state of the intelligent switch is OK, the state of the intelligent switch is drawn
Parameters
----------
dt : Time
The current time step
Returns
----------
None
"""
if self.state == IntelligentSwitchState.REPAIR:
self.remaining_repair_time -= dt
if self.remaining_repair_time <= Time(0):
self.not_fail()
elif self.state == IntelligentSwitchState.OK:
self.draw_fail_status(dt)
[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 current 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_repair_time"][
time
] = self.remaining_repair_time.get_unit_quantity(curr_time.unit)
self.history["state"][time] = self.state.value
[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 instance
Parameters
----------
random_gen : np.random.default_rng()
Random number generator
Returns
----------
None
"""
self.ps_random = random_gen
[docs] def print_status(self):
"""
Prints the status
Parameters
----------
None
Returns
----------
None
"""
pass
[docs] def reset_status(self, save_flag: bool):
"""
Resets the status of the intelligent switch
Parameters
----------
save_flag : bool
Indicates if saving is on or off
Returns
----------
None
"""
self.state = IntelligentSwitchState.OK
self.remaining_repair_time = Time(0)
if save_flag:
self.initialize_history()
[docs] def initialize_history(self):
"""
Initializes the history variables
Parameters
----------
None
Returns
----------
None
"""
self.history["remaining_repair_time"] = {}
self.history["state"] = {}