Working with Models, Modules, and Files in ADE

This page contains changes which are not marked for translation.

Other languages:
English • ‎中文

ADE User Guide >

This section contains examples of common operations and manipulations you might perform on objects in your Analytica model.

Contents

Models and Modules

Note: In VBScript, VBA, and pre-dot-NET versions of Visual Basic, the Set keyword was necessary when assigning an object to a variable. In VB.NET, the Set keyword is no longer necessary. The Set keyword is not used in the examples below.

To create a new model:

If ADE.CreateModel("NewModelName") Then
’Model successfully created
End If

The CreateModel method only requires one parameter, a string containing a model name.

To open an existing Analytica model:

Dim ModName as String
ModName = ADE.OpenModel("C:\ ... \Anamodel.ana")
If ModName="" then
’ Handle Error condition here
End if

If a model has already been opened, that model is closed automatically before the new model is created. If the specified filename is not legal, OpenModel returns an empty string. In that case, use the ErrorCode property of CAEngine to determine the cause of the error. Be aware that an ErrorCode=2 warning is often returned even though the load is successful. For full details as to what has caused an error or warning, use the OutputBuffer property of the CAEngine. You must use the backward slash (\) for the path delimiter when using ADE. It does not support the forward slash (/).

To add a module from a file to the currently open model:

Dim Merge as Boolean = True
Dim ModName as String
ModName = ADE.AddModule ("C:\...\MyLibrary.ana", Merge)
if ModName="" Then
’ Handle error conditions here
End if

The FileSpec parameter should contain the path and filename of the module to be included. The Merge parameter is a Boolean variable that determines whether preexisting objects with identical names are overwritten. If Merge=True, then conflicting variables are overwritten. If Merge=False and there are conflicting variables, then the call to AddModule fails.

To read a script file:

If ADE.ReadScript("C:\..\MyScript.ana") Then
’ Script successfully read
End

If A script file can contain a list of typescript commands. Upon loading the file, the engine executes the commands contained in the file. Errors encountered while running the script file are described in the ErrorText property.

To save a module (i.e., a subset of the current model) in a separate file:

If ADE.SaveModuleFile ("MyLibrary", "C:\...\MyLibrary.ana") Then
’ Save succeeded
End

If The first parameter is the module identifier, the second is the file name.

To save the current model in a file:

If ADE.SaveModel("C:\...\MyNewModel.ana") Then
’ Save succeeded
End If

To close the current model without saving:

If ADE.CloseModel() Then … ’ Close succeeded

The CloseModel method takes no parameters.

ADE Objects

To create a new CAObject object:

Dim ObjName As String = "NewVariable"
Dim ObjClass As String = "Variable"
Dim var As CAObject = ADE.CreateObject(ObjName, ObjClass)

The object name and the class of the object to be created are passed into the CreateObject method. Note that an identifier and not the title of the object should be used when giving the object a name. Most object-related methods use their Identifier attribute, not their Title attribute. ADE can create the following types of objects: variable, module, chance, constant, decision, index, and objective. Refer to the Analytica User Guide for more information on these object types.

To delete an Analytica object from a model:

Dim obj as CAObject
If ADE.DeleteObject(obj) Then … ’ Successful

To set the active module

ObjName = "ModuleToMakeActive"
ObjClass = "Module"
Var = ADE.CreateObject (ObjName, ObjClass)
ADE.CurrentModule = Var

ADE uses a hierarchy to order objects. When an object is created, it is created inside the current module. By default, all objects are placed within the top-level module unless you set the CurrentModule property.

To identify the current module:

Dim module As CAObject = ADE.CurrentModule

To obtain a CAObject object when you know the name of an Analytica variable

This is probably the most commonly used method in ADE.

Dim Var As CAObject = ADE.GetObjectByName ("IdentifierInModel")
If Var Is Nothing Then
’Analytica model associated with Ana
’does not contain variable with
’identifier "IdentifierInModel"
End If

The method CAEngine::Get is synonymous with CAEngine::GetObjectByName.

Get all Analytica attributes using the GetAttribute method

UnitsOfVar = Var.GetAttribute ("Units")

Use the SetAttribute method to change an attribute of an Analytica object:

If Var.SetAttribute ("definition","A/B") Then
’Attribute Set Correctly
Else
’Attribute Not Set
End If

To access or rename the identifier of an object using the Name property

Dim oldName As String = Var.Name
Var.Name = "NewIdentifer"


For the full lists of object attributes, see the Analytica Scripting Guide.

Retrieving Computed Results

The CAObject class contains three methods that cause results to be computed and returned. The Result method evaluates an object in your model and returns the result as a single value. This is most useful if you know that the result is a single number or single text string. The ResultTable method evaluates an object in your model and returns the result as a CATable object. Methods and properties of the CATable object allow you to understand what dimensions are present and to access individual elements (cells). The Evaluate method processes an arbitrary expression and returns the result of parsing and evaluating that expression as a multi-dimensional CATable.

