Source code for esapp.saw.sensitivity

"""Sensitivity analysis specific functions."""
from typing import Union

from ._helpers import create_object_string
from ._enums import YesNo, LinearMethod, IslandReference


[docs] class SensitivityMixin: """Mixin for sensitivity analysis functions."""
[docs] def CalculateFlowSense(self, flow_element: str, flow_type: str): """Calculates the sensitivity of the flow of a line or interface to bus injections. This method determines how much the flow on a specific element changes for a unit change in injection at each bus. Parameters ---------- flow_element : str The flow element string (e.g., '[BRANCH 1 2 1]', '[INTERFACE "name"]'). flow_type : str The type of flow to calculate sensitivity for ("MW", "MVAR", "MVA"). Returns ------- str The result of the script command. Raises ------ PowerWorldError If the SimAuto call fails. """ return self._run_script("CalculateFlowSense", flow_element, flow_type)
[docs] def CalculatePTDF(self, seller: str, buyer: str, method: Union[LinearMethod, str] = LinearMethod.DC): """Calculates the PTDF (Power Transfer Distribution Factor) values between a seller and a buyer. PTDFs indicate how much power flow on a specific branch changes for a unit power transfer between two points in the system. Parameters ---------- seller : str The seller (source) object string (e.g., '[AREA "Top"]', '[BUS 7]'). buyer : str The buyer (sink) object string (e.g., '[AREA "Bottom"]', '[BUS 8]'). method : Union[LinearMethod, str], optional The linear method to use for calculation (LinearMethod.AC, LinearMethod.DC, LinearMethod.DCPS). Defaults to LinearMethod.DC. Returns ------- str The result of the script command. Raises ------ PowerWorldError If the SimAuto call fails. """ m = method.value if isinstance(method, LinearMethod) else method return self._run_script("CalculatePTDF", seller, buyer, m)
[docs] def CalculateLODF(self, branch: str, method: Union[LinearMethod, str] = LinearMethod.DC, post_closure_lcdf: Union[YesNo, str] = ""): """Calculates LODF (Line Outage Distribution Factors) for a specified branch outage. LODFs quantify how much power flow on other branches changes when a specific branch is outaged. Parameters ---------- branch : str The branch element string to outage/close (e.g., '[BRANCH 1 2 1]'). method : Union[LinearMethod, str], optional The linear method to use for calculation (LinearMethod.DC, LinearMethod.DCPS). Defaults to LinearMethod.DC. post_closure_lcdf : Union[YesNo, str], optional Optional parameter (YesNo.YES or YesNo.NO) to include LCDF (Line Closure Distribution Factor) calculation relative to post-closure flow. Defaults to "". Returns ------- str The result of the script command. Raises ------ PowerWorldError If the SimAuto call fails. """ m = method.value if isinstance(method, LinearMethod) else method if post_closure_lcdf: lcdf = post_closure_lcdf.value if isinstance(post_closure_lcdf, YesNo) else post_closure_lcdf return self._run_script("CalculateLODF", branch, m, lcdf) return self._run_script("CalculateLODF", branch, m)
[docs] def CalculateLODFAdvanced(self, include_phase_shifters: bool, file_type: str, max_columns: int, min_lodf: float, number_format: str, decimal_points: int, only_increasing: bool, filename: str, include_islanding: bool = True): """Performs an advanced LODF calculation with various output and filtering options. Parameters ---------- include_phase_shifters : bool If True, includes phase shifters in the LODF calculation. file_type : str The output file type (e.g., "CSV", "AUX"). max_columns : int Maximum number of columns in the output file. min_lodf : float Minimum LODF value to report. number_format : str Format for numeric output (e.g., "DECIMAL", "PERCENT"). decimal_points : int Number of decimal points for numeric output. only_increasing : bool If True, only reports increasing LODF values. filename : str The path to the output file. include_islanding : bool, optional If True, includes islanding information in the output. Defaults to True. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. ValueError If `file_type` or `number_format` are invalid. Notes ----- This method corresponds to the `CalculateLODFAdvanced` script command in PowerWorld. """ ips = YesNo.from_bool(include_phase_shifters) inc = YesNo.from_bool(only_increasing) isl = YesNo.from_bool(include_islanding) return self._run_script("CalculateLODFAdvanced", ips, file_type, max_columns, min_lodf, number_format, decimal_points, inc, f'"{filename}"', isl)
[docs] def CalculateLODFScreening(self, filter_process: str, filter_monitor: str, include_phase_shifters: bool, include_open_lines: bool, use_lodf_threshold: bool, lodf_threshold: float, use_overload_threshold: bool, overload_low: float, overload_high: float, do_save_file: bool, file_location: str, custom_high_lodf: int = 0, custom_high_lodf_line: int = 0, custom_high_overload: int = 0, custom_high_overload_line: int = 0, do_use_ctg_name: bool = False, custom_orig_ctg_name: int = 0): """Performs LODF Screening calculation to identify critical outages and overloads. This method is used to quickly assess the impact of numerous outages based on LODF and overload thresholds. Parameters ---------- filter_process : str Filter for branches to outage/process. filter_monitor : str Filter for branches to monitor. include_phase_shifters : bool If True, includes phase shifters in the calculation. include_open_lines : bool If True, includes initially open lines in the calculation. use_lodf_threshold : bool If True, applies an LODF threshold for reporting. lodf_threshold : float The LODF threshold value. use_overload_threshold : bool If True, applies an overload threshold for reporting. overload_low : float Lower bound for overload threshold (e.g., 100 for 100% limit). overload_high : float Upper bound for overload threshold. do_save_file : bool If True, saves the screening results to a file. file_location : str The path to the output file if `do_save_file` is True. custom_high_lodf : int, optional Custom field index for high LODF. Defaults to 0. custom_high_lodf_line : int, optional Custom field index for high LODF line. Defaults to 0. custom_high_overload : int, optional Custom field index for high overload. Defaults to 0. custom_high_overload_line : int, optional Custom field index for high overload line. Defaults to 0. do_use_ctg_name : bool, optional If True, uses contingency name in output. Defaults to False. custom_orig_ctg_name : int, optional Custom field index for original contingency name. Defaults to 0. Returns ------- None """ ips = YesNo.from_bool(include_phase_shifters) iol = YesNo.from_bool(include_open_lines) ult = YesNo.from_bool(use_lodf_threshold) uot = YesNo.from_bool(use_overload_threshold) dsf = YesNo.from_bool(do_save_file) duc = YesNo.from_bool(do_use_ctg_name) return self._run_script("CalculateLODFScreening", filter_process, filter_monitor, ips, iol, ult, lodf_threshold, uot, overload_low, overload_high, dsf, f'"{file_location}"', custom_high_lodf, custom_high_lodf_line, custom_high_overload, custom_high_overload_line, duc, custom_orig_ctg_name)
[docs] def CalculateShiftFactors(self, flow_element: str, direction: str, transactor: str, method: Union[LinearMethod, str] = LinearMethod.DC): """Calculates Shift Factor Sensitivity values (formerly known as TLRs). Shift Factors quantify how much power flow on a specific element changes for a unit injection change at a particular transactor (e.g., area, bus). Parameters ---------- flow_element : str The monitored flow element string (e.g., '[BRANCH 1 2 1]', '[INTERFACE "name"]'). direction : str The direction of transfer ("BUYER" or "SELLER"). transactor : str The transactor object string (e.g., '[AREA "Top"]', '[BUS 7]'). method : Union[LinearMethod, str], optional The linear method to use for calculation (LinearMethod.AC, LinearMethod.DC, LinearMethod.DCPS). Defaults to LinearMethod.DC. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ m = method.value if isinstance(method, LinearMethod) else method return self._run_script("CalculateShiftFactors", flow_element, direction, transactor, m)
[docs] def CalculateShiftFactorsMultipleElement(self, type_element: str, which_element: str, direction: str, transactor: str, method: Union[LinearMethod, str] = LinearMethod.DC): """Calculates Shift Factor Sensitivity values for multiple elements. This method extends `CalculateShiftFactors` to apply the calculation across a set of elements defined by `type_element` and `which_element`. Parameters ---------- type_element : str The type of element to calculate shift factors for (e.g., "BRANCH", "INTERFACE"). which_element : str A PowerWorld filter name or "ALL" to specify which elements to include. direction : str The direction of transfer ("BUYER" or "SELLER"). transactor : str The transactor object string (e.g., '[AREA "Top"]', '[BUS 7]'). method : Union[LinearMethod, str], optional The linear method to use for calculation (LinearMethod.AC, LinearMethod.DC, LinearMethod.DCPS). Defaults to LinearMethod.DC. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ m = method.value if isinstance(method, LinearMethod) else method return self._run_script("CalculateShiftFactorsMultipleElement", type_element, which_element, direction, transactor, m)
[docs] def CalculateLODFMatrix( self, which_ones: str, filter_process: str, filter_monitor: str, monitor_only_closed: bool = True, linear_method: Union[LinearMethod, str] = LinearMethod.DC, filter_monitor_interface: str = "", post_closure_lcdf: bool = True, ): """Calculates the Line Outage Distribution Factors (LODF) matrix. This method generates a matrix showing the impact of a set of outages/closures on a set of monitored elements. Parameters ---------- which_ones : str Specifies whether to calculate for "OUTAGES" or "CLOSURES". filter_process : str A PowerWorld filter name for branches to outage/close. filter_monitor : str A PowerWorld filter name for branches to monitor. monitor_only_closed : bool, optional If True, only monitors initially closed branches. Defaults to True. linear_method : Union[LinearMethod, str], optional The linear method to use (LinearMethod.DC or LinearMethod.DCPS). Defaults to LinearMethod.DC. filter_monitor_interface : str, optional A PowerWorld filter name for interfaces to monitor. Defaults to "". post_closure_lcdf : bool, optional If True, calculates LCDF (Line Closure Distribution Factor) relative to post-closure flow. Defaults to True. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ mon_closed = YesNo.from_bool(monitor_only_closed) post_lcdf = YesNo.from_bool(post_closure_lcdf) m = linear_method.value if isinstance(linear_method, LinearMethod) else linear_method return self._run_script("CalculateLODFMatrix", which_ones, filter_process, filter_monitor, mon_closed, m, filter_monitor_interface, post_lcdf)
[docs] def CalculateVoltToTransferSense( self, seller: str, buyer: str, transfer_type: str = "P", turn_off_avr: bool = False ): """Calculates the sensitivity of bus voltage to power transfer between a seller and buyer. This helps in understanding voltage impacts of inter-area power exchanges. Parameters ---------- seller : str The seller (source) object string (e.g., '[AREA "Top"]', '[BUS 7]'). buyer : str The buyer (sink) object string (e.g., '[AREA "Bottom"]', '[BUS 8]'). transfer_type : str, optional The type of transfer ("P" for active power, "Q" for reactive power). Defaults to "P". turn_off_avr : bool, optional If True, turns off Automatic Voltage Regulators (AVRs) during the calculation. Defaults to False. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ avr = YesNo.from_bool(turn_off_avr) return self._run_script("CalculateVoltToTransferSense", seller, buyer, transfer_type, avr)
[docs] def CalculateLossSense(self, function_type: str, area_ref: str = "NO", island_ref: Union[IslandReference, str] = IslandReference.EXISTING): """Calculates loss sensitivity at each bus. Loss sensitivity indicates how much system losses change for a unit injection change at each bus. Parameters ---------- function_type : str The type of function for loss calculation (e.g., "AREA", "ZONE", "BUS"). area_ref : str, optional Area reference for calculation ("NO", or an area name). Defaults to "NO". island_ref : str, optional Island reference for calculation ("EXISTING", or an island name). Defaults to "EXISTING". Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ return self._run_script("CalculateLossSense", function_type, area_ref, island_ref)
[docs] def LineLoadingReplicatorCalculate(self, flow_element: str, injection_group: str, agc_only: bool, desired_flow: float, implement: bool, linear_method: Union[LinearMethod, str] = LinearMethod.DC, use_load_min_max: bool = True, max_mult: float = 1.0, min_mult: float = 1.0): """Calculates injection changes required to alter a line flow to a desired value. This tool helps in determining how to adjust generation or load to achieve a target flow on a specific element. Parameters ---------- flow_element : str The flow element string (e.g., '[BRANCH 1 2 1]'). injection_group : str The injection group string (e.g., '[INJECTIONGROUP "GenGroup"]'). agc_only : bool If True, only considers generators participating in AGC for adjustments. desired_flow : float The desired flow value on the `flow_element`. implement : bool If True, immediately implements the calculated injection changes. linear_method : Union[LinearMethod, str], optional The linear method to use (LinearMethod.DC, LinearMethod.AC). Defaults to LinearMethod.DC. use_load_min_max : bool, optional If True, respects load min/max limits during adjustments. Defaults to True. max_mult : float, optional Maximum multiplier for adjustments. Defaults to 1.0. min_mult : float, optional Minimum multiplier for adjustments. Defaults to 1.0. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ agc = YesNo.from_bool(agc_only) imp = YesNo.from_bool(implement) ulmm = YesNo.from_bool(use_load_min_max) m = linear_method.value if isinstance(linear_method, LinearMethod) else linear_method return self._run_script("LineLoadingReplicatorCalculate", flow_element, injection_group, agc, desired_flow, imp, m, ulmm, max_mult, min_mult)
[docs] def LineLoadingReplicatorImplement(self): """Applies the changes calculated by the Line Loading Replicator. This action modifies the system based on the previously determined injection adjustments. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ return self._run_script("LineLoadingReplicatorImplement")
[docs] def CalculateTapSense(self, filter_name: str = ""): """Forces voltage to tap sensitivity calculation. This determines how bus voltages respond to changes in transformer tap settings. Parameters ---------- filter_name : str, optional A PowerWorld filter name to apply to transformers. Defaults to an empty string (all). Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ return self._run_script("CalculateTapSense", f'"{filter_name}"')
[docs] def CalculateVoltSelfSense(self, filter_name: str = ""): """Calculates the sensitivity of a bus's voltage to injections at the same bus. Parameters ---------- filter_name : str, optional A PowerWorld filter name to apply to buses. Defaults to an empty string (all). Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ return self._run_script("CalculateVoltSelfSense", f'"{filter_name}"')
[docs] def CalculateVoltSense(self, bus_num: int): """Calculates the sensitivity of a bus's voltage to injections at all buses. Parameters ---------- bus_num : int The bus number for which to calculate voltage sensitivity. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ bus_str = create_object_string("Bus", bus_num) return self._run_script("CalculateVoltSense", bus_str)
[docs] def SetSensitivitiesAtOutOfServiceToClosest(self, filter_name: str = "", branch_dist_meas: str = ""): """Populates sensitivity values at out-of-service buses by interpolating from the closest in-service buses. Parameters ---------- filter_name : str, optional A PowerWorld filter name to apply to buses. Defaults to an empty string (all). branch_dist_meas : str, optional The branch distance measurement to use (e.g., "X", "R", "Z"). Defaults to "". Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ filt = f'"{filter_name}"' if filter_name else "" return self._run_script("SetSensitivitiesAtOutOfServiceToClosest", filt, branch_dist_meas)
[docs] def CalculatePTDFMultipleDirections(self, store_branches: bool = True, store_interfaces: bool = True, method: Union[LinearMethod, str] = LinearMethod.DC): """Calculates PTDF values between all directions specified in the case. Parameters ---------- store_branches : bool, optional If True, stores PTDFs for branches. Defaults to True. store_interfaces : bool, optional If True, stores PTDFs for interfaces. Defaults to True. method : Union[LinearMethod, str], optional The linear method to use for calculation (LinearMethod.DC, LinearMethod.AC, LinearMethod.DCPS). Defaults to LinearMethod.DC. Returns ------- None Raises ------ PowerWorldError If the SimAuto call fails. """ sb = YesNo.from_bool(store_branches) si = YesNo.from_bool(store_interfaces) m = method.value if isinstance(method, LinearMethod) else method return self._run_script("CalculatePTDFMultipleDirections", sb, si, m)