Tutorial#

Requirements#

Applications#

The PSCAD Automation Library requires that the following tools are installed:

  • PSCAD (such as PSCAD 5.0)

  • Python 3.x (such as Python 3.12.4)

    • PIP - Python’s package manager (included with Python 3.7 and later)

    • PyWin32 - Python extensions for Microsoft Windows

Installation of the above programs is beyond the scope of this tutorial.

Automation Library#

You can check which version of the PSCAD Automation Library is installed by executing:

py -m mhi.pscad

If multiple versions of Python have been installed, each installation could have its own copy of the Automation Library, so you may need to specify the Python version being queried:

py -3.7 -m mhi.pscad

PSCAD’s “Update Client” will automatically install the Automation Library into the latest Python 3.x installation. If you wish to add the Automation Library to a different Python 3.x installation, you could execute a PIP install command similar to the following from the C:\Users\Public\Documents\Manitoba Hydro International\Python\Packages directory:

py -3.7 -m pip install mhi_pscad-3.0.8-py3-none-any.whl

If the the Python Package Index (https://pypi.org/) is not blocked by firewall rules, the latest version of the Automation Library may be installed with:

py -m pip install --upgrade mhi.pscad

Note

Beginning with PSCAD 5.1, the “Update Python Library” on the “Tools” ribbon may be used to install or update the Automation Library.

My First Automation Script#

Running the Tutorial#

The following script is the “simplest” PSCAD automation script that does something useful. It:

  • launches PSCAD,

  • loads the “Tutorial” workspace,

  • runs all simulation sets in the “Tutorial” workspace, and

  • quits PSCAD.

To keep this first example simple, no error checking of any kind is done. Also, no feedback from the simulation is retrieved for the same reason.

#!/usr/bin/env python3
import mhi.pscad

# Launch PSCAD
pscad = mhi.pscad.launch()

# Load the tutorial workspace
pscad.load(r"C:\Users\Public\Documents\PSCAD\5.1.0\Examples\tutorial\Tutorial.pswx", folder=pscad.examples_folder)

# Run all the simulation sets in the workspace
pscad.run_all_simulation_sets()

# Exit PSCAD
pscad.quit()

Many assumptions are being made here.

  1. PSCAD 5.0 or later is installed.

  2. Certificate licensing is used, and a license certificate can be automatically acquired.

    Ensure “Retain certificate” is selected under “Certificate Licensing ➭ Termination Behaviour” and ensure you hold a valid certificate when you exit PSCAD before running the above script.

  3. The “Public Documents” directory is located at C:\\Users\\Public\\Documents.

  4. PSCAD 5.1.0 Examples are installed.

If the last two assumptions are not correct, the script will fail. Don’t worry; this will be corrected in the next step.

Finding the Tutorial#

We can relax the last restriction by retrieving the location of “Examples” directory from PSCAD, and retrieving the “Tutorial” workspace relative to that. Doing so will allow the scripts in this tutorial to be downloaded and executed without modification by the reader.

First, add import os above the other imports so we can use the os.path.join() function. Then, before the pscad.load() statement, retrieve the examples_folder from PSCAD, and then append tutorial to that folder to get the tutorial folder path. Finally, change the pscad.load() statement to load "Tutorial.pscx", but with a folder=tutorial_folder option:

# Locate the tutorial directory
tutorial_dir = os.path.join(pscad.examples_folder, "tutorial")

# Load the tutorial workspace
pscad.load("Tutorial.pswx", folder=tutorial_dir)

See the resulting script.

Logging#

Add import logging to the list of script’s imports, and add the logging.basicConfig statement below:

logging.basicConfig(level=logging.INFO,
                    format="%(levelname)-8s %(name)-26s %(message)s")

If you now run the script, you should see something similar to following output. The paths, port numbers, and process ID’s may be different:

INFO     mhi.pscad                  Automation server port: 54879
INFO     mhi.common.process         Launching C:\Program Files (x86)\PSCAD\5.1.0\bin\win64\PSCAD.exe
INFO     mhi.common.process             Args: ['/startup:au', '/port:54879', '/splash:false', '/silence:true']
INFO     mhi.pscad                  Connecting to [None]:2099
INFO     mhi.pscad.pscad            Loading ['C:\\Users\\Public\\Documents\\Pscad\\5.1.0\\Examples\\tutorial\\Tutorial.pswx']
INFO     mhi.pscad.pscad            Run all simulation sets

In the next steps, we’ll be adding additional logging to our script. The logging already built into the Automation Library can be squelched to warnings and above, so it is easier to see our own log messages. After the logging.basicConfig( ) line, add the following:

# Ignore INFO msgs from automation (eg, mhi.pscad, mhi.common, ...)
logging.getLogger('mhi').setLevel(logging.WARNING)

LOG = logging.getLogger('main')

Next, add logging lines to print out the location of the “tutorial” directory:

LOG.info("Tutorial directory: %s", tutorial_dir)

If you now run the script, you should see something similar to following output. Again, the path may be different, which is of course the whole point of this exercise:

INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial

Error Handling#

If the Automation Library cannot launch PSCAD, it will log the reason why to the console and return the value None. Other problems may be signalled by an “Exception” being raised. A well behaved script must catch these exceptions, and properly clean up. This cleanup should include closing PSCAD.

Replace the commands following the launch of PSCAD with the following, to create a more fault-tolerant script:

if pscad:

    # Locate the tutorial directory
    tutorial_dir = os.path.join(pscad.examples_folder, "tutorial")
    LOG.info("Tutorial directory: %s", tutorial_dir)

    try:
        # Load the tutorial workspace
        pscad.load("Tutorial.pswx", folder=tutorial_dir)

        # Run all the simulation sets in the workspace
        pscad.run_all_simulation_sets()

    finally:
        # Exit PSCAD
        pscad.quit()

else:
    LOG.error("Failed to launch PSCAD")

Whether or not an exception occurs during the loading of the workspace or running all simulation sets, due to the try: ... finally: ... block, PSCAD will always be terminated before the script terminates.

Launch Options#

Minimize PSCAD#

When PSCAD is started, it normally opens the PSCAD window. During automation, it is sometimes desirable to launch PSCAD with its window “minimized”, reducing the amount “screen flickering”, as well as the chance a stray mouse click could “poison” a running automation.

Add minimized=True to the launch() call:

# Launch PSCAD
pscad = mhi.pscad.launch(minimize=True)

Run this new script. You should still see log messages in the Python Shell, and PSCAD appear in the Task Bar, but no PSCAD window should open.

PSCAD Version#

The launch() method does a bit of work behind the scenes. If more than one version of PSCAD is installed, it tries to pick the best version to run. “Best” in this context means:

  • not a “Beta” version

  • not a 4.x version

  • not a 32-bit version, if other choices exist

  • the “lexically largest” version of the choices that remain.

Instead of letting launch() choose the version, the script can specify the exact version to use with the version=... and/or x64=... parameters. For example, to launch the 64-bit version of PSCAD 5.1.0, use:

pscad = mhi.pscad.launch(version='5.1.0', x64=True)

The Automation Library may be queried to determine which versions of PSCAD are installed, using mhi.pscad.versions(). Replacing the launch() statement with the following will mimic its selection process:

versions = mhi.pscad.versions()
LOG.info("PSCAD Versions: %s", versions)

# Skip any 'Beta' versions
versions = [(ver, x64) for ver, x64 in versions if "Beta" not in ver]

# Skip versions prior to '5.0'
versions = [(ver, x64) for ver, x64 in versions if not ver.startswith("4.")]

# Skip any 32-bit versions, if other choices exist
vers = [(ver, x64) for ver, x64 in versions if x64]
if len(vers) > 0:
    versions = vers

LOG.info("   After filtering: %s", versions)

# Of any remaining versions, choose the "lexically largest" one.
version, x64 = sorted(versions)[-1]
LOG.info("   Selected PSCAD version: %s %d-bit", version, 64 if x64 else 32)

# Launch PSCAD
pscad = mhi.pscad.launch(minimize=True, version=version, x64=x64)

With the above changes to the script, the output may be:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial

User Profile#

To ensure reliable, repeatable tests, the Automation Library may instruct PSCAD to launch using “default settings”, ignoring any settings stored in the user profile:

pscad = mhi.pscad.launch(load_user_profile=False)

Regardless of whether or not default settings are used, the pscad.settings() method may be used to change any application settings to the desired value, as demonstrated in the next section.

PSCAD Settings#

Fortran Version#

Not every Fortran compiler is compatible with every version of PSCAD. As PSCAD evolves, support for some compilers is can be added, and support of other compilers may be dropped.

Instead of consulting the ProductsList.xml file, to determine which compilers are installed, and then trying to determine which are supported in some version of PSCAD, it is best to directly ask a running instance of PSCAD what Fortran compilers it supports.

After the if pscad: line, where it is known PSCAD has been successfully launched, add the following:

    # Create a dictionary of new settings to apply
    new_settings = {}

    # Get Fortran compiler versions
    fortrans = pscad.setting_range('fortran_version')
    LOG.info("Fortran versions: %s", fortrans)

Once we have the list of supported Fortran compilers, we can choose the desired one according to some metric:

    # Skip 'GFortran' compilers, if other choices exist
    vers = [ver for ver in fortrans if 'GFortran' not in ver]
    if len(vers) > 0:
        fortrans = vers

    LOG.info("   After filtering: %s", fortrans)

    # Order the remaining compilers, choose the last one (highest revision)
    fortran = sorted(fortrans)[-1]
    new_settings['fortran_version'] = fortran
    LOG.info("   Selected Fortran version: %r", fortran)

Starting at PSCAD 5.1, if an Intel compiler is selected, we must also choose the version of Visual Studios to use as a linker (c_version) if more than one option exists. (When only one linker option exists, such as with the GFortran compilers, no selection is required.)

    if pscad.version_number >= (5, 1) and 'Intel' in fortran:
        # In PSCAD 5.1+ w/ Intel Fortran compiler, a Visual Studios linker
        # selection required.
        linkers = pscad.setting_range('c_version')
        LOG.info("Linker versions: %s", linkers)
        linkers = {ver for ver in linkers if ver.startswith('VS')}
        LOG.info("   After filtering: %s", linkers)
        linker = sorted(linkers)[0]
        new_settings['c_version'] = linker
        LOG.info("   Selected Linker version: %r", linker)

    pscad.settings(**new_settings)

With the above changes to the script, the output may be:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2022 Professional', 'VS 2019 Professional', 'VS 2017 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial

Matlab Version#

In a similar fashion, the PSCAD may be queried for which versions of Matlab are installed and supported. Unlike Fortran, Matlab is not required for PSCAD to run, so there may be no versions of Matlab installed.

Before the code to apply the new settings, add the following:

    # Get all installed Matlab versions
    matlabs = pscad.setting_range('matlab_version')
    LOG.info("Matlab versions: %s", matlabs)

    # Get the highest installed version of Matlab:
    matlab = sorted(matlabs)[-1] if matlabs else ''
    new_settings['matlab_version'] = matlab
    LOG.info("   Selected Matlab version: %r", matlab)

With the above changes to the script, the output may be:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2019 Professional', 'VS 2022 Professional', 'VS 2017 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial

All Settings#

The following script may be used to determine what settings exist, and their current values:

#!/usr/bin/env python3
import mhi.pscad

pscad = mhi.pscad.launch(minimize=True)

for key, value in sorted(pscad.settings().items()):
    print(f"{key:>33}: {value!r}")

pscad.quit()

And produces output similar to:

                    EMTDC_Version: ''
            LCP_MaxConcurrentExec: '8'
                      LCP_Version: ''
                      LanguageDir: '$(HomeDir)\\Languages\\en-us'
                    MEDIC_Version: ''
                  MenuTooltipFile: '$(LanguageDir)\\Tooltips\\MenuTooltips.xml'
                   SocketPortBase: 30000
                  active_graphics: '2_S_'
                adv_changed_color: 'red'
               adv_excluded_color: 'blue'
              adv_highlight_color: '#ffff7538'
               adv_included_color: 'lime'
               automation_ip_addr: 'localhost'
                  automation_port: 0
                autosave_interval: 'NO_ACTION'
                    backup_enable: True
                    backup_folder: '$(LocalDir)\\FileBackups'
                      backup_freq: 60
⋮               ⋮               ⋮               ⋮

To change settings from their defaults, pass one or more key=value arguments to the pscad.settings() method:

pscad.settings(MaxConcurrentSim=8, LCP_MaxConcurrentExec=8)

Some settings only allow values from a highly restricted set. For example, in PSCAD’s Application Options, in the “Enviroment” category, there is a “Modification Tracking” section with an “Auto-save interval” option. At the time of this writing, there are 4 choices for that option. This is also known as the autosave_interval setting. From Python, to get the set of valid values for that setting, the pscad.setting_range(param_name) method is useful:

>>> pscad.setting_range('autosave_interval')
{'15_MINUTES', '1_HOUR', 'NO_ACTION', '5_MINUTES'}

Note

All settings are automatically converted to strings before passing to PSCAD. There is no functional difference between pscad.settings(MaxConcurrentSim=8) and pscad.settings(MaxConcurrentSim="8").

Internally, PSCAD stores and returns all settings as strings. The PSCAD Automation Library will attempt a ‘best effort’ conversion of the strings back to the appropriate type. Unfortunately, the PSCAD Automation Library does not have complete knowledge of all PSCAD setting types and their ranges. In the event of an new and unknown parameter type, the PSCAD Automation Library will simply return the value as a string. If a numeric setting is expected, the Python script is responsible for converting the string into a numeric type. Booleans may be returned as "true" or "false", without the first letter capitalized; again the Python script must accept responsibility for converting the strings into Python boolean values True and False if required.

Projects#

To run all loaded projects one at a time, we first obtain a list of all projects. From this list, we filter out any libraries, which are not runnable. Then, for the remaining Project cases, we call the Project.run() method on each one, in succession.

Replace the pscad.run_all_simulation_sets() line with the following:

        # For each tutorial case ...
        for project in pscad.cases():
            LOG.info("Running '%s' (%s)",
                     project.name,
                     project.parameters()['description'])
            project.run();
            LOG.info("Run '%s' complete", project.name)

This script would produce:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2019 Professional', 'VS 2022 Professional', 'VS 2017 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       Running 'chatter' (Simple case with chatter elimination)
INFO     main                       Run 'chatter' complete
INFO     main                       Running 'fft' (Harmonic Impedance and FFT)
INFO     main                       Run 'fft' complete
INFO     main                       Running 'inputctrl' (Input Control Components)
INFO     main                       Run 'inputctrl' complete
INFO     main                       Running 'interpolation' (Simple case illustrating interpolation)
INFO     main                       Run 'interpolation' complete
INFO     main                       Running 'legend' (Use of macros)
INFO     main                       Run 'legend' complete
INFO     main                       Running 'vdiv' (Single Phase Voltage Divider)
INFO     main                       Run 'vdiv' complete
INFO     main                       Running 'simpleac' (A Simple AC Power System)
INFO     main                       Run 'simpleac' complete
INFO     main                       Running 'multirun' (A Simple Multiple Run Example)
INFO     main                       Run 'multirun' complete
INFO     main                       Running 'pagearray' (Page Inside a Page, Arrays)
INFO     main                       Run 'pagearray' complete

Simulation Sets#

When a workspace contains multiple projects, they may be required to run together or in a particular sequence. A simulation set is often used to control the collection of projects.

Instead of blindly running all projects in the workspace, or simply all simulation sets, we may retrieve the list of simulations sets and run each simulation set individually, under the control of our script. If no simulation sets are found, we can fall back to running each project separately.

Replace the code we just added, with this code instead:

        # Get the list of simulation sets
        sim_sets = pscad.simulation_sets()
        if len(sim_sets) > 0:
            LOG.info("Simulation sets: %s", sim_sets)

            # For each simulation set ...
            for sim_set_name in sim_sets:
                # ... run it
                LOG.info("Running simulation set '%s'", sim_set_name)
                sim_set = pscad.simulation_set(sim_set_name)
                sim_set.run()
                LOG.info("Simulation set '%s' complete", sim_set_name)
        else:
            # For each tutorial case ...
            for project in pscad.cases():
                LOG.info("Running '%s' (%s)",
                         project.name,
                         project.parameters()['description'])
                project.run();
                LOG.info("Run '%s' complete", project.name)

This version of the script runs all projects simultaneously, producing the following output:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2022 Professional', 'VS 2017 Professional', 'VS 2019 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       Simulation sets: ['default']
INFO     main                       Running simulation set 'default'
INFO     main                       Simulation set 'default' complete

If, instead of loading "Tutorial.pswx", we only loaded the "vdiv.pscx" project:

        # Load only the 'voltage divider' project
        pscad.load("vdiv.pscx", folder=tutorial_dir)

there are no simulation sets, so the else: path is taken in our script, and the vdiv project is run:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2019 Professional', 'VS 2017 Professional', 'VS 2022 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       Running 'vdiv' (Single Phase Voltage Divider)
INFO     main                       Run 'vdiv' complete

Event Monitoring#

Event Handlers#

The Automation Library will allow you to observe the communications between the Automation Library and the PSCAD process.

At the top of the file, add the following “Handler” class:

class Handler:

    def send(self, evt):
        if evt:
            LOG.info("%s", evt)
        else:
            LOG.info("TICK")

    def close(self):
        pass

Following the successful launch of PSCAD, we can create an instance of our Handler class, and attach it to the PSCAD instance. After the if pscad:, add the following three lines:

if pscad:

    handler = Handler()
    pscad.subscribe('load-events', handler)
    pscad.subscribe('build-events', handler)

After downgrading some of the earlier LOG.info(...) messages to LOG.debug(...) message, if we run this script, we might see:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2022 Professional', 'VS 2019 Professional', 'VS 2017 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       {'event': 'LoadEvent', 'status': 'BEGIN', 'file-type': 'files'}
INFO     main                       {'event': 'LoadEvent', 'status': 'BEGIN', 'file-type': 'project', 'file': 'C:\\Users\\Public\\Documents\\Pscad\\5.1.0\\Examples\\tutorial\\vdiv.pscx'}
INFO     main                       {'event': 'LoadEvent', 'status': 'END', 'file-type': 'project', 'file': 'C:\\Users\\Public\\Documents\\Pscad\\5.1.0\\Examples\\tutorial\\vdiv.pscx', 'name': 'vdiv', 'type': 'Case', 'Description': 'Single Phase Voltage Divider'}
INFO     main                       {'event': 'LoadEvent', 'status': 'END', 'file-type': 'files'}
INFO     main                       Running 'vdiv' (Single Phase Voltage Divider)
INFO     main                       {'event': 'BuildEvent', 'name': 'Workspace', 'status': 'BEGIN'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Builder', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Compile', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Compile', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Solver', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Solver', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC MAKE', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC MAKE', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Builder', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Mediator', 'status': 'BEGIN', 'project': 'vdiv', 'rank': 1}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC RUN', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Mediator', 'status': 'END', 'project': 'vdiv', 'rank': 1}
INFO     main                       {'event': 'BuildEvent', 'name': 'Workspace', 'status': 'END'}
INFO     main                       Run 'vdiv' complete

As messages are received from PSCAD, the Automation Library sends the message to each registered handler, by calling handler.send(msg). The handler can do pretty much whatever it wants with the message. If it consumes the message, and doesn’t want any subsequent handler from seeing it, the handler should return True.

After a period of time when no messages have been sent back from PSCAD, the Automation Library also sends a blank message to the handler, by calling handler.send(None). This allows the handler a chance to do additional processing. For instance, the Automated Test Suite’s ProgressHandler uses those opportunities to send a get-run-status command to the various projects, in order to track % complete.

Removing Handlers#

If the script decides a certain handler is no longer required, the script can remove it by calling pscad.unsubscribe( eventname ).

    finally:
        # Exit PSCAD
        pscad.unsubscribe('build-events')
        pscad.unsubscribe('load-events')
        pscad.quit()

Automatic Removal#

Since the handler is receiving messages from PSCAD, it is usually in the best position to determine when a particular process is complete. The handler can indicate this to the Automation Library, by returning the special value StopIteration, or by raising the StopIteration exception. When this happens, the Automation Library will automatically remove the handler.

For example, the Load process is complete when a load event is found with a file-type of files and a status of END. Change the Handler’s send() method to the following code:

    def send(self, evt):
        if evt:
            LOG.info("%s", evt)
            if evt['status'] == 'END' and evt.get('file-type', None) == 'files':
                raise StopIteration

        else:
            LOG.info("TICK")

When this new script is run, this output results:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2022 Professional', 'VS 2019 Professional', 'VS 2017 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       {'event': 'LoadEvent', 'status': 'BEGIN', 'file-type': 'files'}
INFO     main                       {'event': 'LoadEvent', 'status': 'BEGIN', 'file-type': 'project', 'file': 'C:\\Users\\Public\\Documents\\Pscad\\5.1.0\\Examples\\tutorial\\vdiv.pscx'}
INFO     main                       {'event': 'LoadEvent', 'status': 'END', 'file-type': 'project', 'file': 'C:\\Users\\Public\\Documents\\Pscad\\5.1.0\\Examples\\tutorial\\vdiv.pscx', 'name': 'vdiv', 'type': 'Case', 'Description': 'Single Phase Voltage Divider'}
INFO     main                       {'event': 'LoadEvent', 'status': 'END', 'file-type': 'files'}
INFO     main                       Running 'vdiv' (Single Phase Voltage Divider)
INFO     main                       {'event': 'BuildEvent', 'name': 'Workspace', 'status': 'BEGIN'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Builder', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Compile', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Compile', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Solver', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Solver', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC MAKE', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC MAKE', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Project Builder', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Mediator', 'status': 'BEGIN', 'project': 'vdiv', 'rank': 1}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC RUN', 'status': 'BEGIN', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Mediator', 'status': 'END', 'project': 'vdiv', 'rank': 1}
INFO     main                       {'event': 'BuildEvent', 'name': 'EMTDC RUN', 'status': 'END', 'project': 'vdiv'}
INFO     main                       {'event': 'BuildEvent', 'name': 'Workspace', 'status': 'END'}
INFO     main                       Run 'vdiv' complete
WARNING  mhi.pscad.pscad            Not currently subscribed to load-events events

The “Not currently subscribed to load-events events” message is generated because we are still trying to unsubscribe to “load-events”, but the handler uninstalled itself.

Build Events#

Build Events are generated when PSCAD builds and runs cases. A build event handler might be installed just before executing the run command, and removed just after the run command finished. Code to do thing might look like this:

handler = BuildEventHandler()
pscad.subscribe("build-events", handler)
project.run()
pscad.unsubscribe("build-events")

This is a lot of boiler-plate code. As a convenience, the Automation Library will perform the subscribe and unsubscribe calls itself, if the handler is passed to the run( ) command directly:

project.run( BuildEventHandler() )

Add an import for mhi.pscad.handler:

import logging
import os
import mhi.pscad
import mhi.pscad.handler

Replace the Handler code from the previous section with the following:

class BuildEventHandler(mhi.pscad.handler.BuildEvent):

    def _build_event(self, phase, status, project, elapsed, **kwargs):

        LOG.info("BuildEvt: [%s] %s/%s %.3f", project, phase, status, elapsed)

Here, we are extending a standard BuildEvent handler. Its send() method already looks for build event messages, and forwards them to the _build_event() method, as well as looks for matching BEGIN and END messages, and returns StopIteration when the final END message is found. This standard BuildEvent handler in turn extends an AbstractHandler, which implements the required do-nothing close() method. As such, most of the required work has already been done for us. We just need to override _build_event().

Remove the previous pscad.subscribe( ) call, and replace the project.run() call with:

                project.run(BuildEventHandler());

When this script is run, the following output is produced:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2019 Professional', 'VS 2022 Professional', 'VS 2017 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       Running 'vdiv' (Single Phase Voltage Divider)
INFO     main                       BuildEvt: [None] Workspace/BEGIN 0.187
INFO     main                       BuildEvt: [vdiv] Project Builder/BEGIN 0.352
INFO     main                       BuildEvt: [vdiv] Project Compile/BEGIN 0.354
INFO     main                       BuildEvt: [vdiv] Project Compile/END 0.892
INFO     main                       BuildEvt: [vdiv] Project Solver/BEGIN 1.144
INFO     main                       BuildEvt: [vdiv] Project Solver/END 1.185
INFO     main                       BuildEvt: [vdiv] EMTDC MAKE/BEGIN 1.812
INFO     main                       BuildEvt: [vdiv] EMTDC MAKE/END 4.444
INFO     main                       BuildEvt: [vdiv] Project Builder/END 4.576
INFO     main                       BuildEvt: [vdiv] Mediator/BEGIN 4.820
INFO     main                       BuildEvt: [vdiv] EMTDC RUN/BEGIN 4.832
INFO     main                       BuildEvt: [vdiv] Mediator/END 5.280
INFO     main                       BuildEvt: [vdiv] EMTDC RUN/END 8.577
INFO     main                       BuildEvt: [None] Workspace/END 5.281
INFO     main                       Run 'vdiv' complete

Our handler is just displaying the events as they occur. It could do more interesting things. For instance, when it receives a BEGIN message, it could record the elapsed time; when it receives a matching END message, it could subtract the elapsed time from the time it recorded earlier, giving the time required for each task:

class BuildEventHandler(mhi.pscad.handler.BuildEvent):

    def __init__(self):
        super().__init__()
        self._start = {}

    def _build_event(self, phase, status, project, elapsed, **kwargs):

        key = (project, phase)
        if status == 'BEGIN':
            self._start[key] = elapsed
        else:
            sec = elapsed - self._start[key]
            name = project if project else '[All]'
            LOG.info("%s %s: %.3f sec", name, phase, sec)

Running this revised script script would produce:

INFO     main                       PSCAD Versions: [('4.6.3', True), ('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1 (Beta)', True), ('5.1.0', True), ('5.2 (Beta)', True)]
INFO     main                          After filtering: [('5.0.0', True), ('5.0.1', True), ('5.0.2', True), ('5.1', True), ('5.1.0', True)]
INFO     main                          Selected PSCAD version: 5.1.0 64-bit
INFO     main                       Launching: 5.1.0
INFO     main                       Fortran versions: ['GFortran 13.2', 'GFortran 13.2 (64-bit)', 'GFortran 8.1', 'GFortran 8.1 (64-bit)', 'Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          After filtering: ['Intel Fortran Compiler Classic 2021.10.0', 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)']
INFO     main                          Selected Fortran version: 'Intel Fortran Compiler Classic 2021.10.0 (64-bit)'
INFO     main                       Linker versions: ['GCC 13.2 (x64)', 'GCC 13.2 (x86)', 'GCC 8.1 (x64)', 'GCC 8.1 (x86)', 'VS 2017 Professional', 'VS 2017 Professional', 'VS 2019 Professional', 'VS 2019 Professional', 'VS 2022 Professional', 'VS 2022 Professional']
INFO     main                          After filtering: {'VS 2022 Professional', 'VS 2017 Professional', 'VS 2019 Professional'}
INFO     main                          Selected Linker version: 'VS 2017 Professional'
INFO     main                       Matlab versions: ['']
INFO     main                          Selected Matlab version: ''
INFO     main                       Tutorial directory: C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial
INFO     main                       Running 'vdiv' (Single Phase Voltage Divider)
INFO     main                       vdiv Project Compile: 0.770 sec
INFO     main                       vdiv Project Solver: 0.122 sec
INFO     main                       vdiv EMTDC MAKE: 2.624 sec
INFO     main                       vdiv Project Builder: 5.004 sec
INFO     main                       vdiv Mediator: 0.482 sec
INFO     main                       vdiv EMTDC RUN: 2.549 sec
INFO     main                       [All] Workspace: 6.075 sec
INFO     main                       Run 'vdiv' complete

The handler can store information collected during the run, that may be accessed afterwards. Of course, to do so, you would need to hold onto a reference to the handler:

handler = BuildEventHandler()
project.run( handler )
info = handler.get_interesting_data()

Build & Run Messages#

Build Messages#

When PSCAD builds a project, the build messages are recorded. The script can retrieve these build messages.

After the project.run(…) line, add the following:

                project.run(BuildEventHandler());
                LOG.info("Run '%s' complete", project.name)

                messages = project.messages()
                for msg in messages:
                    print(f"{msg.scope}  {msg.status}  {msg.text.strip()}")

This script would produce:

⋮               ⋮               ⋮               ⋮
INFO     main                       Run 'vdiv' complete
vdiv  normal  Begin compiling with PSCAD Version 5.1.0
vdiv  normal  Generating 'C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial\\vdiv.if18\vdiv.map'.
vdiv  normal  The total number of live nodes: 1
vdiv  normal  Coding .mak file: 'C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial\\vdiv.if18\\SConstruct'
vdiv  normal  Time for Compile: 46ms  Make: 0ms
vdiv  normal  Solve Time = 47ms
vdiv  normal  Will execute (1): call C:\Program Files (x86)\Intel\oneAPI\setvars-ifort.bat  vs2017 intel64
vdiv  normal  Will execute (1): call "C:\Program Files (x86)\Intel\oneAPI\setvars-ifort.bat"  vs2017 intel64
vdiv  normal  Will execute (2): "C:\Program Files (x86)\PSCAD\5.1.0\bin\win64\Python.exe" -m SCons
vdiv  normal  Will execute (2): "C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial\\vdiv.if18\vdiv_mak.bat"
vdiv  normal  Creating EMTDC executable...
vdiv  normal  C:\Users\Public\Documents\PSCAD\5.1.0\Examples\tutorial\vdiv.if18>call "C:\Program Files (x86)\Intel\oneAPI\setvars-ifort.bat"  vs2017 intel64
vdiv  normal  :: initializing oneAPI environment...
vdiv  normal  Initializing Visual Studio command-line environment...
vdiv  normal  Visual Studio version 15.9.71 environment configured.
vdiv  normal  "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\"
vdiv  normal  Visual Studio command-line environment initialized for: 'x64'
vdiv  normal  :  advisor -- 2023.2.0
vdiv  normal  :  compiler -- 2023.2.0
vdiv  normal  :  dal -- 2023.2.0
vdiv  normal  :  debugger -- 2023.2.0
vdiv  normal  :  dnnl -- 2023.2.0
vdiv  normal  :  dpcpp-ct -- 2023.2.0
vdiv  normal  :  inspector -- 2023.2.0
vdiv  normal  :  mkl -- 2023.2.0
vdiv  normal  :  vtune -- 2023.2.0
vdiv  normal  :: oneAPI environment initialized ::
vdiv  normal  scons: Reading SConscript files ...
vdiv  normal  scons: done reading SConscript files.
vdiv  normal  scons: Building targets ...
vdiv  normal  scons: `.' is up to date.
vdiv  normal  scons: done building targets.
vdiv  normal  Finished compiling with PSCAD Version 5.1.0

Here, we are just extracting the scope, status, and text of the messages. Other fields, such as label and component references could also be extracted.

Run Messages#

After EMTDC has run the project, the run messages may also be retrieved. Unlike the build messages, the run messages are returned as an unstructured blob of text.

Immediately after the above code, add the following lines:

                print("-"*60)
                output = project.output()
                print(output)

When run, this change to the script adds the run messages to the output:

⋮               ⋮               ⋮               ⋮
vdiv  normal  C:\Users\Public\Documents\PSCAD\5.1.0\Examples\tutorial\vdiv.if18>call "C:\Program Files (x86)\Intel\oneAPI\setvars-ifort.bat"  vs2017 intel64
vdiv  normal  :: initializing oneAPI environment...
vdiv  normal  Initializing Visual Studio command-line environment...
vdiv  normal  Visual Studio version 15.9.71 environment configured.
vdiv  normal  "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\"
vdiv  normal  Visual Studio command-line environment initialized for: 'x64'
vdiv  normal  :  advisor -- 2023.2.0
vdiv  normal  :  compiler -- 2023.2.0
vdiv  normal  :  dal -- 2023.2.0
vdiv  normal  :  debugger -- 2023.2.0
vdiv  normal  :  dnnl -- 2023.2.0
vdiv  normal  :  dpcpp-ct -- 2023.2.0
vdiv  normal  :  inspector -- 2023.2.0
vdiv  normal  :  mkl -- 2023.2.0
vdiv  normal  :  vtune -- 2023.2.0
vdiv  normal  :: oneAPI environment initialized ::
vdiv  normal  scons: Reading SConscript files ...
vdiv  normal  scons: done reading SConscript files.
vdiv  normal  scons: Building targets ...
vdiv  normal  scons: `.' is up to date.
vdiv  normal  scons: done building targets.
vdiv  normal  Finished compiling with PSCAD Version 5.1.0
------------------------------------------------------------
Initializing Simulation Run
Executing > "C:\Users\Public\Documents\Pscad\5.1.0\Examples\tutorial\\vdiv.if18\vdiv_30000.bat"
C:\Users\Public\Documents\PSCAD\5.1.0\Examples\tutorial\vdiv.if18>call "C:\Program Files (x86)\Intel\oneAPI\setvars-ifort.bat"  vs2017 intel64 
:: initializing oneAPI environment...
   Initializing Visual Studio command-line environment...
   Visual Studio version 15.9.71 environment configured.
   "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\"
   Visual Studio command-line environment initialized for: 'x64'
:  advisor -- 2023.2.0
:  compiler -- 2023.2.0
:  dal -- 2023.2.0
:  debugger -- 2023.2.0
:  dnnl -- 2023.2.0
:  dpcpp-ct -- 2023.2.0
:  inspector -- 2023.2.0
:  mkl -- 2023.2.0
:  vtune -- 2023.2.0
:: oneAPI environment initialized ::
Communications: Connection established.
EMTDC(tm) Version 5.00 R#93051001
Time Summary: Start Date: 10-16-2018
Time Summary: Start Time: 13:10:06
The actual plot step: '250.000000' 
Time Summary: Stop Time: 13:10:06
Time Summary: Elapsed Time: 00:00:00
Time Summary: Total CPU Time: 47ms.
Terminating connection.
EMTDC run completed.