在ADE中处理模型、模块和文件

This page is a translated version of the page Working with Models, Modules, and Files in ADE and the translation is 99% complete.
Outdated translations are marked like this.
Other languages:
English • ‎中文

ADE用户指南 >

这部分包含了一些你可能在Analytica模型中执行的常见操作和处理示例。

模型和模块

注意:在VBScript、VBA,和pre-dot-NET等Visual Basic版本语言环境中,在将一个对象赋值给一个变量的时候关键字Set是必须的。在VB.NET中关键字Set不在需要了。在下面的示例中没有使用关键字Set。

建立一个新模型:

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

CreateModel 方法仅需要一个参数,包含模型名称的一个字符串。

打开一个现有Analytica模型:

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

如果已经有一个模型打开,该模型将在新模型建立之前自动关闭。如果指定的文件名是不合法的,OpenModel将返回一个空的字符串。在此情况下,使用CAEngineErrorCode属性来确定错误的原因。注意即使载入成功,通常也会返回一条ErrorCode=2警告信息。关于导致错误或者警告信息的具体原因可使用CAEngineOutputBuffer属性来确定。在使用ADE时,你必须在路劲定界符中使用反斜杠(\)。ADE不支持斜杠(/)。

将文件中的模块添加到当前打开的模型中:

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

FileSpec 参数应该包含将被包括的模块的路径和文件名。Merge参数是一个布尔变量,确定先前已经存在的具有相同名称的对象是否被重写。如果Merge=True,那么冲突变量将被重写。如果Merge=False,并且存在冲突变量,那么表示调用AddModule失败。

读取脚本文件:

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

如果一个脚本文件包含一个typescript指令列表。根据载入的文件,引擎执行文件中包含的指令。当运行脚本文件在ErrorText属性中被描述时,将发生错误。

在一个单独的文件中保存模块(也就是当前模型的一个子集):

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

如果第一个参数是模块标识符,那么第二个参数将是文件名。

将当前模型保存到一个文件中:

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

关闭但不保存当前模型:

If ADE.CloseModel() Then … ’ Close succeeded

CloseModel方法不带任何参数。

ADE 对象

建立一个新的CAObject对象

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

将被建立的对象的名称和类型被传递给CreateObject方法。注意在给对象取名时,必须使用对象的标识符而非名称。大多数与对象相关的方法使用标识符属性,而非名称属性。ADE能够建立一下对象类型:一般变量、模块、机会变量、常量、决策变量、索引变量和决策变量等等。关于这些对象类型的更多信息请参考Analytica 用户指南

从模型中删除Analytica对象:

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

设置正在使用的模块

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

ADE使用层次结构给对象排序。当一个对象被建立时,该对象是在当前模块中被建立。默认情况下,所有对象都被置于顶层模块当中,除非你设置了CurrentModule属性。

识别当前模块:

Dim module As CAObject = ADE.CurrentModule

当你知道一个Analytica变量的名称时,获取CAObject 对象

这可能是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

方法CAEngine::GetCAEngine::GetObjectByName等同。

使用GetAttribute方法获取Analytica全部属性

UnitsOfVar = Var.GetAttribute ("Units")

使用SetAttribute 方法改变一个Analytica 对象的属性:

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

使用Name属性访问或者重命名对象的标识符

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


对象属性完整列表请参考Analytica 脚本指南

==检索计算结果== CAObject类型包含三种可以导致结果被计算并返回的方法。Result方法求取模型中的一个对象的值并返回一个单一值结果。如果你知道结果是一个单一数或者单一文本字符串,这非常有用。ResultTable方法求取模型中的一个对象的值并返回一个CATable对象结果。CATable对象的方法和属性让你理解有哪些维度存在,并访问单个元素(单元格)。Evaluate方法处理一个任意表达式并以一个多维CATable的形式返回解析和计算该表达式的结果。

在检索结果时,你控制使用哪种计算方式来计算结果。你可以计算确定性中间值,或者不同的概率视图:Mean(平均值)、Sample(样本)、 PDF(概率密度函数)、CDF(累积密度函数)、Statistics(统计数据)或者Bands(概率带)。将ResultType设置成你想要的结果类型(默认为Mid:中间值)。

