You are on page 1of 213

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

ROMeo is designed with an open architecture that allows for easy


addition of unit operation models. You can add a new unit operation
to ROMeo using the same tools that SIMSCI developers use to
create standard unit operation models. You can write custom
models in MILANO or C++. In addition, you can incorporate already
existing C, C++, or FORTRAN code by making method callbacks
into the MILANO or C++ models.
Creation of a new process model for ROMeo requires development
of two basic parts: (1) the actual mathematical model that is
incorporated into the ROMeo Server, and (2) the user interface for
the ROMeo Client that allows you to add the model to the
flowsheet.
The server-side part of new unit operation model (for example, a
refinery reactor model) can be developed in one of the three ways
listed below. (The implementation of the client-side user interface is
addressed in Steps to Add a New Process Model, 1.1.)
1. As an open-form model written in MILANO in exactly the same
way as any of the models in the standard library of unit
operations.
2. As a closed-form or Black Box Model (BBM) written in C,
C++, or FORTRAN. The Black Box Model must return the
output variable values and both the pattern and the values of the
derivative matrix.
3. As an open-form model or External Equation Block (EEB)
written in C, C++, or FORTRAN. The model must return
function residuals. In addition, the open form model can return:

Process Models 1-1


only the pattern of the derivative matrix, or
both the pattern and the values of the derivative matrix.
Later in this manual, we provide templates and worked examples of
the MILANO and C++ code for models written in each of these three
ways.
In cases 2 and 3, you must write a MILANO interface definition to
handle the mapping of information between ROMeo and the custom
model. Basically, ROMeo "sees" only MILANO models. The custom
model is incorporated in ROMeo in a manner similar to the way
Modular Thermo is incorporated in MILANO models: invisible in
form, but capable of providing the necessary information.
There are a number of MILANO models available in the ROMeo
library that interface with Modular Thermo. These interface models
are used in our standard library process models to perform
thermodynamic calculations. New process models written in
MILANO can use these interface models in the same way. It is
important to realize that a custom mathematical model can
incorporate an arbitrary combination of MILANO equations, Black
Box Models, and External Equation Blocks. Thus, it is easy to
implement the thermodynamic calculations in MILANO while
writing the rest of the model in C, C++ or FORTRAN. These parts
can communicate with one another through common variables.
ROMeo process models use certain modeling conventions referred
to as a framework. The templates and examples supplied later in
this manual follow this framework. A new model that has been
written following this framework will be accessible to a ROMeo
user in exactly the same way as any of the standard models supplied
by SIMSCI.
All MILANO files used in defining model classes in ROMeo are
compiled into a model class library database, mcl.db, which is the
class library database actually used when ROMeo is launched. (A
copy of the class library created by SIMSCI model builders is
shipped with ROMeo and is called mcl_standard.db. This file serves
as a backup so that a copy of the original mcl.db is always
available.) Currently, only one instance of the class library database
is supported. Therefore, any additional model classes that you
create in MILANO must be added to mcl.db.
There are two additional files that you must supply to implement a
new MILANO process model:

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.

1.1 Steps to Add a New Process Model


The procedure for extending ROMeo with additional process model
classes consists of the following steps:

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.

Process Models 1-3


3. Test the new models in ROMeo.

Note: If the process model has a single-input single-output


(SISO) port configuration, consider using the default icon file
UIGenericUnitIcon.dat included in the ROMeo distribution.
Otherwise, create the icon file using the instructions presented
in Modifying the Icon Data File, 7.7.
Once you have tested the new models and you are ready to deploy
them, follow the instructions in Deploying a Custom Model, 7.5.

1.2 Creating .mil Source Files


You can create a MILANO (.mil) file in any text editor or word
processing application that allows you to save the file in a text
format. There are however, distinct advantages to using an editing
environment that automatically recognizes MILANO keywords and
performs other helpful tasks such as inserting curly braces { } and
parentheses in appropriate pairings. Refer to the MILANO Users
Guide, Creating .mil Source Files, 1.2.

1.3 Related Documentation


It is assumed that you have access to, and are familiar with, the
following documents:
MILANO User's Guide - a detailed presentation of the MILANO
modeling language.
ROMeo User's Guide - an overview of the use of ROMeo models
in the flowsheet environment, how their specifications are entered,
and the functioning of ROMeo in Simulation, Data Reconciliation
and Optimization modes.
You should also have access to a C/C++ Integrated Development
Environment (IDE) such as Microsoft Visual C++, version 4.2 or
later. A C/C++ IDE is required to build the DLLs presented in the
sample code for the Black Box Model and the External Equation
Block.

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.

Process Models 1-5


Chapter 2
Process Model Framework

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.

2.1 Process Model Class Templates


The ROMeo distribution CD includes several template files that can
be used as starting points for creating single-input single-output
(SISO), single-input multiple-output (SIMO), multiple-input
single-output (MISO) or multiple-input multiple-output (MIMO)
process models, and for configuring the port arrangement of
flowsheet icons created for use with custom models. Note that each
model template already contains Measurement, Penalty, Tuning
Parameter and EDI ports.
SISOprocessUnitTemplate.milimplements class
SISOdoNothingTemplate

SIMOprocessUnitTemplate.milimplements class
SIMOdoNothingTemplate

MISOprocessUnitTemplate.milimplements class
MISOdoNothingTemplate

Process Models 2-1


MIMOprocessUnitTemplate.milimplements class
MIMOdoNothingTemplate

UIGenericUnitIcon.dat used to develop custom icons

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
Refer to Default Directory Structure with Included Files, 7.4, for
details on the location of these files.
Notice that the template classes inherit from base class
PM_UserAddedProcessUnit. More importantly, the class names
SISOdoNothingTemplate, SIMOdoNothingTemplate,
MISOdoNothingTemplate and MIMOdoNothingTemplate merely act as
placeholders for the actual name required for the class at hand.
(Note that while PM_UserAddedProcessUnit is part of the process
model library (mcl.db), these template classes are not.)
The example reactor model is a SISO unit that uses
SISOdoNothingTemplate as its starting template class.

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>>;

2-2 Process Model Framework


The example states that ConvReactor is to be included in the
Sample group as shown in Table 6.1-1. The following Group
names are reserved for SIMSCI use:
Standard Used for all standard process models included in
the process model library.
Sample Used for all sample process models distributed by
SIMSCI.
We recommend that you select a Group name that is related to
your company, for example, <<Group=ABC>>, where ABC is some
short, meaningful mnemonic for your company name.
Do not use the prefix PM_.
The prefix PM_ is already used in the name of the standard
process models included with ROMeo. Paralleling the use of
the Group property, we recommend that you prefix your model
names with a short mnemonic of your company name, for
example,
BeginModel ABC_MyProcess :: PM_UserAddedProcessUnit
<<Group=ABC>>;

Make explicit the << DataType>> property in block declarations.


A MILANO block (Real, Integer, String, Variable) has a
datatype associated with it. This datatype defines which
attributes are available on the rows of the block. We strongly
recommend that you explicitly associate a datatype with your
block declaration. In this way, you will be protected from any
unnecessary dependence on the current default datatype. In
other words, do not rely on the current datatype defaults, since
they are subject to change. The datatypes you are most likely to
use with a ROMeo application are:
VariablePMF_ExtVarRow
IntegerPMF_ExtIntRow
RealPMF_ExtRealRow
StringPMF_ExtStringRow

A sample variable declaration follows:


Variable <<DataType=PMF_ExtVarRow>> Temp <<Dim=Temp>>;

Process Models 2-3


2.3 Overview of ROMeo Process Model Base Classes
ROMeo Process Model (RPM) base classes constitute a modeling
framework for integrating custom process models into ROMeo
either via ROMeos MILANO language, C/C++ or FORTRAN. A major
feature of ROMeo is that you can interact with models created with
RPM base classes in the same way as with predefined ROMeo
library models. In fact, most of the predefined units in the ROMeo
library are implemented using the same process. The classes listed
here are intended to serve as templates for creating custom models.
These models may range from simple to complex in structure. The
classes define default implementation of various required methods
that you would otherwise need to code. Additionally, you can also
extend or override these methods to further tailor the functionality
of your model. In order to make full use of these base classes, you
should have some exposure to the MILANO programming language
in particular as described in the MILANO Users Guide and to object-
oriented (OO) design methodology in general.

PModel PM_PModel

Equipment PM_Equipment

Unit PM_Unit

Process Unit PM_ProcessUnit

User-Added PM_UserAddedProcessUnit
Process Unit

ROMeo Process Model (RPM) classes are based on the concept of


object-oriented inheritance. The diagram above illustrates the class

2-4 Process Model Framework


inheritance structure of class PM_UserAddedProcessUnit, from which
all custom models must be derived.

Note: In the following discussion, the terms method and function


are used interchangeably.
When you read through the examples of the custom conversion
reactor model in Chapter 5 of this manual, you will encounter many
implementations of the classes and methods listed below.

2.4 Data Members Accessible from Class


PM_UserAddedProcessUnit
A complete listing of the data members accessible from class
PM_UserAddedProcessUnit is given for information only. Refrain
from modifying the values of any data members other than
DebugLevel, ReportLevel and ValidateLevel.

2.4.1 Data Members


Comps
Reference Set Comps <<UserOrdered>>
The component set of the unit or stream.

CurrentCompSlate
Reference PM_ComponentSlate CurrentCompSlate <<Hidden>>

Note: A process unit or process stream always has a valid


component slate (CurrentCompSlate) and component set
(Comps). As a result, you can access these two references
directly.

Note: Because all component slates in Modular Thermo can


be deleted, you must access the component slate only via a
member method, and you should check the validity of the
reference.

CurrentPropSlate
Reference PM_PropertySlate CurrentPropSlate <<Hidden>>

Process Models 2-5


CurrentPropSlate is the list of currently available properties.

Note: It is possible to inadvertently delete all thermodynamic


method slates while in Modular Thermo. Thus, before accessing a
property slate, one must verify that the unit does indeed have a
slate. This verification can be done using the GetPropSlateName()
method (see GetPropSlateName(), page 2-22).

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)

Streams can be only ON or OFF.

Note: You should not modify OnOffStatus directly.

Ports
Reference Set Ports <<UserOrdered>>

2-6 Process Model Framework


This set contains all of the ports in the model.

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

Process Models 2-7


2.5 Methods Accessible from Class PM_UserAddedProcessUnit
Most methods in MILANO are virtual functions; as a result, derived
class methods normally must call base class methods, except
Constructor() and Destructor(), which are taken care of by the
system. Some native methods for string handling are available
because of the inheritance from PM_PModel.
All methods must be declared in the Declaration section and
defined in the main body of the model.

Note: In ROMeo 1.0, the MILANO compiler does not normally


check if a method requires a return value. Thus, you must make
sure the method returns the proper value for all possible paths.

Note: A set cannot be used in an argument or as a return value.

Note: String operations currently supported in ROMeo 1.0 are


"EQ", "=", "==", "!=", "NE", "atoi", "itoa"", "StringLeft",
"StringRight", and "StringConcat".

2.5.1 Object Management Methods


Constructor()
Void Constructor()
The Constructor() member method is automatically invoked
when an object is created by MITRE. As a result, you should not call
this method in any model. Models are not required to provide
a Constructor() function as a default Constructor() will be
generated. The order of calling for object is as follows:
Object member of base class Constructors
Base class Constructors

2-8 Process Model Framework


Derived class Constructors

Note: The order of object member Constructor() calls cannot be


specified. This method is called before the object is registered
with ROMeo, and therefore, cannot access most of ROMeos
functionality, including access name, parent, flowsheet, and
thermo info.
Usage: This method provides a place to give initial values for
primitive data members: Integer, String, Real.

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

Note: As with the Constructor() method, the order of


object Destructor() calls cannot be specified. Implementation
should not access functions outside the object.
Usage: The Destructor() method can be used to destroy objects
that were created via the New operator.

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

Process Models 2-9


model MUST call the submodels Initialize() explicitly. Any
changes in the model can trigger Events.

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:

Initialize submodels, including ports


Set default specifications
Assign component/property slate to submodels
Bind reference objects and reference sets
Connect internal streams to internal units
Calculate thermo constants, for example, molecular
weights and the gas constant
Turn submodel passive or active

Note: Initialize() also triggers Create... Events.

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.

Note: Base class PM_UserAddedProcessUnit supports only


single-stream ports.
InOut -

1 - in port (feed)
2 - out port (product)

2-10 Process Model Framework


PhaseFlag -

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:

UnBind reference objects and reference sets


DisConnect internal streams to internal units
Implementation note, this function also triggers Delete...
Events. RemoveLinks() is called in PM_ProcessUnit.

2.5.2 Model Checking and Verification Methods


The following six methods are used at various stages to determine
whether an object is complete. All methods, except Validate(),
should check the initial (I) attribute. Also, a parent model must
call the submodel's methods. For error or warning headers, the

Process Models 2-11


predefined functions PrintError() and PrintWarning(), which are
called automatically, are used.
The returning status can be either PMF_OK or PMF_Error.

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:

Calculation of thermo constants


Verification if incoming stream has needed properties and
valid values

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:

Verify interaction between specification values, e.g.


consistency of entrainment specification and phases
Check phases of internal streams
Check if a component is in the current component slate

2-12 Process Model Framework


GetState()
Integer GetState()
GetState() is, for most objects, linked to the color status of the
objects icon on the PFD. You should verify the number of
independent/dependent variables in the model by checking the FXI
status. (See ROMeo Glossary entries on fixed/free variable
attributes.) In the case of models with submodels, take care when
calling GetState() for the submodels because individual
submodels can be non-square while the whole model is square.
GetState() is also called when you invoke GenerateEstimates(),
GenerateSolution() and GenerateReport().

Usage: The most common tasks performed in these methods are:

Verification of degrees of freedom


Verification of completeness of specifications. For
example, in the Mixer it is necessary to verify that the
product stream has been supplied with a pressure drop
with respect to... specification. The verification should
be done on the Initial (I) attribute, not the Level (L)
attribute.
Verification of special input/output process streams due to
specifications. For example, a dew point Flash specification
necessitates a vapor phase product stream.

Note: Submodels should be abstract and not check the


squareness for themselves in GetState(). As GetState() is
called very frequently, you should try to optimize its usage. If
possible, place time-consuming checks in CheckStructure()
which is called less frequently.

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.

Process Models 2-13


VerifyFeed()
Integer VerifyFeed()
This method is automatically called from CheckDataForIEG().You
can put an extra check here to verify incoming feed streams.

2.5.3 Report Generation Method


GenerateReport ()
Void GenerateReport (Reference MilanoStream Report)
Some guidelines on usage:
Check ReportLevel for consistency
Use the predefined utility functions:
PrintProcessUnitBanner(..., Report)
PrintThermoInfo(Report)

Print initial, final and UOM attributes of variables and


parameters
Generate report for product streams
Generate report for submodels

2.5.4 Runtime Methods


These methods are called at some point during runtime. They can
be overridden.

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

2-14 Process Model Framework


to the submodel in the routine (except where ports with
SameCompSlateRequired have been modified).

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().

Call UpdateLinks() to refresh all the Links.

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

Initialize all submodels and variables, even if they are not


used.

Process Models 2-15


GenerateEstimates() should return a failure flag if any step
fails.
The value of a fixed variable will not change even if its .L
attribute changes
After solution, check if the estimate is meaningful
All variables and calculations are in Internal Units by
default. See Appendix B, Units of Measure.

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.

2-16 Process Model Framework


Before linking, check if the stream exists and is ON, if not
unlink it.
Call UpdateLinks() for submodels.
If a Link is defined over a set, make sure that it loops in an
intended fashion, that is, only Active or All.
If a Link is defined over a set but some members of the set
are to be excluded, unlink them explicitly.
If a Link is defined over a set and variables from both sides
were defined over different sets, make sure that the Link is
restricted to the intersection of both sets.
If a Link is made within the unit, check the direction here as
well.

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.

Process Models 2-17


UpdateCompsChange()
Void UpdateCompsChange()
This method is called when the object changes its component slate
or the current component slate is modified. In the case of a
component slate change, the system ensures that all the submodels
also have the new component slate.

UpdatePropsChange()
Void UpdatePropsChange()
Component slate comments also apply to the property slate.

2.5.5 System Functions


These system utility functions are accessible for use in a custom
process model. The model should not overwrite them.

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

2-18 Process Model Framework


CopyL2I()
Void CopyL2I()
PURPOSE: Copy variable value from L attribute to I 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

Process Models 2-19


Get1DSearch()
Reference PM_1DSearch Get1DSearch()
PURPOSE: Flowsheet shared one-dimensional search object
INPUT: None
RETURN: PM_1DSearch.

Note: There is only one shared one-dimensional search. If


needed, the model can also have its own one-dimensional search.
One one-dimensional search is needed for each layer of searches
(in nested configuration). This object is used only in IEG.

GetBlackBoxFlash()
Reference PM_BlackBoxFlash GetBlackBoxFlash()
PURPOSE: Flowsheet shared blackbox object
INPUT: None
RETURN: PM_BlackBoxFlash

Note: There is only one shared BlackBoxFlash. If needed, the


model can also have its own BlackBoxFlash. This object is used
only in IEG.

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

2-20 Process Model Framework


GetContainer()
Reference PM_Equipment GetContainer()
PURPOSE: Get a container reference
INPUT: None
RETURN: Returns (nearest) container reference
if it can access container;
NULL, if it cannot access container.
EXAMPLE: MyContainer = GetContainer();

Note: Contents are flowsheet, subflowsheet, composite process


unit, composite non-process unit.

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.

Note: Also see status of parent model.

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.

Process Models 2-21


GetParentContainer()
Reference PM_Equipment GetParentContainer()
PURPOSE: Get a container reference
INPUT: None
RETURN: Returns (nearest) container reference if it can access
container;
NULL, if it cannot access container.
EXAMPLE: MyContainer = GetParentContainer();

Note: Contents are flowsheet, subflowsheet, composite process


unit, composite non-process unit.

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

2-22 Process Model Framework


GetThermoManager()
Reference PM_ThermoManager GetThermoManager()
PURPOSE: Get a Thermo Manager reference
INPUT: None
RETURN: Returns (nearest) Thermo Manager reference
if it can access a Thermo Manager;
NULL, if it cannot access a Thermo Manager

GetThermoProperties()
Reference PM_ThermoProperties GetThermoProperties()
PURPOSE: Flowsheet shared ThermoProperties object.
INPUT: None.
RETURN: PM_ThermoProperties.

Note: There is only one shared ThermoProperties object. This


object is only used to calculate constant properties such as
molecular weight. See Appendix A, Thermodynamic Properties,
for a listing of available properties.

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.

Process Models 2-23


hasProperty()
Integer hasProperty (String primitiveName, String
propertyName)
PURPOSE: See if a property list has a given property
INPUT: Primitive name, and property name

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().

2-24 Process Model Framework


MakeActive()
Void MakeActive()
PURPOSE: Make the model active, that is, include it in math model.
INPUT: None.

Note: Make sure that parent model is active also.

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

Note: In contrast to most other system functions, print() does


not begin with initial capitalization. A full description of the
print() method can be found in the MILANO Users Guide.

Process Models 2-25


PrintError()
Void PrintError(String modelName)
PURPOSE: Print error message to the end user
INPUT: Model full name
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.

Note: For consistency, should be called in GenerateReport().

PrintThermoInfo()
Void PrintThermoInfo(Reference MilanoStream Report)
PURPOSE: Print component and property slate to report; output print
stream.
INPUT: A valid MILANO out stream.

Note: For consistency, should be called in GenerateReport().

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.

2-26 Process Model Framework


Type()
String Type()
PURPOSE: Return final type of this model.
INPUT: None.

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.

Process Models 2-27


Chapter 3
Modular Thermo and Process Models

This chapter explains how to access the properties supported by


Modular Thermo (MT) from a process model. To retrieve property
values, you must define a sufficiently complete thermodynamic
state, namely:
Temperature
Pressure
Composition
Phase type
MT calculates two types of properties:
Component properties depending on the property, you must
supply all or some of the above state information.
Stream (mixture) properties you must supply all of the above
state information.
An important consideration is whether all the state information is
fixed or some of it varies during solution. For instance, a heat of
formation depends only on a fixed reference state; therefore it can
be stored in a MILANO Real parameter. By contrast, a mixture
enthalpy depends on some temperature, pressure or composition
that is unknown until the model has been solved and so must be
stored in a model variable. Therefore, the two ways to set up the
access to MT depend on whether the properties of interest are
constant or vary during solution.

Process Models 3-1


3.1 Accessing Constant Thermo Data
PMF provides a single instance of a PM_ThermoProperties object that
is used to retrieve properties from MT. That this is a single object is
important because each time its Calculate() method is invoked, any
previously calculated values may be overwritten. The necessary
setup is as follows:
Declare a Reference to a PM_ThermoProperties object:
//Handle to the single ThermoProperties object.
Reference PM_ThermoProperties ThermoProperties;

Insert the following sample code in the CheckStructure()


method. Then make all applicable adjustments in the
***USER DATA*** section.

// Set up the ThermoProperties object.


// The next group of lines is a common template.
// Bind to the single PM_ThermoProperties object
// available to the flowsheet.
ThermoProperties = GetThermoProperties();

// Clear data from previous call to


// ThermoProperties object.
ThermoProperties:ClearData();

// Assign Component and Property slates.


If (CurrentCompSlate EQ NULL), Return PMF_Error;
ThermoProperties:AssignComponentSlate
(CurrentCompSlate:SlateName);
If (CurrentPropSlate EQ NULL), Return PMF_Error;
ThermoProperties:AssignPropertySlate
(CurrentPropSlate:SlateName);

// Get name of calling model - used in error messages.


ThermoProperties:CallingModel = GetFullName();

// *** USER DATA - BEGIN ***


// List the properties of interest for this model.
// Use two sets to specify the properties:
// CompProps[] : List of component properties.
// Props[] : List of mixture properties.

// Component properties:
ThermoProperties:CompProps["Wt" ] = Yes; // Molecular weight
ThermoProperties:CompProps["CarbAtom" ] = Yes; // C number
ThermoProperties:CompProps["HydrAtom" ] = Yes; // H number

3-2 Modular Thermo and Process Models


ThermoProperties:CompProps["NitrAtom" ] = Yes; // N number
ThermoProperties:CompProps["OxygAtom" ] = Yes; // O number
ThermoProperties:CompProps["SulfAtom" ] = Yes; // S number
ThermoProperties:CompProps["HeatForm"] = Yes;
// Heat of formation

// Mixture properties:
* ThermoProperties:Props["Wt" ] = Yes; // Molecular weight
* ThermoProperties:Props["Enth"] = Yes; // Enthalpy

// Specify Temperature and Pressure, if necessary.


ThermoProperties:Temp = LocalTemp; // Depends on situation.
ThermoProperties:Pres = LocalPres; // Depends on situation.
* ThermoProperties:MoleFrac[Comps] = someValues;
// Depends on situation.

// Specify the Phase ("Vap", "Liq", "Liq2"); default is "Vap".


* ThermoProperties:PhaseName = "Vap";
// Depends on situation.
// *** USER DATA - END ***

// Calculate properties.
// Note: Calculate() returns an error code.
// You can check against PMF_OK.
ThermoProperties:Calculate();

Note: Above we recommended including the Modular Thermo


code in CheckStructure(). In reality, MT calls may be needed in
other methods as well. For efficiency reasons, CheckStructure()
should be used instead of GetState() whenever possible, since the
latter method is called more often in ROMeo models. In all
situations, though, whenever access to MT is needed, the above
setup should be followed as closely as possible.
If Calculate() returns PMF_OK, then proceed to do whatever the
model needs to do with the thermo data. The component
properties data returned by Calculate() will be stored in
ThermoProperties:CompProp[propName,Comps] and the mixture
properties in ThermoProperties:Prop[propName].
These data should be used immediately since any future access
to MT is likely to erase the values. How the data are handled
depends on their expected lifetime. Here are two scenarios:
1. Data are needed only for an immediate spot check, for
example, when checking the mass balance on a chemical

Process Models 3-3


reaction in which the stoichiometry is specified by the end user.
Typical MILANO code would be:
// Check mass balance.
// -------------------
MassBalChk = Sum([Comps], stoich[Comps]*ThermoProperties:
CompProp["Wt",Comps]);
If (Abs(MassBalChk) GT Abs(MassBalChkTol)),
{
print("%-40s:\n", GetName());
print(" CheckStructure - Error: Mass balance
check not satisfied.\n");
print(" MassBalChk = %f\n", MassBalChk);
print(" MassBalChkTol = %f\n", MassBalChkTol);
GetState_rv = PMF_Error;
};

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];

3.2 Accessing Variable Thermo Data


The setup for variable thermo properties is conceptually similar to
that for constant properties: sufficient state data must be specified,
along with the list of properties of interest. The main differences
are:
Model variables, instead of Real parameters, are used to
represent the state information. It is understood that correct
values for the state variables will be obtained during model
solution.
Model variables are also used to store the values returned by
MT. The correct value of these variables will be obtained during
model solution.
The lifetime of state information and property variables is the
same as that of the process model calling MT. Thus, some type
of local thermo object must be allocated rather than using a
common thermo object for the entire flowsheet. PMF provides

3-4 Modular Thermo and Process Models


the following phase models which provide the runtime and
post-solution interface with MT:
PM_VaporPhase calculates properties for a Vap phase.

PM_LiquidPhase calculates properties for a Liq phase.

PM_Liquid2Phase calculates properties for a Liq2 phase.

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.

3.2.1 Using Phase Models


