Example PGM Files

From SysCAD Documentation

Jump to: navigation, search

Navigation: PGMs

Contents

Sample PGM file (General)

;======================================================================================
; This is a sample PGM file.  The aim is to set the recycle flowrate 
; (from tank3 to tank1) to be half the feed flowrate.
;======================================================================================

;Lines that start with a semicolon (;) are comments only.
;pgm files must end with a $ sign OR Endfile.

;---- Define Variables ------------------------
;Bit is true or false
BIT        DefaultSetPoint*

;Double is a real number
;adding * adds the variable to the Access Window
;adding @ marks the variable read only on the access window
;adding ("Dimension","unit") adds engineering unit to the access window
DOUBLE     FeedSetPoint*("Qm","kg/s"), ActualFeedRate@("Qm","kg/s")
DOUBLE     RecycleFlowRate@, RecycleRatio*

;---Logic--------------------------------
;Adding in an if statement to predefine a default FeedSetPoint and RecycleRatio.
;This will be used when a user calls for a default set point ORwhen there is no feedsetpoint
;or recycleRatio defined.  Othertimes, the user is able to make changes to the FeedSetPoint 
;and RecycleRatio direct from syscad GC_1 access window or trend window.

if (DefaultSetPoint) or (ActualFeedRate ==0 or RecycleRatio ==0)
  FeedSetPoint = 1000 ;kg/s
  RecycleRatio = 0.5  ;FeedSetPoint / RecycleFlowRate
  DefaultSetPoint = 0
endif

;keyword GetTag gets a value from SysCAD
;keyword SetTag sets a value to SysCAD
SetTag("Source1.Qm_Rqd (kg/s)", FeedSetPoint)
ActualFeedRate= GetTag("pipe1.Qm (kg/s)")
RecycleFlowRate = ActualFeedRate * RecycleRatio 
SetTag("Tank3.GM.IOs.[Recycle].Flow (kg/s)", RecycleFlowRate)

$ ;END OF FILE

;The $ sign (or ENDFILE) above marks the end of the file.  It must be present.  
Any text after the first $ sign will be ignored.

Sample PGM File (File layout when using counters)

;===================================================================================
; This is a sample PGM file.  
; The aim is to show how to set up the PGM file when counters are being used.
;===================================================================================

;Lines that start with a semicolon (;) are comments only.
;pgm files must end with a $ sign OR Endfile.

;---- Define Variables ------------------------
long Counter*@
bit ControlOn*
bit Error1*@
Str AssessmentMessage1*@

;--- Logic ------------------------------------

if (OnInitialise)
 ;Place code here that must execute before the first iteration when solve or run is selected...
 ;This can be used to set tags that will become unchangeable once SysCAD is solving.
 ;This would include tags such as solving methods, any list boxes or tick boxes and datum in Dynamic.
 ;Note that SetDynTag(Tag, value) and GetDynTag(Tag) must be used to do this.
 
  SetDynTag("PID_2.Cfg.[0].On", ControlOn)
elseif (OnTerminate)
 ;Place code here that must execute after last iteration when stop is selected or solve is complete...
 ;For example, can have conditional messages to appear at the end of the solve.
 Error1 = ;place any solution checking logic here
 if (Error1)
   AssessmentMessage1 = "Run not successful, do this..." ;message as required...
   MsgBox(AssessmentMessage1)
 endif
 ;can leave blank if nothing will go here, but must have this statement to ensure counter counts correctly.
else
 ;Place code here that must execute every iteration.
 ;NOTE counter must be placed in this section, otherwise it will have extra counts during 
 ;SysCAD initialise and while SysCAD stops.
  Counter = Counter + 1
endif

$ ;END OF FILE

Example PGM with ReactionFinder Classes and Functions

;============================================================================ 
; Demonstration PGM - Class functions. 
; Project Used: Any with a Reaction Block. 
; KWA KENWALT - MARCH 2006 
;============================================================================ 

; Description of the ReactionFinder Class function --- 