不论你是在计算一个标量还是一个表格,你的程序最终获取单个基元值,比如说数字或者文本字符串。你可以使用各种CAObject::RenderingStyle设置来控制这些值被返回的形式。例如。数字值可以以浮点数、格式化字符串、或者完整字符串描述的形式返回。文本字符串返回时可带可不带引号。

计算并获取一个对象的简单结果(例如一个标量)

使用CAObjectResult方法:

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

默认情况下CAObjectResult属性检索对象的中间值结果。返回一个变体结果(或者在.NET中,返回一个System.Object结果)。该方法对于检索计算结果为标量的对象的结果非常方便。

计算并获取非中间值的对象结果

使用 CATable或者CAObjectResultType属性:

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

ResultType属性用来指明 Result应该返回的结果的类型。可能值为: 0=Mid point(中间值)、1=Mean(平均值)、2=Probabilistic Sample(概率样本)、3=PDF(概率密度函数)、4=CDF(累积密度函数)、5=Statistics(统计数据),以及6=Probability Bands(概率带)。当ResultType>=2,结果通常是一个表格,即使中间值和平均值为标量。关于检索表格结果的讨论请参考下一节。

检索格式化结果,设置对象的CAObject::RenderingStyle属性

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

在此示例中,通过使用对象的数字格式属性以格式化文本的形式返回数字。字符串返回带双引号。例如,如果数字格式为带尾部零、千分位和货币符号的固定小数点、两位有效数字的数值1.2K可能以字符串"$1,200.00"的形式返回。该数值以文本字符串的形式返回是因为:NumberAsText的属性设置为True。返回的该字符串为""$1,200.00"",结果字符串中有两个额外的双引号。该特性由StringQuotes属性(0 = 无引号、1 = '单引号'、2 = "双引号")控制。

检索多维结果

在描述如何获取表格对象(具有一个或者多个维度的数组)结果之前,让我们剪短地讨论一下Analytica中的表格概念模型。

一个Analytica表格包含以下几个部分:

  • 索引:每个索引标识表格的一个维度
  • 表格单元中的值
  • 索引标签:标识每个单元格的坐标

索引数量确定表格的维数。例如,如果一个表格包含两个索引,那么表示该表格是二维的。

索引中元素的数量确定表格中实际单元的数量。假设表格TIJ连个索引组成。如果I包含5个元素(AABBCCDDEE),J包含3个元素(ABC),那么T是一个5x3或者3x5的表格,由你的视图确定。

在使用ADE时确定一个表格的视图是非常重要的。由你决定告诉ADE你想如何查看表格。例如,在上面的段落中,如果你告诉ADE先使用索引I,再使用索引J,那么元素2,3由位置I=B, J=CC确定。然而,如果你先使用J,再使用索引I,那么元素2,3由位置I=C, J=BB(注意ADE中的表格是从1开始的1,也就是说,每一个维度从1到NN是索引的大小)确定。通过下面所描述的调用SetIndexOrder的方法,你可以设置表格中索引的顺序,这样你可以以任何你想要的方式查看表格。

在如何参考表格中单个元素方面,ADE方法是非常柔性的。你可以通过元素位置或者标它们的签名称来参考单个元素。例如,如果你告诉ADE给予你在位置2,1(沿着第一个索引的第2行或列,沿着第二个索引的第1行或列)上的元素,或者你可以告诉ADE给予你由‘BB’、’A’描述的元素,其中‘BB’和‘A’是它们在各自索引中的标签名。这些事物类型中经常用到这些方法的有如下描述的(GetDataByElementsGetDataByLabels)。

如前一部分讨论所示,ResultResultType用来计算并获取一个对象的结果。但是,对于计算结果为多维的对象,使用Result通常不方便,因为输出可能是一个如下形式的很长的以调号隔开的字符串:

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

这里,Index1IndexN是表格的索引,Value1ValueN是表格(逐行填充)中的值。因此,如果我们想通过使用 Result方法来获取表格中的某一个特定元素,我们必须解析由 Result返回的以逗号隔开的字符串,这样才能获得想要的元素。不幸地是,ADE提供了一个CATable 类型的ADE对象,包含了可以简化表格处理的方法。