You must declare the necessary phase models of type
PM_LiquidPhase, PM_Liquid2Phase or PM_VaporPhase. In the
Declarations section, you should create one such model for each
different set of state conditions needed in the model. It is also
important to use the <<SubModel>> property with these models. This
property tells MILANO to use the MathRelations section of the phase
model during model generation.
The inputs to the phase models are Temp, Pres, MoleFrac[Comps], and
the outputs are the thermo properties calculated by Modular
Thermo. Note that these outputs, namely Prop[RefProps] and
CompProp[RefCompProp,Comps], are implicit variables and thus
essentially hidden from the end user. If the calling model requires
that these properties be exposed to the user, the calling model must
define another nonimplicit version of the property and set it equal to
the implicit variable using an equation of the form:
v_Variable - <PhaseName>:Variable =E= 0;
The internal data structures supported by the phase models which
are relevant to set up are as follows:
Reference Set RefProps; // For mixture/stream properties.
Reference Set RefCompProps; // For component properties.
The calling model must create corresponding sets and bind them to
the ones in the phase models.
Integer BindToExternalTemp /1/;
Variable Temp <<Dim=Temp>>;
Reference Variable RefTemp <<Dim=Temp>>;

Process Models 3-5


The parent model may use Temp inside this model directly
(BindToExternalTemp = 0), or (default) use some real temperature
defined elsewhere (BindToExternalTemp = 1).
Integer BindToExternalPres /1/;
Variable Pres <<Dim=Pres>>;
Reference Variable RefPres <<Dim=Pres>>;
The parent model may use Pres inside this model directly
(BindToExternalPres = 0), or (default) use some real pressure
defined elsewhere (BindToExternalPres = 1).
Integer BindToExternalMoleFrac /0/;
Variable MoleFrac[Comps] <<NonSparse,Dim=Frac>>;
Reference Variable RefMoleFrac[Comps]
<<NonSparse,Dim=Frac>>;
The parent model may (default) use mole fractions inside this
model directly (BindToExternalMoleFrac = 0), or use some real mole
fractions defined elsewhere (BindToExternalMoleFrac = 1).
Variable Prop[RefProps] <<NonSparse,Implicit>>;
Variable CompProp[RefCompProps,Comps]
<<NonSparse,Implicit>>;
Prop[Props] and CompProp[CompProps,Comps] are implicit variables
returned from MT. Prop contains scalar (mixture) properties and
CompProp contains vector (component) properties.

The setup can thus be summarized:


1. The parent model is responsible for assigning the current
component and property slates (via AssignComponentSlate()
and AssignPropertySlate() methods).
2. By default, the phase model expects RefTemp to be bound to a
non-Reference temperature variable defined in the parent
model. If the parent model is to use the non-Reference
temperature variable inside the phase, then set
BindToExternalTemp = 0;
3. By default, the phase model expects RefPres to be bound to a
non-Reference pressure variable. If the parent model is to use
the non-Reference pressure variable inside the phase, then set
BindToExternalPres = 0;
4. By default, the phase model expects the parent model to use the
non-Reference MoleFrac variables inside the phase. If the parent

3-6 Modular Thermo and Process Models


model is to use non-Reference MoleFrac variables elsewhere,
then set BindToExternalMoleFrac = 1;
If you do set BindToExternalMoleFrac = 1, don't forget to keep
the bindings up to date when Comps or CurrentCompSlate change.
5. RefProps must be bound to a non-Reference set that contains
the scalar properties that are to be calculated at runtime.
6. RefCompProps must be bound to a non-Reference set that
contains the vector properties that are to be calculated at
runtime.
7. Don't forget to call <PhaseName>:Initialize().

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,

Process Models 3-7


//
// 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"]

// Phase models: refPhase is the name used here to


// handle the phase model objects. It is defined over
// the set PortStreamPairs, which contains the list of
// ports/streams. Alternatively, we could have created
// only two instances of the phase model, since there is
// only one feed and one product stream. However, the
// generality shown below will come handy in more
// complex models. The code we write in the methods and
// in MathRelations is also easier to understand and
// maintain. Notice the use of <<SubModel>> property
// to ensure that the MathRelations of each phase model
// is incorporated into the reactor math model.

PM_VaporPhase refPhase[PortStreamPairs]
<<NonSparse,SubModel>>;

// Reference conditions, and reference enthalpies for


// energy balance. Use reference state of heat of
// formation: 25 C, 1 atm. Use v_refTemp and v_refPres
// later on to bind with corresponding variables in the
// PM_VaporPhase models.
// Note: Since v_refTemp and v_refPres are not meant to
// change value, later we make them "fixed and
// independent" using attribute '.FXI' in Initialize();
// Recall: 25 C = 298.15 K, 1 Atm = 101.325 kPa

Variable <<DataType=PMF_ExtVarRow>> v_refTemp


<<Hidden,Dim=Temp,InitialValue=298.15>>;
Variable <<DataType=PMF_ExtVarRow>> v_refPres
<<Hidden,Dim=Pres,InitialValue=101.325>>;

// Variable to hold thermo property of interest.


// In a more complex model, we may need many of these.
Variable <<DataType=PMF_ExtVarRow>>
v_refEnth[PortStreamPairs] <<NonSparse,Dim=Energy/Mole>>;

// Similarly, it is necessary to define sets Props and


// CompProps to be bound with corresponding sets in the

3-8 Modular Thermo and Process Models


// PM_VaporPhase models to be <<UserOrdered>>
// To conform with declaration in PM_VaporPhase.

Set Props <<UserOrdered>>;


Set CompProps <<UserOrdered>>;

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.

// Stream Enthalpy at ref state of Heat of Formation.


//
// Guideline for handling Thermo properties:
//
// Use local variables for the properties because
// the "Prop" variable available in the phase models
// already is declared <<Implicit>>. This means it
// cannot appear in an EEB (e.g., in the energy
// balance that goes to the EEB). Although the "Prop"
// variable can appear in the Input list to a BBM, it

Process Models 3-9


// is still recommended that a local variable be used.
e_refEnth[PortStreamPairs]..
v_refEnth[PortStreamPairs]
- refPhase[PortStreamPairs]:Prop["Enth"] =E= 0;

Bindings
Bindings are done in CheckStructure() for the efficiency rea-
sons mentioned on page 2-12.

// Set up for Modular Thermo and refPhase[].


// -----------------------------------------
// Recall this is done to calculate the Feed and Product
// enthalpies at the REFERENCE CONDITION used for the heat
// heat of formation. Since the stream compositions are
// not known in advance, the required enthalpies become
// variables. The property value from the PM_VaporPhase
// models is found in
//refPhase[PortStreamPairs]:Prop["Enth"].
If (GetState_rv EQ PMF_OK), {
// Bind different data members.
Loop [PortStreamPairs], {
refPhase[PortStreamPairs]:RefTemp = v_refTemp;
refPhase[PortStreamPairs]:RefPres = v_refPres;
refPhase[PortStreamPairs]:BindToExternalMoleFrac = 1;
refPhase[PortStreamPairs]:AssignComponentSlate
(CurrentCompSlate);
refPhase[PortStreamPairs]:AssignPropertySlate
(CurrentPropSlate );
refPhase[PortStreamPairs]:RefProps = Props;
refPhase[PortStreamPairs]:RefCompProps =
CompProps;
Loop [Comps], {
refPhase[PortStreamPairs]:RefMoleFrac[Comps]
= InputOutputStream[PortStreamPairs]:
MoleFrac[Comps];
};
refPhase[PortStreamPairs]:Initialize();
};
Props["Enth"] = True; // Property of interest.
};

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.

3-10 Modular Thermo and Process Models


3.2.2 Process Streams and Modular Thermo
Process streams define their own phase models to compute their
stream properties. However, the state information used in the
calculation is the actual state of the stream. If this is not exactly
what the parent model needs, the parent model must declare its own
phase objects.
The "bindings" sample code shown above illustrates this point very
well. The stream reference enthalpies make use of the stream
compositions. That is the purpose of the statement:
refPhase[PortStreamPairs]:RefMoleFrac[Comps]
= InputOutputStream[PortStreamPairs]:MoleFrac[Comps];
However, the Temp and Pres values must be set to the required
reference state. This creates the need for having phase models in the
parent model.

Process Models 3-11


Chapter 4
Method Calls to
MILANO from BBM
and EEB

You must provide your own implementation of the mathematical


model of an External Equation Block or a Black Box Model in a
procedural language. It is often necessary to access model data from
these implementations. The following routines have been provided
for use in the C++ environment.
Most of these routines require a 32-bit handle identifying the model
object. This handle is passed to the External Equation Block or
Black Box Model custom procedures by ROMeo.
In a few of the routines below, arrays that are allocated in ROMeo
are passed to the custom routines. A corresponding memory
deletion routine is also provided for these routines. You should call
these routines at the appropriate point.
A routine to call a MILANO method on the model object is available.
You can thus implement many of the ROMeo-specific activities in
MILANO and call such methods from your C++ procedures. A class
called MIUserAtom is used in some of the routines. This contains
data values of type integer, real, string, or a model handle. These are
especially useful in creating arguments to a MILANO method as the
arguments can be of any of the above types. Routines to convert
basic data values to a MIUserAtom and vice-versa are provided.

Process Models 4-1


4.1 Overview of Method Calls to the Model
The main use of these methods is to retrieve data from the MILANO
model object. Usually, these data are needed to set up the math
model in the BBM or EEB properly. For instance, in the conversion
reactor model discussed later in this document, function calls are
used to retrieve the list of components (page 5-42), the name of the
base component (page 5-42), the stoichiometric coefficients
(page 5-42), and the heats of formation (page 5-66).
These methods also include methods for retrieving data that may
not be directly used in the math model. One example of this is
method MI_getFullName(), which retrieves the name of the current
model object (for example, FS:Unit["CRTR"]) as shown on
page 5-41. Similarly, MI_isA() can be used to validate if the current
model object is of certain class or type (page 5-44). Function
MI_print() provides a mechanism for printing to the ROMeo
diagnostic window (page 5-46). It is thus possible through these
functions to access a great deal of model information. One use of
this flexibility is the creation of customized reports directly from a
BBM or EEB.
The BBM version of the sample conversion reactor model
illustrates the use of all the functions to call into the model. As you
study this code, please keep in mind that it is included in the BBM
C++ implementation only for illustration, not because it is essential
to the reactor model.

4.2 Include Files


The main C++ file that implements the BBM or EEB should
contain the following #include directive:
#include <PMFWrapper.h>

4-2 Method Calls to MILANO from BBM and EEB


4.3 Listing of Method Calls to MILANO Model

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.

Process Models 4-3


MI_domainAddElem()
void MI_domainAddElem(long hModel, const char* setName,
const char* element)
PURPOSE: Add an element to 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
added.
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.

4-4 Method Calls to MILANO from BBM and EEB


MI_getAttr()
MIUserAtom MI_getAttr(long hModel, const char* blockName,
const char* rowElements, long attrNum)
PURPOSE: Get 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.
RETURN: An instance of a class, MIUserAtom, containing the attribute
value. MIUserAtom class is used to pass data of different
types to ROMeo in a common interface. The MIUserAtom
can be converted to long, double or string format.

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.

Process Models 4-5


MI_getIntegerValue()
MI_getRealValue()
MI_getStringValue()
long MI_getIntegerValue(long hModel,
const char* blockName,const char* rowElements)
double MI_getRealValue(long hModel, const char*
blockName, const char* rowElements)
const char* MI_getStringValue(long hModel, const char*
blockName, const char* rowElements)
PURPOSE: Get 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.
RETURN: The integer/real/string value of the parameter.

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

4-6 Method Calls to MILANO from BBM and EEB


MI_runMethod()
MIUserAtom MI_runMethod(long hModel, const char*
methodName,long numInputArgs,
MIUserAtom argsArray[])
PURPOSE: Execute a MILANO method.
INPUT: hModel a 32-bit handle identifying the model object.
methodName pointer to a string containing the name of the
method.
numInputArgs number of input arguments of this
method.
argsArray an ordered array of MIUserAtom - each
containing value of one argument.
RETURN: An MIUserAtom containing the return value - if there is one.

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.

Process Models 4-7


MI_setIntegerInAtom()
MI_setRealInAtom()
MI_setStringInAtom()
MI_setModelHandleInAtom()
void MI_setIntegerInAtom(MIUserAtom& thisAtom,long val)
void MI_setRealInAtom(MIUserAtom& thisAtom,double val)
void MI_setStringInAtom(MIUserAtom& thisAtom,
const char* val)
void MI_setModelHandleInAtom(MIUserAtom& thisAtom,
long(ModelHandle) val)
PURPOSE: Set a MIUserAtom to a integer/real/string/
long(Modelhandle) value.
INPUT: thisAtom an MIUserAtom.
val value to which the MIUserAtom is set.
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.

4-8 Method Calls to MILANO from BBM and EEB


4.4 Attribute Values Used in Methods that Access the Model
Some of the methodss require the specification of an attribute value,
for example, MI_getAttr(). Symbolic names (actually an enum list)
are used for this purpose. The current list of values appears in the
include file MIAttributeNumbers.h. This file is distributed in the
Models\Include directory.

Model builders cannot use all the attributes listed in


MIAttributeNumbers.h. Table 4.4-1 documents the attributes which
can be used for the MILANO Integer, Real, String, and Variable
blocks. The C++ format of an attribute value is:
MIAttributeNumber::AttrName
where MIAttributeNumber is a fixed part and AttrName is a
placeholder for the names listed in the table below (for example,
MIAttributeNumber::realVal).

Table 4.4-1 contains the following information:


ATTRIBUTE The symbolic name of the attribute.
DATA TYPE The type of the value involved. The handling of the auxiliary
MIUserAtom objects should be consistent with the data type of
the attribute.
DESCRIPTIONBrief explanation of the meaning of the attribute. It is assumed
the user has access to the MILANO User's Guide, where more
details and examples can be found.
READ ONLY? Some attributes are strictly read-only. That is, none of the
MI_set__ functions can be applied to them.

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.

Process Models 4-9


Table 4.4-1 Attributes Available for Custom Models
Block Type Attribute Data Type Description Read Only?

Integer intVal Integer Value.

Real realVal Real Value expressed in internal units.

uomRealVal Real Value expressed in current UOM.

Basis String Flow basis.

Dim String Row Dimension.

dimReport String Current Dimension. Yes

UOM String Row UOM.

uomReport String Current UOM. Yes

String stringVal String Value.

Variable FXI Integer Value of fixed flag. Attributes FX and


INDEPENDENT should not be used
directly in the MILANO code for
ROMeo models because they are
generally manipulated by ROMeo
itself. Instead, FXI is to be preferred.

FS Real Bounds forced step expressed in


internal units.

I Real Initial value expressed in internal


units.

L Real Level value expressed in internal


units.

LO Real Lower bound value expressed in


internal units.

M Real Marginal value.

NS Real Bounds normal step expressed in


internal units.

RT Real Bounds relative tolerance (a ratio).

SM Real Bounds safety margin expressed in


internal units.

uomFS Real Bounds forced step expressed in


current UOM.

uomI Real Initial value expressed in current


UOM.

4-10 Method Calls to MILANO from BBM and EEB


Table 4.4-1 Attributes Available for Custom Models (cont.)
Block Type Attribute Data Type Description Read Only?

Variable uomL Real Level value expressed in current


UOM.

uomLO Real Lower bound value expressed in


current UOM.

uomNS Real Bounds normal step expressed in


current UOM.

uomSM Real Bounds safety margin expressed in


current UOM.

uomUP Real Upper bound value expressed in


current UOM.

UP Real Upper bound value expressed in


internal units.

Basis String Flow basis.

Dim String Row Dimension.

dimReport String Current Dimension. Yes

UOM String Row UOM.

uomReport String Current UOM. Yes

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";
//--------------------------------------------------------------------------------------

C++ code for the Black Box Model:


//--------------------------------------------------------------------------------------
//--- Attributes
cout << endl;
// Retrieve initial value.
MIUserAtom 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;

Process Models 4-11


// Set new value.
cout <<"wrapTempAtom: Setting value to 150 F (uomRealVal)..." << endl;
MI_setRealInAtom(wrapTempAtom, 150.0);
MI_setAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::uomRealVal,wrapTempAtom);
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,MIAttribut = " << MI_getStringInAtom(wrapTempAtom) << endl;
//---------------------------------------------------------------------------

Output from C++ code:


//---------------------------------------------------------------------------
wrapTempAtom: get ::realVal = 298.15
wrapTempAtom: get ::uomRealVal = 77
wrapTempAtom: get ::uomReport = F
wrapTempAtom: Setting value to 150 F (uomRealVal)...
wrapTempAtom: get ::realVal = 338.706
wrapTempAtom: get ::uomRealVal = 150
wrapTempAtom: get ::uomReport = F
wrapTempAtom: get ::dimReport = Temp
wrapTempAtom: get ::Basis =
//---------------------------------------------------------------------------

4-12 Method Calls to MILANO from BBM and EEB


Chapter 5
Part 1: Conversion Reactor Models

This chapter contains the complete implementation of a MILANO


process model for a simple conversion reactor. Although the
mathematical model itself is rather simple, its implementation
illustrates the full range of features normally required in more
complex process models.
The chapter starts with a description of the model, contains a
discussion of the items that must be implemented to make a
functioning ROMeo process model, and concludes with sample
source code of the process model implementation.

5.1 Conversion Reactor - Model Description


The case study example presents the same math model
implemented in three forms:
All-MILANO math model.
Black Box Model (BBM) with rest of math model in MILANO.
External Equation Block (EEB) with rest of math model in
MILANO.

It is important to realize that even when the math model is


expressed as a BBM or EEB, it is still necessary to write the rest of
the process model class in MILANO. Therefore, in the source code
sections, we will see that the MILANO code (outside of the
MathRelations section) for the three versions of the reactor class is
almost identical.

Process Models 5-1


The conversion reactor models a single reaction with known
stoichiometry. At runtime, the end user is expected to:
Specify a component slate for the reactor. (Since we are
modeling a SISO unit, the component slate in the feed stream
automatically determines the reactor component slate.)
Select a "base component" in relation to which a fractional
conversion will be specified.
Specify the fractional conversion.
Specify the stoichiometric coefficient for each component in the
reaction, with reactants and products having negative and
positive coefficients, respectively.
Specify isothermal or adiabatic mode of operation.
The objective of the math model is to compute product
concentration and flow. For isothermal operation, the duty is
computed as well. For adiabatic operation, the product temperature
is computed.

5.2 Implementation within ROMeo


The sample code presented later in this chapter shows one way to
model the reactor problem in ROMeo. Before examining the code,
let us highlight some of the issues and questions that must be
resolved during model development.
Base class - The process model must inherit from
PM_UserAddedProcessUnit. This base class has been specially
designed to support process models written as extensions to the
predefined ROMeo process model library. In particular, it is
important to follow the guidelines and specifications detailed in the
discussion of the PM_UserAddedProcessUnit class, Overview of
ROMeo Process Model Base Classes, 2.3.
Methods - The supplied base class PM_UserAddedProcessUnit
provides all the support needed to incorporate a process model into
a ROMeo flowsheet. However, the process model implementation
usually must overwrite some of the methods in the base class.
Typically methods like Initialize(), GetState(), and
GenerateEstimates() must be reimplemented. You are also free to
declare and implement brand-new methods. You must take care that

5-2 Part 1: Conversion Reactor Models


all new methods do not alter the expected behavior of any method
in the base class.
SISO, SIMO, MISO or MIMO Model - The choice of template
depends on whether a single-input single-output (SISO), single-
input multiple-output (SIMO), multiple-input single-output (MISO)
or multiple-input multiple-output (MIMO) model is required for the
unit. Four MILANO template files are included in the SIMSCI
distribution CD to help you get started. The file names are self-
explanatory:
SISOprocessUnitTemplate.milimplements class
SISOdoNothingTemplate
SIMOprocessUnitTemplate.milimplements class
SIMOdoNothingTemplate
MISOprocessUnitTemplate.milimplements class
MISOdoNothingTemplate

MIMOprocessUnitTemplate.milimplements class
MIMOoNothingTemplate

The example reactor model is a SISO unit that uses


SISOprocessUnitTemplate.mil as its starting template class.

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

Process Models 5-3


general case in which the end user is free to specify the reaction at
runtime. This flexibility requires that the model must rely on sets
and parameters declared in its base classes so that it can interact
with the rest of the ROMeo model.
Modular Thermo - When developing a model, be aware of
differences in setup procedures between "constant" and "variable"
thermo properties. In particular, make sure that bindings for
variables and sets needed in the thermo phase models are
implemented correctly.
Specification of property clause in declaration section - Many
quantities that appear in process models have intrinsic dimensions.
It is often possible to supply reasonable initial values. Property
qualifiers like <<Dim>> and <<InitialValue>> should be used to
take advantage of your knowledge of the process being modelled.
Similarly, other property qualifiers like <<Hidden>>,
<<UserOrdered>>, and <<NonSparse>> should be used to further
specialize the declarations.
Degrees of freedom - It is always important to be aware of how
degrees of freedom appear in the math model, and it is mandatory
when using OPERA as the Solver. Moreover, it is important to
determine how variable links affect the degrees of freedom. In the
sample conversion reactor we will see links coming into play:
Isothermal operation is modeled with a link between the feed
and product stream temperatures.
Adiabatic operation is modeled by fixing the duty at zero while
breaking the temperature link between the feed and product
streams.
Reporting - Make sure you account for all key quantities needed in
the material and energy balance reports.
Model testing - One benefit of degrees of freedom analysis is that
it lists the minimum information needed to test the model, thus
helping you to understand the model in a test setting.

5.2.1 Degrees of Freedom for the Reactor Model


Our reactor model contains two degrees of freedom. In most cases,
two of the following three variables are selected as independent
(fixed) variables:
v_Q duty

5-4 Part 1: Conversion Reactor Models


InputOutputStream["Product"]:Temp reactor temperature

v_conversion fractional conversion of base component

Consequently, in Simulation mode we must fix two of these


variables. By default, v_conversion is specified as independent and
fixed. The value assigned to isAdiabatic affects the model
calculations as follows:
isAdiabatic=0 Isothermal operation: reactor temperature is
equal to feed temperature; model calculates the duty.
isAdiabatic=1 Adiabatic operation: duty is fixed at zero;
model calculates reactor temperature.
A link is used to fix the reactor temperature when Adiabatic=0.
Conversely, no link is enabled when Adiabatic=1.
Additional possibilities for manipulating the degrees of freedom are
available via Unit Customization, by means of which it is possible
to designate independent and dependent variables. For example:
isAdiabatic=0 and duty is fixed (reactor temperature fixed
via link), the model calculates v_conversion.
isAdiabatic=1 and conversion and reactor temperature are
both fixed, the model calculates v_Q.
isAdiabatic=1 and heat duty and reactor temperature are
both fixed, the model calculates v_conversion.
To access Unit Customization in ROMeo, click on the reactor
flowsheet icon, then select the Customization option from the right-
click menu.

5.3 Overview of Source Code


The complete case study consists of several source code files. Refer
to Default Directory Structure with Included Files, 7.4, for the
location of these files in the ROMeo distribution.
ConvReactor.mil An all-MILANO implementation of the
conversion reactor model.
ConvReactorBBM.mil Similar to ConvReactor, but part of the
math model is represented by a Black Box Model.

Process Models 5-5


ConvReactorEEB.mil Similar to ConvReactor, but part of the
math model is represented by an External Equation Block.
ConvReactorBBM.cpp C++ code for the BBM.

ConvReactorBBM.h Auxiliary class declaration for BBM.

ConvReactorEEB.cpp C++ code for the EEB.

ConvReactorEEB.h Auxiliary class declaration for EEB.

ConvReactorIcon.dat Icon data file for class ConvReactor.

ConvReactorBBMIcon.dat Icon data file for class


ConvReactorBBM.

ConvReactorEEBIcon.dat Icon data file for class


ConvReactorEEB.

The source code contains many explanatory and instructive


comments which should prove helpful when implementing other
models. Virtually all comments for class ConvReactor are pertinent
to all three versions. For the most part, duplicate comments have
been eliminated from the BBM and EEB MILANO versions
contained in the document and replaced by references to the parallel
locations in the all-MILANO version. In some cases, comments and
source code fragments are specific to the other two classes. In
particular, look closely at the following items:
Declarations section Some equation declarations are not
needed in BBM.
MathRelations section Some equations are replaced with lists
of variables and equations for BBM and EEB. The comments in
the MathRelations section also contain the rationale for some
decisions related to BBM and EEB.
Pseudocode for implementing BBM and EEB in C++ The
pseudocode provides an easily understood, algebraic form of
the equations implemented in C++.

5-6 Part 1: Conversion Reactor Models


MILANO Source Code ConvReactor.mil

Chapter 5
Part 2: Sample Code

5.4 All-MILANO Model ConvReactor.mil


//***********************************************************
// MILANO Source Code ConvReactor.mil
// Project : ROMeo
// Subsystem : Process Model30
//
// Author : Simulation Sciences
// Date : 9/01/98
// Purpose : Conversion Reactor unit MILANO implementation class
// Copyright (c) 1998 by Simulation Sciences Inc
//***********************************************************
//
// All-Milano version of the model.
//
// Notice use of <<Group=Sample>>. This property assignment adds the
// model to the Sample group in the Model Library Manager Models window.
BeginModel ConvReactor :: PM_UserAddedProcessUnit <<Group=Sample>>;

//----------------------------------------------------------------------
//
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

// Concerning <<Dim>> and <<InitialValue>> properties


//
// Many quantities in process models have well defined
// dimensions, e.g., temperature, pressure, mass/time.
// It is strongly recommended that declarations include
// the <<Dim>> property, if applicable.
//
// Guidelines for equations:
// * Write equations in a consistent set of units.
// ROMeo carries out internal calculations using
// Internal Units, a selected set of SI units.
// Equations must be correctly expressed in Internal Units.
// (See page B-1 for a complete listing.)
// * Be careful with <<InitialValue>>, since the values
// must be specified in Internal Units.
// * The <<Dim>> property makes it possible to change

