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.
PSCAD 5.0 or later is installed.
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.
The “Public Documents” directory is located at
C:\\Users\\Public\\Documents
.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.