; This class frees the user from the problem of the reaction index changing when a new reaction  
; is added to the reaction file before the controlled reaction(s).  The "Init" function should be called 
; in the "OnInitialise" part of a pgm and this finds the index of the required reaction.  
; The "SetExtent" function then sets the extent of the reaction as a fraction of the "Reqdspecie". 
; NOTE: This has been updated to run under SysCAD Build 115 Update 12 
;============================================================================= 

Class ReactionFinder
;--- input variables ------ 
str     ReqdUnit*                   ;the unit containing the reaction file
str     ReqdReaction*               ;the actual reaction that will be controlled
str     ReqdSpecie*                 ;the specie that the control is based upon
double  ReqdExtent*("Frac","%")     ;the required reaction extent
;---- Output variables ------
long    ReactionIndex@              ;the actual reaction index number in the unit
long    totalNumReactions@          ;total number of reactions in the reaction file
;--- local variables ------
str     NumReactions
str     ReactionName, RBReact
str     temp, ReactionNumber
str     errormsg
long    Minlength
long    i,reactioncomp

 Function Init()
  if (strlen(ReqdUnit) > 0)
    i = 1
    ReactionIndex = 0
    NumReactions = StrCat(ReqdUnit, ".RB.NoOfReactions")
    totalNumReactions = GetDynTag(NumReactions)
      while (i <= totalNumReactions)
          ReactionName = StrCat3(ReqdUnit, ".RB.R", IntToStr(i), ".Reaction")
          RBReact = GetDynStrTag(ReactionName)
          Minlength = Min(strlen(RBREact),strlen(ReqdReaction))
            if (Minlength > 0)
               reactioncomp = StriCmp(Left(RBREact,Minlength), Left(ReqdReaction,Minlength))
                if (reactioncomp == 0)
                    temp = StrCat3(ReqdUnit, ".RB.R", IntToStr(i), ".Extent (%.")
                    ReactionNumber = StrCat2(temp, ReqdSpecie, ")")
                    ReactionIndex = i
                    i = totalNumReactions + 1
                endif
            endif
          i = i + 1
      endwhile
      if (ReactionIndex == 0)
         errormsg = strcat3("The reaction ", ReqdReaction, " not found in ", ReqdUnit)
         lognote(errormsg)
      endif
  endif
  return 0
 EndFunct      

 FUNCTION SetExtent()
  if (ReactionIndex > 0)
      SetDynTag(ReactionNumber,ReqdExtent)
  endif
  return 0
 EndFunct

EndClass

;The following is an example of pgm code using the ReactionFinder class to
;call a number of reactions.

>>C:\SysCAD90\Examples\ReactionFinder.pgm

long        NumUnits*       ;In this case NumUnits = 1
double      OverallRxnExt*, Feedore@("Qm","kg/h")
double      tank3Input@("Qm","kg/h")
double      tank3extent@, Output@("Qm","kg/h")
long        iR
 
ReactionFinder Reactions[1]

if (Oninitialise)
  iR = 0
  while (iR < NumUnits)
     Reactions[iR].Init()
     iR = iR + 1
  endwhile
else

  Feedore     = GetTag("Ore_in.Qi.Na2CO3(s) (kg/h)")
  tank3Input  = GetTag("Leached2.Qi.Na2CO3(s) (kg/h)")
  Output      = GetTag("Leached_solution.Qi.Na2CO3(s) (kg/h)")
  tank3extent = 100 - (Feedore * (1 - OverallRxnExt/100) / tank3Input) * 100
  SetTag("LEACH_CONVERSION.Reactions[0].ReqdExtent (%)",tank3extent)
  iR = 0

  while (iR < NumUnits)
    Reactions[iR].SetExtent()
    iR = iR + 1
  endwhile

endif

$

Example PGM Function to Check for Error and Pause Simulation

BIT  CheckErrors*

Function SanityCheck(BIT Wrong, STR Message)
  if (CheckErrors AND Wrong)
    logerror(strcat("Ohoh:",Message))
    pausesimulation = true
  Endif
return 0
EndFunct

Example PGM Class to set specie splits based on user requirements

