Some enhancements on compatibility with PSS/E and MATPOWER
Is your feature request related to a problem? Please describe. Interoperation with PSS/E and MATPOWER.
Describe the solution you'd like Functions to export PSS/E dict to DYR file.
- [x] A function to write MATPOEWR mpc to M file.
- [x] A function to write Power Flow data to RAW file.
- [ ] A function to write PSSE dict to DYR file.
- [ ] A function to replace unsupported models with supported ones
Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.
Additional context
Two example code snippets for reference:
def write_dict_dyr(dyr_dict: Dict[str, pd.DataFrame], outfile: str):
"""
Write a dictionary of dynamic models to a DYR file.
This function takes a dictionary where the keys are model names (e.g., 'REGCA1', 'REECA1')
and the values are pandas DataFrames containing the model parameters. It writes the data
to a DYR file in the correct format, ensuring the following:
- The first column (IBUS) is an integer representing the bus index.
- The second column is the model name, enclosed in single quotes.
- The third column (ID) is an integer representing the device index.
- Remaining columns are the model parameters, written as space-separated values.
- Each line ends with a trailing slash ('/').
Models 'Toggle' are skipped during the writing process.
Parameters:
-----------
dyr_dict : Dict[str, pd.DataFrame]
A dictionary where each key is a model name and each value is a pandas DataFrame
containing the parameters for that model. The DataFrame must have the following structure:
- Column 0: IBUS (integer)
- Column 1: ID (integer)
- Columns 2+: Model parameters (various types).
outfile : str
The path to the output DYR file where the formatted data will be written.
Returns:
--------
None
The function writes the data to the specified file and prints a success message.
Notes:
------
- The function skips models with the name 'Toggle' and prints a message for each skipped model.
- A blank line is not added between models in the output file.
- Ensure the input DataFrames are properly formatted to avoid runtime errors.
Example:
--------
>>> dyr_dict = {
... 'REGCA1': pd.DataFrame([
... [1004, 1, 1.0, 0.01, 10, 0.9, 0.5],
... [1006, 1, 1.0, 0.02, 10, 0.9, 0.5]
... ]),
... 'REECA1': pd.DataFrame([
... [1004, 1, 0, 0, 1, 1, 1],
... [1006, 1, 0, 0, 1, 1, 1]
... ])
... }
>>> write_dict_dyr(dyr_dict, './output.dyr')
Data successfully written to ./output.dyr
"""
with open(outfile, 'w') as f:
for model_name, df in dyr_dict.items():
if model_name in ['Toggle']:
print(f"Skipped {model_name}")
continue
for _, row in df.iterrows():
ibus = int(row.iloc[0]) # format IBUS as integer
model = f"'{model_name}'" # model name
device_id = int(row.iloc[1]) # format ID as integer
# format the rest parameters
params = ' '.join(map(str, row.iloc[2:].values))
# Combine all parts into a formatted line
formatted_line = f"{ibus} {model} {device_id} {params} /"
# Write the formatted line to the file
f.write(formatted_line + '\n')
print(f"Data successfully written to {outfile}")
Replace PSS2A with ST2CUT
# PSS2A -> ST2CUT, there are 22 columns in ST2CUT
ST2CUT = pd.DataFrame()
ST2CUT[0] = dyr['PSS2A'][0] # IBUS
ST2CUT[1] = dyr['PSS2A'][1] # ID
ST2CUT[2] = dyr['PSS2A'][2] # M, IC1 <- M, ICS1
ST2CUT[3] = dyr['PSS2A'][3] # M+1, IB1 <- M+1, REMBUS1
ST2CUT[4] = dyr['PSS2A'][4] # M+2, IB2 <- M+2, ICS2
ST2CUT[5] = dyr['PSS2A'][5] # M+3, IB3 <- M+3, REMBUS2
ST2CUT[6] = 1 # J, K1 <- 1
# J+1, K2 <- J+6, Ks2 * J+7, Ks3
ST2CUT[7] = dyr['PSS2A'][14] * dyr['PSS2A'][15]
ST2CUT[8] = dyr['PSS2A'][10] # J+2, T1 <- J+2, T6
ST2CUT[9] = dyr['PSS2A'][13] # J+3, T2 <- J+5, T7
ST2CUT[10] = sa.ST2CUT.T3.default # J+4, T3 <- default
ST2CUT[11] = sa.ST2CUT.T4.default # J+5, T4 <- default
ST2CUT[12] = dyr['PSS2A'][19] # J+6, T5 <- J+11, T1
ST2CUT[13] = dyr['PSS2A'][20] # J+7, T6 <- J+12, T2
ST2CUT[14] = dyr['PSS2A'][21] # J+8, T7 <- J+13, T3
ST2CUT[15] = dyr['PSS2A'][22] # J+9, T8 <- J+14, T4
ST2CUT[16] = sa.ST2CUT.T9.default # J+10, T9 <- default
ST2CUT[17] = ST2CUT[16] # J+11, T10 <- copy of T9
ST2CUT[18] = dyr['PSS2A'][23] # J+12, LSMAX <- J+15, VSTMAX
ST2CUT[19] = dyr['PSS2A'][24] # J+13, LSMIN <- J+16, VSTMIN
ST2CUT[20] = sa.ST2CUT.VCU.default # J+14, VCU <- default
ST2CUT[21] = sa.ST2CUT.VCL.default # J+15, VCL <- default
A quick fix was applied to ams.io.matpower to resolve a bug where multiple PQ loads connected to the same bus were incorrectly converted, resulting in different load values in MATPOWER.
https://github.com/CURENT/ams/blob/2166f4368af3d382720af38408153a70502eb9f5/ams/io/matpower.py#L520-L533
PSS/E v33 RAW file writer and MATPOWER M-file writer are developed in ams v1.0.10, https://ltb.readthedocs.io/projects/ams/en/latest/release-notes.html#v1-0-10-2025-05-23
Please note that the PSSE RAW file writer has not undergone thorough testing.