5-7 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

// 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>>;

// Stoichiometric coefficients. Negative for reactants,


// positive for products.
// Values for stoich[Comps] are supplied at runtime via the GUI;
// Number of components in [Comps] is determined by the number
// of components in the component slate.
// The <<NonSparse>> declaration and initialization
// ensure that the component slate is
// displayed in the GUI at all times.
// If an array is declared <<NonSparse>> but not initialized, it will
// not appear in the GUI until a value is assigned to it
// somewhere in the program.
// stoich[Comps] will appear in the GUI under Parameters/stoich
//
Real <<DataType=PMF_ExtRealRow>> stoich[Comps]
<<NonSparse,InitialValue=0.0>>;

// v_conversion: Fractional conversion of a Base component.


// Under most situations, v_conversion is fixed. Nevertheless,
// here we declare conversion to be a variable to allow
// for the possibility of letting v_conversion change
// during solution. Its default specification, though, is
// '.FXI' in Initialize().
// v_conversion will appear in GUI Variables/Scalar
//
Variable <<DataType=PMF_ExtVarRow>> v_conversion
<<Dim=Frac,InitialValue=0.0>>;
//
// Base component specification
//
// baseComponent: component to which extent of conversion refers.
// 1. Check for invalid conversion value:
// If the base component is NOT a limiting reactant,
// it is possible to specify an excessively large conversion,
// thus resulting in NEGATIVE mole fractions.
// 2. The base component should be a reactant, not a product.
//
String <<DataType=PMF_ExtStringRow>> baseComponent;

Process Models 5-8


MILANO Source Code ConvReactor.mil

// isAdiabatic: We have implemented two modes of operation:


// adiabatic and isothermal.
// Suggested exercise: Allow the user to specify the reactor
// temperature (same as outlet temperature). Model then calculates
// v_Q (v_conversion stays fixed). This is easily
// done using Unit Customization (right-click on Unit icon).
// Before Customization, set initial value of Temp for
// the Product stream to the desired target. Then from
// Customization, make that same Temp fixed and independent,
// and make v_Q dependent. isAdiabatic will appear in
// the GUI under Parameters/Scalar
Integer <<DataType=PMF_ExtIntRow>> isAdiabatic
<<InitialValue=0>>; // 0=Isothermal, 1=Adiabatic

// MassBalChkTol and AtomBalChkTol:


// Criteria for Mass and Atomic balance checks.
// End user can change these values via the GUI at runtime.
// MassBalChkTol & AtomBalChkTol will appear in the GUI under
// Parameters/Scalar. See Figure 6.5-2.
//
Real <<DataType=PMF_ExtRealRow>> MassBalChkTol
<<InitialValue=1.0E-2>>;
Real <<DataType=PMF_ExtRealRow>> AtomBalChkTol
<<InitialValue=1.0E-2>>;

// v_Q: Heat duty.


// Reaction type Operation mode Behavior
// ------------- -------------- -------------------------
// Exothermic Adiabatic Temperature rise
// Isothermal Negative v_Q (energy removed)
// Endothermic Adiabatic Temperature drop
// Isothermal Positive v_Q (energy added)
//

// v_Q will appear in the GUI under Variables/Scalar


// See Figure 6.5-4.
//
Variable <<DataType=PMF_ExtVarRow>>
v_Q <<Dim=Energy/Time,InitialValue=0.0>>;
//
// Internal working parameters and variables.
//
Variable <<DataType=PMF_ExtVarRow>>
v_reactionRate <<Hidden,Dim=MoleRate,InitialValue=0.0>>;
Variable <<DataType=PMF_ExtVarRow>>
v_netReaction <<Hidden,Dim=MoleRate,InitialValue=0.0>>;
Real <<DataType=PMF_ExtRealRow>>
compFlow <<Hidden,Dim=Mole/Time>>;

Real <<DataType=PMF_ExtRealRow>> AbsStoich <<Hidden>>;


// For convenience.

5-9 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

Integer <<DataType=PMF_ExtIntRow>> Ctr <<Hidden>>; // Counter.

// --------------------------------------------
// 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.

// Handle to the single ThermoProperties object:


Reference PM_ThermoProperties ThermoProperties;

// For reference: 25 C = 298.15 K, 1 Atm = 101.325 kPa


Real <<DataType=PMF_ExtRealRow>> LocalTemp
<<Hidden,Dim=Temp,InitialValue=298.15>>;
Real <<DataType=PMF_ExtRealRow>> LocalPres
<<Hidden,Dim=Pres,InitialValue=101.325>>;

// Heats of formation, heats of reaction:


// We need to save value of HForm for energy balance.
// Reason: There is a SINGLE ThermoProperties object
// for the entire flowsheet. This object can be invoked
// by any process model, thus overwriting previously
// computed values. Here we must save heat of formation
// values because they will be needed in the energy balance.
//
//
Real <<DataType=PMF_ExtRealRow>> HForm[Comps]
<<NonSparse,Dim=Energy/Mole,InitialValue=0.0>> "Heat of formation";
Real <<DataType=PMF_ExtRealRow>> HReaction
<<Hidden,Dim=Energy/Mole,InitialValue=0.0>> "Heat of reaction";
Real <<DataType=PMF_ExtRealRow>> TotHReaction
<<Hidden,Dim=Energy/Time,InitialValue=0.0>> "Total Heat of reaction";

// Mol. wt. - For illustration only (no need to save value).


Real <<DataType=PMF_ExtRealRow>>
Mws[Comps] <<NonSparse,InitialValue=0.0>>;

// Use to check mass and atomic balances.


Set MTNames / CarbAtom, HydrAtom, NitrAtom, OxygAtom, SulfAtom /;
Real <<DataType=PMF_ExtRealRow>> MassBalChk <<Hidden>>;
Real <<DataType=PMF_ExtRealRow>> AtomBalChk <<Hidden>>;
// End setup MT Constant properties

//-----------------------------------------------------------
// Start MT Variable properties
//
// This section handles thermodynamic properties that change at
// runtime (that is, during Solve), e.g., mixture enthalpy.
//
// Background:

Process Models 5-10


MILANO Source Code ConvReactor.mil

//
// 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"]

// Phase models: refPhase is the name used here to


// handle the phase model objects. It is defined over
// the set PortStreamPairs, which contains the list of
// ports/streams. Alternatively, we could have created
// only two instances of the phase model, since there is
// only one feed and one product stream. However, the
// generality shown below will come in handy in more
// complex models. The code we write in the methods and
// in MathRelations is also easier to understand and
// maintain. Notice the use of <<SubModel>> property
// to ensure that the MathRelations of each phase model
// is incorporated into the reactor math model.

PM_VaporPhase refPhase[PortStreamPairs] <<NonSparse,SubModel>>;

5-11 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

// Reference conditions and reference enthalpies for


// energy balance. Use reference state of heat of
// formation: 25 C, 1 atm. Use v_refTemp and v_refPres
// later on to bind with corresponding variables in the
// PM_VaporPhase models.
// Note: Since v_refTemp and v_refPres are not meant to
// change value, later on we make them "fixed and
// independent" using attribute '.FXI' in Initialize();
// For reference: 25 C = 298.15 K, 1 Atm = 101.325 kPa
// Internal units for Temp and Pres are K and kPa, respectively.
//
Variable <<DataType=PMF_ExtVarRow>>
v_refTemp <<Hidden,Dim=Temp,InitialValue=298.15>>;
Variable <<DataType=PMF_ExtVarRow>>
v_refPres <<Hidden,Dim=Pres,InitialValue=101.325>>;

// Declare variables to hold thermo properties of interest.


// In a more complex model, we may need many of these.
// Reference enthalpies will be needed in energy balances.
//
Variable <<DataType=PMF_ExtVarRow>>
v_refEnth[PortStreamPairs] <<NonSparse,Dim=Energy/Mole>>;

// Similarly, need to define sets Props and CompProps,


// to be bound with corresponding sets in the
// PM_VaporPhase models.
// <<UserOrdered>> : To conform with declaration
// in PM_VaporPhase.
Set Props <<UserOrdered>>;
Set CompProps <<UserOrdered>>;
// End Modular Thermo setup - VARIABLE properties
//-----------------------------------------------------------
//
// Energy Balance Report - Auxiliary parameters.
// See code where they appear, for example
// CalculateEnergyTerms(), page 5-26.
//
Real <<DataType=PMF_ExtRealRow>>
LocalEnergyIn <<Hidden,Dim=Energy/Time,InitialValue=0.0>>;
Real <<DataType=PMF_ExtRealRow>>
TotHReactionIn <<Hidden,Dim=Energy/Time,InitialValue=0.0>>;
Real <<DataType=PMF_ExtRealRow>>
HeatDutyIn <<Hidden,Dim=Energy/Time,InitialValue=0.0>>;
Real <<DataType=PMF_ExtRealRow>>
LocalEnergyOut <<Hidden,Dim=Energy/Time,InitialValue=0.0>>;
Real <<DataType=PMF_ExtRealRow>>
TotHReactionOut <<Hidden,Dim=Energy/Time,InitialValue=0.0>>;
Real <<DataType=PMF_ExtRealRow>>
HeatDutyOut <<Hidden,Dim=Energy/Time,InitialValue=0.0>>;

// Links
//

Process Models 5-12


MILANO Source Code ConvReactor.mil

// We handle an isothermal operation by linking the feed


// and product stream temperatures. The alternative
// would be to write an equation setting them equal.
Link l_Temp;

//
// 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.

// For debug printing, as needed.


Integer <<DataType=PMF_ExtIntRow>> dummy <<Hidden,InitialValue=0>>;

//
// Methods
//
DeclareMethod Void Initialize();
DeclareMethod Void UpdateLinks();
DeclareMethod Void RemoveLinks();
DeclareMethod Integer CheckStructure();

5-13 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

DeclareMethod Integer GetState();


DeclareMethod Integer GetStateWrapper(Integer ToDo);
DeclareMethod Integer GenerateEstimates();
DeclareMethod Void GenerateReport(Reference MilanoStream Report);
DeclareMethod Void CalculateEnergyTerms();
DeclareMethod Real TotalEnergyInContribution();
DeclareMethod Real TotalEnergyOutContribution();
DeclareMethod Real TotalMaterialOutContribution();
DeclareMethod Real TotalMaterialInContribution();
DeclareMethod Void GenerateEnergyBalanceReportSection
(Reference MilanoStream Report);

DeclareMethod Void BindMoleFrac();


DeclareMethod Void BindMoleFracEvent(Reference MilanoEvent evObj);
EndSection Declarations;

//----------------------------------------------------------------------
//
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;

// calculate reaction rate in terms of mole rate of baseComponent


e_ReactionRate..
// 1. AbsStoich: Ensures that v_reactionRate is POSITIVE.
// 2. v_reactionRate is equivalent to writing the
// reaction with coefficient of 1 for base component.
v_reactionRate - InputOutputStream["Feed"]:MolarFlow*v_conversion
* InputOutputStream["Feed"]:MoleFrac[baseComponent]
/ AbsStoich =E= 0;

e_NetReaction..
v_netReaction - Sum([Comps], stoich[Comps])*v_reactionRate =E= 0;

Process Models 5-14


MILANO Source Code ConvReactor.mil

e_Flow..
InputOutputStream["Product"]:MolarFlow
- InputOutputStream["Feed"]:MolarFlow
- v_netReaction =E= 0;

// Mass balance: Calculate balance for all but last


// component because material balance on the product
// stream takes care of the remaining component.
e_MBal[Comps] $((InputOutputStream["Feed"]:Comps[Comps])
AND (InputOutputStream["Product"]:Comps[Comps])
AND (Ord(Comps) NE Card(Comps)))..
InputOutputStream["Product"]:MoleFrac[Comps]
*InputOutputStream["Product"]:MolarFlow
- InputOutputStream["Feed"]:MoleFrac[Comps]
*InputOutputStream["Feed"]:MolarFlow
- stoich[Comps]*v_reactionRate =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:
//

5-15 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

// 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;

// Stream enthalpy at reference state of heat of


// formation.
//
// Guideline for handling Thermo properties:
//
// Use local variables for the properties inasmuch as
// the "Prop" variable available in the phase models
// is already declared <<Implicit>>. This means it
// cannot appear in the energy balance that goes to the EEB.
// Although the "Prop" variable can appear in the
// Input list to a BBM, it is still recommended
// that a local variable be used.
e_refEnth[PortStreamPairs]..
v_refEnth[PortStreamPairs]
- refPhase[PortStreamPairs]:Prop["Enth"] =E= 0;

EndSection MathRelations;

//----------------------------------------------------------------------
//
BeginMethod Void Initialize();
//
// Use keyword Super to invoke base class of current model.
Super:Initialize();

// Use PortStreamPair() to match stream (external) names


// with port (internal) names.
// We select "Feed" and "Product" for the port names
// because (1) they are self-explanatory, and
// (2) they match the port names used by default
// in the icon file that SIMSCI distributes with the
// generic UI DLL for SISO process units.
// (One could use different port names,
// in which case it would also be necessary to enter
// the port names in a different icon file.)
// For arguments, see PortStreamPair(), page 2-10.

Process Models 5-16


MILANO Source Code ConvReactor.mil

PortStreamPair("Feed" , 1, "", "", 0);


PortStreamPair("Product", 2, "", "", 0);

// Set up some specifications as Fixed and Independent.


v_PressureDrop.FXI = True; // User can change.
v_conversion.FXI = True; // User can change.
//Doc:
v_refTemp.FXI = True; // User should NOT change.
v_refPres.FXI = True; // User should NOT change.
EndMethod 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();

// Check if feed and product streams exist


If ( (InputOutputStream["Feed"] NE NULL) AND
(InputOutputStream["Product"] NE NULL) ),
{
If (isAdiabatic), {
// Need to unlink, in case link had previously been enabled.
UnLink l_Temp;
v_Q.FXI = True; // Declare v_Q fixed and independent.
v_Q.I = 0.0; // Set initial value.
}
Else {
v_Q.FXI = False; // In case v_Q was FXI in previous run.

5-17 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

// If streams exist, then check if they are ON


If ( (InputOutputStream["Feed"]:CurrentOnOffStatus() EQ PMF_On)
AND
(InputOutputStream["Product"]:CurrentOnOffStatus() EQ PMF_On)
),
{
l_Temp..
InputOutputStream["Product"]:Temp =<=
InputOutputStream["Feed"]:Temp;
}
Else
{
UnLink l_Temp;
};
};
}
Else
{
UnLink l_Temp;
};
EndMethod 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),

Process Models 5-18


MILANO Source Code ConvReactor.mil

{
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.

5-19 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

//----------------------------------------------------------------------
GetState_rv = PMF_OK;

// Make sure that all the dependent properties are being calculated

// Retrieve Modular Thermo properties - CONSTANT properties.


// ----------------------------------------------------------

// Set up the ThermoProperties object.


// The next group of lines is a common template.

// Bind to the single PM_ThermoProperties object available to the


// flowsheet.
ThermoProperties = GetThermoProperties();

// Clear data from previous call to ThermoProperties object.


ThermoProperties:ClearData();

// Assign Component and Property slates.


If (CurrentCompSlate EQ NULL), Return PMF_Error;
ThermoProperties:AssignComponentSlate(CurrentCompSlate:SlateName);
If (CurrentPropSlate EQ NULL), Return PMF_Error;
ThermoProperties:AssignPropertySlate(CurrentPropSlate:SlateName);

// Get name of calling model - used in error messages.


ThermoProperties:CallingModel = GetFullName();

// *** USER DATA - BEGIN ***


// List the properties of interest for this model.
// Use two sets to specify the properties:
// CompProps : List of component properties.
// Props : List of mixture properties.
// Component properties:
ThermoProperties:CompProps["Wt"] = Yes; // Molecular weight
ThermoProperties:CompProps["CarbAtom"] = Yes; // C number
ThermoProperties:CompProps["HydrAtom"] = Yes; // H number
ThermoProperties:CompProps["NitrAtom"] = Yes; // N number
ThermoProperties:CompProps["OxygAtom"] = Yes; // O number
ThermoProperties:CompProps["SulfAtom"] = Yes; // S number
ThermoProperties:CompProps["HeatForm"] = Yes; // Heat of formation
// Mixture properties:
* ThermoProperties:Props["Wt"] = Yes; // Molecular weight
* ThermoProperties:Props["Enth"] = Yes; // Enthalpy

// Specify Temperature and Pressure, if necessary.


ThermoProperties:Temp = LocalTemp; // Depends on situation.
ThermoProperties:Pres = LocalPres; // Depends on situation.
* ThermoProperties:MoleFrac[Comps] = someValues;// Depends on situation.

// Specify the Phase ("Vap", "Liq", "Liq2"); default is "Vap".

Process Models 5-20


MILANO Source Code ConvReactor.mil

* ThermoProperties:PhaseName = "Vap"; // Depends on situation.


// *** USER DATA - END ***
// Calculate properties.
// Note: Calculate() returns an error code. Model developer can
// check against PMF_OK.
ThermoProperties:Calculate();
Display ThermoProperties:CompProp; // Only to see what's happening.

// Save Heat of Formation for later use.


HForm[Comps] = ThermoProperties:CompProp["HeatForm",Comps];
// Save molecular weights - only for illustration.
Mws[Comps] = ThermoProperties:CompProp["Wt" ,Comps];

// Check mass balance.


// -------------------
MassBalChk = Sum([Comps],
stoich[Comps]*ThermoProperties:CompProp["Wt",Comps]);
If (Abs(MassBalChk) GT Abs(MassBalChkTol)),
{
print("%-40s:\n", GetName());
print(" CheckStructure - Error: Mass balance check not
satisfied.\n");
print(" MassBalChk = %f\n", MassBalChk);
print(" MassBalChkTol = %f\n", MassBalChkTol);
GetState_rv = PMF_Error;
};

// Check atomic balance.


// ---------------------
// Note: Modular Thermo reports atomic composition
// only for C, H, N, O, S.
Loop [MTNames], {
AtomBalChk = Sum([Comps],
stoich[Comps]*ThermoProperties:CompProp[MTNames,Comps]);
If (Abs(AtomBalChk) GT Abs(AtomBalChkTol)),
{
print("%-40s:\n", GetName());
print(" CheckStructure - Error: Atomic balance
check not satisfied.\n");
print(" MTName = %s\n", MTNames.Label);
print(" AtomBalChk = %f\n", AtomBalChk);
print(" AtomBalChkTol = %f\n", AtomBalChkTol);
GetState_rv = PMF_Error;
};
};

If (GetState_rv EQ PMF_OK), {
AbsStoich = Abs(stoich[baseComponent]);
HReaction = Sum([Comps], stoich[Comps]*HForm[Comps])/AbsStoich;
};

5-21 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

// Setup for Modular Thermo and refPhase[].


// -----------------------------------------
// Recall that this is done to calculate the Feed and Product
// enthalpies at the REFERENCE CONDITION used for the
// heat of formation. Since the stream compositions are
// not known in advance, the required enthalpies become
// variables. The property value from the PM_VaporPhase
// models is found in refPhase[PortStreamPairs]:Prop["Enth"].
If (GetState_rv EQ PMF_OK), {
// Bind different data members.
Loop [PortStreamPairs], {
refPhase[PortStreamPairs]:RefTemp = v_refTemp;
refPhase[PortStreamPairs]:RefPres = v_refPres;
refPhase[PortStreamPairs]:BindToExternalMoleFrac = 1;
refPhase[PortStreamPairs]:AssignComponentSlate(CurrentCompSlate);
refPhase[PortStreamPairs]:AssignPropertySlate(CurrentPropSlate );
refPhase[PortStreamPairs]:RefProps = Props;
refPhase[PortStreamPairs]:RefCompProps = CompProps;
Loop [Comps], {
refPhase[PortStreamPairs]:RefMoleFrac[Comps]
= InputOutputStream[PortStreamPairs]:MoleFrac[Comps];
};
refPhase[PortStreamPairs]:Initialize();
};
Props["Enth"] = True; // Property of interest.
};

// Specify flash calc type for product stream based on


// 2 specs. Options are:
// "TP" = Temp/Pres
// "HP" = Enthalpy(Duty)/Pres
// "HT" = Enthalpy(Duty)/Temp
// "BubP" = Bubble Point/Pres
// "BubT" = Bubble Point/Temp
// "DewP" = Dew Point/Pres
// "DewT" = Dew Point/Temp
// "VapFracP" = Vapor Fraction/Pres
// "VapFracT" = Vapor Fraction/Temp
If (GetState_rv EQ PMF_OK), {
InputOutputStream["Product"]:FlashType = "TP";
};

Return GetState_rv;
EndMethod CheckStructure;

//----------------------------------------------------------------------
//
BeginMethod Integer GenerateEstimates() ;
//
//----------------------------------------------------------------------

Process Models 5-22


MILANO Source Code ConvReactor.mil

// 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".

// In GenerateEstimates() we want to come up with


// reasonable estimates of the solution. One strategy is
// to "solve" the math model for one variable at a time,
// if possible.
//
// Our reactor model turns out to be too simple to require estimates
// (except for outlet temperature), since conversion is
// usually fixed and all equations except the energy
// balance can be readily solved for a variable.
//
// Here we introduce a factor of 0.5 in the calculation
// of v_reactionRate.L, only to make things slightly more
// interesting to the Solver. (One would not do this
// in a realistic model.)

v_reactionRate.L = 0.5*InputOutputStream["Feed"]:MolarFlow.L
*v_conversion.L
*InputOutputStream["Feed"]:MoleFrac.L[baseComponent]
/Abs(stoich[baseComponent]);

v_netReaction.L = Sum([Comps], stoich[Comps])*v_reactionRate.L;

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;

Loop [Comps] $(InputOutputStream["Feed"]:Comps[Comps]


AND InputOutputStream["Product"]:Comps[Comps]),
{
compFlow = InputOutputStream["Feed"]:MoleFrac.L[Comps]
*InputOutputStream["Feed"]:MolarFlow.L
+ stoich[Comps]*v_reactionRate.L;

InputOutputStream["Product"]:MoleFrac.L[Comps]
= compFlow/InputOutputStream["Product"]:MolarFlow.L;
};

5-23 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

If (isAdiabatic), {
InputOutputStream["Product"]:Temp.L =
InputOutputStream["Feed"]:Temp.L;
v_Q.L = 0;
};

v_refEnth.L[PortStreamPairs] = 0.0; // Expedient!

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!

PrintProcessUnitBanner("Conversion Reactor", Report);


PrintThermoInfo(Report);

Report:print("Process Model Type %s\n", Type());


Report:print("%-19s %-15g %s\n","Conversion", v_conversion.uomL,
v_conversion.uomReport);
Report:print("%-19s %-15g %s\n","Heat Duty" ,v_Q.uomL,v_Q.uomReport );

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);

Process Models 5-24


MILANO Source Code ConvReactor.mil

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"

5-25 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

,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;

If (TotHReaction LT 0), {TotHReactionIn = -TotHReaction;


TotHReactionOut= 0.0;}
Else {TotHReactionOut= TotHReaction; TotHReactionIn = 0.0;};

If (v_Q.L GT 0), {HeatDutyIn = v_Q.L; HeatDutyOut= 0.0;}


Else {HeatDutyOut= -v_Q.L; HeatDutyIn = 0.0;};

EndMethod CalculateEnergyTerms;

//----------------------------------------------------------------------
//
BeginMethod Real TotalEnergyInContribution();
//
//----------------------------------------------------------------------
// TotalEnergyInContribution()
//PENDING: Explain what we do here; purpose of this method.

CalculateEnergyTerms();
LocalEnergyIn = TotHReactionIn
+HeatDutyIn

Process Models 5-26


MILANO Source Code ConvReactor.mil

-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 ("%-39s%-#20.4g%-#20.4g\n","Reference Enthalpy"


,-
v_refEnth.uomL["Feed"]*InputOutputStream["Feed"]:MolarFlow.uomL
,-
v_refEnth.uomL["Product"]*InputOutputStream["Product"]:MolarFlow.uomL
);

5-27 Part 2: Sample Code


MILANO Source Code ConvReactor.mil

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;

Process Models 5-28


MILANO Source Code for BBM ConvReactorBBM.mil

5.5 Black Box Model ConvReactorBBM.mil


//***********************************************************
// MILANO Source Code for BBM ConvReactorBBM.mil
// Project : ROMeo
// Subsystem : Process Model
// Author : Simulation Sciences
// Date : 9/01/98
// Purpose : Conversion Reactor unit MILANO implementation class
// Copyright (c) 1998 by Simulation Sciences Inc
// ALL RIGHTS RESERVED
//***********************************************************
// Comments and code in ConvReactorBBM.mil that differ from
// or supplement the all-MILANO implementation ConvReactor.mil
// are indicated by a change bar in the margin.
//
// In many cases, long sections of code and comments in
// ConvReactorBBM.mil that are identical to those found in
// ConvReactor.mil have been deleted.
//
// Black Box Model version.
// Notice use of <<Group=Sample>>. See page 5-29.
BeginModel ConvReactorBBM :: PM_UserAddedProcessUnit <<Group=Sample>>;

//----------------------------------------------------------------------
//
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>>;

5-29 Part 2: Sample Code


MILANO Source Code for BBM ConvReactorBBM.mil

//
// 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>>;

// Declare Black Box Model (BBM).

Process Models 5-30


MILANO Source Code for BBM ConvReactorBBM.mil

// NOTE: Entire '<<...>>' property clause MUST fit in a single line!


BlackBox m_rxnModel << DLLName=ConvReactorBBM.dll,
SizeSparsityProc="modelSparsity", FuncGradProc="modelEvaluation",
ExitProc="modelCleanUp">>;

//
/------------------------------------------------------------------
// 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.

// INPUT variables. For C++ code, see page 5-42.


Input v_conversion;
Input v_PressureDrop;
Input InputOutputStream["Feed"]:Pres;
Input InputOutputStream["Feed"]:MolarFlow;
// Include ALL Feed moleFrac, in the event
// that baseComponent is last entry in set Comps.
Loop [Comps],
{Input InputOutputStream["Feed"]:MoleFrac[Comps];};

// List of OUTPUT variables. For C++ code, see page 5-43.


Output InputOutputStream["Product"]:Pres;
Output v_reactionRate;
Output v_netReaction;
Output InputOutputStream["Product"]:MolarFlow;
// Do not include last product component because
// material balance on the stream takes
// care of it.
Loop [Comps] $ (Ord(Comps) NE Card(Comps)),
{Output InputOutputStream["Product"]:MoleFrac[Comps];};

5-31 Part 2: Sample Code


MILANO Source Code for BBM ConvReactorBBM.mil

};

// See Energy balance, page 5-15, for explanation why


// the Milano version is used for both the all-Milano
// and Black Box Model classes.
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;

// See Stream Enthalpy at reference state of Heat of


// Formation, page 5-16, for comments.
e_refEnth[PortStreamPairs]..
v_refEnth[PortStreamPairs]
- refPhase[PortStreamPairs]:Prop["Enth"] =E= 0;

*++++++++++++++++++++++++++++++++++++++++++++++++
* 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

Process Models 5-32


MILANO Source Code for BBM ConvReactorBBM.mil

*
* 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
* ;
*

5-33 Part 2: Sample Code


MILANO Source Code for BBM ConvReactorBBM.mil

* // For ProdMolarFlow NE 0.0


* // ------------------------
*
* d ProdMoleFrac[Comps] stoich[Comps] d v_reactionRate
* --------------------- = ------------- * ----------------
* d v_conversion ProdMolarFlow d v_conversion
*
* ProdMoleFrac[Comps] d ProdMolarFlow
* - ------------------- * ------------------
* ProdMolarFlow d v_conversion
*
*
* d ProdMoleFrac[Comps] FeedMoleFrac[Comps]
* --------------------- = -------------------
* d FeedMolarFlow ProdMolarFlow
*
* stoich[Comps] d v_reactionRate
* + ------------- * ----------------
* ProdMolarFlow d FeedMolarFlow
*
* ProdMoleFrac[Comps] d ProdMolarFlow
* - ------------------- * ------------------
* ProdMolarFlow d FeedMolarFlow
*
*
*
* // If ProdMoleFrac[Comps] has Comps == bC
* // --------------------------------------
*
* d ProdMoleFrac[bC] FeedMolarFlow
* ------------------ = ----------------
* d FeedMoleFrac[bC] ProdMolarFlow
*
* stoich[bC] d v_reactionRate
* + ------------- * ------------------
* ProdMolarFlow d FeedMoleFrac[bC]
*
* ProdMoleFrac[Comps] d ProdMolarFlow
* - ------------------- * ------------------
* ProdMolarFlow d FeedMoleFrac[bC]
*
*
* // If ProdMoleFrac[Comps] has Comps != bC
* // --------------------------------------
*
* d ProdMoleFrac[Comps] FeedMolarFlow
* --------------------- = ----------------
* d FeedMoleFrac[Comps] ProdMolarFlow
*

Process Models 5-34


MILANO Source Code for BBM ConvReactorBBM.mil

* d ProdMoleFrac[Comps] stoich[Comps] d v_reactionRate


* --------------------- = ------------- * ------------------
* d FeedMoleFrac[bC] ProdMolarFlow d FeedMoleFrac[bC]
*
* ProdMoleFrac[Comps] d ProdMolarFlow
* - ------------------- * ------------------
* ProdMolarFlow d FeedMoleFrac[bC]
*
* // Backup copy (general form)
*
* d ProdMoleFrac[Comps] FeedMolarFlow
* ---------------------- = ---------------- (if Comps2==Comps)
* d FeedMoleFrac[Comps2] ProdMolarFlow
*
* stoich[Comps] d v_reactionRate
* + ------------- * ---------------------- (if Comps2==bC)
* ProdMolarFlow d FeedMoleFrac[Comps2]
*
* ProdMoleFrac[Comps] d ProdMolarFlow
* - ------------------- * ---------------- (if Comps2==bC)
* ProdMolarFlow d FeedMoleFrac[Comps2]
*
*++++++++++++++++++++++++++++++++++++++++++++++++

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();

5-35 Part 2: Sample Code


MILANO Source Code for BBM ConvReactorBBM.mil

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;

//----------------------------------------------------------------------
//

Process Models 5-36


MILANO Source Code for BBM ConvReactorBBM.mil

BeginMethod Integer GenerateEstimates() ;


//
// Implementation of GenerateEstimates() in
// ConvReactorBBM.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
// ConvReactorBBM.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 ConvReactorBBM.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
// 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;

5-37 Part 2: Sample Code


C++ Source Code Black Box Model Header File ConvReactorBBM.h

5.6 Black Box Model ConvReactorBBM.h

#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().
//

Process Models 5-38


C++ Source Code Black Box Model Header File ConvReactorBBM.h

// 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.

// The matter of set-up classes is UNNECESSARY if your C++ code


// does not retrieve data from the MILANO model. That is, if
// nothing is retrieved, then there is nothing to be "remembered."
// Said another way, if you never have to use the pModel pointer
// passed to the DLL functions, you don't need to define setup
// classes.
//

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);