The following Class Example PGM file - Class_Specie.pgm (given under the table) allows the user to set the specie split in a General Model (GM) based on any of the following requirements:

Example function call using the SpecieClass Defined in the Class_Specie.pgm Purpose Description
Init("Cu", "s")                           ;call initialisation function   
IonSplit("Splitter.GM.IOs.[P_002]", 80)   ;call the split function  
Set Mass Fraction Split based on One (1) given Element Set the split Mass Fraction of all species containing a given element in a user defined phase, i.e. the user can send 80% of all of the Copper in the solid phase to a required stream.
Init2("Cu", "S", "s")                     ;call initialisation function   
IonSplit("Splitter.GM.IOs.[P_002]", 75)   ;call the split function 
Set Mass Fraction Split based on Two (2) given Elements Set the split Mass Fraction of all species containing two given elements in a user defined phase, i.e. the user can send 75% of all species that contain both Copper and Sulphur in the solid phase to a required stream.
This method selects CuS(s), Cu2FeS4(s), etc, but not Cu(s) or NiS(s) - the species must contain BOTH elements.
IndPhaseSplit("Splitter.GM.IOs.[P_002]", 2, "aq")
Set Mass Fraction Split based on One (1) given Individual Phase Set the split of all species in an Individual Phase to a stream, i.e. send 2% of all (aq) species to a stream.
PhaseSplit("Splitter.GM.IOs.[P_002]",  5, "l") 
Set Mass Fraction Split based on One (1) given Phase Set the split of all species in a Phase to a stream, i.e. send 5% of all liquid species to a stream.
DensitySplit("Density_Splitter_001.GM.IOs.[P_HeavySolids]", 3000, "s")
Set Mass Fraction Split based on Density Set the split of all species in a Phase to a stream based on density separation, i.e. send 100% of all solids with density > 3000 kg/m3 to a stream.


PGM FILE: Class_Specie.pgm
;=======================================================================================
;--- SysCAD General Controller  - Specie Splitter class ---
long SpecieCount
; Find the total number of species in the project
SpecieCount = SDB.SpecieCount()