作为表格计算并获取对象结果

使用 CAObjectResultType方法:

Dim Obj AsCAObject = 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

CAObjectResultTable方法返回CATable类型的一个自动化对象。CATable包含各种允许你设置、检索和处理单个表格元素的方法。很有可能,在检索完CATable对象后第一件事就是去设定结果表中索引的顺序。

解析和计算任意表达式

使用CAObjectEvaluate

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

如果要使用Evaluate,你必须先获得一个CAObject实例。虽然你计算的表达式可能和任何具体对象没关系,但是CAObject有几个用途。第一,对象的ResultType属性提供了一个位置指明你想计算的结果类型。第二,如果你想使用NumberAsText显示风格,和指示的对象存储的数字格式确定数字如何被格式化。但是,通常你使用的对象是不重要要的;你可能甚至使用顶层模型对象作为你的文本对象。

在比较前面的两个例子的同时也说明了通常有两种方式检测失败原因。如果在一种方法计算过程中国出错,那么ErrorCode属性为非零。并且对于任何方法,如果失败的话,返回值是Nothing或者False。

设定CATable对象的索引顺序

使用SetIndexOrder方法:

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

上面的代码假设我们正在处理一个二维表格。我们设定该表格的索引顺序,以便Index2为第一个索引,Index1为第二个索引。

在一些计算机语言中,一个数组的第一个元素被认为位置为0(从0开始),而另外一些语言中认为该位置为1(从1开始)。Analytica的Slice函数和ADE方法都认为数组第一个元素位置为1。早期的Visual Basic版本是从1开始的,但是目前的Visual Basic版本和其它现代编程语言从0开始。在上面的示例中,通过如下方式声明和使用Visual Basic数组:

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

在现代Visual Basic中,这些代码声明了一个位置从0到2这个范围内的数组——一个包含3个元素的数组。应为第一个元素没有被设置,它包含特殊值Empty。ADE可以识别要传递的数组到底是基于0(位置从0开始)还是基于1(位置从1开始)。因此,根据你的偏好,使用位置从0开始的版本同样一点问题没有,例如:

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

通过索引顺序检索表格中的元素

使用GetDataByElements 方法:

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

该代码使用GetDataByElements检索Index2=2, Index1=1位置上的元素并将结果存储到该Element(元素)中。

通过索引标签检索表格中的元素

使用 GetDataByLabels方法:

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

上面的代码使用了GetDataByLabels检索Index2="SomeLabelInIndex2",Index1="SomeLabelInIndex1"位置上的元素,并将结果存储到Element(元素)中。

控制由GetDataByLabels、GetDataByElements、AtomicValue,或者GetSafeArray方法获得的元素格式

设定CATable的RenderingStyle 属性:

Dim TableResult as CATable = Obj.ResultTable
Dim rs As CARenderingStyle = TableResult.CATable::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>

通过一次调用检索一个完整的Visual Basic或者.NET数组表格

使用GetSafeArray 方法:

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

上面的代码使用了GetSafeArray将整个表格存储到TheWholeTable中。由GetSafeArray 返回的与该表格关联的每一个维度的元素被从1N,其中N是维度的长度。通过在调用GetSafeArray之前使用该代码可以将安全数组的下届改成0:tt>

TableResult.CATable::RenderingStyle.SafeArrayLowerBound = 0

对于在C#中读取一个.NET数组中的一个多维结果的语法值得提一下:

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

确定表格的维数

使用NumDims属性:

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

获取与表格关联的索引名称

使用CATable::IndexNames方法:

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

IndexNames方法按照SetIndexOrder中指定的顺序返回表格中索引名称。如果对于CATableSetIndexOrder没有预先设置,那么将返回默认的索引顺序。

将CAIndex对象与你的表格关联

使用 CATableGetIndexObject方法:

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)

上面的示例检索了最后的CAIndex对象。CAIndex对象提供了属性和方法允许你获得关于单个索引的信息。

获取索引中元素的数量

使用IndexElements 属性:

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

获取索引中指定位置的索引标签

