Technical Reference
Technical Reference
Technical Reference
You may not copy, transmit, or translate all or any part of this document in any form or by any means, electronic
or mechanical, including photocopying, recording, or information storage and retrieval systems, for any purpose
other than your personal use without the prior and express written permission of Imagine That Inc.
The software described in this manual is furnished under a separate license and warranty agreement. The soft-
ware may be used or copied only in accordance with the terms of that agreement. Please note the following:
ExtendSim blocks and components (including but not limited to icons, dialogs, and block code)
are copyright © by Imagine That Inc. and/or its Licensors. ExtendSim blocks and components
contain proprietary and/or trademark information. If you build blocks, and you use all or any
portion of the blocks from the ExtendSim libraries in your blocks, or you include those
ExtendSim blocks (or any of the code from those blocks) in your libraries, your right to sell, give
away, or otherwise distribute your blocks and libraries is limited. In that case, you may only sell,
give, or distribute such a block or library if the recipient has a valid license for the ExtendSim
product from which you have derived your block(s) or block code. For more information,
contact Imagine That Inc.
Imagine That!, the Imagine That logo, ExtendSim, Extend, and ModL are either registered trademarks or
trademarks of Imagine That Incorporated in the United States and/or other countries. Mac OS is a registered
trademark of Apple Computer, Inc. Microsoft is a registered trademark and Windows is a trademark of Mic-
rosoft Corporation. GarageGames, Inc. is the copyright owner of the Torque Game Engine (TGE), and the
copyright for Stat::Fit® is owned by Geer Mountain Software. All other product names used in this manual
are the trademarks of their respective owners. TGE and Stat::Fit are licensed to Imagine That, Inc. for distri-
bution with ExtendSim. All other ExtendSim products and portions of products are copyright by Imagine
That Inc. All right, title and interest, including, without limitation, all copyrights in the Software shall at all
times remain the property of Imagine That Inc. or its Licensors.
Acknowledgments
Extend was created in 1987 by Bob Diamond; it was re-branded as ExtendSim in 2007.
Chief architects for ExtendSim 10: Steve Lamperti and Bob Diamond
Simulation Engineers: Anthony Nastasi, Cecile Pieper, Peter Tag, and Dave Krahl
Graphics, documentation, and editing: Kathi Hansen, Carla Sackett, and Pat Diamond
Imagine That Inc • 6830 Via Del Oro, Suite 230 • San Jose, CA 95119 USA
408.365.0305 • fax 408.629.1251 • [email protected]
www.ExtendSim.com
Table of Contents
TABLE OF CONTENTS
TECHNICAL OVERVIEW
Introduction ..............................................................................................................1
About the Technical Reference.......................................................................................2
Additional resources.......................................................................................................3
Parts of a Block.........................................................................................................5
The Example block.........................................................................................................6
The block’s user interface—its dialog............................................................................6
The block’s structure ......................................................................................................6
Overview of block parts, by tab and pane ......................................................................7
Icon tab ...........................................................................................................................9
Script tab.........................................................................................................................11
Dialog tab .......................................................................................................................13
Help tab ..........................................................................................................................14
Dialog items....................................................................................................................14
Connectors......................................................................................................................20
ModL Overview........................................................................................................25
ModL feature overview ..................................................................................................26
ModL compared to other programming languages ........................................................27
ModL language terminology ..........................................................................................30
Differences between equation blocks and programmed blocks .....................................31
Structure of a block’s ModL code ..................................................................................32
Accessing connectors from a block’s code ....................................................................34
Accessing dialog items from a block’s code ..................................................................35
Accessing code from other languages ............................................................................42
External source code.......................................................................................................42
TUTORIAL
Creating a Block .......................................................................................................43
Building a simple block that converts miles to feet .......................................................44
Adding user interaction and display features .................................................................48
Adding an intermediate results feature...........................................................................51
Adding 2D animation .....................................................................................................53
Other features you might have used ...............................................................................54
Defining functions ..........................................................................................................56
APPENDIX
Menu Command Numbers........................................................................................409
Upper Limits.............................................................................................................413
ASCII Table ..............................................................................................................417
Cross-Platform Considerations.................................................................................419
Libraries..........................................................................................................................420
Models ........................................................................................................................... 420
Menu and keyboard equivalents .................................................................................... 420
Menu and keyboard equivalents for developers ............................................................ 421
Transferring files between operating systems................................................................ 421
IPC or multi-server considerations ................................................................................ 423
Cross-platform code....................................................................................................... 424
INDEX
Technical Overview
Introduction
Where you learn where you need to begin
Overview
It presumes you have read the chapters in the Overview module.
• “Programming Tools” describes all the tools, such as include files and external source
code control, that ExtendSim provides to help you program efficiently; it starts on
page 81.
• “Programming Techniques” gives procedures and suggestions for programming using
ModL and for interfacing ExtendSim with other languages, such as VBA. That chapter
starts on page 91.
• “Animation Using ModL”, starting onpage 125, describes the ExtendSim 2D capabil-
ity and features.
• “Simulation Architecture” gives important information about how ExtendSim runs
simulations and how discrete event and discrete rate models and blocks work. The
chapter starts on page 157.
• “Debugging”, which begins on page 190, discusses model and code debugging and
shows how to use the ExtendSim source code debugger.
• Reference
Starting on page 210 are three chapters that list and discuss all of the ExtendSim variables,
messages, and functions.
• Appendices
• Appendix A: upper limit values for ExtendSim
• Appendix B: an ASCII table
• Appendix C: menu commands and numbers for the ExecuteMenuCommand function
• Appendix D: cross-platform (Windows and Macintosh) considerations
As you will see, programming blocks in ExtendSim is quite easy, especially if you have ever
programmed in any language.
Additional resources
Imagine That Inc. provides several resources to support your simulation experience.
1) Getting Started. The Getting Started model open when you launch ExtendSim. Use this
interface to explore sample models and to view tutorials on building and running models.
2) Online help:
• Access the electronic User Reference and Technical Reference by giving the command
Help > ExtendSim Help or press F1 on your keyboard.
• Use tooltips to identify interface elements.
• Get complete definition of how a block works, including descriptions of its dialog
items and connectors, by clicking a block’s Help button.
3) Web advice. FAQs are available at www.ExtendSim.com/support/advice/faq.html.
4) Networking. Links for ExtendSim user forums, networks, and blogs are at www.Extend-
Sim.com/support/advice/forum.html. For example, the ExtendSim E-Xchange is a user
4 Overview
Additional resources
forum for sharing ideas, insights, and modeling techniques with other ExtendSim users.
Use this forum to post issues and solutions, share blocks and models, and to talk directly to
Overview
other people developing simulations. You must register to join, but access is free and avail-
able to all ExtendSim modelers.
5) Complimentary support. Get technical assistance for installation issues, basic usage ques-
tions, and troubleshooting for up to 60 days after purchasing a new product or upgrade.
Parts of a Block
An introduction to the internals of a block
This chapter discusses a typical ExtendSim block’s internal structure—its icon, dialog, code,
and more.
Overview
☞ The Technical Reference assumes you know how to build models since many of the concepts
used when building blocks assume an understanding of how blocks are used in models.
The Example block
The Example block is a good source for investigating the dialog and internals of a block and
will be used throughout this chapter. It is a copy of the Simulation Variable block (Value
library) that ships with ExtendSim.
Any changes you make to a block in an ExtendSim library will affect that block in all existing
models and will get discarded whenever the library is updated. Thus, it is important that you
don’t make any changes to the blocks that are shipped with your ExtendSim product. Instead,
make a copy of the block and save it with a new name and in a new library, as was done
for this example.
Open a new model worksheet.
Open the Tutorial library located at ExtendSim/Documents/Libraries/Example Libraries.
From the Tutorial library’s library window, select the Example block and place it on the
model worksheet.
The block’s user interface—its dialog
Every block has a dialog, which may be as simple as just the OK and Cancel buttons or it may
be quite complex. A block’s dialog is its user interface—that is what modelers see when they
double-click the block’s icon.
Dialog of the Example block
Double-click the icon of the Exam-
ple block. This opens its dialog,
revealing two tabs:
• An Options tab dealing with
the system variables
• A Comments tab for user com-
ments
The frame, text, buttons, and entry
boxes that are seen in the tabs are col-
lectively known as dialog items.
In each block’s dialog, a Help button,
block label field, and View popup are
located at the bottom of the dialog and
to the left of the scroll bar, if there is one.
The block’s structure
A block’s internal structure is where the user-interface and block behavior is created and where
it’s icon, ModL code, dialog items, and other block components are defined. ExtendSim has
built-in editing tools for creating or modifying blocks.
Parts of a Block 7
Overview of block parts, by tab and pane
Overview
1) Select the block by clicking once on its icon in a model worksheet. Then choose Develop>
Open Block Structure.
2) Right-click the block’s icon in a model worksheet or in the library window. Then select
Open Block Structure.
3) Double-click the block’s icon on a model worksheet or the library window while holding
down the Alt (Windows) or Option (Mac OS) key.
Icon tab
The Icon tab is for creating the icon and everything else in its environment. The icon is the
visual representation of the block as seen in a model. Icons can display 2D animation and most
often have connectors that facilitate the exchange of data between blocks.
8 Overview
Overview of block parts, by tab and pane
Dialog tab
The Dialog tab is where the block’s dialog is created and, if wanted, tabs for grouping dialog
items. The dialog is the window that appears when you double-click a block’s icon.
Help tab
Connectors pane
This pane lists the names of the block’s connectors, if any. It is also used to edit the default
connector names so they can more closely represent their function. See “Editing connector
names” on page 22.
Parts of a Block 9
Icon tab
Overview
sent to the block code as a message when the dialog item is activated. By default, these names
are listed in order created; they can also be sorted alphabetically.
Icon tab
The Icon tab of the Example
block’s structure is shown at
right.
The area at the left of the
Icon tab is used to enter and
edit the icon(s) for the block
and to add animation
objects, block connectors,
and icon views.
The Example block’s icon
has one input connector on
the left of its icon and two
animation objects, numbered
1 and 2.
☞ The panes on the right of the
Icon tab are for Connectors
and Dialog Item Names as discussed on page 8.
Icon
A block’s icon is its most obvious aspect since it appears on the model worksheet. An icon
consists of a drawing or group of drawn objects, the block’s connectors, and possibly one or
more animation objects.
A block can have more than one icon; which one is shown is determined by which view is
selected, as discussed in “Icon views” on page 9.
There are two ways to create an icon:
1) With the ExtendSim drawing tools, as discussed in the User Reference. The Shapes and
Alignment tools provide a drawing environment for quickly creating icons.
2) By pasting drawings from the Clipboard. You can use a painting or drawing program to
create an icon. Then copy and paste it into the Icon tab.
Use the same tools for selecting objects in the icon pane as you would use to select graphic
objects in the model worksheet or notebook.
Icon views
The Icon views popup is located at the
top of the Icon tab. Each block has at
least one icon, which is its default. It is
also possible for blocks to display dif-
ferent icons. For example, a block
could have a Forward view icon and a
different icon with a Reverse view. Or
10 Overview
Icon tab
the block could show a different icon depending on the type of machine it represents or based
on a selection in the block’s dialog. ExtendSim accomplishes this by facilitating the creation of
Overview
The block’s ModL code interacts with animation objects, causing them to show various behav-
iors. Depending on how the objects are coded, the display could change due to user interaction
Overview
with the block (its dialog or connectors) and/or due to information received during the simula-
tion run. For the Example block, the animation object for the Example displays as text which
system variable has been selected in the block’s dialog.
There are several ways to animate a block using 2D animation objects:
• Typically, the block’s icon would be animated but it is also possible to animate outside the
icon’s footprint.
• Blocks can: show, hide, and change the colors of text and shapes; move a shape and increase
or decrease its size; show a changing level; show a picture or a movie; or move a picture
along connection lines between two blocks.
The Item and Rate libraries use 2D animation extensively.
For more information about 2D animation
• The ExtendSim User Reference gives an overview of 2D animation, including block-to-
block animation that flows along the connections in discrete event models.
• In this Technical Reference, the tutorial “Adding 2D animation” on page 53 shows how to
add 2D animation objects to a custom block.
• The section “2D animation” on page 126 has a lot more information about programming 2D
animation effects.
• ExtendSim has many functions that facilitate customizing animation depending on which
icon views are being selected by the modeler. See the functions for “Icon views” on
page 330.
Script tab
12 Overview
Script tab
he Script tab of the Example block looks like the screenshot above. This tab is used to enter
and edit the block’s ModL code and comments. ModL is the internal programming language
Overview
for ExtendSim.
Unlike the other block parts, which can be seen by the modeler, ModL code can only be
accessed through a block’s structure window or in an equation-based block’s editor window.
☞ As shown on page 78 there is a Script dialog in the Edit > Options menu that is used to specify
characteristics for a block structure’s Script tab. For example, you can change the colors of
user functions or keywords. When the block’s Script tab is the active window, use Alt + O to
open the Script dialog.
ModL code
If you know a programming language, you will probably recognize the structure of the ModL
code. ModL is essentially C++ with some enhancements and extensions to make it more robust
for simulation modeling.
☞ When you build blocks using ModL, the block’s program is compiled to native machine code.
Layout
After the copyright and modification history information, the first lines are the declaration of
the types of variables used in the code. Following is the code which is grouped into sections,
where each section is either a message handler or a function. Lines that begin with “//”, “**”,
or “/*” are comments.
For more information about the ModL language
• “ModL Overview” on page 25
• A tutorial starting on page 44
• “The ModL Language” on page 59
Functions
This popup lists the message handlers (in all caps) and functions used in the block.
Selecting something from the list causes the code to scroll to the section that uses the function
or message handler. It also opens the include file if the function or message handler is used in
an include.
For more information
• “Messages and Message Handlers” on page 213
• “ModL Functions” on page 225.
Includes
Lists and opens the include files that are used in the code. Include files are standard header
files that are put in ModL code and can contain ModL commands such as definitions, assign-
ments, and functions. The purpose of an include file is to simplify maintenance when several
blocks use similar variable definitions and functions. Include files are discussed on page 81.
Parts of a Block 13
Dialog tab
Dialog tab
Overview
The Dialog tab for the Example block’s structure looks like the screenshot shown here.
Dialog items
The buttons, parameter fields, check boxes, and so forth that comprise a block’s dialog are
known as dialog items.
☞ For a complete list and description of dialog items, see page 14.
Tabs
The block’s Dialog tab has two tabs at the top—Options and Comments.
Tabs in a dialog are used to group dialog items by function. When you create or modify a
block’s dialog you can:
• Add tabs to the dialog by clicking the + sign
• Add dialog items to a tab after bringing the tab to the front
• Rename a tab by double-clicking its name and choosing a new name in the window that
appears
• Delete a tab by clicking its close button, the X next to its name
• Move dialog items from one tab to another using the Cut, Copy, and Paste commands
Be careful when deleting a tab with dialog items on it. See the caution on page 18 about delet-
ing dialog items from blocks that are used in models.
Dialog Resizer
Since they usually have different numbers and types of dialog items, a block’s tabs are often
different sizes. The Dialog Resizer allows you to position the right and bottom edges of each
tab separately. This determines what is visible for each tab when it becomes the active window.
14 Overview
Help tab
Use the keyboard’s arrow keys, or drag the bottom right corner of the resizer, to set the default
size for each tab. ModL functions can also be used to set or reset the size of each tab in the dia-
Overview
log.
☞ The arrow keys can be used to change the position of the resizer’s bottom right corner.
Help tab
This tab is used to enter and edit the online Help for the block. This text appears when you
click the Help button in the lower left corner of a block’s dialog and is about the block and how
it can be used in a model. It is not available through the ExtendSim Help menu command,
which provides help for using the ExtendSim application.
You can add formatting to the text by selecting it and using the buttons in the Text toolbar.
☞ By default the block’s name and the first sentence of the text in the Help tab is displayed as a
tooltip when the cursor is hovered over the block. You can choose that just the block name, but
not the Help text, be displayed. To do this, turn off the “Include additional block information”
option in the Edit > Options > Model tab.
Dialog items
The frames, text, buttons, tables, and entry boxes that go into a dialog are collectively known
as dialog items. Dialog items are created on the Dialog tab using buttons from the Dialog Items
toolbar, shown below. Each dialog item is then configured or defined using options in its Prop-
erties window.
☞ See “Accessing dialog items from a block’s code” on page 35 for how dialog items are called in
ModL.
Overview
Radio Round buttons that appear in groups where each group has a 37
Button unique group number. Only one button in the group can be
selected at a time; this causes all the other buttons in the group
to become deselected. Radio buttons can have labels that
appear as text to their right; the labels can be changed using
ModL code.
Frame Used to group dialog items. Has an optional label that will 40
appear at the top of the frame. Does not require a dialog item
name. This dialog item can have its text label formatted.
Static Text Text that appears as a label in the dialog. Can be changed 39
(Label) through ModL code but not by the modeler. Can be formatted.
Dynamic Entry box that takes or displays text. Limited to 32,000 charac- 36
Text ters. This item uses an automatically resized dynamic array to
store the text. It is useful for larger amounts of text such as for
comments or for equations in the Equation and Optimizer
blocks.
Editable Entry box that takes or displays text. Limited to 255 characters. 36
Text Users can dynamically link editable text to a cell in an Extend-
Sim database or global array instead of just entering data.
Editable Same as Editable Text, above, but limited to 31 characters to 36
Text 31 save memory.
Data Table A two-dimensional table with scrollbars and adjustable column 38
widths (similar to a spreadsheet) for holding numbers. If block
code provides for it, modelers can change the number of rows
and columns and can dynamically link tables to an ExtendSim
database or global array. Can have its text label formatted.
Text Table A two-dimensional table with scrollbars and adjustable column 38
widths (similar to a spreadsheet) for holding text. If block code
provides for it, modelers can change the number of rows and
columns and can dynamically link tables to an ExtendSim data-
base or global array. The text can be formatted.
The Text Table uses a significant amount of memory and
searching strings is slower than searching data. If possible,
use the Data Table dialog item instead, especially if the
table is large.
Slider A control that allows you to select from a range of values by 41
moving a value indicator. You can manually drag the knob to
change a value or use ModL code to move the knob to show a
value.
Meter An output-only item that shows a needle in a meter. 41
Switch A switch that resembles a light switch. It has two values, 0 (off) 41
and 1 (on).
Calendar Takes an ExtendSim date value and displays it on a calendar. 42
16 Overview
Dialog items
Each properties window displays the properties of the selected dialog item. For the Add dialog
item, the information is:
• The dialog item is of the type Static Text; its button in the Dialog Items toolbar is shown to
the right of its type
• The variable name, for use in the script, is Static_Text8_lbl
• The dialog item’s dimensions and position in the dialog are given
• Its zOrder is 0
• The text label that appears in the dialog is Add
• The label is visible on this dialog tab, but not visible on all the block’s dialog tabs
Parts of a Block 17
Dialog items
Overview
are available for all dialog items.
☞ In addition to the options in the properties window, some dialog items can have their text or
labels stylized or aligned as discussed in “Stylizing and aligning dialog items” on page 19.
Option Description
Type A dialog item’s type (static text, frame, etc) is determined by which dia-
log item you choose from the Dialog Items toolbar and cannot be
changed through the properties window. Dialog item types are listed on
page 14.
Name A dialog item’s Name is the variable name or message name used by the
block’s code to interact with that item in the dialog, as discussed in
“Accessing dialog items from a block’s code” on page 35. As of Extend-
Sim 10 names are required for all dialog items; default names are entered
by the system for frames and static text. The name:
1) Must start with a letter
2) Cannot contain any non-alphanumeric characters
3) Can be up to 31 characters in length
X,Y,W,H By default, the fields (X, Y, W, and H) reflect the size and position of
dialog items as they are created. Their size and position can also be
adjusted after the dialog item created.
zOrder zOrder is the forward/backward position of dialog items. It's what is
effected by the Bring to Front and Send to Back buttons in the Alignment
toolbar. The zOrder numeric value gives programmers complete control
over the dialog item.
Format Parameters only. The number formats are: General, 2 decimal places,
Integer, Scientific, and Percent.
Fill Color Colors the text label. Works the same as the Fill Color tool in the Shapes
toolbar. For dialog items with multiple labels (such as the Popup Menu)
the selected color will be applied to all the labels.
☞ ModL code allows more control over dialog item appearance. For
example, use the SetDialogItemColor function to set a color, and
other functions to change the color or border depending on model
circumstances. See “Dialog items” on page 305.
Border Color Works the same as the Border Color tool in the Shapes toolbar. See
above note.
Label Dialog items have optional text labels. These can be up to 255 characters
in length. If defined, labels are displayed as part of or along with the dia-
log item in the block’s dialog. For example, the text that appears to the
right of a checkbox is a label. For tables, labels are used to name the col-
umns.
☞ If a dialog item has a label that will be displayed in the block’s dia-
log, that label can sometimes be formatted using standard charac-
ters. See “Stylizing and aligning dialog items” on page 19.
18 Overview
Dialog items
Option Description
Overview
DI ID Upon creation, each dialog item is assigned a unique ID. Some functions
use this identification number in addition to the Name, to control the
item.
Tab Number Determines which dialog tab the dialog item is on. For dialog items that
are set to be visible on all tabs, the Tab Number is -1. For other items, the
numbering starts with 0, indicating the first tab.
Tab Order Many dialog items have a tab order number. This determines the order
dialog items will be selected when modelers tab between entry boxes on
the dialog. When the tab order is changed for one dialog item, the tab
order for the other dialog items is automatically adjusted.
Be careful when changing the tab order of dialog items. If the block
is used in a model, changing a dialog item’s tab order can cause the
block’s cloned dialog items to become confused. In this case the clone
will present itself with multiple question marks; it must be deleted and
replaced.
Rows/Columns/Row Text Tables and Data Tables only. These numbers are for the body rows
Height and columns only; headers will be added automatically.
Visible By default dialog items are visible in the tab in which they are created.
(See below for making a dialog item visible in all tabs.) Unchecking this
option provides a safe alternative to deleting a dialog item when you no
longer want it in an existing block.
Deleting a dialog item from a block that is used in a model could dis-
rupt the order of the data in the dialog. The data will have to be reen-
tered for each instance of that block in all models that use it. Instead
of deleting the dialog item, hide it by unchecking the Visible option.
When the Visible option is unselected, the item will not appear in the dia-
log of the block in the model. It will, however, show in the Dialog tab as
a red rectangle without text. Hidden dialog items can be moved in the
Dialog tab. You can also revert a hidden dialog item by opening its prop-
erties and selecting the Visible option.
☞ You can also temporarily hide and show dialog items using the Hide-
DialogItem function; it is described in the dialog item function list
that starts on page 305. Also consider using the DIMoveTo and
DIMoveBy functions to move dialog items out of the way depend-
ing on dialog settings.
Visible in all tabs If a dialog has tabs, this option will cause the dialog item to appear on
every tab. This is common for static text that describes the purpose of the
block as well as the OK and Cancel buttons. For dialog items that are
visible in all tabs, their Tab Number (discussed above) is -1.
Parts of a Block 19
Dialog items
Option Description
Overview
Display only Under normal circumstances, many dialog items are editable or respond
to clicks in the dialog. Checking the Display only option means that a
modeler can’t change the dialog item, or that a click will be ignored, in
the block’s dialog. Instead, it can only be set through ModL code.
This option is typically used to display results or to temporarily or per-
manently disable a dialog item depending on settings in the block.
In a block structure’s Dialog tab, display-only
items have a gray outer border instead of the
standard black border; this is shown at right.
They also appear as dimmed in the block’s dia-
log. Display-only dialog items can still be cop-
ied and cloned
☞ Using ModL functions, the state of any dialog item can be dynami-
cally changed between editable and not editable.
Add to right click Buttons only. Cause the block’s Button dialog items to appear in a menu when
menu a block on the model worksheet is right-clicked. These commands can then be
executed without having to open the block’s dialog to click the button.
☞There are also functions that can control many dialog item properties. See “Dialog items” on
page 305.
Stylizing and aligning dialog items
In addition to the above property options, numbers, and colors, some dialog items can have the
style (and sometimes the alignment) of their text labels formatted in their Properties windows.
Dialog items that support stylizing and/or alignment
• Data tables
• Frames
• Popup menus
• Static text
• Text tables
Available formats
As indicated below, formatting is not case sensitive.
STYLE ALIGNMENT
Bold: <B> or <b> Left: <L> or <l>
Italicized: <I> or <i> Right: <R> or <r>
Underlined: <U> or <u> Centered: <C> or <c>
☞ For dialog items with multiple labels (such as popup menus or tables) set styles separately for
each label.
20 Overview
Connectors
Connector types
The first six buttons in the Icon toolbar are for selecting the type of connector.
• The ExtendSim User Reference describes the use of the first five connectors: value, item,
flow, universal, and array.
• The user-defined (or “diamond”) connector does not have any “special” properties, and is
provided for your convenience for custom applications. For example, if you design a new set
of blocks and want to be sure that modelers only connect those blocks to each other, you
Parts of a Block 21
Connectors
would use this connector. If the modeler tries to connect a diamond connector to a value or
item connector, ExtendSim will not let them.
Overview
☞ By default new connectors are added to the icon as a normal (single/non-variable) connectors.
They can be changed to variable connectors (arrays of single connectors) using the connector
option tools, below.
Connector options
After the connectors, the next six buttons in the Icon toolbar are options for causing a connec-
tor to be variable rather than normal. While normal connectors represent one input or output,
variable connectors act like a row of single connectors, where the row can be expanded or con-
tracted to provide a required number of inputs or outputs.
The first five choices allow you to select, respectively, a variable connector that the modeler
can expand downward, to the right, upward, or to the left, or which cannot be manually
expanded or contracted (variable connector with no resize bar).
The sixth choice converts a variable connector into a normal connector. Use this if you selected
a variable connector by mistake.
In the block’s code, you can specify a maximum and minimum number of variable connectors
and change the number of connectors dynamically. An example of using normal and variable
connectors is the Math block (Value library). To work with variable connectors, see the writeup
on page 35 and the functions on page 303.
☞ Regardless of connector type (Value, Item, etc.), each connector can be normal or variable
depending on the option selected in the Icon toolbar. However, the entire row of a variable con-
nector must be of only one type of connector.
Animation object
The last button in the Icon toolbar is the Animation Object button. This is used to add 2D ani-
mation objects to a block’s icon environment as discussed in “2D animation” on page 10 and
“Adding 2D animation” on page 53.
Connector names
By default each connector is assigned a unique name which can be changed. The last part of a
connector name defines whether it is an input or output connector.
Connector names are shown in the Connectors pane of a block’s structure.
For example, the name of the connector for the Example block is as shown
at right. This block has one normal (non variable) value output connector
named VariableOut.
When you add connectors to the icon, they are all initially input connectors.
To make one of these connectors an output connector, change its name to
something that ends with “Out.
Rules for connector names
• Connector names are not case sensitive
• The name must start with a letter
• The name cannot contain any non-alphanumeric characters or spaces
• The name must be fewer than 32 characters in length
• Input connectors must end in some form of the word “In” (IN, in, In, iN)
22 Overview
Connectors
• Output connectors must end in some form of the word “Out” (OUT, out, Out, ouT, etc)
Overview
Connector tooltips
Tooltips can display custom text when the mouse hovers over a connector. This is helpful to
Overview
show additional information about the connector (including its value during the simulation)
and what it can be used for. See “Connector tool tips” on page 305 and the Equation block
(Value library).
For more information about connectors see:
• “Accessing connectors from a block’s code” on page 34
• “Working with connectors” on page 100
• “Block connectors and connection information” on page 299
24 Overview
Connectors
Overview
Overview
ModL Overview
Creating ModL code and dialogs for custom blocks
This chapter and the others that follow will teach you how to create new blocks, modify exist-
ing blocks, or call functions from equation-type blocks such as the Equation and Optimizer
Overview
blocks (Value library) and the Equation(I) and Queue Equation blocks (Item library).
☞ These chapters only describe creating standard blocks, not hierarchical blocks. Hierarchical
blocks contain ExtendSim blocks and are created through the user interface, without program-
ming, as described in the User Reference.
As you saw in the preceding chapter, there are many parts of a block, the most complex of
which is the ModL code. This chapter shows how a block’s code is laid out and the basic ways
that ModL code lets blocks interact with other blocks, with their own dialogs, and with the
general parameters of a simulation.
☞ This overview of the ModL language is a prelude to, and should be read before, the “The ModL
Language” reference chapter that starts on page 59.
ModL feature overview
As you will see, ModL is very much like C, although it is not as complicated and not case sen-
sitive. ModL also has some enhancements that will help you create block code:
• Block code is organized as message handlers and function definitions, rather than just func-
tion definitions. Message handlers and functions can be overridden (e.g. if they are from
include files) and can have local variables.
• The names of connectors and dialog items are treated as static variables that can be read or
set from within message handlers or functions. The dialog and connector changes take effect
immediately.
• Blocks can query, control, and send messages to other blocks, even if they are not connected.
• Blocks can have icon views facilitating the direction of model flow.
• The ModL language has several string data types. Strings can be up to 255 characters and
can be concatenated (strung together) with the + (plus) operator.
• ModL has subscript checking, causing the code to abort if you try to access an element
beyond the size of an array.
• There are over 1,200 ModL functions for performing general and simulation-specific tasks.
In addition, there are many global variables that can be accessed from ModL code as well as
some predefined constants.
• Including 2D animation in a block is easy. You do not need to do any graphics in your block
code. Instead, you can position animation objects on the icon and use animation functions to
show pictures or text within the objects.
• You can use multi-dimensional arrays (with up to five sets of dimensions). Arrays can be
passed to blocks or functions as entire arrays or as individual elements. ModL arrays can be
fixed (specified size) or dynamic (one dimension undeclared). You can use dynamic arrays to
hold values when you do not know how many elements will be needed.
• You can create ExtendSim databases, linked lists, and global arrays that are useful as in-
memory data repositories. You can also use ExtendSim blocks or code to access external
spreadsheets and ADO and ODBC compatible databases.
• ModL allows for efficient connectivity with other languages, so you can make use of other
features and technologies.
ModL Overview 27
ModL compared to other programming languages
• ExtendSim has an internal source code editor (with code completion, syntax colorization,
and more) as well as a source code debugger.
Overview
• An external source code feature allows multiple people to efficiently and effectively work on
the code of blocks at the same time.
ModL compared to other programming languages
An ExtendSim block’s code is written in ModL, a programming language that is much like C
or C++ that has been enhanced for simulation purposes.
☞ DLLs and Shared Libraries provide a method for incorporating other technologies, such as
Visual Basic, Java, or Visual C++, into ExtendSim. For more information, see “DLLs” on
page 86.
If you code, and if you don’t
• If you have some familiarity with C or C++: Although ModL is specialized for simulation, it
uses many concepts from C++ and you can certainly program in ModL. Note that you do not
need to know much C/C++ in order to be completely comfortable in ModL. The table that
starts on page 27 lists major differences between ModL and C++.
• If you program in a language other than C/C++: ModL should not present much of a chal-
lenge. You can use your programming knowledge to program using ModL or write DLLs in
other languages and call them from within ExtendSim code. The table that starts on page 29
compares common constructs for ModL and for some other common languages.
• If you do not program: You can still use the equation-based blocks, make some modifica-
tions to existing blocks, and build simple blocks without programming experience.
☞ Whether you know programming or not, the equation-based blocks provide access to ModL
functions and variables. This is useful for accomplishing specialized tasks without having to
program a block. The equation-based blocks are listed in the User Reference.
ModL compared to C++
There are only a few differences between ModL and C++. They are:
ModL C++
case insensitive case sensitive
real or double (Mac OS and Windows: 16 significant digits) double
integer or long (32 bit) long
string or Str255 (255 characters maximum) typedef struct Str255
{
unsigned char length;
unsigned char str[255];
} Str255;
28 Overview
ModL compared to other programming languages
ModL C++
Overview
ModL C++
Overview
#define, #include, #ifdef, #ifndef, #else, #endif can be used as Macro definition is allowed in
preprocessor directives to conditionally compile code if a sym- addition to preprocessor direc-
bol of any type is defined (e.g. constant, variable, connector, tives.
function, etc.). There is no macro definition.
do do { do 10 x = x+i;
{ x = x+i; x = x+i i = i+1;
x = x+i; i = i+1; i = i+1 if (i .LT. 10) goto
i = i+1; }while (i < 10); loop while i < 10 10
}
while (i < 10);
//comments //comments rem comments ! comments
** comments ' comments
/* enclose multi-line /* enclose multi-line comments (NOTE: only to end (NOTE: only to
comments like this like this */ of current line) end of current line)
*/
strng = strng+"abc"; strng = strng+"abc"; strng = strng&"abc" strng = strng // 'abc'
strng = x; strng = double.toString(x); strng = Str(x) depends on imple-
mentation
if (strng < "abc") if (strng.compareTo("abc") < 0) if strng <"abc" if (strng .LT. 'abc')
... { then then
... ... ...
Term Description
array An indexed list of numbers or strings, with indices starting at 0 (zero).
Arrays can be fixed or dynamic. Dynamic arrays are static and cannot be locally
declared. Fixed arrays can be declared as static or local.
constant Value that does not change.
data type The type of storage used for the data: real, integer, string, pointertype
E notation or Exponential number specified as a number raised to a power of 10. For example,
scientific nota- “6.3E3” means 6,300 and “5E-1” means 0.5.
tion
function Predefined named group of code instructions with specified arguments that may
return a value (void functions don’t return a value) and can be called in a block’s
code. Can be overridden by defining the function in an include file which can
then be overridden in the block’s code.
global variables Variables that are used to pass information between blocks. They are predefined
by ExtendSim and can be viewed or modified by any block or equation. These
variables’ values are preserved between simulation runs and are saved with the
model. See “Scope of global, local, and static variables” on page 62 for more
information regarding the scope of those variables.
identifier Name that is entered.
ModL Overview 31
Differences between equation blocks and programmed blocks
Term Description
Overview
literal Number or string that is entered as a constant.
local variable Variable that is locally declared and is valid only within the message handler or
user-defined function in which it is defined. Note that these are temporary vari-
ables and their values are not preserved after exiting a message handler or func-
tion. See “Scope of global, local, and static variables” on page 62 for more
information.
Do not give local and static variables the same name; local variables with
the same names as static variables override the static variables.
message han- Grouping of code that tells ExtendSim what to do in a particular circumstance
dler that is defined by the message. Can be overridden.
statement Section of code ending with “;”.
static variables Variable that is valid throughout the block’s code in which it is defined. The val-
ues for these variables are preserved and are stored with the model when it is
saved. See “Scope of global, local, and static variables” on page 62 for more
information.
Use caution when deleting static variables for blocks already used in mod-
els. It has the same harmful effect as deleting dialog items (discussed in the
section on “Hiding/showing dialog items” on page 95).
system variable Provide information about the state of the simulation. Like global variables, sys-
tem variables are valid in any block in a model, are declared by ExtendSim, and
can be viewed or modified by any block or equation.
type declara- Defining a variable as a certain data type: real, integer, string, or pointertype.
tion
☞ Include files used with equations are normally saved in the same location as the model using
them; this makes it easy to move both the model and the includes it uses to a different location.
Include files used in block code should be saved in the Extensions/Includes folder.
Structure of a block’s ModL code
ModL is essentially C++ with enhancements and extensions to make it more robust for simula-
tion modeling.
Layout of the code
Like C programs, a block’s code starts with data type declarations and constant definitions
(see page 33). Because you declare these at the beginning of the code, before any message han-
dlers or user-defined functions, they are considered static or permanent variables. Unless over-
ridden by a local variable declaration, static variables are valid throughout the block’s code.
However, their scope does not extend outside of that block’s code. Global variables are pre-
defined and have a global scope, making them valid in every block.
☞ For more information about the scope of variables, see “Scope of global, local, and static vari-
ables” on page 62 for more information.
After the type declarations, there are function (and void function) definitions and many mes-
sage handlers (see page 33). This is where you write code and define the behavior of the block.
The functions and message handlers are just definitions; they need to be called in order to be
executed. They can also be overridden by re-declaring any number of times below the first
declaration.
• Message handlers begin with a line “on messageName” and tell ExtendSim what to do in
various circumstances; they are usually executed by the application. For example, a message
handler in every block begins with “on Simulate” and the code within the message handler
starts and ends with curly braces (“{“ and “}”).
ModL Overview 33
Structure of a block’s ModL code
• Functions are of the form “type functionName(type argument, ...)” or “void function-
Name(type argument, ...)” depending on whether they return a value. Functions are called
Overview
within message handlers or from other parts of the block’s code.
When you type the first letters of ModL functions in the Script tab, code completion pops up a
window so you can get the correct spelling and arguments. As code is written, syntax coloring
gives visual cues about its structure.
Like C, ModL ignores blank lines and indentation. Of course, it is a good idea to indent code
with Tab characters and use comments. Single line comments are preceded by “//” or “**”.
Multi-line comments start with a “/*” and end with a “*/”.
Data types
There are four main data types in ModL:
Constants
Constant declarations can be of data type real, integer, or string, but not pointertype. The gen-
eral form for a constant definition is:
CONSTANT id IS literal;
ModL includes four general-purpose predefined constants: Pi, Blank, True, and False. For
more information, see page 62.
Constants are not directly supported in equation-based blocks; use an include or set the value
from a Constant block (Value library).
Functions, message handlers, and local variables
ModL code has functions and message handlers that group the code into sections.
• Functions are procedures that do calculations and can be called from different points in the
code. Functions can return a value; void functions do not return a value.
• Message handlers interpret messages that come from the simulation, from another block, or
from user interaction with a block’s dialog. Message handlers begin with a line “on mes-
sageName”, where messageName is the name of the message. ExtendSim runs the message
handler whenever one of the messages is passed to the block.
• Local variables are variables that are declared in message handlers and user-defined func-
tions. Their scope is just the message handler or function in which they are declared.
Message handlers cannot be declared in equation-based blocks; instead call SendMsgToB-
lock(). See the table onpage 31 for additional differences when using equation blocks.
Message handler structure
Message handlers are denoted by:
34 Overview
Accessing connectors from a block’s code
on messagename
{
Overview
Overview
connector can be changed to a normal output connector by adding “Out” to the end of its name.
• To read from an input connector, use its name in the right side of a statement. For instance,
read from an input connector called “firstConIn” with:
myNumber = firstConIn;
• To set the value of an output connector, assign it a value. For example, to set the value of an
output connector called “totalOut”, use:
if (myNumber > 0)
totalOut = 1.0;
Variable connectors
Each variable connector is actually a row of single connectors where the row expands and con-
tracts. This allows the developer and modeler to control how many connectors are displayed
for a particular purpose. They are described in the User Reference.
☞ See “Adding connectors to the icon” on page 22 for the steps required to change the default
(normal) connector into a variable connector.
Accessing a variable connector from code
• Use the function ConArrayGetValue to read from a variable input connector. Note that input
connector indexes start at 0.
• To set the value of an variable output connector, use the function ConArraySetValue. Note
that output connector indexes start at 0.
As of ExtendSim 10 names are required for all dialog items. The system supplies a default
name for static text and frames; it can be changed following the rules given in “Options in the
Overview
Dynamic text items can be accessed directly via the string dynamic array assigned to the
dynamic text item or using the dynamic text functions (see “Dynamic text items” on page 320).
Overview
For an example of using dynamic text items, see the Equation block (Value library).
To declare the string dynamic array:
string aStringDynamicArray[]; // the dynamic array declaration
....
To set up the dynamic text item in the CreateBlock message handler:
myDynamicTextItem = DynamicTextArrayNumber(aStringDynamicArray);
To directly access the text:
first255Characters = aStringDynamicArray[0];
The example above shows a dynamic text dialog item attached to a string array. Dynamic text
dialog items can be attached to arrays of any size string.
Use the dynamic text functions to find and replace text. See “Dynamic text items” on
page 320.
Checkboxes and radio buttons
Checkbox and radio button dialog items return true/false values: true if the checkbox or radio
button is selected, false if not. They also send their dialog item name (as a message name) to
the block’s code when they are clicked. The code could have an “On DialogItemName” mes-
sage handler to process the message. The dialog item name could also be used as a variable to
query or set the dialog item’s value.
For example, if a block represents a teller in a
bank, instead of entering a number you could
use radio buttons to set the teller’s speed. The
dialog might look like the one shown at the
right.
The five radio buttons would have the dialog
names VSlow, Slow, Med, Fast, and VFast. To
make sure that only one of them can be
selected at a time, they must all have the same
Radio Group ID when they are defined. In this
example, the group ID was left at the default
(group 0).
To set the variable “theDelay” based on which
button was chosen, the code uses the state-
ments:
if (VSlow)theDelay = initDelay * 1.25; // v slow is 1.25 normal
if (Slow) theDelay = initDelay * 1.1;// slow is 1.1 of normal
if (Med) theDelay = initDelay * 1.0;// medium is 1 of normal
if (Fast) theDelay = initDelay * 0.91;// fast is 0.91 of normal
if (VFast)theDelay = initDelay * 0.8;// v fast is 0.8 of normal
The “if” statements are executed only if that button value is True (non-zero); of course, only
one of them can be true because they are all in the same radio button group. You could also
structure the checking with five message handlers, such as:
38 Overview
Accessing dialog items from a block’s code
The following code fragment shows how to read and write to a data table named “dataTable”
that has 4 rows and 3 columns. Data tables are treated as arrays, which are discussed in detail
Overview
in “Arrays, pointers, queues, delay, linked list, and string lookup table functions” on page 376.
As in the C language, array subscripts start at 0, not 1.
. . .
// Read the first row, second column cell into myValue.
myValue = dataTable[0][1];
. . .
// Set the fourth row, third column cell to myValue
dataTable[3][2] = myValue;
Data tables can be attached to dynamic arrays. They can also have variable columns and the
behavior of the columns can be extensively customized. For more information, see the descrip-
tion and functions in “Block data tables” on page 312 and “Formatting/interactivity using col-
umn and parameter tags” on page 321.
The text table allows you to type in text, numbers, or both. Since all entries are strings, to use
the numbers in ModL code you must first convert them to real values using the StrToReal
function.
The headers for data tables and text tables can be styled and aligned, as discussed in “Stylizing
and aligning dialog items” on page 19.
Static text (label)
Static text appears in a dialog as a label and is non-editable by the modeler. The system assigns
default names to static text; the names can be changed by the block developer according to the
rules given in “Options in the dialog item’s properties window” on page 17. Names can be
used in the ModL code to change the text label, show and hide it, and so forth.
☞ The changed text label is not stored in the block. Thus the read value of static text is always
what was originally entered when the dialog item was defined, even if it is changed by setting
it to a different text value in the code. If you use the dialog item name in an equation, you will
always get the text that was entered when the dialog item was created.
If you change the text of a label, your code must set the text when the modeler opens the block.
Do this using the On DialogOpen message handler.
on DialogOpen
{
myLabel = "desired text"; // set it every time the dialog opens
}
See also “Changing text in response to a user’s action” on page 94.
Popup menu items
When an item in a popup menu is selected, the menu’s dialog item name returns a value which
is the integer corresponding to the position of the item in the menu, where 1 is the value for the
first item in the list. For example, in a 5-item menu, the values of its dialog item name will be
set to 1, 2, 3, 4, or 5 based on which menu item the modeler chooses.
☞ For historical reasons, popup menu indexes start at 1, not 0.
40 Overview
Accessing dialog items from a block’s code
Switch
A switch looks like a standard light switch.
Overview
When you click on the side that is not down, it makes a small clicking sound,
changes to the other value, and sends a message to the ModL code.
The switch dialog name always returns either 0 (off) or 1 (on), depending on the value of the
switch. You can also control the switch by setting its variable name to 0 or 1 in the code.
Slider
A slider allows you to enter a value by dragging its knob along its length.
The minimum and maximum values can be set from ModL code; the modeler can
change the minimum and maximum values by clicking and editing them in the
block’s dialog. The current value can be set from the code and can also be set as the
model runs by dragging the slider up or down. In this way, you can use the slider
both for visual output and for input.
The slider is represented in a three-element array of reals that represent the minimum, maxi-
mum, and current values. Thus, if a slider is called “theSlider,” it could be initialized with the
lines:
theSlider[0]=0.0; // Minimum of 0
theSlider[1]=10.0; // Maximum of 10
theSlider[2]=3.33; // Starting value of 3.33
As the model runs, the value of the slider can be checked by reading the third array element:
theSetting = theSlider[2];
Meter
A meter allows you to view a value on a meter.
You set the minimum, maximum, and current values from the ModL code.
The meter is represented in a three-element array of reals that represent the mini-
mum, maximum, and current values. Thus, if your meter is called “theMeter,” you
might initialize it with the lines:
theMeter[0] = 0.0; // Minimum of 0
theMeter[1] = 30.0; // Maximum of 30
theMeter[2] = 10.0; // Starting value of 10
As the model runs, you can set the value shown on the meter in the third array element, such
as:
theMeter[2] = theSetting;
Calendar
The Calendar dialog item takes an ExtendSim date value (discussed
Overview
Creating a Block
Learn how to build an ExtendSim block
and save it in a library
This chapter shows how to create a continuous block and have it perform some tasks. So you
have something to compare to, the final block, called “Miles”, is located in the Custom Blocks
library which is located in the folder ExtendSim/Documents/Libraries/Example Libraries.
Building a simple block that converts miles to feet
For this first section, the Miles block will have two value connectors, an input and an output.
The block will look at the value of the input connector (the number of miles), multiply it by
5280 (the number of feet in a mile), and copy the result to the output connector.
Create the block
Tutorial
To be consistent with the ExtendSim style guide, set X: 10, Y: 16, Width: 220, Height: 16.
(Alternatively you could resize and position the dialog item on the Dialog tab.)
In case you will add more tabs, check the box so that this text label will be Visible in all
tabs.
In the Label field, enter <b>Converts miles to
another length. (As discussed on “Stylizing
and aligning dialog items” on page 19, enter-
ing “<b>” in front of the text formats it as
Tutorial
bold; this style will appear once the block is
compiled.)
Leave the rest of the options as is and click
OK to close the properties window
With those coordinates, the label will be placed in the upper left corner of the Dialog tab. It
should now look like the screenshot here.
Save the block
It’s a good idea to save the block as you make changes to it. Since there isn’t any code in this
block yet, you should save it without compiling.
Choose File > Save Block
This saves the structure of the block without compiling the code. Alterna-
tively, you could close the structure window and, in the window that appears,
choose to Save Without Compiling.
☞ In the library window, uncompiled blocks are displayed with their names in red italics.
Icon tab
The Icon tab is for creating an icon and adding connectors.
Go to the structure window’s Icon tab
The Icon tab has a default icon
Icon and text
For the icon you could use the ExtendSim drawing environment or a painting program, or copy
clip art and paste it in. For this tutorial, just keep the default icon and add text.
Double-click on the Icon tab worksheet to create a text box:
Enter the text Miles->???
With the text selected, use the Bold command in the toolbar to
make the text bold and the Fill Color button in the Shapes toolbar
to make the text red
Position the text on top of the icon.
As needed, resize the icon and text using their resize buttons
The icon should now look similar to the one shown above.
46 Tutorial
Building a simple block that converts miles to feet
Connectors
The Miles block needs two value connectors, an input and an output. As discussed on page 20,
connectors can be either normal (a single connector) or variable (a row of single connectors).
The default is that connectors are normal, and that is what is required for the Miles block.
Adding connectors
If the Icon tool is not already open, choose the command Tools > Icon.
In the Icon toolbar select the Value connector, the first one in the list.
Click near the left side of the icon to add that value input connector. Notice that the name of
Tutorial
user functions or keywords. When the block’s Script tab is the active window, use Alt + O to
open the Script dialog.
Go to the structure window’s Script tab
As seen at the right, the Script tab is empty except
for a comment (“ModL code goes here”) and
three message handlers: Simulate, CheckData,
and InitSim.
These message handlers get automatically added
Tutorial
because most of the blocks you create will use
these messages and unused message are ignored.
For this block, the action happens in the Simulate message handler.The other default message
handlers can be left blank since there is nothing to check or initialize at the beginning of the
simulation run.
Below the opening bracket that follows the Simulate message, type: UnitsOut = MilesIn *
5280.0;
so that the code looks as follows:
on Simulate
{
UnitsOut = MilesIn * 5280.0;
}
☞ The spaces on each side of the operators are optional; the semicolon at the end of the state-
ment is not optional.
The code means that for each step of the simulation, ExtendSim reads the value at the input
connector, multiplies it by the real value 5280.0, and sets the output connector to that product.
Save and compile the block
After the code has been
entered:
Close the structure
window by clicking its
close box or giving the
command File > Close.
ExtendSim opens a
dialog for saving changes, seen at right. Click Save, Compile if Needed. This compiles the
ModL code and saves the changes to the block in the library.
If there are any compilation errors, ExtendSim will warn you.
☞ While not done for this block, the blocks you create can also be assigned categories, as
described on page 55.
Test the block
To test the Miles block:
Open a new model window if one is not already open.
If the model opens with an Executive block, delete the Executive block, since this isn’t a
discrete event simulation.
48 Tutorial
Adding user interaction and display features
Dialog tab
The enhanced Miles dialog will have a popup menu for choosing a unit to convert to, parame-
ter fields for obtaining an input from the user and for displaying results, and a frame for orga-
nizing the dialog items.
Create a popup menu
Open the structure window for the Miles block, using one of the methods listed in “How to
open a block’s internal structure” on page 7.
Go to the block’s Dialog tab
If the Dialog Items toolbar isn’t already open, open it from the Tools menu
Click in the Dialog Items toolbar to select a Popup Menu and place it on the Dialog tab
Define the popup menu
Double-click the Popup Menu to open its prop-
erties and configure it as below:
Name: units_pop
X: 24
Y: 70
Width: 76
Height: 16
Label: Kilometers;Yards;Feet;Inches
Creating a Block 49
Adding user interaction and display features
Tutorial
In its properties window, enter:
Label: Convert miles to:
It is not necessary to change the dialog item name or any other properties for the frame.
The Dialog tab should now look like the one shown above.
Save the dialog changes
Give the command File > Save Block to save your work
☞ This is a quick way to save changes without closing the block’s structure.
Add two parameter fields
To add entry and reporting fields for the numbers:
In the Dialog Items toolbar:
Click once to select the Parameter dialog item, but then...
While holding down the Alt key, click twice on the Dialog tab to create two parameter
fields
Press the escape key to stop placing parameters on the Dialog tab
Move the parameter fields so that they are at the same
horizontal position and below the frame
☞ To create multiple instances of a dialog item, hold the Alt or Option key down while repeatedly
clicking on the Dialog tab; then use the Escape key to finish. Alternatively, once you’ve placed
one parameter on the Dialog tab, you could use the Edit > Duplicate command to add copies of
dialog items to the Dialog tab, or just get the dialog item from the Dialog Items toolbar again.
Configure the parameter fields
In the properties window for the leftmost parameter:
Enter Name: InNum_prm
Set the width to 60 and the height to 16.
Click OK to close the properties window.
In the properties window for the parameter on the right:
Enter Name: OutNum_prm and click OK to close its properties window
Set the width to 60 and the height to 16.
50 Tutorial
Adding user interaction and display features
Select the Display only choice. This will cause the parameter value to be displayed in
the block’s dialog without being editable.
Click OK to close its properties window.
Adding more static text labels
The next step is to define two more Static Text dialog
items.
For the first static text item:
Tutorial
Tutorial
UnitsOut = MilesIn * 1.609344;
else if (units_pop == UNITS_YARDS)
UnitsOut = MilesIn * 1760.0;
else if (units_pop == UNITS_FEET)
UnitsOut = MilesIn * 5280.0;
else if (units_pop == UNITS_INCHES)
UnitsOut = MilesIn * 63360.0;
OutNum_prm = UnitsOut;
}
Notice that “units_pop” is the name of the popup menu defined on page 48. Also notice that if
“Yards” is selected in the block’s dialog, the statement “if (units_pop == UNITS_KILOME-
TERS)” evaluates false and its “else” clause is executed. The “if (units_pop == UNITS_-
YARDS)” statement then evaluates true and executes its statement, and the “else” clauses
following it will not be executed.
☞ The numbers multiplied by MilesIn can be reals or integers. ModL performs all necessary type
conversions automatically. However, since connectors are always of type real, you should use
reals for values that are used with connectors. That way, ExtendSim will not need to convert
integers to reals on each step. (For more information about type conversions, see page 64.)
Save and compile the block
After you have finished writing the code, close the block by clicking its close box. Choose
Save, compile if needed to compile the new ModL code and save the block in the library.
Test the Miles block as you did before, trying all the conversions. Notice that you can keep the
Miles dialog open during the test.
Adding an intermediate results feature
You may have noticed something missing from the Miles block: what if you just want to con-
vert a single number without running a whole simulation? As stated earlier, ExtendSim passes
dialog messages to a block even if a simulation is not running. It is thus easy to make this block
useful even outside of a simulation.
52 Tutorial
Adding an intermediate results feature
Adding 2D animation
The icon of this block indicates that it converts miles to something, but that’s not very informa-
tive. Displaying text on an icon is a convenient method to show block conditions – in this case,
what kind of conversion the block is performing.
☞ The ModL code will ensure that the animated text is displayed even if the modeler doesn’t have
Show 2D Animation selected; the display is also independent of the simulation run.
Change the icon and add the animation object
As discussed in “2D animation” on page 10, the Animation Object tool is used to add
Tutorial
animation to icons. This tool is the last one in the Icon toolbar, shown below.
}
else if(units_pop == UNITS_FEET)
{
AnimationTextTransparent(1, "Feet");
AnimationShow(1);
}
else if(units_pop == UNITS_INCHES)
Tutorial
{
AnimationTextTransparent(1, "Inches");
AnimationShow(1);
}
}
The ModL compiler will give an error message if code containing “smart quotes” is copied into
the Code pane. To fix the problem, replace the copied quotes with new ones in the Code pane.
Createblock message handler
Replace the code in the “On CreateBlock” message handler to initialize the animation text.
// feet is the default setting
on CreateBlock
{
units_pop = UNITS_FEET;
AnimationTextTransparent(1, "Feet");
AnimationShow(1);
}
Close the block’s internal structure, saving and compiling the changes.
☞ Notice that the text will show only when a new Miles block is placed on the model worksheet.
Testing the block
To test this new functionality:
When you place a new Miles block in a model, the default setting (Feet)
should be displayed on its icon. Icon with animation
Changing the selected radio button in the block’s dialog should cause a
corresponding change on the icon.
The final Miles block is located in the ExtendSim/Libraries / Example Libraries / Custom
Blocks library. See below for additional features to consider when building custom blocks.
☞ Animation objects can be layered on top of each other, then called in block code to appear or
not depending on circumstances. Use each animation object’s zOrder to place it in the layer
you want. For more information, see “Creating 2D animation objects” on page 127.
Other features you might have used
The preceding example showed how to build a simple block. This section describes some addi-
tional ExtendSim features that could have been used when building this block.
Creating a Block 55
Other features you might have used
Tutorial
Add to right-click menu Cause the block’s Button dialog items to appear when 17
a block is right-clicked
Dialog item tooltips Tooltips display dialog item names without having to 20
open the block’s dialog
Hiding/showing dialog items Use code to dynamically hide and show dialog items 95
based on model conditions
Icon views Multiple icons per block; user selectable 9
Variable connectors They act like a row of normal (single) connectors 21
Connector labels Tooltips display connector information such as results. 22
Connector tooltips Display custom text through tooltips 23
Column tags Put strings, checkboxes, buttons, dates, popup menus, 321
the infinity character, and so forth into a parameter
field or the cell of a data table
Programming tools Code completion, include files, debugger, conditional 78
compilation, and more
DLLs and Shared Libraries A legacy of code, or programming capabilities that are 86
outside of ModL’s range, can be accessed using DLLs 88
(for Windows) or Shared Libraries (on the Macintosh)
External source code control Saves the source code of blocks as external files so 83
multiple developers can work on it
For example, the Math block (Value library) performs basic math functions; therefore, its block
category is Math. ExtendSim uses the block category in two places: 1) to organize blocks
within the Library menu, and 2) to organize blocks within reports. Categories of blocks in
libraries and reports are discussed in the User Reference.
To set or edit a block’s category:
With the block’s structure window open,
select the command Develop > Set Block
Category.
Tutorial
On Simulate
{
InNum_prm = MilesIn;
Creating a Block 57
Defining functions
UnitsOut = CalculateOutput(MilesIn);
}
Tutorial
58 Tutorial
Defining functions
Tutorial
Integrated Development
Environment (IDE)
IIDE
ModL strings are not accessed in the same way as strings in C++. To access the contents of a
ModL string beyond assigning its contents, you need to use ModL functions.
☞ ModL strings are internally stored as Pascal style strings, with a leading size byte. In most
cases you will not have to worry about the internal storage of the string. However, it does
become relevant when you pass a string to outside code through a DLL function call. In that
case, the ModL functions DLLPtoCString and DLLCtoPString will be useful - see the function
list that starts on page 265.
Pointertype data types
This data type contains the address of data that is held in dynamic arrays and compiled equa-
tions. A pointertype can be stored in a real, which means that you can store pointertypes in a
real type array or in an ExtendSim database for use by the model.
Declaration examples
For the real/double and integer/long data types, the identifiers are interchangeable. The type
declarations and constant definitions are set up like they are in C.
Some typical type declarations might be:
real nextTime;
real dataArray[], averages[10], theMatrix[10][10];
str15 str15Array[];
str31 str31Array[];
string strArray[], errorStrings[6], theError;
integer checkUsed, multiArray [][3][5][10][2];
pointertype p;
As you can see from the example above, ModL has fixed and resizable (dynamic) arrays, and
arrays can be up to five dimensions.
ModL already has some pre-defined variables that can be treated just like other static variables.
These system variables are described in the “ModL Variables” chapter that starts on page 210.
☞ Each variable type consumes a different amount of data, with integers using 4 bytes, reals using
8 bytes, strings using 256 bytes, and pointertypes using 8 bytes. At the same time, there is a
limit on the total amount of static data that can be declared. Thus if you define a string array as
string x[200] (which uses 200x256 or 51,200 bytes of memory), it will exceed the local or
62 IDE
Scope of global, local, and static variables
static data limit of 32,767 bytes (not including dynamic arrays and pointertypes) and the com-
piler will report an error condition.
Scope of global, local, and static variables
Variables define memory that can store a value or values. There are several types of ModL
variables.
Whether a variable is global, static, or local defines what is known as its scope. The scope of a
variable determines where it can be accessed by code. The following information is important
to keep in mind when using variables in block code.
• Global variables are pre-defined in the IDE. A global variable’s scope is the entire model. In
a model, a global variable can be referenced from within any block’s code or within equa-
tion-based blocks.
• The scope of a static variable (a variable declared at the top of a block’s code) or dialog item
variable (the name of a dialog item) is the code of that specific block. This means that a
block’s static variable cannot be used directly in the code of other blocks or in the equations
used in equation-based blocks.
IDE
• A local variable’s scope is just the message handler or user-defined function in which it is
declared.
IIDE
Constants that are pre-defined
ModL includes four numerical predefined constants:
PI = 3.14159265358;
BLANK = (noValue);
TRUE = 1;
FALSE = 0;
Setting a dialog parameter to BLANK will make it display as an empty field. BLANK values
show nothing in a dialog’s text field and are NoValues for all math calculations.
☞ Do not compare the constant BLANK with a value to determine if the value is BLANK (that is,
NoValue). The result will always be FALSE. Use the NoValue function instead. This function
returns a TRUE if the value passed to it is a NoValue.
There are other predefined constants that are specific to functions, such as the color constants
used with the Animation functions.
BLANK and NoValue
The constant BLANK is a special value that represents “no value”. A NoValue can only be rep-
resented by a real variable, not an integer. Technically, it is not a number and appears in a dia-
log as a blank item. To make a variable a NoValue, assign BLANK to it (a = BLANK).
If a number and a NoValue are added, multiplied, divided or subtracted, the answer is always a
NoValue. Thus, if any of the values in any equation is a NoValue, the result will always be a
NoValue.
If a real value is divided by 0, the answer is a NoValue; the square root of a negative number is
also a NoValue. In fact, any operation on numbers that causes an undefined result or an infinity
produces a NoValue answer which can be tested with the NoValue function listed in the section
“Basic math” on page 227.
☞ To test for a NoValue, do not compare it to BLANK in an “if” statement. Instead, always use
the NoValue function:
if (myValue == BLANK) // WRONG! THIS WILL NOT WORK!
NoValues can cause unexpected problems when converting reals to integers. It is a good idea
to screen for NoValues before converting reals to integers, as discussed in “Numeric type con-
version”, below.
Numeric type conversion
Generally, ModL performs all type conversion automatically. Thus, integer values can be
assigned to reals, and mixed-type arithmetic can be performed without explicit type conversion
beforehand.
☞ Because conversions are computer intensive, it is best to avoid numerical type conversions.
This is particularly true whenever there are repeated or often-used calculations.
ModL converts the arguments of function calls to the type needed by the function. For exam-
ple:
a = cos(integer);
Because the cosine function expects the argument to be a real value, the integer is converted
to a real value before the function is called.
IDE
Real to integer
Like all programming languages, converting from real numbers to integers in ModL is not
always exact. If a real number is also an integer, it will be exactly converted. Otherwise, the
conversion will cause the fractional value (mantissa) to be truncated. Thus, 0.001*1000.0 may
not equal 1 (the integer value), but may equal 0.99999... When this number is converted to an
integer, the answer is 0, not 1.
☞ In an operation between an integer and a real, the result is always a real.
NoValue to integer
As described above, setting a real value into an integer variable has a consistent result, namely
the truncation of the real value. This is true in all cases except where the real variable contains
a BLANK, or NoValue, value.
☞ If a real contains a BLANK or NoValue value, the NoValue will be too large to fit into an inte-
ger. Thus the integer will contain a meaningless value which could cause problems in calcula-
tions.
The best method for dealing with this potential problem is to screen the real values for NoVal-
ues before assigning them to the integer variable. The following code is an example of how to
do this.
Real realV;
integer intV;
if (NoValue(realV))
intV = 0; // Can’t convert NoValue to integer
// Meaningless result
else
intV = realV; // Can convert real to integer
Integer to real
There is no loss of information or special concerns when converting an integer to a real num-
ber.
The ModL Language 65
Arrays
However, using integer constants for real expressions is dangerous and can give the wrong
results.
For example, consider the following code:
z = 1/2*a;
In this case, z will always equal 0. The integer 1 divided by the integer 2 equals 0 because the
result of integer operations cannot be a fraction; it must be an integer. The statement should be
instead written as:
z = 1.0/2.0*a;
IIDE
anOutputString = "The answer is " + aRealNum + ".";
Remember that array subscripts start at 0 and end at 1 less than the number of elements in the
declaration (that is, there are n elements in 0 to n-1).
Fixed and dynamic arrays
ModL has both fixed and dynamic arrays.
Fixed arrays have specified sizes that cannot be changed in the code. The leftmost dimension
of dynamic arrays are variable in size and can be assigned a size or resized without changing
existing data. Dynamic array size is limited to two billion elements, and you can declare up to
254 dynamic arrays per block. Dynamic arrays can be passed between blocks or used globally.
See “Passing arrays” on page 102.
Dynamic arrays are declared in the same manner as fixed arrays, except that their first dimen-
sion value is missing. For example:
REAL MyArray[ ][4];
defines a two-dimensional dynamic array of real numbers. There is a varying number of rows
and exactly four columns (indexed 0 through 3).
IDE
Dynamic arrays must be static variables, not local ones. Thus, you cannot declare a dynamic
array variable in a message handler. However, you can resize dynamic arrays inside of a mes-
sage handler or in a user-defined function.
There are several functions for sizing dynamic arrays:
Function Use
DisposeArray Frees memory when you are finished with the array
DynamicDataTableVariableColumns Causes the right dimension to be variable. This is only useful for
data tables.
GetDimension Returns the size of the missing left dimension
GetDimensionByName Returns the size of the missing left dimension based on the block
number and the name of the array
GetDimensionColumns Returns the number of columns in a two dimensional array
GetDimensionColumnsByName Returns the number of columns in the two dimensional array,
based on the block number and the name of the array
MakeArray Sets the size of the missing left dimension
MakeArray2 Sets the size of the missing left dimension for an array in any
block, including a block other than the one calling the code. It
allows resizing of dynamic arrays passed in to functions as a string
name.
The GetDimension function can be used with any array, not just dynamic arrays. GetDimen-
sion returns the value of the first (leftmost) dimension, whereas GetDimensionColumns
returns the value of the rightmost dimension in a two dimensional array.
These functions are described fully in “Dynamic and non-dynamic arrays” on page 376. Also
see “Variable column data tables” and “Dynamic data table resizing” on page 313.
The ModL Language 67
Array-like structures
IIDE
array segment as an argument. An array segment is an array with fewer dimensions than the
full array. Array segmenting can only be done by specifying the leftmost dimensions, not the
rightmost dimensions. For example, assume that you had the following declarations:
real x[2], y[2];
real z[50][2];
To pass the fifth row of z (which contains two elements), to a function such as AddC (which
only wants an array of one dimension), you would use:
AddC(x, y, z[4]);
Array-like structures
Global arrays
There is another kind of array that can be set up using functions and is useful for data needed
globally throughout the model. Global arrays provide a repository for model-specific data.
Global arrays are dynamic arrays that, like global variables, can be accessed by any block in
the model. However, they differ from global variables in the following ways:
• Global arrays are accessed and managed through a suite of functions.
• You create and dispose global arrays as they are needed. There is no limit to how many
global arrays can be associated with a given model.
See “Using passed arrays to make structures” on page 105 for an example of using global
arrays to make structures. The global array functions start on page 378.
Linked lists
ModL has a suite of functions to support a linked list data structure. A linked list is an internal
data structure that allows the construction and manipulation of complex lists of data. These
queue-like, multiple type structures maintain internal pointers between the different elements,
speeding movement of elements (sorting) around within the list.
• Each structure element can simultaneously contain any number of integer, real, and string
data types, allowing the creation of complex sorted structures.
68 IDE
Operators
• They are faster than their linear equivalent if their internal sorting functionality is taken
advantage of, as in a Queue block (Item library).
• They are owned by individual blocks but can be accessed globally from any block.
See “Linked lists” on page 385 for a suite of functions. See the queue blocks in the Item library
or the blocks in the Rate library for examples of using linked lists.
Database tables
ExtendSim database tables are array-like structures. For more information about the Extend-
Sim database see “Working with databases” on page 111. The list of database functions starts
on page 354.
Operators
ModL offers a full set of mathematical and logical operators, as shown below.
Assignment operators
IDE
Operator Description
Math operators
Operator Description
The + operator is used both to add numeric values and to concatenate strings. For example:
The ModL Language 69
Operators
IIDE
AND or && Boolean (logical) combination
OR or || Boolean (logical) conjunction
NOT or ! Boolean (logical) inverse
!= or <> Magnitude not equal to
< Magnitude less than
<= Magnitude less than or equal to
> Magnitude greater than
>= Magnitude greater than or equal to
== Magnitude equal to
The three standard Boolean operators are not bit-wise logical operators, but only operate on
TRUE or FALSE expression values.
The standard magnitude operators return a Boolean value (1 for true and 0 for false) after com-
paring their arguments.
Operators in an expression are generally evaluated from left to right; however there is a hierar-
chy of precedence among the operators. The following list is in descending order of prece-
dence; within each group, operators have equal precedence.
☞ Putting any expression in parentheses ensures that it will always be evaluated first.
1) ( )
2) - (negation)
3) NOT or !
4) ^
5) MOD or %, *, /
6) + (addition and concatenation), -
7) <, >, <=, >=, = =, <> or !=
8) OR or ||, AND or &&
70 IDE
Control statements and loops
Statement Use
Abort Abort;
Break Break;
Continue Continue;
Do-While Do
STATEMENT;
While (boolean); // Note semicolon
For For (init_assignment; boolean; incr_assignment)
STATEMENT;
IDE
{
statement;
statement;
...
} // Note no semicolon here
Use the If statement for boolean comparisons such as
if (total < 0)
{
isNegative = TRUE;
findings = abs(total);
}
...
You can also use the If-Else construct if you have two paths to choose from:
if (total < 0)
{
IIDE
isNegative = TRUE;
findings = 100 + total;
}
else
findings = 100 - total;
...
The FOR construct lets you set the initial value, continuing boolean condition, and action to
take on each step in the parentheses. For example:
for (i = 0; i <10; i++)
a[i] = i;
will set a[0] to 0, a[1] to 1, and so on up to a[9].
The While loop repeats the statement while the expression is true; the expression is evaluated
at the beginning of the loop. Thus,
x = 3;
y = 3;
while (y<3)
{
x++;
y++;
}
would leave x and y set to 3 because the loop is never executed.
The Do-While construct tests at the end of the loop, so
x = 3;
y = 3;
do
{
x++;
y++;
}
while (y<3);
would leave x and y set to 4 because the test occurs at the end of the loop, after x and y have
already been incremented.
72 IDE
User-defined functions
The Switch statement is used to check values against integer constants and act on those cases.
Note that the integers in the CASE statement must be constants, not variables. For instance,
switch (numberOfRepeats)
{
case 0:
UserError("You didn't run it.");
wasOK = FALSE;
break;
case 1:
UserError("Thank you, it ran once.");
wasOK = TRUE;
break;
default: // any other number
UserError("You ran it more than once; please stop.");
wasOK = FALSE;
break;
}
The GoTo syntax is supported only within a message handler or user-defined function. Control
IDE
TYPE (or VOID) name (TYPE id, TYPE id,…, TYPE id) // zero or more
arguments
{
optional local variable declarations
Return(value);
}
In these definitions, VOID is a function that does not return any value and TYPE and VOID
can be integer, real or string. All arguments are optional. Arrays may be passed as arguments.
User-defined functions can be recursive, that is, they can call themselves.
Limitations
• Unless they are declared in include files, user-defined functions are local to the blocks in
which they are defined. To make one or more user-defined functions available for use by
IIDE
multiple blocks, create an include file as discussed in “Include files” on page 81.
• User-defined functions are not directly supported in equation-based blocks; they must be
declared in an include file. See the other limitations of equation blocks on page 31.
Defining
User-defined functions must be defined before they are used since the ModL compiler needs to
know the types of the arguments for type conversion. (Type conversions are discussed on
page 63.)
If you define a function that calls another user-defined function, both cannot be defined first.
The solution is to have a declaration of the function before it is actually called in the ModL
code:
TYPE (or VOID) name (TYPE id, TYPE id,…, TYPE id); //Note the ";"
This is called a forward declaration and tells ModL the types of the function and arguments,
and that the function will be defined later. The form is exactly the same as a function defini-
tion, but instead of braces, it ends in a semicolon.
Exiting
Exit a user-defined function at any point with a Return statement for Void type, Return(value)
for other types, or the Abort statement (see Abort, above).
For example:
real MyCalc(real x1, real x2)
{
real sum; // declare a temp variable
If Abort is called in a function that was otherwise going to return a value, the code is halted
completely and the return value is no longer necessary. That is, the code execution does not
return to the calling routine, so the return value of the function is moot.
Overriding user-defined functions
User-defined functions can be overridden by being re-declared any number of times below the
first declaration. In this case, the code that is executed is the final version of the routine. In the
code pane, the earlier versions of the routine will be colored brown to show that they have been
overridden.
Overriding is useful in that include files can have basic forms of functions and message han-
dlers which can be re-declared and overridden in the main block code. See “Include files” on
page 81.
Declaring arrays as arguments for user-defined functions
This section shows how to create a function that has arrays as arguments.
If the array size is not fixed, you can declare arrays as arguments to functions with the first
IDE
(leftmost) dimension blank; additional dimensions must have a value. This allows you to pass
either kind of array (fixed or dynamic) and any length of array to a user-defined function.
The following is an example of functions that add all of the elements of the rows in a variable-
sized array and return the sum.
real rowSum(real x[])
{
integer length, i; // Temporary variables
real sum;
return(sum);
}
on Simulate
{
real valuesArray[36], mySum;
...
mySum = rowSum(valuesArray);
...
}
Message handlers
Message handlers group code into sections. They interpret messages that come from the simu-
lation, from another block, or from user interaction with a block’s dialog. While messages can
originate either from the ExtendSim application or from blocks, it is always a block that is on
the receiving end of a message.
ExtendSim runs the message handler whenever one of the messages is passed to the block
The format of a message handler is:
on MessageName
{
zero or more declarations and/or statements;
}
MessageName must be the name of one of the messages listed in the chapter “Messages and
Message Handlers”. The code of the message handler is contained between the curly braces
(“{” and “}”) and tells ExtendSim what to do in the specific circumstance. To exit from a mes-
IIDE
sage handler before the ending brace, use a Return statement or an Abort statement, as
described above.
When you create a block, you can add message handlers that are executed at defined times,
such as when the dialog for the block is opened (so you can initialize the dialog’s contents),
when the simulation is stopped, when a dialog button was clicked, or when the block gets a
message from another block. No matter what happens, there is a message handler available to
perform an action.
Message handler example
The statements in the body of the message handler are in the same format as C functions. For
example, a simple message handler is:
on CreateBlock // The modeler added this block to a model worksheet
{
checkUsed = 1; // Static variable declared at top of the code
myNumber = 1; //Initial setting for dialog item
}
The statements in this message handler are executed when the block is added to the model
worksheet and thus receives the “CreateBlock” message from the ExtendSim application.
The variable “checkUsed” is a static variable for the block, defined at the top of the code. The
variable “myNumber” is the name of a parameter dialog item in the block’s dialog. This state-
ment initializes the parameter to 1 when the block is created (placed in the model).
Messages and message handlers are not supported in equation-based blocks. See the table on
page 31 for additional differences when using equation blocks.
Overriding message handlers
Message handlers can be overridden by being re-declared any number of times below the first
declaration. In this case, the code that is executed is the final version of the message handler. In
the block’s Script tab the earlier versions of the message handler will be colored brown to show
that they have been overridden.
Overriding is useful in that include files can have basic forms of functions and message han-
dlers which can be re-declared and overridden in the main block code. See “Include files” on
page 81.
76 IDE
System variables
You can declare local variables at the beginning of a message handler. However, you should not
have a global and a local variable with the same name. The local variable is temporary and
loses its value when the message handler is exited. Also, within each message handler, local
variables can override static variables. (If a local variable is defined with the same name as a
static variable, any references to that name within that routine or message handler will change
or reference the local variable, and the static variable will not be modified.)
For more information about message handlers, see:
• “Using message handlers” on page 109
• The list of message handlers starting on page 214
System variables
System variables give you information about the state of the simulation. You can read or write
to these variables, but you should be careful when writing to any of them.
The list of system variables starts on page 210.
Global variables
IDE
Programming Tools
Features and capabilities you can use
as you program in ModL
Writing ModL code takes much of the same talents as writing C/C++ programs. However,
ExtendSim provides tools to help make writing block code easier and safer, as discussed in this
chapter.
Script Editor
ExtendSim has an internal, integrated script (source code) editor for creating and debugging
source code.
Syntax styling
Syntax styling gives visual cues about the structure and state of a block’s code, making it easier
to follow the logic.
See the command Edit > Options > Script tab for the following:
• Colorization by syntax, as
shown to the right. The
colors can be customized
using the Change button.
IDE
• Show indentation guides. This option is selected by default in the Edit > Options > Script
tab. It causes vertical lines to be shown in the Script tab’s margin, indicating the tab indenta-
tion of the code. This is useful for seeing if you’ve indented the code correctly, especially for
long indented sections of code.
• Code folding. Click on a code folding marker in the Script tab’s left margin to selectively
hide and display sections of the code.
• Auto indentation. Entering a return at the end of a line takes you to the same indentation
level right below that line. Tab or backspace to change the indentation as wanted.
• Line numbers. Each line in the code is automatically assigned a number in the left margin of
the Script tab. Use the Go To Line button in the Script tab (or the menu command Develop >
Go To Line) to find a specified line.
IDE
code completion speeds up the coding process.
When you type the first letters for a ModL function
or message handler in the block’s Script tab, code
completion pops up a window with a list of func-
tions that start with those letters. Scroll through the
list and double-click to select the desired function.
Once the function has been placed in the script,
type an open parenthesis “(” immediately follow-
ing it. This causes the parenthesis to turn red and
call tips to display the function’s arguments as
shown here. The first argument will be bolded.
When you enter it, the parenthesis will turn black. As you enter each argument, subsequent
arguments get bolded until all are entered.
☞ The opening parenthesis will stay black until you’ve entered all the arguments and followed
them with a closing parenthesis. At that point both parentheses will turn cyan.
Customizing code completion
Code completion and call tips are customizable. All the ModL functions and message handlers
are listed in the application.ini file located in the ExtendSim/Extensions/CodeCompletion
folder. The script editor looks to this text file for the code completion feature.
If you define your own functions or includes and want them to be available for code comple-
tion, create a new text file that follows the format of the application.ini file. Append the “.ini”
extension on the file, then place that new file within the CodeCompletion folder.
☞ Do not change the application.ini file; instead, create a new file. Otherwise, your custom
entries will be overwritten when ExtendSim is updated.
80 IDE
Script Editor
IDE
you change the tabbed indentation on lines in ModL code. For example, if you copy lines
from another block’s code that are at a different indentation level, select the lines and use the
appropriate command to move them to the correct level.
• You can copy names from the Message pane of a block’s structure window for use in the
Script or Help tabs by right-clicking on the name and selecting Copy.
• The text on icons and the Help text can have character formatting. Select the text and give
commands from the Text toolbar. You can also specify a color for the text from the Graphics
toolbar’s Fill Color and Border Color tools.
Debugging and profiling
ExtendSim has a built-in source-code debugger, other debugging tools, and a profiling capabil-
ity that helps to locate code errors or inefficiencies. For more information, see:
• The Debugging Models chapter of the User Reference.
• “Source Code Debugger” on page 192, which works with the code of equation-based blocks
as well as with the blocks you build.
• “Debugging block code without the Source Code Debugger” on page 191, which discusses
how to use ExtendSim functions to do some debugging.
• “Profiling” on page 190. Profiling generates a text file that shows the percentage of time
individual blocks execute during a simulation, indicating if any of your custom blocks need
optimization.
Include files
Include files are standard header files. ExtendSim allows you to use include files in ModL
code; they can contain all ModL commands such as definitions, assignments, and functions.
They can also contain user-defined functions and predefined constants; the functions and con-
stants are accessible by any block that includes that file, including an equation-based block.
Like ModL in general, include files allow for the overriding of functions and message handlers
and can contain preprocessor statements for conditional compilation. Include files contain
user-defined functions and predefined constants; the functions and constants are accessible by
any block that includes that file.
82 IDE
Conditional compilation
Using include files simplifies programming tasks that are repeated in multiple blocks, such as a
library of blocks that use similar variable definitions and functions.
☞ As discussed on page 72, unless they are in an include file, user-defined functions are local to
the block in which they are defined.
Creating an include file
To start a new include file, choose the command Develop > New Include File. This opens an
untitled include file window.
Type the statements you want in this window and choose the File > Save Include File As com-
mand. This saves the include file into the ExtendSim\Extensions\Includes folder.
Naming conventions
For all platforms, the include file’s name must end with “.h” (as for standard C include files)
and the file must be either in, or in a subfolder within, the Extensions/Includes folder that
resides in the same folder as ExtendSim.
Referencing in a block
IDE
To reference an include file from a block’s code, enter a line in the code in the format:
#include "filename.h" (or #include "subfolder\filename.h")
or
#include <filename.h> (or #include <subfolder\filename.h>)
For example, if the name of the include file is “New_Defs,” you would use the command:
#include "New_Defs.h"
You can have as many include files as you wish, as long as all of them reside in the Includes
folder within the Extensions folder.
For an example of how include files are useful, see the Data Import Export block (Value
library) which uses an include file named ADO_DBFunctions. The ModL-coded ADO func-
tions for that include file are described on page 405.
☞ Include files are also called header files because they are usually included at the top or head of
the file. This is the source of their .h extension.
Conditional compilation
With conditional compilation, segments of code are compiled only if certain conditions are
present. Preprocessor directives are used to bracket code segments, causing parts of the code to
be compiled only if a particular symbol has been defined.
A symbol can be any kind of variable, function name, dialog item name, or constant. As seen
below some preprocessor symbols have been pre-defined. You can also define your own sym-
bols using #define, as discussed below.
Preprocessor directives
ModL supports several preprocessor directives to bracket the ModL code that you want condi-
tionally compiled:
• #ifdef symbol. If the symbol is defined, compile the code following the #ifdef until you get
to a #else or a #endif.
Programming Tools 83
External source code control
• #ifndef symbol. If the symbol is not defined, compile the code following the #ifdef until you
get to a #else or a #endif.
• #endif. Marks the end of the current preprocessor directive.
• #else. Used with #ifdef or #ifndef to give an alternative set of code to be compiled.
• #define symbol. Used to define your own symbols when you need to change your code based
on the existence of that new definition, for example within an include file. After defining a
new symbol, you can use it in the #ifdef and #ifndef directives. The syntax of the #define is:
#define myNewSymbol // define a new symbol
IDE
• ExtendSim_10. This symbol is defined only if the application is release 10 or later.
• Platform_Windows_Defined_Symbol.
• Platform_Macintosh_Defined_Symbol
Examples
For example, you can create an include file that has code to modify a dialog item. But if that
dialog item isn’t used in a particular block, the code will be ignored by the preprocessor direc-
tives.
The following is an include file generalized for different blocks.
...
void AFunction(real anArgument)
{
...
#ifdef myDialogItem // Only if myDialogItem is present
myDialogItem = anArgument; // display result in the dialog
#endif
}
A common situation is to use #ifdef to compile a message handler only if a dialog variable
exists. For example, an include file may be used by many different blocks, only some of which
have the dialog variable MyValue_prm. To prevent the compiler from giving an error message
when a block does not include the dialog variable, add the following to the include file:
#ifdef MyValue_prm
On MyValue_prm
{
//message handler for dialog variable
}
#endif
External source code control
ExtendSim supports a mechanism for saving the source code of individual blocks or libraries
of blocks as external files. This external source code feature is useful for situations where mul-
tiple developers work on the code of blocks and/or libraries at the same time.
84 IDE
External source code control
Normally the code of blocks is saved in the library file, along with the blocks’ dialog item defi-
nitions and icons. When blocks or libraries are recompiled with the external source code option
turned on, the library file does not contain the master source code. Instead, the source code is
saved in a separate subfolder inside the Libraries folder. It can then be used with a separate
source code control or management application.
Externalizing source code for a block
Open the block’s structure and go to the Script tab
Choose the command Develop > External Source Code
Close the block’s structure window
In the dialog that appears, choose Save, compile if needed
This causes the block to be recompiled with its source code in an external file.
☞ If source code has been externalized, the green initials CM (for code management) will be dis-
played on the block’s icon in the library window.
IDE
• Cause the green text CM (for “code management”) to appear on the icons in the library win-
dow, for each block that has been recompiled with external source code.
• Create a backup file, with the extension .ck, each time the block is recompiled.
IDE
Cautions when using the external source code feature
Unlike block code, block dialogs, icons, and help text are not editable by multiple developers at
the same time.
Managing non-code parts of blocks
With external source code turned on, the source code for each block is saved as a text file. This
facilitates the management of block code by multiple developers using source code control
software. However, the block dialogs, icons, and help text are not saved in the external files.
Instead, they are saved in the original library file.
When changes need to be made to block dialogs, icons, or help text, the library should be
“locked” using the source code control software. That way, no one else can modify those parts
of the block while they are being changed. After the changes have been made, unlocking the
library releases the blocks so other developers can work on them.
Sharing libraries with others
When you have recompiled a library with the external code option, you need to be careful
about how you manage and share that library. For example, if you give the library to someone
else without giving them the source code files, they will receive warning messages when open-
ing the structures of the blocks. Before giving the library to another person, recompile the
library with the external source code option turned off.
Extensions
Extensions are files of various types, such as text, sound, image files, or DLLs. When you
installed ExtendSim, you also installed an Extensions folder in the same folder or directory as
the ExtendSim program. The Extensions folder contains various files stored in subfolders, such
as DLLs, Includes, and Pictures. In addition to the files shipped with ExtendSim, you can add
your own extension files to the Extensions folder.
☞ Extensions should be stored in the appropriate subfolder. If there is no subfolder for the type of
extension you are adding, put it at the top level of the Extensions folder.
Supported file types
ExtendSim supports the following types of files:
• Text files, which are used for includes and code completion purposes
86 IDE
DLLs
• DLLs
• WAV files
• Various kinds of image files
Macintosh resource files converted using the ExtendSim MacWin converter utility are sup-
ported as pictures for backwards compatibility with earlier versions of ExtendSim. The differ-
ent kinds of extensions are discussed individually later in this chapter.
Naming
Except for DLLs, the name referenced by the ModL functions will be the file name. For DLLs,
as described below, the name referenced will be the function name of the particular function
you are trying to call from the DLL.
For more information, see
• DLLs, below.
• “Shared libraries” on page 88
IDE
• “Sounds” on page 89
• “Picture and movie files” on page 89
• “Customizing code completion” on page 79
DLLs
As discussed in “Accessing code from other languages” on page 42, ExtendSim provides sets
of functions that allow you to call code segments written in a language other than ModL from
within a block’s code. This is handy if you want to access existing functions written in another
language or solve problems that are difficult in ModL. On Windows, these functions are iden-
tified as DLLs or dynamic-link libraries. (See “Shared libraries” on page 88 for how code from
other languages are accessed on Macintosh operating systems.)
For ExtendSim 10 or later, the DLL must be built for 64-bit execution
Overview
DLLs are libraries of code written and compiled in any language. Their standardized interface
provides a method for linking between ExtendSim and languages other than ModL. In order to
access these code libraries, they must be stored in the ExtendSim Extensions directory, dis-
cussed above.
The ExtendSim DLL functions allow you to call DLL code libraries from within a block's code
and use that code to perform operations. For example, you can use a DLL to calculate some
function, perform a task, or even access Windows API calls. DLLs can also be used to access
external devices, or to solve problems that might be difficult or impossible to solve in ModL.
DLL interface
The DLL functions allow you to access existing Windows DLLs. Because they have variable
argument lists, these functions allow you to call almost any existing DLL. This interface
includes the following functions: DLLLongCFunction, DLLDoubleCFunction, DLLBoolC-
Function, DLLVoidCFunction, DLLLongPascalFunction, DLLDoublePascalFunction, DLL-
BoolPascalFunction, DLLVoidPascalFunction, DLLMakeProcInstance.
See the DLL functions on page 265 for more information about this interface.
Programming Tools 87
DLLs
IDE
page 419.
• In the argument list, variables passed from the ModL code to a DLL are passed by value.
• As discussed above, arrays that are passed to a DLL come through as pointers to the original
data in ExtendSim. Accessing and modifying the data is fine, but you should not try to resize
the pointer. If you do, ExtendSim will not be able to access the data and will probably crash.
• Strings are passed to DLLs from ModL as Pascal strings, not C strings. This means that the
string is preceded by a size byte and is not terminated by a zero. For example, if you pass a
string to a DLL, the DLL will get a pointer to 256 bytes of data in which the first byte con-
tains the number of characters in the string. To convert strings to C strings and back again,
see the DLLCtoPString and DLLPtoCString functions in the function list “DLLs and Shared
Libraries” on page 265.
• The most common problem associated with building and using a DLL is making sure that
the names of the routines that you want to call are exported and that they are exported with-
out Name Mangling or Name Decoration. Name Mangling is an option for how names are
exported from a DLL; it adds information about the arguments to the exported name.
☞ When building a DLL for use with ExtendSim, the Name Mangling option should be off.
DLL example
The following code calls a DLL that performs the same function as the ModL code (shown on
page 51) that you used to build the Miles block. (Note that you could accomplish the same
result, but in a slightly different manner, using a Shared Library for the Mac OS.)
88 IDE
Shared libraries
You must copy the sound file into the Extensions directory, as discussed on page 85.
Picture and movie files
IDE
Pictures and movies are used for specialized 2D animation. See the functions in “2D Anima-
tion” on page 270, for more detail. To see an example of using pictures and movies for anima-
tion, see “Showing a picture on an icon” on page 132.
Naming conventions and limitations for pictures
You can have any number of pictures in the Extensions folder. Pictures with names that start
with a “@” will not show up in the block’s animation tab popup menu. This prevents the ani-
mation tab menus from being filled with other, larger types of pictures that are not suitable for
animation between blocks.
As mentioned in “Extensions” on page 85, pictures must be stored as a file in the Pictures sub-
folder of the Extensions folder. The AnimationPicture function will recognize most picture for-
mats.
Protecting libraries
ExtendSim normally keeps both the ModL code and compiled code in the block; if you remove
the ModL code, the compiled code is still there. When you build custom blocks and do not
want others to have access to your block code, you can protect your libraries by removing the
ModL code of the blocks. When a modeler attempts to edit a protected block, ExtendSim dis-
plays a dialog message that the block is protected and cannot be opened. The structure of the
protected block is never shown.
A protected library can be used the same as any other library except that you cannot view or
alter the ModL code. This means that someone using the library has all the functionality of the
blocks in that library but no ability to see how the blocks work. This is a convenient way to
hide proprietary programming while still giving modelers full access to the power of the block.
Protecting the ModL code has the added benefit of preventing someone from changing the icon
or the block’s help text.
☞ After a library is protected, you can never un-protect it. Thus it is good practice to make a copy
of the original and store it on some other media.
The steps for protecting a library are:
Select the command Library > Library Tools > Protect Library.
90 IDE
Protecting libraries
When you give the Protect Library command, ExtendSim warns you that protecting a
library’s ModL code will permanently and irrevocably prevent access to block code.
In the dialog that appears, select and open the library you want to protect.
The Create New Library dialog allows you to rename the library. However, since models
will be expecting the original library name, it is suggested that you leave the library name as
is. The protected library will have the extension “.lbrpr” rather than the normal “.lbr”, so
your original library won’t be overwritten.
When the library is saved, ExtendSim protects the library’s ModL code by cutting it from
the block.
Any copies you make of this protected library will also be protected. You can easily show that
a library is protected by opening it and attempting to edit the structure of a block in the library.
IDE
Integrated Development
Environment (IDE)
Programming Techniques
Procedures and suggestions for how to
create and modify ModL code
This chapter focuses on using ModL functions to create custom blocks and simulation effects
in ExtendSim.
Data source indexing and organization
Communicating between various types of data sources has been greatly assisted by standard-
ized technologies, such as the ability of diverse applications to exchange data through a stan-
dard text file format. However, it is important to keep in mind that each standard has its own
conventions. This can cause data-confusion when transferring data from one type of source to
another.
Transferring data between a data table and a spreadsheet
ExtendSim data tables have zero-based indexes and are organized by row and column. Spread-
sheets are also organized by row and column, but they are one-based. When transferring data
from an ExtendSim data table to an Excel worksheet, the row and column numbers for Excel
must both be increased by 1 compared to their location in the ExtendSim data table.
☞ The first row in an ExtendSim data table could be labeled as 0 or as 1. However, no matter how
the row is labeled, the index for that first row is still 0.
IDE
You can also use the functions described in “Equations” on page 238 to create your own blocks
that take in equations and even allow for debugging. For example, you might want to do this
when building scientific or engineering blocks and can’t predict ahead of time what formulas
you will need.
☞ To allow larger equations or programs into a block’s dialog, see “Equations” on page 238 for a
list of equation functions that support up to 32000 characters in a dialog item. Also, see the
Equation block (Value library) for an example of using a Dynamic text item and a syntax color-
ing window to edit a user-entered equation.
Equation-based blocks can call any of the ExtendSim built-in functions. However, user-defined
functions and procedures cannot be defined directly in an equation-based block; they must be
defined in an include file. For a list of the other differences between equation-based blocks and
the custom blocks you might create, see “Differences between equation blocks and pro-
grammed blocks” on page 31.
Working with dialogs
IDE
With a bit of creativity, you can make dialogs that provide a great deal of information about the
state of a simulation or that help you debug models-in-progress.
In addition to the following information, modifying and creating dialogs, as well as ModL code
interaction with dialogs, is described in more detail in “Accessing dialog items from a block’s
code” on page 35.
Changing text in dialogs
The Miles block example on page 44 showed the usefulness of keeping a dialog open and
watching the numbers in the entry boxes change as the simulation progresses. Dialogs can also
be used for displaying text or messages that might change during the simulation.
Changing text as the simulation runs
Changing the text displayed in a dialog is often more useful than displaying alerts since alerts
stop the simulation until the modeler clicks one of their buttons.
For example, assume that:
• You are modeling a factory that has three shifts, where the name of the shift (day, night,
swing) changes depending on the current time.
• You have a block with a static or editable entry box named Shift that you want to modify.
• Simulation times are in minutes.
You could display the time in the Shift dialog item as a number, but then you have to convert
the time to the shift name in your head:
Shift = (CurrentTime / 60) mod 24;
Instead, you could convert the time in the block’s code and display text in the dialog:
...
string name[2];
name[0] = "Day"; name[1] = "Night"; name[2] = "Swing";
...
Shift = name[((CurrentTime / 60) mod 24) / 8];
94 IDE
Working with dialogs
For example, assume that you want to show values as either octanes (for gasoline) or cetanes
(for diesel fuel). There are two radio buttons that let you decide which unit to show:
// ShowOctaneValues radio button was clicked
IDE
on ShowOctaneValues
{
// set static text label above data table
SetDataTableLabels(“dataTable”, “Octane Values”);
☞ If the octane and cetane arrays were dynamic, the DynamicDataTable function could be used to
switch the data table between the two dynamic arrays. This would execute more quickly and
require less code.
Hiding/showing dialog items
As discussed on page 18, by default dialog items are visible in at least one tab; they may be
hidden by unchecking the Visible checkbox. Dialog items where Visible is unchecked are
shown in red.
You can also choose to dynamically show and hide dialog items depending on a user action or
on the value of other dialog items. You do this using functions (such as HideDialogItem) in the
list that starts on page 305. When the dialog is opened by the modeler, you use a DialogOpen
message handler to show and hide certain items depending on the values of the controlling
items.
For example, the Decision block (Value library) has a parameter field for Relax that appears if
Use Hysteresis is checked. For more complex dialogs, see “Moving dialog items”.
IDE
In some cases you may want a dialog item to not be visible ever. This is common when you
don’t want to use a dialog item anymore, but shouldn’t delete it because the block is already
used in models. In this case, just uncheck the Visible checkbox.
Use caution when deleting a dialog item if the block is being used in any model. Deleting the
item could disrupt the order of the dialog’s data. The data will have to be reentered for each
instance of that block in all models that use it. Instead of deleting the dialog item from a block
used in a model, hide it by unchecking the Visible checkbox in its properties window. (Since
they don’t store data, text frames and static text labels may be safely deleted.)
When you copy or duplicate dialog items
You can copy/paste or duplicate dialog items within a tab, from one tab to different tab within
the same block, or from one block to another. To do this, select the dialog item, then give the
Duplicate (or Copy and Paste) commands.
When you duplicate or copy/paste a dialog item, its Label stays the same but a number is
appended to the original dialog item’s Name. Unless you change it, the new name (with the
appended number), is how the copy of the dialog item will be referenced in ModL code. The
name and Label can be changed by double-clicking the dialog item to access its definition.
Moving dialog items
• To manually move a dialog item within a dialog tab:
• Either select and drag it to the new location within the same window or tab
• Or, double-click it and change its X and Y coordinates in the properties window
• To manually move a dialog item from one tab in the Dialog tab to another, first select the
item, then use the Develop > Move Selected Items to Tab command. Then select the tab to
move the item to.
• You can also write code that moves a dialog item depending on a block’s settings. This is
often easier and more organized than placing all the dialog items on top of each other and
then hiding and showing them depending on the setting. For instance, the parameter fields in
the Random Number block (Value library) move based on which distribution the user
96 IDE
Working with dialogs
selects. The DIPosition functions, as well as DIMoveTo and DIMoveBy, can be used to
move dialog items. These functions are included in the list that starts on page 305.
the ability to read block names and labels, this feature can be used to build a block that can
globally control the model, gather statistics on a class of blocks, or change parameters within
all blocks that have a specified commonality.
☞ In addition to the GetDialogVariable function, see the GetStaticVariable function.
For example, as seen in the Get-Set Dialog Variable model located at Documents/ExtendSim/
Examples/Developer Tips, you can build a block that can cause specified Activity blocks (i.e.
Activity blocks whose labels include a specific wording, such as ABC) to double their entered
delay value. Below is sample code that does this:
Programming Techniques 97
Remote access to dialog variables
nBlocks = NumBlocks();
for (i=0; i<nBlocks; i++) // all the blocks in the model
{
name = BlockName(i); // get the name of the block
label = GetBlockLabel(i); // get the block’s label
IDE
// Found them. now read the parameter for the delay
paramStr = GetDialogVariable(i, “waitDelta_prm”, 0, 0);
return;
}
☞ If you have additional code in this message handler, put it after this code.
Custom stand-alone block referencing remote dialog variables
If you create a stand-alone block that will reference (get or set) remote dialog variables in other
blocks, you can implement any or all of the above methods for collecting the information from
the remote block, as discussed below. (While it is also possible to develop your own interface,
using one or more of the ExtendSim interfaces will be easier and more consistent with existing
blocks.)
Manual data entry
Implementing a manual method for referencing from the list in a custom stand-alone block
depends on your particular implementation, interface, and needs. Some blocks, such as Find
and Replace (Utilities library), only work with one remote dialog variable at a time. Other
blocks, such as Statistics (Report library), have a list of remote dialog variables. For coding
examples, look at one of those blocks.
Clone drop
Adding a clone-drop interface to a custom block requires a DragCloneToBlock message han-
dler. This is called whenever a clone is dragged to the icon of that block.
Inside of this message handler, call GetDraggedCloneList. This function requires two argu-
ments – an integer dynamic array and a string dynamic array. It returns the number of clones
(usually 1) dropped onto the block. You then use this information to reference a dialog item in
another block.
Shift-click
The shift-click feature is more complicated to implement because it requires using a reserved
database (discussed on page 112) and an include file. The reserved database (_leftClickDB)
provides the necessary information for the shift-click action. The include file (MouseClick.h)
has two functions defined in it that are required for managing the reserved database:
Programming Techniques 99
Remote access to dialog variables
IDE
The information sent by the remote block must be processed in the message handler for the
hidden dialog variable. This information has been set in static variables in the stand-alone
block by the remote block. The names of the static variables are set in the RegisterBlockIn-
LeftClickDB function. The information includes the block number, dialog variable name, and
database table’s row and column. These values can be found in the Dialog and Static variables
that are arguments to the RegisterBlockInLeftClickDB function.
In the following code example, the stand-alone block gets:
• The block number for the remote block in the dialog variable AddFactor_prm
• The name of the remote block's dialog variable in the static string variable DialogVarName
• The row and column of the remote dialog variable in the RowColumnDialogVar static string
variable
And the popup menu is labeled “Scenario Manager: Add Factor”. Because the Scenario Man-
ager has two options (one for adding a factor and one for adding a response), this is option 1.
On OpenModel
{
RegisterBlockInLeftClickDB( "AddFactor_prm","DialogVarName",
"RowColumnDialogVar", "Scenario Manager: Add Factor", 1);
}
On AddFactor_prm
{
// Receive message from remote block and process hidden variables
// AddFactor_prm is the block number of the remote block
// DialogVarName is the dialog variable in the remote block
// RowColumn is the row and column in the remote block
}
100 IDE
Working with connectors
Shift-click example
When the Optimizer block (Value library) is added to a model it
creates the reserved database _leftClickDB. The entries in the
database table cause options, such as Optimizer: Add Parameter,
to be added to a menu that appears when an appropriate dialog
item is Shift-clicked.
Through block code, the Shift-click action causes the selected
variable to be used in the Optimizer block. Using this type of
architecture makes it easy for developers to add their own block
options to the Shift-click menu.
Working with connectors
Most blocks have connectors. You add and change connectors using the connector tools in the
Icon Tools tool at the right of the ExtendSim toolbar.
☞ For information about connector types, options, and names, see the writeup that starts on
page 20.
IDE
Variable connectors
By default new connectors are added as a normal (single) connector. This works well for sim-
ple blocks, but often a block will need several inputs or outputs.
As discussed in “Connector options” on page 21, when you select a type of connector (Value,
Item, etc.) it is by default a normal connector. You can then change the connector to be vari-
able. Variable connectors act like a row of normal connectors, where the row can be expanded
or contracted to provide a required number of connectors. To work with variable connectors,
see the writeup on page 35 and the functions on page 303. For an example of how variable
connectors are implemented, see the Math block (Value library).
Initializing connectors
The value of a connector is used to determine whether the block is connected to another block
during the CheckData message handler, and thus cannot be changed there. All connectors are
initialized by ExtendSim to 0.0 after the CheckData message handlers are executed. To initial-
ize connectors before the simulation runs, do it within the InitSim or PostInitSim handler.
For example, to initialize a connector before the simulation runs:
On InitSim // Or use On PostInitSim
{
conOut = initialValue;
}
The blocks in the Item library initialize their connectors in the InitSim handler.
Deleting connectors or changing connector types
ExtendSim keeps an ordered list of the connectors on a block. If you delete a connector on a
block used in a model, it changes the connector order. This may cause unexpected results – the
connectors could become disconnected or connected incorrectly.
For blocks used in existing models, changing connector order could cause a problem. When
you only need to change connector types, do not delete the connector. Instead, simply select it
and click on the correct connector tool. If you have to delete a connector on a block that is used
in a model, carefully examine the block’s connections afterwards.
Programming Techniques 101
Working with arrays
Bidirectional connectors
All ExtendSim connectors are bidirectional. This is useful if you want blocks to communicate
back and forth.
For example, you may want to simulate a network or a bus in which blocks need to both send
to, and receive information from, the other members of the network. Because ExtendSim does
not allow multiple output connectors to be connected together, you could use only input con-
nectors for all the blocks in the network.
Or you may also want source and sink connections, where a source block can have its output
value changed by the sink blocks that are connected to it. This is useful in simulations where
one block’s reserves are depleted by the other blocks connected to it.
To implement these features in blocks, assign or modify the value of an input connector. This
feature makes input connectors bidirectional. When the value of an input connector is modi-
fied, all connected blocks will see this new value when they get their next Simulate message.
The concept of using an input connector for both input and output is shown in the Bidirectional
IDE
Flows model, which is located in the Documents/ExtendSim/Examples/How to/Developer
Tips folder. In that model a power station supplies energy to cities. Each city block has a single
input connector. The block code for the cities subtracts an amount from the input, called “Pow-
erIn”, with the statement:
PowerIn = PowerIn - amountUsed;
This affects the Power Station block by reducing the output power value stored in its output
connector. The power station can check its output connector value and see if it went to 0 or
became negative, signifying that its power reserves have been depleted by the towns:
if (PowerOut <= 0.0) // check the reserve power
{
// Out of power. Tell when this occurred.
UserError("Brownout occurred at time= "+CurrentTime);
abort; // Stop the simulation.
}
Working with arrays
Since you will typically use arrays to store any data which is more complex than a single vari-
able, you will probably use them fairly often. ExtendSim provides lots of features and func-
tions that use arrays, especially regarding discrete event modeling. Note that, while ModL does
not directly support arbitrary user-defined structures, it supports a rich linked list structure (see
“Array-like structures” on page 67 and “Linked lists” on page 385) and it emulates other types
of structures using arrays of arrays. You will find that working with arrays in ExtendSim is
simpler and safer than using the data structures that are available in C.
☞ As shown in the table in “Data source indexing and organization” on page 92, arrays use zero-
based indexing.
Memory usage of variables, arrays, and items
For most models, you do not need to worry about how much memory your variables take up.
You may need this information in some circumstances, especially if you are using huge arrays.
☞ There is no overhead for using arrays.
102 IDE
Working with arrays
The total of all static arrays (non-dynamic arrays) and variables in a block, including any static
data tables in the block’s dialog (which are real arrays, 8 bytes per element), cannot exceed
32,767 bytes. Dynamic data tables are not included in static memory allocation. See “Block
IDE
☞ If you pass arrays, those arrays can only be resized or disposed of in the same block where they
were created.
You can use the SendMsgToBlock function and the BlockReceive message handler to tell the
originating block to resize the array. An example of this is the Executive block (Item library).
It is important to note that any changes made to data in a passed array affects all blocks that
reference that array, including the block that originated the array. If you want to make a change
to a passed array that is not reflected in previous blocks in the model, copy the values from the
passed array to a new array, make changes to that new array, and pass that new array. (You can
copy an array quickly with a “for” loop, as described later in this chapter.)
Passing arrays through connectors
The blocks built in this manual pass single values through their connectors. You cannot pass
arrays as easily as you can single values, but it is not difficult to add the few functions that let
you pass arrays through the connectors.
Because a connector is a real variable, you can pass arrays through connectors. To read a
IDE
passed array from a connector, use the GetPassedArray(connector, array) function. For exam-
ple, assume that you are receiving an array through the input connector called ArrayConnec-
torIn. Your message handler might look like:
real theArray[];
...
on Simulate
{
if (GetPassedArray(ArrayConnectorIn, theArray)) // is it
passed
{
. . . // Yes, use the array
}
else
{
. . . // The array did not arrive yet
// or it is not a passed array
}
. . .
}
All of the values in the passed array can now be accessed and changed by using the theArray
variable in your code.
The process for passing multidimensional arrays is exactly the same, with the exception that
you need to confirm that the fixed dimensions are the same for both the passing and receiving
blocks.
There are two different ways to pass an array to an output connector, depending on whether the
array was passed to the block or it originated in the block. If the array was passed to the block,
simply set the output connector to the same value as the input connector:
ArrayConnectorOut = ArrayConnectorIn; // pass the old pointer on
To pass an array that originated in the block, use the PassArray(array) function. You can assign
the value of this function to an output connector (or to a real variable in your ModL code that is
then assigned to an output connector). Assume that you had changed the values of theArray
104 IDE
Working with arrays
in the example above and wanted to pass them out the connector named ArrayConnectorOut.
You would use:
ArrayConnectorOut = PassArray(theArray); // pass the new pointer
If you are just passing an array through a block without looking at it, you should not use Get-
PassedArray. Simply assign the output connector to the value of the input connector, and the
real number that holds the passed array will be handled with no overhead:
ArrayConnectorOut = ArrayConnectorIn; // pass the old pointer on
The GetPassedArray function needs to be called before accessing a passed array. If an array is
created at the beginning of the simulation and the size is never changed and the array is not dis-
posed of during the simulation, then GetPassedArray only needs to be called once, at the
beginning of the simulation.
☞ If you pass arrays NOT during a run, call GetPassedArray() in any message handler that uses
those arrays before accessing those arrays.
However, GetPassedArray must be called again before accessing any passed array that may
have changed in size or been disposed of. Trying to access a passed array after the creator
block has disposed of or resized it can cause a crash if the GetPassedArray function is not
called immediately before access is attempted. When you resize or dispose of an array, its
memory location may change or otherwise become invalid. A crash can occur because the
block that received the array has a pointer to a specific location in memory, and will try to
access that memory point even if it no longer is a valid array location. Calling GetPassedArray
immediately before accessing the array will relink to the correct memory address if the array
has been resized and will return a FALSE value if the array has been disposed of.
Since GetPassedArray is extremely fast (because it only links the pointer of the array), the saf-
est action is to call it and test its return value before every series of accesses to the array.
☞ The following is an example of what NOT TO DO:
Block #1
integer x[];
on checkdata
{
Makearray(x, 10); // create the array
global9 = passarray(x);
}
on endsim
{
DisposeArray(x); // dispose of the array
}
Block #2 //this is not safe!
Programming Techniques 105
Working with arrays
integer x[];
on initSim
{
GetPassedArray(global9, x);
}
IDE
integer x[];
on initSim
{
GetPassedArray(global9, x);
}
on endSim
{
if (getPassedArray(global9, x)) // This is safer. Get and test the
array first.
{
for(i = 0; I<10; I++)
x[i] = 0;
}
}
For the same reason, it is important to call the function GetArrays() (see “Functions in discrete
event blocks” on page 180) in your custom discrete event block code each time before you
access the ItemArrays.
Using passed arrays to make structures
ModL does not support structures directly, except for linked lists (see “Linked lists” on
page 385). It does, however, allow you to emulate structures using arrays of arrays. This is
safer than using pointers and structures in C.
Suppose you want to pass an array consisting of real, string, and integer values. Since arrays
can be passed to any real variable, many arrays can be passed into a real array, and that array
can be passed through a connector or global variable. The receiving block can get the passed
structure array and then get the individual passed data arrays from that array.
The following shows an example of using passed arrays to make structures.
106 IDE
Working with arrays
on InitSim
{
// Give the arrays a size.
MakeArray(structureArray, 3); // Holds reals, strings, long.
MakeArray(stringValues, 10); // 10 elements for each array
MakeArray(integerValues, 10);
MakeArray(realValues, 10);
structureArray[1] = PassArray(stringValues);
structureArray[2] = PassArray(integerValues);
}
on Simulate
{
// Put data into the realValues, stringValues,
// and integerValues arrays.
// For example, set one element of each array.
realValues[0] = 98.6;
stringValues[0] = "Octane rating";
integerValues[0] = TRUE;
on Simulate
{
if (GetPassedArray(ConnectorIn, structureArray))
{
// Get the reals
GetPassedArray(structureArray[0], realValues);
// Get the strings
GetPassedArray(structureArray[1], stringValues);
// Get the logicals
GetPassedArray(structureArray[2], integerValues);
// Use the array values
if (stringValues[0] == "Octane rating")
. . .
}
else
{
// The structureArray did not arrive yet
IDE
// or is not an array.
. . .
}
}
on initsim
{
arrayIndex = GAGetIndex("myGlobalArray"); // see if global array
already exists
108 IDE
Working with arrays
on simulate
{
real realNumber;
. . .
// Set second row and column of global array to realNumber
// (row and columns start at index zero)
GASetReal(realNumber, arrayIndex, 1, 1);
. . .
IDE
// Read third row and column of global array and assign to realNumber
realNumber = GAGetReal(arrayIndex, 2, 2);
}
On Endsim
{ // We are done with myGlo-
balArray.
if (GAGetIndex("myGlobalArray") != -1) // Only if myGlobalArray
still exists,
GADispose("myGlobalArray"); // dispose of it.
}
integer numRowsRead;
real fileArray[];
string theFileName, thePrompt, theDelim;
...
MakeArray(fileArray, 10000);
numRowsRead = Import(theFileName, thePrompt, theDelim, fileArray);
MakeArray(fileArray, numRowsRead);
The second call to MakeArray reduces the size of the array without disturbing the contents in
the rows left. Of course, if you import into a two-dimensional array, you have to specify the
size of the second dimension.
Working with linked lists
As discussed on page 67, linked lists are complex structures that can enable sophisticated sort-
ing rules. The concepts behind linked lists are beyond the scope of this manual. See “Linked
lists” on page 385 for a basic strategy in working with linked lists. Also, see the Queue blocks
(Item library) for actual linked list code.
IDE
Using message handlers
☞ Messages and message handlers were discussed on page 33 (introduction) and page 75.
ExtendSim uses a sophisticated messaging architecture to signal blocks into action. For
instance, when you add a block to a model, ExtendSim sends the “CreateBlock” message to the
new block. If the block’s code contains a message handler for the “CreateBlock” message (that
is, a bracketed set of lines that are preceded by “on CreateBlock”), the code is executed; if not,
nothing happens.
While messages can originate either from the ExtendSim application or from blocks, it is
always a block that is on the receiving end of a message. When you run a simulation, some
messages are sent to all blocks; others are sent only to a specific block. For instance, the “Cre-
ateBlock” message is sent only to the block that was added to the model. However, the “Init-
Sim” message, which tells the blocks that a simulation is starting, is sent to all blocks.
☞ The messages that a block’s dialog items uses are listed in the Dialog Item Names pane in the
block’s structure window. Use the Copy and Paste commands to copy the message names from
the pane to use in ModL code.
Categories of messages
While there are dozens of messages, they could be thought of as falling into one of three cate-
gories:
1) Messages that are sent to a block when the modeler interacts with the block’s dialog. For
instance, when the modeler clicks the block dialog’s Cancel button.
2) ExtendSim allows blocks to “call” other blocks by sending them a message, whether the
blocks are connected or not. Blocks use this feature to cause an action in another block,
such as having it perform a calculation or open a plot. For example, the UpdateStatistics
message is typically sent to an Activities block by the Statistics block (Report library)
when its statistical variables need to be recalculated and updated.
3) Messages that are typically sent from the application to one or more blocks. For instance,
when a block is added to the model, while the simulation is running, during interaction with
an ExtendSim database, and so forth. For example, the LinkContent message sends the
message that data has changed in an ExtendSim database.
110 IDE
Using message handlers
☞ A complete list and description of ModL messages is in the chapter “Messages and Message
Handlers” that starts on page 213.
Message sent during user interaction with dialog
This example shows what happens when the modeler clicks a button in the dialog. The dialog
item name of the button is “MyExportButton”. (The text label of the button is “Export”; it is
not used in the code.)
// Sent when the modeler clicks a button in the block's dialog
on MyExportButton // The modeler clicked the Export Data button
{
MyExportFTP(); // Call my function to export the data to the web
}
☞ For examples of code for each dialog item, see “Dialog messages” on page 36.
Block-to-block message
When a button is clicked in the calling block, its code sends a message to the receiving block
IDE
and causes that block to return a value. Global variables are used to pass arguments to the
called block as well as to get results from the called block’s actions.
See the Item library for examples of blocks sending messages using connectors.
Calling block
on Button // called when the block’s Button is clicked
{
// globalInt0 contains the block number of the receiving block
// UserMsg0 is the message handler that calculates it
SendMsgToBlock(globalInt0, UserMsg0Msg); // Call it
myResult = global1; // Get the result of the call
}
Receiving block
on UserMsg0 // called from the calling block
{
global1 = 123.5; // assign value to global1
}
IDE
integer recordIndex;// index for setting our record values
on simulate
{
recordIndex++;// increment our record index first (one based)
Contents message if the content of the data source changes or a LinkStructure message if the
structure of the data source (such as the name of a table or the location of a field) changes.
An example of block registration for content changes is the Read block (Value library). When
Link Alerts is checked in its Options tab, the block registers itself so that it will be alerted if/
when changes are made to its source data.
Registered blocks can be located using the Find Links dialog (Edit > Open Dynamic Linked
Blocks) discussed in the User Reference.
Use registered blocks judiciously. Due to the extra messaging, a registered block can signifi-
cantly slow the simulation run.
Reserved databases
ExtendSim databases are internal repositories for storing, managing, and controlling model
data. A reserved database is a specialized type of ExtendSim database that can be hidden from
the modeler. Reserved databases provide database capabilities without the modeler having to
use, or even be aware of, the reserved database.
IDE
Typically a database would be created by a modeler for a specific model. A reserved database,
on the other hand, is usually created by a programmer using the database API.
Example
A common use of a reserved database is to support the architecture
of a block. For example, when the Resource Manager block (Item
library of ExtendSim DE and ExtendSim Pro) is added to a model it
creates a reserved database named _rM_Database. There are numer-
ous tables in that database, each focusing on different aspects of the
block and how it functions. For instance, the Dialog Colors table,
shown here, stores the HSV values of the colors used for text labels
in the block’s dialog. Other tables track filtering conditions, store
resources with their ranking and skill levels, and so forth. When the
modeler enters data and makes selections in the Resource Manager block, these are tracked in
the reserved database. This process is invisible to the modeler.
The Optimizer block (Value library) is an example where a reserved database is used to pro-
vide a feature for the modeler. This is discussed in “Shift-click example” on page 100.
Creating and editing
Reserved databases are created and edited in much the same manner as you would create or
edit any ExtendSim database. Some differences are:
• To notify ExtendSim that the database is to be reserved, enter a leading underscore (_) at the
beginning of the database’s name. For example, the name would look like “_ARe-
servedDB”.
• To prevent modelers from accidentally writing to reserved databases, they require special
write functions. These are listed on page 363. An error message will be displayed if the spe-
cial write functions are used for non-reserved databases, and vice versa.
• Since they are intended for developers, ExtendSim doesn’t support using blocks (such as
Read or Write) to access reserved databases. It also doesn’t allow modelers to link dialog
items to a reserved database.
Programming Techniques 113
Reading text blocks as commands
• When a block that requires a reserved database is added to a model, the code of the block
creates the database in the model. In most cases, unless a block that requires a reserved data-
base is placed in the model, the model will not have any reserved databases.
• If a model has reserved databases, they will not be displayed in the Database List or at the
bottom of the Database menu unless you first give the command Develop > Show Reserved
Databases. By default, this command is not selected. Furthermore, the command is re initial-
ized to off each time the model is opened.
• Even if a reserved database is not listed in the Database List or at the bottom of the Database
menu, it is always accessible through ModL functions.
Changing anything in a reserved database is equivalent to changing the code of a block. It is
likely to corrupt any blocks that uses it.
Reading text blocks as commands
Since every piece of text that you add to a model gets its own number, text on the model work-
sheet can be accessed in a block’s code.
IDE
The BlockName function returns the name of a block for the specific block number. However,
blocks aren’t the only items on the worksheet that have numbers. Because each piece of text
gets a number, and the text is equivalent to a block’s name, you can use BlockName to read
text. This can be useful if you want to see how you have changed some text on the model.
Use this feature to globally change parameters in block dialogs. For example, assume you want
to give a command to the model to change a specific parameter in many blocks. Normally, you
would have to open all of the blocks and type the new parameter value. Here is a strategy that
allows you to type some text, such as “Speed=55”, on the model window that will cause all of
the speed parameters in all of the blocks to change when the simulation is run. Note that the
following function can be put in any block and can be called for each typed value that the code
needs:
114 IDE
Reading text blocks as commands
on BlockReceive0
{
// globalInt1 contains the number of the function
IDE
}
}
Changing data while the simulation is running
Sometimes you need to change values in a block’s dialog while the simulation is running. In
most cases, ExtendSim handles this by allowing you to change the value, which is then used
immediately in the block’s code (usually in the Simulate handler). However, there has to be a
special initializing procedure if the block needs to calculate intermediate values based on that
new data. ExtendSim provides a mechanism to tell the block that its data has been changed.
Then the block can do a recalculation of intermediate data before the simulation resumes.
When any data is changed in a dialog during a simulation, ExtendSim sends a ResumeSim
message to that block before the simulation can resume. It also sends a ResumeSimAllBlocks
message to all of the blocks in the model. These are optional message handlers because most
blocks do not need to recalculate intermediate data, they just use the dialog values directly. But
if the block has a ResumeSim or ResumeSimAllBlocks message handler, it can take some
action before the simulation resumes.
Here is an example of a block that needs to do a lengthy calculation before the simulation
resumes after a change in parameters. It recalculates the coefficient when the modeler changes
the dialog parameter, but doesn’t zero out the accumulated value so the simulation can con-
tinue properly:
real coeffValue, accum;
real CalcCoeffValue(real theValue) // This function does the
// coeffValue calculation
{
real coeff;
integer i;
Scripting
In ExtendSim, the process of building models typically relies heavily upon modeler interac-
tion. The standard process of placing blocks on the worksheet, connecting them together, and
filling in the appropriate dialogs (while graphical and intuitive), requires direct modeler partic-
ipation. However, models can also be built, modified, and controlled indirectly using Extend-
Sim’s scripting features.
Scripting is an extremely powerful feature which allows you to:
• Build, run, and control models from within another application
• Create custom wizards to simplify tasks or interact with modelers
• Develop self-modifying models
By using the scripting functions (see “Scripting” on page 337), you can tell ExtendSim which
blocks to place on the worksheet and where, how to connect the blocks together, and what val-
ues to use for the block’s dialog parameters. In addition, any menu command can be executed
by a function call, for instance to run a model. When used in conjunction with the IPC func-
tions (see “Interprocess Communication (IPC)” on page 250 or “OLE/COM (Windows only)”
on page 253), the scripting functions can be used to build and run entire models based on infor-
mation from another application.
The scripting functions can also provide a means for developing “wizards” – blocks that help
the modeler to perform a task by gathering information, then building or modifying a model
based upon that information.
You can also develop blocks that help models achieve desired results. You could build artificial
intelligence into your models by building blocks that query the model for specific metrics and
simultaneously modify the model based on those metrics. For instance, you would use this
self-modifying feature to automate the process of changing models in response to simulation
results or to build goal-seeking models.
See the Tutorial block (Example Libraries > ModL Tips library > Scripting category) for an
example of using the scripting functions.
Programming Techniques 117
OLE and ActiveX Automation
IDE
a dispatch handle as their first argument.
☞ The Examples\How To\Developer Tips\OLE Automation folder contains examples of C++,
Visual Basic, and VBA code for ActiveX Automation. See explanation for those examples on
page 119 (C++), page 124 (VBA), and page 124 (Visual Basic).
COM DLL example
The “VB.net COM DLL example” model (Windows only) shows how to interface from
ExtendSim with a COM DLL created in VB.net. The COM DLL folder includes the model
plus an ExtendSim library with a custom block as well as the source code used to create the
COM DLL. ExtendSim is the Client in this automation example; this is the inverse of the Cli-
ent App example where VB is the Client.
☞ See the folder Documents/ExtendSim/Examples/How To/Developer Tips/OLE Automation/
VB/COM DLL
Controlling Embedded Objects from ModL script
A set of functions is available in ModL to access embedded objects. These are described in
detail on “OLE/COM (Windows only)” on page 253. They include:
• Functions to insert objects (OLEInsertObject)
• Functions to invoke methods and set properties of objects; (OLEInvoke, OLEPropertyPut,
OLEPropertyGet)
• And many other miscellaneous functions that allow extensive control of an embedded object
Embedded objects or ActiveX controls can be embedded directly onto the model worksheet or
embedded into dialog items built to be embedded object locations.
• When you are trying to control an object that has been embedded onto the model worksheet,
the blockNumber argument is used to determine which object is to be controlled and the dia-
logItem argument is ignored.
• When you are trying to control an object or control that has been embedded into a dialog, the
block number and dialog item arguments are both used.
118 IDE
OLE and ActiveX Automation
These are used in a fairly simple single object model. Execute, Request, and Poke are the pri-
mary means of controlling ExtendSim via ActiveX/OLE Automation. BlockMsg and GetOb-
jectHandle are slightly more obscure, but can also be useful. See “C++ examples” on page 119
for an example of how these methods are used.
Object
For use with C++ or other related languages, the Object is the ExtendSim application, refer-
enced by the following GUID:
{E167B362-7044-11d2-99DE-00C0230406DF}
In Visual Basic, or other environments where ProgIDs are supported, this GUID can also be
referenced by the ProgID “Extend.application”. ProgIDs are a simplified and easier to remem-
ber way of accessing a GUID.
Even though the application name is ExtendSim, for backward compatibility the ProgID is
Extend.application. In the future, the ProgID ExtendSim.application will be supported as well,
but at the time of this writing the correct ProgID is Extend.application.
Because ModL scripts can be executed with the Execute method, complete control of Extend-
Sim is available through the following methods:
1 Execute 120
2 Request 120
3 Poke 121
100 BlockMsg 122
101 GetObjectHandle 123
Topic is the name of the worksheet or model (or “system” if you don't need to specify a
model). If you specify system, the data will be poked to or requested from the top model.
The Item string is specified as follows:
"VariableName:#BlockNumber:RowStart:ColStart:RowEnd:ColEnd"
RowStart, ColStart, RowEnd, and ColEnd can all be set to zero if the item specified is neither a
data table object nor an array.
If the item is not a table, RowEnd and ColEnd can be left off. In this case the string would look
as follows:
"VariableName:#BlockNumber:0:0"
Starting in ExtendSim 7.0.2 there are new forms of the Item string which will allow you to
poke directly to, or request directly from, an ExtendSim database table or a global array. These
forms are as follows:
"GA:#GlobalArrayIndex:RowStart:ColStart:RowEnd:ColEnd"
IDE
"DB:#DBIndex:DBTableIndex:RecordStart:FieldStart:RecordEnd:Field-
End"
Note that the database case has an extra argument.
C++ examples
The following examples show how to access an IDispatch interface and use the five methods
(Poke, Request, Execute, BlockMsg, and GetObjectHandle) in C++. Also see the Exam-
ples\Developer Tips\OLE Automation folder.
Retrieving the IDispatch interface
The following C++ sample code shows one possible way you could access an IDispatch inter-
face on an ExtendSim application.
☞ The GetActiveObject code attempts to find a running copy of ExtendSim in the ROT (running
object table). The CoCreateInstance code creates a new instance of ExtendSim if the running
one is not found.
CLSIDFromString ("{E167B362-7044-11d2-99DE-00C0230406DF}", &clsid);
hr = GetActiveObject(clsid, NULL, (IUnknown **) &m_pUnknown);
if (hr == S_OK)
{
// JSL - found an existing instance
hr = m_pUnknown->QueryInterface(IID_IDispatch, &m_pDisp);
hr = m_pUnknown->Release();
}
else
{
theErr = GetLastError();
MessageBox (NULL, TEXT("GetActiveObject Failed, creating a new
Object"), TEXT("OleTest"), MB_OK);
hr = CoCreateInstance(clsid, // class ID of object
NULL, // controlling IUnkown
CLSCTX_LOCAL_SERVER,// context
IID_IDispatch, // interface wanted
(LPVOID *) &m_pDisp) ;// output variable
120 IDE
OLE and ActiveX Automation
if (hr != NOERROR)
{
theErr = GetLastError();
MessageBox (NULL, TEXT("Create Instance Not Successful"),
TEXT("OleTest"), MB_OK);
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, theErr,
MAKELANID(LANG_NEUTRAL,SUBLANG_DEFAULT),
buf, sizeof(buf), NULL);
MessageBox (NULL, buf, "Error", MB_OK);
return;
}
}
Execute
The Execute method takes just a single argument that is the code to be executed. The dispID of
Execute is 1.
The Execute method is the most flexible method call, as the command that is passed to Extend-
Sim via this method is just a section of ModL script and can contain anything that can be put
IDE
into ModL script, including scripting functions. This means that by using the execute method
you can build models, run models, or do any of a number of things.
The C++ code you would use to call the execute method would look something like this (note
that this code will cause ExtendSim to display a userError statement with the value in user-
global0):
// Arguments are all passed as variants
bStr = SysAllocString((WCHAR *) L"userError(userglobal0);");
VariantInit(&vString);
vString.vt = VT_BSTR;
vString.bstrVal = bStr;
// Call IDispatch::Invoke()
hr = m_pDisp->Invoke(executeID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp3, NULL, &ei, &uiErr);
Request
The Request method uses Topic and Item, as specified a in “Topic and Item” on page 118, and
returns a string value. The dispID of Request is 2.
The C++ code you would use to call the Request method would look something like this (this
code will return the value present in userGlobal0):
Programming Techniques 121
OLE and ActiveX Automation
IDE
dp2.cNamedArgs= 0;
var.vt = VT_EMPTY;
// Call IDispatch::Invoke()
hr = m_pDisp->Invoke( requestID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp2, &var, &ei, &uiErr);
SysFreeString(topicStr);
SysFreeString(itemStr);
Poke
The Poke method takes the three arguments Value, Topic, and Item and sets the value specified
in the Value argument into the item specified in the Item argument. Topic and Item are speci-
fied as in “Topic and Item” on page 118; Value is the string that is going to be poked into the
location specified by Topic and Item. The dispID of poke is 3. Value, Topic, and Item are all
strings.
The C++ code you would use to call the Poke method would look something like this (note that
this code will set the value of Global0 to 34.5):
122 IDE
OLE and ActiveX Automation
dp.cArgs = 3;
dp.rgdispidNamedArgs = NULL;
dp.cNamedArgs = 0;
// Call IDispatch::Invoke()
hr = m_pDisp->Invoke( pokeID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp, NULL, &ei, &uiErr);
SysFreeString(topicStr);
SysFreeString(itemStr);
SysFreeString(valueStr);
BlockMsg
BlockMsg sends a message to a specific block in the active ExtendSim model. The DispID of
BlockMsg is 100. This message will execute a message handler in the block called OLEAuto-
mation.
The BlockMsg method takes two arguments:
• The first is a block number (integer) and specifies the block that is to receive the message.
• The second is a value (integer, real, or string) and can be used to communicate with the
block code.
ExtendSim will set the value of one of three globals to be equal to the value you pass in as the
Value argument. Which global will be set is based on which type of variable passed in. The
example below uses a string variable. The three globals are OLEGlobal, OLEGlobalInt, and
OLEGlobalStr.
As reflected in the code below, the integer values used by the blockMsg method are long inte-
gers. However, by default an integer variable declared in Visual Basic is a short integer. So VB
programmers should take special care to declare the variables as longs in their VB code.
Programming Techniques 123
OLE and ActiveX Automation
// Call IDispatch::Invoke()
hr = m_pDisp->Invoke( msgID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
IDE
DISPATCH_METHOD, &dp, NULL, &ei, &uiErr);
SysFreeString(argStr);
GetObjectHandle
GetObjectHandle returns the Dispatch Handle value for an embedded object within Extend-
Sim. This is useful if your outside code is dealing directly with Dispatch Handles, since it will
allow you to communicate directly with the embedded object inside the ExtendSim application
without going through ExtendSim’s interfaces. The DispID of GetObjectHandle is 101.
getVariant = malloc(sizeof(VARIANTARG)*3);
argStr = SysAllocString((WCHAR *) L"Dialog Item Name");
VariantInit(&getVariant[0]);
getVariant[0].vt = VT_BSTR;// could be a long or a real
getVariant[0].bstrVal = argStr;
VariantInit(&getVariant[1]);
getVariant[1].vt = VT_I4;
getVariant[1].lVal = 23; // blockNumber
// Call IDispatch::Invoke()
hr = m_pDisp->Invoke( getID, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_METHOD, &dp, NULL, &ei, &uiErr);
SysFreeString(argStr);
SysFreeString(argStr2);
124 IDE
OLE and ActiveX Automation
This chapter is specific to using ModL functions for performing 2D and 3D animation.
2D animation
The functions listed in “2D Animation” on page 270 make it easy to add 2D animation to
blocks. This section discusses the general procedures in creating 2D animated blocks, then
shows some examples of how you might add 2D animation to the blocks you build.
Overview
☞ Even if Run > Show 2D Animation is not selected, it is still possible to display 2D animation.
The Show 2D Animation command (Run menu) and the Show 2D Animation button in the
Model toolbar only control whether animation is shown during the simulation run. At all other
times, the block will still show animation if the block creator has coded it to do that. For
instance, animation is available when the modeler makes any changes in a block's dialog,
whether Show 2D Animation is selected or not and regardless of whether the simulation is run-
ning. (Of course, when the command Show 2D Animation is selected, animation is available at
all times.)
IDE
Showing animation outside of a simulation run is a powerful feature because it lets you build
blocks which show their initial status or final values without having to turn on 2D animation.
For example, if a check box is clicked, the dialog can send an “on myCheckBox” message to
the block and the block can animate the change on its icon, as seen for the Miles block in
“Adding 2D animation” on page 53.
Steps
As shown in “Adding 2D animation” on page 53 and described in detail below, the basic steps
for adding 2D animation to a block are:
1) Decide how you want the block to animate, including the shape and color that the anima-
tion objects should have.
2) Create the 2D animation objects in the Icon tab of the block’s structure window. Do this
either by placing an animation object on the Icon tab manually or dynamically through
block code.
3) Initialize the animation objects in the CheckData or InitSim handlers.
4) Add code to update the animation object at the correct times, including (if necessary) code
to slow the display so that it isn’t too fast to be seen.
• For continuous blocks, this code will be in the Simulate message handler.
• For discrete event or discrete rate blocks, this code will be in the function or message
handler appropriate for the data that you want animated. (For example, if you are ani-
mating an item entering a block, the code would go in the ItemIn message handler.)
☞ Some animations (such as moving or stretching) will cause simulations to run slower than other
types (for example, changing color or text).
While it is common that icons are animated, it is also possible to animate in the area around
icons. See the Planet Dance model (located in the folder ExtendSim/Examples/Continuous/
Custom Block Models) for an example of a model that shows animation outside of the icon.
Also see the blocks in the Item library for examples of animating from one block to the other,
along connection lines.
Creating 2D animation objects
All 2D animation is done through the use of one or more animation objects that you put in the
Icon tab of the block’s structure. The animation object itself is a resizable rectangle with dotted
sides, identified by a unique number .
☞ Animation objects are always rectangles in the icon pane. As discussed below, the animation
functions in the block’s code determine the characteristics of the object, for example, the shape
and color that will show as the block is animated.
IDE
To create an animation object:
In the Icon toolbar, select the Animation Object button; it is at the bottom or right side of the
toolbar, depending on how the toolbar is oriented
Click in the Icon tab to place the object and resize as desired. Since this
is the first animation object, it will have a “1” in it, as shown at right.
You will use that object number in all of the animation functions that
call this object.
☞ 2D animation objects can also be created “on-the-fly” using the AnimationObjectCreate func-
tion.
Each animation object has a Proper-
ties dialog that can be accessed by
right-clicking on the object. This dis-
plays information such as the Object
ID and allows you to set the exact
position and dimensions of the object
directly in the structure of the block.
If animation objects are layered on top
of each other, the zOrder allows you
to set where in the layer each object
will be.
Initializing animation objects
In the block’s code, initialize the object in the InitSim message handler. If you always want the
animation object visible, even before an animation is run, put the same code in the CreateBlock
handler.
The initialization will generally consist of a call to one of the object definition functions (Ani-
mationOval, AnimationRndRectangle, AnimationPoly, and so forth), a call to AnimationE-
Color (to set the color for the object). It might also include a call to AnimationShow so that the
object is visible at the beginning of the simulation (for example, for showing initial text or
color). Here is an example:
128 IDE
2D animation
on initSim
{
AnimationOval(1); // Set 1 to oval
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
AnimationEColor(1, color); // Set 1 to the EColor value
AnimationShow(1); // Optional
// makes object visible
}
☞ If you define the animation object in the code as an oval, and resize it on the icon as a square, it
will show as a circle. If you define it as an oval and resize it as a rectangle, it will show as an
oval.
The color of an animation object is set with numbers for hue, saturation, and brightness
(value), often called HSV. Use the Fill Color button in the Shapes toolbar to determine the
HSV values of any color.
IDE
If you want a block to see whether or not the Run > Show 2D Animation command is checked
(for example, to hide the animation object if animation is not on), use the AnimationOn system
variable in the CheckData or InitSim message. It is set to TRUE (1) if animation is on and
FALSE (0) if it is not. For example, instead of the preceding initialization, you might have:
on initSim
{
AnimationOval(1); // Set 1 to oval
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
AnimationEColor(1, color); // Set 1 to the EColor value
if (AnimationOn) // Animation is on
AnimationShow(1);// Optional: show 1 now
else // Animation is not on
AnimationHide(1, FALSE); // Hide object; it is not
// outside of icon
}
IDE
to animate the first animation object with the correct number that it finds.
☞ If more than one hierarchical block has an animation object with the same number, the lowest
one above the controlling block will be the one that is animated.
Showing and hiding a shape
An animation object could be displayed if an input value met some condition or became true,
or if an item arrived in the block or was being processed. Hiding the animation object would
then indicate the opposite condition. You could have a small object near the connector to indi-
cate item arrivals or meeting a condition, such as the Select blocks (Value library). Or you
could have a larger object indicating a true value or processing, such as the Activity blocks
(Item library).
This example uses the animation object drawn above. You want a solid red circle to appear in
the icon when a value is true (greater than 0.5) and you want to hide it when the value is false.
To do this, initialize the animation object and hide it in InitSim. Then put code in the Simulate
message to indicate when and how the object should change:
on initSim
{
AnimationOval(1); // Set 1 to oval
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
AnimationEColor(1, color); // Set 1 to the EColor value
AnimationHide(1, FALSE); // Hide object; it is not
// outside of icon
}
on Simulate // Or appropriate function or message handler
{
...;
if (AnimationOn && ConditionIsTrue) // if both true
AnimationShow(1); // Show object now
else
AnimationHide(1, FALSE); // Else hide object; it is not
// outside of icon
}
130 IDE
2D animation
Moving a shape
Assume that you want the animation object drawn above to move between the original position
and a position 20 pixels higher than the original depending on the values received. The input at
the connector called “con1in” takes in real values from 0 to 1, with 1 indicating the highest
desired input. Since, in screen coordinates, up is considered negative relative to the starting
position, you must call AnimationMoveTo with a negative number to move the object up. Your
code might be:
integer obj1Loc; // Save the object’s location
real clipped;
integer testLoc;
. . .
on initSim
{
AnimationOval(1); // Set 1 to oval
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
IDE
Changing a level
Sometimes you want to display a changing level, such as in a water tank. For this example, use
the animation object drawn above. A simple block that displays a changing level when its input
connector varies between 0.0 (lowest level) and 1.0 (highest level) might look like:
on InitSim
{
// Initialize animation object number 1 as a “level” shape
AnimationLevel(1, 0.0); // Initialize level to low
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
Animation Using ModL 131
2D animation
if (AnimationOn) // Animation is on
AnimationShow(1); // Show level now
else // Animation is off
AnimationHide(1, FALSE); // Hide level; it is not
// outside of icon
}
on simulate // Or appropriate function or message handler
{
AnimationLevel(1, con1in); // Input connector value (0.0 to 1.0)
// controls the height of the level
}
To have the level reflect values other than 0 to 1, scale the input values to correspond to that
range. See the Holding Tank block (Value library) for an example of changing a level.
Stretching a shape
IDE
You can stretch an animation object horizontally or vertically, or both at
the same time (circular), relative to its original position on the icon. For
example, do this to show the relative size of an item (for instance, based
on an attribute value) or to indicate a direction of flow.
The following code stretches the object vertically inside the icon. This
method uses the exact size of the animation object as it is drawn on the
icon to determine the boundaries for the stretch. The input at the connec- Object for stretching
tor called “con1in” takes in real values from 0 to 1, with 1 indicating the
highest desired input. For this example, draw an animation object like the image shown here.
integer origWidth, origHeight; // Boundaries of the object
integer pixels; // How far to stretch
real clipped; // Amount to change
. . .
on InitSim
{
AnimationRectangle(1); // Set 1 to rectangle
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
AnimationEColor(1, color); // Set 1 to the EColor value
origWidth = AnimationGetWidth(1, TRUE); // Get original width
origHeight = AnimationGetHeight(1, TRUE); // Get original height
if (AnimationOn) // Animation is on
AnimationShow(1); // Show object now
else // Animation is off
AnimationHide(1, FALSE); // Hide object; it is not
// outside of icon
}
132 IDE
2D animation
between. Typically you do not know how blocks will be connected until the model is built.
Therefore you must determine the values of these parameters by using function calls to
MyBlockNumber, GetConNumber, and GetConBlocks. You can call the functions from any
block, provided it knows which block is sending and which is receiving.
The following code example illustrates how to determine the appropriate parameter values and
make a call to AnimationBlockToBlock. In this example, AnimationBlockToBlock is called
from the “sending” block (the block from which the picture will start moving). The picture will
move to the “receiving” block connected to the con1Out connector of the “sending” block.
integer array[][2];
...
on InitSim
{
AnimationPicture(1, “MyPicture”); // Set object 1 to picture
myNumber = MyBlockNumber(); // determine “sending” block #
IDE
// determine “sending” connector #
outCon = getConNumber(myNumber, “con1Out”);
getConBlocks(myNumber, outCon,array); // what blocks are connected
// to con1Out?
rBlock = array[0][0]; // determine “receiving” block #
rConn = array [0][1]; // determine “receiving” connector #
}
on simulate
{
// animate picture between blocks
AnimationBlockToBlock(1,myNumber,outConn, rBlock, rConn, 1.0);
}
Changing a color
To use a change in color instead of motion, include a call to AnimationEColor with a variable
for one of the hue, saturation, or brightness (value) arguments:
on InitSim
{
hueVal = 0;
AnimationOval(1); // Set object 1 to oval
//create an EColor value of red with an opaque alpha channel
Color = EColorFromHSV(0, 255, 255, 255);
AnimationEColor(1, color); // Set 1 to the EColor value
if (AnimationOn) // Animation is on
AnimationShow(1); // Show object now
else // Animation is off
AnimationHide(1, FALSE); // Hide object; it is not
// outside of icon
}
134 IDE
2D animation
Changing text
You can also animate by changing text in the animation object created at the beginning of this
section.
☞ Using AnimationText() causes a white background around animated text. To not have this,
instead use the function AnimationTextTransparent() as is done below.
IDE
string objText;
on InitSim
{
AnimationTextTransparent(1, ""); // Set object 1 to blank text
//create an EColor value of black with an opaque alpha channel
Color = EColorFromHSV(0, 0, 0, 255);
AnimationEColor(1, color); // Set 1 to the EColor value
if (AnimationOn) // Animation is on
AnimationShow(1); // Show object now
else // Animation is off
AnimationHide(1, FALSE); // Hide object; it is not
// outside of icon
}
on simulate // Or appropriate function or message handler
{
. . .
if (temp < 1000) // Less than 1000
objText = "Cool";
else if (temp < 1500) // Between 1000 and 1500
objText = "Med";
else // Greater than 1500
objText = "Hot";
AnimationTextTransparent(1, objText); // Set the text
. . .
}
Animating pixels
You can generate a rectangle of pixels where each pixel can be a different color based on the
value for that pixel. For example, use this to generate a contour map or give visual display of
temperatures over a two-dimensional space. For an example of this, see the Mandelbrot model
located at Documents/ExtendSim/Examples/Continuous/Custom Block Models.
Animation Using ModL 135
3D animation
3D animation
The ExtendSim 3D (“E3D”) window provides a fully three-dimensional representation of the
world of the model. The objects modeled in the window maintain information about their posi-
tions in three dimensions as well as other physical properties of their representations. The win-
dow is also tightly integrated with the rest of the ExtendSim simulation engine. Every motion
of every object, every aspect of things that happen in the 3D world, can be controlled from the
ModL programming language.
☞ 3D animation is only available in ExtendSim Pro.
☞ This chapter presumes you have read the information about using the E3D window and envi-
ronment in the ExtendSim User Reference.
About the 3D chapter
This chapter provides information for those interested in code development within the E3D
development environment. It is organized into the following sections:
IDE
5) Overview, including a brief discussion of the Torque Game Engine (TGE), upon which the
E3D environment is based
6) Manipulating existing objects, such as adding a mount point or additional skins
7) Building new objects such as people, vehicles, and so forth
The focus of this chapter is on providing a high-level description of the E3D environment, with
explanations where the E3D environment differs from the TGE.
In many cases the E3D environment uses standard TGE constructs, and they will not be
repeated here. Instead, see the GarageGames website at www.GarageGames.com for complete
details about TGE constructs, including DataBlocks and Torque Scripts.
Overview
The Torque Game Engine and the E3D environment
For 3D animation, ExtendSim incorporates its own development environment, a compiled ver-
sion of the Torque Game Engine (“TGE”), Torque Script files, and numerous 3D functions for
communicating with the E3D window. Together this is termed the E3D development environ-
ment. The TGE is a powerful 3D rendering architecture that GarageGames (www.Garage-
Games.com) licenses as a source code development environment.
Since the E3D environment is open-source, you can modify the animation capabilities of exist-
ing blocks, create entirely new 3D-enabled blocks and 3D objects, and modify object behav-
iors for specialized applications. ExtendSim has numerous ModL functions for defining the
custom behavior of 3D objects and events; the Torque Script scripting environment provides
additional control over the animation environment and object behaviors.
Note that the running of a simulation is not necessarily a part of the model’s control of the E3D
window content. The Boids model (located in the \Examples\3D Animation folder), is an
example of a model that uses custom blocks and does not utilize the simulation loop to control
the behavior of the objects in the model.
☞ If you are serious about developing extensive 3D simulations with ExtendSim, and you want
direct access to the TGE API, consider purchasing at least an “indie” license for the TGE.
More information about the TGE can be found at www.GarageGames.com. (Even if you don't
plan to do any development with the engine, this will allow access to the developer forums.)
136 IDE
3D animation
Performance considerations
The E3D window is doing a complete textured rendering of a complex 3D environment, so the
number of objects being rendered and the capability of the hardware on which the software is
run will have an effect on the performance of the E3D window. See the User Reference for
some suggestions for improving performance.
Modes of E3D animation
Each model has a saved 3D animation mode – QuickView, Concurrent, or Buffered, as dis-
cussed below. These modes are selected in the Run > Simulation Setup > 3D Animation dialog
and control aspects of the interaction between the ExtendSim application, the E3D window,
and the blocks’ ModL code.
The 3D animation modes are
discussed fully in the E3D mod-
ule of the User Reference. The
following is meant to be supple-
mental to that information.
IDE
Quickview
Quickview is the default mode
and allows a model to display its
behavior in the E3D window
without being extensively modi-
fied. In this mode most of the
blocks at the top level of the 2D
model will have a representation
in the E3D window and a 3D
object’s position will corre-
spond to the location of the cor-
responding block in the 2D 3D Animation tab in Simulation Setup dialog
model. However, QuickView
mode uses the immediate func-
tions (discussed in “Types of 3D ModL functions” on page 137) so only one object will move
at a time. This mode allows the modeler to get a quick 3D view of the simulation with minimal
customization of the model.
Concurrent
The Concurrent mode is more commonly used for a model that has been designed or modified
to specifically support E3D functionality. In this mode, multiple items can be moving in the
E3D window at one time and the locations of the blocks in the 2D model don't necessarily cor-
respond to the locations of the objects in the E3D window.
In Concurrent mode events are posted internally with the E3DPost functions. This causes cer-
tain events, such as the creation of an object or an object moving, to be put into a queue to be
performed later. (For more information about the E3DPost functions, see “Types of 3D ModL
functions” on page 137)
An additional aspect of Concurrent mode is that the simulation engine will pause with each
E3DPost function call until the currently posted call has begun processing. This assures that
the simulation and the E3D window keep in sync, but it adds the additional requirement that
the 3D events posted by the model need to be posted in time order (earlier before later). Note
that this is handled automatically by the blocks in the Item library.
Animation Using ModL 137
3D animation
Buffered
Buffered mode is a variation on Concurrent mode, where the information about what should
happen in the E3D window is stored in an internal buffer and replayed later.
As is true of the Concurrent mode, the Buffered mode posts events internally using the
E3DPost functions. (For more information about the E3DPost functions, see “Types of 3D
ModL functions” on page 137.) However, one advantage of the Buffered mode, which only
applies to models built with custom blocks as opposed to models that use the Item library
blocks, is that the events posted with the E3DPost functions do not necessarily need to be
posted in order. This is because the events are queued in the buffer and sorted.
Time ratios and 3D event queues for the modes
As discussed in “Distance and time ratios” on page 137, each simulation time unit will by
default take one second to display in the E3D window. In Concurrent and Buffered modes the
simulation time to real world clock time ratio is carefully respected. In these modes, almost all
of the actions the blocks take in the E3D environment are posted using the E3DPost functions
(see “Types of 3D ModL functions” on page 137) which specify simulation time as the first
IDE
argument of the function call. Internally, ExtendSim maintains a list of the posted events and
processes them at the correct time. This means that multiple events can happen at the same
time and multiple objects can be moving at the same time.
☞ The event queue maintained by the E3D window is independent from the event queue main-
tained by the Executive block.
Types of 3D ModL functions
There are two broad categories of functions that manipulate the 3D objects in the E3D win-
dow:
• Post functions. Each of these functions starts with E3DPost and contains as its first argument
the simulation time value when the function should occur. In many cases, such as in the Item
library, this value will be current time. However there is no reason why a custom implemen-
tation could not use more distant future values.
As discussed in “Modes of E3D animation” on page 136, the post functions are used in the
Concurrent and Buffered animation modes and have the effect of putting the E3D commands
into an internal queue. This queue of commands will be executed in time order by the simu-
lation engine. In Concurrent mode the execution will be immediate; in Buffered mode it will
be delayed until the user clicks on the Start button.
• Immediate functions. These functions do not have a time value associated with them and
they take place immediately. Thus they lose the connection between simulation time and
E3D window time that the Post functions have. An example of a model that uses immediate
functions rather than Post functions would be the Boids model (Examples\3D Animation),
which doesn't even run a simulation.
In Concurrent and Buffered modes, time in the E3D window is related to ExtendSim simula-
tion time by the time ratio defined in the Run > Simulation Setup > 3D Animation dialog
shown on page 136. By default this ratio is 1 simulation time unit to 1 second of real time. For
example, if a simulation is set to take 60 time units, it is in Concurrent mode (using E3DPost
calls to establish events in the E3D window), and the E3D window is open, the animation in
the E3D window should display for 60 seconds.
☞ In QuickView mode the time relationship between simulation time and real time is not pre-
served, so the time ratio defined in the Simulation Setup dialog does not have an effect for that
mode.
References
Read the 3D Animation module in the ExtendSim User Reference before doing any 3D devel-
opment work.
The GarageGames web site (www.GarageGames.com) is useful for finding additional
resources when developing in the E3D environment, contacting consultants for custom work,
and asking questions about the Torque engine.
IDE
There are also several books about the TGE. They tend to be focused on game development
but also contain invaluable information about development with the TGE that will in large part
translate directly into working with the E3D window. A couple of books to consider are: “3D
Game Development All In One” and “The Game Programmers Guide to Torque”.
A complete discussion of the TGE is beyond the scope of this document. Instead, there is
extensive information about the Torque scripting environment, as well as the default layout
and behavior of TGE scripts, on the GarageGames website at www.GarageGames.com.
Manipulating object behaviors and appearances
Objects in the E3D environment have many properties that define how they look, behave, and
interact with the 3D window and with the ExtendSim simulation engine. The following sec-
tions define some of these properties, describe how they work within the context of the E3D
environment, and how you can change or adjust them.
E3D object names and labels
There are two object name-type properties that are used and referenced in ExtendSim – the
name field in the World Editor Inspector and the object label that is displayed along with the
object in the E3D window.
Name field
The Name field is at the top of the Inspector pane of the World Editor Inspector. This field is an
optional text identifier for the object that can be set either in the World Editor or through the
E3DSetName function. The name of an object can be used in ModL functions to locate an item
by name, rather than numerically with the objectID value (see “ObjectIDs, userTags and
groupTags” on page 139.) If used, the name of an object will also appear in the Editor in text
drawn on the item following the objectID.
Object label
The other name-like property is the object label. This is set with the E3DSetObjectLabel func-
tion and produces a visual label that is displayed above the object in the E3D window but not
in the World Editor Inspector’s Inspector pane. You can also change the color of the text of the
object label.
Animation Using ModL 139
3D animation
☞ To display text in the E3D window without having a visual object associated with it, create a
waypoint and set its object label. Waypoints are invisible, but the object label will still be
drawn. For instance, this is how the 3D Text block (Animation 2D-3D library) displays text.
ObjectIDs, userTags and groupTags
ObjectIDs, userTags, and groupTags are the numeric properties associated with objects in the
E3D window. Many of the 3D functions have arguments that refer to these numeric properties.
ObjectIDs
The objectID is the main identifier that the E3D window uses to identify the objects it needs to
support. There is a unique objectID value associated with each object in the E3D window. This
includes not just the objects that are created from ModL code, but also all of the objects that
the window uses as the basic building blocks of the 3D world.
☞ Names can also be used by ModL functions to locate objects, as discussed in “E3D object
names and labels” on page 138.
For example, the Camera object (described in the User Reference) has an objectID. This allows
IDE
you to call any of the ModL functions that take an objectID value on the Camera and facilitates
features like setting the position of the camera dynamically to track a moving object. This is
shown in the 3D Animation\Tips\E3D Path model.
For Concurrent and Buffered mode models, which internally call the E3DPost functions
instead of the immediate functions (as discussed in “Modes of E3D animation” on page 136),
the objectID will not be available at the time the function is called. This is because the objec-
tID is created by the E3D window code when the object is instantiated in the 3D world. In
these modes a temporary userTag is created to identify the object, as discussed below.
☞ UserTags should be used for all “post” functions. You should only use the objectID when you
are sure that the object will exist at the time the function is called.
UserTags
As shown in “Modes of E3D animation” on page 136 and “Types of 3D ModL functions” on
page 137, the Concurrent and Buffered modes call the E3DPost functions. At the time the
E3DPost function is called, the simulation time when the object will be created may not yet
have been reached. So operations on the object are put into a queue to be performed later. This
means that a temporary value, a userTag, needs to be created that will be used to identify the
object before it is created. The userTag is the value that will be returned by the E3DPostCreate-
Object that schedules the creation of the object.
The userTag is used to identify the object until it is actually created in the 3D window. How-
ever, once the object is created and an objectID has been established, the userTag is still avail-
able and each object will have both a userTag and an objectID. Thus the object can be referred
to by either its userTag or its objectID; they are distinguishable from each other by the fact that
userTags are negative and objectIDs are positive.
☞ UserTags should be used for all “post” functions. You should only use the objectID when you
are sure that the object will exist at the time the function is called.
There are ModL functions to convert userTags to ObjectIDs (see the function list in “3D Ani-
mation” on page 276).
GroupTags
GroupTags are another numeric tag on the objects in the E3D window that are specified at the
time of object creation and also stay with the object throughout its lifetime. Unlike userTags
140 IDE
3D animation
and objectIDs, groupTag are not unique identifiers but rather are used to define groups of
objects that the developer wants to be able to reference as a whole.
A common example of how groupTag are used is in the Item library, where each of the items
that travels from block to block is tagged as being part of the same group. This allows the
blocks to delete all of these items as a group when one simulation ends and a new one begins,
without deleting other objects that need to remain for the next run.
☞ By default an object created in the World Editor will be supplied with a groupTag value of 0.
The Item library uses the value of 1 for items that travel from block to block.
E3DDeleteAllObjects takes a groupTag argument and will delete all objects in the E3D win-
dow with that groupTag number. If you pass in a negative 1 or lower, the function will ignore
the groupTag and delete all objects in the E3D Window.
E3DGetObjectNames takes an argument for which kind of objects the function should return.
If you pass in a number greater than zero, that number will define a groupTag and the function
will return the names of the objects in that group. See the function list in “3D Animation” on
page 276 for more detailed information about exactly how these functions operate.
IDE
Object classes
ExtendSim defines several classes of objects in addition to the class structure of object types
defined by the TGE.
All ExtendSim 3D objects descend from ExtendBase, which gives them certain common fea-
tures as described in “DataBlocks” on page 151. Which class a new object falls into will be
defined in its DataBlock. The complete class structure of the objects in the E3D window is
beyond the scope of this documentation.
ExtendItems
ExtendItems are intended to represent the items that pass from block to block in an ExtendSim
model. They have several features:
• They do not support physics features like gravity, friction, and momentum. This is to pre-
serve the synchronization between the simulation and the 3D animation. See “Gravity” on
page 145.
• ExtendItems support the DataBlock variable hasFront, which allows the object to continu-
ously turn toward the direction that it is traveling.
• They support mountStacking and therefore should have a mount0 on the top of the object
and a mountPoint on the bottom. See “MountStack” on page 144 for more information.
ExtendPlayers
ExtendPlayer objects (Male and Female) are based on the AIPlayer class in the TGE. Some
information about them includes:
• Unlike Torque AIPlayer objects, ExtendPlayer objects do not attempt any AI calculation
• Like ExtendItems, they avoid momentum and friction calculations
• They do support gravity. If created at a Z height of greater than 100.0 they will drop to the
ground. See “Gravity” on page 145.
ExtendVehicles
ExtendVehicle objects (Car, AGV, and Forklift):
Animation Using ModL 141
3D animation
• Are similar to ExtendPlayer objects in how they differ from standard Torque objects
• Like ExtendPlayer objects, they support gravity but not friction or momentum
• Do not have any AI calculations
IDE
might see “1.1 0.5 1.0” in the Inspector pane, which would be scaling to 110% on the X axis,
50% on the Y axis, and 100% on the Z axis.
Object position uses the same format as scale, and the X, Y, and Z values represent the X, Y,
and Z coordinates of the object. Changing the X value from 1 to 2, for example, will move an
object 1 meter along the X axis. The default Z values for objects will be a bit above 100.0 since
the flat terrain in the default E3D window is at height Z = 100. See “Gravity” on page 145 for
more information.
Rotation
The User Reference describes how to visually rotate objects in the World Editor, through block
dialogs. Another method of rotating objects would be by changing the numbers in the Inspec-
tor pane.
The World Editor Inspector has four numbers for rotation – three factors and an angle in
degrees – where each factor represents the x, y, or z axis respectively. Each multiplier deter-
mines the amount by which the object is rotated around its particular axis based on the given
angle.
For example, “0 0 1 90.0” means that the object is rotated 90 degrees around the Z-axis while
“1 0 1 45.0" means that the object is rotated 45 degrees around both the X and the Z-axes. The
most common form of rotation in the ExtendSim modeling world is around the Z-axis, as this
will lead to rotation of the front of the object on the flat plane.
Skins
Skins is the 3D animators term for the texture files that show the surface details of objects in
the 3D world. Many of the 3D objects provided with ExtendSim come with more than one skin
You change which skin is showing on an object either through a block’s Block Animation tab
(Item library) or by using ModL functions calls. You can also define a new DataBlock to spec-
ify a new version of an object that uses a specific skin (see “DataBlocks” on page 151 and
“DataBlock variables” on page 153 for more information about them.)
How skins are defined
ExtendSim supports the naming convention “base.objectName.jpg” which allows developers
to add new skins or modify existing ones. This is specified as follows:
142 IDE
3D animation
• Base is the name of the default skin. To select a new skin, change this part of the name. For
example, the Ball object by default will load using the base.ball.jpg skin. To change the ball
object to blue, create a blue.ball.jpg and then either call the appropriate function or select the
skin on a block dialog.
• ObjectName is usually the same as the name of the object and it must be the same for each
skin of a single skin object. For instance, there are several skins in the folder with the Bed
object; the first is called base.bed.png and the others are called floral.bed.png, hospi-
tal.bed.png, and so on.
• The final part, jpg, is just the extension of the file type.
☞ Skins in ExtendSim will all be either jpg or png files.
Most of the objects that ship with ExtendSim have a single overall skin that can be changed.
The two people objects (Male and Female) however, have two skins each – one for the clothing
of the object and a second for the face and hands.
Two skin objects
IDE
The two skin objects, Male and Female, have the following skin patterns:
• Base.maleclothes.jpg
• Base.maleskin.jpg
• Base.femaleclothes.jpg
• Base.femaleskin.jpg
This allows the different skins to be combined in arbitrary fashions. For example, a given
object in the E3D window could be a Female with these two skin layers: Base.femaleskin.jpg
and Medical.femaleclothes.jpg.
Skin setting functions
The ModL function that sets the skins on an object is E3DSetSkin or E3DPostSetSkin, depend-
ing on the 3D mode. This function takes two string arguments for the skins.
• For single skin objects, just enter an empty string for the second string.
Animation Using ModL 143
3D animation
• In the case of double skin objects, enter both skin names. So, for the exam-
ple above, call E3DSetSkin once with the first string set to Base and the
second set to FemaleSkin, and then a second time with the first string set to
Medical and the second set to femaleClothes. (Note that, unless the object
had already had its femaleSkin changed from the base, the first call would
not be necessary, because the Base skin is already the default.)
Skin DataBlocks
There are four DataBlock variables for specifying skins, as seen in “Data-
Block variables” on page 153:
• SkinBaseName1
• SkinBaseName2
• SkinName1
• SkinName2
IDE
You can use these to cause special effects, such as overriding whether or not
to start with the base skin. For example, setting the skinName1 variable in the Female with
DataBlock will cause the object to be created with the skinName1 value in Medical skin
place of the base part of the skinName.
Mounting
Mounting is the process of attaching one 3D object to another at
certain points. An example would be mounting a Box object
onto a Male object. In this case, the Box object automatically
attaches to the mount0 mount node on the Male object. The
Male object then adjusts its animation to change its hand posi-
tion, so it looks like it is holding the Box. And if the Male is
given a destination, the Box will be carried along. All of the
ModL functions and internal structures are associated with
mounting objects, not images.
☞ See also “Carriable items” on page 154 and the functions for
mounting starting on page 286.
Each object has one mountPoint and at least one mount node.
These are internal structures of the DTS file (discussed on
page 149); if you create custom 3D objects these structures Male carrying a Box
should be added when the DTS file is created.
☞ An object’s mountPoint is the part of the object that can mount onto another object. An object’s
mount nodes are the point or points on the object where other objects can be mounted.
144 IDE
3D animation
If you instead want the internal logic in the ExtendSim application to select the node that the
object will be mounted to, specify that the node should be smart mounted. You do this by pass-
ing in a negative 1 for the node. ExtendSim will then select the best node to be used based on
the type of the mount object and the object to be mounted.
MountStack
One additional type of mounting, specific to ExtendSim, is the mountStack. A mountStack is a
stack of objects where each object is mounted on top of the previous one. The mountStack
functions E3DMountStackInsert, E3DMountStackRemove, E3DMountStackLimit, as well as
their Post versions, allow you to maintain a queue of stacked objects with less ModL code than
if you used the Mount and Unmount functions. The mountStack functions are on page 280.
Unmounting
Unmounting an object disconnects the objects from each other but does not change the position
of the objects. In the case of the Male and the Box above, unmounting the Box will leave it and
the Male n the same position but the Male will drop his hands. And if the Male moves away,
the Box will stay where it is.
The unmount functions also have options that allow you to specify a distance and a direction
for moving the unmounted object. See the function descriptions for more information.
Collision
E3D objects defined through ModL function calls can have collision enabled or disabled:
• Collision enabled causes the objects to respect each other's boundaries and to stop when they
bump into each other
• Collision disabled allows objects to pass through each other
It is a modeling decision whether or not you should enable collision for objects created at loca-
tions in your model. Collisions do allow items to line up as if in a waiting line, but in some
cases you will not want the objects to be stopped in their travel by colliding with another
object.
Animation Using ModL 145
3D animation
Gravity
Gravity is implemented in ExtendSim for certain types of objects and not for others.
• The people and vehicle objects will respect gravity. If created at a height or told to travel to a
Z location higher than 100, people and vehicles drop down to the ground.
• ExtendItem objects will not be effected by gravity and can travel at a fixed height or even to
a different height by simply setting a Z location higher than 100. The Boids example (Exam-
ples\3D Animation) shows this – the Boid objects fly through the air by setting 3D destina-
tion locations.
☞ To maintain the constant speeds associated with having travel times match simulation times,
the concepts of friction and momentum are not implemented in the objects that travel from
location to location in ExtendSim.
Sound
The E3D window supports playing sounds and has a few additions to the Torque Audio sys-
tem. Sounds can be either:
IDE
• Associated with objects in the E3D window. The IdleSound DataBlock variables are an
extension to the Torque Audio system so that sounds can be defined and played at automatic
times during a model execution. (See the list of sound variables in “DataBlock variables” on
page 153.)
• Played by ModL function calls, such as E3DPlaySound.
Sounds are globally enabled or disabled in the Edit > Options > 3D tab.
☞ Sounds played in the E3D window are 3 dimensional. Thus if you move the camera in the E3D
window away from or around a sound source, the volume and direction of the sound will
change.
The audio descriptions used in ExtendSim will commonly be either the AudioCloseLooping3d
description used by the BoidSound (a looping sound) or the AudioClose3d used by the Car-
SquealSound (a non-looping sound).
The other way to play a sound in the E3D window is to use the ModL function E3DplaySound.
This function, which you could use in an equation-based block if you aren't custom-coding
blocks, specifies the name of an audioProfile and an X, Y, Z location and plays that sound at
that location.
An example of an object’s ambient sound that is enabled in the E3D window is an Activity
block (Item library) when it is represented in the E3D window by the Machine object. If
sounds are enabled in the Options tab and the Machine is playing its “running” ambient anima-
tion (discussed on page 147), you will hear an active machine sound.
DataBlock of the Machine object
This DataBlock of the Machine object is from ExtendSim\Extend3D\server\scripts\ExItems.cs.
datablock StaticShapeData(Machine)
{
// Mission editor category, this datablock will show up in the
// specified category under the “shapes” root category.
category = "Block";
146 IDE
3D animation
datablock ExtendItemData(Boid)
{
// Mission editor category
category = "ExtendItem";
Ambient animation
DTS objects (objects that are not large-scale interiors or buildings, as discussed on page 149)
can have ambient animations – background behavior such as steam coming from a cup or peo-
IDE
ple breathing. These animations are of two types:
• Those used by the object based on the object type and predefined behaviors for that type. An
example is the “run” animation of the people objects. Whenever these objects are moving
they have internal code that plays the “run” animation, automatically adjusting the speed of
the animation based on the speed at which the object is moving.
• Those played by custom code. An example is the Cup object, which has a “Content” anima-
tion. If you start the Content animation running using the E3DAnimationPlay call, the Cup
will appear to be full of coffee and will have a wisp of steam rising from it. (To see this, cre-
ate a Cup object using the 3D Tester model located at \Examples\3D Animation\Tips and
activate the Content animation using the controls in the Animation group.)
Stop one ambient animation before starting another
Once you have started an ambient animation using the E3DAnimationPlay function, you might
think that you could start another animation using the same function and that would replace the
first animation. Due to the nature of the implementation of the animation threads, you should
stop the first animation using the E3DAnimationStop function before starting the second ani-
mation. In the Cup example, this means that you should stop the “Content” animation before
playing the “Empty” animation.
People objects
The people objects have several special ambient animation features:
• An idle animation (Root) that is always playing. This animation shows a small movement
and essentially makes it look like the people are breathing.
• A look animation that is always playing and controls the hand position of the person. See
also “DataBlock variables” on page 153 and “Looks” on page 155.
• An overall body position which includes sitting, sleeping, and so forth.
Both the look animation and the overall body position animation are automatically set by the
3D engine when the person does certain things. So for the most part you will not need to be
specifically setting animation threads on people objects.
148 IDE
3D animation
veyor belt and the machine is 1 meter from the ground, or 101 meters.
Creating a path
Paths can be created through ModL function calls or through the World Editor Creator. For
more information about creating paths with the World Editor, see the User Reference. The
ModL functions used to create a path are E3DCreatePath, E3DCreateMarker, and
E3DAddMarkerToPath; these functions are described on page 280.
By default paths are not visible. Setting a path to visible with the E3DSetVisibility function
will display the path in the E3D window; this is an extension of the E3D window over standard
Torque. You can also set the color of a path using the E3DpathSetColor function, which
changes how a visible path displays in the E3D window.
Waypoints
A waypoint can be thought of as a path with just one marker; they are often used as destina-
tions for object movement. Like paths and path markers they are invisible in the standard E3D
window but visible in the World Editor. There are a number of functions that refer to way-
points. (See the function reference for descriptions.) Waypoints can also be given object labels
with the SetObjectLabel ModL function, and can therefore be used as a way of displaying text
with no visible object on the viewing area of the E3D Window.
A waypoint can be created through ModL code or through the World Editor Creator in the
same way as other objects. In the World Editor Creator opening the Shapes > Markers category
reveals the WayPointMarker object. Clicking on the WayPointMarker object in the tree will
create a waypoint in the 3D viewing area. See the User Reference for more information about
using the World Editor Creator.
☞ The E3DSetVisibility function cannot be used to make a waypoint visible. Waypoints are never
displayed in the standard E3D window unless you have added an object label to them as
described in the Note on page 139.
Defining new 3D objects
While ExtendSim contains quite a few 3D objects, you might want to add additional ones.
Most of the 3D objects supplied with ExtendSim (such as people, items, vehicles and static
Animation Using ModL 149
3D animation
shapes) are in the DTS format. The following discussion describes how these small-scale 3D
objects are defined.
☞ Buildings or interiors are not usually DTS files. Instead they are DIF files as discussed on
page 155.
The steps involved in building a custom 3D object for use in ExtendSim are:
• Create the object in a 3D graphics program that supports exporting the object as a DTS file
• Export the object as a DTS file
• Create a script file/DataBlock for use in ExtendSim
• Add the script and DTS file to the correct places in the ExtendSim folder structure
IDE
plug-in for a 3D art program) to export a DTS file from a file saved in another format.
ExtendSim DTS file
As an example for developing new objects, see the Wall.dts file and the other files associated
with it; those files are located in the Extensions\E3DObjects folder. (The rest of the 3D objects
provided with ExtendSim are located in the ExtendSim\Extend3D\Data\Shapes folder, but new
objects should be put into the Extensions folder.)
Associated with the Wall.dts file are:
• A Wall.cs file. This is a script file that contains the definition of the wall object, mostly in the
form of a DataBlock. Script files run when the E3D window loads. (Script files are discussed
on page 150 and DataBlocks are discussed on page 151.)
The script for the Wall.cs file is discussed in “Example using Wall object” on page 152.
• The Wall folder which contains the Wall.dts file and the skins of the Wall object. As dis-
cussed in “Skins” on page 141, an object’s default skinBaseName1 will be the name of the
DTS file. In this example, because the Wall object is called wall.dts, the default skin-
BaseName1 is base.wall.jpg.
☞ All .cs files must be placed at the top level of the E3DObjects folder within the Extensions
folder, since that is the only place ExtendSim knows to look for them.
Adding a DTS file to ExtendSim
Place new script and DTS files within the Extensions\E3DObjects folder, with the script (.cs)
files at the top level. As noted above, ExtendSim looks for any .cs files only at the top level of
the E3DObjects folder. However, since the .cs file contains information about where the DTS
file is, the location of the DTS file is flexible.
☞ If you place a DTS file into the Extensions folder, but do not include a script file containing a
DataBlock, you will not be able to place the 3D object into the E3D window.
Exporting a 3D object file created in another program
Object files that have been created for other environments can be used in ExtendSim, but they
must first be exported into the DTS format. This is accomplished using DTS exporters.
150 IDE
3D animation
☞ This discussion is about DTS objects. DIF objects, for buildings and interiors, are discussed on
page 155.
DTS exporters are separate pieces of software that are available for several of the popular 3D
modeling packages (3DS Max, MilkShape, Maya, etc.). In most cases these modeling applica-
tions do not ship with an installed DTS exporter. You must obtain the appropriate DTS
exporter from Garage Games and add it to the modeling software package.
The procedure involves opening the object in the 3D modeling application and selecting an
export command. This varies depending on which application your files are in.
Exporting a basic shape that doesn't have any custom behavior can be quite straightforward.
Objects with more complex behavior, such as ambient animation or custom mountpoints, are
more involved. Most of these complex behaviors are defined in different ways for different file
formats, so most likely it will require some custom modifications to the 3D object.
Check for more information on the Garage Games website about which products have export-
ers available and how to install and work with those exporters.
IDE
IDE
• The “&” character refers to the folder containing the current model.
DataBlocks
A DataBlock is an object definition – the code definition of the initial values of properties of a
3D object as well as a definition of the type/class of the object. You could think of a DataBlock
as being like the definition of an ExtendSim block in a library. A DataBlock defines the com-
mon aspects and behavior of the 3D object, but each instance of the object will have its own
individual parameters associated with it.
The file ExItems contains many of the DataBlocks that have been defined for ExtendSim
objects; it is located at ExtendSim\Extend3D\server\scripts\ExItems.cs.
If you are not doing any extensive 3D scripting or adding custom 3D objects into the Extend-
Sim Extensions folder, you do not need to worry about DataBlocks.
☞ If you are adding multiple 3D objects it is not required that each object have a separate script
file. Instead, you can define multiple DataBlocks in a single script file.
Types of DataBlocks
When a DataBlock is declared, its type is also declared. While you can define your own types,
some typical types of DataBlocks that ExtendSim uses include:
• StaticShapeData
• WheeledVehicleData
• ExtendItemData
• PlayerData
• MissionMarkerData
This definition of the type of the datablock is important, since it will determine what kind of
object ExtendSim creates in the 3D window. For simple cases of placing new objects you will
most likely use ExtendItemData or StaticShapeData. The deciding factor is if the item is going
to be an immobile object (StaticShapeData) or a block-to-block object (ExtendItemData).
152 IDE
3D animation
DataBlock variables
There are many parameters that can be defined in a DataBlock. DataBlock variables are spe-
cific to the type of object that is being defined and can, in fact, be defined dynamically in the
DataBlock itself.
☞ Defining a new variable in a DataBlock will not have an effect on the object unless the variable
is referenced in the script or source code of the object.
Some typical DataBlock variables used by ExtendSim are:
• Category defines groupings that are used both in the Mission Editor and in certain ModL
functions to separate objects into convenient sets. The most common categories that you
would want to use are ExtendItem, Scenery, and Block.
• ShapeFile defines the location of the DTS file. For an example, see the ShapeFile of the Wall
block“Example using Wall object” on page 152.
• Scale defines the default scale of the 3D object. See also “Scale and position” on page 141.
For a list of DataBlock variables that have been specifically defined for ExtendSim or which
IDE
have been modified from how they are used by the Torque engine, see page 153.
ExtendSim-specific DataBlock additions
ExtendSim defines some custom DataBlock variables which can be set to customize the behav-
ior of objects. These are extensions to the 3D functionality defined in the ExtendSim applica-
tion.
As shown on page 145, sounds and ambient animation are examples of additional behaviors
that are enabled through DataBlocks. See also the list of customized DataBlocks on page 153.
Example using Wall object
The script file for the Wall object mentioned earlier only defines one thing – a DataBlock for
the Wall object. The code is:
// datablocks
// JSL - Scenery
datablock StaticShapeData(Wall)
{
// Mission editor category, this datablock will show up in the
// specified category under the “Scenery” root category.
category = "Scenery";
• Finally, the name of the datablock (Wall) is in parentheses. This is the name that will be used
in ExtendSim dialog boxes and script code.
The remaining lines of the DataBlock script define variables as discussed in “DataBlock vari-
ables” on page 152. For a simple object like the Wall, defining just three variables is sufficient:
• Category. For the Wall object, the Category is Scenery.
• ShapeFile.The path “./Wall/Wall.dts” indicates that the Wall.dts file is located within a folder
named “Wall”. The period (“.”) in the path name signifies that the path starts at the current
location; in this case in the Extensions\3DObjects folder where the .cs (script) file is located.
• Scale. As discussed in “Scale and position” on page 141, “1.0 1.0 1.0” specifies that the
object is scaled to its standard size in each of the three dimensions.
DataBlock variables
As discussed in “DataBlocks” on page 151, there are many variables supported in DataBlocks.
The following tables list a subset of the available variables – those that have been custom
IDE
developed for ExtendSim or which have custom behaviors compared to the standard Torque
DataBlocks.
Custom datablock variables
This table describes variables that have been defined and given custom behaviors for Extend-
Sim.
Variable Description
HasFront This DataBlock flag specifies that the object has a front. When the
item is specified as moving in a direction, the object will turn its front
in the direction it is facing. If this flag is not defined, it defaults to
false.
IdleSound[0-4] As described in “Sound” on page 145, this flag specifies one of up to
five sounds that can be associated with the item idling or with certain
ambient animation states.
IdleSoundAnimation[0- As described in “Sound” on page 145, specifies an animation state to
4] associate with a sound. See above for more information.
IdleSoundVol[0-4] Specifies the volume level for the idleSound. Volumes range from 0.0
to 1.0.
MountLook[n] Part of the ambient animation functionality discussed in “People
objects” on page 147. The mountLook flag specifies what look a per-
son is supposed to use when this kind of object is mounted on them.
The mount functionality is part of the carriableItem functionality
described on page 154.
SkinBaseName1 Defines the baseName for the first skin. An example would be the
Male object, where the SkinBaseName1 is maleClothes.
SkinBaseName2 Defines the baseName for the second skin. An example would be the
Female object, where the SkinBaseName2 is femaleSkin.
154 IDE
3D animation
Variable Description
SkinName1 Specifies what the default skin to be used for the object is. Objects
with multiple skins will obey the base.shapename naming convention,
so this variable tells the object what skin to use if you don't want the
object to start with the base skin.
SkinName2 This DataBlock variable specifies what the default skin for the second
skin should be. This is only relevant for objects with multiple skin
types. Currently only the people objects have more than one skin type.
StackMountPoint The mountPoint that will be used for the mountStack functions. This is
defined as 1 for the people objects so that mountStacking on them will
stack on their arms. However, if people objects stack on each other,
they stack on mountPoint 0.
UnmountLook[n] Part of the ambient animation functionality described on page 147.
The UnmountLook flag specifies what look a person is supposed to
revert to when this kind of object is unmounted from them. The
IDE
Variable Description
Carriable items
Mounting and unmounting objects was discussed on page 143 and page 144, respectively. Cer-
tain types of objects in ExtendSim are carriable items which can be carried by a person. This is
defined in the DataBlock by setting the ClassName variable to CarriableItem.
A carriable item call causes the look of the person to change when an object is mounted on
them. For example, when you mount a Box onto a person, they will move their arms to the
'lookbh' position. (The bh stands for box hold, as discussed on page 155.)
If an object that you expect to be carried by a person is not defined as carriable, people objects
will not change their look animation when mounted with the object and the look and feel of the
animation will suffer.
Animation Using ModL 155
3D animation
Example script
datablock ExtendItemData(Box)
{
// Mission editor category
category = "ExtendItem";
IDE
mountLook = lookbh;
unmountLook = look;
};
The mounting code will check to see if the object being mounted has a ClassName of Carri-
ableItem and if the object being mounted onto is a person. If both of these are true, it will use
the mountLook defined in the DataBlock as the new look for the person object. The unmount-
Look will be used as the look for the person when the object is unmounted.
Looks
The various looks supported for the carriableItems are:
• Lookbh. This is the “box hold” look associated with carrying a box. The person will spread
their arms low and outside the sides of the box.
• Lookph. The “pallet hold” look is associated with the pallet object. This look is similar to the
box hold, with a small variation in the position of the hands and arms.
• SuitcaseHold. This hold is for holding a suitcase, single-handed on the person’s right-hand
side. This look can be seen in the Airline Security model (Examples\3D Animation).
• SmallHold: This is for holding a small object like a letter or a stack of paper where both
hands are brought together in front of the person. This look can be seen in the Bank line
models (Examples\Tutorials\E3D Animation).
The DIF format is designed for buildings and objects on large scale. As with the DTS format,
various editors (such as Quark and Cartography Shop) can export DIF files. TGE owners also
get a DIF editor, called Creator, that is specifically designed to develop DIF files.
The creating and exporting process for DIF files can be involved, will be different for each edi-
tor, and is beyond the scope of this manual. Information for how to do this can be found on the
Garage Games website.
Terrain
ExtendSim's default environment file does not make much use of the terrain capabilities built
into the Torque engine. In fact, the blocks in the ExtendSim libraries assume that the terrain
will be flat and will be at a height of 100 units. So if you create models using the standard
ExtendSim environment and use the blocks in the Item library, you should not change from the
flat terrain defined in the default environment file. Changing textures of the terrain in the envi-
ronment file does not affect the behavior of the ExtendSim blocks.
For certain kinds of custom models, however, the ability to manipulate the terrain in the E3D
window might be quite useful. There are several things that can be changed and several mech-
IDE
anisms for how you change them. See the User Reference for information about editing Terrain
and changing Terrain Textures.
Integrated Development
Environment (IDE)
Simulation Architecture
Keep this information in mind as you
create and modify ExtendSim blocks
This chapter describes how the ExtendSim simulation engine works and how discrete event
and discrete rate blocks pass messages and resolve logic issues. This is important information
when you are creating or modifying blocks, since you need to know:
• How the block will work with the ExtendSim simulation engine
• How the block will work with the other blocks that ship with ExtendSim
Running a simulation
It is useful to understand the steps that ExtendSim takes when it runs a simulation so you can
get a feeling for what parts of the process are relevant to models. The following sections give a
step-by-step breakdown of how ExtendSim runs simulations and how it decides what to do
next.
☞ Running continuous simulations starts on this page; running discrete event and discrete rate
simulations is discussed starting on page 162.
How ExtendSim runs continuous simulations
ExtendSim keeps many system variables handy so that it can compute how to run the model.
IDE
Five of the options in the Continuous tab of the Run > Simulation Setup dialog become vari-
ables that are used to determine how the model is run:
Option Variable
End time EndTime
Start time StartTime
Runs NumSims
Time per step (dt) DeltaTime
Number of steps NumSteps
Before anything else happens in the simulation run, these variables are used to calculate an ini-
tial value for the DeltaTime or NumSteps variables. The variable that is calculated depends on
what is selected in the Simulation Setup dialog: if Number of steps is selected, ExtendSim cal-
culates the related variable DeltaTime; if Time per step is selected, ExtendSim calculates Num-
Steps. The formulas used are:
DeltaTime = (EndTime-StartTime)/(NumSteps-1);
NumSteps = Floor (((EndTime - StartTime) / DeltaTime) + 1.5)
This initial value is the value that the blocks see during the PreCheckData, CheckData, and
StepSize simulation messages.
Pseudocode of the simulation loop for continuous simulations
The following is a pseudocode description of ExtendSim’s continuous simulation loop.
Pseudocode is used by developers to describe the controlling logic of a program in a form that
is a cross between English and a programming language.
Simulation Architecture 159
Running a simulation
IDE
Abort Simulation and select bad block;
Send StepSize to blocks;//Continuous models can change
// stepsize
Send InitSimMsg to blocks;// Initialize block variables
Send PostInitSimMsg to blocks;// Check initializations
}
CurrentTime = CurrentTime+DeltaTime;
}
the various blocks should check the values of dialog items to see if they are valid. If any of
them abort, ExtendSim recognizes that fact and the simulation aborts with the block
selected. Connection status of the block can be tested during CheckData: Input connectors
that are connected will show a non-zero value, and unconnected input connectors will show
a zero value. This is useful in determining if a block’s inputs are actually connected in the
model.
The StepSize message is then sent to all blocks. In continuous models, StepSize is used to
manipulate the DeltaTime variable. The smallest value of DeltaTime specified by any block is
found and DeltaTime is set to that value. Note that this DeltaTime overrides the value initially
calculated. If AutoStep Slow was selected, the returned value of DeltaTime is then divided by
5 for more accurate simulation results. The Filter blocks (Electronics library) use the StepSize
message in this way because they need a calculated value of DeltaTime to get accurate results.
Finally, a new value of NumSteps is determined based on DeltaTime, StartTime, and EndTime.
The formula is:
NumSteps = Floor(((EndTime - StartTime) / DeltaTime) + 1.5)
This value is used to govern the actual simulation loop.
☞ Because DeltaTime is used to calculate NumSteps and a rounded value is used for the number
of steps, it is possible for the EndTime of the simulation to be exceeded slightly.
The InitSim message is then sent to all blocks. This message handler is used to initialize vari-
ables within each block. After the InitSim message has been sent to all blocks, the PostInitSim
message is sent and gives the developer a chance to initialize any variables that needed all of
the other blocks to be initialized first.
Table of message handler purposes
The following table lists the major purposes of the messages sent during the initialization loop
for Value library blocks. Notice that some purposes only apply if the Value library block is
used in a discrete event, rather than a continuous, model.
☞ While the table lists the major purposes of the message handlers, a purpose can sometimes be
accomplished using a different message handler than the one indicated.
Simulation Architecture 161
Running a simulation
IDE
PostInitSim Initialize connector values
Schedule events in discrete event models
☞ For the Data Import Export and Command blocks, initialization message handlers can be
selected using options in the blocks’ dialogs.
Step loop
The inner loop:
for CurrentStep = 0 to (NumSteps-1)
is where Simulate messages are sent to all of the blocks in the order determined by the connec-
tions. In continuous simulations the loop is governed by CurrentStep and NumSteps only.
NumSteps is the variable that is used to end the simulation, and the actual number of Simulate
messages (steps) that occurs is NumSteps. That is, if 2 is entered for the Number of steps
option in the Continuous tab of the Simulation Setup dialog, NumSteps becomes 2, the simula-
tion step loop sends Simulate messages to the blocks for CurrentStep equal to 0, and than 1. (If
you want to run a simulation for only a single step, set Number of steps to 1.)
CurrentTime is incremented by DeltaTime for each step of the loop, but otherwise has no effect
on this loop. This means that you can change CurrentTime and DeltaTime without affecting the
loop. It also means that you can change CurrentStep or NumSteps to keep the loop running lon-
ger or stop it prematurely.
☞ You can set CurrentTime in any block to any value, although you might want to have some
logic in the ModL code to prevent conflicts between blocks setting CurrentTime after other
blocks have already changed it. Use the ExtendSim global variables to help establish some
safeguards against these conflicts. For instance, this is how the Executive block (Item library)
is able to control the progression of time in discrete event models.
Final messages
Upon completion of the simulation, ExtendSim sends out the FinalCalc system message to all
blocks. This message handler is used to perform final calculations for all time-dependent sta-
tistics.
162 IDE
Running a simulation
The Report Manager block (Value library) then sends the BlockReport system message to any
blocks that have been selected for a report. This message handler is responsible for writing all
report data to the appropriate ExtendSim database tables.
Finally, ExtendSim sends the EndSim system message to all blocks. The EndSim message han-
dler is used for any “clean up” activities such as disposing of any dynamic arrays to free up
memory.
Aborting multiple simulations
If the Abort statement is executed during the simulation, it only stops the current simulation. If
you want to abort all simulations (for example, when you have specified in the Simulation
Setup dialog that more than one simulation should be run), use the AbortAllSims() function
instead of the Abort statement.
How ExtendSim runs discrete event or discrete rate simulations
ExtendSim keeps many system variables handy so that it can compute how to run the model.
Three of the options in the Setup tab of the Run > Simulation Setup dialog become variables
that are used to determine how a discrete event or discrete rate model is run:
IDE
Option Variable
End time EndTime
Start time StartTime
Runs NumSims
For discrete event and discrete rate models, the DeltaTime and NumSteps variables (used in
continuous simulations and described on page 158) are ignored, because the Executive block
(Item library) calculates CurrentTime based on the time of the next event.
Pseudocode of the simulation loop in discrete event/rate simulations
The following is a pseudocode description of ExtendSim’s discrete event/discrete rate simula-
tion loop:
for CurrentSim = 0 to NumSims-1
{
if (continuing saved paused run) // this was saved while paused
{
CurrentTime = SavedCurrentTime;
CurrentStep = SavedCurrentStep;
Send ContinueSim message to blocks
}
else
{
CurrentTime = StartTime;
CurrentStep = 0;
Send PreCheckDataMsg to blocks;// Prepare for validation
Send CheckDataMsg to blocks;// Validate block variables
if (CheckDataMsg aborts)
Abort Simulation and select bad block;
Simulation Architecture 163
Running a simulation
IDE
Send FinalCalc to all blocks;
Send BlockReport to all reporting blocks;
ExecuteEndSims:
Send EndSimMsg to all blocks;
}
☞ The above comments indicate one purpose of the specific message handler, but each of them
can be used for a variety of purposes, as shown in the table on page 163.
The next several sections discuss the meaning of this pseudocode.
Initialization
The pseudocode:
for CurrentSim = 0 to NumSims-1
instructs ExtendSim to execute the contents of the “for” loop NumSims times. You set Num-
Sims in the Runs field of either the Setup or Continuous tabs of the Simulation Setup dialog.
The value of the variable CurrentSim varies from 0 to NumSims-1. This is the logic that
defines the number of simulations that will be run. If an “abort” statement is executed during a
simulation, the abort will halt the current simulation, increment currentSim by 1, and run any
remaining simulations.
When messages are sent
Different messages are sent depending on whether it is a new run or the run is paused. In addi-
tion, the sequence of sending messages is block dependent. To see the order of messages being
sent, look at the block’s code.
☞ PostInitSim is the only message handler where messages can be passed through block connec-
tors.
Table of message handler purposes
The following table lists the major purposes of the messages sent during the initialization loop
for Item and Rate library blocks, as well as for the Executive block in discrete event and in dis-
crete rate models.
☞ While the following tables list the major purposes of the message handlers, a purpose can
sometimes be accomplished using a different message handler than the one indicated.
164 IDE
Running a simulation
IDE
Create and update global arrays linked to the sections (discrete rate models)
InitSim Initialize variables
Pass event arrays to other blocks
PostInitSim Launch and perform calculation of all effective rates (discrete rate models)
Simulation phase
The Item and Rate libraries rely on the Executive block rather than ExtendSim to control Cur-
rentTime and NumSteps. As opposed to continuous simulations, which rely on time being
incremented uniformly between each step, discrete event and discrete rate simulations are
event based. In discrete event and discrete rate simulations, NumSteps is modified constantly
and the Executive block monitors and manipulates CurrentTime based on the events the blocks
have posted in the Executive’s event queue.
At each simulation step, the Executive searches through a list of event-scheduling blocks and
finds the nearest future event time. The Executive then sends a message to each of the event-
scheduling blocks whose event time is equal to the nearest event time. This may cause other
blocks to post zero time events (rescheduling themselves). The Executive sends a message to
each one of the blocks on the zero time event list (see “Timing for discrete event models” on
page 166 for a detailed discussion).
☞ The code of the Executive can be seen by opening the block’s structure.
Final messages
Upon completion of the simulation, ExtendSim sends out the FinalCalc system message to all
blocks. This message handler is used to perform final calculations for all time-dependent sta-
tistics.
The Report Manager block (Value library) then sends the BlockReport system message to any
blocks that have been selected for a report. This message handler is responsible for writing all
report data to the appropriate ExtendSim database tables.
Finally, ExtendSim sends the EndSim system message to all blocks. The EndSim message han-
dler is used for any “clean up” activities such as disposing of any dynamic arrays to free up
memory.
166 IDE
How discrete event blocks and models work
through the model, and resolve logic issues. To understand the details of the different types of
messages, some understanding of the simulation engine, the underlying data structures, and
event handling is necessary.
Timing for discrete event models
To make a model event-based, add the Executive block (Item library) to the model worksheet.
This block does two things:
1) It maintains a data structure of information about the items in the model
2) It takes control of the time clock from the ExtendSim application, scheduling events, send-
ing messages to the blocks that scheduled the event, and moving the clock forward to the
appropriate time for the next event.
In order to provide true discrete event operation, the simulation clock must move to the exact
time of each event. In order to do this, the Executive block uses three dynamic arrays to store
future events in the model.
• The TimeArray contains the event times
• TimeBlocks contains the block numbers of the blocks that post events
• TimeEventMsgType stores the constant for the message handler that is called when the event
time for a block is reached
The Executive block passes the arrays to the system globals with the statements:
SysGlobal0 = passArray(TimeArray);
SysGlobal7 = passArray(TimeBlocks);
SysGlobal13 = passArray(TimeEventMsgType);
☞ An important consequence of the Executive block controlling the time clock in the model is
that the variable numSteps, which in a continuous model represents the number of simulation
steps that will occur in the total run, is updated only by the Executive block and will always
have a value of one greater than the number of simulation steps that have actually occurred.
Simulation Architecture 167
How discrete event blocks and models work
Scheduling events
Each block that needs to post an event at a specific time in the future needs to add itself to the
Executive block's TimeArray, TimeBlocks, and TimeEventMsgType arrays. This is done by
reserving a position in the arrays and then setting that position in TimeArray to the next event
time (this needs to be done each time a new event time is posted) and TimeBlocks to the block
number of the event scheduling block.
The position in the arrays is reserved in the CheckData message handler with the following
code:
on checkdata
{
// SysGlobalInt0 is current number of event posting blocks in model
// Reserves a position in TimeArray & TimeBlocks arrays
myIndex = SysGlobalint0;
IDE
SysGlobalint0 += 1;
}
SysGlobalInt0 has been initialized to 0. By incrementing SysGlobalInt0, each block will get a
unique value for myIndex.
In the InitSim message handler, the two arrays are passed in from the Executive, the block
number is assigned to this block's position in TimeBlocks, and the initial event time is assigned
to TimeArray:
on initsim
{
// get the pointer to the TimeArray and TimeEventMsgType arrays
if(getPassedArray(SysGlobal0, timeArray) > 0)
{
// blocks in de models do not get Simulate messages
GetSimulateMsgs(False);
// set the first event time to the start of the simulation
timeArray[MyIndex] = StartTime;
// get the pointer to the TimeBlocks array
getPassedArray(SysGlobal7,TimeBlocks);
// put this block's # in reserved position in TimeBlocks
TimeBlocks[myindex] = myBlockNumber();
//Get the pointer to the TimeEventMsgType array
getPassedArray(SysGlobal13,TimeEventMsgType);
//reserved position in TimeEventMsgType
TimeEventMsgType[myIndex] = BlockReceive1Msg;
}
else
GetSimulateMsgs(True);
}
168 IDE
How discrete event blocks and models work
If this block is used in a continuous model, the GetPassedArray call will return 0 and the on
Simulate message handler will be called at every simulation step.
When the Executive sends this block a message (at the time specified in TimeArray), the block
will receive the message in TimeEventMsgType. If you do not set a value in TimeEventMs-
gType, the block will receive a BlockReceive0 message.
Put the event code in this message handler and reschedule the block for the next event time:
On BlockReceive1
{
// process event
ShowTime = CurrentTime;
// schedule event in the future
TimeArray[MyIndex] = CurrentTime + EventTime;
}
The Event block (ModL Tips library) illustrates the event scheduling procedure.
IDE
posted an event at the next event time. The simulation clock is then advanced to the next event
time and a message is sent to each block in the NextTimes array, one block at a time.
After receiving its event message, each block processes its own unique code based on that
event type. For example, a Convey Item block will attempt to pull in an additional item when
the event for an open input occurs, or the Activity block will attempt to push an item out when
that item’s processing duration has completed. Some blocks will conditionally post an event
based on the options selected. An example of this is the Queue, which will post an event if
reneging is selected. Blocks do not have to process items for an event to occur – the Clear Sta-
tistics block (Value library) generates an event at the clear time when used in a discrete event
model.
Residence blocks that do not post future events:
Some of the residence blocks that do not post future events, such as the Queue Matching and
Resource Item blocks, also attempt to move items at event times.
If a residence block needs to return from a message but also needs to attempt to pull in or push
IDE
out items with the same time step, it will send a message to the Executive posting itself on the
CurrentEvents array. The Executive sends a BlockReceive0 to all of the blocks listed in the
CurrentEvents array. This “zero time event” (discussed below) ensures that the residence block
will receive an additional message before the next time step so that additional items can be pro-
cessed.
Zero time events
Sometimes a block needs to post two events at the same simulation time yet have those events
be sequential. In addition, the other blocks in the model need to be given a chance to complete
the posting of their own events after the second event.
An example of this is an Activity block that has just released its item after the specified time
delay. The Activity will need to do two things at the same event time: send the item out to the
next block (if that path is not blocked) and pull another item in (if an item is available). To do
this, it sends the item to the next block and then posts a “current” event to the Executive.
Before the simulation clock advances, the Activity will receive a BlockReceive0 message and
will then try to pull another item in.
To post a zero time event, the block assigns SysGlobalInt8 to its block number and sends a
BlockReceive3 message to the Executive. The Executive maintains a list of all the blocks that
have sent a BlockReceive3 message and before it advances the simulation clock sends a Block-
Receive0 message to each of these blocks in turn. In the example below, the “rescheduled” flag
is used to prevent the block from posting more than one zero time event at a time:
if ( ! rescheduled)
{
// remember block is scheduled as a zero time event
rescheduled = TRUE;
// set the block number for this block
SysGlobalInt8 = MyBlockNumber();
// send message to Executive for a zero time event
SendMsgToBlock(Exec,BLOCKRECEIVE3MSG);
}
170 IDE
How discrete event blocks and models work
For example, if there are currently ten items in a simulation, the index number 5 might be
passed from one block in the model to the next. When a block receives index number 5, it
accesses the information in the Executive block’s arrays for item number 5. For instance, ite-
mArrayC[5][0] would tell if the item could accumulate a cost while itemArrayR[5][1] would
tell the item’s priority. When a block is done with an item, it passes the index value of that item
to the next block.
The Executive block maintains two arrays of real information (itemArrayR[][3] and itemAr-
rayC[][10]) and three arrays of integer information (itemArrayI[][5], itemArrayI2[][5], and ite-
mArray3D[][10]). These arrays are described below:
Real array
The real array itemArrayR[][3], passed through SysGlobal3, contains the following informa-
tion:
Slot # Description
0 Quantity: The number of items that the current item represents. This is used, for exam-
ple, by the Set block (Item Library). Item quantities are used to copy items in queues and
resource blocks. They are also used by certain input connectors (such as on the Activity
block) to convey additional information to a block.
1 Priority: Used by the Set, Get, and Queue blocks. Note that in ExtendSim the lower the
number (including negatives), the higher the priority.
2 Reserved for future use.
Cost array
The real array itemArrayC[][10], passed through SysGlobal9, contains information concerning
cost resources that are batched with the item. This information is used by residence blocks to
calculate the accumulated cost based on the cost rates and the amount of time the item spent in
the block.
Simulation Architecture 171
How discrete event blocks and models work
Slot # Description
0 Item type: When considering cost, all items can be classified as an item that can accumu-
late costs (1) or a resource (2).
1 Resource Rate 1: The cost per time unit of a resource batched to the item using the batch
block.
2 Batch Number 1: Stores the amount of resource 1 batched to the item.
3 Resource Rate 2: The cost per time unit of a resource batched to the item using the batch
block.
4 Batch Number 2: Stores the amount of resource 2 batched to the item.
5 Resource Pool Rate: The accumulated cost per time unit of resources batched to the item
using the Queue block.
IDE
6 Unused
7 Original Cost: Used in calculating cost when unbatching items using the Unbatch block
(Item library).
8 Unused
9 Unused
Integer arrays
There are two integer arrays: itemArrayI and itemArrayI2.
The integer array itemArrayI[][5], passed through SysGlobal4, contains the following informa-
tion:
Slot # Description
0 Free row flag. This is used by the Executive block for memory management. It has a
value of 1 if the row is free (that is, has no existing item associated with it), and a value
of 0 if the row is in use. See the Exit block (Item library) for an example of how to use
this to delete an item.
1 Batch ID. This is used by the batching and unbatching blocks to keep track of which
items are part of what batch.
2 User-defined integer value. This value is left untouched by the blocks in the Item library.
3 Unused except where needed to provide backwards compatibility with Extend 5 or ear-
lier.
4 Block number where item is.
Slot # Description
0 Resource Order ID. If an item has requested at least one advanced resource requirement,
the integer held in slot 0 represents the record associated with the last requested require-
ment in the “Resource Orders” database table. Resource Order ID is used with Advanced
Resource Management (ARM).
1 Unique item ID used by the Report Manager block
2 Report Manager block’s log record index
3 RBD. Event item’s record index into “RBD event registry”
4 RBD. Event item’s record index into “RBD event occurrence log”
3D array
The integer array itemArray3D[][10] stores information for the ExtendSim 3D animation and
is passed through SysGlobal12.
IDE
☞ Some of the values are scaled by 100,000 so that they can be stored in an integer, saving space.
Slot # Description
0 3D objectID. Used to reference the 3D object that represents the item in the E3D win-
dow.
1 ID for the first skin of an item.
2 ID for the second skin of an item.
3 Scale of an object. This is based on a factor of 100,000. (An object with a scale of
100000 will be normal sized; a scale of 50,000 will be half sized.)
4 Object rotation in degrees times 100,000.
5 Object Z location times 100,000. The Z locations are based on a ground level of 100, so
a Z location in itemArray3D of 10,000,000 would be at ground level.
6 Object type. This is the type of 3D object as returned by the E3DGetObjectType func-
tion.
7 Temporary level times 100,000. This stores the Z level for an object before it is placed
on a Conveyor or other object that temporarily raises its position.
8 Restore Z level. If true, the temporary Z level will be used to restore the original Z posi-
tion of the 3D object.
9 Reserved for future use.
The attribute names are stored in a String15 type global array called “_AttributeList”. This
array is created whenever a block that uses attributes is placed in the model. Its single column
contains an alphabetized list of the attribute names entered into the blocks. All blocks that ref-
erence attributes use a popup menu to allow the modeler to select from a list of attributes that
have already been defined for the model or to create a new attribute. When the popup menu is
clicked, these blocks reference the AttribList global array to ensure that all of the attributes
defined in the model are available for selection in the popup menus. Each time a new attribute
is added, this global array is increased in size by one, the attribute name is appended to the list,
and the list is sorted.
The “_AttribType” global array is used to store the attribute’s type at the time the user defines
a new attribute. There are 3 types of attributes: value, string, and db address.
While building a model, it is possible to define attributes that end up not being used or refer-
enced in the model. Cleanup of unused attribute names is done at the start of the simulation.
The Executive clears the AttribList global array in its StepSize message handler. Each block in
the model that references an attribute name then adds all of its referenced attributes to the
IDE
AttribList global array in their StepSize message handlers.
In the InitSim message handler, the Executive sorts the new AttribList global array (which now
includes only attributes which are used in the model). In doing this, each attribute name is
assigned a sequential index (the row index) in alphabetical order. Each block then calls the
Attrib_GetColumnIndex procedure which searches the AttribList global array for the attribute
that is referenced by the calling block. This index is used when referencing the attribute value
during the simulation.
In addition, if either of the two costing attributes (“_cost” or “_rate”, as discussed in the User
Reference) are used in the model, they are assigned the index values at the end of the list of
user-defined attributes.
The attribute with index 0 stores the animation object for the item.
The third global array used for attributes stores the attribute values for each item. In the Exec-
utive’s InitSim message handler, the two-dimensional global array “_AttribValues” is created
to store the values of the attributes during the simulation. The number of columns is calculated
as the “number of user-defined attributes plus one” for the animation attribute and plus two for
the costing attributes (if costing is used in the model). The number of rows corresponds to the
number of items in the model and is increased if additional items are allocated. The attributes’
values can be referenced by using the attribute index as the column and the item index as the
row. For example: the following is pseudocode for setting an attribute:
AttribValueIndex = GaGetIndex("_AttribValues");
GaSetReal(Value1,attribValueIndex,itemIndex,AttribIndex);
where:
Value1 = the value of the attribute
AttribValueIndex = The index to the "_AttribValues" global array
ItemIndex = The index of the item
AttribIndex = The index of the attribute
the name of the connector that received the message. For example the “On ItemIn” message
handler is called when a message is sent to the “ItemIn” connector.
Discrete event blocks have a function in their code called SendMsg. This function is just
included for clarity. It calls the two ModL functions mentioned above.
The SendMsgToInputs and SendMsgToOutputs functions only send messages. In discrete event
models, so that more information can be sent with each message, the global SysGlobalInt3 is
used as an argument to the messages, and the global SysGlobalInt0 is used as a return code
value. Note that some globals are used to perform different functions during the initialization
(CheckData and InitSim) phases of the simulation run.
During the Simulate phase of the run, the meanings of the various values of SysGlobalInt0 and
SysGlobalInt3 are as follows:
Depending on how the message sequence is initiated, items can be either pushed or pulled
through the model. It is easiest to illustrate this with a series of simple examples. The following
figures show a Queue block connected to an Activity block with a single item capacity.
Simulation Architecture 175
How discrete event blocks and models work
Push mechanism
When an item is pushed through the model, the upstream blocks (in this case, a Queue) try to
push their items out into any downstream blocks.
For example, assume that an item has just arrived at the
Queue and the Queue is attempting to pass that item along to
the Activity. The first action is for the Queue to send a wants
message through its item output connector to the Activity.
This is accomplished by setting SysGlobalInt3 to a value of 1
(wants) and calling the function SendMsgToInputs. This indi-
Wants message sent to Activity
cates that the Queue wants to send an item to the Activity.
The Activity receives the message in its “on itemIn” message
handler. If the Activity in the above example is not currently
processing an item and thus is idle, it will return a needs
value to the Queue by setting SysGlobalInt0 to 3 (needs),
indicating that the item can be accepted.
IDE
Needs value returned from Activity
If a needs value has been returned from the Activity, the
Queue then sends a needs message back to the Activity by
setting SysGlobalInt3 to 3 (needs) and calling the function
SendMsgToInputs. At this point the item would be commit-
ted to moving from the Queue to the Activity.
Needs message sent to Activity
If the Activity is currently busy processing another item,
instead of a needs value it will return a rejects value . This is
accomplished by setting SysGlobalInt0 to 0 (rejects). If the item is rejected, the message
sequence will be terminated.
The item is logically moved from one block to the next by
transferring its item index over the connection between the
blocks. To do this, the Queue sets its output connector value
to the item index.
When a block sets its connector value to the item index, the
connector value of any connected blocks will automatically Taken message sent back to Queue
be set to that same item index value.
Since the output connector of the Queue is connected to the input connector of the Activity, the
two connectors will share the item index value. The Activity then sets its input connector to a
negative number and sends a taken message back to the queue to indicate that the item has suc-
cessfully moved. This is done by setting SysGlobalInt3 to 2 (taken) and calling the function
SendMsgToOutputs. In response to the taken message, the queue will update any internal sta-
tistics related to the departure of the item.
Pull mechanism
In addition to being pushed, as in the preceding example,
items can also be pulled through the model. If they have
remaining capacity, downstream blocks try to pull items
into their inputs. For example, when the Activity finishes
processing the item, it will attempt to pull in another item.
To do this, the Activity first sends a wants message to the Wants message sent from Activity
176 IDE
How discrete event blocks and models work
Queue indicating that it is requesting an item. The wants message is sent by setting SysGlo-
balInt3 to 1 (wants) and calling the SendMsgToOutputs function.
If an item is available in the Queue, its output connector will be assigned to that item’s index
value. The Activity will pull in the item and then send a taken message back to the Queue by
setting SysGlobalInt3 to 2 (taken) and calling the SendMsgToOutputs function. If an item is not
available in the Queue, a rejects value (0) will be returned and the message chain will be termi-
nated.
Passing blocks
Both of the blocks in the above examples are residence blocks and can hold items for some
period of time. Passing blocks do not have this ability and must pass the item through in 0
time.
The following example shows an Equation(I) block
reading multiple attribute and other property values to
calculate the delay needed for the Activity. The Equa-
tion(I) block does not affect the messaging communica-
IDE
stuck in the Equation(I) block. And since property-manipulating blocks are only meant to pass
items, not hold them, the Queue will understate the number of items available.
The solution to this problem is to use the Equation(I) block which can then look upstream to
see what the next item coming along will be, and not pull in the item until the downstream path
is free.
Blocked messages
The first part of this process involves sending a
blocked message downstream from the Equation(I)
to see if there are any blocks that could cause this
situation. This is accomplished by setting SysGlo-
balInt3 to 6 (blocked) and calling the SendMs-
gToInputs function. The Equation(I) does this the
first time it gets an incoming message (i.e. the first Blocked message sent to Select Item Out
time the Select Item Out block requests a calculated
value from the value out connector.) The Equation(I) sends a blocked message from its item
IDE
output connector in its on AttribOut message handler. (The on AttribOut message handler is
called when the value out connector on the Equation(I) block gets a message.) If the block
downstream is a potential blocker, it will return a TRUE value by setting SysGlobalInt6 to 1
(TRUE). If a TRUE value is returned in response to the message, then the Equation(I) block
sets a flag that records that it is blocked.
Query messages
If it has been determined that blocking can occur,
each time there is a request for a calculated value,
the Equation(I) block sends a query message
upstream by setting SysGlobalInt3 to 4 (query) and
calling the SendMsgToOutputs function. This mes-
sage is essentially a request for information about Query message sent to Queue
the next item that is available. The message will be
propagated upstream by the blocks until it reaches
a block that can contain items, such as a queue.
The block responding to the query message will check to see what the item index of the next
item to be released will be and will return that value to the querying block by setting the global
SysGlobalInt0 to the item’s index value. The Equation(I) block will then access the property
values for that item. From this point on, each time that a property value is requested from the
Equation(I) block, it will send out the query message and check the property values of the next
item. It will not need to re-send the blocked message again.
ExtendSim will notify modelers if there are any logical ambiguities that will not allow the
model to operate properly. When this occurs, an error message is issued that recommends a
course of action that will resolve the ambiguity.
The Notify message
The final message used by this system is the notify message. This message is used to notify
other blocks that an item has just passed by a specified point in the model. A special sensor
connector receives this message. Sensor connectors do not pass items, they monitor the mes-
sage stream, processing only the notify message. Only a few blocks have sensor connectors,
although all of the blocks that process items will send the notify message through their item
178 IDE
How discrete event blocks and models work
output connector by setting SysGlobalInt3 to 5 (notify) and calling the SendMsgToInputs func-
tion.
In this example, the Gate block limits the num-
ber of items in the section of the model between
its output connector and the activity’s output
connector. It uses its sensor connector to deter-
mine when an item has passed the activity’s
output connector.
Situation that requires a notify message
As an item travels from the Activity to the Set
block, a taken message will be sent to the Activity. In response to this message, the Activity
will send out the notify message. The normal item input connectors in the blocks will ignore
the notify message, but sensor connectors will respond to it and start processing information
about the item. In the above example, when a notify message is received by the sensor connec-
tor, the Gate block knows that another item has passed by and can allow an additional item into
the model section.
IDE
• Send a SIMULATE message to the block to recalculate values to its output connectors.
• Echo to all other inputs THAT HAVE NEVER RECEIVED A MESSAGE to get their
latest values.
• Send a SIMULATE message to the block to recalculate values to its output connectors.
• If Additional messages are received on any connector while processing current message:
IDE
This message emulation capability improves performance and reduces redundancy.
The example code below illustrates an On Simulate message handler adding one to its input by
assigning the output connector (Con1Out) to the input connector (Con1In) plus one. There are
two cases:
• The block received a message from its input connector to recalculate, so it calls its Simulate
message handler and then propagates that input connector message by then sending a mes-
sage via its output connector to any connected block’s inputs so they can act on that mes-
sage.
• The block received a message on its output connector from a downstream block that needs a
new value. It first propagates the message backwards through its inputs so upstream blocks
can recalculate, then calls its Simulate message handler to recalculate its outputs for the
downstream block to use.
Whenever either connector receives a message, the Simulate message handler will be executed
and a message will be sent out the other connector through message emulation. This will prop-
agate messages where appropriate.
On Simulate
{
Con1out = Con1In + 1; // calculate the output value
}
The code below uses message handlers to make a block behave similarly to the message emu-
lation used in the above example. Both examples will perform identically in model operation.
Because message handlers have been explicitly specified for the connectors in the example
below, message emulation has been automatically disabled.
On Con1In
{
Con1Out = Con1In + 1;
SendMsgToInputs(Con1Out);
}
On Con1Out
{
SendMsgToOutputs(Con1In);
Con1Out = Con1In + 1;
}
IDE
On Simulate
{
}
Function Description
SendItem Attempts to pass an item out of the block. First it checks certain block variables to
see if an item is available, then it will output the index value of the item and send a
message to the receiving block (it calls SendMsg).
GetItem Attempts to get an item once a block determines that it is ready to get an item.
First it checks to see if an item is available, then it gets the index value, negates the
connector, and sends a message to the sending block.
PassItem Performs the actions of both the GetItem and SendItem functions. It is used in
blocks that pass items through without delaying them (passing blocks).
SendMsg Sends the messages out through the connectors. It sends out messages based on
the values of its arguments.
☞ Global variables are integers if they contain the “Int” designation (SysGlobalIntX) and are
strings if they contain the “Str” designation (SysGlobalStrX). Otherwise, they are reals.
Use of system globals during Simulate message
IDE
data.
SysGlobal5 Do Not Use DO NOT USE. (Was used in versions prior to 7.0.3 to pass the
TimeEventMsgType array between the Executive and event
scheduling blocks. Use SysGlobal13 instead.)
SysGlobal6 DE blocks Used to access the string item array of discrete event timer data.
SysGlobal7 DE blocks Used to access the TimeBlocks array of event posting blocks.
SysGlobal8 Resource Used in communication between the Resource Pool, Queue (in
pools Resource Pool mode), and Resource Pool Release blocks.
SysGlobal9 Costing Used to access the cost item array for discrete event item data.
blocks
SysGlobal10 Global arrays Communicates the value, row, and column to other global array
blocks when a value in a global array has changed.
SysGlobal11 Throw and Passes a value between blocks.
Catch blocks
(Value
library)
SysGlobal12 DE blocks Used to access the integer item array of discrete event itemAr-
rayI2 data.
SysGlobal13 DE blocks Passes the time event message type array between Executive
and event scheduling blocks.
SysGlobal14 Not used
SysGlobal15 Not used
SysGlobal16 Blocks with Passes array containing names of attribute arrays.
attributes
SysGlobal17 Catch Item Passes Throw block nums array.
SysGlobal18 Not used
182 IDE
Globals in discrete event blocks
message handler.
SysGlobalStr2 Blocks with Name of new string attribute passed to Executive.
attributes
SysGlobalStr4-9 Not used
SysGlobalInt0 DE blocks Return code from the messages that discrete event blocks send
to each other.
SysGlobalInt1 DE blocks Index value for the first free row in the item arrays maintained
that create by the Executive block.
items
SysGlobalInt2 DE blocks Total number of rows of data that have been allocated to the
item arrays. This will always be rounded up to the next alloca-
tion level.
SysGlobalInt3 DE blocks Argument to the messages that discrete event blocks send to
each other.
SysGlobalInt4 Blocking Tells whether the priority is being checked.
blocks and
priority
SysGlobalInt5 Used for v6 Global batch count.
compatibility
SysGlobalInt6 Blocking Specifies whether or not there is a blocked block (see the Get
blocks block).
SysGlobalInt7 DE blocks ID of the item currently being disposed.
SysGlobalInt8 DE blocks Used to pass the block number to the Executive when the block
is rescheduling itself in the CurrentEvents array.
Simulation Architecture 183
Globals in discrete event blocks
IDE
SysGlobalInt13 Random Set to TRUE if a new random number should be generated for a
Number, select block.
Equation, and
Select blocks
SysGlobalInt14 Throw and Used by Throw Item and Catch Item blocks to determine which
Catch (Item Throw block is sending the message.
library)
SysGlobalInt15 Resource Used in communication between the Resource Pool, Queue (in
pools Resource Pool mode), and Resource Pool Release blocks.
SysGlobalInt16 Blocks with Set to TRUE during CheckData message if discrete event
costing model is calculating item costs.
SysGlobalInt17 Blocks with Holds the number of attributes in a discrete event model.
attributes
SysGlobalInt18 Blocks with Argument to BlockTableInfo message handler that chooses the
tables type of information to return.
SysGlobalInt19 DE blocks Used as an argument for blockreceive4 (on queueFunction
message handler).
SysGlobalInt20 Queues, Used in direct communication with queues and resource pools.
Resource
pools
SysGlobalInt21 Queues, Used in direct communication with queues and resource pools.
Resource
pools
SysGlobalInt22 Set, Get, Executive and attribute blocks.
Executive
SysGlobalInt23 DE blocks Block number of the Executive.
SysGlobalInt24 Create, Set, Attribute info command number.
Get, Execu-
tive
184 IDE
Globals in discrete event blocks
IDE
creating; likewise, the argument to SendMsgToOutputs is the name of the input connector.
• To control how the block receives and sends messages, add at least one message handler
(which can be empty) with the name of one of your connectors. Otherwise, the block will
emulate connector messages. Thus, if the name of one of the output connectors is “G1Out”,
you would add a message handler such as:
on G1Out
{
...
}
☞ Using options in the Run > Debugging command, you can cause models to display block mes-
sages as they run. This gives an idea of how messaging works in discrete event models.
How discrete rate blocks and models work
The blocks in the Rate library are for creating discrete rate models. LP technology, which has
global oversight over discrete rate models, as well as messaging in discrete rate models, is dis-
cussed in the User Reference.
Globals in discrete rate blocks
Several reserved global variables (SysFlowGlobals and others) are used in the Rate library
blocks. The table below lists those global variables with a brief description of their use in Rate
library blocks during the Simulate message (most have undefined values during the CheckData
message).
IDE
SysARMGlobal0-19 Unused
Debugging
A guide to debugging models and blocks
Debugging models
This section discusses ways to debug models and the code necessary to add Trace features to
blocks you build. These methods are also useful when you debug block code.
Features that are discussed in the User Reference
The Debugging Tools chapter of the User Reference has a list of blocks that are useful for
debugging models. These blocks display values, help validate item flow, and speed debugging
of a model. That User Reference chapter also contains other information for debugging models
such as showing simulation order.
Adding Trace code
The ExtendSim Trace feature can be useful in debugging a model. If you create your own
blocks, those blocks can take advantage of the ExtendSim tracing features. When building a
new block, you could include code similar to the following.
For the code that follows:
• For continuous blocks, such as those in the Value library, put the code in the Simulate mes-
IDE
sage handler
• For discrete event blocks, such as those in the Item library, put the code in the departure pro-
cedure
// SysGlobal2 is the file reference number for the Debug Trace
// template for trace: BLOCK NAME BLOCK NUMBER CURRENTTIME
if( SysGlobal2 != 0.0 ) // check for open file for TRACE
{
fileWrite(SysGlobal2,"myBlockName block number "+(myBlockNum-
ber()) + ". CurrentTime:"+currentTime+".","",True);
if(getBlockLabel(myBlockNumber()) != "")
fileWrite(SysGlobal1,"Block Label: "+
getBlockLabel(myBlockNumber()),"",True);
....
....
}
☞ The blocks that ship with ExtendSim contain all the necessary Tracing code.
Profiling
Use profiling to determine the amount of time that each block in a model is used, then use that
information to optimize the block’s code. Profiling a model generates a text file showing the
percentage of time individual blocks execute during a simulation. This helps developers who
want to determine if they should optimize custom blocks, although non-developers might also
use it to find the areas of their models that are most heavily used.
To generate a profile text file, choose the Run > Model Debugging > Profile Block Code com-
mand, then run the model. Be sure to run the model long enough (at least 5 seconds for each
block in the model) to compensate for extraneous events and get a good sample. It is also
Debugging 191
Debugging block code without the Source Code Debugger
important to not move blocks in the model between runs if you repeatedly run the profile. For
example, the profile of a Bank Line model might look like:
You can use the information in this profile to look for anomalous results. For example, if one
IDE
of the three Activity blocks used a much higher percentage of the time than the other two, but
you had expected them to be about the same, you could use that information to see what it was
about that block that was different.
Note that only blocks that use 1% or more of the simulation time are shown in the profile. And
the percentages are approximate, so the sum of the percentages might not equal 100%.
Profile text files are opened, closed, and edited just like any other text file.
Debugging block code without the Source Code Debugger
The ExtendSim Source Code Debugger, discussed beginning on page 192, has a lot of advan-
tages in block debugging, offering conditional breakpoints, stack crawl, and viewing variable
values in specified blocks. The following methods may also be useful for debugging code.
Using DebugMsg functions
If you don’t want to use the Source Code Debugger, you can use the DebugMsg function to
insert a breakpoint and monitor variable values as the simulation runs. You specify a message
and variable values as this function’s string argument. When the function gets called, it dis-
plays the argument in an alert.
DebugWrite is the same as the DebugMsg function except that the data is written to a file so
the simulation run isn’t interrupted. The advantage of using DebugMsg or DebugWrite rather
than UserError is that ExtendSim warns if the Debug functions are present when the library is
loaded. See the functions in “Debugging” on page 402.
Viewing intermediate results
When developing a block’s code, there is an easy way to view intermediate results of calcula-
tions without any interruption of the model. Just add an assignment statement:
comments = myVar; // myVar will be visible as it changes
or add some more information and variables:
comments = “myVar = ” +myVar+ “, myVar2 = ” +myVar2; // more info
in your code after some calculations. Then open the block’s dialog, tab to the Comments field,
and run the model. Since “comments” is the comments box (editable text) item in the dialog,
any number assigned to it will be immediately visible in the dialog. This is different than using
192 IDE
Source Code Debugger
the DebugMsg() function (discussed on page 191) to display data, as it doesn’t interrupt the
model for each new number displayed.
Source Code Debugger
No matter what the language, code often does not work the first time. This section shows how
the ModL Source Code debugger can save you time when locating the source of an error in one
of your blocks or the equations in equation-based blocks. It provides a tutorial that shows how
to step through lines of source code, examine values of variables, create breakpoints with con-
ditions, and analyze block problems. It also discusses the various Debugger windows and dia-
logs.
In addition to being useful when creating or editing the source code of blocks, the Source Code
Debugger is available when using equations in equation-based blocks. See the How To:
Debugging Tools section of the ExtendSim User Reference for more information.
Overview of the debugger
A source code debugger makes it much easier to determine the causes of block malfunctions.
You can watch the execution of the ModL code and see its path and the effects it has on any of
IDE
IDE
block to be in debugging mode.
On the model worksheet, right-click the Start block and choose Set Breakpoints and Add
Debugging Code (or select the block and choose that command from the Develop menu).
This recompiles the
block in debugging
mode and opens two
windows:
• The Breakpoints
window shows
the breakpoints
for all the blocks
in the model
• The Set Break-
points window is
for setting break-
points in the
selected block; in
this case, the
Start block
These windows are
described more in
“Source code debugger
reference” on page 203.
For now, since the debugger automatically stops at an error message, you don’t need to set
breakpoints. Close the Set Breakpoints window
Notice that on the model worksheet and in the Tutorial library window, the Start
block’s icon is now surrounded by a red border, indicating that the block is in debug-
ging mode. Blocks in debugging mode will execute more slowly—the red markings
are a reminder that you should remove debugging code when finished.
194 IDE
Debugger tutorial
IDE
Debugger window after clicking top entry in Call Chain
Notice that the location arrow in the Breakpoint margin is now yellow for this entry, indicating
it is the previous entry in the Call Chain. The selected message handler is called DataOut,
which is the name of one of the connectors on the block. It indicates that a connector message
was received from a block that is connected to the Start block.
To see the code of the block that sent this message, you need to compile it in debugging mode
too. Then it can be seen in the Call Chain and you can click its entry to see the code that caused
the chain of events. But rather than setting individual blocks to debugging mode, it is often eas-
ier to set the entire library.
Debugging an entire library
If the Debugger window is open, stop debugging or close the Debugger window. That way
you won’t be in the middle of debugging code when the library is changed.
Choose the menu command Library > Library Tools > Add Debug Code to Libraries
In the window that appears, choose the libraries the model uses (in this case, only the Tuto-
rial library) and click Add Debugging Code
After ExtendSim finishes compiling all of the blocks in the Tutorial library, the three blocks on
the Debug Tutorial model will be outlined in red, indicating that they are in debugging mode.
Run the model again.
When the error occurs, click the Go To Debugger button to access the Debugger window.
196 IDE
Debugger tutorial
In the Source pane’s Breakpoint margin, the yellow location arrow points to line 14, as indi-
cated in the Call Chain. There was a SendMsgToOutputs function call from the Process block
because its input (ProcessIn) was greater than 7.0. (The actual value can be seen in the Vari-
ables pane as 10.6046.)
Debugging 197
Debugger tutorial
IDE
Debugger window with message handler selected
The Variables pane indicates that CurrentTime is 8. Line 32 of the Source pane shows that the
code called MyFunction with an argument equal to10.0 (CurrentTime+2.0).
198 IDE
Debugger tutorial
Click on the bottom Call Chain item where the error occurred (MyFunction, line 16):
IDE
IDE
block’s Set Breakpoints window.)
To set a breakpoint, go to the Breakpoints margin on the left side of the Set Breakpoints
window and click on the code marker for line 16—the location of the B = array[timeIndex]
statement.
A red circle appears where you clicked. Running the model will now cause the simulation to
break (pause) at that point, opening the Debugger window.
Run the model
200 IDE
Debugger tutorial
The Debugger window opens and the breakpoints margin has a green arrow on top of a red
circle. The green arrow indicates that this is the part of the code that will be executed next;
the red circle indicates that there is also a breakpoint there.
IDE
Breakpoint reached
In the Variables pane, timeIndex is 0, which means the simulation is stopped at the beginning.
You can either:
Click the Continue button in the Debugger’s toolbar 10 times until the breakpoint
occurs at timeIndex 10
Or, set conditions as described below
Setting conditions
Clicking until a timeIndex of 10 is reached can get tedious. Instead, set a condition on the
breakpoint so the code only breaks when timeIndex is greater than or equal to 10.
Close the Debugger window or click the Stop Debugging button in the Debugger window’s
toolbar (this also stops the run)
Debugging 201
Debugger tutorial
Choose Develop > Open Breakpoints Window (or bring the Breakpoints window forward
if it is open)
The Breakpoints window has two columns: Breakpoint and Condition. Double-click in the
Condition column that relates to the breakpoint (in this case, there is only one breakpoint).
A new window appears for setting conditions:
IDE
Condition window
Below the Variable B column, check the checkbox Use constant for B and enter 10 as
the constant
Click OK to save your changes and close the Breakpoint Conditions window
Run the model again
When the breakpoint occurs, click the Step over button in the Debugger window’s toolbar to
see the value of b over time. (Note that, in this case, the Step over and Step into buttons do
the same thing, because there is no function call to step into.)
The calculated value of b at timeIndex 10 is zero. This should not happen because, as noted
earlier, we know that the value of the Smedley function should increase over time, not
decrease.
Fixing the block’s code #2
Double click the Array variable to look at its values – the result is
shown at the right.
In the array, elements 10-12 are zero, indicating that the Smedley
IDE
values for the new larger array have not been calculated. The code
should be changed so that no matter what the size of the array is, it
will be filled.
Changing the block’s code
Click the Stop Debugging and Edit Code button in the Debugger’s
toolbar. This closes the Debugger and opens the Script tab of the
Start block’s structure.
In the Start block’s code, change the Initsim message handler (line
43 to line 50) to read:
on initsim
{
integer i, length;
length = GetDimension(array); // get length of array
// initialize the array so we don’t have to recalculate it
for (i=0; i<length; i++)// use length to limit loop
array[i] = Log(GammaFunction(i+1));
}
Instead of hard coding i <10, this code calls a function to return the array length into a new
variable called length which is used to limit the calculation loop. Then any time the size of the
array is changed the entire array will be filled.
Close the block’s structure and Save and Compile the block.
Disabling and removing breakpoints
To temporarily disable a breakpoint, click once on the red circle in the margin of the Break-
points window. This turns the red circle into an empty circle.
To remove a breakpoint, select the breakpoint’s name in the in the Breakpoints window and
delete it. Or click once on the red circle in the left margin of the Debugger window.
Since the Debugger window has closed:
Debugging 203
Source code debugger reference
Remove the breakpoint by selecting the breakpoint information (MYFUNCTION, line 16,
[0]Start) in the Breakpoints window and clicking the Delete key
Run the model again to see the correct output:
IDE
The well-behaved Smedley function
☞ Making Array a dynamic array and then resizing it in InitSim would allow the model to be run
for any EndTime value without overrunning Array.
Source code debugger reference
The following sections discuss the Debugger and its windows and dialogs.
Setting a block or library to be in debugger mode
In order for you to use the Source Code Debugger, ExtendSim has to generate debugging code
for a block or blocks.
• To add debugging code to one or a few blocks, select the block or blocks on the model work-
sheet and choose the command Develop > Set Breakpoints and Add Debugging Code (or
right-click the block). This automatically generates debugging code for the selected blocks
and opens a Set Breakpoints window for each block selected.
• To add debugging code to an entire library, choose the command Library > Library Tools >
Add Debug Code to Libraries. (This takes longer than setting a block to debugging mode.
But it is especially useful if you are trying to debug blocks in a discrete event model, since
the messages will be traceable back to their originators via the Call Chain in the Debugger
window.) After the library is in debugging mode, right-click the blocks on the model work-
sheet that you want to add breakpoints to, or select them and choose the Develop > Set
Breakpoints and Add Debugging Code command.
204 IDE
Source code debugger reference
Debugger window
IDE
When the model is run and execution reaches the breakpoint, the Debugger window opens and
shows the ModL code, values of variables, the Call Chain, and (in the title bar) the current-
Time.
☞ The only way to access the Debugger window is to run a model with one or more blocks in
debugging mode, where there is also either an error message or breakpoints that have been set.
You can set a breakpoint in a block’s Debugger or Set Breakpoint window. However, since the
Debugger window is only open during the model run, it is more common to set breakpoints in
the Set Breakpoint window.
Toolbar
There are six tools at the top of the Debugger
toolbar. From left to right, they are:
• Continue continues execution until the next
breakpoint is reached. Debugger toolbar
• Step Over executes a function call without
stepping into the function code. It is used when you want the debugger to execute the line of
code with a function call, but not to trace the code of the function.
• Step Into steps into the function call. It is used when you want the debugger to trace the
actual function call, including the code of the function.
• Step Out continues execution until it gets to the caller of the function. It is used when you
want to complete the function or message handler that is currently executing and step back
to the calling function.
• Stop Debugging stops the debugging session and returns to the ExtendSim program.
• Stop Debugging and Edit Code stops the execution of the block, opens the block’s structure
window, and positions the cursor at the point where execution stopped. This is particularly
useful when you have found the error and want to edit the code to make a correction.
Debugging 205
Source code debugger reference
Popup menus
• The Functions popup menu can scroll to any function and shows which function you are in.
• The Includes popup menu shows which include files are used in the block. It allows you to
set breakpoints in an include by displaying its contents in the source pane.
IDE
To add breakpoints, click on one of the code markers in the Breakpoints margin. To remove a
breakpoint, click it again. To add a condition to a breakpoint, use the Breakpoints window,
shown on page 206.
Set Breakpoints window
This window shows the ModL code and the breakpoints for the indicated block. The Break-
points margin, with code markers and any breakpoints, is on the left. The popup menus at the
top of this window are the same as for the Debugger window on page 204.
To add a breakpoint, click on a code marker in the Breakpoints margin. This places a red circle
on the code marker, as seen above. To remove the breakpoint, click its red circle in this win-
dow once so it returns to a code marker, or delete the breakpoint from the Breakpoints window,
discussed below.
206 IDE
Source code debugger reference
Breakpoints window
The Breakpoints window shows breakpoints for the entire model as well as any conditions for
those breakpoints. It is used for enabling, disabling, and deleting breakpoints and for adding
conditions to breakpoints. For a model with blocks in debugging mode, the Breakpoints win-
dow is opened by the command Develop > Open Breakpoints Window.
• A red circle indicates an enabled breakpoint.
• To temporarily disable a breakpoint, click the red circle once– it becomes an empty white
circle. To return the breakpoint to active status, click the empty circle once.
IDE
• To delete a breakpoint, select its name from the Breakpoint column and click the Delete key.
• To enable a condition for a breakpoint, double-click in its Condition column, opening the
Breakpoint Conditions dialog.
Debugging 207
Source code debugger reference
IDE
Conditions allow a breakpoint to be ignored unless the condition is TRUE. This is useful when
you get too many breakpoints and you are only interested in a breakpoint that occurs at a spe-
cific time or when a variable reaches a specific value.
The Breakpoint Conditions dialog makes it easy to construct a conditional breakpoint with no
coding. You can enter a currentTime value and/or any other comparison that might be helpful
in narrowing down the problem.
Accessing the dialog
To access the Conditions dialog, double-click in the Condition column of the Breakpoints win-
dow shown on page 206.
To enter a comparison:
Select a variable from column A
Click the desired comparison operator radio button
Choose a variable from column B or check the Use constant for B check box and enter a
constant in that field
Optionally you can enter a currentTime value and/or click the Ignore comparison and always
break check box so that your entered condition will be saved but ignored for the present.
208 IDE
Source code debugger reference
WatchPoints
A WatchPoint condition detects when the variable A changes value and will break to the
Debugger whenever that occurs. To use this, select Watch(A) from the comparison operator list
between the Variable A and Variable B columns. This is most useful in finding a statement in a
different block that is changing a variable incorrectly, and the statement cannot be found easily
by normal means.
In order for watchpoints to work correctly, all blocks in a library should be compiled with
debugging code turned on. WatchPoints slow model execution as they have to be checked con-
tinuously while code is executed.
Arrays
If a variable used in a condition is an array, you need to specify which cell is being referenced.
Do this by filling out the Array Indexes section below the Variable A and/or Variable B col-
umns, as appropriate. For example, to watch the 2nd row and 3rd column of MyArray, you
would enter [1][2] in the Array Indexes field.
Ignore conditions checkbox
IDE
Check Ignore conditions and always break when you’ve met the condition once and may not
meet it again, but you want to keep exploring that breakpoint. This saves the conditions so you
can use them later.
Debugging tips
• To quickly debug a block, select the block and choose Develop > Set Breakpoints and Add
Debugging Code. This checks the block structure, recompiles the block for debugging, and
opens the Set Breakpoint window.
• To debug the sending of interblock messages, compile the entire library for debugging using
the Library > Library Tools menu. That way the Call Chain will contain the entire chain of
messages and it will be obvious which block sent what to whom.
• When a breakpoint occurs, click the Step over button in the Debugger toolbar to see how the
values of the variables change. To jump to a later CurrentTime, go to the Break Point Condi-
tions dialog.
• When finished debugging, you should remove all of the debugging code as it slows execu-
tion considerably. To do this, choose Library > Library Tools > Remove Debug Code from
Libraries.
• Be proactive and use the Debugger to step through code even when you think it is working
properly. Try different cases just to make sure that the block is working as you have
intended. This will give you confidence in what you have written.
Variables, Messages, & Functions
ModL Variables
A detailed description of the ModL variables
that can be used in your block code
This chapter includes a complete list and description of the system and global variables.
• System variables provide information about the state of the simulation
• Global variables are used to pass information between blocks
System variables
System variables give you information about the state of the simulation. They are declared by
ExtendSim and can be viewed or modified by any block in a model.
☞ You can read or write to these variables, but you should be careful when writing to any of them.
Table of system variables
Name Description
AnimationOn Tells the state of the Run > Show 2D Animation command. If it is checked,
AnimationOn is TRUE (1), otherwise it is FALSE (0). (Note that closed hierar-
chical blocks always see a value of FALSE until they are opened. This speeds
simulations by preventing needless animation when the modeler can’t see it
anyway.)
AntitheticRan- If TRUE, ExtendSim's random number functions generate antithetic random
domVariates numbers.
CurrentScenario In models where the Scenario Manager is running a series of scenarios, this is
Variables
the current scenario number. This will be equal to the row in the Scenarios
table that is currently providing the factors to the model.
CurrentSense Used by the sensitivity analysis feature to determine the number of the simula-
tion run for changing sensitivity variables. It is initially set to 0 and is incre-
mented by 1 during each simulation, after ENDSIM. However, you may
choose to change CurrentSense to any value you want for whatever reason
during ENDSIM –ExtendSim will simply increment it after ENDSIM and use
that for its variable calculations. You should not change CurrentSim, and you
can always refer to that variable to find the actual simulation number.
CurrentSim Current simulation number. Its value starts at 0 and increments each step up to
NumSims-1. It only has a positive value if you set the Number of runs option
in the Simulation Setup or Sensitivity Setup dialogs to a value greater than 1.
CurrentSim has a value of -1 when there is no simulation running.
CurrentStep Current step number. In a continuous simulation, its value starts at 0 and incre-
ments each step up to NumSteps. In a discrete event simulation, the value starts
at 0 and increments with each event.
CurrentTime Current time during the simulation. In a continuous simulation, its value starts
at StartTime and increments at DeltaTime for each step in the simulation. In a
discrete event simulation, the Executive block (Item library) changes the Cur-
rentTime system variable only when processing an event.
DeltaTime Time increment per step. This value is initialized by the Simulation Setup dia-
log and represents the basic increment of time used in the simulation. Delta-
Time has no meaning in a discrete event or discrete rate simulation.
ModL Variables 211
Global variables
Name Description
EndTime Ending time for the simulation specified in the Simulation Setup dialog. This is
the time at which the simulation ends, unless a block stops the simulation with
an abort statement or a discrete event or discrete rate simulation runs out of
items or events.
GlobalProofStr Set by the Proof Animation code of a block.
ModernRandom Tells the state of the random number. If the current random number generator
is being used, ModernRandom is 1. If the previous version of the random num-
ber generator is being used (for backwards compatibility), ModernRandom is
0. (See “Random numbers” in the ExtendSim User Reference for a discussion
about the random number generator.)
MovieOn This legacy variable is currently unused.
NumScenarios In models where the Scenario Manager is running a series of scenarios, this is
the total number of scenarios that will be run.
NumSims Number of times the simulation will be repeated, as specified in the Simulation
Setup or Sensitivity Setup dialogs.
NumSteps The total number of steps that will be executed during a continuous simulation.
NumSteps is the number of steps entered in the Simulation Setup dialog. Num-
Variables
Steps has no meaning in a discrete event or discrete rate simulation.
OleGlobal, Ole- These variables are set by the external application sending an OLEAutomation
GlobalInt, OleG- message to a block. They act as arguments that the block can access when it
lobalStr gets the message.
RandomSeed Sequence number used to initialize the random number generator; it is set in
the Simulation Setup or Sensitivity Setup dialogs. When debugging a simula-
tion, it is sometimes necessary to force the random number generator to pro-
duce a repeatable sequence of pseudo-random numbers.
SimDelay Tells the method of simulation order: 0 for Left to right, 2 for Flow order, 3 for
Custom order.
SimMode 0 for manual mode (deltaTime or numSteps values as entered in the Simulation
Setup dialog), 1 for autostep fast (use entered values unless model calculates
smaller deltaTime), and 2 for autostep slow (divide calculated deltaTime by 5),
as specified in the Simulation Setup dialog.
StartTime Starting time of the simulation at step 0. It is initialized in the Simulation Setup
dialog.
Global variables
Global variables are useful for passing information between blocks. They are predefined by
ExtendSim and stored within the model. They can be used by any block anywhere in a model.
The ExtendSim application never changes the values of global variables except to initialize
them when a new model is created.
Types
There are two types of global variables
212 Reference
Global variables
• General use global variables have a name that starts with “Global”. They can be used any
way you want.
• Reserved global variables start with “SysGlobal”. These System Globals are controlled by
the libraries and features that are included with ExtendSim and their use is reserved.
Never use the SysGlobal variables for your own purposes; always use the general use globals
(Global, GlobalInit, and GlobalStr) instead.
General use global variables
The following global variables are available for your use in equations or when creating blocks.
You can use the SysGlobal variables (for example, when creating discrete event or discrete rate
blocks), but you should only use them in the same way they are used by the ExtendSim appli-
cation.
☞ See “Globals in discrete event blocks” on page 181, “Globals in discrete rate blocks” on
page 185, and “Globals for ARM (Advanced Resource Management)” on page 187 for tables
that describe how ExtendSim uses the reserved globals during the Simulate, CheckData, and
InitSim messages.
Messages and message handlers were introduced on page 33 and discussed more in “Message
handlers” on page 75 and “Using message handlers” on page 109.
The following table summarizes each category and type of ModL message. The three catego-
ries of messages (application, user interaction with the dialog, and block-to-block) are dis-
cussed on page 109. Note that while messages can originate either from the ExtendSim
application or from blocks, it is always a block that is on the receiving end of a message.
Summary of messages
Simulation messages
These messages are sent to all blocks during the simulation run in the following order:
Messages
Simulate Every step of the simulation. Note that this message gets sent over and over, not
just once. This is where most of the “action” in a block takes place. For instance,
you check and change the value of connectors in this message handler.
In continuous simulations, the first Simulate message gets sent with Current-
Time=StartTime and CurrentStep=0. For subsequent Simulate messages,
ExtendSim adds 1 to CurrentStep and adds DeltaTime to CurrentTime. The last
Simulate message occurs when CurrentStep=NumSteps-1 and Current-
Time=EndTime, so each block gets NumSteps Simulate messages.
In discrete event and discrete rate simulations, the first Simulate message gets
sent with CurrentTime = StartTime and CurrentStep = 0. For subsequent Simu-
late messages, the Executive block (Item library) controls how CurrentTime is
advanced. See the GetSimulateMsgs() function for how to turn off simulate
messages in a block under certain conditions.
AbortSim Sent only if an Abort occurred during the Simulate messages. This notifies the
blocks to clean up and lets them know that an abort occurred.
FinalCalc Sent after the Simulate messages are over and before the BlockReport messages.
Used for any final calculations that the block might need before the BlockReport
and EndSim messages.
216 Reference
Model Status messages
Messages
Message When sent
BlockClick Sent when the modeler clicks on a block. Use GetMouseX(), GetMouseY(), and
GetBlockTypePosition() to find out what portion of the block was clicked. See
the Mandelbrot model (Documents/ExtendSim/Examples/Continuous/Custom
Block Models) for an example.
BlockIdentify Reserved for use by Imagine That Inc.
BlockLabel Sent to the block that just had its Block Label changed, when the label becomes
deactivated. The block can then use the new value of the label.
BlockMove Upon completion of a move, sent to all blocks that moved. (See “Scripting” on
page 337.)
BlockRead This message must be used only with extreme caution – it can cause a crash if
used improperly. It is used to convert version 3.x block data tables to version 4.0
dynamic data tables. See the Information block (Value library) for an example.
Call only the GetFileReadVersion() and ResizeDTDuringRead() functions in
this message handler.
BlockRight- Sent when a block is right-clicked. Usually used to create a custom popup menu.
Click See the Math block (Value library).
218 Reference
Block Status messages
model, the changes won’t affect the existing blocks, only new blocks added to
the model.
DeleteBlock Sent when the modeler deletes a block from the model. For hierarchical blocks,
this is sent to all internal blocks.
DeleteBlock2 Sent to blocks after their connection lines to other blocks have been deleted,
right before the block deletion occurs.
DragCloneTo- This message gets sent when a modeler drags a clone onto a block and releases
Block the mouse button when the block is highlighted. If you want to get information
about the clones, call the GetDraggedCloneList() function. Used in the Opti-
mizer, Statistics (Report library) and the Scenario Manager and Find & Replace
blocks (Value library).
HBlockClose When a hierarchical block’s submodel or structure is closed. For hierarchical
blocks, this is sent to all internal blocks.
HBlockFrom- Sent to all enclosed blocks when the H-block from a library is placed on the
Library model. The OpenModel and OpenModel2 messages are then sent to the H-
block.
Messages and Message Handlers 219
Dialog messages
Messages
MailSlotRe- Sent repeatedly when there are mailslot messages waiting to be picked up. See
ceive the mailslot functions for more information.
PasteBlock When the modeler pastes a block onto the model. For hierarchical blocks, this is
sent to all blocks within the hierarchical block.
PasteBlock2 Sent after the PasteBlock message has been received by all the blocks pasted.
PasteBlock3 Sent after the PasteBlock2 message has been received by all the blocks pasted.
Plotter0Close, Sent when the modeler closes a plotter window.
Plotter1Close,
Plotter2Close,
Plotter3Close
PlotterProper- Sent to the plotter block when a user makes a change to a plot’s properties.
tyChange
TimerTick Sent by the Timer chore started by the StartTimer function. (See the scripting
functions.)
Dialog messages
Dialog messages are the names of dialog items and are sent to the block whenever the dialog is
used. When a button in a dialog is clicked or a parameter is unselected (for example, after it has
220 Reference
Dialog messages
been changed), ExtendSim sends a message with the same name as the dialog item to the
ModL code.
For example, assume a block has a “Count” button in its dialog. When that button is clicked,
ExtendSim sends the “Count” message to the block. If the block has an “on Count” message
handler, it will be executed; if not, nothing happens.
Names for all the named dialog items in a block are listed in the Variables pane at the lower left
of the structure window. If a dialog item (such as static text) does not have a dialog item name,
it will not be listed in the Variables pane.
Scrolled
DialogClick Sent when the modeler clicks on a dialog item, before the actual dialog item
message is sent to the block. Call WhichDialogItemClicked() to find the name
of the item that was clicked. This message is used, for example, to modify the
items in a popup menu at the time it is clicked on but before it opens to the mod-
eler.
DialogClose When the OK or Cancel buttons or the close box are clicked.
DialogItemRe- Sent when a dialog item becomes visible, if it was set up by calling the
fresh SetVisibilityMonitoring() function.
DialogItem- Sent when the cursor hovers over a dialog item so that the block can customize
ToolTip the tool tip (e.g format a value in a special way) that the modeler sees.
DialogOpen When the block’s dialog is opened. To display any static text labels that can
change based on what is happening in the simulation, set them here. If you don’t
want the dialog to open, execute an Abort statement – see also Plotter I/O block
code.
OK When the modeler clicks the OK button. No need to do any special handling in
this section unless you want to check input data. Use an Abort statement to pre-
vent the dialog from closing if data is not acceptable.
Messages and Message Handlers 221
Connector messages
Connector messages
These messages are sent to individual blocks:
• Via the Connector Message functions
• By the system when a modeler manually changes the number of variable connectors
• When the modeler connects or disconnects a block
☞ The connector functions start on page 299.
Message When sent
ConArray- Sent continuously when a modeler drags a variable connector to increase or
Changed decrease the number of connectors in its array. Call ConArrayChangedWhich-
Messages
Con() to return the name of the connector, and then call ConArrayGetNum-
Cons() to find out how many connectors there are in the dragged connector.
Abort this message handler to prevent the modeler from adding too many or too
few connectors.
ConArray- Sent when the modeler finishes dragging a variable connector, to allow the
ChangedCom- block to see the final number of connectors chosen.
plete
ConArrayCol- Sent when the modeler collapses or expands the variable connectors.
lapseChanged
Connection- Sent to all connected blocks when a connection is deleted. Note that a block can
Break receive multiple ConnectionBreak messages when blocks or right angle connec-
tions are deleted.
Connection- When a connection line is clicked, sent to all blocks connected so that they can
Click react (e.g. report a value). The function ConnectorToolTipWhich() returns the
connector number for that connection.
222 Reference
Block to block messages
OLE messages
These messages that are sent to an individual block on particular events.
Messages
AdviseReceive Sent to the block when it receives updated data from an advise conversation (see
the functions for “Interprocess Communication (IPC)” on page 250).
OLEAutoma- Sent to a block when the BlockMsg automation method is invoked. See
tion “BlockMsg” on page 122.
3D messages
Sent to an individual block during 3D events.
☞ The 3D animation functions start on page 276.
224 Reference
3D messages
ModL Functions
A detailed description of the ModL functions
that can be used in your block code
This chapter includes a complete list of the ModL functions. These functions can be called in
the blocks that use equations (Equation, Equation(I), Queue Equation, and Optimizer) and
when creating new blocks.
ModL function overview
The rest of this chapter is a description of all the functions in ModL, listed by type. Within
types, the functions are grouped by category. Within categories, the functions are listed alpha-
betically.
☞ ModL functions are also listed in the ExtendSim Help command alphabetically and by type,
including their arguments. You can copy a function from there to use in your code.
ModL Functions 227
Math functions
Code completion
When you start to type a function or message handler name in the structure window or include
file of a block, it will come up with a list of possibilities. Click the one you want.
Once the function has been placed in the script,
type an open parenthesis “(” immediately follow-
ing it. This causes the parenthesis to turn red and
causes call tips to display the function’s argu-
ments as shown here. The first argument will be
bolded. When you enter it, the parenthesis will turn black. As you enter each argument, subse-
quent arguments get bolded until all are entered.
Overriding
Functions can be overridden by being re-declared any number of times below the first declara-
tion. This is useful in that include files can have basic forms of functions which can be re-
declared and overridden in the main block code.
Type conversion of arguments
All ModL functions expect their arguments to be the data type specified in the function defini-
tion. If you use another type, ModL will automatically convert the argument to the expected
type before the function is called. For the functions that take no arguments, the parentheses are
still required.
Static data limits
Each function has a limit of 32,560 bytes of data for locally defined static data. Dynamic
arrays, global arrays, and database tables are not part of the count and are the more common
and usually more useful method used to allocate large data structures.
Function returns
Except for void functions, which do not return values, all functions return values that are real,
integer, or string. The type of value returned is indicated in the third column of the function
tables as:
Return Meaning
Functions
R Real or Double (8 byte double)
I Integer or Long (4 byte long integer)
S String (up to 255 characters)
V Void function (no value returned)
Math functions
Basic math
These functions perform numerical operations on their arguments.
228 Reference
Math functions
The FFT function replaces the real array argument with the real and imaginary parts of the
FFT. n must be a power of 2. If inverse is TRUE, the inverse FFT is calculated. The real values
are contained in array[n][0], and the imaginary values are contained in array[n][1] (these two
are denoted together as “array[n][i]”). array[0][i] is zero frequency. array [(n/2)-1][i] is the
most positive and most negative frequency. array[n-1][i] is the negative frequency just below
0. See the “four1” routine in Press, Numerical Recipes in C, for more information on this algo-
rithm.
Trigonometry
These functions assume that the argument represents an angle in radians.
Functions
between - and radians.
Cos(real x) Cosine of angle x. R
Cosh(real x) Hyperbolic cosine of angle x. R
Sin(real x) Sine of angle x. R
Sinh(real x) Hyperbolic sine of angle x. R
Tan(real x) Tangent of angle x. R
Tanh(real x) Hyperbolic tangent of angle x. R
230 Reference
Math functions
Complex numbers
These functions operate on complex numbers composed of two-element real arrays (U, Z, and
result), where U[0] is the real part and U[1] is the imaginary part. All arguments and results are
complex numbers expressed as two-element real arrays:
real U[2], Z[2], result[2];
Statistics/
Description Return
distributions
DBinomial(real Number of successes out of nTrials, each with a probability of R
prob, integer success of prob.
nTrials)
DExponential(real Interval between events. rate is the expected (mean) number of R
rate) events per period.
DGamma(integer Waiting time to the kthEvent in a Poisson process of mean equal R
kthEvent) to 1.
Functions
Statistics/
Description Return
distributions
Random(real i) Uniform pseudo-random integer in the range 0 to i-1 using the I
random seed specified in the Simulation Setup dialog. For exam-
ple, Random(6) returns an integer in the range 0 through 5, inclu-
sive. Random(i) assumes that i is an integer. For the Integer
(uniform) function.
RandomCalculate Returns a random number given a distribution and up to three R
(integer distribu- arguments. If a given distribution does not use all three argu-
tion, real arg1, real ments, a zero should be entered for the unused argument(s). The
arg2, real arg3) following numbers are used to define the distribution:
Beta 1
Binomial 2
Erlang 3
Exponential 4
Gamma 5
Geometric 6
Hyperexponential 7
Integer Uniform 8
Loglogistic 9
Lognormal 10
Negative Binomial 11
Normal 12
Pearsonv 13
Pearsonvi 14
Poisson 15
Real Uniform 16
Triangular 17
Weibull 18
ExtremeValue1A20
ExtremeValue1B 21
JohnsonSB 22
JohnsonSU23
Laplace24
Rayleigh25
Functions
InverseWeibull26
Logarithmic27
Hypergeometric28
Chisquared29
PowerFunction30
Cauchy31
Logistic32
InverseGaussian33
Pareto34
232 Reference
Math functions
Statistics/
Description Return
distributions
RandomCheck- Checks that the arguments passed in are valid for the given distri- I
Param (integer dis- bution. The distribution argument is defined using the numbers
tribution, real arg1, above. Displays an error message if reportError is TRUE and the
real arg2, real arg3, arguments are not valid. If reportError is FALSE, the function
integer reportError) returns the following:
0 Successful
-1 Mean must be greater than 0
-2 Probability must be between 0 and 1
-3 Argument must be between 0 and 1
-4 Shape must be greater than 0
-5 Shape2 must be greater than 0
-6 Most likely value must be between Max and Min values
-7 Min must be less than Max
-8 Arg1 is negative or less than 1.0e-15
-9 Arg2 is negative or less than 1.0e-15
-10 Arg3 is negative or less than 1.0e-15
-11 Arg1 >= Arg2
-12 Arg1 > 1.0
-13 Arg2 > 1.0
-14 Arg3 > 1.0
RandomGetModel- The actual seed used for the model. If the Simulation Setup dialog I
SeedUsed() had 0 entered for the seed, this will return the actual randomized
seed used, not 0. If a non-zero number was entered, this will
return that number. This is different than reading the RANDOM-
SEED global variable, which just shows the actual number
entered in the Simulation Setup dialog, including 0, and doesn’t
show the actual randomized seed used for running the model.
RandomGetSeed() Current seed value or current state of the random number genera- I
tor. Used for saving and restoring the random state when using
different seeds. See RandomSetSeed() below.
RandomReal() Uniform pseudo-random real number x, in the range {0.0 <= x R
<1.0} using the random seed specified in the Simulation Setup
Functions
dialog.
RandomSet- Sets the seed value or saved state of the random number genera- V
Seed(integer i) tor. Used for saving and restoring the random state when using
different seeds. See RandomGetSeed() above.
SeedListClear() Clears the list of the seed values. V
SeedListRegis- Keeps a list of the seed values. Returns a BLANK for success, R
ter(real blockNum- meaning the item was entered in the list, or returns the blockNum-
ber, integer seed) ber of the block that already posted the seed value.
Note: Block number is a real so we can register DB cells that gen-
erate random numbers using a DB attribute. DB attributes will
appear as negative numbers.
StdDevPop(real Population standard deviation of the first i members of the single- R
array[], integer i) dimensional array.
ModL Functions 233
Math functions
Statistics/
distributions Description Return
See “Random numbers” in the main ExtendSim User Reference for information about how
ExtendSim generates random numbers.
Financial
These functions calculate the unknown parameter in loan and annuity calculations given four
known parameters. The financial functions use standard financial arguments:
Argument Meaning
pv Present value of a cash-flow (real)
fv Future value of a cash-flow (real)
pmt Amount of one payment (real)
ratePer Interest rate per period (real)
nPer Number of periods (integer)
pv, fv, and pmt treat cash received as a positive value and cash paid out as a negative value.
Note that ratePer must match the length of the periods indicated by nPer. For example, if nPer
Functions
is the number of months, ratePer is the interest per month.
payAtBegin is a flag variable. If payAtBegin is TRUE (non-zero), payments occur at the
beginning of the period. If FALSE (0), payments occur at the end of the period.
Integration
These functions integrate a stream of values. For instance, you may want to integrate values
coming from inputs during a simulation. In the integration functions, the array used in the inte-
gration calculations must be declared a static array of four real values:
real array[4];
real initConditions, inputValue, deltaTime;
Matrices
Many intricate tasks can be written in just a few matrix operations. For example, solving
simultaneous equations, curve fitting data, finding the roots of a polynomial, and coordinate
transformations may all be done with matrices. For further information about matrices, see
Matrix Methods and Applications by Groetsch and King, (Prentice Hall, 1988).
The matrices used by these functions are in the form matrix[m][n], where m is the number
of rows and n is the number of columns. Vectors are of the form vector[n], where n is the
number of elements in the vector. Matrices are supported up to 1500x1500.
The complex numbers returned by the Roots and EigenValues functions are in an array that is
declared as array[n][2]. This makes array[k][0] the real part, and array[k][1] the imaginary
part.
ModL Functions 235
Math functions
Complex versions of the matrix functions end in the letter C. All arguments to these complex
functions are complex.
Declarations for matrices are as follows:
real matrix[rows][columns]; // real matrix;
// also matrixA, matrixB, ma-
trixR
real vector[rows]; // real vector; also values
real matrixC[rows][columns][2]; // complex;
// also matrixAC, matrixBC, ma-
trixRC
real vectorC[rows][2]; // complex; also valuesC
real resultC[2]; // a complex number
integer n, m; // dimensions
Rows and columns can be bigger than needed. Just specify desired rows and columns when
calling functions.
Functions
into a diagonal matrix through similarity transformations). If the
matrix is singular, the function returns TRUE.
Identity(matrixR, Creates an m by m matrixR with 1s along the diagonal and 0s V
integer m) above and below the matrix diagonal.
Identi- Complex version of Identity. V
tyC(matrixRC,
integer m)
Inner(vectorA, vec- Value of the inner or dot product of vectorA and vectorB of length R
torB, integer m) m.
InnerC(resultC, Complex version of Inner which returns its complex result in V
vectorAC, vec- resultC.
torBC, integer m)
236 Reference
Math functions
m)
MatMat- MatrixR (mA by nB) is created from the product of matrixA (mA V
Prod(matrixR, by nA) and matrixB (mB by nB). Note that nA must equal mB.
matrixA, integer
mA, integer nA,
matrixB, integer
mB, integer nB)
MatMat- Complex version of MatMatProd. V
ProdC(matrixRC,
matrixAC, integer
mA, integer nA,
matrixBC, integer
mB, integer nB)
ModL Functions 237
Math functions
Functions
vectorAC, integer
m, vectorBC, inte-
ger n)
Roots(real val- Calculates the roots of polynomial p of order n. These roots are I
ues[][2], real p[], returned in the complex array values. The coefficients of the poly-
integer n) nomial p are in an array beginning with the coefficient of the sec-
ond highest power. The coefficient of the highest power is
assumed to be 1. For example:
p[] -> x^n + p[0]*x^(n-1)+ p[1]*x^(n-2) ...+p[n-1]
Note that both values and p can be length n or greater. If the
matrix of the polynomial is singular, the function returns TRUE.
238 Reference
Math functions
Bit handling
The bit-handling functions return the integer value result of the operation. In these functions,
bit 0 is the most significant bit and bit 31 is the least significant bit of ModL’s 32-bit integers.
Declarations for bit handling are as follows:
integer bitNum, Count;
Equations
These functions let you create a block in which the user can enter equations built on ModL
code and the ExtendSim built-in functions. (Note that user-defined functions must be defined
in include files in order to be used in an equation block.) See “Dynamic text items” on
page 320 if you want to implement much larger (text edit boxes are initially limited to 255
characters) user-entered equations (up to 32000 characters). See the Equation block (Value
library) for an example of using these and the dynamic text item functions in building your
own equation block.
ModL Functions 239
Math functions
☞ Because ExtendSim will detect a change of platform and will therefore dispose of dynArray-
Name, the code must check and recompile the equation again when the simulation is run. For a
detailed example, see the Equation block (Value library).
Functions
EquationCalculate- Calculates a dynamic text equation using the input arguments I
Dynamic(real from the array arrayValues. Up to 20 input arguments are allowed.
arrayValues[], inte-
ger equationAr-
ray[])
EquationCalculate- This function allows unlimited input and output variables. Input- I
DynamicVari- DynArray values and outputDynArray real array are used in the
ables(real equation like this example: outputsName[i] = inputsName[i];
inputDynArray, Make sure that you have enough elements allocated in the input
real outputDynAr- and output dynamic arrays. See the Equation block in the Values
ray, integer code- library to see how to use this function.
DynArray)
240 Reference
Math functions
Functions
debugEquationIn- This does not affect the visible equation block.
dex)
NOTE: The variable used for DebugEquationIndex should be set
to
-1 (minus one) after this function is called so it works correctly if
EquationDebugCompile(), above, is called after this call.
EquationDebugSet- Opens a “Set Breakpoints” window so the user can click to create I
Breakpoints(inte- debugger breakpoints. Returns a True value if an error occurs.
ger
debugEquationIn-
dex)
242 Reference
I/O functions
I/O functions
File I/O, formatted
Use these functions to manipulate formatted text files. Text files produced with the output
functions must be read in an application that reads text files such as a word processing or
spreadsheet program.
In these functions, if the pathname used is the empty string (""), ExtendSim prompts you with
a standard open or save dialog. This allows you to determine the correct file name at the time
of the simulation. File pathnames for specific files are specified as “driveLetter:\direc-
tory\directory\fileName” (Windows) or “volumeName : folder : folder : fileName” (Mac OS)
with each level separated by backslashes or colons, as appropriate. If the volumeName and
folder names are left off of the pathname, the file name will come from the current folder. Note
that names of files can only be 31 characters long (Windows and Mac OS).
ModL Functions 243
I/O functions
The Import and Export functions let you define the column delimiter (separator) character in
the file to be read or written. In ExtendSim, Excel, Word, and most other tabular data applica-
tions, tabs normally delimit columns, and CRLFs (Windows: carriage returns, line feeds) or
CRs (Mac OS: carriage returns) always delimit rows.
The colDelim argument to these functions is a string which specifies the separator character:
"" The empty string (two quotation marks with nothing between them)
indicates a tab character
"," A comma character
"" A space character (multiple spaces are read as one space)
"(any character)" The character specified will be used as a column separator
☞ There are two sets of functions. The Import and Export functions are used with files that have
numerical data; the ImportText and ExportText functions are used with files that have string
data.
The functions are:
Functions
umns) an error.
Import(string path- Reads the numerical data from the file into a one- or two-dimen- I
Name, string user- sional real array or data table, then returns the number of rows
Prompt, string read (if an error occurs, it returns 0). The function assumes that
colDelim, real columns are delimited by the colDelim string character. Single
array[][]) dimension arrays are read as one column by n rows. Note that you
should initialize the array before using this function. Otherwise,
any values beyond what was read from the file will have the old
values of the array.
244 Reference
I/O functions
File I/O
Description Return
(unformatted)
Create- Creates a new folder from the pathName. For Windows, the path- I
Folder(string path- Name must use backslashes (\) to separate folder names,
Name) “myDrive:\ExtendSimX\myNewFolder”. For Mac OS, colons (:)
should be used, “myDrive:ExtendSimX:myNewFolder”. (In both
cases “X” is the ExtendSim version.) Returns FALSE if success-
ful, TRUE if there was an error.
DirPathFromPath- Returns the folder pathname part of a complete pathname. Also S
Name(string path- see FileNameFromPathName(), below. For example:
Name) “C:\myfolder\”
FileChoose(string Pops up the standard file selection dialog, with the prompt and the S
defaultFilename, default file name specified, and returns the file name of the file
string Prompt) the user selects. This differs from the fileOpen function, which it
otherwise resembles, in that it just returns the file name/path name
of the selected file without opening it. This allows the developer
to use that name however she chooses.
FileClose(integer Closes the file when you are finished writing or reading data to or V
Functions
fileNumber) from the file. Files must be closed before they can be used as data
in other applications. Call FileClose in the EndSim message han-
dler to close files when the simulation is finished.
FileDelete(string Deletes the file. Use this with caution because deleted files are not V
pathname) recoverable.
FileEnd- TRUE if the end of file has been reached during the most recent I
OfFile(integer file- FileRead.
Number)
FileExists(string Returns TRUE if the file exists I
pathname)
ModL Functions 245
I/O functions
File I/O
Description Return
(unformatted)
FileGetDelimiter Type of delimiter found after the most recent FileRead. Returns I
(integer fileNum- FALSE if a column delimiter (such as a tab character) was found
ber) after the data, or TRUE if a CRLF (Windows) or CR (Mac OS)
row delimiter was found. Call this immediately after FileRead to
find out whether a column delimiter, CRLF, or CR followed the
data.
FileGetPathName Returns the file’s path name. S
(integer fileNum-
ber)
FileInfo(string Returns information about the file specified in the filePathName R
filePathName, inte- argument. The which argument specifies what information will be
ger which) returned:
1: created date
2: modified date
Dates are returned as ExtendSim date values.
FileIsOpen(string Returns TRUE if the file described by the pathName is open. I
pathName)
FileNameFrom- Returns the filename part of a complete pathname.Also see Dir- S
PathName (string PathFromPathName(), above, to get the path name part of a com-
pathName) plete path name.
FileNew(string Opens a new or existing text (.txt) or HTML (.htm) file for writ- I
pathname, string ing and returns a fileNumber. If the pathName is an empty string
userPrompt) (""), ExtendSim prompts for a file name, displaying the user-
Prompt string. If the pathname cannot be found, or the Cancel
button has been clicked, FileNew returns FALSE (0). If the file is
already open, it returns the file’s fileNumber. Note that the File-
New function erases all information from an existing file. To
append data to an existing file, use FileOpen. Call FileNew in the
InitSim message handler to create files at the beginning of a simu-
lation.
Functions
246 Reference
I/O functions
File I/O
Description Return
(unformatted)
FileOpen(string Opens an existing text (.txt) or HTML (.htm) file for reading or I
pathname, string writing, and returns a fileNumber for reference. If the pathname
userPrompt) cannot be found, or the file is unreadable, or the Cancel button has
been clicked, FileOpen returns FALSE. If the file is already open,
it returns the file’s fileNumber. If the file is written to after using
FileOpen, the new data is appended to the end of the file. Call Fil-
eOpen in the InitSim message handler to open files at the begin-
ning of a simulation.
NOTES: If you call this function with the following strings (e.g.
*.TXT) as the pathname, it will change the types of files that the
Standard File Dialog will be looking for:
*.TXT - text files, *.DAT - data files, *.ATF - Proof trace file,
*.LAY - Proof layout file.
Note that if pathname is an empty string (““), the user will be
prompted for a filename at run time.
FileRead(integer Reads and returns a string read from the file, up to colDelim (a S
fileNumber, string column delimiter character) or to a CRLF (Windows) or CR (Mac
colDelim) OS) delimiter. To ignore the column delimiter, set colDelim to an
unused character (i.e. “@”). Reading past the end of file causes an
error message. You should test with FileEndOfFile before calling
FileRead. See FileGetDelimiter(), above.
FileRewind(inte- Resets the file to its beginning so that it can be reread. V
ger fileNumber)
FileWrite(integer Writes the string or value into the file. If a number is used for s, V
fileNumber, string ModL will automatically convert the number to a string. If tabCR
s, string colDelim, is FALSE, a column delimiter character is written to the file after
tabCR) s; if TRUE, a CRLF (Windows) or CR (Mac OS) delimiter is writ-
ten after s. If the column delimiter is a plus sign (“+”), no delim-
iter is written between the strings.
GetDirectoryCon- This function takes two dynamic arrays as arguments, calls Make- I
Functions
tents (string path, Array() for them, and fills them with the names of all the files and
stringArray string- subdirectories in the specified folder. The first array will contain
data, longarray the names of all the files/directories, and the second will contain
longdata) an integer value that will be zero for a file, and one for a folder. It
returns the number of row entries in the array. The pathname sep-
arator on a mac is a ":", on windows a "/".
GetFileReadMa- Returns the type of machine the currently active model was saved I
chineType() on. (This is only useful if models have been moved from one plat-
form to another. Otherwise, it will be the same as the machine the
model is running on.) Type 2 is Windows, 1 is models built on
68k Macs, and 4 is models built on PPC Macs.
ModL Functions 247
I/O functions
File I/O
Description Return
(unformatted)
StripLFs (integer Sets a flag in ExtendSim that determines if the fileread functions V
strip) will strip LF characters. This flag defaults to TRUE, so you
should call StripLFs(FALSE) if you find that meaningful LF char-
acters are missing from your data.
StripPathIfLocal Strips off the pathname if the file is in the same folder as the cur- S
(string pathName) rent model. For example, this can remove non-portable path
names from a filename returned from FileOpen() function. If the
file is in the same folder as the model, no pathname is needed.
Internet access
These functions allow data and file access and manipulation using Internet protocols. The FTP
block (Libraries/Example Libraries/ModL Tips) is an example of the use of these functions in
FTP access.
The connection type handles used in these functions are:
gerflags)
INetFTPGetCur- Returns the path to the current FTP directory as a string. S
rentDirectory(inte-
ger FTPHandle)
INetFTPGet- Copies a file from the remote site to the local machine. The I
File(integer path\targetname specifies the name of the file to be retrieved. The
FTPHandle, string path\filename specifies the local name where the file should be
targetName, string put. FailIfExists determines what happens if the local file already
fileName, integer exists. Currently, flags and file attributes should be set to zero.
failIfExists, integer
fileAttributes, inte-
ger flags)
ModL Functions 249
I/O functions
Functions
newName)
INetFTPSetCur- Sets the current directory to path\targetName. I
rentDirectory(inte-
ger FTPHandle,
string targetName)
INetGetFindFile- Returns info about the current file in the FTP search. The only I
Info(which) allowed input is connectionType which=1 (FTP); it returns TRUE
if a directory, FALSE if a file.
INetGetFindFile- Returns the name of the current file in the FTP search. S
Name()
INetOpenSession() Starts an Internet session. Returns a session handle that needs to
be closed with INetClosehandle when the session is complete.
250 Reference
I/O functions
Functions
IPCPoke(integer OBSOLETE AS OF ES10 I
conversation, string
pokeData, string Sends data to the server in the specified conversation. The poke-
item) Data argument is the data to be sent. The item argument indicates
where the data is to be put. For example, in Excel the item argu-
ment could be “R1C1” indicating that the data is to be sent to the
cell at row 1 column 1. Note that the syntax of the item argument
is dependent on the server. This function returns a zero if success-
ful.
IPCPokeAr- OBSOLETE AS OF ES10 I
ray(integer conver-
sation, string item, (Windows only) Pokes an array of data. The data from the
string delim, string dynamic array data will be poked to the target application. The
array data) return value will be zero for success, and nonzero for failure.
252 Reference
I/O functions
The ModL functions below will allow you to access and communicate with either type of
object. The OLE function calls that contain a blockNumber and dialogItem refer to an embed-
ded object on either the worksheet or in a dialog. In the dialog case, both arguments need to be
used. In the worksheet case, just the blockNumber is sufficient, and the dialogItem should be
an empty string (e.g. ““). OLE functions support SafeArray functionality where appropriate.
When these functions are used for OLE Automation, you need to start with the
OLECreateObject function. This function will create an OLE object of the type you specify,
and return an IDispatch interface on that object. From then on you can use the OLEDispatch
functions described below to call methods, or set and get properties on the objects.
Please note that what these functions return, and what effects they have is largely dependent on
the implementation of the OLE object/ActiveX Control that you are embedding.
☞ There are sample blocks in the ModL Tips library in the OLE category that show the syntax of
Functions
these commands. The blocks are called Excel and Embed, and can be used as OLE scripting
tutorials. Embed is a good tool for looking at the methods and properties of a given embedded
object.
OLE (Windows
Description Return
only)
OLEGetHelpCon- Returns the Help context value of the specified dispID. I
text
(integer blockNum-
ber, string dialog-
Item, integer
dispID)
254 Reference
I/O functions
OLE (Windows
Description Return
only)
OLEActivate(inte- Activates the specified embedded object. DialogItem is the dialog I
ger blockNumber, variable name in quotes. Returns FALSE if successful.
string dialogItem)
OLEAddRef(inte- Addrefs the interface specified. Returns the refcount. I
ger interfacePtr)
OLEArrayParam Puts the data in the array 'data' into a safeArray, packaged as a I
(array data, integer parameter for an Invoke call. The variants argument determines
variants) whether each data element will be packaged in a separate variant
or not.
OLEArrayParam- Specifies that the datatable array passed in will be used as an I
VariableCol- argument for the next OLEInvoke call. The numCols argument
umns(short hNum, will define how many columns the function defines the data as
array datatable- containing.
Name, integer
numCols, integer
variants)
OLEArrayResult Retrieves the SafeArrray result data from an Invoke call, putting I
(array data) the data into the array 'data'.
OLEArrayResult- Specifies that the datatable array passed in will be filled with the I
VariableCol- result of the last OLEInvoke call. The numCols argument will
umns(array define how many columns the function defines the data as con-
datatableName, taining.
integer numCols)
OLECreateObject This function is the starting point for OLE Automation. It will I
(string objectRefer- create an OLE object, or provide an interface to an application if
ence) it is already running, and return an Idispatch interface to that
object that can be used with the OLEDispatch calls listed below to
allow the user to control other applications via OLE Automation.
The object reference string is the registry key associated with the
object you wish to embed. (As an example, Excel would be
excel.application.)
Functions
OLE (Windows
only) Description Return
OLE (Windows
Description Return
only)
OLEDispatchIn- See OLEDispatchGetHelpContext(). Same as OLEInvoke(), I
voke (integer Idis- except uses a handle.
patchHandle,
integer dispID)
OLEDispatch- Adds a DispatchHandle to the argument list for the next Invoke I
Param (integer dis- call. Note: arguments are listed in back to front order. Returns
patchHandle) FALSE if successful.
OLEDispatchProp- See OLEDispatchGetHelpContext(). Same as OLEProperty- I
ertyGet (integer Get(), except uses a handle.
IdispatchHandle,
integer dispID)
OLEDispatchProp- See OLEDispatchGetHelpContext(). Same as OLEPropertyPut(), I
ertyPut (integer except uses a handle.
IdispatchHandle,
integer dispID)
OLEDispatchRe- Returns an IdispatchHandle from the last Invoke call. (If a return I
sult() value is available.) This handle can be used in the other OLEDis-
patch calls listed above. This handle will be the Dispatch interface
to an object that is associated with an embedded object on the
worksheet, or in the block dialog. Many embedded objects are
simple objects that will not have methods that return dispatch
handles on other objects, but some, like an embedded Excel work-
sheet, for example, contain ‘Subobjects’ that will need to be refer-
enced in this way.
OLEGAParam Copies the data in the global array defined by arrayindex into a I
(integer arrayIndex, SafeArray, packaged as a paramaeter for an Invoke call. The vari-
integer variants) ants argument determines whether each data element will be
packaged in a separate variant or not.
OLEGAResult Retrieves the SafeArrray result data from an Invoke call, putting
(arrayIndex) the data into the global array referred to be arrayIndex.
Functions
OLE (Windows
Description Return
only)
OLEGetDispID DialogItem is the dialog variable name in quotes. Returns the Dis- I
(integer blockNum- patch ID for the function/variable theName.
ber, string dialog-
Item, string
theName)
OLEGetDoc (inte- DialogItem is the dialog variable name in quotes. Returns the I
ger blockNumber, internal documentation from the type library in string array
string dialogItem, returnDoc. returnDoc will be resized as needed if the text is larger
string returnDoc[], than a single string. This function accesses text that is in the
integer dispID, objects Type Library. What information is available, and whether
integer which) any is available, is object dependent.
Which takes the following values.
0: name (DispID property/Method name)
1: doc (Any available Documentation on the DispID.)
2: file name (FileName of the help file associated with the
dispID.)
OLEGetFuncIndex Returns the function Index used in OLEGetFuncInfo that corre- I
(integer blockNum- sponds to the dispID.
ber, string dialog-
Item, integer
dispID)
OLEGetFuncInfo DialogItem is the dialog variable name in quotes. Returns func- I
(integer blockNum- tion information for the function specified by index. Implementa-
ber, string dialog- tion of this function is object specific, so your results will vary
Item, integer index, dependent on how the developers of the object have implemented
integer which) it.
if which is 0: INVOKEKIND
returns 1 for INVOKE_FUNC
returns 2 for INVOKE_PROPERTYGET
Functions
returns 4 for INVOKE_PROPERTYPUT
returns 8 for INVOKE_PROPERTYPUTREF
if which is 1: cParams
returns Count of total number of parameters
if which is 2 : cParamsOpt
returns Count of optional parameters
if which is 3 : returns DispID (sometimes called memberID).
Note that index is not the same as the dispID. It is just a sequential
index value from 0 to n-1 where n is the number of functions sup-
ported by the object.
OLEGetGUID() Pops up the standard insert item dialog, and returns the GUID of S
the object you select as a string. The objects that appear on the
standard insert item dialog are just those objects that have been
defined as ‘Insertable’ in the registry, and will not necessarily
include all of the objects that you can use with ExtendSim.
258 Reference
I/O functions
OLE (Windows
only) Description Return
OLELongParam Adds an integer value to the argument list for the next Invoke call. I
(integer value) Note: Arguments are listed in back to front order. Returns FALSE
if successful.
OLELongResult() Returns an integer value from the last Invoke call, if a return I
value is available.
OLEObjectIsReg- Checks to see if a specific CLSID is already registered. Returns
istered(string clsid) TRUE if the CLSID is already in the registry and FALSE if it is
not.
OLEProperty- DialogItem is the dialog variable name in quotes. Gets the prop- I
Get(integer block- erty specified by dispID. You must call Result functions to
Number, string retrieve the value.
dialogItem, integer
dispID)
OLEProperty- DialogItem is the dialog variable name in quotes. Sets the prop- I
Put(integer block- erty specified by dispID. You must call Param functions to set up
Number, string the arguments to the method.
dialogItem, integer
dispID)
OLERealParam Adds a real value to the argument list for the next Invoke call. I
(Real value) Note: Arguments are listed in back to front order. Returns FALSE
if successful.
OLERealResult() Returns a real value from the last Invoke call, if a return value is R
available.
OLERelease(inte- Releases the interface pointer specified. Returns the refCount. I
ger interfacePtr)
OLEReleaseInter- Releases the interface pointer returned by OLEGetInterface. I
face (integer inter- Returns FALSE if successful.
facePtr, integer
whichInterface)
Functions
OLERemoveOb- Removes the OLE object from the dialog item. I
ject(integer block-
Number, string
dialogItem)
OLEReq- This function requests a license key from a licensed activeX con- S
uestLicKey(string trol on your machine. This can be used with OLEInsertLicensed-
guid) Object, above, to allow the user to retrieve the license key to be
used when inserting a licensed runtime activeX Control.
260 Reference
I/O functions
OLE (Windows
Description Return
only)
OLESetNamed- Specifies that the first named parameter is the parameter Para- I
Param (integer par- mID. If the Idispatch interface you are using specifies named
amID) parameters, then they are the first parameters by definition. All
this function does is specify which named parameters you are
using. The first time you call it, it specifies what the paramID of
the first named parameter is, the second time the second, and so
on.
OLEStringParam Adds a string value to the argument list for the next Invoke call. I
(string value) Note: Arguments are listed in back to front order. Returns FALSE
if successful.
OLEStringResult() Returns a string value from the last Invoke call, if a return value is S
available.
OLESupressIn- Used to stop those pesky error messages from appearing during V
vokeErrors(integer an invoke of an OLE object.
supressErrors)
OLEVariant- Adds a variant pointer value to the argument list for the next I
Param(string value) invoke call. Note: Arguments are listed in back to front order.
OLEVari- Returns a string value from the specified variant pointer argument S
antResult(integer of the last Invoke call. Which specifies which of the arguments of
which) the invoke call you are referring to, it would be one for the first
one entered, two for the second, and so on (If the specified argu-
ment was a variant pointer argument.)
WinRegSvr32(inte- This function runs the RegSvr32 command line tool used is used I
ger registerObject, to register .dll files as components in the windows registry. The
string fileName, registerObject integer is a flag that determines if you want to reg-
string dir) ister (true) or unregister (false) the object. FileName is the name
of the dll file. Dir is the path name to the directory containing the
dll.
Mailslots are a messaging functionality supported by the windows API. They are unidirec-
tional messages that are sent from a given machine to a specified mailslot.
The MailSlotReceive message handler will be called periodically when there is a waiting mes-
sage available in one of the mailslots created by these functions.
☞ Because mailslot technology is a “polling” system, there will be a time delay between when a
message is sent to when a message is actually received.
☞ If you send out a single message to a mailslot, the mailslot may receive multiple copies of that
message depending on your network configuration. This is a expected behavior of the Micro-
soft implementation of mailslots. If you need to uniquely identify messages, the simplest way
would be to concatenate a unique identifier onto the beginning or the ending of the message
and then ignore the duplicates.
See the Windows API documentation for more information about mailslots.
ModL Functions 261
I/O functions
Mailslot (Windows
Description Return
only)
MailSlot- Closes the specifed mailslot. Returns FALSE if successful. I
Close(integer
index)
MailSlotCreate Creates a mailslot with the specified name. Returns the index I
(string theSlot- number of the mailslot, or a zero if the call failed.
Name)
MailSlotRead(inte- Reads the next message from the specified mailslot. This function S
ger index) will return an empty string if there are no messages waiting.
MailSlotSend Sends a message to the specified mailslot(s). TheComputerName I
(string theComput- field specifies exactly which machine to send the message to. If
erName, string this field is a star "*", this message will be broadcast to all
theSlotName, mailslots with the specified mailslot name in the primary domain
string message) of the sending computer. If this field is a domain name, the mes-
sage will be sent to all mailslots with the specified name in that
domain. The SlotName field must contain the name of the speci-
fied mailslot, and cannot be wildcarded. Returns FALSE if suc-
cessful.
ODBC
ODBC stands for Open Database Connectivity. This Microsoft API allows data connectivity
between applications that support it, and databases that support it. The following functions
allow MODL access to the ODBC API. The following diagram shows the basic sequence of
commands that you would use to connect to a database, and retrieve data.
Functions
If you are trying to change data in the database, or add data, you could substitute the ODB-
CInsertRows, and/or ODBCSetRows calls for the ODBCExecuteQuery,
262 Reference
I/O functions
log, string schema, meaning and use of these arguments. Please note that the argu-
string table, string ments are strings, so you cannot pass in the NULL values that are
column) defined in the SQLColumns specification. For this function,
we've defined an empty string "" to be interpreted as a NULL, so
just use empty strings for unused arguments where NULL is nor-
mally used.
ODBCConfigData- Calls the Windows API SQLConfigDataSource() function with
Source(integer fRe- the entered arguments
quest, string
szDriver, string
szAttributes)
ModL Functions 263
I/O functions
cessInfo)
ODBCTables (inte- Executes a standard query that returns a dataset containing the I
ger connection) names of all the valid tables in the data source. Returns a State-
ment Handle. (Note: it is very important to free all statements
before disconnecting the connection, otherwise the disconnection
may fail.) Returns FALSE (0) if the query is unsuccessful. See
your ODBC documentation (SQLTables) for a list of the mean-
ings of the columns of the resulting dataset.
Serial I/O
These functions allow ExtendSim to interact with serial ports. You can, for example, set up a
simulation that will cause a modem attached to a computer to dial up a remote database, collect
data, run a simulation, and send the results to another location over the modem. Likewise, an
ExtendSim simulation can be controlled by a modem from a remote location.
ModL Functions 265
I/O functions
• Windows: The port arguments are from 1 through 4 for COM1 through COM4, respectively.
• Mac OS: The port arguments are 0 for serial port A (modem port) or 1 for port B (printer
port).
☞ If you use serial functions in your ModL code, and there is any possibility that your blocks will
be used cross-platform (e.g. on both Windows and Mac OS systems), your code should include
checks to allow for the differences between platforms. For more information, see “Cross-Plat-
form Considerations” on page 419.
The SerialRead and SerialWrite functions are asynchronous, meaning that they return immedi-
ately without waiting for a response from the modem. SerialRead reads from the input buffer,
not from the modem, and SerialWrite writes to the output buffer.
Functions
• Variables passed from the ModL code to a DLL/Shared Library are passed by value unless
the variables are strings or arrays, in which case they are passed as pointers. Pointertype (64
bit) variables can also be passed as arguments. Strings are passed to DLLs/Shared Libraries
from ModL as Pascal strings, not C strings. See “DLLs” on page 86, for more information.
• If you use DLL functions in your ModL code, and it is possible that your blocks will be used
cross-platform (for example, on both Windows and Mac OS systems), your code should
include checks to allow for the differences between platforms. For more information, see
“Extensions” on page 423.
• The DLLs and Shared Libraries are stored in the ExtendSim/Extensions/DLLs folder.
☞ See “DLLs” on page 86 for more information about using DLLs. At some point the Extend-
Sim/Examples/How To/Developer Tips/DLLs folder will have some DLL examples.
266 Reference
I/O functions
DLL/Shared
Description Return
Libraries
DLLBoolCFunc- Calls a DLL routine referenced by procAddress and returns a I
tion(integer pro- Boolean (translated into an integer by ExtendSim). Accepts a
cAddress, .....) variable argument list. Assumes a C calling convention.
DLLBoolPascal- Calls a DLL routine referenced by procAddress and returns a I
Function(integer Boolean (translated into an integer by ExtendSim). Accepts a
procAddress, .....) variable argument list. Assumes a Pascal calling convention.
DLLBoolStdcall- Calls a DLL routine referenced by procAddress and returns a I
Function(integer Boolean (translated into an integer by ExtendSim). This function
procAddress, ...) is the same as the other DLL functions except it assumes a Std-
Call calling convention.
DLLCtoPString Converts a C string to a V string that is usable by ModL, as V
(string theString) ExtendSim/ModL internally can use only V (Pascal) strings. In
some cases pre-established DLLs will expect and return C format
strings in the passed parameter string pointer, and this function
can convert the string type safely within the pointer space. See
Functions
DLL/Shared
Description Return
Libraries
DLLLoadLibrary Loads the specified library. This is for people who need to access I
(string pathName) routines in a DLL that is not present in the Extensions folder.
After loading the library, attempts to access DLL routines that are
in that library should succeed. See also DLLUnloadLibrary.
DLLLongCFunc- Calls a DLL routine referenced by procAddress. Returns a 64 bit I
tion(integer pro- integer that can be saved as a ModL integer (32 bit) or, if needed,
cAddress, .....) as a pointertype (64 bit integer/pointer). Accepts a variable argu-
ment list. Assumes a C calling convention.
DLLLongPascal- Calls a DLL routine referenced by procAddress. Returns a 64 bit I
Function(integer integer that can be saved as a ModL integer (32 bit) or, if needed,
procAddress, .....) as a pointertype (64 bit integer/pointer). Accepts a variable argu-
ment list. Assumes a Pascal calling convention.
DLLPtoCString Converts a V string to a C string that is usable by a DLL, as V
(string theString) ExtendSim/ModL internally can use only V (Pascal) strings. In
some cases pre-established DLLs will expect and return C format
strings in the passed parameter string pointer, and this function
can convert the string type safely within the pointer space. See
DLLCtoPString above to convert back to V strings.
DLLLongStdCall- Calls a DLL routine referenced by procAddress. Returns a 64 bit I
Function (integer integer that can be saved as a ModL integer (32 bit) or, if needed,
procAddress, ...) as a pointertype (64 bit integer/pointer). This function assumes a
StdCall calling convention.
DLLMakeProcIn- Returns the ProcAddress expected by the other calls as an argu- I
stance (string proc- ment. Requires a procedure name. This function will search all
Name) open libraries for the named procedure, so it is advisable to call it
once, and save the returned value. Function will return a zero if
procName was not found.
DLLMakeProcIn- Similar to DLLMakeProcInstance except it has a libraryName I
stanceLibrary argument so you can specify which library should be opened and
(string searched for the procedure.
libraryName, string
Functions
procName)
DLLUnloadLi- Unloads the DLL from memory. See also DLLLoadLibrary. I
brary (string name)
DLLVoidCFunc- Calls a DLL routine referenced by procAddress and returns noth- V
tion(integer pro- ing. Accepts a variable argument list. Assumes a Pascal calling
cAddress, .....) convention.
DLLVoidPascal- Calls a DLL routine referenced by procAddress and returns noth- V
Function (integer ing. Accepts a variable argument list. Assumes a Pascal calling
procAddress, .....) convention.
DLLVoidStdcall- Calls a DLL routine referenced by procAddress and returns noth- V
Function (integer ing. This function assumes a StdCall calling convention.
procAddress, ...)
268 Reference
I/O functions
Because of the automatic type conversion provided in ModL, and because they provide an easy
way to display the contents of variables, these functions are also useful for debugging block
code. For example:
ModL Functions 269
I/O functions
Functions
Window() dow, for example, a hierarchical submodel window. Use the Get-
BlockTypePosition() function to get the coordinates of a block in
that window. Can be used in the on blockClick message handler.
HBlockClicked() This function returns the block number of the Hblock that was last V
double clicked. This is intended to be called during a On Hblock-
Open message handler, and will always return a negative one at
other times.
isKeyDown(inte- Returns a True/False value for whether or not the specified key is I
ger keyCode) pressed. The constants for keyCode are the constants for the API
call GetKeyState (Windows) or the GetKeys functionality (Mac-
intosh).
270 Reference
Animation
Animation
2D Animation
Use these functions to implement the ExtendSim 2D animation. Examples of using these func-
tions are shown in “2D animation” on page 126.
The Show 2D Animation command (Run menu) only controls whether animation is shown
during the simulation run. At all other times, the block will still show animation if the block
creator has coded it to do that. For instance, animation is available when the modeler makes
any changes in a block's dialog, whether Show 2D Animation is selected or not and regardless
of whether the simulation is running. When the command Show 2D Animation is selected, ani-
mation is available at all times.
In the functions:
Functions
• “obj” is the integer object number of the animation object on the icon.
• As discussed in “Animating hierarchical blocks” on page 129, hierarchical blocks are ani-
mated indirectly (by blocks in the submodel) by referencing the negative of the hierarchical
block’s object number. If a negative number is used and ExtendSim doesn’t find that object
in the current enclosing H-block, ExtendSim will search the H-block enclosing that one and
so on, until it finds the object or reaches the top level.
• The outsideIcon value is a value that is set to FALSE unless you want to move or stretch out-
side the original size of the icon (setting this to TRUE slows down the animation). All mea-
surements are in pixels.
• Some functions have the option of selecting a pattern in addition to a color. Starting with
ExtendSim 10, patterns remain as arguments for those functions but are no longer supported.
ModL Functions 271
Animation
• AnimationEColor specifies the color of animated objects. See the “Select Color window” on
page 401.
There is a limit of 256 animation objects that can be manually placed on a block’s icon when
the block is created. However, the AnimationObjectCreate function supports thousands of ani-
mation objects. This function can be used to create new animation objects during the run; use
AnimationObjectDelete() to delete the objects during the run.
Functions
objectNum, inte- them. See “EColors” on page 401 for more information.
ger EColorValue
AnimationColor Sets the color of the object using the pattern number, hue, satura- V
(integer obj, integer tion, and brightness.
hue, integer sat,
integer bright, inte- Patterns are not supported as of release 10, so use 1 for a solid
ger pattern) pattern. Also, for ExtendSim 10 or later, use the AnimationE-
Color function instead.
AnimationEColor Set the color of an animation object using an EColor value. See V
(long objNum, long “EColors” on page 401 for more information.
EColorValue)
272 Reference
Animation
Functions
need to be recreated in openModel, or InitSim, or whenever they
are used. They will persist until the model window (Including
Hblock model windows,) is closed, or AnimationObjectDelete is
called.
AnimationObject- This function will delete an animation object. This will not affect I
Delete(integer obj- animation objects that are defined in the block structure, just
Num) those created on the fly with AnimationObjectCreate. Use nega-
tive objNum if in enclosing Hblock.
AnimationObject- Returns TRUE if an animation object with the specified objNum I
Exists(integer obj- exists, and FALSE if it doesn’t. For example, you could test if the
Num) enclosing hierarchical block has a specified animation object.
(i.e. if animationObjectExists(-3) returns a TRUE value, then
there is an animation object in the enclosing Hblock, or any num-
ber of levels above, with the objNum 3.)
274 Reference
Animation
3D Animation
For the 3D functions, all distances are in meters, speeds are in meters per second, and time
units are in real time seconds, which correspond to a single simulation time unit.
3D block functions
Functions
3D time functions
3D window functions
Functions
3D mountStack functions
A mountStack is a stack of objects mounted onto a mount node on some object. These func-
tion just simplify stacking multiple objects onto a single mount point.
3D path functions
Functions
3D environment functions
3D movement functions
Functions
objectID)
E3DResume- Resumes the previous speed value of the object. Each object I
Speed(integer objec- internally saves its old speed when a new speed value is set.
tID) This function resets the speed to the last value used.
284 Reference
Animation
3D post function
Post functions are the equivalent of the similarly named regular E3D function, with the addi-
tion of a time argument specifying when the E3D action will occur. See the appropriate E3D
function for more information about the meaning of the arguments of the functions. Times are
specified in simulation time units, and the most common value of this argument will be to
place the system variable currentTime into it.
3D post
E3DPostAnimationPlay(real time, integer objectID, string which, integer forward, integer threa-
dID)
E3DPostAnimationSetPosition(real time, integer objectID, string which, real pos)
E3DPostAnimationStop(real time, integer objectID, string which)
E3DPostChangeObject(real time, integer objectID, string ObjectName)
E3DPostCopyObject(real time, integer objectID, real x, real y, real z) Functions
E3DPostCreateObject(real time, string objectName, integer objectType, real x, real y, real z, inte-
ger collideable, integer GroupTag)
E3DPostCreateObjectAtWayPoint(real time, string objectName, integer objectType, integer way-
PointID, string wayPointName, integer collideable, integer GroupTag)
E3DPostDeleteAllObjects(real time, integer groupTag)
E3DPostDeleteObject(real time, integer ObjectID, integer deleteMounted)
E3DPostMountObject(real time, integer objectID, integer targetID, integer node)
E3DPostMountStackInsert(real time, integer ObjectID, integer targetID, integer index, integer
baseNode)
286 Reference
Animation
3D post
E3DPostMountStackRemove(real time, integer ObjectID, integer index, integer baseNode, inte-
ger rule, integer direction, real distance)
E3DPostObjectPropertySet(real time, integer objectID, integer which, real value)
E3DPostResumeSpeed(real time, integer objectID)
E3DPostRotateTimed(real startTime, real endTime, integer objectID, real startZ, real endZ, inte-
ger ticks)
E3DPostSetDestination(real time, integer objectID, real duration, real speed, real x, real y, real z,
integer selfDeleting)
E3DPostSetObjectBlockNumber(real time, integer objectID, integer blockNumber)
E3DPostSetObjectLabel(real time, integer objectID, string objectLabel)
E3DPostSetPosition(real time, integer objectID, real x, real y, real z, integer drop)
E3DPostSetRotation(real time, integer objectID, real x, real y, real z)
E3DPostSetScale(real time, integer objectID, real x, real y, real z)
E3DPostSetSkin(real time, integer objectID, string skinName, string skinBaseName)
E3DPostSetSkinByIndex(real time, integer objectID, integer skinIndex1, integer skinIndex2)
E3DPostSetSpeed(real time, integer objectID, real speed)
E3DPostSetTargetObject(real time, integer objectID, real duration, real speed, integer targetID,
string name, integer selfDeleting)
E3DPostSetTargetPath(real time, integer objectID, real duration, real speed, integer targetID,
string name, integer selfDeleting)
E3DPostSetTargetWayPoint(real time, integer objectID, real duration, real speed, integer tar-
getID, string name, integer selfDeleting)
E3DPostSetVisibility(real time, integer objectID, integer visible)
E3DPostStopAllObjects(real time, integer sync)
Functions
E3DPostUnmountObject(real time, integer objectID, integer targetID, integer direction, real dis-
tance)
E3DSetObjectLabel(integer objectID, string name)
3D mounting functions
3D animation functions
Functions
Torque threads for you. Examples of where it does matter are
animations where two sequences use the same parts of the
object, or if you have more than eight different animations that
you want to run. In either case, you need to stop one thread to
successfully run the next.
E3DDialogPic- Shows the object picture within a dialog’s static text item. I
ture(string variable-
Name, string
objectName, real rota-
tion, real rotation2)
E3DGetObjectAnima- Gets the object’s animation names into theArray. I
tionNames(integer
ObjectID, string the-
Array[])
288 Reference
Animation
3D name functions
5: ExtendVehicle
E3DGetObject- Fills the passed in string31 array with the names of the E3D I
Names(integer which, Objects in the 3D world. The array should be a string31
string31 nameArray[]) dynamic array, which the function will resize based on the num-
ber of names to be returned. Which values:
0 or greater: groupTag
-1: everything
-2: Paths
-3: WayPoints
-4: ExtendItems
-5: Players
-6: wheeled vehicles
ModL Functions 289
Animation
3D screenshot functions
3D distance functions
Functions
3D distance Description Return
E3DDistance(integer Returns the distance from the location of the specified object to R
objectID, real x, real y, the specified location.
real z)
E3DDistan- Returns the total distance of the path. R
cePath(integer pathID)
E3DDistanceToOb- Returns the distance between the two objects. R
ject(integer objectID,
integer targetID)
290 Reference
Animation
3D skin functions
3D vector functions
3D vector Description Return
E3DForwardAn- This function returns the forward angle for the Object. Where R
gle(integer objectID, zero means directly in front, PI means directly behind.
integer targetID)
E3DForwardVec- This function returns the forward vector for the Object. The R
tor(integer objectID, forward vector is the vector forward from the Object. The
integer which) which argument specifies which part of the vector is to be
returned. Which values are:
0: X
1: Y
2:Z
E3DGetAngleFrom- This function returns the yaw and pitch angles. The range of R
Vector(real vectorX, yaw is 0 - 2PI. The range of pitch is -PI/2 - PI/2. Which values:
real vectorY, real vec- 0: yaw
torZ, integer which) 1: pitch
E3DGetObjectVec- This function returns a vector for the object, depending on the I
tor(integer objectID, value of the which argument. Vector needs to be a predefined
integer which, real single row real array with at least three elements. Which takes
vector[]) the following values:
0: position
1: forward Vector
E3DGetVectorFro- This function returns the vector from the specified angles. The R
mAngles(real yaw, range of yaw is 0 - 2PI. The range of pitch is -PI/2 - PI/2. Which
real pitch, integer values are:
which) 0: X
1: Y
2: Z
E3DNormalizeVec- Takes the vector passed in, and normalizes the array. Vector I
tor(real vector[]) needs to be a predefined single row real array with at least three
elements.
3D tick functions
These functions start a timer specifically for the use of the 3D window. The E3DTICK mes-
sage will be sent to the block periodically once the E3DTimer has been started with E3DStart-
Tick. Unlike the ExtendSim timers, described separately, the E3Dtimer is controlled by the
E3D engine. It will be sent on each tick of the E3D engine, which will be frequently enough to
update something that needs to move smoothly in the E3D window. If you want a timer that is
based on simulation time, you should use the regular ExtendSim Timers.
Functions
vis)
3D script functions
3D miscellaneous functions
1: ExtendItems
E3DObjectExists(inte- Returns a true (1) if the specified object exists, and a false (0) if I
ger objectID) it doesn’t.
E3DPlaySound(string Plays the sound specified by soundProfileName. At the location I
soundProfileName, specified by x,y,z.
real volume, real x,
real y, real z)
E3DUses3D() Returns the value of the uses3D flag from the sim setup dialog I
for the active model.
ModL Functions 295
Blocks and inter-block communications
Numbers
There are two numbers associated with blocks. Global numbers access all blocks, including
blocks inside of hierarchical blocks. Local numbers access a hierarchical block’s internal
blocks and are the same for all instances of that hierarchical block, whereas the global numbers
are different for each instance. Blocks are numbered from 0 to NumBlocks-1. Block numbers
show in a dialog’s title bar.
Names and labels
• Block names are the names you give a block when you create it. For example, “Data Import
Export” is the name of a block in the Value library. Names appear in the dialog’s title bar.
• Block labels are user-definable names given to a particular block in the model. Block labels
are entered in the area to the right of the Help button at the bottom of a block’s dialog. Labels
appear at the bottom of the block’s icon.
Functions
BlockName(inte- Looks in global slot i and returns either the name of the block, the S
ger i) first 255 characters of text, or an empty string if it is an unused
slot. For example, you can use this function to read text informa-
tion that you have added or modified in a model.
BlockRect (integer Virtually the same as the getBlockTypePosition function, except I
blockNumber, inte- for the useAnimation argument. This argument specifies (with a
ger or real array[4], true/false, 1/0 value) whether or not the animation objects are to
integer useAnima- be included in the returned rectangle. If useAnimation is true, the
tion) rectangle will include the positions of the animation objects that
are off the icon in the rectangle, otherwise it will not.
296 Reference
Blocks and inter-block communications
Block numbers,
Description Return
labels, etc.
FindInHierarchy This function is used by several blocks, including the Catch Item I
(string FindBlock- and Throw Item blocks in the Item library, to locate the corre-
Name, string Find- sponding block associated with the current block. (For example,
BlockLabel, string to find a Catch corresponding to a Throw, and vice versa.) Please
FindDialogName, see the Catch and Throw blocks for an example of how to use this
integer FindDialog) function. The function returns the block number of the resulting
block found; it returns a –1 if no matching block is found. Find-
BlockName is the name of the block to be found (e.g. ‘Catch’, or
‘Throw’). FindBlockLabel is the block label of the block to be
found. FindDialogName is the name of the dialog item you wish
to search for. The FindDialogName field should be filled with the
dialog item name, a colon, and then the value of the dialog item
that you wish to search for. For example Item:54 will search for
the presence of a dialog item with the name “item”, and the value
“54”. FindDialog takes the following values: 0: just check the
block name, and the block label. 1: just check the block name and
the dialog item name and value. 2: check the name, label, and dia-
log item.
FindInHierar- The same as the FindInHierarchy function except it takes a block I
chy2(integer block- number argument.
Number, string
findBlockName,
string findBlockLa-
bel, integer findDi-
alog)
GetBlockLa- Returns the label string for the global block i. S
bel(integer i)
GetBlockMem- Returns the number of bytes of memory used by the block. I
Size(blockNumber)
GetBlock- Returns the string that represents the category (e.g. Math or Hold- S
Type(integer i) ing) for the global block i. Block categories are set in the Develop
> Set Block Category menu.
Functions
Functions
8: STRING15TYPE
9: STRING31TYPE
10: STRING63TYPE
11: STRING127TYPE
GlobalToLocal Returns the local block number for the specified block if it is con- I
(integer blockNum- tained in an H-block. Returns a -1 if the block is not contained in
ber) an H-block.
IconBody (block- Similar to the BlockRect function. Returns the rect for the body of I
Num, real array[4], the icon, allowing (via the useAnimation and useConnectors argu-
useAnimation, use- ments) control over whether the animation objects and/or connec-
Connectors) tors are included in the rect.
Returns a zero for success or a non zero value for an error.
298 Reference
Blocks and inter-block communications
Block numbers,
Description Return
labels, etc.
LocalNumBlocks() Number of internal blocks in the hierarchical block from which I
this function is called. Blocks are numbered from 0 to Local-
NumBlocks()-1.
LocalNumBlocks2 This is same as LocalNumBlock(), except it refers to a global I
(integer block) block number.
LocalToGlobal Converts a local number in the hierarchical block from which this I
(integer i) function is called to a global number.
LocalToGlobal2 Similar to LocalToGlobal, this function will return the global I
(integer Hblock- blocknumber for a local one. The difference is that this function
Num, integer local- allows you to specify which Hblock in the model is used as the
BlockNum) context for the local block number via the first parameter Hblock-
Num.
MakeOptimizer- This function tags the block as an optimizer block so that the V
Block (integer true- Run > Run Optimization command will send a RUN message to
False) that block, assuming there is a “Run" button in the block that will
run the optimization and has an "ON RUN" message handler. Call
this function in "CREATEBLOCK." See the Optimizer block
(Value library).
MyBlockNumber() Global number of the block in which the function is called. Note I
that this number is the first number shown in parentheses in the
block dialog’s title.
MyLocalBlock- Local number of the block in which the function is called. Note I
Number() that this number is the second number shown in parentheses in the
block dialog’s title.
NumBlocks() Global number of blocks in the model, including text blocks and I
unused slots. Blocks are numbered from 0 to NumBlocks()-1.
ObjectIDNext(Inte- Returns the objectID of the next object of the type requested, as I
ger fromBlock, controlled by the which variable. You can step through all the
integer which) blocks in the model quite a bit faster than in V9 since, depending
Functions
on the which value, you can just jump to the next block.
FromBlock specifies where in the list to begin, so it will normally
be started at -1. Which currently takes the arguments:
0: blocks
1: Hblocks
2: both regular and Hblocks
The pseudo code for using the function:
objectID = objectIDNext(-1, 0);
while (objectID > -1)
{
objectID = objectIDNext(objectID, 0);
}
This will loop through all the blocks in the model without needing
to call numblocks or getBlockTypePosition.
ModL Functions 299
Blocks and inter-block communications
Block numbers,
Description Return
labels, etc.
SetBlockLabel Sets the label for the global block i to str. Blocks are numbered V
(integer i, string from 0 to NumBlocks()-1.
str)
ShowBlockLabel Labels are shown by default. To hide a block’s label, use this V
(integer i, integer function with the global block number i and FALSE for show.
show)
Functions
intArray[][2]) The first column of intArray contains the global block number of
a connected block, the second column contains the connector
number of that connected block. Rows and columns are indexed 0
to n-1. IntArray is declared as a dynamic array:
integer intArray[][2];
GetConHblocks Similar to the GetConBlocks() function, above, but returns a list I
(integer blockNum- of connected Hblocks. You can also start from a textblock or
ber, integer iConn, anchor point if you know the block number (connector numbers
array y[]) are zero for textblocks or anchor points).
GetConName (inte- Name of the connector. S
ger block, integer
conn)
300 Reference
Blocks and inter-block communications
Functions
integer conn)
MakeFeedback- If feedBack is TRUE, this function causes ExtendSim to terminate V
Block(feedBack) the flow order search for this block. For multiple feedback cases,
this function prevents feedback from unexpectedly changing the
main flow simulation order. For an example, see the Feedback
block (Utilities library).
NodeGetCurrent- Returns the currently set value of the connected block connectors. R
Value(nodeIDIn- See NodeGetIDIndex(), below.
dex)
NodeGetIDIn- Returns the nodeID for a connected network of block connectors. I
dex(blockNumber, Each connected network has a unique nodeID, which can change
conNum) when additional block connectors are connected or the model is
reopened. The nodeID is equivalent to an index of a real value
that holds the set value of the connected connectors.
302 Reference
Blocks and inter-block communications
Variable connectors
These functions are used with a block’s variable connectors, and to interface them with the
standard connector functions. Note that all of the single connector functions, above, also work.
Where conn is specified in the argument list, use ConArrayGetConNumber() to find the actual
connector number on the block from the array owner and nth connector in the array. For exam-
ple, to send a message out of a variable connector, call ConArrayGetConNumber() to get the
actual number of the connector (its index). Then call SendMsgTo…() and instead of using the
actual connector name (e.g. FlowIn), use V7’s new feature and use the connector number you
got from ConArrayGetConNumber().
These connector functions use a block number and the connector name as a string so you can
use them to control other blocks.
Functions
ConArrayGetNth- Given a block connector number, returns the member index of its I
Con(conn) connector array (e.g. Given the block connector number of
ConIn[3] (could be 253), returns 3 meaning ConIn[3]). A -1
returned is an error.
ConArrayGetNth- Same as ConArrayGetNthCon except it has an additional argu- I
Con2(blocknum, ment to specify the connector on a different block.
conn)
ConArrayGetNum- Returns the number of connectors in this array. If there are no I
Cons(blockNumber, added array connectors, returns 1 for the original connector. Orig-
origConNameStr) ConNameStr is the owning connector name as a string.
304 Reference
Blocks and inter-block communications
ConArraySetCol- Sets the collapsed state on the specified connector. True will col- V
lapsed(integer lapse the connector, and False will uncollapse it.
blockNumber, string
origConName, inte-
ger trueOrFalse)
ConArraySetNum- Call this to set the number of connectors in a variable connector (a V
Cons(blockNumber, 1 for NewNumCons means to only keep the original connector).
origConNameStr, If trueToIgnoreConnections is TRUE, the user can delete connec-
newNumCons, true- tors that have connections on them. If trueToIgnoreConnections is
ToIgnoreConnec- FALSE, connectors that have connections on them will not be
tions) deleted. This means that connections may prevent all of the
desired connectors from being deleted.
ModL Functions 305
Blocks and inter-block communications
Functions
string.
ConnectorToolTip- When the ConnectorToolTip message is received, this function I
Which() returns the connector index of the connector the cursor is over.
This function is also used in the ConnectionMake message to
return the connector being connected.
Dialog items
These functions work with a block’s dialog items and can be used to get and set values from
dialog items in other blocks, as well as change dialog item colors, create popup menus, hide
and show items, etc.
The functions in this list that include a global block number in their argument list can affect
any block in the model, including the calling block if its own block number (from the
MyBlockNumber() function) is used.
306 Reference
Blocks and inter-block communications
☞ Block controls (switch, slider, and meter) can be set or changed via the Get/SetDialogVariable
functions or poke/request functionality just the same way other types of blocks can. In the case
of the block meter, this is easy to recognize, as this control has a dialog, and therefore all the
pieces that you need for setting and getting the values are available. (Block number, and dialog
item name.) In the case of the slider and the switch it’s not so obvious, as these controls don’t
have dialogs, and therefore the dialog item name is not readily available. The names for these
dialog items follow the pattern of the meter, and therefore are as follows:
• Switch: value – This is whether the switch is on, or off, and just takes a value of 0, or 1.
• Slider: value – The current value of the slider. (The position of the thumb.)
• lower – The value of the lower bound of the slider.
• upper – The value of the upper bound of the slider.
☞ For additional formatting options, see “Formatting/interactivity using column and parameter
tags” on page 321. These facilitate both specialized formatting and mouse-interactivity with
parameters and data tables. Also see “Block data tables” on page 312, “Dynamic text items” on
page 320, and “Dynamic linking” on page 317.
blockNumber) return an empty string "" if there are no dialog items of this type
in the dialog.
DialogItemVisible Returns a true value if the specified dialog item is visible. If the I
(integer blockNum- Clones value is a one (TRUE) this function checks to see if any
ber, string variable- clones of the specified item are visible; otherwise it checks to see
NameStr, integer if the primary item is visible.
clones)
DIGetID(integer Returns a dialog item ID number. This is used in the LINKCON- I
blockNumber, TENT and LINKSTRUCTURE message handlers to help identify
string name) which dialog item is getting the message.
DIMoveBy(integer Offsets the dialog item by the values of the y and x parameters. I
blockNumber,
string name, inte-
ger y, integer x)
ModL Functions 307
Blocks and inter-block communications
PopupCanceled() Returns whether or not the last popup menu was canceled. This I
can be called immediately after a ‘flying’ popup menu has been
created, to determine if the user canceled the popup menu action
or not. Canceling would be clicking off the popup menu, without
making a selection.
PopupItem- This function parses the string that is passed in, and removes the S
Parse(itemString) special characters that are used in certain dialog item contexts.
Specifically, it removes the formatting notation (e.g. <RB> for
right adjusted, bold), characters that are user for formatting, and
returns the stripped string.
ModL Functions 311
Blocks and inter-block communications
SetDialogItemE- Sets the color of the dialog item based on the passed in EColor I
Color (long block- value.
Name, string
dialogItemName, See “EColors” on page 401 for more information.
long value)
SetDialogVariable Sets the value of the named variable to the given numeric or string V
(integer blockNum- value. The variable can be any dialog item, static variable, global
ber, string variable- variable, or dynamic array. Row and col apply to the cells of a
NameStr, string data table or text table. For Sliders or Meters, row must be zero
value, integer row, and col is 0 for the minimum, 1 for the maximum, and 2 for the
integer col) value. Row and col are ignored for other types of items.
☞ See also SetVariableNumeric, which should be faster when
Functions
setting non-string values.
SetDialogVariable- Same as SetDialogVariable function, but doesn’t send a dialog V
NoMsg(integer item message to the block.
blockNumber,
string variable-
NameStr, string
value, integer row,
integer col)
SetPopupLa- Sets the named popup menu items to theLabels string. The menu V
bels(string vari- items should be separated by semicolons (;). This function is sim-
ableNameStr, string ilar to SetDataTableLabels in that the changes made by this call
theLabels) are not permanent within a block's dialog. Changes made by this
call are permanent, however, for cloned copies of popup labels.
VariableNameStr is the dialog item name as a string or in quotes.
See AppendPopupLablels() above to add more labels.
312 Reference
Blocks and inter-block communications
quotes.
☞ Starting in ExtendSim 7, you must access all data tables using their dialog item variable name.
Even dynamic data tables need to be accessed using the dialog variable name. This was not the
case in Extend 6 or earlier, but is a ModL compiler change that is necessary to allow data tables
to transparently access linked database or global array data, and to be variable column. Using
the dynamic array name will not allow linked or variable column data tables to work.
☞ If you need large data tables, see the Dynamic data table functions below.
Variable column data tables
The DynamicDatatableVariableColumns function, and the supporting functions that have been
built for it, allow the creation and use of a data table with both variable rows and variable col-
umns. The starting point is a call to the DynamicDatatableVariableColumns function which
will link a dynamic array to a data table, in much the same way as the DynamicDatatable func-
ModL Functions 313
Blocks and inter-block communications
tion, with the addition of allowing the user to define the number of columns that the table sup-
ports.
Each time you want to change the number of columns in the data table, you call Dynamic-
DataTableVariableColumns again with the new number of columns. The internal implementa-
tion of this construct is basically that the link between the data table and the dynamic array
contains the information about the number of columns. This means that you cannot use the
dynamic array variable name to refer to the data, as the dynamic array still has the original
definition of how many columns it has. To reference your data with the variable number of col-
umns, you need to refer to it using the data table variable name, as the data table will use the
information in the link to determine how many columns it has. See “OLE/COM (Windows
only)” on page 253 for OLE functions that fill variable column data tables.
Dynamic data table resizing
The following functions are designed to be support functions for dynamic data table resize
functionality. This functionality is implemented partially through block code, and partially
through the ExtendSim Application. The basic functionality, as seen on dialog boxes in both
the Item and Value libraries, is a button on the lower right hand corner of the data table that can
be clicked popping up a dialog that allows the user to specify the resizing options for the data
table. The application level implementation is the drawing and behavior of the button on the
data table. The presence or absence of the button can be controlled from the block code via the
DTGrowButton function described below. When the button is clicked, the block will receive a
DATATABLERESIZE message. The code of this message handler is where the majority of the
block code controlling the resizing will be executed. Normally the code in this message han-
dler will first be a call to NumericParameter, or NumericParameter2 to determine the desired
resizing of the table, followed by the necessary code to implement the resizing. See the Vari-
able Columns data table section above. See the blocks in the Value and Item libraries for
examples of this code.
Data table linking
Data tables can be linked to global arrays or an ExtendSim database by the user clicking the
Link button at the lower left corner, or using the linking functions below. When the data or
structure that they are linked to changes, LINKCONTENT or LINKSTRUCTURE messages
are sent to individual blocks that are subscribed to an ExtendSim database or global array. See
“Dynamic linking” on page 317.
☞ Starting in ExtendSim V, you must access all data tables using their dialog item variable name.
Even dynamic data tables need to be accessed using the dialog variable name. This was not the
Functions
case in Extend 6 or earlier, but is a ModL compiler change that is necessary to allow data tables
to transparently access linked database or global array data, and to be variable column. Using
the dynamic array name will not allow linked or variable column data tables to work.
Formatting individual columns
For additional formatting options, see “Formatting/interactivity using column and parameter
tags” on page 321. These facilitate both specialized formatting and mouse-interactivity with
data tables.
314 Reference
Blocks and inter-block communications
DTRowHeightSet Sets the height of the rows for a data table object. This function I
(integer block- overrides the row height value set in the structure for a data table.
Num, string
DTName, integer All the rows of the data table will be set to the same height.
height) Returns a zero for success, or a non zero value for an error.
DTToolTi- In conjunction with the DataTableHover message handler dis- V
pSet(string caption- cussed on page 219, this function allows you to show custom tool
String) tips when the cursor hovers over a data table.
DynamicDataT- This function attaches a dynamic array to a dialog data table. This I
able(integer block- allows dynamically resizable data tables, and the ability to change
Number, string what data is displayed in a data table without recopying the data.
dataTableName, You can attach the array to the data table at any time, but it will
array dynamicAr- need to be reattached (dynamicDataTable will need to be called)
rayName) each time that the dynamic array is resized.
ModL Functions 315
Blocks and inter-block communications
Width(integer width. Please note that column number for this function is zero
blockNumber, based starting from the title column, to allow reference to the title
string name, integer column. This means that the first column with data in it is column
column, integer one, unlike most other functions that reference data table col-
width, integer umns.
doClones)
SetDTRowStart Sets the named data table to have its row numbers start at the indi- I
(integer blockNum- cated value. (i.e the first row number, normally zero, will be row-
ber, string name, Start) (0 successful, 1 failed)
integer rowStart)
ModL Functions 317
Blocks and inter-block communications
Dynamic linking
Dynamic linking creates a link between a dialog item (data table or parameter) and a data
source (ExtendSim database or global array). This is a very powerful feature because the links
are live and dynamic—they update instantly when there is a change in the data source.
The ExtendSim user interface allows the modeler to create dynamic links just by right-clicking
on a parameter or clicking the Link button at the lower left of a data table. In addition, Extend-
Sim provides functions, described below, that allow control over how the links are to be cre-
ated and controlled.
For database linking using scripting see the DBDatatable function on page 375 and the DBPa-
rameter function on page 376. For global array linking using scripting, see the GADatatable
function on page 380 and the GAParameter function on page 383. Also see “Database func-
tions” on page 354 and “Global arrays” on page 378.
To simply register a block so that it will be notified if there was a database change, see “Regis-
Functions
tered blocks” on page 111 and “Linking and notification” on page 374.
☞ Starting in ExtendSim 7, you must access all data tables using their dialog item variable name.
Even dynamic data tables need to be accessed using the dialog variable name. This was not the
case in Extend 6 or earlier, but is a ModL compiler change that is necessary to allow data tables
to transparently access linked database or global array data, and to be variable column. Using
the dynamic array name will not allow linked or variable column data tables to work.
318 Reference
Blocks and inter-block communications
Name, integer dis- the block developer to hide this button. This should have the
ableIfTrue) added effect of disabling the link menu command. Return a neg-
ative error number or zero if no error.
ModL Functions 319
Blocks and inter-block communications
Functions
recordIndex) 2: Database
320 Reference
Blocks and inter-block communications
For an example of how to use dynamic text items, look at the Equation block (Value library).
The data table and parameter dialog items check which column tags have been set, and draw
their data, or respond to clicks appropriately.
☞ The Data Init block (Value library) is an example of using column tags.
The basic mechanism for setting a param tag, or column tag, is to call either the DIParam-
TagSet or the DTColumnTagSet function. Column and param tags are not saved when the
model is closed, so the tags are commonly reset in the OpenDialog and CloneInit message han-
dlers.
If you set a column tag that has a value higher than 99, it will be stored as a HeaderTag. Head-
erTags are stored independently from column tags, and will store a behavior for the header for
that column, not for the individual cells in the table. (See Header tags below for more informa-
tion.)
In the data table case, column values start at zero, with zero referring to the first column after
the row column. Each column has four pieces of information that can be associated with it:
Two integer values, the tag itself, a tagOption value, and two string values, the TagString1 and
TagString2. ParamTags for parameters have just one number, the paramTag, and the same two
strings.
The primary tag sets the default behavior for the column/parameter. The TagOption value is
used for specific purposes by some of the tags below, and can also be used to disable the col-
umn using the TAGDISABLE value.
The TagString1 value is the lookup name in the case of string Lookup table columns, for other
tags it’s used as needed. TagString2 is used by some tags. For any tag that displays a string,
except the SL tags and the DBFIELD tag, putting a string into the string1, or string2 field will
prepend the string from string1, and/or append the string from string2.
The column/parameter tags are listed below. The symbol name definitions can be found in the
include file “\Extensions\Includes\ColumnTags v10.h”.
Functions
other meaning of the tag in the column tag.
Tag_- 100 Tags the column/parameter header as being a popup menu. Note: this
Head_Tag_Popup does not change the behavior of clicking on the cell, just the appear-
ance of the cell. The popup behavior needs to be implemented in block
code.
Tag_Hide 98 Tags the column/parameter as being hidden.
324 Reference
Blocks and inter-block communications
Tag_SL_Append 17 Tags the column as containing string lookup values, appended with the
string in tagSstring2.
Tag_SL_Pop 11 Tags the column/parameter as containing string lookup values that
function as popup menus when clicked.
Tag_SL_Prepend 16 Tags the column as containing string lookup values, prepended with
the string in tagString2.
Tag_Str_Flag 80 Tags the column as a numeric column where the colstring will be dis-
played when the value in a cell is a negative one. Otherwise, the col-
umn will be treated as a standard numeric data column.
Tag_Str_Flag_- 81 The same as Tag_Str_Flag, except it doesn’t allow editing.
Noed
ModL Functions 325
Blocks and inter-block communications
The functions WhichDialogItem(), and whichDTCell() can be used with this functionality to
find which dialog item the cursor is currently hovering over.
Functions
blockNumber)
SetDefaultTab- Sets the block so that the dialog will open at a specific tab name. V
Name (string tab-
Name, integer
blockNumber)
VariableNameTo- Returns the name of the tab of a dialog that the indicated dialog S
TabName(string item is on.
varName, integer
blockNumber)
messages to blocks can be used to enable global functions. You can put many functions in a
custom function block, then use the SendMsgToBlock function to send one of the user-defined
messages. Use global variables to select a function and pass parameters to and from the func-
tion. Blocks can also send and receive connector messages and propagate them correctly, as
discussed in “Basic item messaging” on page 174.
In the functions, connName is the name of the connector in the calling block and block is the
global block number of the receiving block. (See “Block numbers, labels, names, categories,
position” on page 295 .)
nName) a specific block first, no matter what the order of connections. Use
this function in INITSIM or CHECKDATA. For example, the Sta-
tus block uses this function.
GetMsgSending- Returns the blocknumber of the block that sends the currently I
Block () executing message to the current block.
ModL Functions 329
Blocks and inter-block communications
Functions
will get an “on xxx” message where xxx is the connected receiv-
ing block’s connector name.
SendMsgToBlock Sends a message to the specified global block. The message is an V
(integer block, inte- ExtendSim constant that corresponds to the message to be sent.
ger messageCon- The messageConstant is not a string. It is derived by taking the
stant) message name and adding MSG after the message name. For
example, to send a USERMSG0 to a block, messageConstant
would be USERMSG0MSG (not a string). See the chapter “Mes-
sages and Message Handlers” on page 213 for all the messages
that can be sent. Note: If the block is a hierarchical block, the sub-
model blocks will not receive the message. Instead, use the
SendMsgToHblock function discussed in this section.
330 Reference
Blocks and inter-block communications
Icon views
These functions are used to interrogate and control block icon classes and views. Classes are
global (e.g. Flowchart class) and always set by the modeler, but views (e.g. Flow down) can be
set by the modeler or the block.
The default class (ExtendSim classic) and view are both zero.
☞ As of ExtendSim 10, icon classes were eliminated.
Classes and views Description Return
Functions
IconGetClass (inte- Gets the current class (0 to 7) of the block, but classes are cur- I
ger blockNumber) rently global, so the entire model will have this class.
IconGetView (inte- Gets the current view (0 to n) of the block. See IconGet- I
ger blockNumber) ViewName(), below.
IconGet- Returns the name of the view specified. S
ViewName (inte-
ger blockNumber,
integer view)
IconSetViewByIn- Sets the block’s view by index (0 to n). V
dex (integer block-
Number, integer
index)
ModL Functions 331
Models and notebook
Functions
(others will be defined in the future)
GetLibraryPath- Function to return the pathname of a library file, given a block in S
Name (integer that library.
blockNumber, inte-
ger specify) specify takes the following values:
1: pathname without library name
2: just library name
GetLibraryString- Returns string information about the library that the block comes S
Info (integer block- from. Specify takes the following values:
Number, integer
specify) 1: Name
(others will be defined in the future)
332 Reference
Models and notebook
Functions
the unlocking case. This function returns a zero if is succeeds, and
the following error codes for specific error conditions:
-1: Unlock password didn’t match.
-2: Model is already locked, it cannot be locked again without
being unlocked first.
-3: lock value out of range.
NotebookClose() Closes the notebook if it is open. I
334 Reference
Models and notebook
OpenNotebook() Opens the model notebook. Since this is from v9, which only had V
one notebook per model, see also OpenNotebook2.
OpenNote- Opens the specified notebook, either for the model worksheet or V
book2(integer for an Hblock. BlockNumber controls which set of Hblock note-
blockNumber, inte- books is referenced by the Index. Pass in the number of a block at
ger Index, integer the top level of the main worksheet or a -1 for blockNumber to get
ripOff) to the top level notebooks. Otherwise, the blockNumber will be
used to identify which Hblock's set of notebooks will be refer-
enced by the Index. If the blockNumber is for a block inside an
Hblock, that Hblock's notebooks will be referenced, otherwise the
blockNumber will identify the hblock itself. If ripOff is true, the
notebook will be opened in the ripped-off state. If false, the note-
book’s tab will be selected.
ModL Functions 335
Models and notebook
Functions
the Equation block to save and close Include files.) Returns 0 for
success or a negative value to indicate failure.
SetBlockSimula- Sets the simulation order value of the specified block. This is only I
tionOrder (integer useful, or allowed if the model simulation order has been set to
blockNumber, inte- custom simulation order. This function returns a zero if success-
ger newOrder) ful, and the following error codes if it fails:
-1: can’t be set during a simulation.
-2: newOrder must be greater than zero.
-3: no active model document.
-4: sim order is not set to custom.
-5: no such block.
336 Reference
Models and notebook
showDuringRun)
showDuringRun determines if the cursor is shown during a simu-
lation or not.
SpinCursorStop() Stops a spinCursor started by spinCursorStart. V
Scripting
These functions are useful in building or changing models when called from blocks or from
other applications. See also the GetDialogVariable() and SetDialogVariable functions under
“Dialog items” on page 305.
See the Scripting blocks in the ModL Tips library for examples of scripting.
ClearConnec- Removes the connection between the specified blocks and con- I
tion(integer block- nector numbers. Returns TRUE if successful.
From, integer
conFrom, integer
blockTo, integer
conTo)
ClearUndo(void) Clears the Undo list and removes any existing undo tasks from V
the Edit menu. After executing this function, the Undo command
will be disabled.
ModL Functions 339
Scripting
Functions
string variable- ableName. If variableName is blank, all of the clone IDs for that
Name, integer block are returned in the array.
cloneIDArray[])
CloneGetPosi- PositionArray is declared as an array of 4 integers. It returns the I
tion(integer following information: positionArray[0] = cloneRect.top, posi-
cloneID, integer tionArray[1] = cloneRect.left, positionArray[2] =
positionArray) cloneRect.bottom, positionArray[3] = cloneRect.right.
CloneHideDis- Disables/enables or hides/shows the specified clone. I
able(integer If disable is True and disableIFtrue is True, the clone is disabled.
cloneID, integer If disable is True and disableIFtrue is False, the clone is enabled.
disable, integer dis- If disable is False and disableIFtrue is True, the function hides
ableIFtrue) the clone; the clone appears if disable is False and disableIFtrue
is False.
Returns zero if successful; otherwise returns an error code (nega-
tive number).
340 Reference
Scripting
FindBlock (string Finds the first block that matches the string searchStr and returns I
searchStr, integer its block number, optionally opening the dialog or selecting the
which, integer block. Which specifies what string in the block you want to com-
openDialogs, inte- pare your searchstring to. It takes the following values:
ger wholeWords,
integer justBlock- BlockLabel:1, BlockName:2, BlockType:3, TextBlockText:4
Num) openDialogs specifies if the block should be just selected, or if
the dialog should be opened. It is overridden by the justBlock-
Num parameter, if it is TRUE. WholeWords specifies if you want
the text to try for an exact match, or to match a partial string. The
final argument justBlockNum if set to true will set the function to
just return a block number, and neither select the block nor open
the dialog.
ModL Functions 341
Scripting
Reporting
These functions are used in the BlockReport message handler to organize reports written by
blocks.
Plotting/Charts
These functions allow you to provide graphs and data in any block you create.
Each trace can be assigned one of two Y axes, Y and Y2, so that traces of different magnitudes
can appear in the same plot.
Some of these functions only apply to the blocks in the Plotter library which is a Legacy library
that was replaced by the Chart library as of ExtendSim 10.
The following arguments are used in the plotting functions:
Functions
33: BlackColor
205: RedColor
341: GreenColor
409: BlueColor
273: CyanColor
137: MagentaColor
EndTime X-axis value that corresponds with the last point of the array.
FunctionName Name of a real, single argument function. For example, cos(x) should be
entered as cos.
IsXLog If TRUE, the X axis is logarithmic.
IsY2Log If TRUE, the Y2 axis is logarithmic.
IsYLog If TRUE, the Y axis is logarithmic.
346 Reference
Plotting/Charts
Y axis.
WhichSig Number (0, 1, 2 ...) specifying one of the plot traces
Y Name of the dynamic array used in the plot. Use MakeArray to allocate Y
before using it in a function.
General plotting
☞ See Pie Chart, Bar Chart, and Scatter Chart functions starting on page 353.
General plotting Description Return
AutoScaleX(inte- Finds the minimum and maximum X axis values of all installed V
ger plot) arrays or installed scatter arrays and adjusts the X axis limits
accordingly. See also the PlotterAutoScaleLimits function.
ModL Functions 347
Plotting/Charts
Functions
ClosePlotter(inte- Closes the plot window, if open. V
ger plot)
ClosePlotter2 (inte- This function just closes the specified plotter window, if it is open. V
ger blockNumber,
integer plot)
DisposePlot(inte- Disposes of a plot window and all its saved plots. This does not V
ger plot) dispose of any installed data arrays.
GetAxis(integer Fills the first nine elements of the axisValues array (declared as V
plot, real axisVal- real axisValues [9]) with the current values of isXLog, xLow, xHi,
ues[9]) isYLog, yLow, yHi, isy2Log, y2Low and y2Hi.
348 Reference
Plotting/Charts
InstallArray(inte- Allows the automatic plotting of arrays. The plot window will V
ger plot, integer plot all the points of this array up to plotPts-1. It should be pre-
whichSig, string ceded by InstallAxis and eventually be followed by showPlot.
sigName, real y, The first time arrays are installed they need to be installed in
real StartTime, real sequential order. The Install Array call is used in two ways in
EndTime, integer plotter blocks. The first time it is called, it installs the array and
plotPts, integer sets parameters such as the color of the line. The second and sub-
useY2Axis, integer sequent times, the formatting options are ignored, and the only
pattern, integer action a call to installArray takes is to reinstall the array itself. If
color) you precede a call to InstallArray with a call to RemoveSignal,
the formatting information will be used.
Note: patterns are not supported as of release 10.
ModL Functions 349
Plotting/Charts
Functions
ger plot, integer ful when you want to see points plotted as they are calculated
whichSig, integer within a loop (such as during simulations). To use this effectively,
index, real yValue) first use InstallArray with a value of 0 for the plotPts argument.
PlotNewPoint increments the plotPts of the installed array when
the point is plotted, and the equation “y[index] = yValue” is inter-
nally executed, putting the new yValue into the installed array.
Note that the first value of index must be 0 when calling PlotNew-
Point for a newly installed array.
PlotSignalFormat Specifies the line format and number format for the trace. V
(integer plot, inte-
ger whichSig, inte-
ger lineFormat,
integer numFor-
mat)
350 Reference
Plotting/Charts
PlotterSignalECol- Sets the color of the specified signal. See “EColors” on page 401. V
orSet (integer plot,
integer whichSig,
integer EColor-
Value)
PlotterSignalVal- Returns a value associate with the specified signal. The which- I
ueGet (integer plot, Value argument specifies the number of the signal:
integer whichSig, 0: Color (prior to ExtendSim 10)
integer which- 1: Hue (prior to ExtendSim 10)
Value) 2: Sat (prior to ExtendSim 10)
3: Value (prior to ExtendSim 10)
Functions
4: Signal visibility
5: use Y2Axis
6: Line format
7: Line symbol
8: Line thickness
10: EColor Value to set the signal line color
PlotterSignalValue- Sets the value of a specified aspect of a plotter signal. Which val- I
Set (integer plot, ues are the same as for PlotterSignalValueGet.
integer whichSig,
integer which-
Value, integer
value)
ModL Functions 351
Plotting/Charts
Functions
to attempt to draw the rest of the points in the data unnecessarily.
PushPlotPic(inte- Pushes the top plot picture, page 1, down to page 2 of the plot V
ger plot) window. The oldest plot (page 4) is discarded. This function only
works if the plot is showing when the function is called.
RefreshPlot- Function that will redraw the plotter without opening the plotter V
ter(integer plot, window if it is closed. Used for redrawing the clones of a plotter
integer whole- when a change has occurred.
frame, integer
openPlotterWin-
dow)
RemoveSig- Removes the last installed array or function from the plot. V
nal(integer plot,
integer unused) For unused, enter any integer; 0 is suggested.
352 Reference
Plotting/Charts
SwitchPlotterRe- Specifies the direction in which the plot will be redrawn. A direc- V
draw(integer plot, tion of 0 specifies left to right, a direction of 1 specifies right to
integer direction) left. This only affects the way that the plot lines are redrawn when
the plot is complete.
Remember to call the ShowPlot function to replot any changes made by these functions. Be
sure to call ShowPlot after all calls that change the plot axis limits or formats.
The structure and contents of plots are saved with the model file, whether they were open or
not.
ModL Functions 353
Plotting/Charts
Functions
Set(integer plot, the which value is out of range.
integer which,
string catego-
ryName)
BarChartSet(inte- Creates a new set, or modifies an existing set in the specified Bar V
ger plot, integer set, Chart. Set is the index value of the set.
string setLabel,
integer color)
BarChartVal- Gets the value for a specified Bar Chart. R
ueGet(integer plot,
integer whichSet,
integer which-
Value)
354 Reference
Database functions
To see how the plotting functions can be used in your own blocks, examine the plotter func-
tions that are used in the code of the various blocks in the Chart library.
Database functions
These are used to create, read, write, import, export, and delete databases and their compo-
nents. They are used by blocks to create and manipulate databases during a run. All database
indexes are 1 based, so they start at 1 and end at N. Databases and tables maintain their
Functions
indexes, even when other databases or tables are deleted. Fields and record indexes can change
if earlier fields or records are deleted.
☞ Reserved databases use specially named functions to manipulate them so they don’t inadver-
tently get changed by the user or developer. These functions have the word “Reserved” in their
name.
Blocks can be linked to parts of the database, so if the database structure or data changes, they
will be notified and can take action. See “Dynamic linking” on page 317 and the LINK-
STRUCTURE and LINKCONTENT messages.
Error codes
For database read/write functions, the Database menu command “Read/Write Index Checking“
can enable error messages if a read/write function call has illegal indexes. This is a good tool to
find illegal indexes and leaving this check on does not impact the speed of a simulation run.
ModL Functions 355
Database functions
Leave it off if it is preventing a legacy model from running. New models have this check on by
default.
In most cases, functions return zero if no error, or non-zero error codes when an error occurs:
Functions
existingTabName)
DBFieldCreate(string Creates field fieldName with specified attributes tableName I
databaseName, string and returns its index. Error: returns negative error code if
tableName, string existing name already used.
fieldName, integer Field format constants defined:
fieldFormat, integer DB_FIELDTYPE_INTEGER_VALUE, DB_FIELD-
decimals, integer TYPE_INTEGER_BOOLEAN (checkbox), DB_FIELD-
unique, integer TYPE_REAL_GENERAL,
readOnly, integer DB_FIELDTYPE_REAL_SCIENTIFIC, DB_FIELDTYPE_-
invisible) REAL_PERCENT, DB_FIELDTYPE_REAL_CURRENCY,
DB_FIELDTYPE_REAL_DATE_TIME, DB_FIELDTYPE_-
REAL_DB_ADDRESS, DB_FIELD-
TYPE_STRING_VALUE, DB_FIELDTYPE_TABLELIST
356 Reference
Database functions
baseName, string
tableChildName, string
fieldChildName, string
tableParentName,
string fieldParent-
Name)
DBRelationDe- Delete relation. Returns negative error code if relation doesn't I
lete(string data- exist.
baseName, string
tableChildName, string
fieldChildName, string
tableParentName,
string fieldParent-
Name)
ModL Functions 357
Database functions
Functions
component.
dex, integer toDataba- Returns index of the new table or -1 if error (bad index or
seIndex, string same table name as existing table in that database).
newTableName)
Database properties
Functions
DB properties Description Return
DBDatabaseExists Passing in a database index, returns TRUE if the database I
(integer databaseIn- exists, FALSE if it doesn’t exist. Also see DBTableExists(),
dex) DBFieldExists(), and DBRecordExists().
DBDatabaseGetIn- Returns database index or negative error if not found. I
dex(string data-
baseName)
DBDatabaseGet- Gets the name of the database or blank string if bad index. S
Name(integer databa-
seIndex)
360 Reference
Database functions
tableIndex, integer
fieldIndex)
DBFieldGetProper- which: I
ties(integer databaseIn- 1: fieldType
dex, integer 2: fieldDecimals
tableIndex, integer 3: fieldUnique
fieldIndex, integer 4: fieldReadOnly
which) 5: fieldInvisible
6: IfFieldID
7: isParentField (note: use judiciously; this is very slow)
8: isChildField, (note: use judiciously; this is very slow)
-1 if error
Also see the DBFieldCreate() function on page 355.
ModL Functions 361
Database functions
Functions
tableIndex)
DBRecordExists(inte- Passing in a database index, table index, field index, record I
ger databaseIndex, index, returns TRUE if the record (database cell) exists,
integer tableIndex, FALSE if it doesn’t exist. Also see DBDatabaseExists(),
integer fieldIndex, DBTableExists(), and DBFieldExists().
integer recordIndex)
362 Reference
Database functions
Functions
childDBAddress, inte- Reads the value as a number without any formatting. Note that
ger altFieldIndex) random distributions in cells will return a different random
number each time that this function is called.
Note: Using this function to read a “List of Tables” field
returns the index of the table read.
DBDataGetAsNumbe- Using a DBAddress, read the value as a number without any R
rUsingAddress(real formatting. Note that random distributions in cells will return
dbAddress) a different random number each time that this function is
called.
Note: Using this function to read a “List of Tables” field
returns the index of the table read.
364 Reference
Database functions
recordIndex, integer
timeUnits)
DBDataGetDateAs- Using a dbAddress, reads a database cell as a date, and con- R
SimTimeUsingAd- verts it to a simulation time value. This allows the user to read
dress(real a date value directly as a simulation time value, avoiding the
addressValue, integer conversion process.
timeUnits)
ModL Functions 365
Database functions
Functions
DBDataSetAsNumbe- Using a DBAddress, write value of field as number to a I
rUsingAddress(real record. Returns a negative error code. Only sends LINKCON-
dbAddress, real val- TENT message to block if value has changed.If setting a
ueDouble) unique field cell to a non-unique value, returns the record
index of the original unique value. See DBDataSetAsNumbe-
rUsingAddressReserved(), which works only with reserved
databases.
DBDataSetAsNumbe- This function works only with reserved databases. Otherwise, I
rUsingAddressRe- it is the same as DBDataSetAsNumberUsingAddress(), which
served(real dbAddress, works only with non-reserved databases.
real valueDouble)
366 Reference
Database functions
recordIndex, string val- index of the original unique value. See DBDataSetAsStrin-
ueString) gReserved(), which works only with reserved databases.
DBDataSetAsStrin- This function works only with reserved databases. Otherwise, I
gReserved(integer it is the same as DBDataSetAsString(), which works only with
databaseIndex, integer non-reserved databases.
tableIndex, integer
fieldIndex, integer
recordIndex, string val-
ueString)
ModL Functions 367
Database functions
Functions
TimeVal, integer
timeUnits)
DBDataSetDateAs- This function works only with reserved databases. Otherwise, I
SimTimeUsingAd- it is the same as DBDataSetDateAsSimTimeUsingAddress()
dressReserved(real which works only with non-reserved databases.
addressValue, real sim-
TimeVal, integer
timeUnits)
368 Reference
Database functions
returnParams[0] = distributionIndex;
returnParams[1] = meanDistParam1;
returnParams[2] = argDistParam2;
returnParams[3] = modeParam3;
returnParams[4] = locationParam4;
returnParams[5] = lowerLimit;
returnParams[6] = upperLimit;
Functions
returnParams[7] = useSeed;
returnParams[8] = seedInit;
returnParams[9] = empiricNumRows;
empTable contains the empirical distribution array, if any.
370 Reference
Database functions
Returns -1 as error.
Functions
ModL Functions 371
Database functions
Functions
ray[], string findValue- string findValueArray[4];
Array[], integer The arrays can be larger than you need as only nonzero
exactMatchArray[]) fieldIndexArray members will be searched. The first zero
fieldIndex will end the fields searched. StartingRecordIndex
can be zero or one to start at the first record. To keep searching
for more matches, increment the returned record index by one
for startingRecordIndex. If exactMatch is FALSE, finds
record containing findValue without having to match the
entire field value.
Returns -1 if record not found or index error.
NOTE: Different find functions return different error codes
because of legacy concerns.
372 Reference
Database functions
DB address functions
These functions stuff the database or global array component indexes into a real number. For
databases, it includes the database index, table index, field index, and record index. The result-
ing real number is very useful as an attribute value that can completely describe a database or
Functions
Depending on the number of records needed, ExtendSim automatically switches to the correct
algorithm. For example, Algorithm #2 is used if more than 1 million records are needed.
ModL Functions 373
Database functions
Functions
addressValue, integer
whichElement, integer
incrementValue)
DBAddressReplaceIn- Replaces part of a DBAddress with newValue. whichElement: R
dex(real addressValue, 1: database, 2: table, 3: field, 4: record
integer whichElement,
integer newValue)
DBDatabaseGetIndex- Returns a dabase index from the DBAddress value. I
FromAddress(real
addressValue)
DBFieldGetIndexFro- Returns a field index from the DBAddress value. I
mAddress(real
addressValue)
374 Reference
Database functions
Viewing a database
These functions register and unregister blocks from databases, independent of dialog items and
their links, so linked blocks can be notified if the data that they are depending on changes in
structure or content. This type of linking is different than user linking of parameters and data
tables to a database because you don’t specify anything to link. If the database changes content
(e.g. the value in a cell that you registered changes) you will get a LINKCONTENT message.
If the database table that you are linked to changes name or number of fields or rows, you will
get a LINKSTRUCTURE message. Please see “Dynamic linking” on page 317, for informa-
tion on finding out what changed when you get the LINKCONTENT, or LINKSTRUCTURE
messages.
☞ All registration set up by DBBlockRegisterContent() or DBBlockRegisterStructure() is good
only for this model session. This disposal of links is done to prevent obsolete links sending
unneeded messages that could slow down a simulation.
ModL Functions 375
Database functions
When the model is closed and reopened, you will have to call these functions again (usually in
the OPENMODEL message handler) for all links that you want.
For an overview, see “Registered blocks” on page 111.
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Dynamic and non-dynamic arrays
The following functions manipulate arrays.
Dynamic arrays are declared as static arrays with their first dimension missing, such as:
real, integer, or string array[], array2Dim[][5];
☞ If you pass a dynamic array as an argument to a user-defined function, you cannot use this local
argument name as the argument to the MakeArray or DisposeArray functions, but must instead
use the original static declared name.
dexByName (long
blockNum, string
arrayName)
FindMinimum(real Accepts two dynamic arrays; one real, one integer. It searches the R
RealArray, integer RealArray for the minimum values and returns the minimum
ResultArray) value. The ResultArray is filled with the position numbers of the
elements that contain the minimum value.
FindMinimum- This function is identical to the FindMinimum function defined in R
WithThreshhold the above, with the addition of the threshhold argument. This
(realArray y, inte- argument specifies a threshhold below which the real values will
gerArray y2, real be ignored. I.e. the minimum value found will always be at the
threshhold) threshhold, or above.
ModL Functions 377
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
arrays passed in to functions as a string name.
SortArray(array, Sorts the array up to numRows. Uses the keyColumn as the sorting V
integer numRows, column. If increase is TRUE, sorts in ascending order (note that,
integer keyColumn, for purposes of sorting, NoValues are considered larger than any
integer increase, number). If this is a string array and
integer sortStrin- sortStringAsNumbers is TRUE, sorts strings as numbers in key-
gAsNumbers) Column. This function works with any kind of array, including
data tables and text tables.
Passing arrays
These functions let you pass dynamic arrays through connectors or global variables. This is
discussed in more detail in “Passing arrays” on page 102. Also see the “Passing Arrays” exam-
ple (Windows: PassArry.mox in the ModLTips folder; Mac OS: Passing Arrays in the ModL
Tips folder).
378 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Pointer functions
Dynamic array pointer functions allow you to copy the contents of dynamic arrays into an
independent data structure that can be created, used by other blocks if desired, and disposed of
by any block. You can create a very large number of independent pointers, if desired. They are
also useful for creating complex structures of pointers.
Using a disposed pointer will cause a crash (uses malloc() and free()).
ray(integer pointer, copies it to a dynamic array, so ModL code can access it. This
dynamicArray) action writes over any old data in that dynamic array. The
dynamic array must be the same type as the array in the
pointer. The pointer must still be disposed of by PointerDis-
pose().
Global arrays
The Global Array functions define and manage global arrays (see “ModL function overview”
on page 226). All of the functions except the ones that start with “GAGet” will return a nega-
tive number if they fail. The following numbers have standard meanings:
ModL Functions 379
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Value Meaning
-1 No arrays defined, or array not found
-2 Array index invalid, or array not defined
-3 Row or column reference out of range
-4 Incorrect array type
-5 Name is blank, or too long (> 15 characters)
-7 Wrong type of array
-8 Array length doesn’t match global array length
Constant Value
GAReal 1
GAInteger 2
GAString 3
GAString15 4
GAString31 5
GAString63 6
GAString127 7
number of GA’s, speed is of the essence, and you are sure that
there will be no duplication of names. If you do create an array
with the same name as an existing array, referencing that array by
name will only access the older array.
GACreateRandom Creates a Global Array with a random name. Useful for quick cre- I
(integer type, inte- ation of global arrays in cases where you need to create many
ger columns) arrays quickly.
GADataTable (inte- Associates a Global Array with a dialog data table in the same I
ger blockNumber, way the DynamicDatatable function associates a dynamic array
string DTname, with one. See the DynamicDatatable() function description for
integer arrayIndex) more information.
ModL Functions 381
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
ByIndex (integer referrenced by arrayIndex.
arrayIndex)
GAGetIn- Returns the Index value of the named array. I
dex(string name)
GAGetInfo(integer This Global Array function returns the value of some of the I
ArrayIndex, inte- Global Array flags for the specified array. Values for Which are:
ger Which) 0:non saving, 1:initializing.
GAGetInit- Gets the initialization value for the global array. This value is set R
Value(integer by GASetInitValue(), and is used during array initialization.
arrayIndex)
382 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
arrayIndex, integer
row, integer col-
umn)
GAGet- Supports the string 63 type, otherwise the same as the GAGet- S
String63(integer String() function.
arrayIndex, integer
row, integer col-
umn)
GAGetType(string Returns the type of the named Array. See table above for type val- I
name) ues.
GAGetTypeByIn- Returns the type of the Global Array referrenced by I
dex (integer array- arrayIndex.
Index)
ModL Functions 383
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
GAPopupMenu This function copies the strings in the specified Global array into I
(integer arrayIndex, the named Popup menu. This is a utility that allows quick con-
string name, integer struction of a popup menu. The flying argument is true if the
rows, integer init, menu is being created “on the fly,” as opposed to adding the array
integer flying) to the existing menu. See the code that controls the Animation tab
of any Item library block as an example.
GAPtr (integer Returns the memory pointer to the data associated with a particu- I
arrayIndex) lar global array. (For passing data to dll's only, and it should be
called only immediately before the DLL call, as memory can
move, making the pointer invalid.)
GAResize(string Changes the number of rows defined for a global array. I
name, integer rows)
384 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
arrayIndex, integer
row, integer col-
umn)
GASetLong(inte- This function is alos known as GASetInteger. See GASetInteger I
ger value, integer for description.
arrayIndex, integer
row, integer col-
umn)
GASetReal(real Sets the real value at the specific row and column of the array I
value, integer with the specified index.
arrayIndex, integer
row, integer col-
umn)
ModL Functions 385
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
dex, integer If the DB table defines multiple fields in different formats, not all
databaseIndex, the data may be copyable.
integer tableIndex)
Linked lists
Linked lists are queue-like, multiple type structures that maintain internal pointers between the
different elements. This speeds the moving around of elements (sorting) within the list. Each
structure element can simultaneously contain any number of integer, real, Str15, Str31, and
Str255 data types, so complex sorted structures can be created. They will be slightly slower to
access than their linear equivalent if used as a simple queue (FIFO, or LIFO) and faster than
their linear equivalent if their internal sorting functionality is taken advantage of, as in a Queue
block (Item library). See that block’s code for a good example of using linked lists to sort.
These functions create and manipulate linked lists which are referred to by an index and are
associated and stored with a block. Because these functions have a global block number as an
386 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
argument, linked lists associated with a specific block can also be accessed globally, from any
other block in the model.
The normal sequence for working with linked lists is:
ListCreate(...); // create the list structures
ListCopyEle- Copies an element from one linked list to another. The first three I
ment(integer parameters specify the element in the first list, the next two spec-
blockN, integer ify the target list, and the last one specifies where in the new list to
listIndex, integer copy the element. As with any linked list function that adds an
fromIndex, integer element, you can specify a -2 to mean that the new element should
targetBlockN, inte- be added in its sorted order.
ger targetListIn-
dex, integer
targetIndex)
ModL Functions 387
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
Max(integer block- value of the specified value. If the Max flag is true, it will return
Number, integer the index of the element that contains the maximum value of that
listIndex, integer entry, otherwise it will return the minimum. (Currently just inte-
compareType, inte- ger and real are implemented. string comparisons are not yet
ger compareIndex, implemented.)
integer max)
388 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
ListGetLong(inte- Returns the integer (integer) value at that element and field index. I
ger blockNumber, If elementIndex is passed in as a value less than zero, it refers to
integer listIndex, the current newly created, but not yet added, item. If elementIn-
integer elementIn- dex is zero or greater it is used as an index value into the specified
dex, integer fieldIn- list.
dex)
ListGetName(inte- Returns the name of the linked list. List names are new in version S
ger blockN, integer 7. Lists do not have a name by default, and will not have a name,
listIndex) until one has been set with the ListSetName function.
ModL Functions 389
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
blockN, integer list.
listIndex, integer
searchType, inte-
ger searchIndex,
integer lVal, real
rVal, string sVal,
integer startIndex)
ListSearchCount- Functions similarly to the ListSearchCount function, except that I
Longs(integer the integer Array Y argument is similar to the ListSearchLongs
blockN, integer function, below. (I.e. this function will count the number of ele-
listIndex, integer ments in the list that contain matches for all the integer elements
Array y, integer in the integer Array.)
startIndex)
390 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Functions
SLFlagReal- Sets one of the twenty real user defined flag values for the speci- I
Set(string slName, fied string lookup. Each string lookup has twenty real flags asso-
integer which, inte- ciated with it. ‘Which’ should take a value from 0 to 19.
ger tableAttribute)
SLFlagSet(string Sets one of the twenty user defined flag values for the specified I
slName, integer string lookup. Each string lookup has twenty flags associated
which, integer with it. ‘Which’ should take a value from 0 to 19. Note that these
tableAttribute) flags are stored internally as a single byte of data, which means
that you can only store values from zero to 127 in the flag. This is
normally intended to store Boolean (True/False) values, but you
can store values up to 127 if you wish. (Negative values will not
be stored.)
SLGetCount() Returns the count of the number of string Lookups defined in a I
model.
392 Reference
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Queues
These functions store queues in a single-dimensional real, dynamic array, that is, an array that
is declared with no dimension, such as real a[] (see the section above on dynamic arrays).
You do not need to use the MakeArray function before calling QueInit. When you have fin-
ished with a queue, you should recover the memory it occupies with the
DisposeArray function; this is often done in the EndSim message handler.
In queues, the first member is numbered “0”, the next member “1”, and so on. This means that
in an array of n members, the last member is numbered “n-1”. n and i are integers, and x is a
real value.
ModL Functions 393
Arrays, pointers, queues, delay, linked list, and string lookup table functions
Queues cannot be directly accessed via the array and an index. You must use the following
functions to access elements within the queue. Also, see “Linked lists” on page 385.
Functions
real x) error message informs you and aborts the operation.
Delay lines
These functions store delay lines in a single-dimensional real, dynamic array, that is, an array
that is declared with no dimension, such as real a[] (see the section above on dynamic
arrays). Delay lines are used in continuous simulations to delay values by a constant amount of
time. They are like a pipe with values flowing in one end and out the other; the delay time is
analogous to the length of the pipe.
Although the delay line functions store delay lines in dynamic arrays, you must not use the
MakeArray function to allocate these arrays. Array allocation is handled automatically by the
delay line functions. When you have finished with a delay line, you should recover the mem-
ory it occupies with the DisposeArray function.
394 Reference
Miscellaneous functions
Miscellaneous functions
Strings
These functions allow you to change and parse a string into whatever component parts you
want. Note that, in ModL, the “+” operator acts as a string concatenation operator. The func-
tions that require a character position indicate the first character in a string as position 0. In
these functions, the arguments s, findString, and replaceString are strings.
Please see “String lookup table functions” on page 391
Functions
StringCompare Returns -1 if s1 < s2, 0 if s1 == s2, 1 if s1 > s2. If caseSens is I
(string s1, string s2, TRUE, uses case. If diacritical is TRUE, uses diacritical marks (ä,
integer caseSens, é, ö, etc.).
integer diacritical)
StringTrim (string This function is used to trim blank spaces (including CR, LF, and S
input, integer TAB characters) off the input string. The resulting string is
which) returned.
The argument “which,” takes the following values:
0-both leading and trailing blanks are trimmed.
1-leading blanks trimmed.
2-trailing blanks trimmed.
3-both leading and trailing blanks are trimmed plus blanks any-
where else in the string
396 Reference
Miscellaneous functions
Attributes
Use these functions in discrete event blocks to work with attribute strings. Attribute strings are
formatted as: AttrName1=val1;AttrName2=val2;...
Obsolete. These function are provided for backwards compatibility with version 3.x. New
blocks built in version 4.0+ should not use these functions.
Time units
These functions convert local time units defined within blocks to the global time unit defined
in the Simulation Setup (see “Units of time” in the main ExtendSim User Reference). Get-
TimeUnits and ConvertTimeUnits use the following values for Time Units.
Functions
dInAMonth, real
dInAYear)
SetTimeUnits(inte- Sets the Time Unit parameter in the Simulation Setup dialog. I
ger value)
communicating with an outside application, you have selected the same version of these date
choices in both applications.
If you have a model saved in ExtendSim, and it has saved date values in one of these formats,
running it in the other date setting will give unexpected results. This legacy Macintosh date
setting is selectable in the Simulation Setup Dialog. Calendar Dates can only be selected in the
simulation setup dialog if the time units for the model are set to seconds or longer, and not to
generic time units, or milliseconds.
☞ Prior to ExtendSim 7, a different time and date format was used, as discussed on page 399.
Date and time Description Return
EDCalcDate(inte- Construct a date value from its individual components. R
ger year, integer
month, integer day,
integer hour, inte-
ger minute, integer
second)
EDCalendarDate- Opens the calendar input dialog for the user to input a date value R
Get(real startDate) and returns that date value. The input dialog will show the value
of the parameter startDate as a starting point.
EDCalendarDates() Returns the value of the CalendarDates checkbox in the simula- I
tion setup dialog box: FALSE is unchecked, TRUE is checked.
EDCalendar- This function opens or closes the calendar window. I
Show(true/false)
EDConvert- Modifies a date value by adding additional time. The additional R
Date(real value, time added to the date value will be in the value parameter, and
integer fromType, what time units it is in will be in the fromType parameter. Note
real startDate) that this function returns a date value, not a number of time units.
EDDateToSim- Converts from a date value to a simulation time value (e.g. a pos- R
Time(real current- sible value of currentTime). Putting in a zero for the timeUnits
Date, integer argument will make the function use the currently specified model
timeUnits) time units. (see Time Units)
Functions
Functions
DiffDate(integer Returns the difference between two date values as a real number R
firstDate, integer which represents the number of days between the two dates.
secondDate)
GetBlock- Returns the modified and created dates of the block. The where- I
Dates(integer From argument takes a zero for the block or a one for the library.
blockNumber, inte- The whichDate argument takes a zero for created or a one for
ger whereFrom, modified. Use the EDdateToString function to get the string val-
integer whichDate) ues of the date & time.
ModifyDate(inte- Returns the old date value plus the date modifier value. The old- I
ger oldDate, real Date value is an ExtendSim integer date value, similar to that
dateModifier) returned from the GetBlockDates function, and the dateModifier
value is a real number representing a number of days.
Now() Number of the current date and time. I
400 Reference
Miscellaneous functions
Timer functions
These allow real time measurements to be set up. The TimerID functions are an extension of
the timer functions that allow multiple (Up to 200) timers to run simultaneously. Each timer is
referenced by an ID number from 0 to 199. The StartTimer() and StopTimer() functions (with-
out a timerID argument) always refer to timer zero.
Stoptimer() This procedure stops the idle timer chore started by startTimer V
above.
StopTimerID (inte- Stops a timer with an ID tag, which can range from 0 to 199. V
ger index)
TickCount() Clock count (in 60ths of a second) since the computer was pow- I
ered up. This is useful for timing operations.
TimerID() This function is to be used in the TimerTick message handler to I
find which timer is responsible for triggering the message.
Returns the ID number of the timer that is currently activating the
message.
ModL Functions 401
Miscellaneous functions
EColors
The following color functions are new in ExtendSim 10. They support a new color information
variable type called an EColor, which is stored in long (integer) variables. EColors contain the
previously supported RGB/HSV color information as well the alpha channel information that
allows color transparency and is new in ExtendSim 10.
Select Color window
You can see any color’s RGB (red, green, blue), HSV (hue, saturation, and value or bright-
ness), and HTML values as well as other settings by selecting the Fill Color tool in the Shapes
toolbar:
Color selector
Pick a basic color from the matrix of colors. Or use your cursor and the button labeled Pick
Screen Color to choose a color from the color swatch at the right. Adding any selected color to
the custom colors section saves the color for other models. Use the slider at the far right to
increase or decrease the value (brightness) of a selected color.
The alpha channel is for the level of transparency; the lower the number, the more transparent
Functions
the color is.
Some functions in ExtendSim releases prior to 10 had the option of selecting a pattern in addi-
tion to a color. Patterns remain as arguments for those functions but are no longer supported.
Debugging
Also see the Abort statement in “Control statements and loops” on page 70 and UserError in
“Alerts and prompts” on page 268.
Note: To stop a simulation such that it neither puts up an error message nor opens windows to
indicate in which process the simulation was stopped, put the following code in the SIMU-
LATE message handler of an equation-based or custom block:
• currentStep = numSteps;
• currentSim = numSims;
• //don’t use the Abort statement or call any abort functions
AbortAllSims() Aborts the simulation and all multiple simulations. Note that the V
Abort statement only aborts the current simulation.
AbortAllSimsSi- Aborts a multiSim run without an error message. I
lent()
AbortSilent() Aborts the simulation run without giving any error messages. V
DebuggerBreak- If called with a true value will act as if a source debugger break- V
point(integer true- point has been set at the line of code where the function is called.
False) This function is useful in debugging the CreatBlock message and
in putting a global breakpoint for all blocks of a type.
ModL Functions 403
Miscellaneous functions
Functions
SelectBlock2(inte- This is same as SelectBlock(), except it refers to a global block V
ger block, integer number.
trueFalse)
TraceModeEnable- Call to enable or disable the current trace when desired. Trace V
Disable(integer mode must be on for this function to work. It returns zero if no
enableIfTRUE) error and -1 if trace mode is not on.
Platforms and
Description Return
versions
GetCurrentPlat- Determines the operating system under which ExtendSim is cur- I
form() rently running. This function returns 0 for 68K Mac OS, 1 for
Power Mac OS or Mac OSX, 2 for Windows 3.1/Win32s, 3 for
Windows NT or XP, and 4 for Windows 95, 98, and ME.
ModL Functions 405
User-defined functions for ADO
Platforms and
versions Description Return
GetExtendVer- Returns a real number in the format 701.1 where 7 is the major R
sion(integer which) version, 1 is the minor version, and 0 is the middle. The value
after the point is 1 for an a, 2 for a b, and so on. This final value
is always zero for a file read version.
Which:
0 : application version
1 : file version
GetExtendVersion- Returns the version number of ExtendSim as a string. S
String()
GetExtendType() Returns the type of the ExtendSim application. I
Normal: 0
LT/RunTime: 2
Demo/Player: 4
GetFileReadVer- Returns the version of the file being read, or previously read. It R
sion() can be used in the On BlockRead message handler to determine
the version of the file that is currently in the process of being read.
In conjunction with the ResizeDTDuringRead function, it will
allow you to inform ExtendSim that a data table has changed size
from the size it was in an older version. (This is useful for using
the Dynamic data table function without breaking existing mod-
els.)
GetFileReadVer- Returns the version of the file being read, or previously read, as a
sionString() string. This is similar to the GetFileReadVersion function, with
the difference that the result is a version string, not a real number.
NOTE: This function returns the complete version string, in the
form ‘major version. minor version.bug fix version', unlike the
GetFileReadVersion function which just returns the major ver-
sion. This function will return an empty string for files earlier than
version 4.0.
Functions
User-defined functions are custom functions, coded in ModL, that can be declared in a block
for local use or declared in an include file for use by multiple blocks. For how to create, use,
and override them, see “User-defined functions” on page 72 and “Include files” on page 81.
The following ActiveX Data Object (ADO) functions are used to implement ADO features in
the Data Import Export block (Value library). These ModL-coded functions are stored in an
include file named ADO_DBFunctions.h. To reference that include file in your block’s code,
use a format discussed on page 81, such as #include “ADO_DBFunctions.h”.
406 Reference
User-defined functions for ADO
ADO_CheckCom- Returns True (1) if the ADO field type is compatible with the I
patibleField- ExtendSim field type.
Type(string
ADODataType,
integer ExtendSim-
Type)
ADO_Close(inte- Closes the connection to the ADO DLL. Call when done access- I
ger ADOAppHan- ing the DLL.
dle, integer Force)
ADO_Cre- Creates a table in an ADO database. V
ateTable(integer ADO_TableName - name of the table
ADOApp, string ADO_FieldArray contains the table names, their type, “Is nul-
ADO_TableName, lable”, and the number of characters
string63 ADO_-
FieldArray[][4])
ADO_DeleteRe- Deletes records from an ADO database table. V
cords(integer ADO_TableName - name of the table in the ADO database.
ADOApp, string Criteria - SQL statement indicating which rows to delete. To
ADO_TableName, delete all rows, leave blank.
string Criteria)
ADO_Execu- Executes a Non-query SQL statement. V
teNonQuery(inte- SQLStr - SQL statement
ger ADOApp,
string SQLStr)
Functions
ADO_Setup() Sets up the connection to the ADO DLL. Call before accessing I
the DLL Returns the ADO Application Handle - referred to in
other functions as ADOApp.
ADO_SQLServer- Returns a list of SQL Server Servers. V
GetServ- ServerInfo - array containing the list of the servers. Allocate this
ers(string63 array before calling the function.
ServerInfo[][4])
408 Reference
User-defined functions for ADO
ConvertExtend- Converts an ExtendSim constant for data type to SQL string for S
SimDataType(inte- data type.
ger
ExtendSimType)
DB_FieldGetTyp- Returns the string description given an ExtendSim field type. S
eString(integer
ExtendSimType)
Functions
Appendix
Command
File Menu
Number
New Model 2
New Text File 1601
Open 3
Recent Files (1-5) 1555-1559
Close 4
Save Model 5
Save Model As 6
Print 9
Update Launch Control 1410
Properties 2001
Exit or Quit 1
Command
Model > Connection Line Style Sub menu
Number
Appendices
Smart 5004
Right-Angle 5001
Straight 5002
Free Form 5003
Menu Command Numbers 411
Command
Database Menu
Number
Read/Write Index Checking 1931
Command
Run Menu
Number
Run Simulation 6000
Show 2D Animation 2020
Stop 30000
Pause 30001
Command
Run > Model Debugging Menu Number
Generate Trace 2040
Add Selected Blocks To Trace 2041
Add All Blocks To Trace 2045
Remove Selected Blocks From Trace 2042
Remove All Blocks From Trace 2043
Show Tracing Blocks 2044
Command
Simulation Status Bar
Number
Slower Animation 30004
Faster Animation 30005
Command
Text Fonts (sets the default font)
Number
Appendices
Courier 6100
Helvetica 6101
Times 6102
Arial 6103
412 Appendix
Appendices
Appendix
Upper Limits
A list of the maximum numbers of things
that you can do at one time
Appendices
416 Appendix
Appendices
Appendix
ASCII Table
To help you determine the values of
the ASCII characters
This table shows the ASCII values from 00 to 127, which are the same for Windows and Mac
OS. Values above 127 are not part of the standard ASCII set and vary depending on the font.
00 NUL 32 space 64 @ 96 `
01 SOH 33 ! 65 A 97 a
02 STX 34 " 66 B 98 b
03 ETX 35 # 67 C 99 c
04 EOT 36 $ 68 D 100 d
05 ENQ 37 % 69 E 101 e
06 ACK 38 & 70 F 102 f
07 BEL 39 ' 71 G 103 g
08 BS 40 ( 72 H 104 h
09 HT 41 ) 73 I 105 i
10 LF 42 * 74 J 106 j
11 VT 43 + 75 K 107 k
12 FF 44 , 76 L 108 l
13 CR 45 - 77 M 109 m
14 SO 46 . 78 N 110 n
15 SI 47 / 79 O 111 o
16 DLE 48 0 80 P 112 p
17 DC1 49 1 81 Q 113 q
18 DC2 50 2 82 R 114 r
19 DC3 51 3 83 S 115 s
20 DC4 52 4 84 T 116 t
21 NAK 53 5 85 U 117 u
22 SYN 54 6 86 V 118 v
23 ETB 55 7 87 W 119 w
24 CAN 56 8 88 X 120 x
25 EM 57 9 89 Y 121 y
26 SUB 58 : 90 Z 122 z
Appendices
27 ESC 59 ; 91 [ 123 {
28 FS 60 < 92 \ 124 |
29 GS 61 = 93 ] 125 }
30 RS 62 > 94 ^ 126 ~
31 US 63 ? 95 _ 127 DEL
Appendix
Cross-Platform Considerations
File conversion, file name comparisons, and keyboard shortcuts
for the Windows and Macintosh operating systems
Libraries
In most cases, libraries should be placed in the ExtendSim\Libraries folder; they can be placed
in subfolders within that folder. Optionally, libraries needed by a model can also be at the
model file location.
Libraries should never be placed anywhere outside of either the Libraries folder or the folder
that contains the model file that uses the library.
ExtendSim supports library file names up to 256 characters. Library names must end in the
“.LBR” extension. (Libraries developed in ExtendSim releases earlier than 10 used the LIX
extension; they are automatically converted to LBR when opened in newer releases.)
Models
Model file names can be any length. All models must end in the “.MOX” extension.
Menu and keyboard equivalents
The following table lists some common actions and keyboard shortcuts under the Windows
and Mac OS systems. Appendix A of the User Reference contains pictures of the ExtendSim
menus, including keyboard equivalents for the menu commands.
Run menu
• Windows to Mac OS: When you transfer files from a Windows computer to a computer run-
ning Mac OS, it is important that you do not delete the MOX extension. The MOX extension
is required so ExtendSim can identify the file as a Windows model. After ExtendSim has
converted the Windows model to Mac OS format, save the model under the same name or a
new name.
• Mac OS to Windows: If you transfer files from a Mac OS to a Windows computer, you may
need to change the name of your file before you transfer it. File names must end in a three-
422 Appendix
Transferring files between operating systems
character extension (the extensions are “.MOX” for ExtendSim model names, “.LBR” for
library names, and “.TXT” for text file names). To change your Mac file names to Windows
format, change the name of the file on the Mac OS computer using the Save As command (if
the file is open) or using the Finder (if the file is not open).
the blocks inside the hierarchical block (for example, to comply with Windows format), you
need to update the hierarchical block’s information so that it can locate the renamed libraries.
The easiest way to do this is to drag hierarchical blocks from their libraries, place them on a
worksheet, and update their structure, as discussed below.
☞ This is only required for hierarchical blocks saved in libraries; hierarchical blocks saved only
in a model get updated with the model.
Cross-Platform Considerations 423
IPC or multi-server considerations
When you add a hierarchical block from a library to a model worksheet, the hierarchical block
causes ExtendSim to open the libraries of the blocks inside it. Since you have renamed those
libraries, ExtendSim will not be able to locate them. In this case, ExtendSim will ask you to
find and open the correct libraries. Note: keeping all your libraries in the Libraries folder will
make this search process easier.
If you save the model worksheet that contains the hierarchical block, the location of the
renamed libraries is saved for the model only. Before you close the model worksheet, you also
need to update the hierarchical block’s library information. To do this, open the hierarchical
block’s structure window and then close it, causing the hierarchical block’s Save dialog to
appear. In the dialog, choose Also save to library. This process is described in the User Refer-
ence.
☞ It is strongly recommended that you keep library names the same on either operating system.
Libraries
Physically transfer libraries to the target computer. Then recompile the libraries under the tar-
get computer’s operating system using the Library > Library Tools > Compile Libraries com-
mand.
Blocks that use the equation functions
If you build blocks that use the equation functions, your code needs to detect if the model is
being opened on a different platform. See the “Equations” on page 238 for more information.
Extensions
Extensions are files (such as pictures and DLLs) that can be accessed by ExtendSim to fulfill
specialized tasks. Like libraries, the extensions that come with your ExtendSim package are
formatted correctly for your operating system. However, if you build your own extensions, and
you want to transfer your extensions (or blocks that use them) to a computer running a differ-
ent operating system, you will need to do some conversion:
• Pictures: As discussed“Picture and movie files” on page 89, ExtendSim accepts most types
of picture files.
• Sounds: WAV files are supported on both platforms and shareware utilities are available to
convert Mac OS sound resources (SNDs) to Windows sound files (.WAV) and vice versa.
• DLLs and Shared Libraries: On Windows the DLL functions will search the ExtendSim
Extensions folder for a DLL file. For the Mac OS those same calls will search for a Shared
Library file.
in the same way regardless of the platform (Windows or Macintosh) on which it runs.
However, ExtendSim is capable of communicating with other applications through ModL
code, and some of these applications may not have a consistent interface across platforms. The
following is a discussion of some of the things to consider when writing ModL code that is
intended to be cross-platform compatible.
The interprocess communication (IPC) functions allow ExtendSim to act as a client application
and request data and services from server applications. When using the IPC functions, it is
important to remember that the syntax of some of the function arguments are dependent both
424 Appendix
Cross-platform code
on the server application that ExtendSim is communicating with and the platform that Extend-
Sim is running on. For example, the serverName argument of the IPCConnect function (which
defines the application you want to connect ExtendSim to) must be in the format appropriate
for that application and platform. The serverName for Microsoft Excel on the Windows operat-
ing system would be “Excel,” while on the Mac OS operating system it would be
“XCEL.”.This type of information can be found in the documentation of the server application.
When writing ModL code that utilizes IPC functions and is meant to be cross-platform com-
patible or capable of operating with multiple server applications, it is necessary to define the
function arguments according to the platform application prior to calling the function. This can
be accomplished by using the platform variables PLATFORMMACINTOSH, and PLAT-
FORMWINDOWS) and using dialog items to define the server application (see blocks in the
IPC library for examples).
For instance, the following code establishes a conversation between ExtendSim (the client)
and Excel (the server) on either the Windows or Mac OS operating system:
if (PlatformMacintosh)
serverName = “XCEL”;
if (PlatformWindows)
serverName = “Excel”;
IPCConnect (serverName, theSpreadsheet);
The following is a list of functions that contain arguments where the syntax of the argument
depends on the server application (the dependent argument is shown in italics):
• IPCConnect(serverName, topic)
• IPCExecute(conversation, executeData, item)
• IPCPoke(conversation, pokeData, item)
• IPCRequest(conversation, item)
Cross-platform code
The following ModL constants return TRUE or FALSE depending on the platform: PLAT-
FORMMACINTOSH; PLATFORMWINDOWS; PLATFORMPOWERPC. You can use these
constants in an If statement to make code be cross-platform capable. For example:
if (PLATFORMWINDOWS)
Windows specific code
else if (PLATFORMMACINTOSH)