// Pointer to Milano model.


long pModel; // Just in case it's needed somewhere else.

5-39 Part 2: Sample Code


C++ Source Code Black Box Model Header File ConvReactorBBM.h

// "Handles" to data (sets and parameters)


//needed to write the Equations.
// ----------------------------------------------------------------
long sizeComps; // Number of elements in set Comps.
const char** Comps; // List of elements in set Comps.
const char* baseComponent; // Name of base component.
long BCIndex; // Offset of baseComponent in set Comps.
double* stoich; // Pointer to stoich[].
double stoichBC; // Value of stoich[baseComponent].
double AbsStoichBC; // Value of Abs(stoich[baseComponent]).

// Offset in the varValuesInput and varValuesOutput arrays.


// --------------------------------------------------------
// INPUTS
int o_conversion;
int o_PresDrop;
int o_FeedPres;
int o_FeedMolarFlow;
int o_FeedMoleFrac0; // FIRST entry in FeedMoleFrac list.

// OUTPUTS
int o_reactionRate;
int o_netReaction;
int o_ProdPres;
int o_ProdMolarFlow;
int o_ProdMoleFrac0; // FIRST entry in ProdMoleFrac list.

// Auxiliary info for use in modelEvaluation() procedure.


long NumInputVariable;
long NumOutputVariable;
long NumNonZero;
};

#endif // CONVREACTOR_BBM_H_INCLUDED

Process Models 5-40


C++ Source Code for Black Box Model ConvReactorBBM.cpp

5.7 Black Box Model ConvReactorBBM.cpp


//----------------------------------------------------------------------
// C++ Source Code for Black Box Model ConvReactorBBM.cpp
// Project : ROMeo
// Subsystem : Process Model
//
// Purpose : Conversion Reactor Model - BBM implemented as a DLL
//
// Copyright (c) 1998 by Simulation Sciences Inc
// ALL RIGHTS RESERVED
//----------------------------------------------------------------------

// Standard C++ include files


#include <iostream.h>
#include <string.h>
#include <math.h>

// ROMeo Model Development Include Files.


#include "PMFWrapper.h"

// Auxiliary classes and functions for this DLL


// in support of the "setup" class.
#include "ConvReactorBBM.h"

//----------------------------------------------------------------------
// 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)
{

cout << endl;


cout << "\n\n\n\n\n" << endl;
cout << " Entering modelSparsity ... queryFlag = " << queryFlag
<< endl;
cout << " getFullName() :" << MI_getFullName(pModel) << endl;
// Illustration only.

int i; // Working offset, usually for set Comps.


int j; // Working offset, usually for derivatives.
int k; // Working offset, usually for variables and equations.

5-41 Part 2: Sample Code


C++ Source Code for Black Box Model ConvReactorBBM.cpp

if (queryFlag == 1) {
// Assume that Milano code handles error situation (GetState()).
// - Only trouble might be for SClients (SimSci developers).

// Create "set up" object. Pointer pS becomes key player!


SaveSetUp* pS = new SaveSetUp(pModel);

// Save pointer to BBMSave object just created.


// --------------------------------------------
MI_setIntegerValue(pModel,"CPPBlockAddr", NULL, (long) pS);

// --------------------------------------------
// 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;
}

// Allocate stoich. Notice check for sizeComps.


if (pS->sizeComps) pS->stoich = new double[pS->sizeComps];

// Retrieve and save value of stoich[].


for (i=0; i<pS->sizeComps; i++) {
pS->stoich[i] = MI_getRealValue(pModel,"stoich",pS->Comps[i]);
}

// Retrieve and save value of stoich[baseComponent].


if (pS->sizeComps) pS->stoichBC = pS->stoich[pS->BCIndex];
if (pS->sizeComps) pS->AbsStoichBC = abs(pS->stoichBC);

// 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;

Process Models 5-42


C++ Source Code for Black Box Model ConvReactorBBM.cpp

// 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 ;

// Print debug info (OPTIONAL - for illustration).


// Users may want to do something like this anyway.
cout << endl;
cout << "(Hex) ps = " << pS << endl;
cout << "(long) ps = " << (long) pS << endl;
cout << "(long) pModel = " << pModel << endl;
cout << endl;
cout << "sizeComps = " << pS->sizeComps << endl;
for (i=0; i<pS->sizeComps; i++) {
cout << "Comps[i]= " << pS->Comps[i] << " \tstoich[i]= "
<< pS->stoich[i] << endl;
}

cout << "baseComponent = " << pS->baseComponent << endl;


cout << "BCIndex = " << pS->BCIndex << endl;
cout << "Comps[BCIndex] = " << pS->Comps[pS->BCIndex] << endl;
cout << "stoichBC = " << pS->stoichBC << endl;
cout << "AbsStoichBC = " << pS->AbsStoichBC << endl;
cout << endl;
cout << "o_conversion = " << pS->o_conversion << endl;
cout << "o_PresDrop = " << pS->o_PresDrop << endl;
cout << "o_FeedPres = " << pS->o_FeedPres << endl;
cout << "o_FeedMolarFlow = " << pS->o_FeedMolarFlow << endl;
cout << "o_FeedMoleFrac0 = " << pS->o_FeedMoleFrac0 << endl;
cout << endl;
cout << "o_ProdPres = " << pS->o_ProdPres << endl;
cout << "o_reactionRate = " << pS->o_reactionRate << endl;
cout << "o_netReaction = " << pS->o_netReaction << endl;
cout << "o_ProdMolarFlow = " << pS->o_ProdMolarFlow << endl;
cout << "o_ProdMoleFrac0 = " << pS->o_ProdMoleFrac0 << endl;
cout << endl;

5-43 Part 2: Sample Code


C++ Source Code for Black Box Model ConvReactorBBM.cpp

cout << "Number INPUT vars = "


<< pS->o_FeedMoleFrac0+pS->sizeComps << endl;
cout << "Number OUTPUT vars = "
<< pS->o_ProdMoleFrac0+pS->sizeComps-1 << endl;
cout << endl;
cout << "NumInputVariable = "
<< pS->NumInputVariable << endl;
cout << "NumOutputVariable = "
<< pS->NumOutputVariable << endl;
cout << "NumNonZero = "
<< pS->NumNonZero << endl;

//-----------------------------------------------------
//Sample function calls - BEGIN ---------------------
//-----------------------------------------------------
//--- Current model's full name
cout << " getFullName(): [" << MI_getFullName(pModel)
<< "]" << endl;

//--- Checking Model Type


cout << endl;
char* maybe[] = {"ConvReactorBBM",
"PM_UserAddedProcessUnit",
"BadModelName"};
for (i=0; i<3; i++) {
int typechecks = MI_isA(pModel, maybe[i]);
if (typechecks==1)
cout << " Model type is: " << maybe[i] << endl;
else if (typechecks==-1)
cout << " Model is derived from: " << maybe[i] << endl;
else
cout << " ** ERROR Type of Model does not check: "
<< maybe[i] << endl;
}

//--- Make a MILANO method call - GetStateWrapper().


// This method passes an argument: 1 means GetState() is to be run
// The return argument will be GetState's return code - normally 0.
cout << endl;
MIUserAtom inAtom[1];
inAtom[0] = (long)1; // For ToDo argument in method
MIUserAtom outAtom;
// Call to MI_runMethod()
outAtom = MI_runMethod(pModel, "GetStateWrapper", 1 , inAtom);
int mret = MI_getIntegerInAtom(outAtom);
cout << " Return Code from GetStateWrapper() = " << mret << endl;

//--- Accessing another model handle - for its parent model


cout << endl;
outAtom = MI_runMethod(pModel, "Parent", 0 , inAtom);
long pHandle = MI_getModelHandleInAtom(outAtom);

Process Models 5-44


C++ Source Code for Black Box Model ConvReactorBBM.cpp

cout << " Parent : getFullName() = ["


<< MI_getFullName(pHandle) << "]" << endl;

//--- Set operations.


cout << endl;
int sizeWrapSet1 = MI_domainGetCount(pModel,"wrapSet1");
const char** wrapSet1 = MI_domainGetAllElems(pModel, "wrapSet1");
cout << " wrapSet1: size (BEFORE) = " << sizeWrapSet1 << endl;
cout << " wrapSet1: elements (BEFORE):" << endl;
for (i=0; i<sizeWrapSet1; i++) {
cout << " wrapSet1[" << i << "] = " << wrapSet1[i] << endl;
}
cout << " wrapSet1: Adding and deleting elements..." << endl;
// Astros already in.
// See Figure 6.5-8 for original members.
MI_domainAddElem (pModel,"wrapSet1","Astros" ); cout <<" Add:
Astros size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;
// Delete Padres
MI_domainDelElem (pModel,"wrapSet1","Padres" ); cout <<" Del:
Padres size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;
// Add Rangers
MI_domainAddElem (pModel,"wrapSet1","Rangers"); cout <<" Add:
Rangers size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;
// Delete remaining members.
MI_domainDelElem (pModel,"wrapSet1","Yankees"); cout <<" Del:
Yankees size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;
MI_domainDelElem (pModel,"wrapSet1","Braves" ); cout <<" Del:
Braves size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;
// Cubs not in set!
MI_domainDelElem (pModel,"wrapSet1","Cubs" ); cout <<" Del:
Cubs size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;
MI_domainDelElem (pModel,"wrapSet1","Indians"); cout <<" Del:
Indians size= " << MI_domainGetCount(pModel,"wrapSet1") << endl;

MI_deleteMemory_domainGetAllElems(wrapSet1); // Recover memory.

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;
}

MI_deleteMemory_domainGetAllElems(wrapSet1); // Recover memory.

//--- Attributes.
cout << endl;
// Retrieve initial value.
MIUserAtom wrapTempAtom =
MI_getAttr(pModel,"wrapTemp",NULL,MIAttributeNumber::realVal);

5-45 Part 2: Sample Code


C++ Source Code for Black Box Model ConvReactorBBM.cpp

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;

// Set new value.


cout << " wrapTempAtom: Setting value to 150 F (uomRealVal)..." <<
endl;
MI_setRealInAtom(wrapTempAtom, 150.0);
//... Notice use of uomRealVal instead of realVal.
// This way the 150 means degrees F instead of degrees K.

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;

//--- Printing to log file.


cout << endl;
char* textLevel[3] = {"Information", "Warning", "Error"};
char* textServer[2] = {"standard output", "server transaction
log"};
for (i=0; i<3; i++) {
for (j=0; j<2; j++) {
char theMsg[200];
strcpy(theMsg, " MI_print(): Test ");
strcat(theMsg, textLevel[i] );
strcat(theMsg, " message is printing to ");
strcat(theMsg, textServer[j] );

Process Models 5-46


C++ Source Code for Black Box Model ConvReactorBBM.cpp

strcat(theMsg, ".\n");
MI_print(i+1, theMsg, j);
}
}

//-----------------------------------------------------
//Sample function calls - END -----------------------
//-----------------------------------------------------
}