When retrieving results, you have control over which computation mode is used to compute the result. You can compute the deterministic mid point value, or the various probabilistic views: Mean, Sample, PDF, CDF, Statistics, or Bands. Set the ResultType to indicate which result type you desire (default is Mid).

Whether you are computing a scalar or a table, your program eventually accesses individual atomic values such as numbers or text strings. You can use various RenderingStyle settings to control the form in which these values are returned. For example, numeric values can be returned as floating point numbers, formatted strings, or full-precision string depictions. Textual strings can be returned with or without surrounding quotes.

To evaluate and obtain a simple result (e.g., a scalar) of an object

Use the Result method of CAObject:

Dim Obj As CAObject
Dim Result
Obj = ADE.GetObjectByName ("ObjectToEvaluate")
Result = Obj.CAObject::Result
If ADE.ErrorCode = 0 Then
’Result was successfully retrieved
Else
’An error occurred
End If

By default, the Result property of CAObject retrieves the midpoint result of the object. It returns the result as a variant (or in .NET, as a System.Object). This method is convenient for retrieving the results of objects that evaluate to a scalar.

To evaluate and obtain the result of an object as something other than the midpoint

Use the ResultType property of CATable or CAObject:

Dim Obj As CAObject = ADE.GetObjectByName("ObjectToEvaluate")
Dim Result
Obj.ResultType = 1 ' get result as mean
Result = Obj.Result
If ADE.ErrorCode = 0 Then
’Result was successfully retrieved as a mean
Else
’An error occurred
End If

The ResultType property is used to indicate the type of result that Result should return. Possible values are 0=Mid point, 1=Mean, 2=Probabilistic Sample, 3=PDF, 4=CDF, 5=Statistics, and 6=Probability Bands. When ResultType>=2, the result is always a table, even if the mid and mean are scalars. See the next section for a discussion on retrieving table results.

To retrieve a formatted result, set properties of the object’s RenderingStyle

Dim Obj As CAObject = ADE.GetObjectByName("ObjectToEvaluate")
Dim Result
Obj.RenderingStyle.NumberAsText = true
Obj.RenderingStyle.StringQuotes = 2 ’ double quotes.
Result = Obj.Result
If ADE.ErrorCode = 0 then
’ Result was successfully returned.
End If

In this example, numbers are returned as formatted text using the object’s number format property. Strings are returned surrounded by double quotes. So, for example, the numeric value 1.2K might be returned as the string "$1,200.00" if the number format happens to be fixed point, two digits, with trailing zeros, thousand separators, and currency. This numeric value is returned as a text string because the NumberAsText property is True. The string would be returned as ""$1,200.00"" with two extra double quote characters in the result string. This is controlled by the StringQuotes property (0 = no quotes, 1 = 'single quotes', 2 = "double quotes").

Retrieving Multi-Dimensional Results

Before describing how to obtain results from table objects (arrays with one or more dimensions), let us briefly discuss the conceptual model of a table in Analytica.

An Analytica table has the following components:

  • Indexes, each of which identifies a dimension of the table
  • Values in the cells of the table
  • Index labels, which identify the coordinates of each cell

The number of indexes determines the dimensionality of the table. So, for example, if a table contains two indexes, then the table is two-dimensional.

The number of elements in the index determines the actual number of cells in the table. Suppose table T is composed of two indexes, I and J. If I has five elements (AA, BB, CC, DD, and EE) and J has three elements (A, B, and C), then T is either a 5x3 table, or a 3x5 table, depending on your perspective.

Determining your perspective of a table is very important when working with ADE. It is up to you to tell ADE how you wish to view the table. So, for example, in the paragraph above, if you tell ADE to use index I first, followed by index J, then element 2,3 would be the element described by position I=B, J=CC. If, however, you tell ADE to use index J first, followed by index I, then element 2,3 would be described by position I=C, J=BB (note that tables in ADE are 1-based; that is, each dimension goes from 1 to N where N is the size of the index). The method called SetIndexOrder, described below, allows you to set the order of the indexes for your table so that you can look at the table in any way you desire.

The ADE methods are very flexible in terms of how you refer to individual elements in the table. You can either refer to the individual elements by their position number or by their label names. So, for example, you can tell ADE to give you the element at position 2,1 (2 along the first index, and 1 along the second index), or you can tell ADE to give you the element described by ‘BB’,’A’ where ‘BB’ and ‘A’ are label names in their respective indexes. The methods most commonly used for these types of transactions (GetDataByElements and GetDataByLabels) are described below.

As discussed in the previous section, the Result and ResultType methods are used to evaluate and obtain the result of an object. For objects that evaluate to multi-dimensional results, however, it is often inconvenient to use the Result method because the output would be a long commadelimited string in the following form:

Table Index1...IndexN [Value1, Value2...]

