The provided environment.yml file can be used to create a new “environment” that includes all the required dependencies for running the custom scripts. Two examples for creating this new environment—named “cympyEnv” here—are provided below: Example directly in Python: python -m venv c:\path\to\environment.yml Example with Anaconda Python: conda env create --name cympyEnv --file=c:\path\to\environment.yml Once the cympyEnv has been created, it must be activated before running any of the custom scripts.
After creating and activating the cympyEnv, the steps below can be used to import the CymPy package:
- Create a text file called “cympy.pth” that contains the path to the parent folder where the CymPy library is located (e.g., “C:\Program Files\CYME\CYME_9_4_rev01”). An example is provided.
- Place “cympy.pth” in the “site-packages” folder of the cympyEnv environment (e.g., “C:\Users...\Anaconda3\envs\cympyEnv\Lib\site-packages”)
- Include “import cympy” at the top of any Python script for which the package will be used.
- Change any file reference to reflect their locations on your system (all folders not provided here should be placed in the main Co-Simulation Folder
- Change the directory in the Anaconda Prompt to the project location
- Run the simulation using the batch file (The file locations inside the batch files must be changed to match your system path)(Batch files can be edited with any text editor)
cd CoSim Directory
run_cosim.bat
This repository runs an hourly transmission and distribution (T&D) co-simulation with HELICS. One federate, distribution/main.py, runs CYME load flows through the cympy API. The other, transmission/transmission_cost.py, drives a PowerWorld Simulator case through SimAuto. Each hour the distribution side publishes the kW of every CYME spot load, and the transmission side publishes bus voltages (kV) for a list of mapped substations. The loop covers hours 1 to 24, and the distribution side writes CYME summary, overload and voltage reports at the end.
flowchart LR
A["run_cosim.bat<br/>sets EVfilepath,<br/>runs helics run --path run.json"]
B["HELICS broker"]
C["CYME study (.xst)<br/>load_data_dummy_data.csv<br/>EV load CSV"]
D["distribution/main.py<br/>CYME load flow each hour"]
E["PowerWorld case (.pwb)<br/>MW and MVAR time series<br/>weather CSV<br/>dummy_list_mapped_system.csv"]
F["transmission/transmission_cost.py<br/>PowerWorld through SimAuto"]
G["Co-Simulation-Results/(date)/<br/>summary, overload,<br/>line loading, voltage CSVs"]
H["Co-Simulation-Results/(date)/Weather_data_added/<br/>load CSVs, generator CSVs,<br/>PowerWorld logs"]
A --> B
B --> D
B --> F
C --> D
E --> F
D -->|"transmission_system_load<br/>spot load kW"| F
F -->|"distribution_system_voltage<br/>bus kV"| D
D --> G
F --> H
What the code does, in order:
run_cosim.batsets theEVfilepathenvironment variable and runshelics run --path run.json. This starts a broker and the two federates from the repository root. Both federates use a ZMQ core (seehelics_utils/).- Each hour,
distribution/main.pyruns a CYME load flow, readsTotalKWfor every spot load, and publishes the list ontransmission_system_load. - Each hour,
transmission/transmission_cost.pyreadsBusKVVoltfor the loads at each substation number indummy_list_mapped_system.csv. It then sets load MW and MVAR from that hour's column of the time-series files, setsGenMWMaxfor the generators listed in the weather file, and publishes the voltages it read ondistribution_system_voltage. - The transmission side passes the received values to
update_power(), which adds each value toLoadMWof one load at the substation in the same list position, writes the load table to CSV and solves the power flow. The script then saves the PowerWorld log and generator data. As committed, theupdate_power()call fails in hour 1 (see Known issues). - The distribution side prints the voltages it receives. The current code does not write them into the CYME model. It also reads the EV load file named by
EVfilepathand prints the hourly EV total, but does not add that total to the CYME loads. - After hour 24,
distribution/main.pywrites its report CSVs once, labelledX24. It does this only if the last voltage string it received contains a comma (a vector of two or more values).
| Folder | What it contains | Main contributor (git history) | Start here |
|---|---|---|---|
distribution/ |
CYME distribution federate, CYME report helpers, a placeholder hourly load table | Diana Wallison | main.py |
helics_utils/ |
Small HELICS value-federate wrapper imported by both federates | Diana Wallison | __init__.py |
transmission/ |
PowerWorld transmission federate, its helper functions, a local copy of the ESA SAW class |
Diana Wallison | transmission_cost.py |
Files in the repository root (all added by Diana Wallison):
| File | What it is |
|---|---|
run_cosim.bat |
Sets EVfilepath, runs helics run --path run.json, then helics kill-all-brokers |
run.json |
HELICS runner configuration: a broker and the two federates |
environment.yml |
Conda environment export named cympyEnv (Python 3.12.7, Windows package builds) |
cympy.pth |
Example path file that points Python at the CYME install folder |
10_simulation_output_combined_remap_D_Loads.csv |
EV load table read through EVfilepath: columns Node Name, X1 to X24, D Sub; 21,997 rows |
dummy_list_mapped_system.csv |
Substation mapping list: columns Area, T Sub, D Sub, ID, Longitude, Latitude, Substation Number, Substation Name; 1,841 rows. The transmission federate uses Substation Number. |
The steps in the sections above still apply. These details were checked against the code.
- Use a Windows PC. The scripts build paths with backslashes, and the PowerWorld link uses Windows COM.
- Install CYME with its Python API (
cympy) for the distribution federate. - Install PowerWorld Simulator with SimAuto for the transmission federate. The code drives it through the
SAWclass intransmission/saw_editing_file.py, which usespywin32. - Create the conda environment from the repository root in an Anaconda Prompt:
conda env create -f environment.yml, thenconda activate cympyEnv.environment.ymlis a conda file (Python 3.12.7). Thepython -m venvexample above does not read it. - Install the packages the code imports that
environment.ymldoes not list:pip install networkx dss-python OpenDSSDirect.py.distribution/power_world_setup.pyalso importsesa, which is not listed either. No script imports that file, soesais needed only if you use it. - Edit
cympy.pthso it holds your CYME folder (the example containsC:\Program Files\CYME\CYME), and copy it into...\envs\cympyEnv\Lib\site-packages.distribution/main.pyanddistribution/cyme_functions.pyalso runimport _db. That module is not in this repository or inenvironment.yml, so it must be importable in the same environment. - Put the model files the scripts expect in place (see Inputs and outputs), or edit the file names in the scripts.
- Edit the hard-coded paths:
EVfilepathinrun_cosim.bat, the distributionexecline inrun.json(see Known issues), andstudyFilenameindistribution/main.pyif your CYME study has another name.
From an Anaconda Prompt with cympyEnv active, start in the repository root:
cd <path to>\T-D_Co-Simulation
run_cosim.bat
run.json launches both federates with "directory": ".", so the scripts run with the repository root as the working directory. Without the batch file:
set EVfilepath=C:\full\path\to\10_simulation_output_combined_remap_D_Loads.csv
helics run --path run.json
helics kill-all-brokers
Settings at the top of the two federate scripts:
| Script | Variable | Value in the repository | Effect |
|---|---|---|---|
distribution/main.py |
system |
"EV" |
"base" does not run as written (see distribution/) |
distribution/main.py |
date |
'May 3' |
Name of the output folder under Co-Simulation-Results |
distribution/main.py |
duration |
25 |
Hours 1 to 24 |
transmission/transmission_cost.py |
date |
'Aug. 6' |
Selects the time-series and weather files and the output folder |
transmission/transmission_cost.py |
weather |
True |
Applies the weather file and puts the OPF and generator outputs under Weather_data_added. The weather file is read and the logs go to Weather_data_added whatever the value. |
transmission/transmission_cost.py |
pw_file |
Texas7k_20221101_WithPFWModels_loadscaledmidnight.pwb |
PowerWorld case, read from transmission/ |
The two scripts set date separately, and the committed values differ.
python distribution\cyme_functions.py (run from the repository root) is a separate CYME test script. It opens the same CYME study and writes two test CSVs into distribution/.
Inputs in the repository:
10_simulation_output_combined_remap_D_Loads.csv: read bydistribution/main.pythroughEVfilepath. Only its hourly total is used, and only for printing.dummy_list_mapped_system.csv: theSubstation Numbercolumn is read bytransmission/transmission_cost.py.distribution/load_data_dummy_data.csv: 16 node IDs with placeholder values for hours 1 to 24, read bydistribution/main.py.
Inputs not in the repository (file names are hard-coded):
distribution/testing_cyme_fullbonnet_file_10_net.xst(CYME study).transmission/Texas7k_20221101_WithPFWModels_loadscaledmidnight.pwb(PowerWorld case).transmission/MWtimeseries_Aug. 6.csvandtransmission/MVARtimeseries_Aug. 6.csv(hourly load columnsX1toX24).transmission/weather/renewable_generation_Aug. 6.csv(columnsDateTime,GenNamepw,MaxMWare used).
Files with the four transmission names are in EV-Research-Simulations (see Related repositories).
Outputs, under Co-Simulation-Results\ in the repository root:
distribution/main.py, once after hour 24, inCo-Simulation-Results\May 3\:Summary\summary_X24.csv,Overload Summary\overload_summary_by_network_X24.csv,Overload Summary\overload_summary_by_source_X24.csv,Overloads\all_overloads_X24.csv,Overloads\line_loading_X24.csv,Voltages\all_voltages_X24.csv. These are written only if the last received voltage string contains a comma. These folders must exist before the run.distribution/main.pyalso writestest.csv(spot load kW and kvar totals, overwritten each hour) to the working directory.helics runsends the printed output of each process todistribution_system.log,transmission_system.logandbroker.login the folder that holdsrun.json(the repository root).transmission/transmission_cost.py, each hour, inCo-Simulation-Results\Aug. 6\Weather_data_added\:OPF\opf_load_data_X<hour>.csv(the load table after the distribution values are added; the folder is named OPF, but the active code solves a power flow),log<hour>.txtandlog_after<hour>.txt(PowerWorld log), andGenerator_data\generator_data_hour_X<hour>.csv. The script creates these folders. As committed, the run stops before these files are written (see Known issues).
run.jsonstarts the distribution federate withpython distribution_system/main.py, but the folder in this repository isdistribution/. Change that line topython distribution/main.py --loglevel=7.run_cosim.batsetsEVfilepathto a path on the author'sD:drive.distribution/main.pystops with aKeyErrorifEVfilepathis not set.environment.ymldoes not includenetworkx(imported bytransmission/saw_editing_file.py), ordss-pythonandOpenDSSDirect.py(imported asdssandopendssdirectbydistribution/main.py). Both federates fail at import without them.transmission_cost.pycallsupdate_power(pw, P, IDs, opf_file)with four arguments, butupdate_power()intransmission/power_world_setup.pytakes nine. The transmission federate stops with aTypeErrorin hour 1, after it receives the first load vector.distribution/main.pydoes not create its output folders. Eachif not <folder>:test checks a non-empty string, soos.makedirsnever runs. Create the folders underCo-Simulation-Results\<date>\first.update_load()indistribution/main.pydoes not apply the hourly values fromload_data_dummy_data.csv(details indistribution/).
- EV-Research-Simulations, folder
Full-Co-Simulation/: same federate layout (distribution_system/,helics_utils/,transmission/,run.json).transmission/saw_editing_file.pyhere is identical toFull-Co-Simulation/transmission/updated_esa_functions.pythere.distribution/power_world_setup.pyis identical toFull-Co-Simulation/distribution_system/power_world_setup.py.helics_utils/__init__.pydiffers by one commented-out line.transmission/transmission_cost.pyandtransmission/power_world_setup.pyare edited versions; for example, both importSAWfromsaw_editing_fileinstead ofesa. That folder also holds the PowerWorld case, MW and MVAR time-series files and weather files named intransmission_cost.py. - ESA (the
esapackage on PyPI):transmission/saw_editing_file.pycontains ESA'sSAWclass, and its docstrings link to that repository. It matchesesa/saw.pyin the esa 1.3.5 wheel on PyPI except that the module docstring and the import of ESA'sinitialize_boundandcalculate_boundhelpers are removed.
From the git history (the 2026-09 commit that added these README sections is not counted):
- Diana Wallison: 29 commits
- Jonathan Snodgrass: 1 commit (initial commit)
- First commit 2025-09-03; last commit before this README update 2025-12-17.
distribution/main.pyanddistribution/cyme_functions.pywere changed through 2025-12-17 and hold the most recent work.transmission/was last changed on 2025-10-07 andhelics_utils/on 2025-10-06.run.jsondates from 2025-10-06,run_cosim.batfrom 2025-10-07, andenvironment.ymlandcympy.pthfrom 2025-10-20.