if (queryFlag == 2) {

// Get pointer to "setup" object previously saved.


// ------------------------------------------------
SaveSetUp* pS = (SaveSetUp*)
MI_getIntegerValue(pModel,"CPPBlockAddr",NULL);

// Fill in arrays numVarInEqn, varIndex.


// This is patterned after calculations of numNonZero (Section N).

j = 0; // Keeps track of derivatives.


k = 0; // Keeps track of output variables (the equations).

// 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.
{

5-47 Part 2: Sample Code


C++ Source Code for Black Box Model ConvReactorBBM.cpp

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;

// Print debug info (OPTIONAL - for illustration).


// Users may want to do something like this anyway.
cout << "--- @11: Listing of numVarInEqn[] and varIndex[]" << endl;
for (k=0, j=0; k<*numOutputVariable; k++) {
cout << endl;
cout << " numVarInEqn[" << k <<"] = " << numVarInEqn[k] <<
endl;
for (i=0; i<numVarInEqn[k]; i++, j++) {
cout << " varIndex[" << j << "] = " << varIndex[j] << "
varInputIndex" << 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)
{

Process Models 5-48


C++ Source Code for Black Box Model ConvReactorBBM.cpp

cout << endl;


cout << " Entering modelEvaluation ..." << " flagCalc = "
<< flagCalc << endl;
cout << " getFullName() :" << MI_getFullName (pModel) << endl;
// Illustration only.

int i; // Working offset, usually for set Comps.


int j; // Working offset, usually for derivatives.
int k; // Working offset, usually for variables and equations.

double sumStoich; // Intermediate value.


double scratch1; // Intermediate value.
double scratch2; // Intermediate value.
double scratch3; // Intermediate value.

int reactionRate_conversion ;// Save this index in derivatives[].


int reactionRate_FeedMolarFlow ;// Save this index in derivatives[].
int reactionRate_FeedMoleFracBC ;// Save this index in derivatives[].
int NetReaction_conversion ;// Save this index in derivatives[].
int NetReaction_FeedMolarFlow ;// Save this index in derivatives[].
int NetReaction_FeedMoleFracBC ;// Save this index in derivatives[].
int Flow_conversion ;// Save this index in derivatives[].
int Flow_FeedMolarFlow ;// Save this index in derivatives[].
int Flow_FeedMoleFracBC ;// Save this index in derivatives[].

// Get pointer to "set up" object previously saved.


// ------------------------------------------------
SaveSetUp* pS = (SaveSetUp*)
MI_getIntegerValue(pModel,"CPPBlockAddr",NULL);

if (flagCalc==1 || flagCalc==3) {
// OUTPUT function values.
// -----------------------
// This is patterned after calculations of numNonZero (Section N).

k = 0; // Keeps track of output variables (the equations).

// 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;

5-49 Part 2: Sample Code


C++ Source Code for Black Box Model ConvReactorBBM.cpp

// 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).

j = 0; // Keeps track of derivatives.

// e_Pres
derivatives[j++] = -1.; // PresDrop

derivatives[j++] = 1.; // FeedPres

// e_ReactionRate
derivatives[reactionRate_conversion = j++] // conversion
= varValuesInput[pS->o_FeedMolarFlow]
*varValuesInput[pS->o_FeedMoleFrac0
+ pS->BCIndex]
/pS->AbsStoichBC;

derivatives[reactionRate_FeedMolarFlow = j++] // FeedMolarFlow

Process Models 5-50


C++ Source Code for Black Box Model ConvReactorBBM.cpp

= varValuesInput[pS->o_conversion]
*varValuesInput[pS->o_FeedMoleFrac0
+ pS->BCIndex]
/pS->AbsStoichBC;

derivatives[reactionRate_FeedMoleFracBC = j++] // FeedMoleFracBC


= varValuesInput[pS->o_conversion]
*varValuesInput[pS->o_FeedMolarFlow]
/pS->AbsStoichBC;

// e_NetReaction
derivatives[NetReaction_conversion = j++] // conversion
= sumStoich*derivatives[reactionRate_conversion];

derivatives[NetReaction_FeedMolarFlow = j++] // FeedMolarFlow


= sumStoich*derivatives[reactionRate_FeedMolarFlow];

derivatives[NetReaction_FeedMoleFracBC = j++] // FeedMoleFracBC


= sumStoich*derivatives[reactionRate_FeedMoleFracBC];

// e_Flow
derivatives[Flow_conversion = j++] // conversion
= derivatives[NetReaction_conversion];

derivatives[Flow_FeedMolarFlow = j++] // FeedMolarFlow


= 1+derivatives[NetReaction_FeedMolarFlow];

derivatives[Flow_FeedMoleFracBC = j++] // FeedMoleFracBC


= derivatives[NetReaction_FeedMoleFracBC];

// 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];

// With respect to conversion.


derivatives[j++] = scratch1
*derivatives[reactionRate_conversion]
-scratch2
*derivatives[Flow_conversion];

// With respect to FeedMolarFlow.


derivatives[j++] = varValuesInput[pS->o_FeedMoleFrac0 + i]
/varValuesOutput[pS->o_ProdMolarFlow]
+scratch1
*derivatives[reactionRate_FeedMolarFlow]
-scratch2

5-51 Part 2: Sample Code


C++ Source Code for Black Box Model ConvReactorBBM.cpp

*derivatives[Flow_FeedMolarFlow];

// With respect to FeedMoleFrac[Comps] and


FeedMoleFrac[baseComponent].
// Careful!
derivatives[j++] = varValuesInput[pS->o_FeedMolarFlow]
/varValuesOutput[pS->o_ProdMolarFlow];
scratch3 = scratch1
*derivatives[reactionRate_FeedMoleFracBC]
-scratch2
*derivatives[Flow_FeedMoleFracBC];
if (i != pS->BCIndex) {
derivatives[j++] = scratch3; // Increment j.
}
else {
derivatives[j-1] += scratch3;
// Subtract 1 to update PREVIOUS entry.
}
}
else {
derivatives[j++] = 0; // o_conversion;
derivatives[j++] = 0; // o_FeedMolarFlow;
derivatives[j++] = 0; // o_FeedMoleFrac0 + i;
if (i != pS->BCIndex) {
derivatives[j++] = 0; // o_FeedMoleFrac0 + BCIndex;
}
}
}

// 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;
}

/---------------------------------------------------------------------

extern "C" __declspec (dllexport)


long modelCleanUp (long pModel)
{

cout << endl;


cout << " Entering modelCleanUp ..." << endl;
cout << " getFullName() :" << MI_getFullName (pModel) << endl;

Process Models 5-52


C++ Source Code for Black Box Model ConvReactorBBM.cpp

// Illustration only.

// Get pointer to "set up" object previously saved.


// ------------------------------------------------
SaveSetUp* pS = (SaveSetUp*)
MI_getIntegerValue(pModel,"CPPBlockAddr",NULL);

if (pS) delete pS;

cout << " Leaving modelCleanUp ..." << endl;


cout << endl;

return 0;
}

5-53 Part 2: Sample Code


MILANO Source Code for External Equation Block ConvReactorEEB.mil

5.8 External Equation Block ConvReactorEEB.mil


//***********************************************************
// MILANO Source Code for External Equation Block ConvReactorEEB.mil
// Project : ROMeo
// Subsystem : Process Model
// Author : Simulation Sciences
// Date : 9/01/98
// Purpose : Conversion Reactor unit MILANO implementation class
// Copyright (c) 1998 by Simulation Sciences Inc
// ALL RIGHTS RESERVED
//***********************************************************
// Comments and code in ConvReactorEEB.mil that differ from
// or supplement the all-MILANO implementation ConvReactor.mil
// are indicated by a change bar in the margin.
//
// In many cases, long sections of code and comments in
// ConvReactorEEB.mil that are identical to those found in
// ConvReactor.mil have been deleted.
//
// External Equation Block version
// Notice use of <<Group=Sample>>. See page 5-7.
BeginModel ConvReactorEEB :: PM_UserAddedProcessUnit <<Group=Sample>>;

//---------------------------------------------------------------------
//
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>>;

Process Models 5-54


MILANO Source Code for External Equation Block ConvReactorEEB.mil

//
// 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>>;

5-55 Part 2: Sample Code


MILANO Source Code for External Equation Block ConvReactorEEB.mil

// Declare External Equation Block (EEB).


// Note: Entire '<<...>>' property clause MUST fit in a single line!
ExternalEquationBlock m_rxnModel << DLLName=ConvReactorEEB.dll,
SizeSparsityProc="modelSparsity", FiniteDifference=False,
FuncGradProc="modelEvaluation", ExitProc="modelCleanUp">>;

/------------------------------------------------------------------
// 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.

// List of VARIABLES. For corresponding C++ code, see page 5-66.


Include v_conversion;
Include v_reactionRate;
Include v_netReaction;
Include v_PressureDrop;
Include InputOutputStream["Feed"]:Pres;
Include InputOutputStream["Feed"]:MolarFlow;
Include InputOutputStream["Feed"]:Prop["Enth"];
Include v_refEnth["Feed"];
// Detail: Include ALL Feed moleFrac, in the event
// that baseComponent is last entry in set Comps.
Loop [Comps],
{Include InputOutputStream["Feed"]:MoleFrac[Comps];};

Include v_Q;
Include InputOutputStream["Product"]:Pres;
Include InputOutputStream["Product"]:MolarFlow;
Include InputOutputStream["Product"]:Prop["Enth"];
Include v_refEnth["Product"];

Process Models 5-56


MILANO Source Code for External Equation Block ConvReactorEEB.mil

// Include all Product components but one because


// material balance on the product stream takes
// care of the remaining component.
Loop [Comps] $ (Ord(Comps) NE Card(Comps)),
{Include InputOutputStream["Product"]:MoleFrac[Comps];};

// 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;
};

// Stream Enthalpy at reference state of Heat of


// Formation.
//
// Guideline for handling Thermo properties:
//
// Use local variables for the properties, because
// the "Prop" variable available in the phase models
// already is declared <<Implicit>>. This means it
// cannot appear in the energy
// balance that goes to the EEB). Although the "Prop"
// variable can appear in the Input list to a BBM, it
// is still recommended that a local variable be used.
e_refEnth[PortStreamPairs]..
v_refEnth[PortStreamPairs]
- refPhase[PortStreamPairs]:Prop["Enth"] =E= 0;

//----------------------------------------------------------------------
* 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

5-57 Part 2: Sample Code


MILANO Source Code for External Equation Block ConvReactorEEB.mil

*
* 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

Process Models 5-58


MILANO Source Code for External Equation Block ConvReactorEEB.mil

*
* 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
*

5-59 Part 2: Sample Code


MILANO Source Code for External Equation Block ConvReactorEEB.mil

* 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;

//----------------------------------------------------------------------

Process Models 5-60


MILANO Source Code for External Equation Block ConvReactorEEB.mil

//
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;

5-61 Part 2: Sample Code


MILANO Source Code for External Equation Block ConvReactorEEB.mil

//----------------------------------------------------------------------
//
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;

Process Models 5-62


C++ Source Code for EEB Header File ConvReactorEEB.h

5.9 External Equation Block ConvReactorEEB.h


#ifndef CONVREACTOR_EEB_H_INCLUDED
#define CONVREACTOR_EEB_H_INCLUDED

/----------------------------------------------------------------------
// 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.

5-63 Part 2: Sample Code


C++ Source Code for EEB Header File ConvReactorEEB.h

long lModel; // Convenience, in case it's needed somewhere else.

// "Handles" to data (sets and parameters) needed to write the


Equations.
//----------------------------------------------------------------------
// Use static because the data are needed in both functions.
long sizeComps; // Number of elements in set Comps.
const char** Comps; // List of elements in set Comps.
const char* baseComponent; // Name of base component.
long BCIndex; // Offset of baseComponent in set Comps.
double* stoich; // Pointer to array stoich[].
double* HForm; // Pointer to array HForm[].
double stoichBC; // Value of stoich[baseComponent].
double AbsStoichBC; // Value of Abs(stoich[baseComponent]).

// Offset in the varValues and funcValues arrays.


// ----------------------------------------------
// VARIABLES
int o_conversion;
int o_reactionRate;
int o_netReaction;
int o_PresDrop;
int o_FeedPres;
int o_FeedMolarFlow;
int o_FeedEnth;
int o_refEnthFeed;
int o_FeedMoleFrac0; // FIRST entry in FeedMoleFrac list.

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;

// Auxiliary info for use in modelEvaluation() procedure.


long SupplySparsityFlag;
long NumVariable;
long NumEquation;
long NumNonZero;
};
#endif // CONVREACTOR_EEB_H_INCLUDED

Process Models 5-64


C++ Source Code for External Equation Block ConvReactorEEB.cpp

5.10 External Equation Block ConvReactorEEB.cpp


//---------------------------------------------------------------------
// C++ Source Code for EEB ConvReactorEEB.cpp
// Project : ROMeo
// Subsystem : Process Model
// Purpose : Conversion Reactor Model - External Equation Block (EEB)
// implemented as a DLL
//
// Copyright (c) 1998 by Simulation Sciences Inc
// ALL RIGHTS RESERVED
//
//---------------------------------------------------------------------

// Standard C++ include files


#include <iostream.h>
#include <string.h>
#include <math.h>

// ROMeo Model Development Include Files.


#include "PMFWrapper.h"

// Auxiliary classes and functions for this DLL in


// support of the "set up" class.
#include "ConvReactorEEB.h"

//---------------------------------------------------------------------

extern "C" __declspec (dllexport)


long modelSparsity (long pModel,
long queryFlag,
long* supplySparsityFlag,
long* numEquation,
long* numVariable,
long* numNonZero,
long* numVarInEqn,
long* varIndex,
double* sparsityVarValues)
{
cout << endl;
cout << "\n\n\n\n\n" << endl;
cout << " Entering modelSparsity ... queryFlag = " << queryFlag <<
endl;
cout << " getFullName() :" << MI_getFullName(pModel) << endl; //
Illustration only.

int i; // Working offset, usually for set Comps.


int j; // Working offset, usually for derivatives.
int k; // Working offset, usually for variables and equations.

5-65 Part 2: Sample Code


C++ Source Code for External Equation Block ConvReactorEEB.cpp

if (queryFlag == 1) {
// Assume that Milano code handles error situation (GetState()).
// - Only trouble might be for SClients (SimSci developers).

// Create "set up" object. Pointer pS becomes key player!


SaveSetUp* pS = new SaveSetUp(pModel);

// Save pointer to EEBSave object just created.


// --------------------------------------------
MI_setIntegerValue(pModel,"CPPBlockAddr",NULL, (long) pS);

// --------------------------------------------
// Retrieve data needed to write the Equations.
// --------------------------------------------
pS->sizeComps = MI_domainGetCount (pModel,"Comps");

// Note: delete this memory using MI_deleteElementNames().


pS->Comps = MI_domainGetAllElems(pModel, "Comps");
pS->baseComponent= MI_getStringValue(pModel,"baseComponent",NULL);

// baseComponentIndex
pS->BCIndex = -1;
for (i=0; i<pS->sizeComps; i++) {
if (strcmp(pS->Comps[i],pS->baseComponent)==0) pS->BCIndex = i;
}

// Allocate stoich, HForm. Notice check for sizeComps.


if (pS->sizeComps) pS->stoich = new double[pS->sizeComps];
if (pS->sizeComps) pS->HForm = new double[pS->sizeComps];

// Retrieve and save value of stoich[], HForm[].


for (i=0; i<pS->sizeComps; i++) {
pS->stoich[i] = MI_getRealValue(pModel,"stoich",pS->Comps[i]);
pS->HForm[i] = MI_getRealValue(pModel,"HForm" ,pS->Comps[i]);
}

// Retrieve and save value of stoich[baseComponent].


if (pS->sizeComps) pS->stoichBC = pS->stoich[pS->BCIndex];
if (pS->sizeComps) pS->AbsStoichBC = abs(pS->stoichBC);

// 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++;

Process Models 5-66


C++ Source Code for External Equation Block ConvReactorEEB.cpp

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;

// Print debug info (OPTIONAL - for illustration).


// Users may want to do something like this anyway.
cout << endl;
cout << "sizeComps = " << pS->sizeComps << endl;
for (i=0; i<pS->sizeComps; i++) {
cout << "Comps[i]= " << pS->Comps[i] << " \tstoich[i]= " <<
pS->stoich[i] << " \tHForm[i]= " << pS->HForm[i] << endl;
}

5-67 Part 2: Sample Code


C++ Source Code for External Equation Block ConvReactorEEB.cpp

cout << "baseComponent = " << pS->baseComponent << endl;


cout << "BCIndex = " << pS->BCIndex << endl;
cout << "Comps[BCIndex] = " << pS->Comps[pS->BCIndex] << endl;
cout << "stoichBC = " << pS->stoichBC << endl;
cout << "AbsStoichBC = " << pS->AbsStoichBC << endl;
cout << endl;
cout << "o_conversion = " << pS->o_conversion << endl;
cout << "o_reactionRate = " << pS->o_reactionRate << endl;
cout << "o_netReaction = " << pS->o_netReaction << endl;
cout << "o_PresDrop = " << pS->o_PresDrop << endl;
cout << "o_FeedPres = " << pS->o_FeedPres << endl;
cout << "o_FeedMolarFlow = " << pS->o_FeedMolarFlow << endl;
cout << "o_FeedEnth = " << pS->o_FeedEnth << endl;
cout << "o_refEnthFeed = " << pS->o_refEnthFeed << endl;
cout << "o_FeedMoleFrac0 = " << pS->o_FeedMoleFrac0 << endl;
cout << endl;
cout << "o_Q = " << pS->o_Q << endl;
cout << "o_ProdPres = " << pS->o_ProdPres << endl;
cout << "o_ProdMolarFlow = " << pS->o_ProdMolarFlow << endl;
cout << "o_ProdEnth = " << pS->o_ProdEnth << endl;
cout << "o_refEnthProd = " << pS->o_refEnthProd << endl;
cout << "o_ProdMoleFrac0 = " << pS->o_ProdMoleFrac0 << endl;
cout << endl;
cout << "o_e_Pres = " << pS->o_e_Pres << endl;
cout << "o_e_ReactionRate = " << pS->o_e_ReactionRate << endl;
cout << "o_e_NetReaction = " << pS->o_e_NetReaction << endl;
cout << "o_e_Flow = " << pS->o_e_Flow << endl;
cout << "o_e_MBal0 = " << pS->o_e_MBal0 << endl;
cout << "o_e_EBal = " << pS->o_e_EBal << endl;
cout << endl;
cout << "*supplySparsityFlag= " << *supplySparsityFlag << endl;
cout << "*numVariable = " << *numVariable << endl;
cout << "*numEquation = " << *numEquation << endl;
cout << "*numNonZero = " << *numNonZero << endl;
cout << endl;
cout << "SupplySparsityFlag = " << pS->SupplySparsityFlag <<endl;
cout << "NumVariable = " << pS->NumVariable << endl;
cout << "NumEquation = " << pS->NumEquation << endl;
cout << "NumNonZero = " << pS->NumNonZero << endl;
cout << endl;
}

if (queryFlag == 2) {

// Get pointer to "set up" object previously saved.


// ------------------------------------------------
SaveSetUp* pS = (SaveSetUp*)
MI_getIntegerValue(pModel,"CPPBlockAddr",NULL);

Process Models 5-68


C++ Source Code for External Equation Block ConvReactorEEB.cpp

// Fill in arrays numVarInEqn, varIndex.


// This is patterned after calculations of numNonZero (Section N).

j = 0; // Keeps track of derivatives.


k = 0; // Keeps track of equations.

// 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;

5-69 Part 2: Sample Code


C++ Source Code for External Equation Block ConvReactorEEB.cpp

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;

// Print debug info (OPTIONAL - for illustration).


// Users may want to do something like this anyway.
cout << "--- @11: Listing of numVarInEqn[] and varIndex[]" << endl;
for (k=0, j=0; k<*numEquation; k++) {
cout << endl;
cout << " numVarInEqn[" << k <<"] = " << numVarInEqn[k] <<
endl;
for (i=0; i<numVarInEqn[k]; i++, j++) {
cout << " varIndex[" << j << "] = " << varIndex[j] << "
varInputIndex" << endl;
}
}

cout << " Leaving modelSparsity ... queryFlag = " << queryFlag <<
endl;
cout << endl;

return 0;
}

//---------------------------------------------------------------------

extern "C" __declspec (dllexport)


long modelEvaluation (long pModel,
double* varValues,
double* funcValues,
double* derivatives,
long flagCalc)
{
cout << endl;
cout << " Entering modelEvaluation ..." << " flagCalc = " << flagCalc
<< endl;
cout << " getFullName() :" << MI_getFullName (pModel) << endl; /
/ Illustration only.

int i; // Working offset, usually for set Comps.


int j; // Working offset, usually for derivatives.

Process Models 5-70


C++ Source Code for External Equation Block ConvReactorEEB.cpp

int k; // Working offset, usually for variables and equations.

double sumStoich; // Intermediate value.


double sumHForm; // Intermediate value.

// Get pointer to "set up" object previously saved.


// ------------------------------------------------
SaveSetUp* pS = (SaveSetUp*)
MI_getIntegerValue(pModel,"CPPBlockAddr",NULL);

if (flagCalc==2 || flagCalc==3) {
// EQUATION function values.
// -------------------------
// This is patterned after calculations of numNonZero (Section N).

k = 0; // Keeps track of equations.

// 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]

5-71 Part 2: Sample Code


C++ Source Code for External Equation Block ConvReactorEEB.cpp

*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).

j = 0; // Keeps track of derivatives.

// e_Pres
derivatives[j++] = 1.; // ProdPres
derivatives[j++] = -1.; // FeedPres
derivatives[j++] = 1.; // PresDrop

// e_ReactionRate
derivatives[j++] = 1.; // reactionRate

derivatives[j++] = -varValues[pS->o_FeedMolarFlow]// conversion


*varValues[pS->o_FeedMoleFrac0 + pS->BCIndex]
/pS->AbsStoichBC;

derivatives[j++] = -varValues[pS->o_conversion] // FeedMolarFlow


*varValues[pS->o_FeedMoleFrac0 + pS->BCIndex]
/pS->AbsStoichBC;

derivatives[j++] = -varValues[pS->o_conversion] // FeedMoleFracBC


*varValues[pS->o_FeedMolarFlow]

Process Models 5-72


C++ Source Code for External Equation Block ConvReactorEEB.cpp

/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;
}

5-73 Part 2: Sample Code


Demo Code for UOM Features

//---------------------------------------------------------------------

extern "C" __declspec (dllexport)


long modelCleanUp (long pModel)
{
cout << endl;
cout << " Entering modelCleanUp ..." << endl;
cout << " getFullName() :" << MI_getFullName (pModel) << endl; /
/ Illustration only.

// Get pointer to "set up" object previously saved.


// ------------------------------------------------
SaveSetUp* pS = (SaveSetUp*)
MI_getIntegerValue(pModel,"CPPBlockAddr",NULL);

if (pS) delete pS;

cout << " Leaving modelCleanUp ..." << endl;


cout << endl;

return 0;
}

5.10.1 // Demo Code for UOM Features


//
// We now make use of some of the features available through
// the MilanoObject MilanoUOM. This object is declared in
// Romeo10\Server\System\MilanoBuiltIn.mil
// This code is executed only if the integer parameter doUomTest
// is nonzero. Its default value is set to 1 when a reactor model
// is created, but the user can change its value from the Model window.
// The sample code shows calls to the getProperty() and setProperty()
// methods that come included with any process model that inherits
// from class PM_UserAddedProcessUnit. In addition, the sample code
// illustrates the use of the auxiliary MilanoObject called MilanoUOM.
// In particular, the code makes use of the method
// MilanoUOM:convertValue().

// Code similar to this is typically included in a reporting


// method.
//
// The Display statements implemented below should result in
// the following output (values have been formatted into a table):
//
// PARAMETER: FS:Unit["CRTR"]:uomTestTemp UOM=K.
//
//dummy uomTestTemp uomTestuomReal uomTestInternalUOM uomTestuomReport
//----- ----------- -------------- ------------------ ----------------
// 10 298.15 77 F (blank)
// 11 300 80.33 F (blank)

Process Models 5-74


Demo Code for UOM Features

// 12 873.15 1112 F (blank)


// 13 573.15 572 F (blank)
// 14 773.15 932 F (blank)
// 15 422.039 300 F (blank)
// 16 300 300 K (blank)

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);

// Change internal value.


dummy=11; Display dummy;
uomTestTemp = 300.0;
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);

// Change internal value using convertValue(): "C" to Internal.


dummy=12; Display dummy;
uomTestTemp = myUOM:convertValue("Temp","C","Internal", 600.0);
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);

// Change internal value using convertValue(): "C" to "K".


dummy=13; Display dummy;
uomTestTemp = myUOM:convertValue("Temp","C","K", 300.0);
uomTestuomReal = uomTestTemp.uomRealVal;
uomTestInternalUOM = getProperty("uomTestTemp","UOM");

5-75 Part 2: Sample Code


Demo Code for UOM Features

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);

// Change internal value using convertValue(): "C" to Internal.


dummy=14; Display dummy;
uomTestTemp = myUOM:convertValue("Temp","C","Internal", 500.0);
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);

// Change uomRealVal: Value expressed in UOM in declaration ("F").


dummy=15; Display dummy;
uomTestTemp.uomRealVal = 300.0;
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);

// Change UOM property to "K".


// Then change uomRealVal: Value expressed in new UOM ("K").
dummy=16; Display dummy;
setProperty("uomTestTemp","UOM","K");
uomTestTemp.uomRealVal = 300.0;
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);
};

Process Models 5-76


Chapter 6
Procedures

This chapter addresses the procedures for including custom process


models in the Model Class Library mcl.db, the generation of BBM
and EEB DLLs using Microsoft Developer Studio, and the
registration of custom process units in ROMeo so that it is possible
to enter data for them from the GUI at runtime.

6.1 Adding Process Models to mcl.db


The following steps presuppose that you have already created an
all-MILANO custom process model and that you now wish to include
it in the Model Class Library mcl.db.

To add a custom model to mcl.db:


From the Windows desktop, select Start/Programs/Simulation
Sciences/Model Library Manager to launch the Model Library
Manager.
The Model Library Manager application contains three
subwindows:
Models lists the process models currently contained in
mcl.db and the base classes from which they are derived. The
standard process models supplied with ROMeo are shown
under the Standard group. The sample custom models
distributed by SIMSCI are shown under the Sample group. Any
custom user-defined models will be shown under the group
defined by the Group property as described in Guidelines, 2.2.

Process Models 6-1


Files used to enter the custom process model MILANO files
that will be added to mcl.db.
Output displays MILANO compilation and installation
messages and results.

Figure 6.1-1: Model Library Manager Dialog Box

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.

Figure 6.1-2: Select Model Source File Dialog Box

Next, navigate into the ConvReactor/System folder and double-


click on ConvReactor.mil to include it in the Files window for
insertion into mcl.db. The Files window also displays all
custom models that have been previously added to mcl.db.

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.

Note: Be sure to order the files in such a way that class


dependencies can be correctly compiled.

Note: Double-clicking on the .mil file in the Files window


launches the NotePad editor. You can change the editor using
the Options/Editor... option.

Figure 6.1-3: Files Window

To compile the custom models listed in the Files window


without installing them into mcl.db, select Build/Compile from
the main menu, or click on the Compile icon. Compilation and
installation messages are displayed in the Output message
window.

Note: You can view the line-by-line compilation results by


right-clicking anywhere in the Output message window and
selecting the View option or by double-clicking anywhere in
the Output message window.

Figure 6.1-4: Output Message Window

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

Process Models 6-3


custom models, select Build/Install from the main menu, or
click on the Install icon to access the Install Models dialog box.

Note: This step permanently changes mcl.db. Any model


application databases created henceforth in ROMeo will use this
modified mcl.db. You can restore mcl.db to its original SIMSCI-
supplied state by selecting Build/Restore, but any model
application databases created with the modified mcl.db become
unusable.

Figure 6.1-5: Install Dialog Box

Enter a new version number and a new version description. The


version number must be sequentially greater than the previous
version number. Any string is acceptable for the version
description. After the installation is complete, the new version
number and description will be displayed in the Current
Version Number and Current Version Description fields the
next time you visit this window. Note that this version
information corresponds to the user version as opposed to the
system version supplied by SIMSCI.

Note: You can determine the current version number and


description as well as the build timestamp using the
dbUtilR.exe and VerInfoR.exe utilities located in
..\ROMeo10\Server\bin.
Using the -v switch with dbUtilR.exe yields the following
typical information on mcl.db located in ..\ROMeo10\
Server\System:
C:\PROGRA~1\SIMUL~1\ROMEO10\SERVER\SYSTEM>
..\bin\dbutilr -v mcl.db
--- UserVersion ---
Version Number:1.0001
Version Description:First Conversion Reactor Build
Version Time Stamp:Tue Nov 10 1998 11:39:38 1998
Drop Version Number:0

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.

Figure 6.1-6: Models Window

6.2 Creating a Project File for a BBM or EEB DLL


This example illustrates the creation of a project workspace for the
ConvReactorEEB model using Visual C++ 4.2

To create a project:
Select File/New from the main menu.

Figure 6.2-1: MS Visual C++ 4.2 New Dialog Box

Select Project Workspace in the list box and click OK .


In the New Project Workspace dialog box, select Dynamic Link
Library and choose the location of your new workspace. It is
most convenient to place it in the same directory as your source
code files, located in the \Models\XXX\Server subdirectory of
your installation (where XXX is the name of the model) and
click Create .

Process Models 6-5


Figure 6.2-2: MS Visual C++ 4.2 New Project Workspace Dialog Box

Select Insert/Files into Project 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 .

To set compiler/linker options:


Select Build/Settings from the main menu to access the Project
Settings dialog box, then select the C/C++ tab.
Select Preprocessor in the Category list box.

6-6 Procedures
For Additional include directories: specify ..\..\include
which should point to the \models\include subdirectory.

Figure 6.2-4: Project Settings Dialog BoxC/C++ Preprocessor Category

Select Code Generation in the Category list box.

Figure 6.2-5: Project Settings Dialog BoxC/C++ Code Generation Category

For Use run-time library: specify Debug Multithreaded


DLL for the Win32 Debug configuration and Multithreaded
DLL for the Win32 Release configuration.
Make sure that Struct member alignment: is set to 8 Bytes
(the default).

To specify location of link libraries:


Select the Link tab, then General in the Category list box.
Add the two Object/Library modules in front of those already
specified: ..\..\Lib\PMFWrapper.lib and ..\..\Lib\MAServerR.lib.

Process Models 6-7


(This presupposed that the library files were installed into the
\Models\Lib subdirectory.)

Figure 6.2-6: Project Settings Dialog BoxLink General Category

To specify location of the DLL:


By default, the DLL will be generated in the Debug (or Release)
subdirectory of the project file. You can specify the exact
output filename and location by entering it in the Output file
name: field. For example, \Program Files\Simulation
Sciences\ROMeo10\Server\ Bin\ConvReactorEEB.dll.

Note: The previous step is optional.

To build the DLL:


Select Build/Rebuild All from the menu bar. When complete,
the DLL will be generated in the specified directory.

6.3 Mixed-Language DLL: Interfacing C++ and FORTRAN


The procedure for creating a mixed-language DLL is similar to
what was documented in an earlier section. The main difference is
that programmers need to pay close attention to calling conventions
for the languages involved.
In this section we present a scenario for creating an External
Equation Block employing C++ and FORTRAN. We assume that
users will run through this scenario when trying to make FORTRAN
legacy code available to ROMeo. We further assume that the
compilers involved are Microsoft Visual C++ and FORTRAN
PowerStation.

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.

To enter additional compiler settings:


Select Build/Settings from the PowerStation menu bar.
Select the FORTRAN tab.

Figure 6.3-1: Project Settings Dialog BoxFortran Language Category:

Figure 6.3-2: Project Settings Dialog BoxFortran Libraries

Process Models 6-9


6.3.1 C++ to FORTRAN Calls
The BBM and EEB interfaces, as documented in the MILANO User's
Guide, are always used to call the corresponding DLLs. That is, the
interface calls always take place via C++ functions. Thus, the
FORTRAN code must be called from within these C++ functions.

C++ Calling FORTRAN: Declare FORTRAN Procedures in


C++
This is the most common scenario. MILANO calls the BBM or EEB
via the C++ interface; the interface functions in turn call FORTRAN
functions or subroutines to do the work.
There are several points to keep in mind:
Use the __stdcall keyword in the declaration.
FORTRAN names are converted to uppercase by default. You can
declare the functions and subroutine names with uppercase
letters, or use mixed case and #define as shown below. There
are other, more involved ways to handle procedure names.
Under most situations, FORTRAN handles arguments by
reference.
Array indexing conventions: FORTRAN starts indexing at 1;
C++ starts indexing at 0. MILANO follows the C++ convention.
The most critical array in this respect is varIndex[], which must
return 0-based indices to MILANO.

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
);

FORTRAN declaration for the same procedures:


subroutine MSpars(
1 nComp, ! Input (no of components)
1 pModel, ! Input
1 queryFlag, ! Input
1 supplySparsityFlag, ! Input
1 numEquation, ! Output
1 numVariable, ! Output
1 numNonZero, ! Output
1 numVarInEqn, ! Output
1 varIndex ! Output
1 )

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

Process Models 6-11


integer*4 pModel
double precision varValues(*)
double precision funcValues(*)
double precision derivatives(*)
integer*4 flagCalc

FORTRAN Calling MILANO: Wrapper Procedure in C++


Sometimes the FORTRAN code must call back to the MILANO
model to retrieve or set values that are not readily available in the
argument list passed via the EEB or BBM interface. In such cases, it
is necessary to write a C++ function to access the MILANO model.
This function makes use of the functions available in the
PMFWrapper library. Since the C++ function will be called as if it
were a FORTRAN function or subroutine, it is again important to use
the __stdcall declaration.

Example:
C++ declaration:

#define getSetMilanoInteger GETSETMILANOINTEGER


// For Fortran.
extern "C"
void __stdcall getSetMilanoInteger(
long& pModel, // Input
long& task, // Input
char itemId[], // Input
unsigned int itemIdLen, // String length, from Fortran
long& value // Input/Output
)

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 ! }

The example shows a subroutine call that includes a string