使用GetValueByNumber 方法:

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

获取一个索引中索引标签的位置

使用GetNumberByValue 方法:

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

在一个零维度数组中获取标量值

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

有时候,不可能提前知道一个对象的求值结果是返回一个多维结果还是一个标量。在此情况下,使用ResultTable。如果结果是一个标量,NumDims将返回0。在此情况下,所谓的“数组”其实根本不是一个数组,而是包含一个单一基元值。在调用CATable::Slice或者CATable::Subscript方法后,结果可能是一个零维度数组。要获取其基元值,使用CATable::AtomicValue方法即可。

SliceSubscript运算中减少维数

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

CATableSliceSubscript方法返回一个维数减1的新CATable对象。这些方法与Analytica内嵌的Slice和Subscript函数相似。Slice返回沿给定维度的第N个切片(通过位置)。Subscript返回与指定索引值相应的切片。

在表格中建立表格和设定值

我们可以将上面所描述的相同方法应用于definition tables(定义表格)以便从结果表中检索值。一个定义表格,顾名思义,就是当一个对象的定义是一个Table函数的时候(在Analytica中又称为编辑表)。

Analytica变量的值(通过ResultTable访问)可以是一个数组——不是因为它是由一个定义表格定义的,而只因为被定义为一个返回一个数组值的表达式或者函数。

在使用编辑表时,你需要注意你是将常规的表达式传递给每个表格单元,还是只是传递字符串。RenderingStyle.GeneralExpression属性确定你传送给表格的字符串值是如何被解译的。默认情况下,GeneralExpression=true ,表示如果你将一个单元值设定为字符串"Revenue",那么它实际上是由一个变量标识符而非文字字符串组成的表达式。如果你将文字常量植入到一个定义表格中(例如你有可能将一个输入表格放到你的模型中),你应该使用CATable::RenderingStyle.GeneralExpression=false,或者记得在文字字符串值上预先考虑添加引号。

一个被定义为定义表格的对象没有必要在ResultTable被调用时生成同样的表格。毕竟,定义表格可以定义为一个由标识符组成的数组。当ResultTable被调用时,每一个标识符的结果被求值,同时产生了一个新的表不同)。如果标识符求值为数组,那么结果表可能比定义表格拥有更多维度。

作为CATable获取对象的定义表格

使用CAObjectDefTable方法:

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

在检索到定义表格后,我们可以使用上面小节中描述过的所有相同方法 GetDataByElementsGetDataByLabelsSetIndexOrder等等,来检索表格中的元素,以及获取与表格中索引有关的信息。我们也可以使用我们上面使用过的确定对象结果是多维的还是标量的方法来确认对象的定义是表格还是标量:

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 ("定义")
If ADE.ErrorCode = 0 Then
’you have a scalar definition
Else
’an error occurred
End If
Else
’you have a table definition
End If

根据索引顺序设定表格中的元素

使用CATableSetDataByElements 方法:

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

该代码使用SetDataByElementsIndex2=2, Index1=1位置上的元素设定为Element。注意ABC引号的使用。这里,因为ABC是带单引号的,所以我们将字符串“ABC”放到表格中。如果我们反过来将Element设定为“ABC”,那么必须将表达式ABC置于表格中。在后一种情形中,ABC可能会是一个变量。如果标识符ABC在模型中不存在,那么在后一种情形中,当尝试设定元素时会发生错误。代码使用Update来更新带有新定义的模型。有一点需要注意:包含对象的模型直到Update被调用后才被更新。因此,如果Update没有被调用,并且依赖于此对象的节点的结果稍后才被计算的话,该对象的就定义将一直被使用。另一点需要注意的是:Update 函数对于结果表和定义表差别很大。对于结果表,Update 从指定对象再次检索结果。因此,对于通过使用SetDataByElementsSetDataByLabels做出的任何改变都将被重写。

根据索引标签设定表格中的元素

使用CATableSetDataByLabels 方法:

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

上面的代码使用SetDataByLabelsposition Index2="SomeLabelInIndex2", Index1="SomeLabelInIndex1"位置上的元素设定为Element。在此例当中,RenderingStyle.GeneralExpression属性被设定为False。这避免了需要像前面SetDataByElements示例一样需要明确包含引号。