Here, Index1 to IndexN are the indexes of the table, and Value1 to ValueN are the values in the table (which are filled in row by row). So, if we wanted to get at a particular element in the table after using the Result method, we would have to parse through the comma-delimited string returned from Result to get at the element of interest. Fortunately, ADE provides an ADE object of type CATable that provides methods to simplify the manipulation of tables.

To evaluate and obtain the result of an object as a table

Use the ResultType method of CAObject:

Dim Obj As CAObject = ADE.GetObjectByName("MultiDimObject")
Dim TableResult As CATable = Obj.ResultTable
If Not (TableResult Is Nothing) Then
’Result table was successfully retrieved
Else
’An error occurred
End If

The ResultTable method of CAObject returns an automation object of type CATable. CATable contains various methods that allow you to set, retrieve, and manipulate individual elements in the table. More than likely, the first thing that you want to do after retrieving the CATable object is to set the index order of the result table.

To parse and evaluate an arbitrary expression

Use the Evaluate method of CAObject.

Dim Obj As CAObject = ADE.GetObjectByName("ContextObject")
Obj.ResultType = 2 ’ Sample
Dim TableResult As CATable = Obj.Evaluate("Normal(X,Y^2) / Z")
If ADE.ErrorCode <> 0 Then
’An error occurred
Else
’Evaluation successful
End If

To use Evaluate, you must first obtain a CAObject instance. Although the expression you are evaluating might have nothing to with any specific object, the CAObject serves a couple of purposes. First, the ResultType property of the object provides a place to specify the result type that you want computed. Second, if you make use of the NumberAsText rendering style, the number format stored with the indicated object determines how the numbers are formatted. Often, however, the object you use is of no consequence; you can even use the top-level model object as your context object.

Comparing the previous two examples demonstrates also that there are often two ways to detect failure. The ErrorCode property is non-zero if an error occurred during the evaluation of a method. And for many methods, the return value is Nothing or False if it fails.

To set the index order of a CATable object

Use the SetIndexOrder method:

Dim Obj As CAObject
Dim TableResult As CATable
Dim IndexOrder (2) as String
Set Obj = ADE.GetObjectByName ("MultiDimObject")
Set TableResult = Obj.ResultTable
If Not (TableResult Is Nothing) Then
’Result table was successfully retrieved
IndexOrder (1) = "Index2"
IndexOrder (2) = "Index1"
If TableResult.SetIndexOrder(IndexOrder)Then
’Index Order set successfully
Else
’An error occurred in setting index order
End If
Else
’An error occurred
End If

The code above assumes that we are manipulating a two-dimensional table. We set the index order of this table so that Index2 is the first index, and Index1 is the second index.

In some computer languages, the first element of an array is considered position 0 (zerobased), and in other languages it is position 1 (one-based). Analytica’s Slice function, and the ADE methods are one-based. Older versions of Visual Basic are one-based, while current versions of Visual Basic and most other modern programming languages are zerobased. In the example above, the Visual Basic array was declared and used as follows:

Dim IndexOrder(2) As String
IndexOrder (1) = "Index2"
IndexOrder (2) = "Index1"

In modern Visual Basic, this declares an array that ranges from position 0 to position 2 — an array having three elements. Because the first element was not set, it contains the special value Empty. ADE can recognize whether zero-based or one-based arrays are being passed to it. So, depending on your preference, it would work equally well to use a zero-based version, for example:

Dim IndexOrder(1) As String
IndexOrder (0) = "Index2"
IndexOrder (1) = "Index1"
ResultTable.SetIndexOrder(IndexOrder)

To retrieve an element in a table by index order

Use the GetDataByElements method:

Dim Obj As CAObject
Dim TableResult As CATable
Dim IndexOrder (2) As String
Dim Pos (2) As Integer
Dim Element
Obj = ADE.GetObjectByName("MultiDimObject")
TableResult = Obj.ResultTable
If Not (TableResult Is Nothing) Then
’Result table was successfully retrieved
IndexOrder (1) = "Index2"
IndexOrder (2) = "Index1"
RetValue = TableResult.SetIndexOrder (IndexOrder)
If RetValue = True Then
’Index Order set successfully
Pos (1) = 2
Pos (2) = 1
Element = TableResult.GetDataByElements (Pos)
If ADE.ErrorCode = 0 Then
’element retrieved successfully
Else
’an error occurred
End If
Else
’An error occurred in setting index order
End If
Else
’An error occurred
End If

This code uses GetDataByElements to retrieve the element at position Index2=2, Index1=1 and stores the result to Element.

To retrieve an element in a table by index labels

Use the GetDataByLabels method:

Dim Obj As CAObject
Dim TableResult As CATable
Dim IndexOrder (2) As String
Dim Pos (2) As String
Dim Element
Obj = ADE.GetObjectByName (“MultiDimObject”)
TableResult = Obj.ResultTable
If Not TableResult Is Nothing Then
’Result table was successfully retrieved
IndexOrder (1) = "Index2"
IndexOrder (2) = "Index1"
If TableResult.SetIndexOrder(IndexOrder) Then
’Index Order set successfully
Pos (1) = "SomeLabelInIndex2"
Pos (2) = "SomeLabelInIndex1"
Element = TableResult.GetDataByLabels (Pos)
If ADE.ErrorCode = 0 Then
’element retrieved successfully
Else
’an error occurred
End If
Else
’An error occurred in setting index order
End If
Else
’An error occurred
End If

