SysCAD COM Interface Class

From SysCAD Documentation
Jump to navigation Jump to search

Basic COM Functionality in a python class

Save the code in a file syscadif.py This needs to be either in the working directory, or somewhere on the PYTHONPATH (so that you can import the module from any script) Then import the module and create an instance of the SysCADCom class:

import syscadif
sc = syscadif.SysCADCom()

After a project is loaded, you can get and set tags, and run the model or scenarios. For convenience, operators __getitem__ and __setitem__ are provided which allow using a similar syntax to PGM: Copy Tag for PGM can be used to grab the tag string with enclosing brackets.

 sc.setTag("SLURRY_IN.QmReqd (t/h)", 500)
 sc["SLURRY_IN.QmReqd (t/h)"] =500    ## equivalent
 sc.run()
 prod = sc.getTag("P_007.Qo.QM.Au(s) (oz/d)")
 prod = sc["P_007.Qo.QM.Au(s) (oz/d)"] ## equivalent

## Setting a single tag for three different scenarios: Flow in P_01 and P_03 for feeds of 1, 3, and 5 tph
 sc.RunScenarios([1,3,5], "Feed1.QmRqd (tph)", ["P_01.Qm (tph)", "P_03.Qm (tph)"]) 
# Four different scenarios, setting two tags
 sc.RunScenarios([[2,4], [3,5], [4, 7], [5, 8]],    ## List of value lists
                 ["Feed1.QmRqd (tph)","Feed2.QmRqd (tph)"], 
                 ["P_01.Qm (tph)", "P_03.Qm (tph)"])

Creating an instance of the SysCADCom class will fire up SysCAD (or attach if SysCAD is already running). To see the code below click on the Expand link:

Python Code      
import win32com.client
import time, os
from tkinter import filedialog

PrjFolder = "C:/93Files"   # Where you keep SysCAD projects

class SysCADCom:
    def __init__(self):
        self.ProgID = r"SysCADSimulator93.Application"
        self.SysCAD = self.Prj = self.Tags = self.Solver = None
        self.Probal = self.Dynamic = None
        self.SysCAD = win32com.client.DispatchEx(self.ProgID)
        self.build = self.SysCAD.VersionNumber(2)

    def OpenProject(self, fn=None, checkFile = True):
        print (self.ProgID)
        if fn is None:
            self.fn = filedialog.askopenfilename(filetypes=[("SysCAD Projects", "*spj")],
                                             initialdir = PrjFolder,
                                             defaultextension="spj")
        else:
            self.fn = fn
        if not self.fn: return 0
        if checkFile and not os.path.isfile(self.fn):
            print ("Project File not found")
            return 0
        self.Prj = self.SysCAD.OpenProject(self.fn)
        self.Tags = self.Prj.Tags
        self.Solver = self.Prj.Solver
        self.RunMode()
        time.sleep(1)

    def RunMode(self):
        '''Select Run mode depending if project is SS or dynamic'''
        if self.Solver.RunMode & 1:
            self.Probal = self.Solver.Probal
            self.Dynamic = None
        else:
            self.Dynamic = self.Solver.Dynamic
            self.Probal = None

    def CloseProject(self):
        self.SysCAD.CloseProject()
        
    def Close(self):    
        '''remove all references to COM objects...'''
        del self.Probal
        del self.Dynamic
        del self.Solver
        del self.Tags
        del self.Prj
        del self.SysCAD

    def startSysCAD(self):
        if self.Solver.RunMode & 1:
            self.Probal.Start()
        else:
            self.Dynamic.Start()
        
    def run(self, sleepTime=0.1):
        '''Run a Probal project to completion. For a project that takes a longer time to solve
         increase sleepTime'''
        if self.Probal is not None:
            self.Probal.Start()
            while not self.Probal.IsStopped:
                time.sleep(sleepTime)
        elif self.Dynamic is not None:
                self.Dynamic.Start()
        else:
            print ("No project")

    def stop(self):
        if self.Solver.RunMode & 1:
            self.Probal.Stop()
        else:
            self.Dynamic.Stop()
            
    def RunScenarios(self, XVals, Tag, getTagList, verbose=True):
        '''Run a number of scenarios. 
        If Tag is a string, XVals should be a list or iterable of appropriate elements
        Otherwise Tag should be a list of tags or iterable, and XVals a list of multiple values
        Accumulate the results and return'''
        Y = []
        for x in XVals:
            if verbose: print (x)
            if isinstance(Tag, str):
                self.setTag(Tag, x)  ## Change tag value
            else:
                self.setTags(Tag, x)
            self.run()
            Y.append(self.getTags(getTagList))
        return Y
            
    def getTag(self, tag):
        '''Fetch a single tag'''
        return self.Tags.TagValue(tag)
    def __getitem__(self, tag):
        return self.Tags.TagValue(tag)

    def getTags(self, tagList):
        '''Fetch a list of tags'''
        return [self.Tags.TagValue(tag) for tag in tagList]

    def setTag(self, tag, value):
        '''Set a single tag'''
        self.Tags.SetTagValue(tag, value)
    def __setitem__(self, tag, value):
        self.Tags.SetTagValue(tag, value)

    def setTags(self, tagLis, valLis):
        '''Set a list of tags to corresponding values'''
        for t, v in zip(tagLis, valLis):
            self.Tags.SetTagValue(t, v)

    def state(self, timeout = 0.0):
        if timeout: time.sleep(timeout)
        return self.Probal.IsStopped