Class SpecieClass
 str STag
 double TempValue
 long ReqPhase, Sphase, isp, SplitPhase, NumIonSpecies
 array IonIndex
 
 ;------------------------------------------------------------------------------
 ; Initialisation function to set up an array with all of the species in the 
 ; required phase (GPhase) that contain the user defined element (Ion)
 Function Init(str Ion, str GPhase)
   IonIndex.SetLen(25)
   IonIndex.SetAll(0)
   NumIonSpecies = 0
   
   long Cmp1, SpPhase, ReqdPhase, j
   ; Find the index of the required phase
   ReqPhase = SDB.FindPhase(GPhase)
   isp = 0
   j = 0
   ; Scroll through all the species in the required phase in the project to find 
   ; ones that contain the required element
   while (isp < SpecieCount)
     SpPhase = SDB.SpIPhaseNo(isp)
     if (SpPhase == ReqPhase)
       Cmp1 = SDB.SpElemMoles(isp, Ion) 
       if (Cmp1 > 0)
         IonIndex.SetAt(j,isp)
         j = j + 1
       endif
     endif
     isp = isp + 1
   endwhile
   NumIonSpecies = j
   return 0
 EndFunct

 ;------------------------------------------------------------------------------
 ; Initialisation function to set up an array with all of the species in the 
 ; required phase (GPhase) that contain both user defined elements (Ion1 and Ion2)
 Function Init2(str Ion1, str Ion2, str GPhase)
   IonIndex.SetLen(20)
   IonIndex.SetAll(0)
   NumIonSpecies = 0
   
   long Cmp1, Cmp2, SpPhase, ReqdPhase, j
   ; Find the index of the required phase
   ReqdPhase = SDB.FindPhase(GPhase)
   isp = 0
   j = 0
   ; Scroll through all the species in the required phase in the project to find 
   ; ones that contain both the required elements
   while (isp < SpecieCount)
     SpPhase = SDB.SpIPhaseNo(isp)
     if (SpPhase == ReqdPhase)
       Cmp1 = SDB.SpElemMoles(isp, Ion1) 
       Cmp2 = SDB.SpElemMoles(isp, Ion2) 
       if ((Cmp1 > 0) AND (Cmp2 > 0))
         IonIndex.SetAt(j,isp)
         j = j + 1
       endif
     endif
     isp = isp + 1
   endwhile
   NumIonSpecies = j
   return 0
 EndFunct

 ;------------------------------------------------------------------------------
 ; Function to split a single required specie to a stream at a user defined value 
 Function SpecieSplit(str SplitTag, double ReqValue, str ReqdSpecie)
   str tempsplit
     tempsplit = StrCat3(SplitTag, ".Splt.", ReqdSpecie ," (%)")
     SetDynTag(tempsplit, ReqValue)
   return 0
 EndFunct
  
 ;------------------------------------------------------------------------------
 ; Function to split a single specie with a required index to a stream at a user defined value 
 Function SpecieIndexSplit(str SplitTag, double ReqValue, long SpecieIndex)
   str tempsplit, RequiredSpecie
     RequiredSpecie = SDB.SpSymbol(SpecieIndex)
     tempsplit = StrCat3(SplitTag, ".Splt.", RequiredSpecie ," (%)")
     SetDynTag(tempsplit, ReqValue)
   return 0
 EndFunct
  
 ;------------------------------------------------------------------------------
 ; Function to split all species containing a required element(s) to a stream at a user defined value
 ; Must have initialised the array first using Init or Init2
 Function IonSplit(str SplitUnit, Double SplitValue)
   str TempSp
   long js
   js = 0
   while (js < NumIonSpecies)
     isp = IonIndex.GetAt(js)
     TempSp = SDB.SpSymbol(isp)
     SpecieSplit(SplitUnit, SplitValue, TempSp)
     js = js + 1
   endwhile
   return 0
 EndFunct
  
 ;------------------------------------------------------------------------------
 ; Function to split all species in a required individual phase to a stream at a user defined value 
 Function IndPhaseSplit(str SplitUnit, Double SplitValue, str ReqdIPhase)
   str TempSp
   long SpPhase    
   SplitPhase = SDB.FindIPhase(ReqdIPhase)
   isp = 0
   while (isp < SpecieCount)
     SpPhase = SDB.SpIPhaseNo(isp)
     if (SpPhase == SplitPhase)
       TempSp = SDB.SpSymbol(isp)
       SpecieSplit(SplitUnit, SplitValue, TempSp)
     endif
     isp = isp + 1
   endwhile
   return 0
 EndFunct
  
 ;------------------------------------------------------------------------------
 ; Function to split all species in a required phase to a stream at a user defined value 
 Function PhaseSplit(str SplitUnit, Double SplitValue, str ReqdPhase)
   str TempSp
   long SpPhase    
   SplitPhase = SDB.FindPhase(ReqdPhase)
   isp = 0
   while (isp < SpecieCount)
     SpPhase = SDB.SpPhaseNo(isp)
     if (SpPhase == SplitPhase)
       TempSp = SDB.SpSymbol(isp)
       SpecieSplit(SplitUnit, SplitValue, TempSp)
     endif
     isp = isp + 1
   endwhile
   return 0
 EndFunct

 ;------------------------------------------------------------------------------
 ; Function to split all species in a required phase based on Density to a stream at a user defined value 
 Function DensitySplit(str SplitUnit, Double DensitySplitValue, str ReqdPhase)
   str TempSp
   long SpPhase    
   SplitPhase = SDB.FindPhase(ReqdPhase)
   isp = 0
   while (isp < SpecieCount)
     SpPhase = SDB.SpPhaseNo(isp)
     if (SpPhase == SplitPhase)
         TempSp = SDB.SpSymbol(isp)
         if SDB.SpDensity(isp,298.15,101.325) > DensitySplitValue
            SpecieSplit(SplitUnit, 100, TempSp)
         Else
            SpecieSplit(SplitUnit, 0, TempSp)
         endif	
     endif
     isp = isp + 1
   endwhile
   return 0
 EndFunct
  