argument (argument #3 in FORTRAN call). The C++ function must
provide an additional argument to store the string length that
FORTRAN automatically generates.

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.

To add a process unit or column section to ROMeo:


Select Options/Unit Registration from the ROMeo main menu
to open the Unit Configuration Utility data entry window.

Figure 6.4-1: ROMeo Unit Configuration Utility Window

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

Process Models 6-13


DLL resides in the default directory, enter Default or leave
the cell blank.
Specify the Icon Data File, if you have created a custom
flowsheet icon for the new unit. It is permissible to use the
UIGenericUnit.dll (which creates the three common DEWs)
with a custom icon data file. The provided icon data file,
UIGenericUnitIcon.dat, defines a multiple inlet/multiple
outlet (MIMO) unit. The icon data file specifies the port
configuration for the unit. The parameters for specifying
port configuration are documented in Modifying the Icon
Data File, 7.7.
Specify the MILANO Model Name, for example,
ConvReactor. A large number of MILANO models are
included in the c:\Program Files\Simulation
Sciences\ROMeo10\Models\Standard Models directory for
reference.
Include the Model Name. This is the name that will appear
on the PFD palette.

Note: Changes do not take effect until you exit and restart
ROMeo.

6.5 Entering Data for a Custom Process Model


The following presupposes that you have closed and restarted
ROMeo after adding the new custom reactor model. The default
flowsheet icon for a custom model is a square and will be used
unless you specify a different icon data file.

To specify slates and product stream phases:


Double-click on the flowsheet icon to access the three data
entry windows (DEWs) that all process models have in
common: Thermo/Products, Notes and Diagnostics. The
sample custom model illustrated here is a SISO unit, thus it
incorporates only a single product stream. Unless you have
created a custom GUI DLL, the DEWs will appear as below:

6-14 Procedures
Figure 6.5-1: Common Data Entry Windows

Use the Thermo/Products DEW to specify unit (and


stream) component slate, thermo method slate and the
product stream phases as you would in a standard process
model.
Enter notes, description, comments, etc., for future users or
general reference in the Notes DEW.
Consult the Diagnostics DEW for message relating to
completeness of specifications, etc.

To enter process unit specifications:


If you have not designed a set of DEWs specially tailored to accept
unit specification input, you can use the Model window that is
created when the MILANO code for the custom process model is
compiled.
Right-click on the units flowsheet icon and select Model... to
open the models General Data Access Window (GDAW).
Expand the Parameters node to display data entry fields with
current values for the parameters that have been defined in the

Process Models 6-15


MILANO code. Certain of these parameters will be common to
all process models, while others may be model- specific.

Figure 6.5-2: Custom Conversion Reactor Model Parameters

ValidateLevel specifies the level of checking in the


Validate() method. See Validate(), page 2-13 and
ValidateLevel, page 2-7.
OnOffStatus specifies whether the process model is On
or Off. See OnOffStatus, page 2-6.
UserOnOff a process unit can be turned On or Off by
another process unit or by the user. This parameter puts the
On/Off status under user control. See page 2-7.

baseComponent declared as a PMF_ExtStringRow datatype


in the Declarations section of the MILANO model code.
Enter the component name used when constructing the
component slate in Modular Thermo. Do not use a
synonym (e.g. C1 for METH). Quote marks are not required
to delimit the name.
isAdiabatic declared as a PMF_ExtIntRow datatype in the
Declarations section of the MILANO model code. Values of
0 and 1 indicate isothermal or adiabatic operation,
respectively.
MassBalChkTol declared as a PMF_ExtRealRow datatype in
the Declarations section of the MILANO model code. This
fractional tolerance value is used to check the mass balance
of the reaction.
AtomBalChkTol declared as a PMF_ExtRealRow datatype in
the Declarations section of the MILANO model code. This
fractional tolerance value is used to check the stoichiometry
of the reaction.

6-16 Procedures
doUomTest UOM test flag. See page 5-74 for an example
of usage.

Figure 6.5-3: Custom Conversion Reactor Model Stoichiometric Coefficients

Enter the stoichiometric coefficients for the reaction in Parameters/


stoich at runtime. The stoich array is declared in the user input
part of the Declarations section (page 5-8). The components in
stoich are those in the component slate assigned to the unit.

Figure 6.5-4: Custom Conversion Reactor Model Variables

The reactor model scalar variables, v_PressureDrop, v_conversion


and v_Q are also declared and initialized to 0.0 in the user input
part of the Declarations section (page 5-8). Values for the .I
attribute can be entered from the GUI at runtime. Level values (.L)
are generated during solution. You can right-click on the first
column in each row to change the display to a convenient UOM.

Process Models 6-17


Figure 6.5-5: Custom Conversion Reactor Reference Enthalpies of Formation

After solution, level values for the reference enthalpies of formation


for the feed and product streams are displayed in Variables/
v_refEnth.

Figure 6.5-6: Custom Conversion Reactor Component Enthalpies of Formation

Figure 6.5-7: Custom Conversion Reactor Component Molecular Weights

The arrays for component heats of formation (HForm) and molecular


weights (Mws) are declared in the Modular Thermo setup of constant
properties where all values are initialized to 0.0 (page 5-10). Actual
values shown in Figure 6.5-6 and Figure 6.5-7 are retrieved from
Modular Thermo in the CheckStructure() method (page 5-21), and
may be previewed at runtime before solution by invoking Generate
Estimates.

6-18 Procedures
Figure 6.5-8: Custom Conversion Reactor Sample Data Structure

The data structure wrapset1 containing the names of selected


baseball teams is an example of custom sets that can be constructed
in a MILANO process model. Data structures such as these can be
used to pass values to and from BBMs and EEBs. It is also possible
to modify these data structures from within the external C++ code.
See Adding and Deleting Elements, page 5-45.

Process Models 6-19


Chapter 7
Special Topics

This chapter shows how to convert a Black Box Model to an


External Equation Block, outlines Schema Evolution, lists the
directory structure and files for MILANO process models, and
provides guidelines on modifying the icon data file.

7.1 Converting Black Box Models to External Equation Blocks


This section provides instructions on converting a Black Box Model
(BBM), which is only capable of returning function values for a
given set of inputs, to a MILANO External Equation Block (EEB) so
that derivative information can be automatically generated by
MILANO. A short illustrative example is also included. It is assumed
that the reader is already familiar with the concept of the EEB in
MILANO and the corresponding terminology as documented in the
MILANO Users Guide.

In order to implement this conversion, MILANO must be able to


recognize the inputs to and the outputs from the BBM. MILANO
variables that correspond to inputs and outputs from the BBM must
first be defined. Once this correspondence has been achieved, the
custom model must be presented to MILANO in an appropriate
equation form. The approach taken here is to match the outputs
from the BBM to the corresponding MILANO variables through a set
of MILANO equations that calculate the difference between the two
values. The Solver then attempts to drive this difference to zero
during the solution process.
The steps for converting a BBM to a MILANO EEB model are
summarized below:

Process Models 7-1


1. Declare an EEB in the Declarations section of the MILANO
model. The declaration takes the following form:
ExternalEquationBlock userModel
<< DLLName=ExtEqnBlkInterface.dll,SizeSparsityProc=
"modelSparsity", FiniteDifference=True, FuncGradProc=
"modelEvaluation" >>;

Note: The entire property clause delimited by the double angle


brackets (<< ... >>) must be contained in single line of MILANO
code and may not include a carriage return.

Note: The FiniteDifference option must be set to True.


2. In the MathRelations section of the MILANO model, include the
list of variables addressed in the EEB. This list includes the
MILANO variables corresponding to the inputs and outputs of
the custom BBM and the MILANO equations that match the user
outputs to the corresponding MILANO variables. This is
illustrated in 7.1.2 where 11 custom functions are evaluated
using 21 input variables. Note that these variables and
equations must also be declared in the Declarations section of
the MILANO model.
3. The model statistics should be given in the SizeSparsityProc
(i.e., modelSparsity()) routine. Typical data would be:
Number of MILANO equations: 11(user outputs)
Number of MILANO variables:32 (user inputs + outputs)
SupplySparsityFlag must be set to 0 as a flag to the system that
the sparsity information is to be automatically determined by
MILANO. Here you must also supply initial values for the
MILANO variables, using the sparsityX array, thus indicating to
the system which point to use to calculate the sparsity pattern.
See 7.1.2 for an example of the SizeSparsityProc routine. For
details on the SizeSparsityProc routine, see Milano Users
Guide, Black Box Model, 7.5.
4. MILANO calls FuncGradProc (i.e., modelEvaluation()) when it
evaluates the values and gradients for the external equations.
Therefore, the model must be transformed in this routine into
an EEB model form as explained earlier. An example of this
transformation can be seen in 7.1.3. Using this routine, calls
are made to the custom BBM during optimization to retrieve
custom function values, which, in turn, are subtracted from the

7-2 Special Topics


corresponding MILANO variables to calculate the equation
residuals. The Solver then attempts to drive these residuals to
zero.

7.1.1 MILANO Specification of a Custom Model (EEB)


userModel ..
{
// MILANO variables corresponding to the inputs to
// the custom black box model
Include v_X0;
Include v_X1;
.
.
.
Include v_X20;

// MILANO variables corresponding to the outputs from


// the custom black box model
Include v_X21;
Include v_X22;
.
.
.
Include v_X31;

// MILANO equations matching custom outputs to the


// corresponding MILANO variables
Include e_X21;
Include e_X22
.
.
.
Include e_X31;
};

7.1.2 SizeSparsityProc for a Custom Model (EEB)


extern "C" __declspec (dllexport)
long modelSparsity(long pModl,
long queryFlag,
long* supplySparsityFlag,
long* neqn,
long* niv,
long* nz,
long* nvineqn,
long* iijac,
double* sparsityX)

Process Models 7-3


{
if (queryFlag == 1) {
*neqn = 11;
*niv = 32;
*supplySparsityFlag = 0;

return 0;
}

sparsityX[0] = 6.895; sparsityX[1] = 689.476;


sparsityX[2] = 0.126; sparsityX[3] = 0.1;
sparsityX[4]= 0.1;sparsityX[5]= 0.2;
sparsityX[6] = 0.3; sparsityX[7] = 0.3;
sparsityX[8] = 0.; sparsityX[9] = 0.0;
sparsityX[10] = 25456.8; sparsityX[11] = 689.476;
sparsityX[12] = 0.189; sparsityX[13] = 0.0;
sparsityX[14] = 0.0; sparsityX[15] = 0.0;
sparsityX[16] = 0.1; sparsityX[17] = 0.1;
sparsityX[18] = 0.2; sparsityX[19] = 0.2;
sparsityX[20] = 22533.6; sparsityX[21] = 82.581;
sparsityX[22] = 6.895; sparsityX[23] = 0.315;
sparsityX[24] = 0.04; sparsityX[25] = 0.04;
sparsityX[26] = 0.08; sparsityX[27] = 0.18;
sparsityX[28] = 0.18; sparsityX[29] = 0.12;
sparsityX[30] = 0.12; sparsityX[31] = 23702.9;

return 0;
}

7.1.3 FuncGradProc for a Custom Model


The following code illustrates how function values returned from
the Black Box Model are subtracted from the MILANO variables to
yield the equation residuals.
extern "C" __declspec (dllexport)
long modelEvaluation (
long pModl,
double* x,
double* f,
double* tg,
int flag)
{

double Ycalc[11];
UserModelWrapper(x,Ycalc);

7-4 Special Topics


f[0] = x[21] - Ycalc[0];
f[1] = x[22] - Ycalc[1];
f[2] = x[23] - Ycalc[2];
f[3] = x[24] - Ycalc[3];
f[4] = x[25] - Ycalc[4];
f[5] = x[26] - Ycalc[5];
f[6] = x[27] - Ycalc[6];
f[7] = x[28] - Ycalc[7];
f[8] = x[29] - Ycalc[8];
f[9] = x[30] - Ycalc[9];
f[10] = x[31] - Ycalc[10];

return 0;
}

7.2 Sparsity Patterns


A sparsity pattern describes which variables appear in each
equation. A more generic term for sparsity pattern is incidence
matrix. However, in the ROMeo context we use the term sparsity
pattern instead to convey the idea that in most models the incidence
matrix is sparse. That is, in most equations only a few variables are
present.
Supplying the correct sparsity pattern is essential in MILANO-based
models because certain data structures are set up based on the
pattern. When supplying the sparsity pattern it is important to bear
in mind that MILANO (like C/C++) uses zero-based arrays to store
the information. This stands in contrast to the one-based arrays in
FORTRAN.

Sparsity Pattern for a Black Box Model


Assume the model contains the following equations incorporating
four input variables (x1,x2,x3,x4) and two output variables
(y1,y2):
y1 - x1 + x2 -x3 = 0
y2 - x2*x4 = 0
Observing zero-based indexing, the input and output variables are
ordered and indexed as follows:
Input : x1, x2, x3, x4 Indices: 0, 1, 2, 3
Output: y1, y2 Indices: 0, 1

Process Models 7-5


The data specified in the "size and sparsity procedure" would be:
numInputVariables 4
numOutputVariables 2
numVarInEqn 3, // # inputs in 1st eqn: x1, x2, x3
2 // # inputs in 2nd eqn: x2, x4
varIndex 0,1,2, // position indices for inputs in
// 1st eqn: x1, x2, x3
1,3 // position indices for inputs in
// 2nd eqn: x2, x4
numNonZero 5 // # indices saved in varIndex
// (equal to sum of entries in
// numVarInEqn)

Note: During derivative evaluation, the data saved in the


derivatives array must correspond to the indices saved in the
varIndex array. That is, the data must appear in the same order.

Sparsity Pattern for an External Equation Block


Assume the model contains the following equations incorporating
four variables:
eqn0: x1 + x2 -x3 = 0
eqn1: x3 - x4 = 0
eqn2: x2*x4 = 0
Let the equations be ordered as presented above, and let the
variables be ordered and indexed as follows:
Variables: x3, x1, x2, x4 Indices: 0, 1, 2, 3
We did not follow the order x1, x2, x3, x4 because we want to
show that what really matters is the order in which the variables are
presented to the EEB (or BBM), not the name of the variables.
The data specified in the "size and sparsity procedure" would be:
numEquation 3
numVariable 4

7-6 Special Topics


numVarInEqn 3, // # var in 1st eqn: x1, x2, x3
2, // # var in 2nd eqn: x3, x4
2 // # var in 3rd eqn: x2, x4
varIndex 1,2,0, // Position indices for var
// in 1st eqn: x1, x2, x3
0,3, // Position indices for var
// in 2nd eqn: x3, x4
2,3 // Position indices for var
// in 3rd eqn: x2, x4
numNonZero 7 // # indices saved in varIndex
// = Sum of entries in numVarInEqn

Note: During derivative evaluation, the data saved in the


derivatives array must correspond to the indices saved in the
varIndex array. That is, the data must appear in the same order.
The indices appearing in varIndex for each equation need not be
ordered in any particular way. For example, for the first equation
we show 1,2,0 above. However, any permutation of these three
indices is also a valid specification, for example:
0,1,2 0,2,1 1,0,2 1,2,0 2,0,1 2,1,0
What is really important is that the derivative values in the
derivatives array are ordered in the same way as the indices in
the varIndex array.

7.3 Schema Evolution


When a flowsheet is created or modified in ROMeo, the current
model class library, mcl.db, is used to create instances of various
classes such as streams, unit models, and the like. A problem arises
if the class library is changed after the flowsheet has been created.
When the flowsheet database is to be reopened, the object instances
may not match the changed definitions of the object classes. For
example, an incompatibility may arise if a new variable has been
added to the Mixer class, and Mixer instances saved to the database
do not have this variable. ROMeo is able to modify the instance
databases to conform to the new class library for a restricted set of
changes in the class library. This is referred to as the schema
evolution feature.
The following types of changes are handled by MILANO schema
evolution:
Adding new primitives.

Process Models 7-7


Changing class-based properties. However, existing instance
data will not be changed.
Adding new methods.
Changing existing method body. However, existing instance
data will not be changed.
Renaming an existing method.
The following types of changes are not handled by MILANO schema
evolution:
Deletion of primitives.
Rearranging order of declarations of current primitives.
Renaming current primitives.
Redefining current primitives for example, domains of a
variable.
It is important to bear in mind how schema evolution is impacted by
model changes. In the early phases of model development it is
reasonable to:
Make numerous model changes and revisions.
Use simple test flowsheets that are easy to set up from scratch.
However, as the model matures, the complexity of the test
flowsheets may increase significantly. Eventually, the new process
models will form part of production flowsheets.
Model changes affect the ability to evolve an existing flowsheet
from an old version of the model to a new one. In many cases the
evolution is simple and automatic if some basic rules are obeyed:
Do not delete or rename existing data member in a class.
Do not change the relative order of existing data members in a
class.
Add data members to a class only at the end of the current list of
data members. (This is only a guideline, since it is possible to
insert new data members between existing ones as long as the
relative order of the existing ones is not changed.)

7-8 Special Topics


Take care when changing property values in declarations. Some
properties, like <<Hidden>> do not impact schema evolution, but
others do.
These rules refer only to data members. By contrast, methods can
be added, deleted, renamed, and redefined at will without impacting
schema evolution as long as the logic in the new methods does not
alter the semantics of the existing data in the database.

7.4 Default Directory Structure with Included Files


The ROMeo distribution contains the following files installed in the
indicated directory structure.

7.4.1 Client Directory


The file listed below is installed in the indicated directory as part of
the ROMeo Client installation:
C:\Program Files\Simulation Sciences\ROMeo10\Client\Bin
UIGenericUnit.dll

7.4.2 Server Directories


The files listed below are installed in the indicated directories as
part of the ROMeo Server installation:
C:\Program Files\Simulation Sciences\ROMeo10\Server\Bin
PMFWrapper.dll
MitreServerR.dll
MLMR.exe
ConvReactorBBM.dll
ConvReactorEEB.dll
C:\Program Files\Simulation Sciences\ROMeo10\Server\System
mcl_standard.db
MitreServer.adb

7.4.3 Model Directories on Client Computer


The following directory contains subdirectories as indicated for
header files, library files, standard MILANO process models
supplied by SIMSCI and newly developed MILANO process
models.
C:\Program Files\Simulation Sciences\ROMeo10\Models
C:\Program Files\Simulation Sciences\ROMeo10\Models\Include

Process Models 7-9


Header files:
PMFWrapper.h
MIUserAtom.h
MIAttributeNumbers.h
C:\Program Files\Simulation Sciences\ROMeo10\Models\Lib
Library files:
PMFWrapper.lib
MAServerR.lib
Standard MILANO files supplied by SIMSCI are stored in this
directory.
C:\Program Files\Simulation Sciences\ROMeo10\Models\Templates
SISOprocessUnitTemplate.mil (used to develop SISO process units)
SIMOprocessUnitTemplate.mil (used to develop SIMO process
units)
MISOprocessUnitTemplate.mil (used to develop MISO process
units)
MIMOprocessUnitTemplate.mil (used to develop MIMO process
units)
UIGenericUnitIcon.dat (used to develop icons for custom models)
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)
C:\Program Files\Simulation Sciences\ROMeo10\Models\Standard
Models
PM1DSearch.mil PMBasisChanger.mil
PMBlackBoxFlash.mil PMColebrook.mil
PMComponentMerger.mil PMComponentSeparator.mil
PMComponentSlate.mil
PMCompositeNonProcessUnit.mil
PMCompositeProcessUnit.mil PMCompressor.mil
PMController.mil PMCV.mil
PMDPCorrelation.mil PMEjector.mil
PMEquipment.mil PMExpander.mil
PMFisherLV.mil PMFlash.mil
PMGain.mil PMGenericDP.mil
PMHoneywellGV.mil PMInstrumentType.mil
PMMeasurement.mil PMMISOUnitOp.mil
PMMixer.mil PMNonProcessPort.mil
PMNonProcessStream.mil PMNonProcessUnit.mil
PMPenalty.mil PMPhase.mil

7-10 Special Topics


PMPhaseEquilibrium.mil PMPModel.mil
PMPObject.mil PMPort.mil
PMProcessPort.mil PMProcessStream.mil
PMProcessUnit.mil PMProcessUnitShell.mil
PMPropertySlate.mil PMPump.mil
PMSIMOUnitOp.mil PMSimplePipe.mil
PMSingleUnitAddOn.mil PMSink.mil
PMSISOController.mil PMSISOControllerMode.mil
PMSISODPUnitOp.mil PMSISOUnitOp.mil
PMSource.mil PMSplitter.mil
PMStream.mil PMStreamEcon.mil
PMSUSISOUnitOp.mil PMSVMeasurement.mil
PMSVTuningParameter.mil PMThermoProperties.mil
PMTieredSplitter.mil PMTuningParameter.mil
PMUnit.mil PMUserAddedProcessUnit.mil
PMValve.mil

7.5 Deploying a Custom Model


After you have completed development and testing of a custom
process model, you must deploy it to both the ROMeo server
computer and to all client computers that will use it.

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.

Note: If the DLLs were originally developed on an Intel-


based computer and the target computer is also Intel-based,
you may copy the DLLs directly. However, if the target
computer is of a different architecture (such as DEC Alpha-
based), then you must copy the source files to the target
computer and rebuild the DLLs there.

ROMeo Client
If the custom process model employs a custom icon data file,
copy this file to each client computer.

Process Models 7-11


From the ROMeo main menu of each client computer, select
the Options/Unit Registration to add a new button to the icon
palette.

7.6 Directories and Files for Typical Custom Models


Process models can be added to ROMeo in any of three forms: as
pure-MILANO models, MILANO models including Black Box Models
(BBMs), or as MILANO models including External Equation Blocks
(EEBs). In both of the latter cases, the BBM and EEB sections are
written in some non-MILANO code such as C/C++ or FORTRAN.
these different forms are represented here by three versions of
conversion reactor unit operation and one version of a flash unit
operation. The file naming conventions illustrated below can be
considered typical:
ConvReactorA pure MILANO implementation of the
conversion reactor model.
ConvReactorBBMAn implementation of the conversion
reactor model in which the MILANO model includes C++ code
defining part of the math model in terms of an input/output
model. See Black Box Model, 7.5, in the MILANO Users
Guide for details.
ConvReactorEEBAn implementation of the conversion reactor
model in which the MILANO model includes C++ code defining
part of the math model in terms of an external equation-oriented
model. See External Equation Block (EEB), 7.6, in the
MILANO Users Guide for details.
EzFlashEEBAn implementation of the flash model in which
the MILANO model includes FORTRAN code for the EEB. The
EzFlashEEB files are included in the ROMeo distribution.

The installation program creates the following directories and files


for the different implementations of the conversion reactor and the
flash models:
C:\Program Files\Simulation Sciences\ROMeo10\Models\ConvReactor
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactor\Client
UIReactorIcon.dat
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactor\Server

7-12 Special Topics


ConvReactor.mil
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactorBBM
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactorBBM\Client
UIReactorBBMIcon.dat
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactorBBM\Server
ConvReactorBBM.mil
ConvReactorBBM.mak
ConvReactorBBM.mdp
ConvReactorBBM.cpp
ConvReactorBBM.h
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactorEEB
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactorEEB\Client
UIReactorEEBIcon.dat
C:\Program Files\Simulation
Sciences\ROMeo10\Models\ConvReactorEEB\Server
ConvReactorEEB.mil
ConvReactorEEB.mak
ConvReactorEEB.mdp
ConvReactorEEB.cpp
ConvReactorEEB.h
C:\Program Files\Simulation
Sciences\ROMeo10\Models\EzFlashEEB\Client
EzFlashEEBIcon.dat
C:\Program Files\Simulation
Sciences\ROMeo10\Models\EzFlashEEB\Server
EzFlashEEB.mil
EzFlashEEB.mak
EzFlashEEB.mdp
EzFlashEEB.cpp
EzFlashEEB.h
EzFlashEEB2.for

7.7 Modifying the Icon Data File


The icon data file is a text file employing a special syntax that
defines the appearance of the process unit icon and its port
arrangement. Simple modifications to an existing icon data file

Process Models 7-13


generally cover most requirements. However, when more extensive
changes are anticipated, the reference information in this section
will prove helpful.

7.7.1 Icon Construction - Structure of the Icon Definition


File
The overall structure of an icon definition file is as follows:
GROUPany number of group segments; each GROUP segment is
terminated by the next GROUP statement, an END statement or an
end-of-file.
ICONany number of ICON sections in a GROUP segment; each
ICON segment is terminated by the next GROUP statement, the next
ICON statement, an END statement or an end-of-file.

shapewordany number in each ICON section

DATAone or more data sets for each shapeword

BEGOUTLINEany number of optional outline sequences

shapeword or PLINat least one shapeword or PLIN statement


is mandatory
DATAone or more data sets for each shapeword or PLIN
statement

ENDOUTLINEmatches BEGOUTLINE

PORTany number in each ICON section

DATAone or more data sets for each PORT

PLIN any number in each ICON section)

DATAone or more data sets for each port line

ENDstatement terminating a GROUP segment

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

7-14 Special Topics


whole, such as fill color. If both a shapeword line and the
terminating ENDOUTLINE line supply a non-default value for an entity,
the individual shapeword line data will take precedence for that
particular part of the outline. If only one gives a default, the other
will be used.
The requirements for order within the ICON segment are
considerably less strict than the preceding outline might suggest.
The order of the keywords shapeword, BEGOUTLINE/ENDOUTLINE, PORT
and PLIN is not significant. As long as each shapeword, PORT and PLIN
is followed by its appropriate DATA statement(s), the shapewords,
PORTs and PLINs can appear in any order. Like items need not be
grouped together. Within a BEGOUTLINE/ENDOUTLINE sequence,
however, the items should be presented in such a manner that they
describe a closed figure with the items drawn in the order presented.
DATA statements consist of a string of integers separated by white
space. If there are multiple consecutive DATA statements, the strings
of values are concatenated. Thus DATA 1 2 3 followed by DATA 4 5 6
is equivalent to DATA 1 2 3 4 5 6.

7.7.2 Specifying Icon Appearance


All text strings must be entered in quotes. All integers are separated
by white space. Floating point values must incorporate a decimal
point with optional numerals to the right of the decimal point.
The ICON.DAT file processor interprets // and what follows in the
same line as comment text.

Style Codes

Icon Color Codes


