TransCAD有几个现成的流量延误函数(VDF)可供用户在交通分配时选择,其中包括Akcelic Flow Delay(HCM2000)、Bureau of PublicRoad (BPR)、Conical Congestion、Generalized Cost 、Logit Delay以及信号交叉口延误函数等多种常用函数。用户还可以自己创建流量延误函数的动态链接库,用来解决特别的交通分配问题。例如,在TransCAD的软件用户界面中,用户可以选择相应的延误函数,并可对不同的路段类型设置不同的参数。如果用户希望不同的路段类型使用不同的函数形式,这就可能需要定制VDF了。
1编译环境设置
必须用Microsoft Visual C的7.0版本以上编译 DLL,并采用__fastcall形式。编译好的DLL用.VDF的后缀名放在TransCAD安装目录下,调用交通分配程序时就可以看到用户自己定义的VDF。如果DLL编译不恰,或者缺少必要的函数,TransCAD会返回错误信息。TransCAD需要的一些常数,定义在VDFDLL.H文件里。这里我们用Visual Studio 2010版本为例。
1.1动态链接库项目创建
在Visual Studio 2010选择文件-新建项目,创建一个新的项目,选择Win32项目。在名称编辑栏输入UserVDF,在位置编辑栏输入“C:\Program Files\TransCAD 8.0\VDFDev”,如下图所示:
点击确认后,进入Win32应用程序向导。
这里我们假定你的TransCAD是安装在“C:\ProgramFiles\TransCAD 8.0”下面,而你自己的VDF工程要存储在它下面的VDFDev文件夹里面。
单击“下一步”,弹出程序设置对话框。
在应用程序类型单选列表选择DLL类型。在附件选项选择空项目。最后点击完成。Visual Studio在你指定的“C:\Program Files\TransCAD 8.0\VDFDev”下面的UserVDF文件夹里生成几个项目的文件。
原先在“C:\ProgramFiles\TransCAD 8.0\ GISDK\VDF”文件夹里,TransCAD已经安装了创建用户自己的VDF所需要的两个文件(VDFDLL.H和VDF_Preprocessor.c)和一个VDF的例子(bpr.c)。下面我们用bpr.c为例,解释如何为TransCAD编译你自己的VDF。
1.2加载VDF代码
TransCAD使用的动态链接库必须用Microsoft Visual C 7.0或以上的版本通过快速(__fastcall)调用协议(argument-callingconvention)进行编译。编译好的执行文件必须用后缀为.VDF的文件名存放在TransCAD程序目录下,以便TransCAD自动找到它。这些要求可以通过下列步骤实现:
(1)把原先在C:\ProgramFiles\TransCAD 8.0\ GISDK\VDF文档里,三个文件VDFDLL.H、VDF_Preprocessor.c和bpr.c,复制到“C:\Program Files\TransCAD 8.0\VDFDev\UserVDF”。
(2)在解决方案资源管理器树视窗口下面,在你刚刚生成的UserVDF项目节点单击鼠标右键,选择“添加—现有项”。
(3)将VDFDLL.H和bpr.c加入项目(VDF_Preprocessor.c不需要,它在bpr.c被包含了,resource.h是Visual Studio系统带的头文件)。
打开bpr.c,在第120行作如下改动:
shortDLLEXPORT VDF_GetLabel(char *label)
{
strncpy(label, "用户测试BPR函数", VDF_LABELSIZE);
return TC_OKAY;
}
这里我们只是把字串“Bureau of PublicRoads (BPR)”换成“用户测试BPR函数”。
你自己的VDF函数当然不只是函数的名称和TransCAD程序提供的这个例子中有所不同,你可以进一步修改这个例子,或从头编写你自己的VDF程序。基本的步骤和要实现的函数在TransCAD交通需求模型手册的有关章节中已经有具体描述。
1.3设置编译参数
(1)在解决方案资源管理器树视窗口下面,鼠标右键单击UserVDF节点,选择“属性”打开项目设置界面。注意,调试项目是采用Debug模式,正式的dll使用Release模式编译。你也可以在配置下拉菜单中选择“所有配置”设置所有模式的配置。
在配置属性页面的常规、输出目录编辑栏,输入TransCAD 8.0程序所在的文件夹,这可以是相对路径名“..\..\..”,因为工程文件夹比TransCAD8.0程序文档低三级(这里项目在UserVDF文件夹下面又创建了一个UserVDF文件夹,多了一层)。
(2)在调试页面的命令编辑栏输入TransCAD的执行文件“tcw.exe”所在的路径名(可以是相对目录..\..\..\ tcw.exe)。
作这项选择与创建VDF没有关系,但它可以让你在MicrosoftVisual Studio的IDE环境下进行你的VDF程序的纠错。
(3)单击C/C++下的高级页,在调用约定下拉菜单选择“__fastcall(/Gr)”。
(4)在链接器下面的常规页面的输出文件编辑栏,把输出的执行文件的后缀从.dll改成.vdf。
1.4编译和链接VDF
(1)编译。你定制VDF函数的程序写好以后,可以用VisualStudio的生成-生成解决方案命令,快捷键F7,或鼠标点击按钮来进行编译和连接。如果一切顺利,这将在TransCAD程序文档中创建一个UserVDF.vdf文件和同名但后缀为.lib和.pdb等等的文件。对TransCAD使用你的VDF而言,只需保存动态链接库函数UserVDF.vdf文件。有关其他文件和更多编译、连接和执行程序的选项,请参阅VisualStudio的用户手册。
(2)64位TransCAD版本的延误函数编译。TransCAD 6.0以上开发了64位版本。用vs2010打开之前dll项目,这时候项目的默认是32位的,点击生成菜单下面的“配置管理器”--“活动解决方案配置”选择debug或者release,“活动解决方案平台”下选择“新建”,在弹出的对话框“键入或选择新平台”下选择“x64”,直接点击“确定”。
(3)用定制的VDF进行TransCAD交通分配。打开TransCAD以后,点击File-OpenWorkspace打开C:\Users\用户名\Documents\Caliper\TransCAD 8.0\Tutorial文件夹下的Tutorial文档中的Workspace 文件“Traffic Assign.wrk”。TransCAD将打开一个地图、矩阵和相应的网络。选择TransCAD的Planning-Traffic Assignment对话框:
注意到你的VDF(用户测试BPR函数)已经出现Delay Function下拉菜单下的选项当中。
(4)调试VDF。用定制程序编译和链接无误以后,可以用Visual Studio的调试-启动调试命令或快捷键F5启动TransCAD。
在必要时,用Visual Studio你可以在自己程序的指定地点设置断点(Break Points)。程序执行到你的断点你可以检查输入变量的值,你的程序的流程和返回值。编制自己的VDF时,这样的查错功能往往是很重要的。
程序满意以后,你可以将其重新编译成优化的格式(Optimized)。这可以通过Visual Studio的生成菜单下面的“配置管理器”--“活动解决方案配置”命令来实现。在Configuration Manager对话框,把“活动解决方案配置”改成Release,并对你的VDF的Release版本重复前面“设置编译参数”和“编译和链接VDF”章节描述的步骤(如果所有配置中已经设置,则不需要),以便生成优化的VDF执行文件,使你定制的交通分配程序以最快的速度进行。
2 延误函数的程序编写
2.1基本要求
在TransCAD中可以创建自己的延误函数进行交通分配。VDF函数必须保证是凸的以保证交通分配的收敛性,满足以下条件:
•单独递增;
•连续可导;
•必须有过饱和状态的定义(一些路段的分配流量会大于通行能力)。
必须用Microsoft Visual C的7.0版本以上编译 DLL,并采用__fastcall形式。编译好的DLL用.VDF的后缀名放在TransCAD安装目录下,调用交通分配程序时就可以看到用户自己定义的VDF。如果DLL编译不恰,或者缺少必要的函数,TransCAD会返回错误信息。TransCAD需要的一些常数,定义在VDFDLL.H文件里。
2.2主要变量
自由流时间T0和通行能力CAPACITY必须为前2个输入变量。另外,后面6个变量必须为LENGTH, SPEED, Preload, Type,CURRENT和 N_FIELDS。分别表示路段长度,自由流速度,预加载,路段类型、当前拥挤成本,延误函数字段数目。其余变量可以添加在中间。下面是一个广义成本延误函数typedef声明的例子:
typedef enum field_
{
T0, | // Free flow travel time |
CAPACITY, | // Link Capacity |
ALPHA, | // BPR Alpha Parameter |
BETA, | // BPR Beta Parameter |
K, | // Constant |
OP_COST, | // Operating Cost |
VOT, | // Value of Time |
LENGTH, | // Link Length |
SPEED, | // Free flow Speed |
PRELOAD, | // Preload Volume |
TYPE, | // Link Type |
CURRENT, | // Updated Time |
N_FIELDS | // Number of Fields |
} FIELD;
VDF允许定义一些输入变量以及他们是否必要,或者是默认的参数值而与网络无关。例如,PRELOAD变量不是必须的,ALPHA和BETA参数的值可以默认设定。有些变量只是在特定条件下需要,譬如网络里面已经有自由流时间,LENGTH 和 SPEED变量就不需要了。变量的值可以设置上下限的值。TransCAD程序目录下的GISDK\VDF文件夹可以找到gc_vdf.c和VDF_Preprocessor.c代码文件。
初始化DLL必须做以下程序:
void InitVDFDLL(int *ptc_status)
要获得延误函数文字描述:
short _export VDF_GetLabel(char *label)
要获得参数的默认值,需要包含以下函数:
long | VDF_GetNParameters( void ) |
short | VDF_GetParameters(char **param_names) |
short | VDF_GetDefaults(double *d) |
路段传入4字节浮点矩阵数据。矩阵比参数的数目多2行,通过VDF_GetNParameters (n)函数返回。矩阵的列数和路段数相等。第一个参数是自由流时间,第二个为通行能力。最后n+2个为DLL计算的当前路段成本以及路段类型。
初始化DLL后,获取矩阵数据的参数信息需要初始化,通过pre-process函数实现:
short VDF_Preprocess(float **Cost, long*links, void *defaults, short *types, short *n_types)
这个函数即使在成本数组初始化的情况下,也需要调用,这是DLL获取路段数据以访问矩阵成本数据的地方。默认的数组要么是一维的默认值,或者二维默认值依赖于路段类型。
用户也可以设置延误函数的常数,用下面的回调函数获取常数项数目,修改常数项的值以及设置常数项:
long | VDF_GetNConstants() |
short | VDF_GetConstantNames*char **constant_names) |
short | VDF_GetConstants(double *c) |
short | VDF_SetConstants(double *c) |
成本回调函数为:
double | VDFValue(double *FlowVal, long *link, float **Cost, short *DisabledLinks) |
void | VDFValues(double *Flow, float **Cost, long *links, short *DisabledLinks) |
void | VDFTimeOnly(double *Flow, float **Cost, long *links, short *DisabledLinks) |
VDFTimeOnly()函数用来计算拥挤时间,计算的结果保存在交通分配结果表中的AB_Time和 BA_Time 字段。函数VDFValue()和VDFValues() 用来计算成本。VDFValue() 是一次计算一个路段,而 VDFValues()是一次计算所有路段。计算的结果保存在交通分配结果表中的AB_VDF 和 BA_VDF 字段。因此AB_VDF和BA_VDF 字段包含了所有的拥挤成本。
如果VDF用来OUE交通分配,需要增加两个函数:
double | VDF_Derivative(double *FlowVal, long *link, float **Cost, short *DisabledLinks) |
double | VDF_Integral(double *Flow, float **Cost, long *links, short *DisabledLinks) |
这个两个函数分别是VDFValue()的导数和积分。其他分配方法不需要这两个函数。
2.3BPR延误函数的例子
您有任何技术问题和软件购买需要,请联系我们:
客服微信号:YishuvInfo
微信公众号:TransCADTransModeler
邮箱:TransInfoTech@163.com