通过一次调用设定整个表格

使用PutSafeArrayUpdate

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

从头开始建立一个完整表格

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

上面的代码建立了一个以IJ作为索引的定义表格。该表格的大小由I和J的大小决定。表格中的所有单元格初始值都被设成0。稍后用户可以调用DefTable,再通过使用SetIndexOrderSetDataByElementsSetDataByLabelsPutSafeArrayUpdate在表格中放入值。注意:CreateDefTable函数很少在ADE程序中使用。毕竟,和在ADE中相比,在Analytica 中建立一个对象要容易的多。

调整数值的返回状态

Analytica模型在属性或者表格或索引的单元格中可以包含几种不同的数值数据类型。数据类型包括浮点数、文本字符串、特殊值Undefined(未定义)Null(空值)、参考、映射到其他对象的句柄。当这些数据类型被返回并且最后描绘出你所使用的程序语言中的数据类型时,你可能想或者需要改变这些数值的返回状态。你可以使用RenderingStyle

CAObjectCATableCAIndex对象都包含调用RenderingStyle的属性,该属性返回一个CARenderingStyle对象。通过改变rendering style(显示风格)属性可以改变数值的返回状态。你也可以控制Analytica返回的安全数组的数据位置是从1开始还是从0开始。这些设置影响CAObject::GetAttributeCAObject::Result;它们同时也影响CATable::GetDataByElementsCATable::GetDataByLabelsCATable::AtomicValueCATable::GetSafeArrayCAIndex::GetValueByNumber

在将数值传递到 DefTable中的单元格中时,你也可以控制单元格是被植入文本字符串还是数值,或者是一般表达式。这由CARenderingStyleGeneralExpression属性控制。

CAEngineDefaultRenderingStyleDefaultDefTableRenderingStyle属性可以在CAEngine被实例化以后设定一次,以设定全局样式风格。例如,如果你总是使用位置从0开始的数组,这可以被指定一次。

检索风格被设定为数字的数字值

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

默认情况下,数字值作为数字返回,因此除非NumberAsText在某个点设定为True,要么没必要明确指明。

检索风格被设定为格式化字符串的数字值

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

Obj有关的数字格式被用于格式化数字值。对于此例,四位有效数字带后缀的风格返回“333.3K”。

检索风格设定为全精度字符串数字值

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继续使用与Obj有关的数字格式,但是有效数字被增加以避免精度损失。因此,后缀、指数、固定小数点、以及百分百格式不会被舍位。如果一个日期、整数,或者布尔格式被使用,有时仍然可能发生舍位的情况。在上面的示例中,返回值为:333.333333333333

检索不带引号的字符串结果

tab.RenderingStyle.StringQuotes= 0

检索带引号结果

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

对未定义值使用自定义

ADE.DefaultRenderingStyle.UndefValue = ""

默认状态下,特殊值未定义作为一个特殊Windows变体类型Empty返回。有一些脚本语言不能处理Empty数据类型,因此,如果你遇到此问题,你可能想改变该值。

将定义表格的单元设定为字符串值

defTab.RenderingStyle.GeneralExpression= False

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

在此例当中,指示的表格单元被设定成字符串值"A & B"。当该表格被求值时,此单元格的结果是一个包含"A & B"这5个字符的字符串。

将定义表格的单元格设定成表达式

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

这里单元格被设定成表达式"A & B"。当该表格被求值时,名称为A的变量和变量B被求值,他们的结果被强制转化为字符串,并使用&运算符连接。

你可以使用GeneralExpression=True将表格单元设定成文字串,但是你必须在表达式中明确嵌入引号。例如:

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

GeneralExpression默认设置为True。

终止进程内计算

CAObject::ResultTableCAObject::Result,和CAObject::Evaluate这些方法可能导致非常耗时间的计算,一致阻碍你的应用程序。有些模型可能花费很多分钟,甚至几个小时来计算结果。正常情况下,调用ResultTable时要等到结果完全被计算后才返回。 