0 Black 1 Blue
2 Green 3 Cyan
4 Red 5 Magenta
6 Brown 7 Light Gray
8 Dark Gray 9 Light Blue
10 Light Green 11 Cyan
12 Light Red 13 Magenta
14 Yellow 15 White
16 Light Yellow 17 Dark White

Process Models 7-15


Button Color Codes
18 Light gray button DOWN
19 Dark gray for button UP
20 Dark Border
21 Light Border
22 Pushed
23 Light Red (Flags that item requires additional data.)
24 Light Yellow

Line Style Codes


0 Solid
1 Dash
2 DashDot
3 DashDotDot
4 Dot
5 Solid (Flags that item requires additional data.)

Fill Style Codes


0 Hollow
1 Solid
2 Horizontal hatching
3 Vertical hatching
4 Fdiagonal (not used)
5 Bdiagonal (not used)
6 Cross
7 Diagcross

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.

A GROUP segment starts with a GROUP statement and ends with


another GROUP statement, an END statement or an end-of-file in the
input stream.

7-16 Special Topics


A GROUP segment contains one or more ICON statements, each of
which starts an ICON section.
Table 7.7-1: GROUP Statement Arguments
Arguments Description

<id> Application-specific ID number for objects of this


group. The number must be unique within the
application. There are application-specific API calls
that use this number to identify a current group.
ROMeo itself, however, does not use this number.
The Group id number (which must be less than 65536)
is used as the Windows id for the button on the icon
palette. This number is used by GUI automation tools
such as QA Partner to unambiguously locate the button
so QA Partner can press it and lay the icon down on the
flowsheet.
Do not indiscriminately change these numbers!

<description> Text description for the group. This text will be


displayed beneath the icon on the toolbar if the Options/
Drawing/Defaults/General/Large Icons option is
selected.

<class> Application-specific data class (quoted string) for


objects of this group. Some API calls use this class
name, and it can be stored in a database.

<show> 1 icon is included in the icon palette


0 icon not available

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

<text> Text, appearing on the selection menu when multiple


icons are specified in a GROUP. This specification can be
invoked for the whole group (at runtime) by picking
Options/DrawingDefaults/UnitDisplay or (also at
runtime) for an individual instance by selecting the unit,
then selecting Edit-DisplayStyle from the main menu.

<rlog> Routing logic code (not currently used)

Process Models 7-17


Table 7.7-2: ICON Statement Arguments (cont.)
Argument Description

<rflag> Rotation flag during laydown:


0 flip and rotate,
1 flip only
2 neither
Flip allows reflection on both the x and the y axis.
Rotate allows rotation in multiples of 90 degrees.

<sfac> Scaling factor. This floating point number has a default


value of 1.0. A larger factor means a proportionately
larger icon. In an initial setup, when using the global
values in the sample file but before any scaling has
occurred, a single coordinate unit will correspond to
approximately two pixels on the screen.

<dform> Default autolabel format. This text string (quotes are


required) with the conventions of a string in C/C++
specifies the label displayed under each instance of the
icon. Each instance of the icon is numbered
consecutively starting at the number specified below. An
example is "FLASHDRUM%03d". All icons in the same
GROUP should have the same dform specification.

<dstart> Default autolabel starting number. This sets the number


of the first instance of the icon on the flow sheet. All
icons in the same GROUP should have the same dstart
value.

<input> Operator input required


1 yes
0 no

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

7-18 Special Topics


the DATA line(s) vary depending on the individual shapeword. A
value of -1 for a parameter causes the default setting to be used.
Table 7.7-3: Shapeword Statement Arguments
Argument Description

<ID> The numeric ID for this shape. Normally set to -1.

<line_color> The line color. Default is -1. See Color Codes above.

<fill> Fill flag, -1 for default. See Fill Style Codes above.

<fill_color> Fill color, -1 for default. See Color Codes above.

<width> Line width, -1 for default, >= 0 is line width in screen


pixels.

<style> Line style, -1 for default. See Line Style Codes above.

The coordinates in Table 7.7-4 increment to the right (for x) and


down (for y). The origin can be chosen anywhere, but standard
practice is to locate the origin in the upper left hand corner of the
icon, thus making all coordinate values positive. Before scaling,
each unit of the coordinate system corresponds to roughly two
screen pixels. The coordinates must be supplied as integer values.
Table 7.7-4: Shapeword DATA Statements
Shapeword Definition DATA Explanation

LINE Connected x1,y1, Line can be multi-segment, i.e.


straight x2,y2, if more than two data pairs are
line(s) ... given, consecutive line
segments are drawn.

LINE2 Connected x1,y1, As above.


straight x2,y2,
line(s) with ...
arrow at end
of last
segment

LINE3 Connected x1,y1, As above.


straight x2,y2,
line(s) with ...
arrows at
end of each
segment

Process Models 7-19


Table 7.7-4: Shapeword DATA Statements (cont.)
Shapeword Definition DATA Explanation

RLIN Repeating, x1,y1, x1,y1 and x2,y2 define the


disconnected x2,y2, first line.
straight lines dx,dy, dx, dy specify the offset to the
number following line (offset applies to
both ends).
number is the number of lines
drawn.

POLY Closed x1,y1, Polygon closes automatically


Polygon x2,y2, from the last point to the initial
... point.

RECT Rectangle
xmin,y
min,
xmax,y
max

ELLIPSE Unrotated xc,yc, xc,yc specify the center point.


ellipse xr,yr xr,yr are the radii of the x and
y semiaxes.

CIRCLE Circle xc,yc,


radius

ARC Elliptic arc xc,yc, Angles are measured in degrees


xr,yr, counterclockwise from the
angle1 positive x axis.
,
angle2

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.

7-20 Special Topics


DATA <size> <rotation> <xalign> <yalign> <xpos> <ypos>

Table 7.7-5: TEXT Statement Arguments


Argument Description

<id> .

<color> Line color, -1 is default. See Color Codes above.

<style>

<text> .

PORT and PLIN Statements


PORT <id> <color> <type> <unused> <width> <style> PortName
Comment

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.

<color> Line color, -1 is default. See Color Codes above.

<type> Port type.


0 Process stream
3 Controller
4 Measurement
5 Tuning Parameter
6 Penalty
7 Tuning Parameter/Measurement pair
8 Composition Estimator
10 Top-only unit-to-unit port, connects to 11
11 Bottom-only unit-to-unit port, connects to 10
12 Top or bottom unit-to-unit port, connects to 12
13 Left side only unit-to-unit port, connects to 14
14 Right side only unit-to-unit port, connects to 13
15 Left or right unit-to-unit port, connects to 15

<unused> Always -1.

<width> -1 for default, else width in pixels

<style> Always -1.

Process Models 7-21


Table 7.7-6: PORT Statement Arguments (cont.)
Argument Description

PortName PortName should be the same name used in the


PortStreamPair() method call which is usually found in
the Initialize() method.

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.

DATA <max_feed> <max_prod> <direct> <rnum> <style> <portgroup>


<port> <nRel> <requiredgroup> <req_feeds> <req_prods>
<dep_flag> <phase> <x1> <y1> <x2> <y2>

Table 7.7-7: PORT and PLIN DATA Statements


Argument Description

<max_feed> Maximum number of feed (input) streams.


-1 no limit
0 none

7-22 Special Topics


Table 7.7-7: PORT and PLIN DATA Statements (cont.)
Argument Description

<max_prod> Maximum number of product (output) streams.


-1 no limit
0 none
For any one port, normally either <max_feed> or
<max_product> should be zero, unless the port belongs to
a feed/product portgroup, see below.

<direct> Connection direction, unused (see "rnum" below), enter -


1.

<rnum> Resource number defining connection direction:


0 left
1 up
2 right
3 down
Used only for PORT, but not for PLIN.

<style> PORT linestyle, not used. Enter 0.

<portgroup> Relative portgroup. A PORT can belong to a portgroup. A


portgroup has exactly two members, each of which is a
port or a port line.
0no portgroup membership.
>0a portgroup.
One member of a portgroup is a feed and the other is for a
product, but the assignment of which is which is left open.
Note that a portgroup is different from a GROUP of icons
above and also from a requiredgroup below.

<port> Not used. Enter 0.

<nRel> Not used. Enter 0.

<requiredgroup> Indicates that at least one of the ports in a requiredgroup


must be connected.
0no group membership.
> 0port belongs to the requiredgroup of that number.
Note: requiredgroup is distinct from the portgroup and
from the GROUP of icons. A requiredgroup can have any
nonzero positive number of members.

<req_feeds> The minimum number of feeds. This minimum (if given


as > 0) must be met, regardless of any group memberships
etc. Exception: if the port is a member of a portgroup,
either this number must be satisfied or <req_prods> must
be satisfied

<req_prods> The minimum number of products. This minimum (if


given as > 0) must be met, regardless of any group
memberships etc. Exception: if the port is a member of a
portgroup, either this number must be satisfied or
<req_feeds> must be satisfied.

Process Models 7-23


Table 7.7-7: PORT and PLIN DATA Statements (cont.)
Argument Description

<dep_flag> Either 0 or equal to portgroup. In the latter case, if this


port is connected, the other port in the group must also be
connected. One will be a feed and the other a product.

<phase> Not used. Set to 0.

<x1> <y1> Location of port or port line starting point, x,y-


coordinates.

<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>

The ENDOUTLINE statement has the same format as the shapeword


statement. Any value that is individually specified for a part of the
outline will take precedence over the value in ENDOUTLINE. Note
also that fill and fill_color have no meaning except for an
enclosed entity.
Table 7.7-8: ENDOUTLINE Statement Arguments
Argument Description

<ID> The numeric ID for this shape. Normally set to -1 for


default.

<line_color> The line color. Default is -1. See Color Codes above.

<fill> Fill flag, -1 for default. See Fill Style Codes above.

<fill_color> Fill color, -1 for default. See Color Codes above.

<width> Line width, -1 for default, >= 0 is line width in screen


pixels.

<style> Line style, -1 for default. See Line Style Codes above.

7.8 Sample Icon


The following example of a GROUP includes three different kinds of pump icons. The
detailed command lines needed to draw the first of these follows Figure 7.8-1.
GROUP 10007 "Pump" "Pump"
ICON "Pump" 0 1 0.0 "P%0.3d" 100 1
...
ICON "Electric Pump" 0 1 0.0 "P%0.3d" 100 1
...

7-24 Special Topics


ICON "Steam Pump" 0 1 0.0 "P%0.3d" 100 1
...
GROUP 10004 "Valve" "Valve"
...

Figure 7.8-1: Sample Icon for SISO Pump


Feed port graphic (outside)
Feed port graphic (inside)
Product port
Upper left arc Note: Feed and product
ports and port lines are
visible only while the
PFD is in connect mode.
Feed port Product port graphic
Upper right arc x

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

Process Models 7-25


// DATA x1,y1, x2,y2, x3,y3, x4,y4
DATA 0 4 5 4 5 6 0 6 // Feed graphic (inside)
PORT 100 2 -1 -1 -1 -1 // Feed port
// PORT <id> <color> <type> <unused> <width> <style>
DATA -1 0 0 2 0 0 0 0 0 1 0 0 -1
// DATA <max_feed> <max_prod> <direct><rnum> <style>
<portgroup> <port> <nRel> <requiredgroup> <req_feeds>
<req_prods> <dep_flag> <phase>
DATA -2 5
// DATA <x1> <y1>
PORT 107 2 -1 -1 -1 -1 // Liquid Product port
DATA 0 1 0 0 0 0 0 0 0 0 1 0 0
// DATA xc,yc
DATA 12 1
// ID is a shapeword
ID -1 -1 -1 -1 -1 -1
// DATA xc,yc
DATA 5 16 // Location of id

7-26 Special Topics


7.9 Icon Data File Template
The following template file offers a starting point to specify process model icons. Pay
attention to the lines marked TODO. It is also important to set the GROUP id to a value that
does not conflict with other icon data files. More specifically, the default value
GROUP 690010
should be changed to a number like:
GROUP 690011
In other words, specify a value higher than 690010.
//******************************************************************************
//* Project: ROMeo
//* Sub-system: ROMeo Unit Wizard
//*
///* Purpose: Template for a unit operation icon
//*
//* Copyright (c) 1998 by Simulation Sciences Inc.
//* ALL RIGHTS RESERVED
//******************************************************************************
// =====================================================================
//
// TEXT ARGUMENTS
//
// --------------------------------------------------------
// ARG # | 1 2 3 4 5
// --------------------------------------------------------
// DESC | TYPE ID LINE STYLE TEXT
// | COLO
// | TEXT
// --------------------------------------------------------
//
// DATA LINE: SIZE ROTATION XALIGN YALIGN XPOS YPOS
// ------------------
// 0 = Left Top
// 1 = Right Bottom
// 2 = Center Center
//

======================================================================

// TODO - In the code below


// Replace "GUI Name" by the name that will appear on the palette
// Replace "MILANO Name by the name of the MILANO class e.g. PM_Flash
// Replace MY by the letters that will be used by default for the unit name.
// Make sure the group id number doesn't conflict with any other unit's id.
GROUP 690010 "GUI Name" "MILANO Name" 1

ICON "GUI Name" 0 1 8 "MY%d" 1 0

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

Process Models 7-27


ENDOUTLINE -1 -1 -1 -1 -1 -1

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

// Measurement Out Port


PLIN 401 2 4 -1 -1 -1 "Measurement"
DATA -1 0 0 1 0 0 0 0 0 0 0 0 0 // top
DATA 2 0 8 0
PLIN 402 2 4 -1 -1 -1 "Measurement"
DATA -1 0 0 3 0 0 0 0 0 0 0 0 0 // bottom
DATA 2 10 8 10

// Tuning Parameter Out Port


PLIN 501 2 5 -1 -1 -1 "TuningParameter"
DATA -1 0 0 1 0 0 0 0 0 0 0 0 0 // top
DATA 2 0 8 0
PLIN 502 2 5 -1 -1 -1 "TuningParameter"
DATA -1 0 0 3 0 0 0 0 0 0 0 0 0 // bottom
DATA 2 10 8 10

// Penalty Out Port


PLIN 701 2 6 -1 -1 -1 "Penalty"
DATA -1 0 0 1 0 0 0 0 0 0 0 0 0 // top
DATA 2 0 8 0
PLIN 702 2 6 -1 -1 -1 "Penalty"
DATA -1 0 0 3 0 0 0 0 0 0 0 0 0 // bottom
DATA 2 10 8 10

END
// Everything below the "END" line is ignored.
Appendix A
Thermodynamic Properties

A.1 Refinery Inspection Properties


Note: Values for all properties suffixed with PERCENT or PPM are entered and reported on
a fractional basis. Thus 70% coke wt. percent must be entered as COKEWTPERCENT = 0.70.
AROMATICV NNUM
AROMATICWT NWTPERCENT
AROMCARBFRAC OLEFINBV
BRANCHCARBFRAC OLEFINCARBFRAC
BROMINENUMBER OLEFINCV
CETANENUMBER OLEFINMV
CNUM ONUM
COKEWTPERCENT OWTPPM
CONCARBRESPPM PARAFFINV
CWTPERCENT PARAFFINWT
HNUM PARAFFINWTRATIO
HWTPERCENT RAMSCARBPERCENT
IRONWTPPM RONCLEAR
MERCAPTANPPM RONLEADED
MONCLEAR SNUM
MONLEADED SODIUMPPM
NAPHTHALENEV SWTPERCENT
NAPHTHALENEWT UVDIAROMATICWT
NAPHTHENEV VANADIUMPPM
NAPHTHENEWT WAXWTPERCENT
NICKELWTPPM ZNUM
NITRBASICPERCENT

Process Models A-1


A.2 Refinery Inspection Property Points
ANILINEPOINT TCLOUD
FLASHPOINT TPLUG
FREEZEPOINT TPOUR
SMOKEPOINT

A.3 Fixed Point Properties


ACENTRIC (=OMEGA) OMEGA (=ACENTRIC)
API PARACHOR
AUTOIGNITION PC
AWK (=VDWA) PTP
CHAO RACKETT
DIELECTRIC RADIUS
DIPOLE SG60F
GFORM SLTB
GHV SLTM
HCOMBUST SOLP
HFORM SOLUPARA (=SOLP)
HFUSIONNMP SVTB
HIFLAMM TC
HLTB TDIELECTRIC
HLTM TTP
HVAPNBP UOPK
HVTB VC
LHV VDWA (=AWK)
LOFLAMM VDWV
MVOL60F VWK (=VDWV)
MW ZC
NBP ZRA (=RACKETT)
NMP

A-2 Thermodynamic Properties


A.4 Correlated Properties
CONDLSAT DHLSATATTMAX
CONDLSATATTMAX DHLSATATTMIN
CONDLSATATTMIN DHSSATATTMAX
CONDLSATCOEFS DHSSATATTMIN
CONDLSATCORR DHVAPORIZEATTMAX
CONDLSATEXTRTMAX DHVAPORIZEATTMIN
CONDLSATEXTRTMIN DPSATATTMAX
CONDLSATFLOWBASIS DPSATATTMIN
CONDLSATILIMIT DRHOLSATATTMAX
CONDLSATLOGFORM DRHOLSATATTMIN
CONDLSATPROPCONV DRHOSSATATTMAX
CONDLSATTEMPUOM DRHOSSATATTMIN
CONDLSATTMAX DSURFATTMAX
CONDLSATTMIN DSURFATTMIN
CONDVSAT DVISCLSATATTMAX
CONDVSATATTMAX DVISCLSATATTMIN
CONDVSATATTMIN DVISCVSATATTMAX
CONDVSATCOEFS DVISCVSATATTMIN
CONDVSATCORR EPS
CONDVSATEXTRTMAX HIDEAL
CONDVSATEXTRTMIN HIDEALATTMAX
CONDVSATFLOWBASIS HIDEALATTMIN
CONDVSATILIMIT HIDEALCOEFS
CONDVSATLOGFORM HIDEALCORR
CONDVSATPROPCONV HIDEALEXTRTMAX
CONDVSATTEMPUOM HIDEALEXTRTMIN
CONDVSATTMAX HIDEALFLOWBASIS
CONDVSATTMIN HIDEALILIMIT
DCONDLSATATTMAX HIDEALLOGFORM
DCONDLSATATTMIN HIDEALPROPCONV
DCONDVSATATTMAX HIDEALTEMPUOM
DCONDVSATATTMIN HIDEALTMAX
DHIDEALATTMAX HIDEALTMIN
DHIDEALATTMIN HLSAT

Process Models A-3


HLSATATTMAX HVAPORIZEFLOWBASIS
HLSATATTMIN HVAPORIZEILIMIT
HLSATCOEFS HVAPORIZELOGFORM
HLSATCORR HVAPORIZEPROPCONV
HLSATEXTRTMAX HVAPORIZEREF
HLSATEXTRTMIN HVAPORIZETEMPUOM
HLSATFLOWBASIS HVAPORIZETMAX
HLSATILIMIT HVAPORIZETMIN
HLSATLOGFORM PSAT
HLSATPROPCONV PSATATTMAX
HLSATREF PSATATTMIN
HLSATTEMPUOM PSATCOEFS
HLSATTMAX PSATCORR
HLSATTMIN PSATEXTRTMAX
HSSAT PSATEXTRTMIN
HSSATATTMAX PSATFLOWBASIS
HSSATATTMIN PSATILIMIT
HSSATCOEFS PSATLOGFORM
HSSATCORR PSATPROPCONV
HSSATEXTRTMAX PSATREF
HSSATEXTRTMIN PSATTEMPUOM
HSSATFLOWBASIS PSATTMAX
HSSATILIMIT PSATTMIN
HSSATLOGFORM REFT
HSSATPROPCONV RHOLSAT
HSSATTEMPUOM RHOLSATATTMAX
HSSATTMAX RHOLSATATTMIN
HSSATTMIN RHOLSATCOEFS
HVAPORIZE RHOLSATCORR
HVAPORIZEATTMAX RHOLSATEXTRTMAX
HVAPORIZEATTMIN RHOLSATEXTRTMIN
HVAPORIZECOEFS RHOLSATFLOWBASIS
HVAPORIZECORR RHOLSATILIMIT
HVAPORIZEEXTRTMAX RHOLSATLOGFORM
HVAPORIZEEXTRTMIN RHOLSATPROPCONV

A-4 Thermodynamic Properties


RHOLSATTEMPUOM SURFTMIN
RHOLSATTMAX VISCLSAT
RHOLSATTMIN VISCLSATATTMAX
RHOSSAT VISCLSATATTMIN
RHOSSATATTMAX VISCLSATCOEFS
RHOSSATATTMIN VISCLSATCORR
RHOSSATCOEFS VISCLSATEXTRTMAX
RHOSSATCORR VISCLSATEXTRTMIN
RHOSSATEXTRTMAX VISCLSATFLOWBASIS
RHOSSATEXTRTMIN VISCLSATILIMIT
RHOSSATFLOWBASIS VISCLSATLOGFORM
RHOSSATILIMIT VISCLSATPROPCONV
RHOSSATLOGFORM VISCLSATTEMPUOM
RHOSSATPROPCONV VISCLSATTMAX
RHOSSATTEMPUOM VISCLSATTMIN
RHOSSATTMAX VISCVSAT
RHOSSATTMIN VISCVSATATTMAX
SURF VISCVSATATTMIN
SURFATTMAX VISCVSATCOEFS
SURFATTMIN VISCVSATCORR
SURFCOEFS VISCVSATEXTRTMAX
SURFCORR VISCVSATEXTRTMIN
SURFEXTRTMAX VISCVSATFLOWBASIS
SURFEXTRTMIN VISCVSATILIMIT
SURFFLOWBASIS VISCVSATLOGFORM
SURFILIMIT VISCVSATPROPCONV
SURFLOGFORM VISCVSATTEMPUOM
SURFPROPCONV VISCVSATTMAX
SURFTEMPUOM VISCVSATTMIN
SURFTMAX

Process Models A-5


Appendix B
Units of Measure

B.1 UOM Classes


All calculations in ROMeo are carried out in the internal units of
measure (UOM) listed below. The UOM assigned to variables in
the GUI (that is, in the units standard data entry windows or in the
units Model Data Entry Window) are simply display UOM. When
you specify a value for a variable in a particular unit operation in
terms of psia, the ROMeo GUI converts this psia value into kPa
(the internal pressure UOM), ROMeo then carries out the
calculations in the internal units, whereupon the ROMeo GUI
reconverts the results back into psia for display. Understanding how
units are handled in ROMeo is essential for the proper creation and
use of macros, custom equations and process models.

B.1.1 UOM Terminology


The UOM nomenclature shown below is observed in this document
and elsewhere in the ROMeo documentation.
Table B.1-1: UOM Terminology
Term Description
Unit-of-Measure "K", "F", "m", "sec", "kg/hr", "kg-m2/sec2", etc.
(UOM)
Unit-of-Measure "Pressure", "Temperature", "Rate", etc.
Class (UOM class)
Unit-of-Measure Set A collection of specific UOM defaults for UOM
(UOM set) classes. Examples include "English", "Metric", "SI",
etc.
Base Class A UOM class in the MILANO utilities that is not built
up from any other MILANO UOM class. "Temp" is a
base class.

Process Models B-1


Table B.1-1: UOM Terminology (cont.)
Term Description
Internal Base Class A base class used internally for specialized processing
of some composite classes. These internal base classes
should not be directly specified or used.
Composite Class A MILANO UOM class that is built up from two or
more base classes: the "density" class is defined as
"mass / volume".
Custom Class A MILANO UOM class that is built up at runtime
from two or more UOM classes. For example, the
string "Pres / VolRate 2" would be used to define a
custom UOM class of pressure divided by the square
of the volumetric flowrate.
Dimension In the UOM Class table below, it is one of: M (Mass),
L (length), t (time), T (temperature), Q (charge), and $
(currency).

B.1.2 Specifying UOM Classes


Many of the UOM utilities require specification of a UOM class as
a text string. A UOM Class may be specified as one of the
predefined MILANO UOM Classes from the list below, such as
"Pres", "Rate", etc. Alternatively, one can build custom UOM
classes from the MILANO predefined classes:
"Leng/Time"
"Mass Leng 2 / Time 2"
"Mass Leng 2 Time -2"
It is currently not possible to add to the built-in list of MILANO
predefined classes.

B.1.3 Specifying Units-of-Measure


Many of the UOM utilities require specification of a UOM as a text
string. A UOM may be specified by providing one of the valid
UOMs for the corresponding UOM class. Consult Units of
Measure, Table B.3-1, for a list of the valid unit-of-measure strings.
If the UOM class is a composite class, or a combination of base/
composite classes, then specify the UOM string as a concatenation
of the individual UOMs for each constituent class. For example,
"Velocity" is a composite class ("Leng / Time"), so in this case
specify the UOM as a Length UOM plus a Time UOM. You must
include the division sign where needed, but do not use the asterisk

B-2 Units of Measure


to indicate multiplication. Combine the UOM strings in the
numerator and denominator by using a hyphen: BTU/lb-hr.
Asterisks are used to designate UOM multipliers.
If the UOM class includes an exponent, include the exponent as part
of the UOM string. See UOM Exponents, B.1.5 for details.

B.1.4 UOM Multipliers


Multipliers of "one thousand" and "one million" can be provided for
the UOM string. The two available formats are:
API format "M" or "MM" plus space plus the UOM
string: "MM BTU/hr".
SI format "k" or "M" plus an asterisk plus the UOM
string: "M*kJ/hr".

B.1.5 UOM Exponents


Custom UOM classes may contain integer exponents. When you
specify a UOM for this class, include the exponent as part of that
string. Use parentheses if the exponent is applied to a UOM which
ends in a number or which contains a dash or division sign.
Table B.1-2: UOM Exponents
UOM Class UOM UOM Class UOM
Pres VolRate kpa-m3/sec Pres/VolRate kpa/(m3/sec)
Pres VolRate 2 kpa(m3/sec)2 Pres/VolRate 2 kpa/(m3/sec)2

