|
|
Line 1: |
Line 1: |
− | [[Category:ADE User Guide]]
| + | #REDIRECT [[The ADE Tutorial]] |
− | [[ADE User Guide|<< Back to ADE User Guide]]
| |
− | | |
− | This tutorial shows you how to use the Analytica Decision Engine (ADE) from within a Visual Basic program.
| |
− | | |
− | ==Your first ADE application==
| |
− | First let’s write a simple ADE application from scratch, just to be sure that everything is set up correctly. Follow these steps:
| |
− | | |
− | #Bring up Visual Studio.NET.
| |
− | #Select '''New Project''', then select the Project Type “Visual Basic Projects” and the template “Console Application.” Select a project name, e.g., “FirstADEtry,” and an appropriate folder location.
| |
− | #From the '''Project''' menu, select '''Add Reference''' and select the '''COM''' tab in the dialog. Find and select '''Analytica Decision Engine Local Server 4.6''' (<tt>Ade.exe</tt>) and click '''OK'''.
| |
− | #*'''''Note:''' If you have installed ADE 64-bit and do not have ADE 32-bit installed, Visual Studio may not show '''Analytica Decision Engine Local Server 4.6''', even though it is properly installed. This occurs because Visual Studio itself is a 32-bit application. If this happens, select the Browse tab on the Add Reference dialog, navigate to the ADE install directory (usually'' <tt>C:\Program Files\Lumina\ADE 4.6</tt>''), and select ''<tt>ADE64.exe</tt>''.''
| |
− | #*'''''Note:''' If you cannot find this entry in the list of COM servers, then ADE 4.6 is not properly installed. See [[Installation of ADE]] for instruction on how to install ADE before reading further.''
| |
− | #Add to the Module1 class as follows: <tt>
| |
− | #:Imports ADE
| |
− | #:Module Module1
| |
− | #::Public ADE As [[CAEngine]]
| |
− | #::Sub Main()
| |
− | #:::Dim FileName, ModelName As String
| |
− | #:::FileName = "C:\Program Files\Lumina\Analytica 4.6"
| |
− | #:::FileName &= "\Example Models\Tutorial Models\Car Cost.ana"
| |
− | #:::ADE = New [[CAEngine]]
| |
− | #:::ADE.[[CAEngine::MonitorProcess|MonitorProcess]]( System.Diagnostics.Process.GetCurrentProcess().Id )
| |
− | #:::ModelName = ADE.[[CAEngine::OpenModel|OpenModel]](FileName)
| |
− | #:::If ModelName = "" Then
| |
− | #::::Console.Write(FileName & " not found")
| |
− | #:::Else
| |
− | #::::Console.Write("Congratulations on opening ")
| |
− | #::::Console.WriteLine(ModelName)
| |
− | #::::Console.WriteLine("Press 'enter' to exit")
| |
− | #::::Console.ReadLine()
| |
− | #:::End If
| |
− | #::End Sub
| |
− | #:End Module</tt>
| |
− | #Now just run the program. If your program prints “Congratulations on opening Carcosts” you have just successfully written your first ADE program.
| |
− | | |
− | | |
− | This first program did the following:
| |
− | *Created a [[CAEngine]] automation object called ADE (using <code>new [[CAEngine]]</code>).
| |
− | *Opened an Analytica model (using the [[CAEngine::OpenModel|OpenModel]] method of [[CAEngine]]).
| |
− | *Displayed the name of the model (the return value of [[CAEngine::OpenModel|OpenModel]]).
| |
− | We go into the details of these and other functions in the next section.
| |
− | | |
− | ===What's next?===
| |
− | We will not attempt to explain all of the features of ADE in this tutorial. These are described in the following chapters of this guide. Here, we give you the background to explore the more advanced features of ADE on your own.
| |
− | | |
− | From this point, we use the example model called <tt>Txc.ana</tt>. You can find <tt>Txc.ana</tt> in the '''Risk Analysis''' folder under the '''Example Models''' folder installed with Analytica. If you cannot find it, or if you opted not to install the examples when you originally installed Analytica, there is a copy in the '''Examples\Tutorial.NET''' folder in the directory where you installed ADE.
| |
− | | |
− | The Txc model demonstrates risk-benefit analysis of reducing the emissions of the fictitious air pollutant TXC. Please open the Txc model with Analytica to see how it works.
| |
− | | |
− | The example Visual Basic.NET program called <tt>TestTxc</tt> in your ADE '''Examples\Tutorial.NET''' folder shows many aspects of ADE. This program creates an ADE automation object, opens the <tt>Txc.ana</tt> model with this object, gets the definition of the <tt>Population Exposed</tt> variable, evaluates the <tt>Total Cost</tt> variable, prints out the result of the <tt>Total Cost</tt> variable as a table by getting at the individual components of the table, and changes the definition of the <tt>Population Exposed</tt> variable. It then gets the result of the <tt>Total Cost</tt> variable again, to see what effect the change of definition for <tt>Population Exposed</tt> had on the <tt>Total Cost</tt> variable. If things are set up properly, <tt>TestTxc</tt> displays the window shown in “Text Txc window”.
| |
− | | |
− | The application displays the definition of the <tt>Population Exposed</tt> variable (<tt>"Normal (30M, 3M)"</tt>), and the table associated with <tt>Total Cost</tt>, based on the definition of <tt>Population Exposed</tt>. You can change the definition of <tt>Population Exposed</tt> by selecting '''File > Change Population Exposed''' from the main menu and seeing the effect this has on the <tt>Total Cost</tt> table.
| |
− | | |
− | [[File:TextTxcWindow.png]]
| |
− | | |
− | ===Distinguishing title from identifier===
| |
− | Whenever an ADE function requires a variable, you must pass it the '''''[[Identifier]]''''' of the variable, not its '''''[[Title]]'''''. This can be confusing since Analytica normally displays the titles of each variable in an influence diagram. By default, when you first create each object, Analytica automatically creates an identifier based on the title. It substitutes an underscore (_) for each blank or other character in the title that is not a letter or number.
| |
− | | |
− | You can show the identifiers in an influence diagram by pressing ''Control+y'' (or by selecting '''Show by identifier''' from the Object menu). For model <tt>Txc.ana</tt>, you can see that the identifier of the variable titled <tt>Population Exposed</tt> is <tt>Pop_exp</tt>. It is important to use <tt>Pop_exp</tt> as the identifier when passing this variable to ADE functions. ADE would not be able to find the variable if you pass <tt>Population Exposed</tt>, and would return an error.
| |
− | | |
− | ===Creating an ADE object from within Visual Basic===
| |
− | | |
− | If you haven’t already, load the project called <tt>Examples\Tutorial\TestTxc.sln</tt> into Visual Basic.NET, and view the code for the file called <tt>TestTxc.vb</tt>. The code looks like this: <tt>
| |
− | :Imports ADEW
| |
− | :. . .
| |
− | :Public adeEngine As [[CAEngine]]
| |
− | | |
− | :Public Sub Main()
| |
− | ::Dim exeDirectory, theModel As String
| |
− | ::Dim theModelString As String
| |
− | ::exeDirectory = VB6.GetPath
| |
− | ::theModel = exeDirectory & "\..\" & "Txc.ana"
| |
− | ::adeEngine = New [[CAEngine]]
| |
− | ::...
| |
− | ::theModelString = adeEngine.[[CAEngine::OpenModel|OpenModel]](theModel)
| |
− | ::...
| |
− | ::frmMain.DefInstance.Show()
| |
− | :End Sub </tt>
| |
− | | |
− | At the very top of the file, the code declares the automation object '''adeEngine''' as a [[CAEngine]] object. Using this object, we can access all of the public functions exposed by [[CAEngine]] (see [[ADE Server Class Reference]] for a complete listing). This line then creates the [[CAEngine]] object. <tt>
| |
− | :adeEngine = New [[CAEngine]]</tt>
| |
− | | |
− | The <tt>adeEngine</tt> variable now holds our in-process [[CAEngine]] object. If we want to use the local (out-of-process) server version of ADE, we can add a reference to the project to the '''Analytica Decision Engine Server 4.6 COM''' component and change the top line from <tt>Imports ADEW</tt> to <tt>Imports ADE</tt>.
| |
− | | |
− | Here is another way to obtain a new [[CAEngine]] object. This sequence does not require adding a reference to the project.<tt>
| |
− | :adeEngine = CreateObject("ADEW4.6.CAEngine") ’ in-process
| |
− | :adeEngine = CreateObject("ADE4.6.CAEngine") ’ out-of-process </tt>
| |
− | | |
− | To understand the pros and cons of using an in-process server versus as out-of-process (or local) server, and which automation server to use for different scenarios, see [[Using_the_Analytica_Decision_Engine_Server#In-process_vs_Out-of-process | In-process vs. out-of-process]], as well as other books related to COM servers.
| |
− | | |
− | ===COM vs. Automation interface===
| |
− | In the example above, we used a COM interface to call ADE. In a COM interface, the object ([[CAEngine]] in this case) is declared as [[CAEngine]], and the compiler resolves each member function and can detect several obvious errors at compile time. In addition, Visual Studio can provide a list of methods and parameter types as tool tips as you program, which is helpful when writing programs that use ADE. COM calls are slightly faster than Automation calls, but the speed difference is not usually significant in applications of ADE. With ADE 4.6, we recommend using the COM interface if your programming language supports it.
| |
− | | |
− | In VB Automation, you can declare an object simply as Object, rather than a more specific types such as [[CAEngine]], [[CAObject]], and so on. When '''ADE''' methods are called using Automation, the methods are resolved at run time. At compile time, the compiler does not know whether your '''ADE''' object has a function named [[CAEngine::OpenModel|OpenModel]]. In VB, the syntax for calling a COM method or an Automation method is identical — the only difference is whether the object’s type is declared explicitly.
| |
− | | |
− | In VC++ and C#, the syntax for calling COM is not the same as for Automation. In these cases, COM is much more convenient, while Automation can get rather tedious. However, some languages, including VBScript and other scripting languages, support only Automation and not COM.
| |
− | | |
− | ===Monitoring the Process===
| |
− | When using the out-of-process ADE server, your own code must release the [[CAEngine]] COM object when it terminates. When this final [[CAEngine]] usage is released, the ADE.exe process automatically terminates. In the code seen so far, the VB language takes care releasing the object automatically when it reaches the end of the program. However, while you are debugging your own code, you may terminate your program prematurely to fix a bug, your program may be killed from Task Manager, or your own code may crash, causing your program’s process to terminate before it had a chance to release the object. Because the COM object is never released, the ADE.exe process cannot know that it is no longer in use, and you may get zombie ADE.exe processes lingering.
| |
− | | |
− | To avoid this, it is a good practice to call [[CAEngine::MonitorProcess]] immediately after obtaining a [[CAEngine]] instance. You pass the method the process id for your program’s own process. In this fashion, ADE can learn which process is using it, and will set up a thread to detect if your process terminates before ADE is fully released. If your program’s process does terminate, the ADE process immediately shuts itself down, eliminating the build-up of zombie ADE processes.
| |
− | | |
− | To obtain your process ID from a .NET application, use the '''GetCurrentProcess().Id''' found in theSystem.Diagnostics.Process namespace. In other languages, you can use the Windows SDK function '''GetProcessId( )'''.
| |
− | | |
− | '''[[CAEngine::MonitorProcess|MonitorProcess]]()''' can only be used to monitor processes running on the same computer as ADE’s process, so you can’t use this if running ADE through DCOM. There is no need to use this when using the in-process ADEW server.
| |
− | | |
− | ==Opening a model with ADE==
| |
− | We will now open the <tt>Txc.ana</tt> model, and show the main window of our application. Use the following call:<tt>
| |
− | :theModelString = adeEngine.[[CAEngine::OpenModel|OpenModel]](theModel)
| |
− | :frmMain.DefInstance.Show </tt>
| |
− | | |
− | The [[OpenModel]] function of [[CAEngine]] opens the model. If successful, the variable <tt>theModelString</tt> contains the name of the model. Otherwise, it contains an empty string. Although we haven’t done so in this example for the sake of brevity, you should check to see that the string returned from [[OpenModel]] isn’t empty. If it is, there was an error in opening your model. You can find out what kind of error with the [[ErrorCode]] and [[ErrorText]] properties of [[CAEngine]] (<tt>adeEngine.[[CAEngine::ErrorCode|ErrorCode]] and adeEngine.[[CAEngine::ErrorText|ErrorText]]</tt>). We will see how to use these two properties later on. For a listing of all the error codes, see [[ADE Error Codes]].
| |
− | | |
− | ==Retrieving objects from the Analytica model==
| |
− | The next step is to retrieve objects (variables, modules, functions, etc.) from our model, so that we can access their attributes ([[definition]], [[title]], [[class]], etc.). Our example model (<tt>Txc.ana</tt>) manipulates the <tt>Pop_exp</tt> and <tt>Cost</tt> objects. In particular, it modifies <tt>Pop_exp</tt> to see how this effects the <tt>Cost</tt> object.
| |
− | | |
− | The '''PrintAttributes''' function in the file <tt>frmMain.frm</tt> of our <tt>TxcTest.vbproj</tt> (<tt>TxcText.sln</tt>) project shows how to do this. This function is first called by the '''Form_Load''' function of <tt>frmMain.frm</tt>, when the application starts, to display the '''Cost''' table. It is also called whenever we wish to print out the current result of our '''Cost''' table. The function looks like this: <tt>
| |
− | :Public Sub PrintAttributes(ByRef inputIdentifier As String, ByRef outputIdentifier As String)
| |
− | ::Dim inputObject, outputObject As [[CAObject]]
| |
− | ::Dim resultTable As [[CATable]]
| |
− | ::Dim definitionAttrInput As String
| |
− | ::inputObject = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]](inputIdentifier)
| |
− | ::outputObject = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]](outputIdentifier)
| |
− | ::definitionAttrInput = inputObject.[[CAObject::GetAttribute|GetAttribute]]("definition")
| |
− | ::resultTable = outputObject.[[CAObject::ResultTable|ResultTable]]
| |
− | ::Call PrintResultTable(resultTable, inputIdentifier, definitionAttrInput, outputIdentifier)
| |
− | ::ReleaseComObject(resultTable)
| |
− | ::ReleaseComObject(inputObject)
| |
− | ::ReleaseComObject(outputObject)
| |
− | :End Sub </tt>
| |
− | | |
− | '''PrintAttributes'''works with the variable identifiers <tt>Pop_exp</tt> passed as parameter '''inputIdentifier''' and '''Cost''' passed as parameter '''outputIdentifier'''. It fetches the corresponding objects using the [[GetObjectByName]] function of [[CAEngine]] as follows: <tt>
| |
− | :inputObject = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]](inputIdentifier)
| |
− | :outputObject = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]](outputIdentifier)</tt>
| |
− | | |
− | If [[GetObjectByName]] succeeds, it returns an object of type [[CAObject]]. You then use the functions of '''[[CAObject]]'''. See [[CAObject Functions | SendCommand(command)]] for a listing all [[CAObject]] functions. If [[GetObjectByName]] fails, the return value is <tt>Nothing</tt>. The code should check to make sure that the result from [[GetObjectByName]] is valid. If not, use the [[ErrorCode]] and [[ErrorText]] properties of [[CAEngine]] to get more information about the error. For example: <tt>
| |
− | :Set inputObject = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]](inputIdentifier)
| |
− | :If inputObject Is Nothing Then
| |
− | ::MsgBox(“This error from GetObjectByName occurred: “& _ vbCrLf & adeEngine.[[CAEngine::ErrorCode|ErrorCode]] & “:” & adeEngine.[[CAEngine::ErrorText|ErrorText]])
| |
− | :Else
| |
− | ::'inputObject valid
| |
− | :End If</tt>
| |
− | | |
− | ===Getting object attributes===
| |
− | Each Analytica object has a set of attributes (analogous to properties), such as [[identifier]], [[title]], [[description]], and [[class]]. You can use the [[GetAttribute]] function to obtain an attribute from an Analytica object. For example, to get the definition of '''inputObject''' (currently, the cost): <tt>
| |
− | :definitionAttrInput = inputObject.[[CAObject::GetAttribute|GetAttribute]]("[[Definition]]") </tt>
| |
− | | |
− | In the <tt>Txc.ana</tt> model, the definition of <tt>Pop_exp</tt> is "<tt>[[Normal]](30M, 3M)</tt>" which we store in '''definitionAttrInput'''.
| |
− | | |
− | ===Evaluating objects and retrieving results===
| |
− | Use [[Result]] or [[ResultTable]] methods of [[CAObject]] to get the value of a variable. ADE automatically evaluates the variable first, if necessary. Use the [[Result]] method if you are sure the result will be ''atomic'', i.e., a single element. Otherwise, use [[ResultTable]], which retrieves the result as an ''array''. An atomic result is treated as a special case of an array, one with zero dimensions. If the value is atomic, the method [[AtomicValue]] returns its single value as a number or string.
| |
− | | |
− | By default, [[Result]] and [[ResultTable]] return the mid value of the result, i.e., the result of ADE evaluating it as deterministic. For a probabilistic value, set the [[ResultType]] property of [[CAObject]] to the desired uncertainty view — Mean, Sample, PDF, CDF, Confidence bands, or Statistics (see [[ResultType]] for details). We get the value of outputObject like this: <tt>
| |
− | :resultTable = outputObject.[[CAObject::ResultTable|ResultTable]] </tt>
| |
− | | |
− | The result is a [[CATable]] object, which lets us access individual elements in a table.
| |
− | | |
− | If you call [[Result]] to get an array (or table) value, it returns the array as a string, listing the indexes and elements separated by commas. It is usually easier to use [[ResultTable]], so that you don’t have to parse elements of the table from the string.
| |
− | | |
− | ===Getting the index elements of a table===
| |
− | An Analytica table has zero or more indexes. If it has one index, then it is one-dimensional; if it has two indexes, it is two-dimensional, and so on. A zero-dimensional table holds a ''single atomic'' (or scalar) value. You can use the [[NumDims]] function of CATable to get the number of dimensions (same as number of indexes) of a table. To get at the individual indexes of a table, use methods [[IndexNames]] and [[GetIndexObject]] of [[CATable]].
| |
− | | |
− | The function '''PrintResultTable''' in <tt>frmMain.frm</tt> shows the use of these two functions. '''PrintResultTable''' is called from '''PrintAttributes''', and does the actual work of printing the table that shows up in our '''TestTxc''' application (for brevity, we show only the parts of this function related to ADE).<tt>
| |
− | :Public Sub PrintResultTable(ByRef resultTable As CATable, ByRef inputIdentifier As String, ByRef definitionAttrInput As String, ByRef outputIdentifier As String)
| |
− | ::Dim theIndexName, theTableName As String
| |
− | ::Dim theIndexElement As String
| |
− | ::Dim theTableElement
| |
− | ::Dim theIndexObj As [[CAIndex]]
| |
− | ::Dim numEls As Integer
| |
− | ::Dim spaces, i As Integer
| |
− | ::Dim lenStr As Short
| |
− | ::Dim OutputStr As Short
| |
− | ::Dim spaceString, underlineString As String
| |
− | ::...
| |
− | ::theIndexName = resultTable.[[CATable::IndexNames|IndexNames]](1)
| |
− | ::theTableName = resultTable.[[CATable::Name|Name]]
| |
− | ::theIndexObj = resultTable.[[CATable::GetIndexObject|GetIndexObject]](theIndexName)
| |
− | ::numEls = theIndexObj.[[CAIndex::IndexElements|IndexElements]]
| |
− | ::...
| |
− | ::For i = 1 To numEls
| |
− | :::theIndexElement = theIndexObj.[[CAIndex::GetValueByNumber|GetValueByNumber]](i)
| |
− | :::theTableElement = resultTable.[[CATable::GetDataByElements|GetDataByElements]](i)
| |
− | :::...
| |
− | ::Next i
| |
− | ::InformationPane.Text = outputString
| |
− | :End Sub</tt>
| |
− | | |
− | The lines of '''PrintResultTable''' that get an index of a table are as follows: <tt>
| |
− | :theIndexName = resultTable.[[CATable::IndexNames|IndexNames]](1)
| |
− | :theIndexObj = resultTable.[[CATable::GetIndexObject|GetIndexObject]](theIndexName)</tt>
| |
− | | |
− | We get the name of first index using the [[IndexNames]] function of [[CATable]]. We pass it into the [[GetIndexObject]] function of [[CATable]] to get a [[CAIndex]] object that represents our index. This automation object returns information about its corresponding index. If this function fails, it returns <tt>Nothing</tt>. In that case, use [[ErrorCode]] and [[ErrorText]] functions of [[CAEngine]] to find out why.
| |
− | | |
− | ==Getting information from CATable and CAIndex==
| |
− | [[PrintResultTable]] also shows how to get information from [[CATable]] and [[CAIndex]] objects. This code gets the index and table elements of the '''Cost''' table: <tt>
| |
− | :numEls = theIndexObj.[[CAIndex::IndexElements|IndexElements]]
| |
− | :For i = 1 To numEls
| |
− | ::theIndexElement = theIndexObj.[[CAIndex::GetValueByNumber|GetValueByNumber]](i)
| |
− | ::theTableElement = resultTable.[[CATable::GetDataByElements|GetDataByElements]](i)
| |
− | ::...
| |
− | :Next i </tt>
| |
− | | |
− | The [[IndexElements]] property of [[CAIndex]] returns the number of elements in the (first) index. The [[GetValueByNumber]] function of [[CAIndex]] gets individual index elements.
| |
− | | |
− | To get the individual table elements of the '''Cost''' table object, '''resultTable''', we use the [[GetDataByElements]] function of [[CATable]], passing in the coordinates of the element in the table.
| |
− | | |
− | When we retrieve an individual element of our [[CATable]] object ('''resultTable'''), we take advantage of the fact that the table is one-dimensional. Therefore, we only need to pass [[GetDataByElements]] a single number representing the position in our table. If we were dealing with two or more dimensions, however, we would need to pass [[GetDataByElements]] an array specifying the coordinates of the element of our table to retrieve. So, if we want to retrieve the element at position (4,3) of a two-dimensional table, we would write: <tt>
| |
− | :Dim W as Variant 'return element
| |
− | :Dim IndexPtrs(1 To 2) As Variant 'position in table
| |
− | ::...
| |
− | :IndexPtrs(1) = 4
| |
− | :IndexPtrs(2) = 3
| |
− | :W = resultTable.[[CATable::GetDataByElements|GetDataByElements]](IndexPtrs) </tt>
| |
− | | |
− | ===Controlling formats of atomic values===
| |
− | Each atomic value in a [[CATable]] can be a number, string, or one of a few other basic types (''e.g,''. [[Null]], [[Undefined]], [[Reference]], or [[Handle]]). These are returned as ''variants'', a data structure understood by Visual Basic, specifying the type and value. The [[RenderingStyle]] property of [[CATable]] controls how the underlying Analytica value is mapped to the Visual Basic variant.
| |
− | | |
− | For example, it can return a numeric value as a number, or a string using the Analytica model’s number format setting. If it is formatted, an option controls whether to truncate the number of digits or to return it with full precision.
| |
− | | |
− | In the [[PrintResultTable]] subroutine, located in <tt>frmMain.vb</tt>, the rendering style is explicitly specified:<tt>
| |
− | :resultTable.[[CATable::RenderingStyle|RenderingStyle]].[[CARenderingStyle::NumberAsText|NumberAsText]] = True
| |
− | :resultTable.[[CATable::RenderingStyle|RenderingStyle]].[[CARenderingStyle::FullPrecision|FullPrecision]] = False
| |
− | :resultTable.[[CATable::RenderingStyle|RenderingStyle]].[[CARenderingStyle::StringQuotes|StringQuotes]] = 2 </tt>
| |
− | | |
− | The first line specifies that numeric values should be formatted as text according to the number format associated with the result object. For example, in the program output, we see <tt>30.103M</tt> instead of <tt>30102995.6639812</tt>, which would likely be displayed if we had let Visual Basic concatenate the numeric value to our result string. In the event that a string-valued cell occurs in the result, it returns with explicit double quotes around the value. See [[CARenderingStyle]] for additional properties available through the [[CARenderingStyle]] object.
| |
− | | |
− | ===Other ways to access tables===
| |
− | There are several ways to access the elements of a multi-dimensional [[CATable]]. Some might be more convenient in certain scenarios than others.
| |
− | | |
− | The first way is to use the [[GetDataByElements]] or [[GetDataByLabels]] methods of [[CATable]], shown in the code example above. In this case, you supply the coordinates of the cell whose atomic value you wish to retrieve.
| |
− | | |
− | A second way is to use the [[CATable::Slice|Slice]] or [[CATable::Subscript|Subscript]] methods of [[CATable]] to obtain a new [[CATable]] object having one less dimension. By repeatedly reducing the dimensionality, you eventually reach zero dimensions, in which case you have a single atomic value. At that point, the [[AtomicValue]] method of [[CATable]] returns this value. The [[AtomicValue]] method is the only way to access a scalar value (since it doesn’t have a coordinate). You must use this method if you need to generate a graph image of a slice of the full result.
| |
− | | |
− | A third way is to use the [[GetSafeArray]] method of [[CATable]], to convert the multi-dimensional array into a ''safe array'' (or into a .NET array). You can then manipulate the multi-dimensional array directly in VB or other .NET language. Since there is no inherent ordering to Analytica dimensions, but safe arrays and .NET arrays have an explicit ordering, you must first use the [[SetIndexOrder]] of [[CATable]] to specify the ordering of dimensions before calling [[GetSafeArray]]. Note that this is not necessary if you know that your array is one-dimensional.
| |
− | | |
− | ===Modifying objects===
| |
− | A custom application often gets input from a user or other external source to transfer into input variables in the Analytica model. You can do this either by setting the definition of an input variable, or by using a definition table.
| |
− | | |
− | '''TestTxc''' shows how to modify the definition of '''Pop_exp''', which is a model input that effects the Cost result variable. To set the definition in the example, select '''File > Change Population''' Exposed from the main menu. A dialog appears, as shown in the figure below:
| |
− | | |
− | [[File:RedefiningtheVariableDefinition.jpg]]
| |
− | | |
− | | |
− | Enter a new definition into the field and click '''Ok'''. The main window displays the new value of Cost. The '''OkButton_Click''' function in <tt>ChangeDef.frm</tt> is called when the '''Ok''' button is clicked in the dialog. It modifies the definition of <tt>Pop_exp</tt>, and then calls the [[PrintAttributes]] function that prints the result of <tt>Cost</tt>.
| |
− | | |
− | The function looks like this: <tt>
| |
− | :Private Sub OkButton_Click(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles OkButton.Click
| |
− | ::Dim errorText As String
| |
− | ::Dim pop_exp_Object As [[CAObject]]
| |
− | ::Dim errorCode As Short
| |
− | ::Dim errorString As String
| |
− | ::newDefinition = PopExposedDef.Text
| |
− | ::pop_exp_Object = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]]("pop_exp")
| |
− | ::pop_exp_Object.[[CAObject::SetAttribute|SetAttribute]]("[[Definition]]", newDefinition)
| |
− | ::errorCode = adeEngine.[[CAEngine::ErrorCode|ErrorCode]]
| |
− | ::If errorCode <> 0 Then
| |
− | :::MsgBox("This error occurred while processing your definition: " & vbCrLf & vbCrLf & adeEngine.[[CAEngine::ErrorText|ErrorText]]) :::PopExposedDef.Focus()
| |
− | ::Else
| |
− | :::Me.Close()
| |
− | :::frmMain.DefInstance.PrintAttributes("Pop_exp", "Cost")
| |
− | ::End If
| |
− | ::ReleaseComObject(pop_exp_Object)
| |
− | :End Sub</tt>
| |
− | | |
− | This function grabs the new definition typed into the '''New Definition''' for '''Population Exposed''' field and sets it to the <tt>Pop_exp</tt> object by using the [[SetAttribute]] function of [[CAObject]] object. It then calls [[PrintAttributes]], which evaluates the <tt>Cost object</tt>, and prints the new table. To set a new definition for the <tt>pop_exp</tt> variable, we get the [[CAObject]] for <tt>Pop_exp</tt>, and set its definition to the definition typed in by the user. This is done with the following code:<tt>
| |
− | :pop_exp_Object = adeEngine.[[CAEngine::GetObjectByName|GetObjectByName]]("pop_exp")
| |
− | :pop_exp_Object.[[CAObject::SetAttribute|SetAttribute]]( "[[Definition]]", newDefinition )</tt>
| |
− | | |
− | Whenever you call [[SetAttribute]], you should check the [[ErrorCode]] of the [[CAEngine]] automation object ('''adeEngine'''), in case the definition is illegal. Try entering a new definition such as <code>[[Uniform]](25M,35M)</code> and click '''Ok'''. When the definition of <tt>pop_exp</tt> is changed, the result for <tt>Cost</tt> gets recomputed by ADE when '''ResultTable''' is next called for the Cost variable (when the application window is repainted).
| |
− | | |
− | ==Graphing with ADE==
| |
− | | |
− | Using the same graphing engine used by Analytica 4.6, you can generate a chart or graph to display an array-valued or uncertain result. In ADE 4.6, you can use the [[GraphToFile]] and [[GraphToStream]] methods of [[CATable]]. The graphs are returned in several possible image formats, such as '''image/png''', '''image/bmp''' or '''image/jpeg'''.
| |
− | | |
− | The easiest way to select from the available graphing options is to open your model with Analytica. You can experiment with the settings for the various defaults or override selected variables to see how they look. When you’ve chosen the settings you want, save the model. ADE then uses these settings when producing result graphs for each variable.
| |
− | | |
− | For higher-dimensional results, some work might be necessary to select the slice of the result that will be plotted and the specific pivot (i.e., which dimensions appear on the X-axis versus in the key). The [[CATable::Subscript|Subscript]] or [[CATable::Slice|Slice]] methods of [[CATable]] can be used to select the particular slice to be plotted and [[SetIndexOrder]] can be used to control the pivot. See [[CATable]] for details. In our <tt>Tutorial.NET</tt> example, we have a one-dimensional result (<tt>Cost</tt>), and do not need to worry about slicing or pivoting.
| |
− | | |
− | The [[GraphToStream]] method is used to transfer the graph image directly from ADE to a userinterface method. [[GraphToStream]] is a bit more complicated to use than [[GraphToFile]], since [[GraphToFile]] requires little more than a file name to write the image to. To use [[GraphToStream]], we must set up a stream in memory, allow ADE to write to that stream, and then reconstitute the image from that stream. Because .NET streams are not compatible with COM streams, you need to use the [[StreamConnector]] class provided with ADE. The '''GraphResult_Click''' routine in <tt>frmMain</tt> shows the use of [[GraphToStream]]. Select the '''Graph Result''' menu option from the main application window, and the results appear in a graph as shown in the graph below.
| |
− | | |
− | [[File:resultgraph.jpg]]
| |
− | | |
− | ==Conclusion==
| |
− | | |
− | In this tutorial, we introduced several important aspects of the Analytica Decision Engine. We saw how to create the ADE server object, open a model with ADE, get at an individual object in a model, evaluate objects, access elements in a table, and modify objects in a model. But, ADE can do a lot more!
| |
− | | |
− | We hope that you have learned enough about the basics so that you can now explore the more advanced features on your own. We recommend that you now read the rest of this guide to learn about what ADE can do.
| |
− | | |
− | ==See Also==
| |
− | | |
− | {| style="margin: 1em auto 1em auto;width: 100%;border:0;table-layout: fixed;" cellpadding=5
| |
− | |+ ADE User Guide Navigation
| |
− | |- style="text-align: center"
| |
− | | [[Installation of ADE]] << Previous || [[ADE User Guide]] || Next >> [[Using the Analytica Decision Engine Server]]
| |
− | |}
| |
Enable comment auto-refresher