你可能想给你的终端用户提供终止当前计算的能力,例如当按下一个"break:中断"键或者按钮。或者,当你的应用程序在冗余计算过程仍然在处理过程中突然被终止时,你可能想终止当前计算,以便ADE也终止。

如果要想有终止计算的能力,在你的应用程序当中你必须有某种形式的多线程。调用ADE的现场被占用,一直等待ADE返回,这样应用程序中的某一其它线程必须探测你要终止计算的请求。当探测到请求后,第二个线程通过一个全局系统事件对象让该请求向ADE通讯。在你开始冗余计算之前,你必须从ADE中获取用来定位该全局事件对象的信息。每一个CAEngine实例都有其自身的事件对象,并且有唯一的全局名称,但是在整个CAEngine实例时间内相同的事件对象应用于同一CAEngine实例。

获取事件对象(使用Windows Platform SDK调用):

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

在用来探测终止计算请求的单个线程中,下面的代码将该请求发送给ADE(使用Windows Platform SDK调用):

SetEvent(abortHandle)

注意:OpenEventSetEvent为Windows Platform SDK调用,不是ADE的一部分。同时也注意一下abortHandle变量必须是一个从两个线程都能访问的全局变量。然而,第二个线程不需要访问ADE对象本身。相反,abortEventName能够被共享,并且第二个线程能调用OpenEvent

当时间呗标记后,ADE退出当前计算,并从当前方法返回。当ADE从当前计算退出时,会感觉有一点延时。当它返回后,CAEngine.ErrorCode设定为78(“计算终止”)。你的应用程序继续使用同一ADE实例,因为它比被终止的调用有优先权。

使用CALicense实例化CAEngine

在开始使用ADE之前,第一件事你必须做的就是实例化一个CAEngine对象。你可以选择直接实例化你的CAEngine对象,或者也可以先实例化一个CALicense对象,在用他来实例化你的CAEngine对象。在你成功获取CAEngine对象时,与你使用这两种方法中哪一种没关系。不同之处在于:你使用了CALicense对象来实例化你的CAEngine对象,关于为失败的原因,更多信息可以参考。尤其是,当失败是由于注册码的问题,你的应用程序有机会妥善处理错误。

如果你正在建立一个打算分发给许多终端用户并基于ADE的应用程序,而这些用户没有ADE许可证,你必须和Lumina协商安排给ADE授权以便分发你的应用程序。该授权形式需要你的应用程序提供一个特殊类型的注册码给ADE,称为应用程序注册码,应为你的终端用户在其计算机上通常没有ADE注册码。注意:以这种形式重新发布ADE的授权不包含在标准的ADE授权协议中,需要支付额外的授权费用。要使用该应用程序注册码,你必须使用一个CALicense实例化你的CAEngine,应为你的应用程序使用CALicense对象提供注册码给Analytica。

使用CALicense实例化CAEngine的步骤如下: 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 );
}

如果你已经有一个应用程序注册码,在SetApplicationLicenseCode中插入以下调用:

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

使用Analytica图形引擎

当你获得一个最少包含一个维度的CATable 结果时,你可以以图像的方式获得该结果的图形。改用发之一就是将图形作为JPEG图像嵌入到在后端使用ADE的web页面中。

获得结果图形的步骤如下:

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

如果你能够在Analytica中不用切片器查看结果图形,那么步骤4和5就没有必要了。

将结果图形写入文件:

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

从一个ASP.NET web页面动态生成结果图形

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

在此示例代码中, ResponseRequestSession是动态服务器页面对象。用户浏览器中的HTTP包含一个类似如下的标签:

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

在Microsoft引入.NET时,他们没有在in .NET中制作与Windows中IStream兼容的基本Stream类型结构。因为这个原因,有必要在将.NET Stream传递给 GraphToStream之前,围绕.NET Stream建立一个执行IStream接口的stream wrapper( 流包装器)。该包装器,StreamConnector类型,包含在AdeTest示例中。要使用上面的示例,请将StreamConnector.vb文件添加到你的项目中.

另请参考

ADE用户指南导航
使用ADE服务器 << 上一页 在ADE中处理模型、模块和文件 下一页 >> ADE服务器类型参考
Comments


You are not allowed to post comments.