The code above uses GetDataByLabels to retrieve the element at position Index2="SomeLabelInIndex2", Index1="SomeLabelInIndex1" and stores the result to Element.

To control the format of elements obtained by GetDataByLabels, GetDataByElements, AtomicValue, or GetSafeArray methods

Set CATable’s RenderingStyle properties:

Dim TableResult as CATable = Obj.ResultTable
Dim rs As CARenderingStyle = TableResult.RenderingStyle
rs.NumberAsText = True
rs.FullPrecision = True
rs.UndefValue = ""
rs.StringQuotes = 1 Dim Element
If TableResult.SetIndexOrder(Split("Index2;Index1",";")) Then
Element = TableResult.GetDataByLabels( _
Split("SomeLabel1,SomeLabel2”,”,”))
If ADE.ErrorCode=0 Then
’ Element retrieved successfully
End If
End If

/tt>

To retrieve the whole table into a Visual Basic or .NET array in one call

Use the GetSafeArray method: <tt>

Dim Obj As CAObject
Dim TableResult As CATable
Dim IndexOrder (2) as String
Dim Pos (2) As Integer
Dim TheWholeTable
Obj = ADE.GetObjectByName ("MultiDimObject")
TableResult = Obj.ResultTable
If Not (TableResult Is Nothing) Then
’Result table was successfully retrieved
IndexOrder (1) = "Index2"
IndexOrder (2) = "Index1"
If TableResult.SetIndexOrder(IndexOrder) Then
’Index Order set successfully
TheWholeTable = TableResult.GetSafeArray
If ADE.ErrorCode = 0 Then
’table retrieved successfully
Else
’an error occurred
End If
Else
’An error occurred in setting index order
End If
Else
’An error occurred
End If

The code above uses GetSafeArray to store the entire table in TheWholeTable. The elements of each dimension associated with the table returned from GetSafeArray are indexed 1 to N, where N is the length of the dimension. The lower bound of the safe array can be changed to zero using this code prior to calling GetSafeArray:

TableResult.RenderingStyle.SafeArrayLowerBound = 0

The syntax for reading a multi-dimensional result in a .NET array in C# is worth mentioning:

Array theWholeTable = (Array) tableResult.GetSafeArray( );

To determine the number of dimensions of the table

Use the NumDims property:

NumDimensions = ADE.Get("MultiDimObject").ResultTable.NumDims

To get the index names associated with the table

Use the IndexNames method:

Dim CurIndexName As String
Dim Obj As CAObject = ADE.GetObjectByName ("MultiDimObject")
Dim TableResult As CATable = Obj.ResultTable
Dim NumDimensions As integer = TableResult.NumDims
Dim I as Integer
For I = 1 To NumDimensions
CurIndexName = TableResult.IndexNames(I)
MsgBox “Current index is “ & CurIndexName
Next I

The IndexNames method returns the index names of the table in the order specified to SetIndexOrder. If SetIndexOrder has not been set for the CATable, then the default order of the indexes is returned.

To associate CAIndex objects with your table

Use the GetIndexObject method of CATable:

Dim Obj As CAObject = ADE.GetObjectByName ("MultiDimObject")
Dim Res As CATable = Obj.ResultTable
Dim NumDimensions As Integer = Res.NumDims
Dim CurIndexName As String = Res.IndexNames(NumDimensions)
Dim IndexObj As CAIndex = Res.GetIndexObject(CurIndexName)

The example above retrieved the last CAIndex object, with respect to the index order, from the table. The CAIndex object provides properties and methods that allow you to obtain information about the respective index.

To get the number of elements in the index

Use the IndexElements property:

Dim Obj As CAObject = ADE.GetObjectByName ("MultiDimObject")
Dim Res As CATable = Obj.ResultTable
Dim NumDimensions As Integer = Res.NumDims
Dim CurIndexName As String = Res.IndexNames (NumDimensions)
Dim IndexObj As CAIndex = Res.GetIndexObject(CurIndexName)
Dim NumElsInIndex As Integer = IndexObj.IndexElements

To get an index label at the specified position in the index

Use the GetValueByNumber method:

Dim I As Integer
Dim Obj As CAObject = ADE.GetObjectByName("MultiDimObject")
Dim Res As CATable = Obj.ResultTable
Dim NumDimensions As Integer = Res.NumDims
Dim CurIndexName As String = Res.IndexNames(NumDimensions)
Dim IndexObj As CAIndex = Res.GetIndexObject (CurIndexName)
Dim Str As String = "The elements in the index are: " & vbCrLf
For I=1 To IndexObj.IndexElements
Str = Str & IndexObj.GetValueByNumber(I) & " "
Next I
MsgBox Str

To get at the position of an index label in an index

Use the GetNumberByValue method:

Dim Obj As CAObject = ADE.GetObjectByName ("MultiDimObject")
Dim Res As CATable = Obj.ResultTable
Dim IndexName As String = Res.IndexNames(Res.NumDims)
Dim IndexObj As CAIndex = Res.GetIndexObject(IndexName)
Dim IndexPosition As Integer
IndexPosition = IndexObj.GetNumberByValue("SomeIndexLabel")
If ADE.ErrorCode = 0 Then
’the index position was successfully retrieved
Else
’an error occurred
End If

To obtain the scalar value in a zero-dimensional array

Dim Res As CATable = ADE.Get("SomeObject").ResultTable
Dim x As Object
If Res.NumDims = 0 Then
x = Res.AtomicValue
Else
’ Handle the array case.
End If

Sometimes, it is not possible to know in advance whether the evaluation of an object returns a multi-dimensional result or a scalar. In this case, use ResultTable. If the result happens to be a scalar, NumDims returns zero. In this case, the so-called “array” isn’t an array at all, but rather contains a single atomic value. It is also possible to end up with a zero-dimensional array after calling the CATable::Slice or CATable::Subscript methods. To obtain the atomic value, use the CATable::AtomicValue method.

To reduce dimensionality in Slice and Subscript operations

Dim PandL As CATable = ADE.Get("P_n_L_Statement").ResultTable
Dim CatIndex As CAIndex = PandL.GetIndexObject("Categories")
Dim Expenses As CATable = PandL.Subscript(CatIndex,"Expenses")
Dim Year As CAIndex = Expenses.GetIndexObject("Year")
Dim InitialExpense
InitialExpense = Expenses.Slice(Year,1).AtomicValue

The Slice and Subscript methods of CATable return a new CATable object with the number of dimensions reduced by one. These methods are similar to the Slice and Subscript functions built into Analytica. Slice returns the Nth slice (by position) along a given dimension. Subscript returns the slice corresponding to a specified index value.

Creating Tables and Setting Values in Tables

We can apply the same methods described above to definition tables to retrieve values from result tables. A definition table, as the name suggests, is when the definition of an object is a Table function (also known as an edit table in Analytica).

The value of an Analytica variable (accessed via ResultTable) can be an array — not because it was defined by a definition table, but simply because it is defined as an expression or function that returns an array value.

When using an edit table, you need to pay careful attention to whether you are passing general expressions into each table cell, or just literal strings. The RenderingStyle.GeneralExpression property determines how string values that you send to the table are interpreted. By default, GeneralExpression=true, which means that if you set a cell value to the string "Revenue", this is an actual expression consisting of one variable identifier, and not a literal string. If you are populating a definition table with literal constants (as you might an input table to your model), you should either use RenderingStyle.GeneralExpression=false, or remember to prepend and append quotation marks on all literal string values.

An object defined as a definition table does not necessarily produce the same table when ResultTable is called. After all, the definition table can be defined to be an array of identifiers. When ResultTable is called, each identifier’s result is evaluated, and a new table is produced (which would be different than the definition table). If identifiers evaluate to arrays, the result table might have more dimensions than the definition table.

To get the definition table of an object as a CATable

Use the DefTable method of CAObject:

Dim Obj As CAObject
Dim TableDef As CATable
Obj = ADE.GetObjectByName("MultiDimObject")
TableDef = Obj.DefTable
If Not TableDef Is Nothing Then
’Definition table was successfully retrieved
Else
’An error occurred, or definition is not a table
End If

After the definition table is retrieved, we can use all the same methods described in the section above GetDataByElements, GetDataByLabels, SetIndexOrder, etc.) to retrieve elements in the table and to obtain information about the indexes in the table. We can also use the same method that we used above in determining whether the result of the object was multi-dimensional or scalar to determine whether the definition of the object is a table or scalar:

Dim Obj As Object
Dim TableDefinition As Object
Dim ScalarDefinition
Obj = ADE.GetObjectByName ("SomeObject")
TableDefinition = Obj.DefTable
If TableDefinition Is Nothing Then
ScalarDefinition = Obj.GetAttribute ("definition")
If ADE.ErrorCode = 0 Then
’you have a scalar definition
Else
’an error occurred
End If
Else
’you have a table definition
End If

To set an element in a table by index order

Use the SetDataByElements method of CATable:

Dim Obj As CAObject
Dim TableDef As CATable
Dim IndexOrder (2) As String
Dim Pos (2) As Integer
Dim Element
Obj = ADE.GetObjectByName ("MultiDimObject")
TableDef = Obj.DefTable
If Not TableDef Is Nothing Then
’Definition table was successfully retrieved
IndexOrder (1) = “Index2”
IndexOrder (2) = “Index1”
If TableDef.SetIndexOrder (IndexOrder) Then
’Index Order set successfully
Pos (1) = 2
Pos (2) = 1
Element = "'ABC'" ’ Notice the extra quotes
If TableDef.SetDataByElements(Element,Pos) Then
’element successfully set
If TableDef.Update Then
’model successfully updated
Else
’error updating def in model
End If
Else
’an error occurred
End If
Else
’An error occurred in setting index order
End If
Else
’An error occurred, or definition is scalar
End If

This code uses SetDataByElements to set the element at position Index2=2, Index1=1 to Element. Note the use of the quotes around ABC. Here, since ABC is single quoted, we are putting the string “ABC” in the table. If we instead set Element to “ABC”, then the expression ABC would be placed in the table. In the latter case, ABC would likely be a variable. If an identifier, ABC, did not exist in the model, then an error would have occurred while trying to set the element in the latter case. The code then used Update to update the model with the new definition. It is important to note that the model containing the object is not updated until Update is called. Therefore, if Update is not called, and the result of a node that depends on this object is later calculated, the old definition of this object is still used. The other important thing to note is that Update functions very differently for result tables than for definition tables. For result tables, Update retrieves the result from the specified object again. Therefore, it overwrites any changes that were made to the object using SetDataByElements and SetDataByLabels.

To set an element in a table by index labels

Use the SetDataByLabels method of CATable:

Dim Obj As CAObject
Dim TabDef As CATable
Dim IndexOrder (2) as String
Dim Pos (2) as String
Dim Element Obj = ADE.GetObjectByName("MultiDimObject")
TabDef = Obj.DefTable
If Not TabDef Is Nothing Then
’Definition table was successfully retrieved
TabDef.RenderingStyle.GeneralExpression = False
IndexOrder (1) = "Index2"
IndexOrder (2) = "Index1"
If TabDef.SetIndexOrder (IndexOrder) Then
’Index Order set successfully
Pos (1) = "SomeLabelInIndex2"
Pos (2) = "SomeLabelInIndex1"
Element = "ABC"
If TabDef.SetDataByLabels(Element,Pos) Then
’element set successfully
If TabDef.UpdateThen
’model successfully updated
Else
’an error occurred
End If
Else
’an error occurred
End If
Else
’An error occurred in setting index order
End If
Else
’An error occurred, or definition is scalar
End If

The code above uses SetDataByLabels to set the element at position Index2="SomeLabelInIndex2", Index1="SomeLabelInIndex1" to Element. In this example, the RenderingStyle.GeneralExpression property was set to False. This eliminates the need to explicitly include quotes around the string as was done in the previous example for SetDataByElements.

To set the whole table in one call

Use PutSafeArray and Update:

Dim Obj As CAObject
Dim TableResult, TableDef As CATable
Dim RetValue
Dim TheWholeTable
Obj = ADE.GetObjectByName("MultiDimObject")
TableDef = Obj.DefTable
TableResult = Obj.ResultTable
TheWholeTable = TableResult.GetSafeArray
‘make changes to TheWholeTable
RetValue = TableDef.PutSafeArray (TheWholeTable)
If RetValue = True Then
’table successfully put
RetValue = TableDef.Update
If RetValue = True Then
’model successfully updated
End If
End If

To create a whole table from scratch

Use CreateDefTable:

Dim Obj As CAObject
Dim RetValue
Dim IndexLabs (2) As String
Obj = ADE.CreateObject ("MyNewTable", "Variable")
IndexLabs (1) = "I"
IndexLabs (2) = "J"
RetValue = Obj.CreateDefTable (IndexLabs)
If RetValue = True Then
’a table indexed by I and J has successfully
’been created. We are assuming that I and J
’already exist
Else
’an error occurred when creating the table
End If

The code above created a definition table indexed by I and J. The table is dimensioned according to the size of I and J. All the cells in the table are initially set to 0. The user can then call DefTable, and then use SetIndexOrder, SetDataByElements, SetDataByLabels, PutSafeArray, and Update to put values into the table. Note that the function CreateDefTable is very rarely used in an ADE program. After all, it is much easier to create an object in Analytica than it is in ADE.

Adjusting How Values are Returned

Analytica models can contain several different data types for values in attributes or in the cells of a table or index. Data types include floating point numbers, textual strings, the special values Undefined and Null, references, and handles to other objects. When these data types are returned and ultimately mapped to data types in the programming language you are using, you might want or need to alter how the values are returned. You can do so using RenderingStyle.

The CAObject, CATable, and CAIndex objects all contain a property called RenderingStyle, which returns a CARenderingStyle object. Properties of the rendering style can be changed to alter how values are returned. You can also control whether safe arrays returned by Analytica are 1-based or 0-based. These settings impact CAObject::GetAttribute and CAObject::Result; they also impact CATable::GetDataByElements, CATable::GetDataByLabels, CATable::AtomicValue, CATable::GetSafeArray, and CAIndex::GetValueByNumber.

When transferring values to cells in a DefTable, you can also control whether the cells are populated by literal strings and values, or by general expressions. This is controlled by the GeneralExpression property of CARenderingStyle.

The DefaultRenderingStyle and DefaultDefTableRenderingStyle properties of CAEngine can be set once just after the CAEngine has been instantiated to set the rendering style globally. For example, if you always use zero-based arrays, this can be specified once.

Retrieving numeric values as numbers

obj.RenderingStyle.NumberAsText = False
Dim x As Double = obj.Result

Numeric values are returned as numbers by default, so unless NumberAsText is set to True at some point, there is no need to specify this explicitly.

Retrieving numeric values as formatted strings

Dim TableResult As CATable = Obj.Evaluate("1 / 3 * 10 ^ 6")
TableResult.RenderingStyle.NumberAsText = True
TableResult.RenderingStyle.FullPrecision = False
Dim s As String = TableResult.AtomicValue

The number format associated with Obj is used to format the numeric value. A suffix style with four digits returns “333.3K” for this example.

Retrieving numeric values as strings with no loss of precision

Dim TableResult As CATable = Obj.Evaluate("1 / 3 * 10 ^ 6")
TableResult.RenderingStyle.NumberAsText = True
TableResult.RenderingStyle.FullPrecision = True
Dim s As String = TableResult.AtomicValue

Analytica continues to use the number format associated with Obj, but the significant digits is increased to avoid any loss in precision. So, suffix, exponential, fixed point, and percent formats are not truncated. If a date, integer, or Boolean format is used, some truncation might still occur. In the example, the return value would be 333.333333333333.

Retrieving string results without quotation marks

tab.RenderingStyle.StringQuotes= 0

Retrieving string results with explicit quotation marks

tab.RenderingStyle.StringQuotes = 1 ’ for single quotes
tab.RenderingStyle.StringQuotes= 2 ’ for double quotes

Using a custom value for Undefined

ADE.DefaultRenderingStyle.UndefValue = ""

By default, the special value Undefined is returned as a the special Windows variant type Empty. There are some scripting languages that cannot deal with the Empty data type, so if you encounter this problem, you might want to change this value.

Setting the cells of a definition table to string values

defTab.RenderingStyle.GeneralExpression= False

defTab.SetDataByElements("A & B",inds)

In this example, the indicated table cell is set to the string value "A & B". When this table is evaluated, this cell’s result is a string containing the five characters "A & B".

Setting the cells of a definition table to expressions

defTab.RenderingStyle.GeneralExpression = True
defTab.SetDataByElements("A & B",inds) </tt>

Here the cell is set to the expression "A & B". When this table is evaluated, the variable named A and the variable B is evaluated, and their results are coerced to strings and concatenated by the & operator.

You can set table cells to literal strings with GeneralExpression=True, but you must embed explicit quotations marks in the expression. For example:

defTab.RenderingStyle.GeneralExpression= True
defTab.SetDataByElements("’A & B’",inds)

GeneralExpression=True by default.

Terminating an In-progress Computation

Methods such as CAObject::ResultTable, CAObject::Result, or CAObject::Evaluate can initiate lengthy evaluations that could tie up your application. Some models can take many minutes, or even several hours, to compute the result. Normally, your call to ResultTable does not return until the result is fully computed.

You might want to provide your end user with the capability to abort the current computation, such as when a "break" key or button is pressed. Alternatively, you might want to terminate the current computation if your application is suddenly being terminated while a lengthly computation is still processing, so that ADE also terminates.

To implement the ability to abort a computation, you need to have some form of multi-threading in your application. The thread that calls ADE is occupied waiting for ADE to return, so some other thread in your application must detect the request to terminate the computation. When this request is detected, the second thread communicates this request to ADE through a global system event object. You must obtain the information required to locate this global event object from ADE before you have started the length computation. Each CAEngine instance has its own event object with a unique global name, but the same event object applies to the same CAEngine instance for the entire lifetime of the CAEngine instance.

To obtain the event object (using Windows Platform SDK calls):

Dim abortEventName As String
Dim abortHandle as Handle ’ This needs to be global
ade.SendCommand("GetProcessInfo('Abort Event Object')")
abortEventName = ade.OutputBuffer
abortHandle = OpenEvent(EVENT_MODIFY_STATE, FALSE, abortEventName )
...
’ Launch the computation
tab = obj.ResultTable

In a separate thread that detects a request to terminate the computation, the following code sends that request to ADE (using Windows Platform SDK calls):

SetEvent(abortHandle)

Note that OpenEvent and SetEvent are Windows Platform SDK calls, not part of ADE. Also notice that the abortHandle variable must be a global that is accessible from both threads. However, the second thread does not require access to the ADE objects themselves. Alternatively, the abortEventName can be shared and the second thread can call OpenEvent.

When the event has been flagged, ADE backs out of the current computation and returns from the current method. A small delay might be experienced while ADE backs out of the current computation. When it has returned, the CAEngine.ErrorCode is set to 78 (“Computation aborted”). Your application might continue using the same ADE instance as it would have prior to the call that was aborted.

Instantiating CAEngine using CALicense

To start using ADE, the first thing you need to do is instantate a CAEngine object. You have the option of instantiating your CAEngine object directly, or you can instantiate a CALicense object first and use it to instantiate your CAEngine object. When you’ve successfully obtained a CAEngine object, it doesn’t matter which of these two methods you used to get it. The difference is that if you use a CALicense object to instantiate your CAEngine, more information about why it failed is available. In particular, if the failure is due to a license code problem, your application has an opportunity to handle the error gracefully.

If you are creating an ADE-based application that are to be redistributed to many end users, who would otherwise not have an ADE license, you need to make arrangements with Lumina to license ADE for distribution with your application. This form of licensing requires your application to provide a special type of license code to ADE, called an application license code, since your end users usually do not have a license code of ADE on their computer. Note that a license to redistribute ADE in this fashion is not included as part of the standard ADE license agreement, and additional license fees apply. To use an application license code, you must use a CALicense to instantiate your CAEngine, since your application uses the CALicense object to supply the license code to Analytica.

The steps for instantiating a CAEngine using a CALicense are as follows, e.g.,:

' In VB
Imports ADE
...
Dim license As CALicense = New CALicense
Dim ade As CAEngine = license.NewCAEngine
If (ade Is Nothing) Then
' substitute error handling routine here
ReportError(license.ErrorText)
End If
// In C#
Using ADE;
...
CALicense license = new CALicense();
CAEngine ade = license.NewCAEngine();
if (ade==null) {
ReportError( license.ErrorText );
}

If you have an application license code, insert a call to SetApplicationLicenseCode:

license = new CALicense
license.SetApplicationLicenseCode("1234-5678-ABCD-EFGH-IJKL")
ade = license..NewCAEngine

Using the Analytica Graphing Engine

When you have a CATable result with at least one dimension, you can obtain a graph of the result as an image. One use of this is to embed graphs as JPEG images in a web page that uses ADE on the back end.

Obtaining the graph of a result requires the following steps:

  1. Select the appropriate graph settings, such as chart type, axis range settings, colors, fonts, and so on. The easiest way is to open the model in Analytica Enterprise, and select the settings you want for each variable using the Graph Setup dialog.
    The graph template you create using the Graph Setup dialog is stored in the GraphSetup attribute of the object. You can copy the GraphSetup attribute from an existing variable if you need to change the style template.
  2. From ADE, obtain a CATable with the result to be graphed.
  3. Set the GraphWidth and GraphHeight properties of the CATable object to indicate the desired size of the graph in pixels.
  4. If your result has more than two dimensions, use one of the following options:
    • call Slice or Subscript to reduce the dimensionality to the desired dimensionality for the plot (usually one dimension if there is no key or two dimensions if there is a key).
      • If you have more than one dimension, call SetIndexOrder to select the desired pivot for the graph.
    or
    • set GraphWithStoredPivot to true. Use this option to produce the same slice and pivot as seen when viewed in desktop Analytica.
  5. If you are sending the graph to an output stream, obtain a Windows IStream interface to the stream. If you have a .NET Stream (System.io.Stream), you need to use a wrapper class (see below).
  6. Call either the GraphToStream or GraphToFile methods of CATable, depending on where you want the graph written to. The graph can be created in different MIME types (e.g., image/ JPEG).

If you are able to view the result graph in Analytica with no slicers, then steps 4 and 5 are unnecessary.

Writing a result graph to a file:

Dim res As CATable = obj.ResultTable
res.GraphWidth = 640
res.GraphHeight = 400
If res.GraphToFile("C:\Temp\Result.JPG","image/JPEG") Then
’ success
End If

Dynamically generating a result graph from an ASP.NET web page

<%
Response.ContentType = "image/JPEG"
Dim varName As String = Request.QueryString("var")
Dim ADE As CAEngine = Session("ADE") ’ assume existing session
Dim res As CATable = ADE.Get(varName).ResultTable
res.GraphWidth = 640
res.GraphHeight = 400
Dim stream As StreamConnector = _ new StreamConnector( Response.OutputStream)
If res.GraphToStream( stream, "image/JPEG") Then
’ success
End If
%>

In this example code, Response, Request, and Session are Active Server Page objects. The HTTP in the client browser would contain a tag like this:

<img src="http://www.acme.com/Myapp/graph.aspx?var=Profit">

When Microsoft introduced .NET, they did not make the base Stream class interface in .NET compatible with the IStream interface in Windows. Because of this, it is necessary to create a stream wrapper that implements the IStream interface around the .NET Stream before passing it to GraphToStream. This wrapper, class StreamConnector, is included in the example AdeTest. To use the example above, add the file StreamConnector.vb to your project.

See Also


ADE User Guide Navigation
Using the Analytica Decision Engine Server << Previous Working with Models, Modules, and Files in ADE Next >> ADE Server Class Reference
Comments


You are not allowed to post comments.