EndClass

One of the advantages of using this class when doing specie splits, is that if the user adds species to the project, this class will automatically include it in the split.

For an example PGM that uses this class, see Example PGM file including the Specie Class.

Example PGM file including the Specie Class

The following is an example of a PGM file that uses the above splitter class:

;=======================================================================================
;--- SysCAD General Controller for a Generic Splitter ---

>> Class_Specie.pgm

;--- variable declarations ---

TextLabel("Required Phase (s, l or g)")
str       Phase*

TextLabel("Elemental Recoveries")
double    NiRecovery*("Frac","%")
double    CuRecovery*("Frac","%")

TextLabel()
Double    LiquidRecovery*("Frac","%")

; Local Variables

double      prevNi, prevCu, prevLiquid

SpecieClass NiSplit, CuSplit
 
if (OnInitialise)
 ;Initialise the functions in the class for elemental splits
  NiSplit.Init("Ni", "s")
  CuSplit.Init("Cu", "s")
 
  prevNi = 0
  prevCu = 0
  prevLiquid = 0
 
else
 ; Split based on elements.  Only call the function when the required recovery changes.
  if (NiRecovery != prevNi)
     NiSplit.IonSplit("Split_Unit.GM.IOs.[P_002]", NiRecovery)
     prevNi = NiRecovery
  endif
 
  if (CuRecovery != prevCu)
     CuSplit.IonSplit("Split_Unit.GM.IOs.[P_002]", CuRecovery)
     prevCu = CuRecovery
  endif

  if (LiquidRecovery != prevLiquid)
     NiSplit.PhaseSplit("Split_Unit.GM.IOs.[P_002]", LiquidRecovery, "l")
     prevLiquid = LiquidRecovery
  endif
 
endif

$ ; --- end of file ---

Example PGM with Classes and Functions

;============================================================================
; Demonstration PGM - Class functions.
; Project Used: Alumina Digestion project.
; KWA KENWALT - MARCH 2003
;============================================================================

;============================================================================
;                         DEFINING SUB ROUTINES                              
;============================================================================
;----------------------------
Class BayerLiquor
;----------------------------

;-----DEFINE Bayer Liquor VARIABLES--------------------------------------------

STR StreamTagName*, MyTag, Liquor, Water
STR Al2O3, Na2C2O4, Na2C5O7, Na2CO3, Na2SO4, NaCl, NaOH, SiO2, Temp
DOUBLE LiquorQm("Qm","kg/s"), WaterQm("Qm","kg/s"), Al2O3Qm("Qm","kg/s")
DOUBLE Na2C2O4Qm("Qm","kg/s"), Na2C5O7Qm("Qm","kg/s"), Na2CO3Qm("Qm","kg/s")
DOUBLE Na2SO4Qm("Qm","kg/s"), NaClQm("Qm","kg/s"), NaOHQm("Qm","kg/s")
DOUBLE SiO2Qm("Qm","kg/s"), TNa, TAl2O3, Density_25("Rho","kg/m^3")@
DOUBLE Density_T("Rho","kg/m^3")@, T("T","dC")
DOUBLE A("Conc","g/L")@, C("Conc","g/L")@, S("Conc","g/L")@, A_C@, C_S@ 

 ;----FUNCTION GET VARIOUS MASSES----------------------------------------------
 
Function Mass()
 LiquorQm = GetDynTag(Liquor)
 WaterQm = GetDynTag(Water)
 Al2O3Qm = GetDynTag(Al2O3)
 Na2C2O4Qm = GetDynTag(Na2C2O4)
 Na2C5O7Qm = GetDynTag(Na2C5O7)
 Na2CO3Qm = GetDynTag(Na2CO3)
 Na2SO4Qm = GetDynTag(Na2SO4)
 NaClQm = GetDynTag(NaCl)
 NaOHQm = GetDynTag(NaOH)
 SiO2Qm = GetDynTag(SiO2)
 return 0
EndFunct

;----FUNCTION TO INITIALISE Tags----------------------------------------------