B.1.6 Usage Guidelines


Observe the following guidelines when employing ROMeo UOM:
All custom equations must employ internal UOM classes.
Use the Token to specify UOM classes in your code.
Initial values for instance variables in Customization units must
be supplied in the Model Data Entry Window to avoid a cross-
check error when running the flowsheet.

Process Models B-3


Note: The time unit that appears on the ROMeo GUI is hours.
The internal ROMeo time UOM is seconds. Thus, when writing
macros or custom equations, be aware that ROMeo assumes that
the implicit time unit is the second. If Var1 is a flowrate variable:
Var1 - 1.0 == 0
Var1 has the value of 1 kg-mol/sec or 3600 kg-mol/hr, since
ROMeo assumes the numeral 1.0 to represent 1.0 kg-mol/sec.

B.2 UOM Classes and Predefined UOM Sets


Entries in the English, Metric, SI and Internal columns are
default UOM for the set.
Table B.2-1: UOM Classes and Sets
Base Class Token English Metric SI Internal
Dimensionless Dimensionless
Area Area ft2 m2 m2 m2
Area, Fine FineArea in2 mm2 mm2 m2
Basis Basis Mole Mole Mole Mole
Composition Frac fraction fraction fraction fraction
Composition, Mass MassFrac fraction fraction fraction fraction
Composition, Mole MoleFrac fraction fraction fraction fraction
Composition, Volume VolFrac fraction fraction fraction fraction
Currency Currency currency currency currency currency
Dipole Moment Dipole DEB DEB DEB DEB
Energy Energy BTU kcal kJ kJ
Fouling Coefficient Foul hr-ft2-F/BTU hr-m2-C/kcal m2-K/kW m2-K/kW
Heat Capacity Cp BTU/lb-mol-F kcal/kg-mol-K J/kg-mol-K J/kg-mol-K
Heat Transfer Coeff * Area UA BTU/hr-F kcal/hr-K kW/K kW/K
Heat Transfer Coefficient Htco BTU/hr-ft2-F kcal/hr-m2-K kW/m2-K kW/m2-K
Length Leng ft m m m
Length, Fine FineLeng in mm mm m
Mass Mass lb kg kg kg
Mole Mole lb-mol kg-mol kg-mol kg-mol
Pressure Pres psia kg/cm2 kPa kPa
Pressure difference PresDiff psi kg/cm2 kPa kPa
Pressure, Absolute PresAbs psia kg/cm2 kPa kPa
Rotation Rotation rpm rpm rpm rps
Surface Tension Surf dyne/cm dyne/cm N/m N/m
Temperature Temp F C K K
Temperature difference TempDiff F C K K
Temperature, Absolute TempAbs R K K K
Thermal Conductivity Cond BTU/hr-ft-F kcal/hr-m-C kW/m-K kW/m-K
Time Time hr hr hr sec

B-4 Units of Measure


Table B.2-1: UOM Classes and Sets (cont.)
Base Class Token English Metric SI Internal
Torque Torque lb-ft N-m N-m N-m
Viscosity Visc CP CP Pa-sec Pa-sec
Viscosity, Kinematic KVis cST cST cST cST
Volume, Actual Vol ft3 m3 m3 m3
Volume, Liquid Vol ft3 m3 m3 m3
Volume, Vapor VapVol ft3 m3 m3 m3

Table B.2-2: UOM Internal Base Classes and Sets


Internal Base Class Token English Metric SI Internal
Petro Mass PetroMass API kg kg kg
Powertop PowerTop BTU kcal kJ kJ

Table B.2-3: UOM Composite Classes and Sets


Composite Class Token English Metric SI Internal
Basis Composition BasisFrac Molefraction Mole fraction Mole fraction Mole fraction
Density Density lb/ft3 kg/m3 kg/m3 kg/m3
Density, Petro PetroDensity API kg/m3 kg/m3 kg/m3
Frequency Freq 1/hr 1/hr 1/hr 1/sec
Inertia Inertia lb-ft2 kg-m2 kg-m2 kg-m2
Power Power HP kcal/hr kJ/hr kJ/sec
Quantity Quantity lb-mol kg-mol kg-mol kg-mol
Rate Rate lb-mol/hr kg-mol/hr kg-mol/hr kg-mol/sec
Rate, Mass MassRate lb/hr kg/hr kg/hr kg/sec
Rate, Mole MoleRate lb-mol/hr kg-mol/hr kg-mol/hr kg-mol/sec
Rate, Volume VolRate ft3/hr m3/hr m3/hr m3/sec
Specific Enthalpy SpEnthalpy BTU/lb kcal/kg kJ/kg kJ/kg
Specific Entropy SpEntropy BTU/F-lb kcal/C-kg kJ/K-kg kJ/K-kg
Specific Volume, Liquid SpVol ft3/lb-mol m3/kg-mol m3/kg-mol m3/kg-mol
Specific Volume, Vapor VapSpVol ft3/lb-mol m3/kg-mol m3/kg-mol m3/kg-mol
Velocity Velocity ft/hr m/hr m/hr m/sec

Table B.2-4: Definition of Composite UOM Classes


Composite Class Definition Composite Class Definition
BasisFrac Basis Frac Quantity Basis Mole
Density Mass / Vol Rate Basis Mole / Time
Freq 1 / Time SpEnthalpy Energy / Mass
Inertia Mass Leng 2 SpEntropy Energy / TempDiff Mass
MassRate Mass / Time SpVol Vol / Mole
MoleRate Mole / Time VapSpVol VapVol / Mole
PetroDensity PetroMass / Vol Velocity Leng / Time
Power PowerTop / Time VolRate Vol / Time

Process Models B-5


B.3 Units of Measure for UOM Base Classes
Use the UOMClass to specify the Table B.3-1: Units of Measure (cont.)
<<Dim>> property in MILANO code. UOM Class Token Description
Area mic2 Micron^2
Use the Token to specify units of
mm2 Millimeter^2
measure in MILANO code.
mmic2 Millimicron^2
UOM multipliers for 1000 and yd2 Yard^2
1,000,000 can be supplied in API Basis Liq. Vol. Standard Liquid Volume
format (M BBL, MM BBL) or SI format Mass Mass
using an asterisk (k*m3, M*m3). Mole Mole
Vap. Vol. Standard Vapor Volume
To supply a UOM for a composite or Volume Actual Volume
custom UOM class, combine Cond BTU/hr-ft-F BTU/hour-foot-F
appropriate UOMs from the base cal/hr-m-C Calorie/hour-meter-C
classes: "lb/hr" for "Rate" or "kpa/ cal/sec-cm-C Calorie/second-cm-C
(m3/sec)2" for "Pres/VolRate 2". kcal/hr-m-C Kilocalorie/hour-m-C

Table B.3-1: Units of Measure kW/m-C Kilowatt/meter-C


kW/m-K Kilowatt/meter-Kelvin
UOM Class Token Description
W/m-C Watt/meter-Celsius
Dimensionless
W/m-K Watt/meter-Kelvin
ActVol bbl API barrel
Cp BTU/lb-mol- BTU/pound-mole-C
cm3 Centimeter^3 C
dm3 Decimeter^3 BTU/lb-mol- BTU/pound-mole-F
ft3 Foot^3 F

gal U.S. gallon BTU/lb-mol- BTU/pound-mole-K


K
igal Imperial gallon
cal/g-mol-C Calorie/gram-mole-C
in3 Inch^3
cal/g-mol-K Calorie/gram-mole-K
km3 Kilometer^3
cal/kg-mol-C Calorie/kg-mole-C
liter Liter
cal/kg-mol-K Calorie/kg-mole-K
m3 Meter^3
CHU/g-mol-F CHU/gram-mole-F
mi3 Mile^3
CHU/kg-mol- CHU/kilogram-mole-F
mm3 Millimeter^3 F
yd3 Yard^3 CHU/lb-mol- CHU/pound-mole-F
F
Area acre Acre
J/g-mol-C Joule/gram-mole-C
ang2 Angstrom^2
J/g-mol-K Joule/gram-mole-K
cm2 Centimeter^2
J/kg-mol-C Joule/kg-mole-C
dm2 Decimeter^2
J/kg-mol-K Joule/kilogram-mole-K
ft2 Foot^2
kcal/g-mol-C Kilocalorie/g-mole-C
hect Hectare
kcal/g-mol-K Kilocalorie/g-mole-K
in2 Inch^2
kcal/kg-mol- Kilocalorie/kg-mole-C
km2 Kilometer^2 C
m2 Meter^2 kcal/kg-mol- Kilocalorie/kg-mole-K
mi2 Mile^2 K

Process Models B-6


Table B.3-1: Units of Measure (cont.) Table B.3-1: Units of Measure (cont.)
UOM Class Token Description UOM Class Token Description
kJ/g-mol-C Kilojoule/gram-mole-C SEK Swedish Krone
kJ/g-mol-K Kilojoule/gram-mole-K SGD Singapore Dollar
kJ/kg-mol-C Kilojoule/kg-mole-C SVC El Salvador Colon
kJ/kg-mol-K Kilojoule/kg-mole-K VEB Venezuelan Bolivar
Cp MJ/g-mol-K Megajoule/gram-mole- Dipole Coul-m Coulomb-meter
K
DEB Debye
MJ/kg-mol-K Megajoule/kg-mole-K
EU Electrostatic unit
PCU/g-mol-F PCU/gram-mole-F
FineArea acre Acre
PCU/kg-mol- PCU/kilogram-mole-F
F ang2 Angstrom^2

PCU/lb-mol- PCU/pound-mole-F cm2 Centimeter^2


F dm2 Decimeter^2
Currency currency currency ft2 Foot^2
$ US Dollars hect Hectare
ARS Argentinian Peso in2 Inch^2
AUD Australian Dollar km2 Kilometer^2
BEF Belgian Franc m2 Meter^2
BRE Brazilian Real mi2 Mile^2
CAD Canadian Dollar mic2 Micron^2
cents US cents mm2 Millimeter^2
CHF Swiss Francs mmic2 Millimicron^2
CLP Chilean Peso yd2 Yard^2
COP Colombian Peso Energy BTU British Thermal Unit
CRC Costa Rica Colon cal Calorie
credits credits CHU Centigrade Heat Unit
DEM German Mark ft-lb Foot-pound
DKK Danish Krone g-cm Gram-centimeter
DMR Dominican Rep. Peso J Joule
ECS Equadorian Sucre kcal Kilocalorie
ECU European Currency kg-m Kilogram-meter
ESP Spanish Peseta kJ Kilojoule
FIM Finnish Markkaa kW-hr Kilowatt-hour
FRF French Francs PCU Pound Centigrade Unit
GBP British Pound FineLeng ang Angstrom
GYD Guatemala Quetzal cm Centimeter
HKD Hong Kong Dollar dm Decimeter
HNL Honduras Lempira ft Foot
ITL Italian Lira in Inch
JPY Japanese Yen km Kilometer
MXN Mexican Peso m Meter
NOK Norwegian Krone mi Mile
PEN Peruvian New Sol mic Micron
Pence British Pence

Process Models B-7


Table B.3-1: Units of Measure (cont.) Table B.3-1: Units of Measure (cont.)
UOM Class Token Description UOM Class Token Description
mm Millimeter ppm Parts Per Million
mmic Millimicron ppb Parts Per Billion
yd Yard Mole lb-mol Pound-mole
Foul hr-ft2-F/BTU Hour-foot^2-F/BTU kg-mol Kilogram-mole
hr-m2-C/kcal Hour-meter^2-C/kcal g-mol Gram-mole
hr-m2-K/kJ Hour-meter^2-K/kJ tonm-mol Metric ton-mole
m2-K/kW Meter^2-Kelvin/kW oz-mol Ounce-mole
m2-K/W Meter^2-Kelvin/W ton-mol Short ton-mole
Frac fraction Fraction tonl-mol Long ton-mole
percent Percent MoleFrac fraction Fraction
ppb Parts Per Billion percent Percent
ppm Parts Per Million ppm Parts Per Million
Htco BTU/hr-ft2-F BTU/hour-foot^2-F ppb Parts Per Billion
kcal/hr-m2-K Kilocalorie/hour-m^2-K PetroMass API API gravity
kJ/hr-m2-K Kilojoule/hour-m^2-K spgr Specific gravity
kW/m2-K Kilowatt/meter^2-K lb Pound
W/m2-K Watt/meter^2-K kg Kilogram
KVis cST Centistoke tonm Metric ton
in/sec Inch/second g Gram
ST Stoke oz Ounce
Leng ang Angstrom ton Short ton
cm Centimeter tonl Long ton
dm Decimeter PowerTop BTU British Thermal Unit
ft Foot cal Calorie
in Inch CHU Centigrade Heat Unit
km Kilometer ft-lb Foot-pound
m Meter g-cm Gram-centimeter
mi Mile HP Horsepower
mic Micron J Joule
mm Millimeter kcal Kilocalorie
mmic Millimicron kg-m Kilogram-meter
yd Yard kJ Kilojoule
Mass g Gram kW Kilowatt
kg Kilogram kW-hr Kilowatt-hour
lb Pound PCU Pound Centigrade Unit
oz Ounce W Watt
ton Short ton Pres ata Technical atm (abs)
tonl Long ton ate Technical atm (gauge)
tonm Metric ton atm Atmosphere
MassFrac fraction Fraction bar Bar (abs)
percent Percent barg Bar (gauge)

B-8 Units of Measure


Table B.3-1: Units of Measure (cont.) Table B.3-1: Units of Measure (cont.)
UOM Class Token Description UOM Class Token Description
dyne/cm2 Dyne/centimeter^2 MPa Megapascal
Pres in H2O Inches of water PresDiff N/m2 Newton/meter^2
in Hg Inches of mercury Pa Pascal
kg/cm2 Kilogram/centimeter^2 psf Pound/foot^2
kPa Kilopascal psi Pound/inch^2
mm H2O Millimeters of water torr Torr
mmHg Millimeters of mercury Rotation rpd Rotations per day
MPa Megapascal rph Rotations per hour
N/m2 Newton/meter^2 rpm Rotations per minute
Pa Pascal rps Rotations per second
psf Pound/foot^2 Surf dyne/cm Dyne/centimeter
psia Pound/inch^2 (abs) g/cm Gram/centimeter
psig Pound/inch^2 (gauge) N/m Newton/meter
torr Torr PDL/in Poundal/inch
PresAbs ata Technical atm (abs) Temp C Celsius
atm Atmosphere F Fahrenheit
bar Bar (abs) K Kelvin
dyne/cm2 Dyne/centimeter^2 R Rankine
in H2O Inches of water TempAbs K Kelvin
in Hg Inches of mercury R Rankine
kg/cm2 Kilogram/centimeter^2 TempDiff C Celsius
kPa Kilopascal F Fahrenheit
mm H2O Millimeters of water K Kelvin
mmHg Millimeters of mercury R Rankine
MPa Megapascal Time sec Second
N/m2 Newton/meter^2 min Minute
Pa Pascal hr Hour
psf Pound/foot^2 day Day
psia Pound/inch^2 (abs) wk Week
torr Torr mon Month
PresDiff ata Technical atm (abs) yr Year
ate Technical atm (gauge) Torque lb-ft Pound-foot
atm Atmosphere N-m Newton-meter
bar Bar (abs) UA BTU/hr-F BTU/hour-F
dyne/cm2 Dyne/centimeter^2 kcal/hr-K Kilocalorie/hour-K
in H2O Inches of water kJ/hr-K Kilojoule/hour-K
in Hg Inches of mercury kW/K Kilowatt/K
kg/cm2 Kilogram/centimeter^2 W/K Watt/K
kPa Kilopascal VapVol cm3 Centimeter^3
mm H2O Millimeters of water dm3 Decimeter^3
mmHg Millimeters of mercury ft3 Foot^3

Process Models B-9


Table B.3-1: Units of Measure (cont.) Table B.3-1: Units of Measure (cont.)
UOM Class Token Description UOM Class Token Description
in3 Inch^3 POIS Poise
VapVol km3 Kilometer^3 Vol bbl API barrel
liter Liter cm3 Centimeter^3
m3 Meter^3 dm3 Decimeter^3
mi3 Mile^3 ft3 Foot^3
mm3 Millimeter^3 gal U.S. gallon
yd3 Yard^3 igal Imperial gallon
Visc CP Centipoise in3 Inch^3
kg/m-day Kilogram/meter-day km3 Kilometer^3
kg/m-hr Kilogram/meter-hour liter Liter
kg/m-min Kilogram/meter-minute m3 Meter^3
kg/m-sec Kilogram/meter-second mi3 Mile^3
lb/ft-day Pound/foot-day mm3 Millimeter^3
lb/ft-hr Pound/foot-hour yd3 Yard^3
lb/ft-min Pound/foot-minute VolFrac fraction Fraction
lb/ft-sec Pound/foot-second percent Percent
lb-sec/ft2 Pound-second/foot^2 ppb Parts Per Billion
Pa-sec Pascal-second ppm Parts Per Million

B-10 Units of Measure


Index

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...

Process Models I-1


Dim modelEvaluation() , 1-3, 5-31, 5-48, 5-56, 5-64,
See Properties, Real/Variable attributes... 5-70, 7-2
dimReport Function calls into the MILANO model
See Real/Variable attributes... overview of , 4-2
DisConnect() variableName.FX
See System functions See Variable attributes...
Display statement , 5-21 variableName.FXI
displayProperties() See Variable attributes...
See System functions
doUomTest , 5-74, 6-17
DOWN , 2-6 G
GDAW (General Data Access Window)
E See GUI
Generate...()
See Runtime methods
Equations, in custom reactor model
e_EBal , 5-13, 5-16, 5-30 GenerateReport()
See Methods accessible...
e_Flow , 5-13, 5-15
e_MBal , 5-13, 5-15 Get/get...()
See System functions
e_NetReaction , 5-13, 5-14
e_Pres , 5-13, 5-14 GetState()
See Methods accessible...
e_ReactionRate , 5-13, 5-14
e_refEnth , 5-30 Graphical User Interface (GUI) , 1-3, 5-8, 5-29
Unit DLL , 1-3
Equipment
UOM displayed in , B-1
defined , 2-6
On/Off/Down Status , 2-6 GROUP
Statement in icon data file , 7-16
EquipmentCopyI2L()
See System functions Group
See Properties
Exit routine
modelCleanUp() , 5-31
ExitProc
See Exit routine
H
External Equation Block
declaration , 7-2 hasProperty()
equations , 5-64 See System functions
variables , 5-64 Hidden
See Properties

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

Process Models I-2


Implicit MI_blockGetCount() , 4-3
See Properties MI_deleteMemory_domainGetAllElems() , 4-3,
Incidence matrix 5-39, 5-45
See sparsity patterns MI_deleteMemory_getStringInAtom() , 4-3
variableName.INDEPENDENT MI_deleteMemory_getStringValue() , 4-3, 5-39
See Variable attributes... MI_domainAddElem() , 4-4, 5-45
Initial Estimate Generation (IEG) , 2-15, 2-20 MI_domainDelElem() , 4-4, 5-45
Initialize() MI_domainGetAllElems() , 4-4, 5-45
See Methods accessible... MI_domainGetCount() , 4-4, 5-45
InitialValue MI_getAttr() , 4-5, 4-9, 5-45
See Properties MI_getFullName() , 4-2, 4-5, 5-45
Integer attributes in custom models MI_getIntegerInAtom() , 4-5, 5-44
intVal , 4-10 MI_getIntegerValue() , 4-6, 5-47, 5-49, 5-68, 5-71
Internal units , 2-16 MI_getModelHandleInAtom() , 4-5, 5-44
MI_getRealInAtom() , 4-5, 5-46
intVal
MI_getRealValue() , 4-6, 5-42, 5-66
See Integer attributes...
MI_getStringInAtom() , 4-5, 5-46
IsA()
MI_getStringValue() , 4-6, 5-66
See System functions
MI_isA() , 4-2, 4-6, 5-44
isAdiabatic , 5-5, 5-9, 6-16
MI_print() , 4-2, 4-6, 5-46
MI_runMethod() , 4-7, 5-36, 5-44
MI_setAttr() , 4-7, 5-46
K MI_setIntegerInAtom() , 4-8
MI_setIntegerValue() , 4-8, 5-42, 5-66
Keywords MI_setModelHandleInAtom() , 4-8
__stdcall , 6-10, 6-12 MI_setRealInAtom() , 4-8, 5-46
MI_setRealValue() , 4-8
MI_setStringInAtom() , 4-8
L MI_setStringValue() , 4-8
use of class MIUserAtom , 4-1
variableName.L Methods accessible from UserAddedProcessUnit
See Variable attributes... CheckDataForIEG() , 2-12
variableName.LO CheckDataForSolution() , 2-12
See Variable attributes... CheckStructure() , 2-12, 5-19
Log...Msg() Constructor() , 2-8, 5-39
See System functions Destructor() , 2-9, 5-39
GenerateReport() , 2-14, 5-24
GetState() , 2-13, 5-18
M Initialize() , 2-9, 5-16
Makeconsistent() , 2-10
PortStreamPair() , 2-10, 5-16
variableName. M
Predeletion() , 2-11
See Variable attributes...
Validate() , 2-13
MakeActive/Passive()
VerifyFeed() , 2-14
See System functions
MI_...()
Makeconsistent()
See Method calls to MILANO model
See Methods accessible...
MIAttributeNumbers.h , 4-9
MassBalChk , 5-21
Microsoft Visual C++ , 1-4, 6-8
MassBalChkTol , 5-9, 5-21, 6-16
MILANO
mcl.db
block , 2-3
See Model class library
Library Manager , 2-2
Method calls to MILANO model
model templates , 7-10

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

N Process model class


templates , 2-1
Process Model Framework (PMF) , 2-1
NonSparse
Process model templates
appearance in the GUI , 5-8
MIMOdoNothingTemplate , 2-2
See Properties
MISOdoNothingTemplate , 2-2
variableName.NS
SIMOdoNothingTemplate , 2-2
See Variable attributes...
SISOdoNothingTemplate , 2-2
Properties
DataType , 2-3
Dim , 2-3, 5-4, 5-7

Process Models I-4


Group , 2-2, 5-7 TotalEnergyInContribution() , 2-17, 5-26
Hidden , 5-4, 5-8 TotalEnergyOutContribution() , 2-17, 5-27
Implicit , 5-16 TotalMaterialInContribution() , 2-17, 5-14
InitialValue , 5-4, 5-7 TotalMaterialOutContribution() , 2-17, 5-14
NonSparse , 5-4, 5-8 UnBindStream() , 2-17
RowBased , 4-9 UpdateCompsChange() , 2-18
SubModel , 3-5, 5-11 UpdateLinks() , 2-16, 5-17, 5-36
UserOrdered , 5-4, 5-12 UpdatePropsChange() , 2-18
Property clause
syntax restrictions , 5-31, 7-2
Pseudocode S
for BBM C++ code , 5-32
for EEB C++ code , 5-57 Schema evolution , 7-7
Sections
Declarations , 5-7, 5-29, 5-54
R Events , 5-14, 5-31, 5-56
MathRelations , 5-14, 5-31, 5-56
Real attributes in custom models setProperty()
Basis , 4-10 See System functions
Dim , 4-10 Size and sparsity routine
dimReport , 4-10 modelSparsity() , 1-3, 5-31, 5-41, 5-56, 5-65, 7-2
realVal , 4-10 SizeSparsityProc
UOM , 4-10 See Size and sparsity routine
uomRealVal , 4-10 variableName.SM
uomReport , 4-10 See Variable attributes...
realVal Solver , 7-1
See Real attributes...
Sparsity patterns
Refinery inspection properties (RIP) , A-1 Black Box Model , 7-5
Refinery inspection property (RIP) External Equation Block , 7-6
points , A-2 Statements
RemoveLinks() ENDOUTLINE , 7-24
See Runtime methods GROUP , 7-16
ReportLevel ICON , 7-17
See Data members accessible... PLIN , 7-21
ROMeo Process Model (RPM) , 2-4 PORT , 7-21
RowBased shapeword , 7-18
See Properties shapeword DATA , 7-19
variableName.RT TEXT , 7-20
See Variable attributes... Stream
Runtime methods name as external name , 5-16
AddPropsAndFlows() , 2-14 On/Off Status , 2-6
AssignCompSlateToSubModel() , 2-14 String attributes in custom models
AssignPropSlateToSubModel() , 2-15 stringVal , 4-10
BindMoleFrac() , 5-17 String operations
BindStream() , 2-15 in Version 1.0 , 2-8
CalculateEnergyTerms() , 5-14, 5-26, 5-27 stringVal
GenerateEnergyBalanceReport() , 5-27 See String attributes...
GenerateEnergyBalanceReportSection() , 2-15 SubModel
GenerateEstimates() , 2-15 See Properties
GenerateMaterialBalanceReportSection() , 2-16 System functions
RemoveLinks() , 2-11, 2-16, 5-18, 5-36 AssignComponentSlate() , 2-18, 3-6, 5-20, 5-22

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

Process Models I-6


uomNS , 4-11 v_reactionRate , 5-9, 5-14, 5-15, 5-56
uomSM , 4-11 v_refEnth[] , 5-12, 5-56
uomUP , 4-11 v_refPres , 5-12
UP , 4-11 v_refTemp , 5-12
Variables VerifyFeed()
implicit , 3-5, 3-9 See Methods accessible...
model , 3-4
Variables, in custom reactor model
v_conversion , 5-8, 5-56 W
v_netReaction , 5-9, 5-14, 5-56
v_PressureDrop , 5-8, 5-56 White space , 1-5
v_Q , 5-9, 5-16, 5-56

I-7 Index

You might also like