### Install dependencies Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/README.md Commands to install the project dependencies using uv for production or development environments. ```bash uv sync --no-dev ``` ```bash uv sync ``` -------------------------------- ### Install with specific Python version Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/README.md Specify a Python version for the local virtual environment during installation. ```bash uv sync --python 3.13 ``` -------------------------------- ### Initialize PowerFactory Interface Configuration Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__add_loads.ipynb Setup the required environment variables and project paths for the PowerFactory 2026 interface. ```python %load_ext autoreload %autoreload 2 import logging import math import pathlib import time import typing as t from collections.abc import Sequence from powerfactory_tools.versions.pf2026 import PowerFactoryInterface from powerfactory_tools.versions.pf2026.interface import ValidPFValue from powerfactory_tools.versions.pf2026.interface import ValidPythonVersion from powerfactory_tools.versions.pf2026.types import CalculationCommand from powerfactory_tools.versions.pf2026.types import PFClassId from powerfactory_tools.versions.pf2026.types import PowerFactoryTypes as PFTypes # PowerFactory configuration PF_SERVICE_PACK = 2 # mandatory PF_USER_PROFILE = "TODO" # mandatory, name of the user profile in the PowerFactory data base PF_INI_NAME = "PowerFactory" # optional specification of ini file name to switch to full version (e.g. PowerFactoryFull for file PowerFactoryFull.ini) PF_PYTHON_VERSION = ValidPythonVersion.VERSION_3_14 # python version of local code environment must match the python version of PowerFactory API # Consider to use raw strings to avoid misinterpretation of special characters, e.g. r"dir\New Project" or r"dir\1-HV-grid". PROJECT_NAME = "PowerFactory-Tools" # may be also full path "dir_name\\project_name" EXPORT_PATH = pathlib.Path("control_action_results") ``` -------------------------------- ### Install PowerFactory Tools Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/docs/joss_paper/paper.md Install the ieee-powerfactory-tools package using pip. This is a prerequisite for using the export functionality. ```shell pip install ieeh-powerfactory-tools ``` -------------------------------- ### Execute control actions using PowerFactoryInterface Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Initializes the PowerFactoryInterface with user-defined service pack and profile settings, then executes control examples for specific bus systems. ```python _project_name = PROJECT_NAME.split("\\") full_export_path = pathlib.Path().cwd() / EXPORT_PATH / _project_name[-1] # Configure logging to output to the notebook's standard output logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() with PowerFactoryInterface( powerfactory_service_pack=PF_SERVICE_PACK, powerfactory_user_profile=PF_USER_PROFILE, powerfactory_ini_name=PF_INI_NAME, python_version=PF_PYTHON_VERSION, project_name=PROJECT_NAME, logging_level=logging.INFO, # log_file_path=full_export_path / pathlib.Path("log_pf_control.txt"), # noqa: ERA001 ) as pfi: logger.info("3_Bus : Run control example ... ") run_three_bus_control_example(pfi, full_export_path) logger.info("3_Bus : Run control example ... Done") logger.info("9_Bus : Run control example ... ") run_nine_bus_control_example(pfi, full_export_path) logger.info("9_Bus : Run control example ... Done") ``` -------------------------------- ### Install PowerFactory Tools via pip Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/README.md Use this command to install the package in your Python environment. ```bash pip install ieeh-powerfactory-tools ``` -------------------------------- ### Import Required Modules Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Initial setup for the export script, including autoreload configuration and necessary PSDM model imports. ```python %load_ext autoreload %autoreload 2 import json import logging import pathlib from collections.abc import Sequence from psdm.steadystate_case.case import Case as SteadystateCase from psdm.topology.topology import Topology from psdm.topology_case.case import Case as TopologyCase ``` -------------------------------- ### Configure PowerFactory Interface and Projects Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__multiple_projects.ipynb Setup the PowerFactory interface version, user profile, and define the project names to be processed. ```python %load_ext autoreload %autoreload 2 import logging from powerfactory_tools.versions.pf2026 import PowerFactoryInterface from powerfactory_tools.versions.pf2026.interface import ValidPythonVersion # PowerFactory configuration PF_SERVICE_PACK = 2 # mandatory PF_USER_PROFILE = "TBD" # mandatory, name of the user profile in the PowerFactory data base PF_INI_NAME = "PowerFactory" # optional specification of ini file name to switch to full version (e.g. PowerFactoryFull for file PowerFactoryFull.ini) PF_PYTHON_VERSION = ValidPythonVersion.VERSION_3_14 # python version of local code environment must match the python version of PowerFactory API # Consider to use raw strings to avoid misinterpretation of special characters, e.g. r"dir\New Project" or r"dir\1-HV-grid". PROJECT_NAME_1 = "PowerFactory-Tools" # may be also full path "dir_name\\project_name" PROJECT_NAME_2 = "Another-Project" # may be also full path "dir_name\\project_name" ``` -------------------------------- ### Example of Importing Topology Schema Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_import.ipynb Configures paths, case, and schema type for importing grid data. It then logs the import process and calls the import_schema function. ```python GRID_PATH = pathlib.Path().cwd() / "grids/" CASE = "Base" SCHEMA = Topology PSDM_CLASS = {Topology: "topology.json", TopologyCase: "topology_case.json", SteadystateCase: "steadystate_case.json"} # Configure logging to output to the notebook's standard output logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() json_file_path = GRID_PATH / CASE / (CASE + NAME_SEPARATOR + "HV_9_Bus" + NAME_SEPARATOR + PSDM_CLASS[SCHEMA]) logger.info(f"Import PSDM schema {SCHEMA} from path {json_file_path} ... ") data, _ = import_schema(SCHEMA, json_file_path) logger.info(f"Import PSDM schema {SCHEMA} from path {json_file_path} ... Done.") ``` -------------------------------- ### Importing PSDM Schema Classes Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_import.ipynb Imports necessary classes for handling PSDM data and PowerFactory tools. This setup is required before performing any import operations. ```python %load_ext autoreload %autoreload 2 import json import logging import pathlib from psdm.base import _Base from psdm.steadystate_case.case import Case as SteadystateCase from psdm.topology.topology import Topology from psdm.topology_case.case import Case as TopologyCase from powerfactory_tools.str_constants import NAME_SEPARATOR ``` -------------------------------- ### Navigate to the project directory Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/README.md Change the current working directory to the cloned project folder. ```bash cd powerfactory-tools ``` -------------------------------- ### Activate and Release Projects Sequentially Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__multiple_projects.ipynb Use join_project and release_project methods within a context manager to handle multiple projects sequentially. ```python # Configure logging to output to the notebook's standard output logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() with PowerFactoryInterface( powerfactory_service_pack=PF_SERVICE_PACK, powerfactory_user_profile=PF_USER_PROFILE, powerfactory_ini_name=PF_INI_NAME, python_version=PF_PYTHON_VERSION, logging_level=logging.DEBUG, # log_file_path=full_export_path / pathlib.Path("log_pf_control.txt"), # noqa: ERA001 ) as pfi: # Activate project 1 pfi.join_project(PROJECT_NAME_1) # Execute some control actions pfi.release_project() # Activate project 1, but in this example without the initial unit conversion to default units pfi.join_project(PROJECT_NAME_1, set_default_units=False) # Execute some control actions pfi.release_project() # Activate project 2 pfi.join_project(PROJECT_NAME_2) # Execute some control actions pfi.release_project() ``` -------------------------------- ### Configure Study Cases and Grids Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Creates a new study case with specific grids and variants, then manages active grid selection. ```python study_case = pfi.create_study_case( name="Industry_Park_v2", grids=pfi.independent_grids(), grid_variants=[variant], target_datetime=dt.datetime(1980, 1, 1, tzinfo=dt.timezone.utc), ) # Switch to this new study case pfi.switch_study_case(study_case.loc_name) # collect all actives grids grids_active = pfi.grids(calc_relevant=True) # noqa: F841 # Let only one grid be active pfi.deactivate_grids() pfi.activate_grid(pfi.grid(grid_name)) ``` -------------------------------- ### Create Load and Study Case Routines Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__add_loads.ipynb Functions to create new loads at specific terminals and manage study case/grid variant switching. ```python def create_load(pfi: PowerFactoryInterface, /, *, grid: PFTypes.Grid, load_data: dict[str, t.Any]) -> PFTypes.Load | None: logger = logging.getLogger() terminal = load_data.pop("terminal") load_name = load_data.pop("name") logger.info(f"Create new load '{load_name}' at terminal '{terminal.loc_name}' ...") term_cubic = terminal.GetContents("*." + PFClassId.CUBICLE.value)[0] # it is necessary to add the copy exactly on a bus, otherwise the field won't have the attribute 'cterm' new_cubicle = terminal.AddCopy(term_cubic, "NewField") data = {"bus1": new_cubicle} load_data.update(data) load = pfi.create_object( name=load_name, class_name=PFClassId.LOAD.value, location=grid, data=load_data, ) return t.cast("PFTypes.Load", load) if load is not None else None def routine_create_new_study_case_and_add_loads( pfi: PowerFactoryInterface, *, study_case_name: str, grid_variant_name: str, grid: PFTypes.Grid, loads_data: Sequence[dict[str, ValidPFValue]], ) -> Sequence[PFTypes.Load] | None: """Use this routine to create a new study case (based on the previously active one) and add new loads to given terminals. Args: study_case_name (str): new study case name grid_variant_name (str): new grid variant name grid (PFTypes.Grid): grid to which the loads belongs loads_data (Sequence[dict[str, ValidPFValue]]): list of dictionaries with load data Returns: Sequence[PFTypes.Load]: list of newly added loads """ ## Create new study case and grid variant # Get active study case and grid variants active_sc = pfi.app.GetActiveStudyCase() default_active_variants = pfi.grid_variants(only_active=True) # Create new study case new_sc = pfi.study_case_dir.AddCopy(active_sc) new_sc.loc_name = study_case_name # type: ignore[reportOptionalMemberAccess] pfi.switch_study_case(study_case_name) # Create and activate new grid variant activation_time = math.floor(time.time()) # now in seconds new_variant = pfi.create_grid_variant(name=grid_variant_name, data={"tAcTime": activation_time}, force=True) pfi.switch_grid_variant(grid_variant_name) ## Add new loads loads = [create_load(pfi, grid=grid, load_data=load_data) for load_data in loads_data] ## Reactivate old (already existing) and new grid variants pfi.deactivate_grid_variants() # reactivate old active variants for variant in default_active_variants: pfi.activate_grid_variant(variant) # reactivate new variant at the end pfi.activate_grid_variant(new_variant) return pfi.filter_none(loads) ``` -------------------------------- ### Manage Grid Variants and Topology Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Demonstrates creating a grid variant, activating it, modifying transformer status, and deactivating variants. ```python # Create Grid Variant variant = pfi.create_grid_variant(name="Variant1", location=variant_folder, update=True) # Switch to this new grid variant (activate it and only it) pfi.switch_grid_variant(variant.loc_name) # Set transformer out of service # Deactivate active scenario if scenario_active is not None: pfi.deactivate_scenario(scenario_active) # As no scenario is active anylonger, changes regarding operation are directly saved in grid variant # Set transformer out of service transformer = pfi.transformer_2w("Transformer_2w_110/20", grid_name=grid_name) transformer.outserv = 1 # Deactivate all grid variants for variant in pfi.grid_variants(only_active=True): pfi.deactivate_grid_variant(variant) ``` -------------------------------- ### Clone the repository Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/README.md Use this command to clone the powerfactory-tools repository from GitHub. ```bash git@github.com:ieeh-tu-dresden/powerfactory-tools.git ``` -------------------------------- ### Configure PowerFactory Interface Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Initializes the PowerFactory interface with required user profile and version settings. Ensure the local Python version matches the PowerFactory API version. ```python %load_ext autoreload %autoreload 2 import datetime as dt import logging import pathlib from powerfactory_tools.str_constants import NAME_SEPARATOR from powerfactory_tools.utils.io import FileType from powerfactory_tools.utils.io import PandasIoHandler from powerfactory_tools.versions.pf2026 import PowerFactoryInterface from powerfactory_tools.versions.pf2026.interface import ValidPythonVersion from powerfactory_tools.versions.pf2026.types import CalculationType from powerfactory_tools.versions.pf2026.types import ModeInpLoad from powerfactory_tools.versions.pf2026.types import PFClassId from powerfactory_tools.versions.pf2026.types import ResultExportMode # PowerFactory configuration PF_SERVICE_PACK = 2 # mandatory PF_USER_PROFILE = "TODO" # mandatory, name of the user profile in the PowerFactory data base PF_INI_NAME = "PowerFactory" # optional specification of ini file name to switch to full version (e.g. PowerFactoryFull for file PowerFactoryFull.ini) PF_PYTHON_VERSION = ValidPythonVersion.VERSION_3_14 # python version of local code environment must match the python version of PowerFactory API # Consider to use raw strings to avoid misinterpretation of special characters, e.g. r"dir\New Project" or r"dir\1-HV-grid". PROJECT_NAME = "PowerFactory-Tools" # may be also full path "dir_name\\project_name" EXPORT_PATH = pathlib.Path("control_action_results") ``` -------------------------------- ### Manage Scenarios and Outages Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Creates a new scenario, activates it, and sets a specific line out of service. ```python logger.info("3_Bus : Create new operating case (scenario) and set 'Line_2_3' out of service ...") scenario = pfi.create_scenario(name="op_case_b") if scenario is not None: pfi.activate_scenario(scenario) # set "Line_2_3" out of service line_2_3 = pfi.line("Line_2_3", grid_name=grid_name) if line_2_3 is not None: line_2_3.outserv = True else: logger.info("3_Bus : Could not found line 'Line_2_3'.") ``` -------------------------------- ### Run Automatic Graph Layout Tool Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__add_loads.ipynb Routine to unfreeze the grid diagram and execute the graphic layout command. ```python def run_layout(pfi: PowerFactoryInterface, /, *, selection: PFTypes.Selection | None = None) -> bool: """This function gets command GRAPHIC_LAYOUT_TOOL, adjusts and executes it.""" logger = logging.getLogger() # Unfreeze grid diagram desktop = pfi.app.GetFromStudyCase(PFClassId.DESKTOP.value) if desktop is not None: desktop = t.cast("PFTypes.Desktop", desktop) desktop.Show() desktop.Unfreeze() else: logger.warning("Desktop set could not be loaded. Thus, graphic keeps frozen and automatic layouting does not work. Quitting ...") return False logger.debug("Start automatic layout applicaton ...") layout_cmd = pfi.app.GetFromStudyCase(CalculationCommand.GRAPHIC_LAYOUT_TOOL.value) layout_cmd = t.cast("PFTypes.CommandSglLayout", layout_cmd) layout_cmd.iAction = 1 layout_cmd.orthoType = 1 layout_cmd.nodeDispersion = 0 layout_cmd.insertionMode = 0 layout_cmd.neighborhoodSize = 3 if selection is not None: layout_cmd.neighborStartElems = selection error = layout_cmd.Execute() if error: logger.warning("Automatic layouting failed.") return False return True ``` -------------------------------- ### Execute Control Routine Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb A comprehensive function demonstrating grid element requests, element selection, and attribute modification within PowerFactory. ```python def run_nine_bus_control_example(pfi: PowerFactoryInterface, export_path: pathlib.Path) -> None: # noqa: PLR0915 """A sophisticated collection of possible control actions. This example is related to the provided project "PF2026_PowerFactory-Tools.pfd" with the 9-Bus grid "HV_9_Bus". Arguments: pfi {PowerFactoryInterface} -- an instance of PowerFactoryInterface export_path {pathlib.Path} -- directory within to export results """ logger = logging.getLogger() # select study case "Outage" to see the different results of element selection in example 2 default_study_case_name = "Base" grid_name = "HV_9_Bus" ############ ## Example 1: Request elements of grid logger.info("Start control example, section I...") # Activate study case "Base" study_case = pfi.switch_study_case(default_study_case_name) # Create new variant to work within (add second if one already exists with same name) variant_folder = pfi.create_folder(name="user_variants", location=pfi.grid_variant_dir, update=True) grid_variant = pfi.create_grid_variant(name="control_example", location=variant_folder, force=True) if grid_variant: pfi.switch_grid_variant(grid_variant.loc_name) # Get grid object with specified name grid = pfi.grid(grid_name) # Get all objects from specific grid data = pfi.compile_powerfactory_data(grid) # All nodes in grid {grid_name}, also these that are out of service terminals_grid = data.terminals ############ ## Example 2: Select special elements logger.info("Start control example, section II...") # All nodes from the project (source may be multiple grids) # --> from all grids (independent if active or not) + all nodes (independent if out of service or not) terminals_project = pfi.terminals() # noqa: F841 # All nodes from the active study case # --> therefore calculation relevant terminals_study_case = pfi.terminals(calc_relevant=True) # noqa: F841 # As within this study case only one grid is active, the following statement leads to the same result: terminals_grid = pfi.terminals(grid_name=grid_name) # noqa: F841 # All active nodes from the active study case # --> therefore exclude nodes which are not in service active_terminals_study_case = pfi.terminals(calc_relevant=True, include_out_of_service=False) # Select only terminals with nominal voltage of xx kV voltage_threshold = 110 terminals_sel = [] # selected terminals for term in active_terminals_study_case: # nominal voltage u_n = term.uknom if u_n == voltage_threshold: terminals_sel.append(term) ############ ## Example 3: Change attribute values logger.info("Start control example, section III...") # Select some loads that names start with "Load", do not consider LV and MV Loads loads = pfi.loads("Load*", grid_name=grid_name) # Change power of loads for load in loads: # for primitive types (int, float, str, bool), value can be assigned directly load.plini = 2 # active power in MW load.mode_inp = ModeInpLoad.PQ.value # type: ignore[assignment] # need to be fixed: for elaborated types, value ought be assigned using the update_value method of the interface # e. g. specify the type of input mask for load power (here, define P and Q) ``` -------------------------------- ### Add loads to a PowerFactory grid Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__add_loads.ipynb Initializes the PowerFactory interface, defines load data for specific terminals, creates a new study case variant, and runs the automatic layout tool. ```python _project_name = PROJECT_NAME.split("\\") full_export_path = pathlib.Path().cwd() / EXPORT_PATH / _project_name[-1] # Configure logging to output to the notebook's standard output logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger() with PowerFactoryInterface( powerfactory_service_pack=PF_SERVICE_PACK, powerfactory_user_profile=PF_USER_PROFILE, powerfactory_ini_name=PF_INI_NAME, python_version=PF_PYTHON_VERSION, project_name=PROJECT_NAME, logging_level=logging.INFO, # log_file_path=full_export_path / pathlib.Path("pf_control.log"), # noqa: ERA001 ) as pfi: logger.info("3_Bus : Run control example 'Add loads' ... ") study_case_name = "3_Bus" grid_name = "HV_3_Bus" # From active study case: get all relevant! terminals logger.info("3_Bus : From active study case: get all terminals ...") study_case = pfi.switch_study_case(study_case_name) grid = pfi.grid(grid_name) origin_data = pfi.compile_powerfactory_data(grid) terminals = origin_data.terminals # Specify load data (connected terminal, load name, further load data) loads_data = [{"name": "NewLoad1", "terminal": terminals[1], "plini": 1, "qlini": 0.5}, {"name": "NewLoad2", "terminal": terminals[2], "plini": 2, "qlini": 1}] loads = routine_create_new_study_case_and_add_loads(pfi, study_case_name="3_Bus NewLoadsAdded", grid_variant_name="NewLoadsAdded", grid=grid, loads_data=loads_data) logger.info("3_Bus : Run Automatic Layout Tool with newly created loads as selection.") # Create selection with all origin grid elements as base for the layout tool selection = pfi.create_sgl_layout_selection(data=terminals) # Run automatic layout tool success = run_layout(pfi, selection=selection) logger.info("3_Bus : Run control example 'Add loads' ... Done") ``` -------------------------------- ### Create Variable Monitors Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Configures variable monitors for terminals using existing or new result objects. ```python logger.info("Start control example, section IV...") ## Adapt default result object # Get existing default result object ("Alle Berechnungsarten" or "All calculations") - may not yet exist when first executed default_result = pfi.result("All*", study_case_name=study_case.loc_name) # Create variable monitor objects for default result if default_result is not None: for term in terminals_sel: # Create variable monitor (unsymmetric case) for each terminal pfi.create_variable_monitor( element=term, result=default_result, variables=element_vars_unsym["node"].keys(), ) # Create variable monitor (symmetric case) for each terminal pfi.create_variable_monitor(element=term, result=default_result, variables=element_vars_sym["node"].keys()) ## Create new result object # Create new result object new_result = pfi.create_result(name="New Results", study_case=study_case) new_result.calTp = CalculationType.ALL_CALCULATIONS.value # type: ignore[assignment] # would be also the default value # Create variable monitor objects for term in terminals_sel: # Create variable monitor (unsymmetric case) for each terminal pfi.create_variable_monitor( element=term, result=new_result, variables=element_vars_unsym["node_reduced"].keys(), ) # Create variable monitor (symmetric case) for each terminal pfi.create_variable_monitor(element=term, result=default_result, variables=element_vars_sym["node"].keys()) ``` -------------------------------- ### Run Time Domain Simulations Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Executes RMS or EMT time-domain simulations with specified properties. ```python logger.info("Start control example, section VI...") sim_length = 3 # in seconds # define additional simulation properties: see selection of attributes of PFType.CommandTimeSimulationStart rms_sim_data = {"dtgrd": 0.005} # step size in seconds rms_result = pfi.run_rms_simulation(sim_length, data=rms_sim_data) # symmetrical by default ``` -------------------------------- ### Retrieve Grid Elements Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Demonstrates various methods to filter and retrieve generators from the active study case. ```python generators2 = pfi.generators(calc_relevant=True, include_out_of_service=False) # noqa: F841 generators3 = pfi.generators(grid_name=grid_name) # noqa: F841 generators4 = pfi.grid_elements( # noqa: F841 class_name=PFClassId.GENERATOR.value, # class name, same as passing the raw string: "ElmGenstat" name="*", # name doesn't matter grid_name=grid_name, # which grid is to be used to search for generators calc_relevant=True, # only get calc relevant generators include_out_of_service=True, # include also out of service generators ) ``` -------------------------------- ### Execute Load Flow Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Runs an AC symmetrical load flow calculation. ```python logger.info("3_Bus : Run load flow and export nodal voltages ...") pfi.run_ldf(ac=True, symmetrical=True) ``` -------------------------------- ### Configure PowerFactory Exporter Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Select the compatible exporter version and define mandatory project configuration parameters such as user profile and Python version. ```python from powerfactory_tools.versions.pf2026 import PowerFactoryExporter from powerfactory_tools.versions.pf2026.interface import ValidPythonVersion from powerfactory_tools.versions.pf2026.types import PFClassId # PowerFactory configuration PF_SERVICE_PACK = 2 # mandatory PF_USER_PROFILE = "tbd" # mandatory, name of the user profile in the PowerFactory data base PF_PYTHON_VERSION = ValidPythonVersion.VERSION_3_14 # python version of local code environment must match the python version of PowerFactory API PF_INI_NAME = "PowerFactory" # optional specification of ini file name to switch to full version (e.g. PowerFactoryFull for file PowerFactoryFull.ini) PF_INI_PATH = None # optional specification of root path to ini file (C:\\My\\Ini_Root_Directory). If not specified, the default PowerFactory path will be used. # Consider to use raw strings to avoid misinterpretation of special characters, e.g. r"dir\New Project" or r"dir\1-HV-grid". PROJECT_NAME = "PowerFactory-Tools" # may be also full path "dir_name\\project_name" STUDY_CASES = ["3_Bus", "Base", "Outage", "Industry_Park"] # list of study cases to be exported EXPORT_PATH = pathlib.Path("export") ``` -------------------------------- ### Load and display exported JSON files Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Loads specific study case JSON files from the export path and prints their contents as formatted strings. ```python _project_name = PROJECT_NAME.split("\\") t = Topology.from_file(EXPORT_PATH / _project_name[-1] / "Industry_Park__HV_9_Bus__topology.json") t_s = t.model_dump() print(json.dumps(t_s, sort_keys=True, default=str, indent=2)) # noqa: T201 ``` ```python _project_name = PROJECT_NAME.split("\\") tc = TopologyCase.from_file(EXPORT_PATH / _project_name[-1] / "Industry_Park__HV_9_Bus__topology_case.json") tc_s = tc.model_dump() print(json.dumps(tc_s, sort_keys=True, default=str, indent=2)) # noqa: T201 ``` ```python _project_name = PROJECT_NAME.split("\\") ssc = SteadystateCase.from_file( EXPORT_PATH / _project_name[-1] / "Industry_Park__HV_9_Bus__steadystate_case.json", ) ssc_s = ssc.model_dump() print(json.dumps(ssc_s, sort_keys=True, default=str, indent=2)) # noqa: T201 ``` -------------------------------- ### Define Variable Monitors Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Dictionaries defining variables to monitor for symmetrical and asymmetrical load flow cases. ```python # symmetrical load flow case element_vars_sym = { "node": { "m:U": "Uabs_PH_E", "m:phiu": "Phase_Voltage", }, } # asymmetrical load flow case element_vars_unsym = { "node": { "m:U1": "Uabs1", "m:U2": "Uabs2", "m:U0": "Uabs0", "m:phiu1": "Uang1", "m:phiu2": "Uang2", "m:phiu0": "Uang0", }, "node_reduced": { "m:U1": "Uabs1", "m:U2": "Uabs2", "m:U0": "Uabs0", }, "line": { "m:I1:bus1": "Iabs1", "m:I2:bus1": "Iabs2", "m:I0:bus1": "Iabs0", "m:phii1:bus1": "Iang1", "m:phii2:bus1": "Iang2", "m:phii0:bus1": "Iang0", }, } ``` -------------------------------- ### Retrieve Study Cases, Scenarios, and Variants Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Retrieves lists of study cases, operation scenarios, and network variants, optionally filtering for active items. ```python # Study Case study_cases = pfi.study_cases() # get all # noqa: F841 study_case_active = pfi.study_case(only_active=True) # get only active one # noqa: F841 # Network Variation variant = pfi.grid_variants() # get all variants_active = pfi.grid_variants(only_active=True) # get only active one(s) # noqa: F841 # Operation Scenarios scenarios = pfi.scenarios() # get all # noqa: F841 scenario_active = pfi.scenario(only_active=True) # get only active one ``` -------------------------------- ### Run Load Flow and Export Results Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Executes a load flow calculation and exports results using different variants, including CSV export and custom JSON data handling. ```python logger.info("Start control example, section V...") # The results would be stored in the related result objects, which are the $default_result and the $new_result ## Run symmetrical AC load flow pfi.run_ldf(ac=True, symmetrical=False) ## Setup result export - variant I # a) Assign variable monitors to a result pfi.write_variable_monitors_for_result(default_result) # b) Create result export command and assign the result objectand execute res_exp_cmd_1 = pfi.create_result_export_command( result=default_result, study_case=study_case, export_path=export_path, export_mode=ResultExportMode.CSV, name="My_Result_Export", file_name="LDF_Results_full", ) if res_exp_cmd_1 is not None: # Use english separators for CSV res_exp_cmd_1.iopt_sep = False res_exp_cmd_1.col_Sep = "," res_exp_cmd_1.dec_Sep = "." # Execute result export - variant I pfi.run_result_export(res_exp_cmd_1) ## Setup result export - variant II # a) Assign variable monitors to a result pfi.write_variable_monitors_for_result(new_result) # b) Create result export command and execute res_exp_cmd_2 = pfi.create_result_export_command( result=new_result, study_case=study_case, export_path=export_path, export_mode=ResultExportMode.CSV, name="My_Result_Export_2", file_name="LDF_Results_selected", ) if res_exp_cmd_2 is not None: # Use english separators for CSV res_exp_cmd_2.iopt_sep = False res_exp_cmd_2.col_Sep = "," res_exp_cmd_2.dec_Sep = "." # Execute result export - variant II pfi.run_result_export(res_exp_cmd_2) ## Export results - Variant III # Do further user specific work and fill result_data dictionary based on PF result data = { f"{terminals_sel[0].loc_name}": { "Uabs1": { "value": terminals_sel[0].GetAttribute("m:U1"), }, }, } # Store results ioh = PandasIoHandler() ioh.export_user_data( data, export_root_path=export_path, file_type=FileType.JSON, file_name=pfi.app.GetActiveStudyCase().loc_name + NAME_SEPARATOR + "custom_user_data", ) ``` -------------------------------- ### Export data using PowerFactoryExporter instance Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Uses the PowerFactoryExporter context manager to export study cases. Note that this blocks the PowerFactory application until the notebook process terminates. ```python with PowerFactoryExporter( project_name=PROJECT_NAME, powerfactory_ini_name=PF_INI_NAME, powerfactory_ini_path=PF_INI_PATH, # only necessary, if you specified a path for your custom ini root directory. If not specified, you can remove this line. powerfactory_service_pack=PF_SERVICE_PACK, powerfactory_user_profile=PF_USER_PROFILE, python_version=PF_PYTHON_VERSION, logging_level=logging.INFO, element_specific_attrs=element_specific_attrs, ) as exporter: _project_name = PROJECT_NAME.split("\\") # Export each study case of the specified project and save it in a separate folder in the specified export path. exporter.export( export_path=EXPORT_PATH / pathlib.Path(_project_name[-1]), study_case_names=STUDY_CASES, plausibility_check=True, ) # As alternative, export just the study case that is active at the moment # exporter.export(export_path=EXPORT_PATH) # noqa: ERA001 ``` -------------------------------- ### Display raw JSON schema of Power System Data Model Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Retrieves and prints the Pydantic JSON schema for the specified data models. ```python t_s = Topology.model_json_schema() print(json.dumps(t_s, sort_keys=True, default=str, indent=2)) # noqa: T201 ``` ```python tc_s = TopologyCase.model_json_schema() print(json.dumps(tc_s, sort_keys=True, default=str, indent=2)) # noqa: T201 ``` ```python ssc_s = SteadystateCase.model_json_schema() print(json.dumps(ssc_s, sort_keys=True, default=str, indent=2)) # noqa: T201 ``` -------------------------------- ### Define 3-Bus Control Routine Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Defines a function to perform control actions on a 3-bus grid, including switching study cases and retrieving grid components. ```python def run_three_bus_control_example(pfi: PowerFactoryInterface, export_path: pathlib.Path) -> None: """A simple collection of possible control actions. This example is related to the provided project "PF2026_PowerFactory-Tools.pfd" with the 3-Bus grid "HV_3_Bus". Arguments: pfi {PowerFactoryInterface} -- an instance of PowerFactoryInterface export_path {pathlib.Path} -- directory within to export results """ logger = logging.getLogger() study_case_name = "3_Bus" grid_name = "HV_3_Bus" study_case = pfi.switch_study_case(study_case_name) # noqa: F841 grid = pfi.grid(grid_name) if grid is None: logger.info(f"3_Bus : Could not found grid '{grid_name}'. Please check the name of the grid and adjust the variable 'grid_name' accordingly.") err_msg = f"Could not found grid '{grid_name}'." raise ValueError(err_msg) ## Example 1): From active study case: get all relevant! terminals, lines, loads and generators logger.info("3_Bus : From active study case: get all terminals, lines, loads and generators ...") terminals = pfi.terminals(calc_relevant=True) lines = pfi.lines(calc_relevant=True) # noqa: F841 loads = pfi.loads(calc_relevant=True) generators = pfi.generators(calc_relevant=True) # noqa: F841 ``` -------------------------------- ### Export Nodal Voltages Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Extracts nodal voltage magnitudes and exports them to a CSV file using PandasIoHandler. ```python data = {} for term in terminals: entry = {f"{term.loc_name}__Uabs1": term.GetAttribute("m:Ul")} data.update(entry) # Store results ioh = PandasIoHandler() ioh.export_user_data( data, export_root_path=export_path, file_type=FileType.CSV, file_name="3_bus_nodal_voltages_case_a", ) ``` -------------------------------- ### Schema Import Function Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_import.ipynb A utility function to import PSDM schema data from a specified file path. It returns the imported data and its JSON string representation. ```python def import_schema(schema_class: Topology | TopologyCase | SteadystateCase, file_path: pathlib.Path) -> tuple[_Base, str]: """Example to import PSDM schema from file.""" data = schema_class.from_file(file_path) json_str1 = json.dumps(data.model_dump(mode="json"), indent=2, sort_keys=True) return data, json_str1 ``` -------------------------------- ### Export data using standalone export function Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Executes the export in a separate process, preventing the PowerFactory application from being blocked after the operation completes. ```python from powerfactory_tools.versions.pf2026 import export_powerfactory_data ext_log_file_path = pathlib.Path(r"export\logfile.txt") _project_name = PROJECT_NAME.split("\\") # As the export function is executed in a process that is terminated after execution, the PowerFactory API is also closed. export_powerfactory_data( project_name=PROJECT_NAME, powerfactory_ini_name=PF_INI_NAME, powerfactory_service_pack=PF_SERVICE_PACK, powerfactory_user_profile=PF_USER_PROFILE, python_version=PF_PYTHON_VERSION, export_path=EXPORT_PATH / pathlib.Path(_project_name[-1]), study_case_names=STUDY_CASES, logging_level=logging.INFO, log_file_path=ext_log_file_path, element_specific_attrs=element_specific_attrs, plausibility_check=True, ) ``` -------------------------------- ### Display PowerFactory GUI in Non-Interactive Mode Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/README.md Opens the PowerFactory application window temporarily during script execution. Ensure the window is closed via user input rather than the GUI close button to avoid errors. ```python pfi.app.Show() time.sleep(5) # wait for 5 seconds input("Press Enter to continue...") # Wait for user input before proceeding pfi.app.Hide() ``` -------------------------------- ### Retrieve Graphic Elements Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Accesses the graphic representation of grid elements and diagrams. ```python # Get graphic element of a random load random_load = loads[0] load_graphic = pfi.graphic_of_element(random_load) if load_graphic is not None and load_graphic.pDataObj == random_load: logger.info(f"3_Bus : Found graphic element '{load_graphic.loc_name}' for load '{random_load.loc_name}'.") # Get grid diagram of actual grid grid_diagram = pfi.diagram_of_grid(grid) if grid_diagram is not None and grid_diagram.pDataFolder == grid: logger.info(f"3_Bus : Found grid diagram '{grid_diagram.loc_name}' for grid '{grid.loc_name}'.") ``` -------------------------------- ### Modify Load Power Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Increases the active and reactive power of all loads by 5%. ```python logger.info("3_Bus : Raise the consumed power of the load by 5 % ...") # Change power of loads for load in loads: load.plini = load.plini * 1.05 # active power in MW load.qlini = load.qlini * 1.05 # reactive power in MW ``` -------------------------------- ### Export PowerFactory Network to PSDM Format Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/docs/joss_paper/paper.md Use the PowerFactoryExporter to export a PowerFactory network to PSDM Python objects or JSON files. Ensure all configuration paths and names are correctly set. ```python import pathlib from powerfactory_tools.versions.pf2025 import PowerFactoryExporter from powerfactory_tools.versions.pf2025.interface import ValidPythonVersion PF_PATH = pathlib.Path("C:/Program Files/DIgSILENT") PF_SERVICE_PACK = 2 # mandatory PF_USER_PROFILE = "TODO" # mandatory, name of the user profile in PF data base PF_PYTHON_VERSION = ValidPythonVersion.VERSION_3_13 # project name may be also full path "dir_name\project_name" # (name is choosen related to example PF project in GitHub repository) PROJECT_NAME = "PowerFactory-Tools" # a valid study case name in the choosen PF project STUDY_CASE_NAME = "Base" # directory, the export results will be saved to EXPORT_PATH = pathlib.Path("export") with PowerFactoryExporter( powerfactory_path=PF_PATH, powerfactory_service_pack=PF_SERVICE_PACK, powerfactory_user_profile=PF_USER_PROFILE, python_version=PF_PYTHON_VERSION, project_name=PROJECT_NAME, ) as exporter: # Option I: Export to PSDM Python objects grids = exporter.pfi.independent_grids(calc_relevant=True) for grid in grids: grid_name = grid.loc_name data = exporter.pfi.compile_powerfactory_data(grid) meta = exporter.create_meta_data(data=data, case_name=STUDY_CASE_NAME) # Create the three PSDM base classes topology = exporter.create_topology(meta=meta, data=data) topology_case = exporter.create_topology_case(meta=meta, data=data, topology=topology) steadystate_case = exporter.create_steadystate_case(meta=meta, data=data, topology=topology) # Now, the PSDM objects can be used by the user ... # Option II: Export to PSDM-formatted JSON files exporter.export( export_path = EXPORT_PATH, study_case_names=[STUDY_CASE_NAME], ) ``` -------------------------------- ### Export RMS Simulation Results Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_control__basic.ipynb Exports RMS simulation results to a CSV file using specified formatting options. ```python # if rms simulation was successful, run result export using builtin function if rms_result: result_export_data = {"iopt_sep": False, "col_Sep": ",", "dec_Sep": "."} # Use english separators for CSV res_exp_cmd = pfi.create_result_export_command( result=rms_result, study_case=study_case, export_path=export_path, export_mode=ResultExportMode.CSV, file_name="RMS_Results", name="RMS_Export", data=result_export_data, ) # Use english separators for CSV pfi.run_result_export(res_exp_cmd) # Run EMT simulation emt_result = pfi.run_emt_simulation(sim_length) # noqa: F841 ``` -------------------------------- ### Define Additional Export Attributes Source: https://github.com/ieeh-tu-dresden/powerfactory-tools/blob/main/examples/powerfactory_export.ipynb Specify extra attributes to export for specific PowerFactory element types using a dictionary mapping class IDs to attribute lists. ```python element_specific_attrs: dict[PFClassId, Sequence[str | dict]] = { PFClassId.LINE: ["nlnum", "fline", "typ_id"], # list of attribute names for elements of type Line PFClassId.GENERATOR: [ "loc_name", {"pQlimType": ["cap_Ppu", "cap_Qmnpu"]}, # list of (nested) attribute names for elements of type Generator ], } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.