Function InitTag()
 MyTag = StreamTagName
 Liquor   = StrCat(MyTag, ".Qo.Liquids (kg/s)")
 Water    = StrCat(MyTag, ".Qo.H2O(l) (kg/s)")
 Al2O3    = StrCat(MyTag, ".Qo.Al2O3(aq) (kg/s)")
 Na2C2O4  = StrCat(MyTag, ".Qo.Na2C2O4(aq) (kg/s)")
 Na2C5O7  = StrCat(MyTag, ".Qo.Na2C5O7(aq) (kg/s)")
 Na2CO3   = StrCat(MyTag, ".Qo.Na2CO3(aq) (kg/s)")
 Na2SO4   = StrCat(MyTag, ".Qo.Na2SO4(aq) (kg/s)")
 NaCl     = StrCat(MyTag, ".Qo.NaCl(aq) (kg/s)")
 NaOH     = StrCat(MyTag, ".Qo.NaOH(aq) (kg/s)")
 SiO2     = StrCat(MyTag, ".Qo.SiO2(aq) (kg/s)")
 Temp     = StrCat(MyTag, ".T (dC)")
 Return 0
EndFunct
 
;----FUNCTION - DENSITY @ 25 dC------------------------------------------------
 Function Density25()
   Mass()
   TNa         = (Na2CO3Qm + (NaOHQm/80 + Na2C2O4Qm/134 + Na2C5O7Qm/218 + NaClQm/116.9 
                  + Na2SO4Qm / 142.05) * 106 ) * (100 / LiquorQm)
   TAl2O3      = Al2O3Qm*100/LiquorQm
   Density_25  = (0.982 + (0.01349855 * TNa) + (-0.00024948 * TNa * TNa) + 
                 (0.00000273* TNa * TNa * TNa) + (0.00208035* TAl2O3)+ 
                 (0.00004113* TAl2O3 * TAl2O3) + (-0.00000728* TAl2O3 * TAl2O3 * TAl2O3)+
                 (0.00033367* TNa * TAl2O3))*1000
 Return 0
 EndFunct

;----FUNCTION - DENSITY @ Temp ------------------------------------------------
 Function DensityT()
    T  = GetDynTag(Temp)
    Density_T  = Density_25 * (1 - (0.0005021858*0.85*(T-25))-(0.0000011881*0.85*(T-25)*(T-25)))
 Return 0
 EndFunct

;----FUNCTION - Concentration ------------------------------------------------
 Function Conc()
    A    = Al2O3Qm / LiquorQm * Density_25
    C    = NaOHQm/80*106 / LiquorQm * Density_25
    S    = Na2CO3Qm / LiquorQm * Density_25 + C
    A_C  = A/C
    C_S  = C/S
 Return 0
 EndFunct

;----FUNCTION - EXECUTE FUNCTIONS---------------------------------------------
 Function Exec()
    Density25()
    DensityT()
    Conc()
 Return 0
 EndFunct
  
 EndClass
 
;=================================================
; DEFINING EQUIPMENT IN THE PROJECT
;=================================================
;Example of Defining Classes individually
BayerLiquor P4, P9, P10, P14
 
;Example of Defining Classes with an Array 
BayerLiquor  Pipe[3]

;=================================================
; DEFINING LOGIC IN THE PROJECT
;=================================================
 
 if (Oninitialise)
  ;------Initialise Tag Name(s)---------
   P4.InitTag("P_4")
   P9.InitTag("P_9")
   P10.InitTag("P_10")
   P14.InitTag("P_14") 
  ;Example of calling functions from classes defined with an array.
   pipe[0].initTag("P_11")
   pipe[1].initTag("P_12")
   pipe[2].initTag("P_13")
 Elseif (OnTerminate)
 Else
   ;-------Executing Functions--------
   P4.Exec()
   P9.Exec()
   P10.Exec()
   P14.Exec()
   ;Example of calling functions from classes defined with an array.
   pipe[0].Exec()
   pipe[1].Exec()
   pipe[2].Exec()
  Endif

;=================================================
ENDFILE
;=================================================
Personal tools
Document Sections