Process Models Guide
Process Models Guide
A Guide to Creating
MILANO Process Models
Process Models in ROMeo The software described in this guide is furnished under a license
agreement and may be used only in accordance with the terms
of that agreement. Information in this document is subject to
change without notice. Simulation Sciences Inc. assumes no
liability for any damage to any hardware or software
component or any loss of data that may occur as a result of the
use of the information contained in this manual.
Copyright Notice Copyright 2002 Simulation Sciences Inc. All Rights
Reserved. No part of this publication may be copied and/or
distributed without the express written permission of
Simulation Sciences Inc., 601 Valencia Ave., Brea, CA 92823-
6346
Trademarks ROMeo and SIMSCI are registered marks or trademarks of
Simulation Sciences Inc.
Windows, Windows 95, Windows NT, and MS-DOS are
registered marks or trademarks of Microsoft Corporation.
Pentium is a registered trademark of Intel Corporation.
All other products are trademarks or registered trademarks of
their respective companies.
Printed in the United States of America, 2/02.
Contents
Chapter 1
Overview
Steps to Add a New Process Model . . . . . . . . . . . . . . . . . . . . . . . .1-3
Creating .mil Source Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-4
Related Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-4
Typographic Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-5
Chapter 2
Process Model Framework
Process Model Class Templates. . . . . . . . . . . . . . . . . . . . . . . . . . .2-1
Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-2
Overview of ROMeo Process Model Base Classes . . . . . . . . . . . .2-4
Data Members Accessible from Class
. . . . . . . . . . . . . . . . . . . . . . . . . PM_UserAddedProcessUnit2-5
Data Members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-5
Methods Accessible from Class PM_UserAddedProcessUnit . . .2-8
Object Management Methods . . . . . . . . . . . . . . . . . . . . . . . . .2-8
Model Checking and Verification Methods . . . . . . . . . . . . .2-11
Report Generation Method . . . . . . . . . . . . . . . . . . . . . . . . . .2-14
Runtime Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-14
System Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-18
Chapter 3
Modular Thermo and Process Models
Accessing Constant Thermo Data . . . . . . . . . . . . . . . . . . . . . . . . .3-2
Accessing Variable Thermo Data. . . . . . . . . . . . . . . . . . . . . . . . . .3-4
Using Phase Models . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-5
Process Streams and Modular Thermo . . . . . . . . . . . . . . . . .3-11
Process Models iv
Chapter 4
Method Calls to MILANO from BBM and EEB
Overview of Method Calls to the Model . . . . . . . . . . . . . . . . . . . . 4-2
Include Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Listing of Method Calls to MILANO Model . . . . . . . . . . . . . . . . 4-3
Attribute Values Used in Methods that Access the Model . . . . . . 4-9
Chapter 5
Part 1: Conversion Reactor Models
Conversion Reactor - Model Description . . . . . . . . . . . . . . . . . . . 5-1
Implementation within ROMeo. . . . . . . . . . . . . . . . . . . . . . . . . . . 5-2
Degrees of Freedom for the Reactor Model . . . . . . . . . . . . . . 5-4
Overview of Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-5
Chapter 5
Part 2: Sample Code
All-MILANO Model ConvReactor.mil 5-7
Black Box Model ConvReactorBBM.mil 5-29
Black Box Model ConvReactorBBM.h 5-38
Black Box Model ConvReactorBBM.cpp 5-41
External Equation Block ConvReactorEEB.mil 5-54
External Equation Block ConvReactorEEB.h 5-63
External Equation Block ConvReactorEEB.cpp 5-65
// Demo Code for UOM Features . . . . . . . . . . . . . . . . . . . . 5-74
Chapter 6
Procedures
Adding Process Models to mcl.db. . . . . . . . . . . . . . . . . . . . . . . . . 6-1
Creating a Project File for a BBM or EEB DLL . . . . . . . . . . . . . . 6-5
Mixed-Language DLL: Interfacing C++ and FORTRAN. . . . . . . 6-8
C++ to FORTRAN Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-10
Unit Registration in ROMeo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6-13
Entering Data for a Custom Process Model . . . . . . . . . . . . . . . . 6-14
Chapter 7
Special Topics
Converting Black Box Models to External Equation Blocks . . . . 7-1
MILANO Specification of a Custom Model (EEB) . . . . . . . . 7-3
SizeSparsityProc for a Custom Model (EEB). . . . . . . . . . . . . 7-3
v Contents
FuncGradProc for a Custom Model . . . . . . . . . . . . . . . . . . . .7-4
Sparsity Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-5
Schema Evolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-7
Default Directory Structure with Included Files . . . . . . . . . . . . . .7-9
Client Directory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-9
Server Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-9
Model Directories on Client Computer. . . . . . . . . . . . . . . . . .7-9
Deploying a Custom Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-11
Directories and Files for Typical Custom Models . . . . . . . . . . . .7-12
Modifying the Icon Data File. . . . . . . . . . . . . . . . . . . . . . . . . . . .7-13
Icon Construction - Structure of the Icon Definition File . . .7-14
Specifying Icon Appearance . . . . . . . . . . . . . . . . . . . . . . . . .7-15
Sample Icon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-24
Icon Data File Template. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .7-27
Appendix A
Thermodynamic Properties
Refinery Inspection Properties. . . . . . . . . . . . . . . . . . . . . . . . . . . A-1
Refinery Inspection Property Points . . . . . . . . . . . . . . . . . . . . . . A-2
Fixed Point Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2
Correlated Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-3
Appendix B
Units of Measure
UOM Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-1
UOM Terminology . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-1
Specifying UOM Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . B-2
Specifying Units-of-Measure . . . . . . . . . . . . . . . . . . . . . . . . B-2
UOM Multipliers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
UOM Exponents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
Usage Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
UOM Classes and Predefined UOM Sets . . . . . . . . . . . . . . . . . . B-4
Units of Measure for UOM Base Classes . . . . . . . . . . . . . . . . . . B-6
Index
Process Models vi
Chapter 1
Overview
1-2 Overview
GUI Unit DLL - This file creates the data entry windows (DEWs)
for the new unit. You have the option of creating a complete set of
DEWs through which you can enter the unit specifications just as
you would with a standard SIMSCI model, or you can simply use
the UIGenericUnit.dll, which contains just the three data entry
windows common to all ROMeo process units: Thermo/Phases,
Notes and Diagnostics. These three common DEWs provide the
same functionality to the new model as they do to any other process
model for component slate, thermo method slate, product stream
phase specification, etc. If a custom set of DEWs has not been
created for the new unit, you can supply unit specifications, variable
and parameter values via the units model window (referred to also
as the General Data Access Window, (GDAW), or simply the GUI).
Icon Data File - This file specifies the inlet and outlet port
configuration for the unit. Here, too, you can create a completely
new custom icon data file or use UIGenericUnitIcon.dat. For details,
see Modifying the Icon Data File, 7.7.
ROMeo Server:
1. Write the new model class definitions in MILANO.
2. Add the new classes to the process model database using the
Model Library Manager program (MLMR.exe).
3. If Black Box Model and/or External Equation Block
components are needed in the process models, write the
modelSparsity() and modelEvaluation() functions and build
the DLL.
ROMeo Client:
1. Define the appearance of the icon which will appear in the
ROMeo GUI in the icon data file.
2. Add the new icon to the PFD icon palette using the Unit
Registration facility accessible from the ROMeo Options
menu.
1-4 Overview
1.4 Typographic Conventions
This document observes the following typographic conventions:
Example Description
expression Words in italic indicate syntactic categories and
function as placeholders for information that
you must supply. Italic type is occasionally
used for emphasis, particularly when a topic is
introduced.
D:\filename.ext Words in sans-serif type indicate file and
directory names.
BeginModel FLASH; Monospace type indicates keywords, literal
characters and code fragments.
tokenOne tokenTwo Tokens are separated by a blank. In actual
MILANO input, tokens can be separated by
white space (one or more blanks, tabs or
newlines).
Alt1 Alternatives are listed on separate lines, or
Alt2
Alt3
Alt1|Alt2|Alt3 are separated by vertical bars on the same line.
expressionopt The subscript opt indicates an optional entry for
argument, parameter, etc.
Void, void MILANO is case sensitive. Case usage
generally differs from that of C/C++.
In this document, the word Model usually means the Model class.
All comments about Models also apply to MilanoObjects, except
when mathematical relationships are involved.
We now introduce the modeling capabilities that are built into the
process model library. Behind this capability sits the Process Model
Framework (PMF) which provides a rich and process-specific
interface between the standard process models and the MITRE
environment. The same capabilities available to SIMSCI
developers are made available through the facility discussed below.
Thus, in many respects, the procedures you will follow in building a
process model are no different from those used by SIMSCI
developers when they created the standard process models.
SIMOprocessUnitTemplate.milimplements class
SIMOdoNothingTemplate
MISOprocessUnitTemplate.milimplements class
MISOdoNothingTemplate
2.2 Guidelines
Adhering to the following guidelines will help you maintain a clear,
easily recognizable distinction between custom models and the
standard models in the process model library included with
ROMeo:
Use the <<Group>> property.
The Group property is applied during model declaration and acts
as a tag. This tag is retrieved by the MILANO Library Manager
(MLM) and is a great aid when updating the library. Consider
the following example:
BeginModel ConvReactor :: PM_UserAddedProcessUnit
<<Group=Sample>>;
PModel PM_PModel
Equipment PM_Equipment
Unit PM_Unit
User-Added PM_UserAddedProcessUnit
Process Unit
CurrentCompSlate
Reference PM_ComponentSlate CurrentCompSlate <<Hidden>>
CurrentPropSlate
Reference PM_PropertySlate CurrentPropSlate <<Hidden>>
DebugLevel
Integer DebugLevel /0/
This data member specifies level of output during runtime.
Common values for this flag are:
0 no debug information
5 normal
10 all
OnOffStatus
Integer OnOffStatus /1/
Any Equipment item (e.g., process units, streams, flowsheets,
Measurements and Controllers) can be activated/deactivated via its
On/Off flag. The default state of an Equipment item is active with
its On/Off flag set to ON. The ON state means that all of its variables
are included in the final flowsheet model, while the OFF state
indicates exclusion from the final flowsheet model.
The product stream properties (flowrate, composition, etc.) of
an OFF unit are fixed at the values that existed when the unit was
last ON. The flowrate of a product stream from a DOWN unit is zero.
Units can be:
ON (PMF_On)
OFF (PMF_Off)
DOWN (PMF_Down)
Ports
Reference Set Ports <<UserOrdered>>
Port[Ports]
Reference PM_Port Port[Ports] <<NonSparse, Hidden>>
ReportLevel
Integer ReportLevel /2/
Report levels are:
2 - complete report
1 - normal report
0 - no report
UserOnOff
Integer UserOnOff /3/
Values for this flag are:
0 OFF
1 ON
2 Down
3 Default (value not set by user)
The end user can use this flag to set the status of the unit or stream
at runtime.
ValidateLevel
Integer ValidateLevel /0/
This flag is similar to DebugLevel and is used in the Validate
method.
As with DebugLevel, common values for this flag are:
0 no validation
5 normal
10 all
Destructor()
Void Destructor()
The Destructor() method is used to destroy any values of the
object before the object itself is destroyed. As with
the Constructor(), you are not required to implement this method
as it will be called automatically and in a predefined order:
Derived class Destructors
Base class Destructors
Object member of base class Destructors
Initialize()
Void Initialize()
In ROMeo, the parent of the new object invokes this method after
the new object is registered with the system. The object now can
access all the functionality of the ROMeo framework, including
name, parent, flowsheet and Modular Thermo. You can arrange the
order of invocation, including a call to the base classs
Initialize(). However, for a model with a submodel, the parent
Note: This method will be called only once during lifetime of the
object. Do not use this function to reset an object.
Usage: The most common tasks performed in this method are:
Makeconsistent()
Integer Makeconsistent()
This function is an implementation method concerning the ROMeo
Case feature, and involves mostly internal data storage. When
handling models with submodels, it is recommended that you call
Makeconsistent() for the submodels.
PortStreamPair()
Void PortStreamPair(String PortName, Integer InOut, String
UnitName, String UnitPortName, Integer PhaseFlag)
This short-cut function matches a reference stream to a reference
port. If the port already exists, it will merely bind them. It the port
does not exist, a new process port will be created.
1 - in port (feed)
2 - out port (product)
0 - none specified
1 - vapor only
2 - liquid only
3 - vapor and liquid only
4 - liquid 2 only
5 - liquid 2 and vapor only
6 - liquid 2 and liquid only
7 - all 3
Predeletion()
Void Predeletion()
This function is invoked before an object is destroyed when the
object still has access to ROMeo functionality. As in Initialize(),
a parent model is responsible for calling the methods of its object
members. The order of invocation can be arranged, for example, by
calling the Predeletion() of the base classes. However, for a model
with a submodel, the parent model MUST call the submodels
Predeletion() explicitly. Also, any changes in the model can
trigger Events.
Note: This method will be called only once during the lifetime of
the object. Do not use this function to reset an object.
Usage: The most common tasks performed in this method are:
CheckDataForIEG()
Integer CheckDataForIEG()
This method is called immediately before a unit or stream
GenerateEstimates(). CheckDataForIEG() ascertains whether the
information inside the object is adequate for Initial Estimate
Generation (IEG).
Usage: Most common tasks performed by CheckDataForIEG() are:
CheckDataForSolution()
Integer CheckDataForSolution()
This method is called just before the model is sent to the Solver.
CheckStructure()
Integer CheckStructure()
This function is designed to supplement GetState() by handling
data cross-checks that take a significant time. This method is
invoked as a pre-processor of GenerateEstimates(),
GenerateSolution(), and GenerateReport(). You can also trigger
this check from the PFD (via the Cross Check Data option). In a
Flowsheet or Collection, CheckStructure() is called for one unit
after another and stops when it encounters the first failure. You
cannot specify the order of execution. As a result, for a given unit,
you cannot assume that connecting upstream or downstream units
or streams have already been verified.
Usage: Most common tasks performed by CheckStructure() are:
Validate()
Integer Validate()
This method corresponds to the Check Solution Validity command
in ROMeo, and it is normally invoked after the Solver finishes the
solution. The verification should be done on the Level (L)
attribute, not the Initial (I) attribute. Also, see ValidateLevel()
for consistent level of checking.
AddPropsAndFlows()
Integer AddPropsAndFlows()
This method is called from PModel::CheckStructure()
automatically. You should override this function if you need to add
extra thermo parameters or variables. For a list of properties, see
Appendix A, Thermodynamic Properties. Consult the ROMeo
online Glossary for property descriptions.
AssignCompSlateToSubModel()
Void AssignCompSlateToSubModel()
Normally, a model should assign the component slate to its
submodel before calling Super:AssignCompSlateToSubModel().
Since ROMeo automatically assigns the units component slate to
the product streams, there is no need to assign the component slate
AssignPropSlateToSubModel()
Void AssignPropSlateToSubModel()
Comments for AssignCompSlateToSubModel() apply here.
BindStream()
Void BindStream(Reference PM_Port port,
Reference PM_Stream stream)
This method is called when a stream is connected to a port for the
first time. (It is assumed that it has already been determined that the
stream is valid to be connected to the port.)
Observe the following guidelines:
For most cases, check if the stream is a process stream. If it
is a non-process stream, simply return.
If changes (fix, free, change of phase) must be made to a
product stream, it is better to put them in UpdateLinks() or
CheckStructure().
GenerateEnergyBalanceReportSection()
Void GenerateEnergyBalanceReportSection
(Reference MilanoStream Report)
Override this function if a unit has changes in energy balance, or if
the requirement must be more specific than merely that all the
inputs must be equal to the outputs. Units with a duty or work
specification should override this function.
GenerateEstimates()
Integer GenerateEstimates()
The principal purpose of GenerateEstimates() is to initialize the
model with values that will enable the Solver to satisfy the
specifications and to make the problem feasible.
GenerateEstimates() affects only the L attribute
GenerateMaterialBalanceReportSection()
Void GenerateMaterialBalanceReportSection(Reference Milano-
Stream Report)
See comments on GenerateEnergyBalanceReportSection().
RemoveLinks()
Void RemoveLinks()
This function is used to remove link structures inside a unit. It is
called automatically when a unit is about to be turned OFF.
UpdateLinks()
Void UpdateLinks()
This function is used to create or update link structures inside a unit.
It is called automatically when a unit is about to be turned ON or a
stream connected to the unit is about to be ON.
Note: This applies mainly to linking variables from the unit and
from its connecting streams.
Link is a directional structure. In other words, a Link
should be made only from
1) upstream object to downstream object,
2) feed to unit,
3) unit to product, or
4) feed to product.
To comply with the On/Off feature, a unit should fix/free
only its own variables. If it is necessary to fix a variable in a
product stream, create a new variable inside the unit, link it
to the product stream variable, and then fix/free the local
variable.
It is strongly recommended that a unit not fix/free feed
stream variables.
UnBindStream()
Void UnBindStream(Reference PM_Port port,
Reference PM_Stream stream)
This method is called when a stream has already been removed
from the port. As a result, the stream reference from the argument
list is probably the only way to access the stream.
See comments on BindStream() method.
TotalEnergyInContribution()
Real TotalEnergyInContribution()
This function calculates the total energy added to the system. For
implementation, see page 5-26.
TotalEnergyOutContribution()
Real TotalEnergyOutContribution()
This function calculates the total energy removed from the system.
For implementation, see page 5-27.
TotalMaterialInContribution()
Real TotalMaterialInContribution()
This function calculates the total material added to the system.
TotalMaterialOutContribution()
Real TotalMaterialOutContribution()
This function calculates the total material removed from the system.
UpdatePropsChange()
Void UpdatePropsChange()
Component slate comments also apply to the property slate.
AssignComponentSlate()
Void AssignComponentSlate(String compSlateName)
PURPOSE: Assign component slate for a model.
INPUT: Component slate name.
AssignPropertySlate()
Void AssignPropertySlate(String propSlateName)
PURPOSE: Assign property slate for a model
INPUT: Property slate name
Connect()
Void Connect(Reference PM_Port port,Reference PM_Stream aa)
PURPOSE: Connect a stream to a port.
INPUT: References to stream and port.
Note: Call this function from the object that contains the port. If
this port is shared with more than one object, only one Connect is
permitted. Other objects need only BindStream().
CopyI2L()
Void CopyI2L()
PURPOSE: Copy variable value from I attribute to L attribute.
INPUT: None
CreateNonProcessPort()
Integer CreateNonProcessPort(String portName)
CurrentOnOffStatus()
Integer CurrentOnOffStatus()
PURPOSE: Get On/Off status of the model, this includes checking
parents.
OUTPUT: PMF_On, PMF_Off, PMF_Down
DisConnect()
Void DisConnect(Reference PM_Port port,Reference PM_Stream
aa)
PURPOSE: Disconnect a stream from a port.
INPUT: References to stream and port
Note: Call DisConnect() from the object that contains the port. If
the port is shared with more than one object, only one
DisConnect() is permitted. Other objects only need
UnBindStream(). Any connection made inside the model requires
corresponding disconnect either in PreDeletion() or in
Destructor().
displayProperties()
Void displayProperties(String primName)
PURPOSE: Display the property values for a given primitive
INPUT: Primitive name, and property name
EquipmentCopyI2L()
Void EquipmentCopyI2L(Integer Flag)
PURPOSE: Copy I to L or L to I for equipment and all the attached
streams
INPUT: 0 I to L
1 L to I
GetBlackBoxFlash()
Reference PM_BlackBoxFlash GetBlackBoxFlash()
PURPOSE: Flowsheet shared blackbox object
INPUT: None
RETURN: PM_BlackBoxFlash
getBooleanProperty ()
Integer getBooleanProperty(String primitiveName, String
propertyName)
PURPOSE: Get a property for a primitive in the model (only for boolean-
type prop)
INPUT: Primitive name, and property name
GetCompSlateName()
String GetCompSlateName()
PURPOSE: Get component slate name
OUTPUT: String
GetFlowsheet()
Reference PM_Flowsheet GetFlowsheet()
PURPOSE: Get a flowsheet reference
INPUT: None
RETURN: Returns (nearest) flowsheet reference, if it can access
flowsheet
NULL, if it cannot access flowsheet.
EXAMPLE: MyFlow = GetFlowsheet();
getModelStatus()
Integer getModelStatus()
PURPOSE: Get model's active/passive status
INPUT: None.
GetName()
String GetName()
PURPOSE: Get a short name of the object
INPUT: None
RETURN: Returns short name
Note: Some objects might not have short names. This function
should be used only if objects have been created by the
flowsheet.
GetParentFlowsheet()
Reference PM_Flowsheet GetParentFlowsheet()
PURPOSE: Get a flowsheet reference that is not itself, if it can access
flowsheet
INPUT: None
RETURN: Returns flowsheet reference
if it can access flowsheet;
NULL, if it cannot access flowsheet.
EXAMPLE: MyFlow = GetParentFlowsheet();
getProperty()
String getProperty(String primitiveName, String
propertyName)
PURPOSE: Get a property for a primitive in the model (only for string-
type prop).
INPUT: Primitive name and property name.
EXAMPLE: Dimension and UOM are properties.
GetPropSlateName()
String GetPropSlateName()
PURPOSE: Get property slate name
OUTPUT: String; "" if no property slate
GetThermoProperties()
Reference PM_ThermoProperties GetThermoProperties()
PURPOSE: Flowsheet shared ThermoProperties object.
INPUT: None.
RETURN: PM_ThermoProperties.
GetUOMDifferenceClass()
String GetUOMDifferenceClass(String sUOMClass)
PURPOSE: Get string that corresponds to the UOM difference of
sUOMClass.
INPUT: None.
RETURN: String.
EXAMPLE: For "Pres", the return value is "PresDiff".
GetUOMInverseClass()
GetUOMInverseClass()
PURPOSE: Get string that corresponds to the UOM Inverse of
sUOMClass.
INPUT: None.
RETURN: String.
IsA()
Integer IsA(String s1)
PURPOSE: Finds out if the object is of a certain class or if it is derived
from that class.
INPUT: String type; for example PM_Unit
RETURN: Returns
1 if this is the specified class
-1 if it is derived from the specified class
0 if it has no relation with it
EXAMPLE: If (thisObject:IsA(PM_Unit) == 0), Return ;
LogErrMsg()
Void LogErrMsg(String format, Vararg)
PURPOSE: Set message to transaction log as error.
INPUT: Same as print().
LogInfoMsg()
Void LogInfoMsg(String format, Vararg)
PURPOSE: Set message to transaction log as information.
INPUT: Same as print().
LogWarnMsg()
Void LogWarnMsg(String format, Vararg)
PURPOSE: Set message to transaction log as warning.
INPUT: Same as print().
MakePassive()
Void MakePassive()
PURPOSE: Make the model passive, that is, exclude it from math model.
INPUT: None
Note: This will exclude all submodels of the model from the
math model.
Parent()
Reference MilanoRootClass Parent()
PURPOSE: Return a reference to parent model
INPUT: None
RETURN: Returns flowsheet reference, if it can access flowsheet,
NULL, if it cannot access flowsheet.
print()
Void print(String format, Vararg)
PURPOSE: Print to the current system outStream
INPUT: Format, similar to C.
string
RETURN: None
PrintFeedsAndProds()
Void PrintFeedsAndProds(Reference MilanoStream Report)
PURPOSE: Print process feeds and products to Report; output print
stream.
INPUT: A valid MILANO out stream.
PrintThermoInfo()
Void PrintThermoInfo(Reference MilanoStream Report)
PURPOSE: Print component and property slate to report; output print
stream.
INPUT: A valid MILANO out stream.
PrintWarning()
Void PrintWarning(String modelName)
PURPOSE: Print warning to the end user
INPUT: Model full name
RETURN: None
setProperty ()
Void setProperty (String primitiveName, String
propertyName, String value)
PURPOSE: Set a property for a primitive in the model (only for string-
type prop).
INPUT: Primitive name, and property name.
EXAMPLE: Dimension and UOM are properties.
ValidateMessage()
Void ValidateMessage(Integer severity, String modelName)
PURPOSE: Print error/warning message in validation to the end user
INPUT: Severity level:
0, normally warning;
1, normally error;
Model full name.
RETURN: None.
// Component properties:
ThermoProperties:CompProps["Wt" ] = Yes; // Molecular weight
ThermoProperties:CompProps["CarbAtom" ] = Yes; // C number
ThermoProperties:CompProps["HydrAtom" ] = Yes; // H number
// Mixture properties:
* ThermoProperties:Props["Wt" ] = Yes; // Molecular weight
* ThermoProperties:Props["Enth"] = Yes; // Enthalpy
// Calculate properties.
// Note: Calculate() returns an error code.
// You can check against PMF_OK.
ThermoProperties:Calculate();
2. Data are needed for use at a later time: for example, when heat
of formation data are needed in the energy balance appearing in
the MathRelations section. The approach is to declare a Real
parameter to store these data.
Typical MILANO code would be:
// Save Heat of Formation for later use.
HForm[Comps] = ThermoProperties:CompProp["HeatForm",Comps];
The setup for these phase models is more complex than for constant
thermo properties since the phase models have their own set of
internal state variables. In parallel with the internal state variables,
there is a corresponding list of reference variables.
Example
The following segments of code show the implementation in the
conversion reactor model. In this example, we elected to have
actual state variables in the parent model. Since the desired
enthalpies are needed in the MathRelations, we also declare
variables for them in the parent model.
Declarations
// In this example we need to calculate the enthalpy of
// the Feed and Product streams AT THE REFERENCE
// CONDITION OF THE HEAT OF FORMATION. The reference
// temperature and pressure are both known and fixed,
// but the stream compositions are not known until the
// model has been solved. That means the required reference
// enthalpies are model VARIABLES.
//
// In this example we assume the entire reactor process,
// including input and output streams, occurs in the
// VAPOR phase. Thus, we use PM_VaporPhase models to
// calculate the necessary reference enthalpies. If
// other phases were involved, we would use models
// of type PM_LiquidPhase and PM_Liquid2Phase as needed.
// In all cases, the setup is handled the same way.
//
// Further understanding of how setup for Modular
// Thermo works: In the energy balance we also need the
// enthalpy of the Feed and Product streams at their
// actual conditions. However, we do NOT create phase
// models for these enthalpies because the
// PM_ProcessStream models already handle that. All we
// must do is retrieve the values directly from the
// stream variable, for example,
PM_VaporPhase refPhase[PortStreamPairs]
<<NonSparse,SubModel>>;
MathRelations
// On Energy balance.
//
// Duty = (HFeedAtRefCond - HFeedAtFeedCond) + HRx
// +(HProdAtProdCond - HProdAtRefCond )
// where:
// HRx = Sum([Comps], stoich[Comps]*HForm[Comps])
// *v_reactionRate
// and "RefCond" is the reference condition used to
// calculate the heat of formation (25 C, 1 atm).
//
// Rearranging:
//
// Duty - HRx
// - (HProdAtProdCond - HProdAtRefCond)
// + (HFeedAtFeedCond - HFeedAtRefCond)
// = 0
//
e_EBal..
v_Q - Sum([Comps], stoich[Comps]*HForm[Comps])
*v_reactionRate
- ( InputOutputStream["Product"]:Prop["Enth"]
- v_refEnth["Product"]
)*InputOutputStream["Product"]:MolarFlow
+ ( InputOutputStream["Feed"]:Prop["Enth"]
- v_refEnth["Feed"]
)*InputOutputStream["Feed"]:MolarFlow
=E= 0;
//
// For a detailed discussion of the derivation of the
// the energy balance equation e_EBal, see page 5-15.
Bindings
Bindings are done in CheckStructure() for the efficiency rea-
sons mentioned on page 2-12.
Degrees of freedom
Specify .FXI for Temp and Pres in Initialize().
v_refTemp.FXI = True; // User should NOT change.
v_refPres.FXI = True; // User should NOT change.
MI_blockGetCount()
long MI_blockGetCount(long hModel, const char* blockName)
PURPOSE: Get number of entries in a block (e.g., parameter, variable).
INPUT: hModel 32-bit handle identifying the model
object.
blockName pointer to a string containing the name of the
block.
RETURN: Number of entries in the block.
MI_deleteMemory_domainGetAllElems()
void MI_deleteMemory_domainGetAllElems
(const char** dataArray)
PURPOSE: Delete memory previously allocated in
MI_domainGetAllElems() routine.
INPUT: dataArray the data array returned in
MI_domainGetAllElems() routine.
RETURN: None.
MI_deleteMemory_getStringInAtom()
void MI_deleteMemory_getStringInAtom(const char* data)
PURPOSE: Deletes memory previously allocated in MI_getString()
routine.
INPUT: data data array returned in MI_getString().
RETURN: None.
MI_deleteMemory_getStringValue()
void MI_deleteMemory_getStringValue(const char* data)
PURPOSE: Delete memory previously allocated in
MI_getStringValue().
INPUT: data data array returned in MI_getStringValue().
RETURN: None.
MI_domainDelElem()
void MI_domainDelElem(long hModel, const char* setName,
const char* element)
PURPOSE: Delete an element from a set.
INPUT: hModel a 32-bit handle identifying the model object.
setName pointer to a string containing the name of the set.
element pointer to a string containing the element to be
deleted.
RETURN: None.
MI_domainGetAllElems()
const char** MI_domainGetAllElems(long hModel,
const char* setName)
PURPOSE: Get all elements of a set.
INPUT: hModel a 32-bit handle identifying the model object.
setName pointer to a string containing the name of the set.
RETURN: Pointer to an array of String pointers. Each string contains one
element of the set.
NOTE: User must call the memory cleanup routine
MI_deleteMemory_domainGetAllElems().
MI_domainGetCount()
long MI_domainGetCount(long hModel,
const char* setName)
PURPOSE: Get the number of elements in set.
INPUT: hModel a 32-bit handle identifying the model object.
setName pointer to a string containing the name of the set.
RETURN: Number of elements in the set.
MI_getFullName()
const char* MI_getFullName(long hModel)
PURPOSE: Get name of the model object.
INPUT: hModel a 32-bit handle identifying the model object.
RETURN: Pointer to a string containing the name.
MI_getIntegerInAtom()
MI_getRealInAtom()
MI_getStringInAtom()
MI_getLongInAtom()
long MI_getIntegerInAtom(MIUserAtom thisAtom)
double MI_getRealInAtom(MIUserAtom thisAtom)
const char* MI_getStringInAtom(MIUserAtom thisAtom)
long MI_getModelHandleInAtom(MIUserAtom thisAtom)
PURPOSE: Get integer/real/string/long(ModelHandle) value
contained in a MIUserAtom. The MIUserAtom must have
been created with the proper type of data value.
INPUT: thisAtom an MIUserAtom.
RETURN: The integer/real/string/long(ModelHandle) value of
the MIUserAtom.
NOTE: For string type, you must call function
MI_deleteMemory_getString() to delete memory for the
string.
MI_isA()
int MI_isA(long hModel, const char* searchType)
PURPOSE: Determine if model is of a specified class or derived
therefrom.
INPUT: hModel a 32-bit handle identifying the model object.
searchType pointer to a string containing the specified
class.
RETURN: 1 if model is of the specified class
-1 if model is derived from the specified class
0 if model has no relation with the specified class
MI_print()
void MI_print(int level, const char* printString,
int Server)
PURPOSE: Send messages to transaction log or to standard out.
INPUT: level level of message:
1 information
2 warning
3 error
printString string to be output.
Server destination of message:
0 message to be printed to standard output
1 message to be printed to server transaction log
MI_setAttr()
void MI_setAttr(long hModel, const char* blockName,
const char* rowElements, long attrNum,
MIUserAtom value)
PURPOSE: Set value of an attribute of a row in a block.
INPUT: hModel a 32-bit handle identifying the model object,
blockName pointer to a string containing the name of the
block,
rowElements pointer to a string. The string contains set
elements for the row in comma-separated form,
attrNum number of the attribute,
value an MIUserAtom containing the attribute value.
RETURN: None.
MI_setIntegerValue()
MI_setRealValue()
MI_setStringValue()
void MI_setIntegerValue(long hModel, const char* blockName,
const char* rowElements, long value)
void MI_setRealValue(long hModel, const char* blockName,
const char* rowElements, double value)
void MI_setStringValue(long hModel, const char* blockName,
const char* rowElements, const char* value)
PURPOSE: Set value of a row in a PARAMETER (i.e., Integer, Real,
String) block.
INPUT: hModel a 32-bit handle identifying the model
object
blockName pointer to a string containing the name of the
block
rowElements pointer to a string. The string contains set
elements for the row in comma-separated form
value long/double/string containing the value
RETURN: None.
Note: Special logic applies to the use of the Dim and UOM
attributes. These two attributes can only be accessed if the
dimension property on the primitive is set to the string "RowBased".
Thus, such a variable would be declared as follows:
Variable v_myVar <<Dim=RowBased>>;
An exception occurs if the Dim and UOM attributes are being
accessed (both read from as well as written to) for a variable that
does not have a RowBased dimension property.
Example
The C++ code for the conversion reactor Black Box Model provides various examples of
method calls into the model and attribute values. Here we show only one code fragment.
Context: A MILANO Real parameter is used to set a temperature value. The C++
code for the Black Box Model will retrieve this value, along with other attributes.
Then the value will be reset. Notice the use of various "UOM" attributes.
MILANO declaration:
//--------------------------------------------------------------------------------------
Real wrapTemp <<Dim=Temp,InitialValue=298.15>>
"A temperature Real block";
//--------------------------------------------------------------------------------------
MIMOprocessUnitTemplate.milimplements class
MIMOoNothingTemplate
Icon data file - The SIMSCI distribution also includes a GUI DLL
and corresponding icon data files for the various feed/product port
configurations:
UIGenericUnitIcon.dat used to develop the port configuration
for the custom model
SISOIcon.dat provides port configuration for SISO model
SIMO1x3Icon.dat provides port configuration for SIMO
model
MIMO3x2Icon.dat provides port configuration for MIMO
model
MISO3x1Icon.dat provides port configuration for MISO
model
If the custom model requires a different port configuration, you
must create a suitable icon data file. Instructions for modifying an
icon data file are found in Modifying the Icon Data File, 7.7.
Model generality - Is the model meant to describe a given, fixed,
reaction or a general reaction? Our example code illustrates the
Chapter 5
Part 2: Sample Code
//----------------------------------------------------------------------
//
BeginSection Declarations;
//
//Use v_ prefix to make variables easier to recognize
//Use l_ prefix to make linked variables easier to recognize
//Use e_ prefix to make equations easier to recognize
// UOM at runtime.
//
// On <<Hidden>> property
// Most "internal" parameters and variables
// should be declared <<Hidden>> so they don't show up in the Model
// General Data Access Window (GDAW or also simply the GUI).
//
// User input -------------------------------------------
// v_PressureDrop will appear in the GUI under Variables/Scalar
//
Variable <<DataType=PMF_ExtVarRow>> v_PressureDrop
<<Dim=PresDiff,InitialValue=0.0>>;
// --------------------------------------------
// Start setup MT Constant properties
//
// This section handles thermodynamic properties that don't
// change at solve time, e.g., pure-component
// molecular weights, heats of formation, carbon numbers, etc.
//-----------------------------------------------------------
// Start MT Variable properties
//
// This section handles thermodynamic properties that change at
// runtime (that is, during Solve), e.g., mixture enthalpy.
//
// Background:
//
// In this example we need to calculate the enthalpy of
// the Feed and Product streams at the reference
// condition of the heat of formation. The reference
// temperature and pressure are both known and fixed,
// but the stream compositions will not be known until the
// model is solved. That means the required reference
// enthalpies are model variables.
//
// In this example we assume the entire reactor process,
// including input and output streams, occurs in the
// vapor phase. Thus, we use PM_VaporPhase models to
// calculate the necessary reference enthalpies. If
// other phases were involved, we would also use models
// of type PM_LiquidPhase and PM_Liquid2Phase as needed.
// In all cases, the setup is handled the same way.
//
// Further about Modular Thermo setup:
// In the energy balance, we also need the
// enthalpy of the Feed and Product streams at their
// actual conditions. However, we do NOT create phase
// models for these enthalpies because the
// PM_ProcessStream model already handles that. All we
// have to do is retrieve the values directly from the
// stream variable, e.g.,
//
// InputOutputStream["Feed"]:Prop["Enth"]
//
// In fact, through ROMeo the end user can specify
// runtime properties for each stream. Each of these
// properties is then available for use in the model
// using the construct:
//
// InputOutputStream["portName"]:Prop["propName"]
// Links
//
//
// Equations
//
Equation e_Pres;
Equation e_ReactionRate;
Equation e_NetReaction;
Equation e_Flow;
Equation e_MBal[Comps];
Equation e_EBal;
Equation e_refEnth[PortStreamPairs] <<NonSparse>>;
//
// UOM Test items: To illustrate some UOM functionality.
// Note: This is for demonstration only and has nothing
// to do with the conversion reactor model per se.
// Flag doUomTest is used to enable/disable
// execution of the test code that appears in
// CheckStructure(). Initially the test code is
// enabled. However, you can go to GUI Parameters/Scalar to disable
// execution:
// doUomTest = 0 : Disable demo code execution.
// = 1 : Enable demo code execution.
// For Demo Code for UOM Features, see page 5-74.
Integer <<DataType=PMF_ExtIntRow>>
doUomTest <<InitialValue=1>>; // Flag for use appears in GUI.
// Recall: 298.15K = 25C = 77F
Real <<DataType=PMF_ExtRealRow>> uomTestTemp
<<Hidden,Dim=Temp,UOM=F,InitialValue=298.15>>;
Real <<DataType=PMF_ExtRealRow>> uomTestuomReal <<Hidden>>;
String <<DataType=PMF_ExtStringRow>> uomTestInternalUOM <<Hidden>>;
String <<DataType=PMF_ExtStringRow>> uomTestuomReport <<Hidden>>;
MilanoUOM myUOM; // Provides support for UOM conversions.
//
// Methods
//
DeclareMethod Void Initialize();
DeclareMethod Void UpdateLinks();
DeclareMethod Void RemoveLinks();
DeclareMethod Integer CheckStructure();
//----------------------------------------------------------------------
//
BeginSection Events;
//
//----------------------------------------------------------------------
// For details on the following events, see Milano Users Guide,
// A.1.8, Reference Set Bind, A.1.3, Set Element Addition, and
// A.1.4, Set Element Deletion.
Event PostSetBind On Comps Calls BindMoleFracEvent;
Event PostSetAdd On Comps Calls BindMoleFracEvent;
Event PostSetDelete On Comps Calls BindMoleFracEvent;
EndSection Events;
//----------------------------------------------------------------------
//
BeginSection MathRelations;
//
//----------------------------------------------------------------------
e_Pres..
InputOutputStream["Product"]:Pres - InputOutputStream["Feed"]:Pres
+ v_PressureDrop =E= 0;
e_NetReaction..
v_netReaction - Sum([Comps], stoich[Comps])*v_reactionRate =E= 0;
e_Flow..
InputOutputStream["Product"]:MolarFlow
- InputOutputStream["Feed"]:MolarFlow
- v_netReaction =E= 0;
// On Energy balance.
//
// When calculating the energy balance, we will use the
// MILANO version for both the all-MILANO and Black Box Model
// classes. (See page 5-32.) This is because only
// v_Q is available as an implicit variable. However,
// if the reactor is adiabatic, then v_Q must be fixed to
// 0, which would not be allowed if it were an implicit
// variable. Since using a BBM is equivalent to treating its
// output variables as though they were implicit variables in
// MILANO, we conclude that the energy balance is not a
// good candidate to go into the BBM.
// For more about implicit variables and implicit equations,
// see MILANO Users Guide Implicit Variables, 7.3.3 and
// Implicit Equations, 7.4.5.
// For the treatment of the energy balance and
// the duty variable v_Q in the EEB MILANO code,
// and the output duty variable in the EEB CPP code,
// see page 5-56 and page 5-67, respectively.
//
// Duty = (HFeedAtRefCond - HFeedAtFeedCond) + HRx
// +(HProdAtProdCond - HProdAtRefCond )
//
// where:
//
// HRx = Sum([Comps], stoich[Comps]*HForm[Comps])*v_reactionRate
//
// and "RefCond" is the reference condition used to
// calculate the heat of formation (25 C, 1 atm).
// (See variables v_refTemp and v_refPres, page 5-12.)
//
// Rearranging:
//
// Duty - HRx
// - (HProdAtProdCond - HProdAtRefCond)
// + (HFeedAtFeedCond - HFeedAtRefCond)
// = 0
e_EBal..
v_Q - Sum([Comps], stoich[Comps]*HForm[Comps])*v_reactionRate
- ( InputOutputStream["Product"]:Prop["Enth"]
-v_refEnth["Product"]
)*InputOutputStream["Product"]:MolarFlow
+ ( InputOutputStream["Feed"]:Prop["Enth"]
-v_refEnth["Feed"]
)*InputOutputStream["Feed"]:MolarFlow
=E= 0;
EndSection MathRelations;
//----------------------------------------------------------------------
//
BeginMethod Void Initialize();
//
// Use keyword Super to invoke base class of current model.
Super:Initialize();
//----------------------------------------------------------------------
//
BeginMethod Void BindMoleFrac();
//
Loop [PortStreamPairs], {
Loop [Comps], {
refPhase[PortStreamPairs]:RefMoleFrac[Comps]
= InputOutputStream[PortStreamPairs]:MoleFrac[Comps];
};
};
EndMethod BindMoleFrac;
//----------------------------------------------------------------------
//
BeginMethod Void BindMoleFracEvent(Reference MilanoEvent evObj );
//
BindMoleFrac();
EndMethod BindMoleFracEvent;
//----------------------------------------------------------------------
//
BeginMethod Void UpdateLinks();
//
// Use keyword Super to invoke base class of current model.
Super:UpdateLinks();
//----------------------------------------------------------------------
//
BeginMethod Void RemoveLinks();
//
//----------------------------------------------------------------------
// Use keyword Super to invoke base class of current model.
Super:RemoveLinks();
UnLink l_Temp;
EndMethod RemoveLinks;
//----------------------------------------------------------------------
//
BeginMethod Integer GetState();
//
//----------------------------------------------------------------------
// GetState() tasks:
// The most common tasks performed in GetState() are:
// (1) Verify degrees of freedom
// (2) Verify completeness of specifications
// (3) Verify input/output stream phase requirements due
// to specifications. For details, see GetState(), page 2-13.
// GetState() is also called by GenerateEstimates(),
// GenerateSolution(), and GenerateReport(), page 2-14.
// Use keyword Super to invoke base class of current model.
If (Super:GetState() NE PMF_OK) , Return PMF_Error;
GetState_rv = PMF_OK;
If (NOT v_PressureDrop.FXI),
{
print("%-40s:\n", GetName());
print(" GetState - Error: v_PressureDrop should be fixed.\n");
GetState_rv = PMF_Error;
};
If (Card(Comps) == 0), {
print("%-40s:\n", GetName());
print(" GetState - Error: Component set Comps is empty.\n");
print(" GetState - Action: Specify component and component
slate(s).\n");
GetState_rv = PMF_Error;
Return GetState_rv; // Error is bad enough to justify a Return!
};
If (baseComponent == ""),
{
print("%-40s:\n", GetName());
print(" GetState - Error: baseComponent is not set.\n");
GetState_rv = PMF_Error;
}
Else // Check that baseComponent matches one component.
{ // (At this point set Comps is non-empty, from earlier check.)
Ctr = 0;
Loop [Comps], {Ctr = Ctr + 1$(Comps.Label == baseComponent)};
If (Ctr == 0), {
print("%-40s:\n", GetName());
print(" GetState - Error: baseComponent does not match any
component name.\n");
print(" GetState - Action: Check spelling of baseComponent.\n");
GetState_rv = PMF_Error;
}
Else { // Check for nonzero stoich[baseComponent].
If (stoich[baseComponent] == 0), {
print("%-40s:\n", GetName());
print(" GetState - Error: stoich[baseComponent] cannot be
zero.\n");
GetState_rv = PMF_Error;
}
};
};
Return GetState_rv;
EndMethod GetState;
//----------------------------------------------------------------------
BeginMethod Integer CheckStructure();
//
// Called after GetState(), before generating estimates and before
// generating solution. Should be used to perform time-consuming checks
// and make any data modifications that may be required.
//----------------------------------------------------------------------
GetState_rv = PMF_OK;
// Make sure that all the dependent properties are being calculated
If (GetState_rv EQ PMF_OK), {
AbsStoich = Abs(stoich[baseComponent]);
HReaction = Sum([Comps], stoich[Comps]*HForm[Comps])/AbsStoich;
};
Return GetState_rv;
EndMethod CheckStructure;
//----------------------------------------------------------------------
//
BeginMethod Integer GenerateEstimates() ;
//
//----------------------------------------------------------------------
// GenerateEstimates() tasks
// GenerateEstimates() initializes the model with
// values that will allow the Solver to satisfy the
// specifications and to make the problem feasible.
// See Glossary entry "Feasibility".
v_reactionRate.L = 0.5*InputOutputStream["Feed"]:MolarFlow.L
*v_conversion.L
*InputOutputStream["Feed"]:MoleFrac.L[baseComponent]
/Abs(stoich[baseComponent]);
If (InputOutputStream["Product"] NE NULL),
{
InputOutputStream["Product"]:Pres.L =
InputOutputStream["Feed"]:Pres.L
- v_PressureDrop.L;
InputOutputStream["Product"]:MolarFlow.L
= InputOutputStream["Feed"]:MolarFlow.L
+ v_netReaction.L;
InputOutputStream["Product"]:MoleFrac.L[Comps]
= compFlow/InputOutputStream["Product"]:MolarFlow.L;
};
If (isAdiabatic), {
InputOutputStream["Product"]:Temp.L =
InputOutputStream["Feed"]:Temp.L;
v_Q.L = 0;
};
If (InputOutputStream["Product"]:GenerateEstimates() NE PMF_OK),
Return PMF_Error;
};
Return PMF_OK;
EndMethod GenerateEstimates;
//----------------------------------------------------------------------
//
BeginMethod Void GenerateReport (Reference MilanoStream Report);
//
//----------------------------------------------------------------------
// Note that MilanoStream is an I/O (as in read and write)
// object (I/O stream), not a process stream!
Report:print("\n");
Report:print("Reactor Set Up:\n");
Report:print(" %-17s %d %s\n" ,"isAdiabatic", isAdiabatic, "
(0=No, 1=Yes)");
Report:print(" %-17s %-10s\n","baseComponent", baseComponent);
Report:print("\n");
Report:print(" %-12s %6s %10s\n", "Component", "stoich",
" HForm");
Report:print(" %-12s %6s %10s\n", "---------", "------",
"--------");
Loop [Comps], {
Report:print(" %-12s %6g %10g %s\n"
,Comps.Label,stoich[Comps],HForm.uomRealVal[Comps],
HForm.uomReport[Comps]);
};
Report:print("\n");
Report:print(" %-21s %10g %s\n"
,"HReaction (1 mol bC)"
, HReaction.uomRealVal, HReaction.uomReport);
Report:print("\n");
Report:print("PortStreamPairs:\n");
Loop [PortStreamPairs], {
Report:print(" %-13s\n", PortStreamPairs.Label);
Report:print(" Stream : %s\n"
,InputOutputStream[PortStreamPairs]:GetFullName());
Report:print(" Temp : %10g %s\n"
,InputOutputStream[PortStreamPairs]:Temp.uomL
,InputOutputStream[PortStreamPairs]:Temp.uomReport);
Report:print(" Pres : %10g %s\n"
,InputOutputStream[PortStreamPairs]:Pres.uomL
,InputOutputStream[PortStreamPairs]:Pres.uomReport);
Report:print(" Enth@Stream : %10g %s\n"
,InputOutputStream[PortStreamPairs]:Prop.uomL ["Enth"],
InputOutputStream[PortStreamPairs]:Prop.uomReport["Enth"]);
Report:print(" Enth@RefCond: %10g %s\n"
,v_refEnth.uomL [PortStreamPairs]
,v_refEnth.uomReport[PortStreamPairs]);
Report:print(" MolarFlow : %10g %s\n"
,InputOutputStream[PortStreamPairs]:MolarFlow.uomL
,InputOutputStream[PortStreamPairs]:MolarFlow.uomReport);
Report:print(" MoleFrac :\n");
Loop [Comps], {
Report:print(" %10s %10g\n"
,Comps.Label
,InputOutputStream[PortStreamPairs]:MoleFrac.uomL[Comps]);
};
};
Report:print("\n");
Report:print("%-15s%20s%20s%15s\n","","Initial Value",
"Final Value", "UOM");
Report:print("%-15s%20g%20g%15s\n","v_reactionRate"
,v_reactionRate.uomI
,v_reactionRate.uomL
,v_reactionRate.uomReport);
Report:print("%-15s%20g%20g%15s\n","v_netReaction"
,v_netReaction.uomI
,v_netReaction.uomL
,v_netReaction.uomReport);
Report:print("%-15s%20g%20g%15s\n","Pressure Drop"
,v_PressureDrop.uomI
,v_PressureDrop.uomL
,v_PressureDrop.uomReport);
Report:print("%-15s%20g%20g%15s\n","Heat Duty"
,v_Q.uomI
,v_Q.uomL
,v_Q.uomReport);
Report:print("%-15s%20g%20g%15s\n","Reactor Temp"
,InputOutputStream["Product"]:Temp.uomI
,InputOutputStream["Product"]:Temp.uomL
,InputOutputStream["Product"]:Temp.uomReport);
Report:print("%-15s%20g%20g%15s\n","Conversion"
,v_conversion.uomI
,v_conversion.uomL
,v_conversion.uomReport);
Report:print("%-15s\n" ,"v_refEnth:");
Loop [PortStreamPairs], {
Report:print(" %-13s%20g%20g%15s\n",PortStreamPairs.Label
,v_refEnth.uomI [PortStreamPairs]
,v_refEnth.uomL [PortStreamPairs]
,v_refEnth.uomReport[PortStreamPairs]);
};
InputOutputStream["Product"]:GenerateReport(Report);
EndMethod GenerateReport;
//----------------------------------------------------------------------
//
BeginMethod Void CalculateEnergyTerms();
//
//----------------------------------------------------------------------
TotHReaction = Sum([Comps],
stoich[Comps]*HForm[Comps])*v_reactionRate.L;
EndMethod CalculateEnergyTerms;
//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyInContribution();
//
//----------------------------------------------------------------------
// TotalEnergyInContribution()
//PENDING: Explain what we do here; purpose of this method.
CalculateEnergyTerms();
LocalEnergyIn = TotHReactionIn
+HeatDutyIn
-v_refEnth.L["Feed"]
*InputOutputStream["Feed"]:MolarFlow.L
;
Return LocalEnergyIn;
EndMethod TotalEnergyInContribution;
//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyOutContribution();
//
//----------------------------------------------------------------------
CalculateEnergyTerms();
LocalEnergyOut= TotHReactionOut
+HeatDutyOut
-v_refEnth.L["Product"]
*InputOutputStream["Product"]:MolarFlow.L
;
Return LocalEnergyOut;
EndMethod TotalEnergyOutContribution;
//----------------------------------------------------------------------
//
BeginMethod Void GenerateEnergyBalanceReportSection(Reference
MilanoStream Report);
//
//----------------------------------------------------------------------
// Method Void GenerateEnergyBalanceReport() is
// implemented in a base class (PM_ProcessUnit).
//
// This method provides a general utility for
// generating an Energy balance report for a process
// unit. It creates a table containing the energy
// rates for all the feed and product process streams.
// It calls GenerateEnergyBalanceReportSection(),
// allowing a particular unit operation to contribute
// additional lines to the report. The Real
// LocalEnergy is used to display the values in the
// current default UOM for Energy/Time. The Real
// values TotalEnergyOut and TotalEnergyIn are used to
// keep track of the totals and should be modified by
// process units that contribute a section to this
// report (the Energy balance report).
TotalEnergyInContribution();
Report:print("%-40s","Heat of Reaction");
If (TotHReaction LT 0), {
Report:print("%-#20.4g\n" , TotHReactionIn.uomRealVal);
} Else {
Report:print("%-20s%-#20.4g\n","", TotHReactionOut.uomRealVal);
};
Report:print("%-40s","Heat Duty");
If (v_Q.L GT 0), {
Report:print("%-#20.4g\n" , HeatDutyIn.uomRealVal);
} Else {
Report:print("%-20s%-#20.4g\n","", HeatDutyOut.uomRealVal);
};
EndMethod GenerateEnergyBalanceReportSection;
//----------------------------------------------------------------------
EndModel ConvReactor;
//----------------------------------------------------------------------
//
BeginSection Declarations;
//
// With the few exceptions as noted below,
// the Declarations section of ConvReactorBBM.mil is identical
// to that of ConvReactor.mil. For code and comments
// common to both models, see Declarations, page 5-7.
//
// CPPBlockAddr is used to save the address of the "setup
// class defined in the C++ DLL code. We declare it CPPBlockAddr
// <<Hidden>> because the end user at runtime need not care about
// its value. Although we initialize CPPBlockAddr to zero,
// it is not important because the C++ code takes full
// control and responsibility over its value.
// Since in our example only a single BBM or the
// EEB representation can be selected at a time, but not both, we
// use a single parameter to keep track of the "setup"
// object's address. But if we had, say two BBM
// components in the MathRelations, then we would
// declare one such Integer parameter for each BBM.
// Keep in mind that the names used here will be used
// in the C++ code.
// CPPBlockAddr is <<Hidden>> so it will not appear in the GUI.
//
Integer <<DataType=PMF_ExtIntRow>>
CPPBlockAddr <<Hidden,InitialValue=0>>;
//
// Start of Modular Thermo Constant properties setup.
// Declaration of Modular Thermo Constant properties, is identical
// in both models. See page 5-10.
// End of Modular Thermo Constant properties setup.
// -------------------------------------------
//
// Start of Modular Thermo Variable properties setup.
// Declaration of Modular Thermo Variable properties, is identical
// in both models. See page 5-10.
// End of Modular Thermo Variable properties setup.
//
// -------------------------------------------
//
// Energy Balance Report is identical
// in both models. See page 5-15.
//------------------------------------------------------------------
//
// Data structures to illustrate use of wrapper functions
// available when writing BBM and EEB C++ code.
// The contents of wrapSet1 and wrapTemp can be changed
// from the C++ code. Thus Cubs and Rangers are commented out,
// but they (or any others that might be needed)
// can be added from the C++ section, while the items initally included
// in the MILANO model can be deleted.
// See Adding and Deleting Elements, page 5-45.
// (This example has been included only for demonstration; it has nothing
// to do with the conversion reactor model per se.)
//
Set wrapSet1 <<Hidden>> "Baseball Teams"
/ Astros, Padres, Braves, Yankees, RedSox, Indians /;
* Cubs, Rangers,
Real <<DataType=PMF_ExtRealRow>> wrapTemp
<<Hidden,Dim=Temp,InitialValue=298.15>> "Temperature Real block";
//------------------------------------------------------------------
//
// See Links, page 5-12, for comments.
Link l_Temp;
//------------------------------------------------------------------
//
// Equations
// Note that ConvReactorBBM.mil declares only e_EBal and e_refEnth.
// To compare the listing of equations in ConvReactor.mil, see page 5-13.
// The values calculated by e_Pres, e_ReactionRate, e_NetReaction,
// e_Flow and e_MBal[Comps] in the all-MILANO model are calculated here
// by the Black Box.
Equation e_EBal;
Equation e_refEnth[PortStreamPairs] <<NonSparse>>;
//
/------------------------------------------------------------------
// Methods
// The same methods are declared in both models. See page 5-13.
//
EndSection Declarations;
//----------------------------------------------------------------------
//
BeginSection Events;
// The Events section is identical in both models. See page 5-14.
//
EndSection Events;
//----------------------------------------------------------------------
//
BeginSection MathRelations;
//
//----------------------------------------------------------------------
m_rxnModel ..
{
// Order of variables in Input and Output
// statements must be matched in the C++ code.
};
*++++++++++++++++++++++++++++++++++++++++++++++++
* PSEUDOCODE FOR C++ VERSION OF BLACK BOX MODEL EQUATIONS
* --------------------------------------------------------
* (HELPS WRITE C++ CODE FOR DLL.)
*
* e_Pres..
* ProdPres = FeedPres - PresDrop;
*
* d ProdPres
* ---------- = -1
* d PresDrop
*
* d ProdPres
* ---------- = 1
* d FeedPres
*
*
* e_ReactionRate..
* Let AbsStoich = Abs(stoich[baseComponent]);
* // [bC] = [baseComponent]
* v_reactionRate = v_conversion*FeedMolarFlow*FeedMoleFrac[bC]
/AbsStoich; // See AbsStoich, page 5-14.
*
* d v_reactionRate
* ---------------- = FeedMolarFlow*FeedMoleFrac[bC]/AbsStoich;
* d v_conversion
*
* d v_reactionRate
* ---------------- = v_conversion*FeedMoleFrac[bC]/AbsStoich;
* d FeedMolarFlow
*
* d v_reactionRate
* ------------------ = v_conversion*FeedMolarFlow/AbsStoich;
* d FeedMoleFrac[bC]
*
*
* e_NetReaction..
* v_netReaction = Sum([Comps], stoich[Comps])*v_reactionRate;
*
* d v_netReaction d v_reactionRate
* ----------------- = Sum([Comps], stoich[Comps]) * ----------------
* d v_conversion d v_conversion
*
* d v_netReaction d v_reactionRate
* ----------------- = Sum([Comps], stoich[Comps]) * ----------------
* d FeedMolarFlow d FeedMolarFlow
*
* d v_netReaction d v_reactionRate
* ----------------- = Sum([Comps], stoich[Comps]) * ----------------
* d FeedMoleFrac[bC] d FeedMoleFrac[bC]
*
*
* e_Flow..
* ProdMolarFlow = FeedMolarFlow + v_netReaction;
*
* d ProdMolarFlow d v_netReaction
* --------------- = ---------------
* d v_conversion d v_conversion
*
* d ProdMolarFlow d v_netReaction
* --------------- = 1 + ---------------
* d FeedMolarFlow d FeedMolarFlow
*
* d ProdMolarFlow d v_netReaction
* ------------------ = ------------------
* d FeedMoleFrac[bC] d FeedMoleFrac[bC]
*
*
* // e_MBal - IMPLICIT form:
* e_MBal[Comps] $(Ord(Comps) NE Card(Comps))..
* ProdMoleFrac[Comps] =
* BeginCase
* Case(ProdMolarFlow NE 0.0)
* (
* FeedMoleFrac[Comps]*FeedMolarFlow + stoich[Comps]*v_reactionRate
* )
* / ProdMolarFlow
* EndCase
* ;
*
EndSection MathRelations;
//----------------------------------------------------------------------
//
BeginMethod Void Initialize();
//
// Implementation of Initialize()
// in ConvReactorBBM.mil is identical to
// that in ConvReactor.mil. See page 5-16, for code and comments.
EndMethod Initialize;
//----------------------------------------------------------------------
//
BeginMethod Void BindMoleFrac();
//
// Implementation of BindMoleFrac()
// in ConvReactorBBM.mil is identical to
// that in ConvReactor.mil. See page 5-16, for code and comments.
EndMethod BindMoleFrac;
//----------------------------------------------------------------------
//
BeginMethod Void BindMoleFracEvent( Reference MilanoEvent evObj );
//
//----------------------------------------------------------------------
BindMoleFrac();
EndMethod BindMoleFracEvent;
//----------------------------------------------------------------------
//
BeginMethod Void UpdateLinks();
//
// Implementation of UpdateLinks() in ConvReactorBBM.mil
// is identical to that in ConvReactor.mil.
// See page 5-17, for code and comments.
EndMethod UpdateLinks;
//----------------------------------------------------------------------
//
BeginMethod Void RemoveLinks();
//
// Use keyword Super to invoke base class of current model.
// Implementation of RemoveLinks() identical to ConvReactor.mil.
// See page 5-18. Because of brevity code repeated here.
Super:RemoveLinks();
UnLink l_Temp;
EndMethod RemoveLinks;
//----------------------------------------------------------------------
//
BeginMethod Integer GetStateWrapper(Integer ToDo);
//
// Illustrative method to show use of MI_runMethod() in PMFWrapper.lib
// (called from C++ code for BBM). See page 5-44.
//----------------------------------------------------------------------
If (ToDo ==1) , {Return GetState();}
Else {Return 0;};
EndMethod GetStateWrapper;
//----------------------------------------------------------------------
//
BeginMethod Integer GetState();
// Implementation of GetState() in ConvReactorBBM.mil is identical
// to that in ConvReactor.mil. See page 5-18, for code and comments.
EndMethod GetState;
//----------------------------------------------------------------------
//
BeginMethod Integer CheckStructure();
//
// Implementation of CheckStructure() in ConvReactorBBM.mil is
// identical to
// that in ConvReactor.mil. See page 5-19, for code and comments.
EndMethod CheckStructure;
//----------------------------------------------------------------------
//
//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyInContribution();
//
// Implementation of TotalEnergyInContribution() in
// ConvReactorBBM.mil is identical to that in ConvReactor.mil.
// See page 5-26 for code and comments.
EndMethod TotalEnergyInContribution;
//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyOutContribution();
//
// Implementation of TotalEnergyOutContribution() in
// ConvReactorBBM.mil is identical to that in ConvReactor.mil.
// See page 5-27 for code and comments.
EndMethod TotalEnergyOutContribution;
//----------------------------------------------------------------------
//
BeginMethod Void GenerateEnergyBalanceReportSection(Reference
MilanoStream Report);
//
// Implementation of GenerateEnergyBalanceReportSection() in
// ConvReactorBBM.mil is identical to that in ConvReactor.mil.
// See page 5-27 for code and comments.
EndMethod GenerateEnergyBalanceReportSection;
//----------------------------------------------------------------------
EndModel ConvReactorBBM;
#ifndef CONVREACTOR_BBM_H_INCLUDED
#define CONVREACTOR_BBM_H_INCLUDED
//----------------------------------------------------------------------
// C++ Source Code Black Box Model Header File ConvReactorBBM.h
//
// Project : ROMeo
// Subsystem : Process Model
//
// Date : 9/14/98
// Purpose : Support functions BBM and EEB
// DLL code.
//
// Copyright (c) 1998 by Simulation Sciences Inc
// ALL RIGHTS RESERVED
//----------------------------------------------------------------------
//
// Define a class for keeping track of setup information.
//
// The class definition depends on each particular BBM or EEB.
// This comes from the need to allow the possibility of having
// more than one instance of the reactor (or whatever process
// unit it is) in the flowsheet. Since the DLL code is shared
// by ALL instances in the flowsheet, it becomes necessary to find
// a way to save the setup data for each process
// model instance individually.
// Approach:
// 1 A Milano Integer parameter is declared in the Milano model.
// Since the MathRelations section can consist of multiple BBM
// and EEB components, one such Milano Integer parameter should be
// defined for each BBM and EEB that appears in the MathRelations.
// It is recommended the <<Hidden>> property be attached to
// the parameter since the end users have no need to manipulate
// that value.
// 2 C++ Code: Define a setup class for each of the BBM and EEB.
// The name of the classes is left to the developer.
// 3 Use a static pointer, say pS, as the handle for the setup
// object that is allocated when calling 'new'.
// 4 Use auxiliary functions saveBlockPtr() and getBlockPtr()
// to save to and retrieve from the MILANO parameter that
// corresponds to the given equation block.
//
// NOTE: saveBlockPtr() and getBlockPtr() work with any setup
// class because they rely on void* pointer values. This
// also means that an explicit cast is required when
// calling getBlockPtr().
//
// 5 On class design:
// We make everything public instead of writing a bunch of
// methods, mainly because we only anticipate using
// the class within the DLL.
// Moreover, the real intent of the class is to store bookkeeping
// information. It is not required to do data manipulation,
// other than freeing memory previously allocated.
class SaveSetUp {
public:
// Constructor(s).
// Requirements:
// Initialize certain data members.
SaveSetUp(long pMdl) {
pModel = pMdl; // Just in case it's needed somewhere else.
sizeComps = 0; // CRUCIAL.
stoich = 0; // CRUCIAL - Criteria for 'delete'.
BCIndex = -1; // CRUCIAL for now...
// maybe a more direct way can be found later.
NumInputVariable = 0; // CRUCIAL.
NumOutputVariable =0; // CRUCIAL.
NumNonZero = 0; // CRUCIAL.
Comps = 0; // Allocated by ROMeo
baseComponent = 0; // Allocated by ROMeo
}
// Destructor.
// Requirements:
// Delete any allocated memory.
~SaveSetUp() {
if (stoich) delete [] stoich;
if (Comps) MI_deleteMemory_domainGetAllElems(Comps);
if (baseComponent) MI_deleteMemory_getStringValue(baseComponent);
// OUTPUTS
int o_reactionRate;
int o_netReaction;
int o_ProdPres;
int o_ProdMolarFlow;
int o_ProdMoleFrac0; // FIRST entry in ProdMoleFrac list.
#endif // CONVREACTOR_BBM_H_INCLUDED
//----------------------------------------------------------------------
// For explanation of arguments of modelSparsity(), see
// Size and Sparsity Routine (BBM), MILANO Users Guide, page 7-25.
extern "C" __declspec (dllexport)
long modelSparsity (long pModel,
long queryFlag,
long* numInputVariable,
long* numOutputVariable,
long* numNonZero,
long* numVarInEqn,
long* varIndex)
{
if (queryFlag == 1) {
// Assume that Milano code handles error situation (GetState()).
// - Only trouble might be for SClients (SimSci developers).
// --------------------------------------------
// Retrieve data needed to write the Equations.
// --------------------------------------------
pS->sizeComps = MI_domainGetCount(pModel,"Comps");
pS->Comps = MI_domainGetAllElems(pModel, "Comps");
pS->baseComponent =
MI_getStringValue(pModel,"baseComponent",NULL);
// baseComponentIndex
pS->BCIndex = -1; // Can put in constructor.
for (i=0; i<pS->sizeComps; i++) {
if (strcmp(pS->Comps[i],pS->baseComponent)==0) pS->BCIndex = i;
}
// Section M.
// Offset in varValuesInput and varValuesOutput arrays.
// INPUT variables - SAME order as in Milano equation block.
k = 0;
pS->o_conversion = k++;
pS->o_PresDrop = k++;
pS->o_FeedPres = k++;
pS->o_FeedMolarFlow = k++;
for (pS->o_FeedMoleFrac0 = k, i=0; i<pS->sizeComps; i++, k++);
pS->NumInputVariable = k;
// Section N.
// OUTPUT variables - SAME order as in Milano equation block.
// (Also count number of nonzeros in Jacobian.)
k = 0; pS->NumNonZero = 0;
pS->o_ProdPres = k++; pS->NumNonZero += 2; // e_Pres
pS->o_reactionRate = k++; pS->NumNonZero += 3; // e_ReactionRate
pS->o_netReaction = k++; pS->NumNonZero += 3; // e_NetReaction
pS->o_ProdMolarFlow = k++; pS->NumNonZero += 3; // e_Flow
for (pS->o_ProdMoleFrac0 = k, i=0; i<pS->sizeComps-1; i++, k++)
// Notice -1.
{
pS->NumNonZero += 3 + (i != pS->BCIndex); // e_MBal[Comps]
}
pS->NumOutputVariable= k;
*numInputVariable = pS->NumInputVariable ;
*numOutputVariable = pS->NumOutputVariable;
*numNonZero = pS->NumNonZero ;
//-----------------------------------------------------
//Sample function calls - BEGIN ---------------------
//-----------------------------------------------------
//--- Current model's full name
cout << " getFullName(): [" << MI_getFullName(pModel)
<< "]" << endl;
sizeWrapSet1 = MI_domainGetCount(pModel,"wrapSet1");
wrapSet1 = MI_domainGetAllElems(pModel, "wrapSet1");
cout << " wrapSet1: size (AFTER) = " << sizeWrapSet1 << endl;
cout << " wrapSet1: elements (AFTER):" << endl;
for (i=0; i<sizeWrapSet1; i++) {
cout << " wrapSet1[" << i << "] = " << wrapSet1[i] << endl;
}
//--- Attributes.
cout << endl;
// Retrieve initial value.
MIUserAtom wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::realVal);
MI_setAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::uomRealVal,wrapTemp
Atom);
wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::realVal);
cout << " wrapTempAtom: get ::realVal = " <<
MI_getRealInAtom(wrapTempAtom) << endl;
wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::uomRealVal);
cout << " wrapTempAtom: get ::uomRealVal = " <<
MI_getRealInAtom(wrapTempAtom) << endl;
wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::uomReport);
cout << " wrapTempAtom: get ::uomReport = " <<
MI_getStringInAtom(wrapTempAtom) << endl;
// Retrieve more attributes.
wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::dimReport);
cout << " wrapTempAtom: get ::dimReport = " <<
MI_getStringInAtom(wrapTempAtom) << endl;
wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::Basis);
cout << " wrapTempAtom: get ::Basis = " <<
MI_getStringInAtom(wrapTempAtom) << endl;
strcat(theMsg, ".\n");
MI_print(i+1, theMsg, j);
}
}
//-----------------------------------------------------
//Sample function calls - END -----------------------
//-----------------------------------------------------
}
if (queryFlag == 2) {
// e_Pres
numVarInEqn[k++] = 2;
varIndex[j++] = pS->o_PresDrop;
varIndex[j++] = pS->o_FeedPres;
// e_ReactionRate
numVarInEqn[k++] = 3;
varIndex[j++] = pS->o_conversion;
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_FeedMoleFrac0 + pS->BCIndex;
// e_NetReaction
numVarInEqn[k++] = 3;
varIndex[j++] = pS->o_conversion;
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_FeedMoleFrac0 + pS->BCIndex;
// e_Flow
numVarInEqn[k++] = 3;
varIndex[j++] = pS->o_conversion;
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_FeedMoleFrac0 + pS->BCIndex;
// e_MBal[Comps]
for (i=0; i<pS->sizeComps-1; i++) // Notice -1.
{
numVarInEqn[k++] = 3 + (i != pS->BCIndex);
varIndex[j++] = pS->o_conversion;
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_FeedMoleFrac0 + i; // Due to
FeedMoleFrac[Comps].
if (i != pS->BCIndex)
varIndex[j++] = pS->o_FeedMoleFrac0 + pS->BCIndex; // Due to
FeedMoleFrac[baseComponent].
}
// Consistency checks:
if (k != pS->NumOutputVariable)
cout << "***ERR: @10: k != NumOutputVariable : " << k << "!=" <<
pS->NumOutputVariable << endl;
if (j != pS->NumNonZero)
cout << "***ERR: @10: j != NumNonZero : " << j << "!=" <<
pS->NumNonZero << endl;
cout << " Leaving modelSparsity ... queryFlag = " << queryFlag <<
endl;
cout << endl;
return 0;
}
//---------------------------------------------------------------------
// For arguments of modelEvaluation(), see Function and Derivative Value
// Routine (BBM), MILANO Users Guide, page 7-27.
extern "C" __declspec (dllexport)
long modelEvaluation (long pModel,
double* varValuesInput,
double* varValuesOutput,
double* derivatives,
long flagCalc)
{
if (flagCalc==1 || flagCalc==3) {
// OUTPUT function values.
// -----------------------
// This is patterned after calculations of numNonZero (Section N).
// e_Pres
varValuesOutput[k++] = varValuesInput[pS->o_FeedPres]
-varValuesInput[pS->o_PresDrop];
// e_ReactionRate
varValuesOutput[k++] = varValuesInput[pS->o_conversion]
*varValuesInput[pS->o_FeedMolarFlow]
*varValuesInput[pS->o_FeedMoleFrac0 +
pS->BCIndex]
/pS->AbsStoichBC;
// e_NetReaction
for (sumStoich=0.0, i=0; i<pS->sizeComps; i++) sumStoich +=
pS->stoich[i];
varValuesOutput[k++] = sumStoich
*varValuesOutput[pS->o_reactionRate ];
// e_Flow
varValuesOutput[k++] = varValuesInput[pS->o_FeedMolarFlow]
+varValuesOutput[pS->o_netReaction ];
// e_MBal[Comps]
for (i=0; i<pS->sizeComps-1; i++) // Notice -1.
{
if (varValuesOutput[pS->o_ProdMolarFlow]) {
varValuesOutput[k++] =(varValuesInput[pS->o_FeedMoleFrac0 +
i]
*varValuesInput[pS->o_FeedMolarFlow]
+pS->stoich[i]
*varValuesOutput[pS->o_reactionRate ])
/varValuesOutput[pS->o_ProdMolarFlow];
}
else varValuesOutput[k++] = 0;
}
// Consistency check.
if (k != pS->NumOutputVariable)
cout << "***ERR: @30: k != NumOutputVariable : " << k << "!=" <<
pS->NumOutputVariable << endl;
}
if (flagCalc == 3) {
// Jacobian values.
// ----------------
// This is patterned after calculations of numNonZero (Section N).
// e_Pres
derivatives[j++] = -1.; // PresDrop
// e_ReactionRate
derivatives[reactionRate_conversion = j++] // conversion
= varValuesInput[pS->o_FeedMolarFlow]
*varValuesInput[pS->o_FeedMoleFrac0
+ pS->BCIndex]
/pS->AbsStoichBC;
= varValuesInput[pS->o_conversion]
*varValuesInput[pS->o_FeedMoleFrac0
+ pS->BCIndex]
/pS->AbsStoichBC;
// e_NetReaction
derivatives[NetReaction_conversion = j++] // conversion
= sumStoich*derivatives[reactionRate_conversion];
// e_Flow
derivatives[Flow_conversion = j++] // conversion
= derivatives[NetReaction_conversion];
// e_MBal[Comps]
for (i=0; i<pS->sizeComps-1; i++) // Notice -1.
{
if (varValuesOutput[pS->o_ProdMolarFlow]) {
scratch1 = pS->stoich[i]/varValuesOutput[pS-
>o_ProdMolarFlow];
scratch2 = varValuesOutput[pS->o_ProdMoleFrac0 + i]
/varValuesOutput[pS->o_ProdMolarFlow];
*derivatives[Flow_FeedMolarFlow];
// Consistency check.
if (j != pS->NumNonZero)
cout << "***ERR: @35: j != NumNonZero : " << j << "!="
<< pS->NumNonZero << endl;
}
cout << " Leaving modelEvaluation ..." << " flagCalc = "
<< flagCalc << endl;
cout << endl;
return 0;
}
/---------------------------------------------------------------------
// Illustration only.
return 0;
}
//---------------------------------------------------------------------
//
BeginSection Declarations;
//
// With the few exceptions as noted below,
// the Declarations section of ConvReactorEEB.mil is identical
// to that of ConvReactor.mil. For code and comments
// common to both models, see Declarations, page 5-7.
//
// CPPBlockAddr is used to save the address of the "setup
// class defined in the C++ DLL code. We declare it CPPBlockAddr
// <<Hidden>> because the end user at runtime need not care about
// its value. Although we initialize CPPBlockAddr to zero,
// it is not important because the C++ code takes full
// control and responsibility over its value.
// Since in our example only a single BBM or the
// EEB representation can be selected at a time, but not both, we
// use a single parameter to keep track of the "setup"
// object's address. But if we had, say two BBM
// components in the MathRelations, then we would
// declare one such Integer parameter for each BBM.
// Keep in mind that the names used here will be used
// in the C++ code.
// CPPBlockAddr is <<Hidden>> so it will not appear in the GUI.
//
Integer <<DataType=PMF_ExtIntRow>>
CPPBlockAddr <<Hidden,InitialValue=0>>;
//
// Start of Modular Thermo CONSTANT properties setup.
// Declaration of Modular Thermo Constant properties, is identical
// in both models. See page 5-10.
// End of Modular Thermo CONSTANT properties setup.
// -------------------------------------------
//
// Start of Modular Thermo Variable properties setup.
// Declaration of Modular Thermo Variable properties, is identical
// in both models. See page 5-10.
// End of Modular Thermo Variable properties setup.
// -------------------------------------------
//
// Energy Balance Report is identical in both models.
// See page 5-15.
//------------------------------------------------------------------
//
// Data structures to illustrate use of wrapper functions
// available when writing BBM and EEB C++ code.
// The contents of wrapSet1 and wrapTemp can be changed from the C++
// code. Thus Cubs and Rangers are commented out, but they (or
// any others that might be needed) can be added from the C++ section,
// while the items initially included in the MILANO model can be deleted.
//
// See Adding and Deleting Elements, page 5-45.
// (This example has been included only for demonstration; it has nothing
// to do with the conversion reactor model per se.)
//
Set wrapSet1 <<Hidden>> "Baseball Teams"
/ Astros, Padres, Braves, Yankees, RedSox, Indians /;
* Cubs, Rangers,
Real <<DataType=PMF_ExtRealRow>> wrapTemp
<<Hidden,Dim=Temp,InitialValue=298.15>> "Temperature Real block";
//
/------------------------------------------------------------------
//
// See Links, page 5-12, for comments.
Link l_Temp;
/------------------------------------------------------------------
//
// Equations
// Note that in contrast to ConvReactorBBM.mil, the EEB version declares
// all of the equations that the all-MILANO version does.
Equation e_Pres;
Equation e_ReactionRate;
Equation e_NetReaction;
Equation e_Flow;
Equation e_MBal[Comps];
Equation e_EBal;
Equation e_refEnth[PortStreamPairs] <<NonSparse>>;
/------------------------------------------------------------------
// Methods
// The same methods are declared in both models. See page 5-13.
//
EndSection Declarations;
//----------------------------------------------------------------------
//
BeginSection Events;
// The Events section is identical in both models. See page 5-14.
//
EndSection Events;
//----------------------------------------------------------------------
//
BeginSection MathRelations;
//
//----------------------------------------------------------------------
m_rxnModel ..
{
// Recall that ordering of variables and equations in
// Include statements must be matched in the C++ code.
Include v_Q;
Include InputOutputStream["Product"]:Pres;
Include InputOutputStream["Product"]:MolarFlow;
Include InputOutputStream["Product"]:Prop["Enth"];
Include v_refEnth["Product"];
// List of EQUATIONS.
Include e_Pres;
Include e_ReactionRate;
Include e_NetReaction;
Include e_Flow;
// Include all Product material balances but one
// because material balance on the product stream
// takes care of the remaining component.
Loop [Comps] $ (Ord(Comps) NE Card(Comps)),
{Include e_MBal[Comps]; };
Include e_EBal;
};
//----------------------------------------------------------------------
* PSEUDOCODE FOR C++ VERSION OF EXTERNAL EQUATION BLOCK EQUATIONS
* ----------------------------------------------------------------
* (HELPS WRITE C++ CODE FOR DLL.)
*
* e_Pres..
* ProdPres - FeedPres + PresDrop = 0;
*
* d e_Pres
* ---------- = 1
* d ProdPres
*
* d e_Pres
* ---------- = -1
* d FeedPres
*
* d e_Pres
* ---------- = 1
* d PresDrop
*
*
* e_ReactionRate..
* Let AbsStoich = Abs(stoich[baseComponent]);
* // [bC] = [baseComponent]
* v_reactionRate - v_conversion*FeedMolarFlow*FeedMoleFrac[bC]/
AbsStoich = 0
*
* d e_ReactionRate
* ---------------- = 1
* d v_reactionRate
*
* d e_ReactionRate
* ---------------- = - FeedMolarFlow*FeedMoleFrac[bC]/AbsStoich
* d v_conversion
*
* d e_ReactionRate
* ---------------- = - v_conversion*FeedMoleFrac[bC]/AbsStoich
* d FeedMolarFlow
*
* d e_ReactionRate
* ------------------ = - v_conversion*FeedMolarFlow/AbsStoich
* d FeedMoleFrac[bC]
*
*
* e_NetReaction..
* v_netReaction - Sum([Comps], stoich[Comps])*v_reactionRate = 0
*
* d e_NetReaction
* ---------------- = 1
* d v_netReaction
*
* d e_NetReaction
* ---------------- = - Sum([Comps], stoich[Comps])
* d v_reactionRate
*
*
* e_Flow..
* ProdMolarFlow - FeedMolarFlow - v_netReaction = 0;
*
* d e_Flow
* --------------- = 1
* d ProdMolarFlow
*
* d e_Flow
* --------------- = -1
* d FeedMolarFlow
*
* d e_Flow
* --------------- = -1
* d v_netReaction
*
*
* e_MBal[Comps] $(Ord(Comps) NE Card(Comps))..
* ProdMoleFrac[Comps]*ProdMolarFlow
* - FeedMoleFrac[Comps]*FeedMolarFlow
* - stoich[Comps]*v_reactionRate = 0;
*
* d e_MBal[Comps]
* --------------------- = ProdMolarFlow
* d ProdMoleFrac[Comps]
*
* d e_MBal[Comps]
* --------------- = ProdMoleFrac[Comps]
* d ProdMolarFlow
*
* d e_MBal[Comps]
* --------------------- = - FeedMolarFlow
* d FeedMoleFrac[Comps]
*
* d e_MBal[Comps]
* --------------- = - FeedMoleFrac[Comps]
* d FeedMolarFlow
*
* d e_MBal[Comps]
* ---------------- = - stoich[Comps]
* d v_reactionRate
*
*
* e_EBal..
* v_Q - Sum([Comps], stoich[Comps]*HForm[Comps])*v_reactionRate
* - (ProdEnth - refEnthProd)*ProdMolarFlow
* + (FeedEnth - refEnthFeed)*FeedMolarFlow
* = 0;
*
* d e_EBal
* -------- = 1
* d v_Q
*
* d e_EBal
* ---------------- = - Sum([Comps], stoich[Comps]*HForm[Comps])
* d v_reactionRate
*
* d e_EBal
* ---------- = - ProdMolarFlow
* d ProdEnth
*
* d e_EBal
* ------------- = ProdMolarFlow
* d refEnthProd
*
* d e_EBal
* --------------- = - (ProdEnth - refEnthProd)
* d ProdMolarFlow
*
* d e_EBal
* ---------- = FeedMolarFlow
* d FeedEnth
*
* d e_EBal
* ------------- = - FeedMolarFlow
* d refEnthFeed
*
* d e_EBal
* --------------- = (FeedEnth - refEnthFeed)
* d FeedMolarFlow
*
//----------------------------------------------------------------------
EndSection MathRelations;
//----------------------------------------------------------------------
//
BeginMethod Void Initialize();
//
// Implementation of Initialize()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-16, for code and comments.
EndMethod Initialize;
//----------------------------------------------------------------------
//
BeginMethod Void BindMoleFrac();
//
// Implementation of BindMoleFrac()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-16, for code and comments.
EndMethod BindMoleFrac;
//----------------------------------------------------------------------
//
BeginMethod Void BindMoleFracEvent(Reference MilanoEvent evObj);
//
BindMoleFrac();
EndMethod BindMoleFracEvent;
//----------------------------------------------------------------------
//
BeginMethod Void UpdateLinks();
//
// Implementation of UpdateLinks()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-17, for code and comments.
EndMethod UpdateLinks;
//----------------------------------------------------------------------
//
BeginMethod Void RemoveLinks();
//
// Use keyword Super to invoke base class of current model.
// Implementation of RemoveLinks() identical to ConvReactor.mil.
// See page 5-18.
Super:RemoveLinks();
UnLink l_Temp;
EndMethod RemoveLinks;
//----------------------------------------------------------------------
//
BeginMethod Integer GetState();
// Implementation of GetState()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-18, for code and comments.
EndMethod GetState;
//----------------------------------------------------------------------
//
BeginMethod Integer CheckStructure();
//
// Implementation of CheckStructure()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-19, for code and comments.
EndMethod CheckStructure;
//----------------------------------------------------------------------
//
BeginMethod Integer GenerateEstimates() ;
//
// Implementation of GenerateEstimates()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-23, for code and comments.
EndMethod GenerateEstimates;
//----------------------------------------------------------------------
//
BeginMethod Void GenerateReport (Reference MilanoStream Report);
//
// Implementation of GenerateReport() in ConvReactorEEB.mil is
// identical to that in ConvReactor.mil.
// See page 5-24, for code and comments.
EndMethod GenerateReport;
//----------------------------------------------------------------------
//
BeginMethod Void CalculateEnergyTerms();
//
// Implementation of CalculateEnergyTerms()
// in ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-26, for code and comments.
EndMethod CalculateEnergyTerms;
//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyInContribution();
//
// Implementation of TotalEnergyInContribution() in
// ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-26 for code and comments.
EndMethod TotalEnergyInContribution;
//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyOutContribution();
//
// Implementation of TotalEnergyOutContribution() in
// ConvReactorEEB.mil is identical to that in ConvReactor.mil.
// See page 5-27 for code and comments.
EndMethod TotalEnergyOutContribution;
//----------------------------------------------------------------------
//
BeginMethod Void GenerateEnergyBalanceReportSection
(Reference MilanoStream Report);
//
// Implementation of GenerateEnergyBalanceReportSection() in
// ConvReactorEEB.mil is identical to
// that in ConvReactor.mil. See page 5-27 for code and comments.
EndMethod GenerateEnergyBalanceReportSection;
//----------------------------------------------------------------------
EndModel ConvReactorEEB;
/----------------------------------------------------------------------
// C++ Source Code for EEB Header File ConvReactorEEB.h
// Project : ROMeo
// Subsystem : Process Model
// Date : 9/14/98
// Purpose : Support functions BBM and EEB DLL code.
// Copyright (c) 1998 by Simulation Sciences Inc
// ALL RIGHTS RESERVED
//----------------------------------------------------------------------
//
// Define a class for keeping track of set up information.
// SEE COMMENTS IN BlockPtrBBM.h FOR DETAILS.
//
class SaveSetUp {
public:
// Constructor(s).
// Requirements:
// Initialize certain data members.
SaveSetUp(long pMdl) {
lModel = pMdl; // Optional, in case it's needed somewhere else.
sizeComps = 0; // Mandatory.
stoich = 0; // Mandatory - Criterion for 'delete'.
HForm = 0; // Mandatory - Criterion for 'delete'.
BCIndex = -1; // Mandatory for now... maybe a more direct
way can be found later.
SupplySparsityFlag = 0; // Mandatory.
NumVariable = 0; // Mandatory.
NumEquation = 0; // Mandatory.
NumNonZero = 0; // Mandatory.
Comps = 0; // Allocated by ROMeo
baseComponent = 0; // Allocated by ROMeo
}
// Destructor.
// Requirements:
// Delete any allocated memory.
~SaveSetUp() {
if (stoich) delete [] stoich;
if (HForm ) delete [] HForm ;
if (Comps) MI_deleteMemory_domainGetAllElems(Comps);
if (baseComponent) MI_deleteMemory_getStringValue(baseComponent);
}
// Pointer to Milano model.
int o_Q;
int o_ProdPres;
int o_ProdMolarFlow;
int o_ProdEnth;
int o_refEnthProd;
int o_ProdMoleFrac0; // FIRST entry in ProdMoleFrac list.
// EQUATIONS
int o_e_Pres;
int o_e_ReactionRate;
int o_e_NetReaction;
int o_e_Flow;
int o_e_MBal0; // FIRST entry in ProdMoleFrac list.
int o_e_EBal;
//---------------------------------------------------------------------
if (queryFlag == 1) {
// Assume that Milano code handles error situation (GetState()).
// - Only trouble might be for SClients (SimSci developers).
// --------------------------------------------
// Retrieve data needed to write the Equations.
// --------------------------------------------
pS->sizeComps = MI_domainGetCount (pModel,"Comps");
// baseComponentIndex
pS->BCIndex = -1;
for (i=0; i<pS->sizeComps; i++) {
if (strcmp(pS->Comps[i],pS->baseComponent)==0) pS->BCIndex = i;
}
// Section M.
// Offset in varValues and funcValues arrays.
// Variables - SAME order as in Milano equation block.
k = 0;
pS->o_conversion = k++;
pS->o_reactionRate = k++;
pS->o_netReaction = k++;
pS->o_PresDrop = k++;
pS->o_FeedPres = k++;
pS->o_FeedMolarFlow = k++;
pS->o_FeedEnth = k++;
pS->o_refEnthFeed = k++;
for (pS->o_FeedMoleFrac0 = k, i=0; i<pS->sizeComps; i++, k++);
pS->o_Q = k++;
pS->o_ProdPres = k++;
pS->o_ProdMolarFlow = k++;
pS->o_ProdEnth = k++;
pS->o_refEnthProd = k++;
for (pS->o_ProdMoleFrac0 = k, i=0; i<pS->sizeComps-1; i++, k++);
// Notice -1.
pS->NumVariable = k;
// Section N.
// EQUATIONS - SAME order as in Milano equation block.
// (Also count number of nonzeros in Jacobian.)
k = 0; pS->NumNonZero = 0;
pS->o_e_Pres = k++; pS->NumNonZero += 3;
// e_Pres
pS->o_e_ReactionRate = k++; pS->NumNonZero += 4;
// e_ReactionRate
pS->o_e_NetReaction = k++; pS->NumNonZero += 2;
// e_NetReaction
pS->o_e_Flow = k++; pS->NumNonZero += 3;
// e_Flow
for (pS->o_e_MBal0 = k, i=0; i<pS->sizeComps-1; i++, k++)
// Notice -1.
{
pS->NumNonZero += 5; // e_MBal[Comps]
}
pS->o_e_EBal = k++; pS->NumNonZero += 8;
// e_EBal
pS->NumEquation = k;
*numVariable = pS->NumVariable;
*numEquation = pS->NumEquation;
*numNonZero = pS->NumNonZero;
*supplySparsityFlag = pS->SupplySparsityFlag = 1;
if (queryFlag == 2) {
// e_Pres
numVarInEqn[k++] = 3;
varIndex[j++] = pS->o_ProdPres;
varIndex[j++] = pS->o_FeedPres;
varIndex[j++] = pS->o_PresDrop;
// e_ReactionRate
numVarInEqn[k++] = 4;
varIndex[j++] = pS->o_reactionRate;
varIndex[j++] = pS->o_conversion;
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_FeedMoleFrac0 + pS->BCIndex;
// e_NetReaction
numVarInEqn[k++] = 2;
varIndex[j++] = pS->o_netReaction;
varIndex[j++] = pS->o_reactionRate;
// e_Flow
numVarInEqn[k++] = 3;
varIndex[j++] = pS->o_ProdMolarFlow;
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_netReaction;
// e_MBal[Comps]
for (i=0; i<pS->sizeComps-1; i++) // Notice -1.
{
numVarInEqn[k++] = 5;
varIndex[j++] = pS->o_ProdMoleFrac0 + i; // Due to
ProdMoleFrac[Comps].
varIndex[j++] = pS->o_ProdMolarFlow;
varIndex[j++] = pS->o_FeedMoleFrac0 + i; // Due to
FeedMoleFrac[Comps].
varIndex[j++] = pS->o_FeedMolarFlow;
varIndex[j++] = pS->o_reactionRate;
}
// e_EBal
numVarInEqn[k++] = 8;
varIndex[j++] = pS->o_Q;
varIndex[j++] = pS->o_reactionRate;
varIndex[j++] = pS->o_ProdEnth;
varIndex[j++] = pS->o_refEnthProd;
varIndex[j++] = pS->o_ProdMolarFlow;
varIndex[j++] = pS->o_FeedEnth;
varIndex[j++] = pS->o_refEnthFeed;
varIndex[j++] = pS->o_FeedMolarFlow;
// Consistency checks:
if (k != pS->NumEquation)
cout << "***ERR: @10: k != NumEquation : " << k << "!=" << pS-
>NumEquation << endl;
if (j != pS->NumNonZero)
cout << "***ERR: @10: j != NumNonZero : " << j << "!=" << pS-
>NumNonZero << endl;
cout << " Leaving modelSparsity ... queryFlag = " << queryFlag <<
endl;
cout << endl;
return 0;
}
//---------------------------------------------------------------------
if (flagCalc==2 || flagCalc==3) {
// EQUATION function values.
// -------------------------
// This is patterned after calculations of numNonZero (Section N).
// e_Pres
funcValues[k++] = varValues[pS->o_ProdPres]
-varValues[pS->o_FeedPres]
+varValues[pS->o_PresDrop];
// e_ReactionRate
funcValues[k++] = varValues[pS->o_reactionRate]
-varValues[pS->o_conversion]
*varValues[pS->o_FeedMolarFlow]
*varValues[pS->o_FeedMoleFrac0 + pS->BCIndex]
/pS->AbsStoichBC;
// e_NetReaction
for (sumStoich=0.0, i=0; i<pS->sizeComps; i++) sumStoich
+= pS->stoich[i];
funcValues[k++] = varValues[pS->o_netReaction]
-sumStoich
*varValues[pS->o_reactionRate];
// e_Flow
funcValues[k++] = varValues[pS->o_ProdMolarFlow]
-varValues[pS->o_FeedMolarFlow]
-varValues[pS->o_netReaction];
// e_MBal[Comps]
for (i=0; i<pS->sizeComps-1; i++) // Notice -1.
{
funcValues[k++] = varValues[pS->o_ProdMoleFrac0 + i]
*varValues[pS->o_ProdMolarFlow]
-varValues[pS->o_FeedMoleFrac0 + i]
*varValues[pS->o_FeedMolarFlow]
-pS->stoich[i]
*varValues[pS->o_reactionRate];
}
// e_EBal
for (sumHForm=0.0, i=0; i<pS->sizeComps; i++) sumHForm
+= pS->stoich[i]*pS->HForm[i];
funcValues[k++] = varValues[pS->o_Q]
-sumHForm
*varValues[pS->o_reactionRate]
-( varValues[pS->o_ProdEnth]
-varValues[pS->o_refEnthProd]
)*varValues[pS->o_ProdMolarFlow]
+( varValues[pS->o_FeedEnth]
-varValues[pS->o_refEnthFeed]
)*varValues[pS->o_FeedMolarFlow];
// Consistency check.
if (k != pS->NumEquation)
cout << "***ERR: @30: k != NumEquation : " << k << "!="
<< pS->NumEquation << endl;
}
if (flagCalc == 3) {
// Jacobian values.
// ----------------
// This is patterned after calculations of numNonZero (Section N).
// e_Pres
derivatives[j++] = 1.; // ProdPres
derivatives[j++] = -1.; // FeedPres
derivatives[j++] = 1.; // PresDrop
// e_ReactionRate
derivatives[j++] = 1.; // reactionRate
/pS->AbsStoichBC;
// e_NetReaction
derivatives[j++] = 1.; // netReaction
derivatives[j++] = -sumStoich; // conversion
// e_Flow
derivatives[j++] = 1.; // ProdMolarFlow
derivatives[j++] = -1.; // FeedMolarFlow
derivatives[j++] = 1.; // netReaction
// e_MBal[Comps]
for (i=0; i<pS->sizeComps-1; i++) // Notice -1.
{
derivatives[j++] = varValues[pS->o_ProdMolarFlow]; //
ProdMoleFrac[Comps]
derivatives[j++] = varValues[pS->o_ProdMoleFrac0 + i]; //
ProdMolarFlow
derivatives[j++] = -varValues[pS->o_FeedMolarFlow]; //
FeedMoleFrac[Comps]
derivatives[j++] = -varValues[pS->o_FeedMoleFrac0 + i]; //
FeedMolarFlow
derivatives[j++] = -pS->stoich[i]; // reactionRate
}
// e_EBal
derivatives[j++] = 1.; // Q
derivatives[j++] = -sumHForm; // reactionRate
derivatives[j++] = -varValues[pS->o_ProdMolarFlow]; // ProdEnth
derivatives[j++] = varValues[pS->o_ProdMolarFlow]; // refEnthProd
derivatives[j++] =-( varValues[pS->o_ProdEnth] // ProdMolarFlow
-varValues[pS->o_refEnthProd]
);
derivatives[j++] = varValues[pS->o_FeedMolarFlow]; // FeedEnth
derivatives[j++] = -varValues[pS->o_FeedMolarFlow]; // refEnthFeed
derivatives[j++] = ( varValues[pS->o_FeedEnth] // FeedMolarFlow
-varValues[pS->o_refEnthFeed]
);
// Consistency check.
if (j != pS->NumNonZero)
cout << "***ERR: @35: j != NumNonZero : " << j << "!=" <<
pS->NumNonZero << endl;
}
cout << " Leaving modelEvaluation ..." << " flagCalc = " << flagCalc
<< endl;
cout << endl;
return 0;
}
//---------------------------------------------------------------------
return 0;
}
If (doUomTest), {
// Display current values.
dummy=10; Display dummy;
uomTestuomReal = uomTestTemp.uomRealVal;
uomTestInternalUOM = getProperty("uomTestTemp","UOM");
uomTestuomReport = getProperty("uomTestTemp","uomReport");
Display uomTestTemp, uomTestuomReal, uomTestInternalUOM,
uomTestuomReport;
LogInfoMsg("\nuomTest: dummy=%d uomTestTemp=%.2f
uomTestInternalUOM=[%s] uomTestuomReal=%.2f
uomTestuomReport=[%s]\n", dummy, uomTestTemp, uomTestInternalUOM,
uomTestuomReal, uomTestuomReport);
uomTestuomReport = getProperty("uomTestTemp","uomReport");
Display uomTestTemp, uomTestuomReal, uomTestInternalUOM,
uomTestuomReport;
LogInfoMsg("\nuomTest: dummy=%d uomTestTemp=%.2f
uomTestInternalUOM=[%s] uomTestuomReal=%.2f uomTestuomReport=[%s]\n",
dummy, uomTestTemp, uomTestInternalUOM, uomTestuomReal,
uomTestuomReport);
To insert a file:
Click anywhere in the Files window to activate the Insert icon
and the Insert/File main menu option.
Select either Insert option to access the Select Model Source
File dialog box.
6-2 Procedures
You can insert more than one new custom model at a time. In
fact, whenever you add a new custom model, all other custom
models that you have created previously must be recompiled
into mcl.db, since custom models are always compiled directly
into the original standard model library.
As the last step, you must install the compiled custom model(s)
into mcl.db. During this step, ROMeo modifies mcl.db to
include the complied custom model(s) and refreshes the Model
window to reflect the new state of mcl.db. the models for
their Group property and constructs the process model
groupings displayed in the Models window. To install the
6-4 Procedures
The newly installed example Conversion reactor model and the
process model class from which it is derived are now included
in the Sample group.
To create a project:
Select File/New from the main menu.
Figure 6.2-3: MS Visual C++ 4.2 Insert Files into Project Window
Select the files to be compiled into the DLL and click Add .
6-6 Procedures
For Additional include directories: specify ..\..\include
which should point to the \models\include subdirectory.
6-8 Procedures
We illustrate the basic procedures by example using the EzFlashEEB
code included in the ROMeo distribution. You are advised to
consult the Programming with Mixed Languages section of the
FORTRAN PowerStation on-line documentation for further details.
Example:
C++ declaration
// MSpars : Has same role as modelSparsity() in C++.
#define MSpars MSPARS // For Fortran.
extern "C"
void __stdcall MSpars(
long* nComp, // Input (number of components)
long* pModel, // Input
long* queryFlag, // Input
long* supplySparsityFlag, // Input
long* numEquation, // Output
long* numVariable, // Output
long* numNonZero, // Output
long numVarInEqn[], // Output
long varIndex[] // Output
);
6-10 Procedures
// MEval : Has same role as modelEvaluation() in C++.
#define MEval MEVAL // For Fortran.
extern "C"
void __stdcall MEval(
long* nComp, // Input (number of components)
long* pModel, // Input
double varValues[], // Input
double funcValues[], // Output
double derivatives[], // Output
long* flagCalc // Input
);
integer*4 nComp
integer*4 pModel
integer*4 queryFlag
integer*4 supplySparsityFlag
integer*4 numEquation
integer*4 numVariable
integer*4 numNonZero
integer*4 numVarInEqn(*)
integer*4 varIndex(*)
subroutine MEval(
1 nComp, ! Input (no of components)
1 pModel, ! Input
1 varValues, ! Input
1 funcValues, ! Output
1 derivatives, ! Output
1 flagCalc ! Input
1 )
integer*4 nComp
Example:
C++ declaration:
FORTRAN call:
if (task .EQ. 0 .OR. task .EQ. 2) then ! {
! task=0 : Save numEquation, numVariable, numNonZero.
! task=2 : Retrieve numEquation, numVariable, numNonZero.
call getSetMilanoInteger(pModel,task, '1'C, numEquation)
call getSetMilanoInteger(pModel,task, '2'C, numVariable)
call getSetMilanoInteger(pModel,task, '3'C, numNonZero )
end if ! }
6-12 Procedures
6.4 Unit Registration in ROMeo
You can add, reorder or remove standard and custom units in
ROMeo using the Unit Configuration Utility. In the following
description, it is assumed that you are adding a custom process unit
rather than a custom column section.
Click in first column of the row and select the Add right-click
option. A new row is added at the bottom of the table.
Supply the appropriate entries for each of the following:
Specify the GUI Unit DLL Name if you have created a
custom set of DEWs for the new unit. You do not need to
include the .DLL extension. Alternatively, enter
UIGenericUnit, which contains the three data entry
windows common to all ROMeo process units: Thermo/
Phases, Notes and Diagnostics. Use these common DEWs
as you would in any other process model for component
slate, thermo method slate, product stream phase
specification, etc. If a custom set of DEWs is not available
for the new unit, you can supply unit specifications,
variables and parameter values via the GUI.
Specify the DLL Directory in which the unit DLL resides.
Assuming a standard installation in the C:\ drive of the
client computer, the default directory will be C:\Program
Files\Simulation Sciences\ROMeo10\Client\Bin. If the unit
Note: Changes do not take effect until you exit and restart
ROMeo.
6-14 Procedures
Figure 6.5-1: Common Data Entry Windows
6-16 Procedures
doUomTest UOM test flag. See page 5-74 for an example
of usage.
6-18 Procedures
Figure 6.5-8: Custom Conversion Reactor Sample Data Structure
return 0;
}
return 0;
}
double Ycalc[11];
UserModelWrapper(x,Ycalc);
return 0;
}
ROMeo Server
Copy the MILANO source files to the ROMeo server
computer. Run the Model Library Manager application to
update the model class library database with the new model(s).
If the new process model uses a Black Box Model or External
Equation Block, the supporting DLLs must be copied to, or
created on, the server computer.
ROMeo Client
If the custom process model employs a custom icon data file,
copy this file to each client computer.
ENDOUTLINEmatches BEGOUTLINE
The capitalized keywords above are the actual words used. Most
keywords also have a set of parameters. The shapeword can be any
of a number of geometrical shapes such as LINE, CIRCLE and POLY.
When a closed figure is defined other than by a single shapeword
(such as CIRCLE), the BEGOUTLINE and ENDOUTLINE keywords delimit
the list of items that together constitute the closed figure.
ENDOUTLINE accepts parameters that affect the closed shape as a
Style Codes
GROUP Statement
Group <id> <description> <class> <show>
A GROUP specified in the icon file appears as one icon on the palette.
Initially, the first ICON in the GROUP will display, but this setting can
be changed at runtime. If more than one ICON is specified in the
GROUP, users, when selecting the palette icon, will be presented with
a selection menu prompting them to select a specific ICON in the
GROUP.
ICON Statement
ICON <text> <rlog> <rflag> <sfac> <dform> <dstart> <input>
Each ICON section starts with an ICON statement and ends with
another ICON statement, a GROUP statement, an END statement or an
end-of-file.
Table 7.7-2: ICON Statement Arguments
Argument Description
shapeword Statement
shapeword <ID> <line_color> <fill> <fill_color> <width>
<style>
A shapeword specifies a shape. An icon must have at least one
shapeword (exclusive of the ID, see below), and normally contains
at least one closed area, defined either as a shapeword for a closed
area (POLY, RECT, CIRCLE or ELLIPSE) or an OUTLINE sequence that
defines a closed area. A shapeword is followed by one or more DATA
statements. The DATA statements concatenate: several DATA
statements are equivalent to a single DATA statement with all the
parameters concatenated.
Options for shapeword are LINE, LINE2, LINE3, RLI, POLY, RECT,
ELLIPSE, CIRCLE, ARC or ID. Each shapeword statement has its own
set of parameters, followed by DATA statements. The data in the
shapeword statement line are always the same, whereas the data in
<line_color> The line color. Default is -1. See Color Codes above.
<fill> Fill flag, -1 for default. See Fill Style Codes above.
<style> Line style, -1 for default. See Line Style Codes above.
RECT Rectangle
xmin,y
min,
xmax,y
max
ID Icon ID xc,yc
placement
TEXT Statement
TEXT <id> <color> <style> <text>
The TEXT statement specifies any text that will appear on the icon.
<id> .
<style>
<text> .
The PORT statement defines the type, appearance and location of the
icon ports. Syntax is similar to that of the shapeword statement.
Table 7.7-6: PORT Statement Arguments
Argument Description
<id> The port ID. Note that if there are several icons in a
GROUP, they must have the same number of ports, and
the ports must have the same sequence of ID numbers.
Within each icon, the port ID must be unique, however.
There are API calls available to the user that specify port
ID.
Comment Optional.
The PLIN statement defines a "port line" and is handled the same
way as the PORT statement with the following differences:
The item is a line to which a port can be attached at any point.
This produces the following additional differences:
The associated DATA statement has two more parameters
that specify not merely the location but also the beginning
and end point of possible port locations.
The line defined by the PLIN statement can be part of an enclosed
area. Thus, PLIN statements can occur within a BEGINOUTLINE/END-
OUTLINE sequence.
Note: For the sake of simplicity, we recommend that you use the
PORT statement rather that PLIN for stream connections.
Note: Feed and Product are the default names for the feed and
product ports, respectively. For SISO units, an explicit naming of
the ports is optional and using the default portnames is generally
sufficient. However, for unit with multiple feed or product ports,
(SIMO, MISO and MIMO configurations), portnames must be
specified explicitly.
<x2> <y2> x,y-coordinates of the port line ending point; defined only
if the keyword is PLIN.
ENDOUTLINE Statement
ENDOUTLINE <ID> <line_color> <fill> <fill_color> <width>
<style>
<line_color> The line color. Default is -1. See Color Codes above.
<fill> Fill flag, -1 for default. See Fill Style Codes above.
<style> Line style, -1 for default. See Line Style Codes above.
Pump 100
Bottom arc ID
Base y
For ease of reference, selected statement prototypes have been included before the
pertinent statements.
// GROUP <id><description><class><show>
GROUP 10007 "Pump" "Pump"
// ICON <text> <rlog> <rflag> <sfac> <dform> <dstart> <input>
ICON "Pump" 0 1 0.0 "P%0.3d" 100 1
// shapeword <ID> <line_color> <fill> <fill_color> <width> <style>
POLY -1 -1 -1 -1 -1 -1 // all default settings
// DATA x1,y1,x2,y2, ...
DATA 9 8 11 11 -1 11 1 8 //Base
BEGOUTLINE
ARC -1 -1 -1 -1 -1 -1 // all default settings
// DATA xc, yc, xr, yr, angle1, angle2
DATA 5 5 5 5 90 166 // Upper Left arc
// DATA
LINE -1 -1 -1 -1 -1 -1
// DATA x1,y1, x2,y2, x3,y3, x4,y4
DATA 0 4 -2 4 -2 6 0 6 // Feed graphic (outside)
ARC -1 -1 -1 -1 -1 -1
// DATA xc, yc, xr, yr, angle1, angle2
DATA 5 5 5 5 192 360 // Bottom arc
ARC -1 -1 -1 -1 -1 -1
// DATA xc, yc, xr, yr, angle1, angle2
DATA 5 5 5 5 0 34 // Upper right arc
LINE -1 -1 -1 -1 -1 -1
// DATA x1,y1, x2,y2, x3,y3, x4,y4
DATA 9 2 12 2 12 0 5 0 // Product graphic
ENDOUTLINE -1 -1 -1 -1 -1 -1
LINE -1 -1 -1 -1 -1 -1
======================================================================
BEGOUTLINE
LINE -1 -1 -1 -1 -1 -1
DATA 0 0 0 10
LINE -1 -1 -1 -1 -1 -1
DATA 0 10 10 10
LINE -1 -1 -1 -1 -1 -1
DATA 10 10 10 0
LINE -1 -1 -1 -1 -1 -1
DATA 10 0 0 0
ID -1 -1 -1 -1 -1 -1
DATA 10 12
// TODO - Uncomment the following 2 lines to make text appear on the icon
// TEXT -1 -1 -1 "GUI Name"
// DATA 16 0 2 2 5 5
// TODO - Uncomment the following 3 lines to specify a single feed port.
// Replace "Port Name" with the name of the port in the model
// PORT 112 2 0 -1 -1 -1 "Port Name"
// DATA 1 0 0 2 0 0 0 0 0 1 0 0 0
// DATA 0 5
// TODO - Uncomment the following 3 lines to specify a single product port.
// Replace "Port Name" with the name of the port in the model
// PORT 111 2 0 -1 -1 -1 "Port Name"
// DATA 0 1 0 0 0 0 0 0 0 0 1 0 0
// DATA 10 5
// TODO - Uncomment the following 3 lines to specify a line feed port.
// Replace "Port Name" with the name of the port in the model
// PLIN 100 2 0 -1 -1 -1 "Port Name"
// DATA -1 0 0 0 0 0 1 0 1 1 0 1 -1 // Feeds, Left side
// DATA 0 2 0 8
// TODO - Uncomment the following 3 lines to specify a line product port.
// Replace "Port Name" with the name of the port in the model
// PLIN 101 2 0 -1 -1 -1 "Port Name"
// DATA 0 -1 0 0 0 0 1 0 1 0 1 2 0 // Products, Right side
// DATA 10 2 10 8
// The following lines must be included for the unit to work properly in
// the ROMeo environment
END
// Everything below the "END" line is ignored.
Appendix A
Thermodynamic Properties
A Mws , 5-10
TotHReaction , 5-10
Constructor()
AbsStoich , 5-9, 5-14 See Methods accessible...
AddPropsAndFlows() CopyI2L/L2I()
See Runtime methods See System functions
Assign...Slate() Correlated Properties , A-3
See System functions
CPPBlockAddr , 5-29, 5-47, 5-54
Assign...SlateToSubModel()
See Runtime methods CreateNonProcessPort()
See System functions
AtomBalChk , 5-21
Current...Slate
AtomBalChkTol , 5-9, 5-21, 6-16 See Data members accessible...
CurrentOnOffStatus()
See System functions
B
Base component , 5-8, 6-16 D
Basis
See Real/Variable attributes... #define , 6-10
BindStream() Data members accessible from
See Runtime methods UserAddedProcessUnit
Black Box Model Comps , 2-5, 5-73
input variables , 5-40 CurrentCompSlate , 2-5
output variables , 5-40 CurrentPropSlate , 2-5
DebugLevel , 2-6
OnOffStatus , 2-6, 6-16
C Port[Ports] , 2-7
ReportLevel , 2-7
Case UserOnOff , 2-7, 6-16
feature in ROMeo , 2-10 ValidateLevel , 2-7, 6-16
Check...() Data structures
See Methods accessible... in wrapper functions , 5-30
Connect() DataType
See System functions See Properties
Constants, in custom reactor model DebugLevel
HForm , 5-10 See Data members accessible...
HReaction , 5-10 Degrees of freedom , 5-4
LocalPres , 5-10 Destructor()
LocalTemp , 5-10 See Methods accessible...
F
I
Feasibility , 2-15
Fixed point properties , A-2 #include , 4-2
variableName.I
FORTRAN , 1-1
See Variable attributes...
PowerStation , 6-8, 6-9
Icon data files , 1-3
variableName.FS
MIMO3x2Icon.dat , 2-2, 5-3
See Variable attributes...
MISO3x1Icon.dat , 2-2, 5-3
FuncGradProc
SIMO1x3Icon.dat , 2-2, 5-3
See Function and derivative value routine
SISOIcon.dat , 2-2, 5-3
Function and derivative value routine
UIGenericUnitIcon.dat , 2-2, 5-3
I-3 Index
schema evolution , 7-7 O
standard models , 7-10
MilanoObject
MilanoUOM , 5-74 ON/OFF/DOWN , 2-6
MilanoStream OnOffStatus
See Data members accessible...
defined , 5-24
MITRE , 2-1
MLMR.exe , 1-3 P
See also Model Library Manager
Model
Parent()
closed-form , 1-1
See System functions
MIMO , 2-1, 5-3, 6-14
Phase models
MISO , 2-1, 5-3
PM_Liquid2Phase , 3-5
open-form , 1-1
PM_LiquidPhase , 3-5
PM_Liquid2Phase , 5-11
PM_VaporPhase , 3-5
PM_LiquidPhase , 5-11
variable and set binding in , 5-4
PM_ProcessStream , 5-11
PM_VaporPhase , 5-11 PM_
SIMO , 2-1, 5-3 PModel , 2-8
SISO , 2-1, 2-2, 5-3 ProcessUnit , 2-11
ThermoProperties , 3-2, 5-10
Model class library
UserAddedProcessUnit , 2-2
mcl.db , 1-2, 6-1, 6-2
mcl_standard.db , 1-2 Port name
as internal name , 5-16
Model Development Tools
directory structure , 7-9 Port[Ports]
See Data members accessible...
Model Library Manager , 1-3, 6-1
Ports
modelCleanUp()
preconfigured in model templates , 2-1
See Exit routine
PortStreamPair()
modelEvaluation()
See Methods accessible...
in FORTRAN , 6-11
Predeletion()
See Function and derivative value routine
See Methods accessible...
modelSparsity()
Prefixes, use of
in FORTRAN , 6-10
e_ in equations , 5-7
See Size and sparsity routine
l_ in linked variables , 5-7
Modular Thermo
m_ in models , 5-56
Calculate() method , 3-2, 3-3
PM_ in SIMSCI models , 2-3
constant properties , 5-10
v_ in variables , 5-7
variable properties , 5-10
print/Print...()
See System functions
I-5 Index
AssignPropertySlate() , 2-18, 3-6, 5-20, 5-22 Typographic conventions , 1-5
Connect() , 2-18
CopyI2L() , 2-18
CopyL2I() , 2-19 U
CreateNonProcessPort() , 2-19
CurrentOnOffStatus() , 2-19, 5-18
UIGenericUnit.dll , 1-3
DisConnect() , 2-19
displayProperties() , 2-19 UIGenericUnitIcon.dat , 1-3
EquipmentCopyI2L() , 2-19 UnBindStream()
Get1DSearch() , 2-20 See Runtime methods
GetBlackBoxFlash() , 2-20 UOM
getBooleanProperty() , 2-20 Class , B-4, B-5, B-6
GetCompSlateName() , 2-20 Internal set , B-4, B-5
GetContainer() , 2-21 See MilanoObject
See Real/Variable attributes...
GetFlowsheet() , 2-21
Token , B-4, B-5, B-6
getModelStatus() , 2-21
GetName() , 2-21, 5-19 variableName.uom...
See Real/Variable attributes...
GetParentContainer() , 2-22
GetParentFlowsheet() , 2-22 variableName.UP
See Variable attributes...
getProperty() , 2-22, 5-74
GetPropSlateName() , 2-22 Update...()
See Runtime methods
GetThermoManager() , 2-23
GetThermoProperties() , 2-23, 5-20 UserOnOff
See Data members accessible...
GetUOMDifferenceClass() , 2-23
GetUOMInverseClass() , 2-23 UserOrdered
See Properties
hasProperty() , 2-24
IsA() , 2-24
LogErrMsg() , 2-24
LogInfoMsg() , 2-24, 5-75
V
LogWarnMsg() , 2-24
MakeActive() , 2-25 Validate()
MakePassive() , 2-25 See Methods accessible...
Parent() , 2-25 ValidateLevel
print() , 2-25 See Data members accessible...
PrintError() , 2-26 ValidateMessage()
PrintFeedsAndProds() , 2-26 See System functions
PrintThermoInfo() , 2-26, 5-24 Variable attributes in custom models
PrintWarning() , 2-26 FS , 4-10
setProperty() , 2-26, 5-74, 5-76 FX , 4-10
Type() , 2-27, 5-24 FXI , 4-10
ValidateMessage() , 2-27 I , 4-10
INDEPENDENT , 4-10
L , 4-10
T LO , 4-10
M , 4-10
NS , 4-10
ThermoProperties
RT , 4-10
object , 5-10, 5-20
SM , 4-10
See also PM_ThermoProperties
uomFS , 4-10
Total...Contribution()
uomI , 4-10
See Runtime methods
uomL , 4-11
Type()
uomLO , 4-11
See System functions
I-7 Index