Top Banner
0 时序计算通用模型接口 OpenMI 开发技术及应用 第一章 第一章 第一章 第一章 OpenMI OpenMI OpenMI OpenMI应用概述 应用概述 应用概述 应用概述................................ ................................ ................................ ............................................. ............. ............. ............. 0 1.1 简要......................................................... 0 1.2 OpenMI 概述.................................................. 2 1.3 面向对象程序和 UML........................................... 7 1.4 连接模型 ................................................... 12 1.5 开发 OpenMI 系统 ............................................ 16 第二章 第二章 第二章 第二章 数据交换 数据交换 数据交换 数据交换 ................................ ................................ ................................ .................................................. .................. .................. .................. 22 22 22 22 2.1 运行时数据交换 ............................................. 22 2.2 描述交换数据 ............................................... 27 2.3 配置连接形成合成体 ......................................... 44 2.4 使用 OpenMI 配置编辑器 ...................................... 47 第三章 第三章 第三章 第三章 开发 开发 开发 开发OpenMI OpenMI OpenMI OpenMI系统 系统 系统 系统 ................................ ................................ ................................ ........................................... ........... ........... ........... 56 56 56 56 3.1 OpenMI 标准系统............................................. 56 3.2 建立 OpenMI 系统 ............................................ 58 3.3 纯代码系统 ................................................. 63 3.4 配置系统支持 ............................................... 67 3.5 图形用户接口 ............................................... 77 第四章 第四章 第四章 第四章 移植 移植 移植 移植OpenMI OpenMI OpenMI OpenMI模型 模型 模型 模型 ................................ ................................ ................................ ........................................... ........... ........... ........... 80 80 80 80 4.1 概要 ....................................................... 80 4.2 计划移植 ................................................... 82 4.3 打包 ....................................................... 85 4.4 一步一步操作移植 ........................................... 87 4.5 简单河流模型移植 ........................................... 96 4.6 测试组件 .................................................. 104 4.7 实现 IManageState 接口 ..................................... 106 4.8 OMI 文件................................................... 107 4.9 模型移植模式设计 .......................................... 108 4.10 完成移植的其它问题 ....................................... 114 第五章 第五章 第五章 第五章 非模型组件 非模型组件 非模型组件 非模型组件 ................................ ................................ ................................ ............................................... ............... ............... ............... 115 115 115 115 5.1 桌面及数据库应用软件 ...................................... 115 5.2 可视化 .................................................... 124 5.3 HarmonIT 定做的控件........................................ 125
143

时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

Apr 17, 2020

Download

Documents

dariahiddleston
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

0

时序计算通用模型接口 OpenMI

开发技术及应用

目目目目 录录录录

第一章第一章第一章第一章 OpenMI OpenMI OpenMI OpenMI 应用概述应用概述应用概述应用概述.................................................................................................................................................................................... 0000

1.1 简要.........................................................0

1.2 OpenMI 概述..................................................2

1.3 面向对象程序和 UML...........................................7

1.4 连接模型 ...................................................12

1.5 开发 OpenMI 系统 ............................................16

第二章第二章第二章第二章 数据交换数据交换数据交换数据交换 ........................................................................................................................................................................................................ 22222222

2.1 运行时数据交换 .............................................22

2.2 描述交换数据 ...............................................27

2.3 配置连接形成合成体 .........................................44

2.4 使用 OpenMI 配置编辑器 ......................................47

第三章第三章第三章第三章 开发开发开发开发 OpenMIOpenMIOpenMIOpenMI 系统系统系统系统 ............................................................................................................................................................................ 56565656

3.1 OpenMI 标准系统.............................................56

3.2 建立 OpenMI 系统 ............................................58

3.3 纯代码系统 .................................................63

3.4 配置系统支持 ...............................................67

3.5 图形用户接口 ...............................................77

第四章第四章第四章第四章 移植移植移植移植 OpenMIOpenMIOpenMIOpenMI 模型模型模型模型 ............................................................................................................................................................................ 80808080

4.1 概要 .......................................................80

4.2 计划移植 ...................................................82

4.3 打包 .......................................................85

4.4 一步一步操作移植 ...........................................87

4.5 简单河流模型移植 ...........................................96

4.6 测试组件 ..................................................104

4.7 实现 IManageState 接口 .....................................106

4.8 OMI 文件...................................................107

4.9 模型移植模式设计 ..........................................108

4.10 完成移植的其它问题 .......................................114

第五章第五章第五章第五章 非模型组件非模型组件非模型组件非模型组件 ............................................................................................................................................................................................ 115115115115

5.1 桌面及数据库应用软件 ......................................115

5.2 可视化 ....................................................124

5.3 HarmonIT 定做的控件........................................125

Page 2: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

0

第一章第一章第一章第一章 OpenMI 应用概述应用概述应用概述应用概述

1.1 简要简要简要简要

OpenMI 是一种接口标准,适用于以时间序列为基础的模型,它规定了模型运行时各模型之间交换数据所应遵循的的规范,并以数据接口形式加以确定。通过采用该标准,各模型可以并行运行,并共享每一时间步的信息,即:在模型运行时同时允许模型之间数据交换。这一关键技术使得模型可在操作层面实现集成,众所周知,模型集成有利于理解和预测交互处理过程,而且有效的集成方法是水管理系统成功建立的必备能力和方法。 任何遵循OpenMI标准要求的模型都能进行数据交换,任何已有的模型经过按照OpenMI标准修改后亦可以进行数据交换。 该指南为开发者和用户提供了编制 OpenMI 标准模型并对他们进行连接和运行相关信息,第一章对 OpenMI进行介绍,并对建立 OpenMI标准的模型及其移植过程作相应的介绍。 OpenMI环境包括许多用于模型转换的工具,可将现有的模型转换为 OpenMI连接组件,对于建立遵循 OpenMI标准的模型这些工具当然不是必需的,但它可以使得任务变得更简单些。 该部分内容介绍 OpenMI对象的一些细节、能用 OpenMI连接的模型及经过测试的例子,

OpenMI的术语将贯穿于该指南。

1.1.1对对对对 OpenMI的需求的需求的需求的需求 欧盟水框架指令要求集成水管理,并对整个模型构建过程实践加以指导,模型集成过程是集成管理开发中的关键内容,其面临的挑战是:当前不但是个体建模过程而且模型之间还要互相通信,将所有的处理过程作为单个模型构建显然不是一种好的选择,这种方式不能利用已有的模型,其维护方式也非常困难,不能提供灵活的维护机制。对整个模型处理的现实方法是使用模型集成技术,这种方法可以连接不同处理过程的模型,并能交互处理地进行模拟。 直到现在,还没建立一种基本的集成连接操作处理机制,然而,随着计算机技术发展,水框架指令提供了建立该机制的动力,并得到欧洲委员会资助和多位前任领导的支持,其基本项目是 HarmonIT,建立开放式模型接口及操作环境是该项目的组成部分,OpenMI 接口是 OpenMI组件运行数据交换的标准接口,OpenMI操作环境是一套软件工具,其功能包括构建新的模型,及对现有模型进行连接集成编译并运行测试。 从课题研究至应用操作任务,连接机制均是对单个模型集成处理的关键,如 OpenMI,在水框架指导的目标下它可以使得水管理功能有效实现。经过四年的研发、测试及修改工作,OpenMI处理方式已被广泛地接受,这点也可从多个国家共同参与的 OpenMI培训会确知,开发人员相信这种高质量的软件架构处理方式不久的将来会变成欧洲标准甚至全球标准,而这种方式的应用也不仅是在水管理领域。然而,采纳 OpenMI模式需模型开发者相互做出一定的承若,在 OpenMI被广泛的布置实施前或已经成为一种标准前,许多组织不太愿意作出承若,因而,OpenMI咨询组织的建立有利于用户交流,同时有利于 OpenMI的未来发展。

OpenMI 环境由一系列软件工具构成,这些工具用于开发新的模型,或对已有的模型处

Page 3: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

1

理,使其遵循 OpenMI标准,集成 OpenMI组件模型系统并运行调试。

OpenMI组件不受模型本身限制,接口也可用于多种数据交换,如数据库、TXT文本文件、GUIs、报表及可视辅助工具等。

1.1.2目标和对象目标和对象目标和对象目标和对象

OpenMI的目标是提供一种处理机制,使得半成品处理模型本身在运行时能够相互连接、共享数据源和功能模块,增强模型交互处理能力。 实现这种处理机制基本要求包括: ・ 能应用于新建的或现有的模型; ・ 尽可能的减少对模型开发者自由开发的限制; ・ 使得以时间序列为基础模拟技术得到更广泛的应用,当然不局限于该类模拟; ・ 能满足现有的应用程序代码在最小的更改情况下得到新的应用; ・ 保持价值性、技术性及时效性的延续,要求所移植模型最小化,而且这些因素不能遏止 OpenMI的应用; ・ 使用简单; ・ 不存在无理由的效率降低。

1.1.3各组织为什么要采用各组织为什么要采用各组织为什么要采用各组织为什么要采用 OpenMI呢呢呢呢???? 应用水框架指令(WFD)对于决策人员、流域管理者、灌溉机构、咨询单位、模型构建开发者等人员能带来哪些益处呢?对于这点,在讨论应用 OpenMI 的实践中已经得到几点共识: ・ 确保并增强现有模型开发投入效益发挥(如在 OpenMI编译中不需要完全重写代码); ・ 线性化的模型连接处理,有利于模型交互处理效率的提高; ・ 可用于标准模型组合及具有相同处理的不同模型之间交换,可帮助敏感分析及基础研究; ・ 缩短开发时间并因此提高决策支持系统价值; ・ 为模型用户增加选择,使得他们能在不同资源的交叉比较中确定所需; ・ 为模型开发者个体模型增加可卖性,因为他们可以顺利连接至已建立的系统,并提高相互的价值; ・ 为中小企业开发尤其是学术研究部门增加发展机会; ・ 因为能直接购买 OpenMI编译工具使得模型开发者可以集中精力对模型研究; ・ OpenMI环境工具可为模型连接、移植以及模型运行监视提供便利; ・ 相对于重写整个模型模块,利用 OpenMI技术改写部分模型其所用的代价非常少; ・ 使用模型用户可在自己构建的系统环境中运行第三方计算核心模型; ・ 不需要了解其他组织的模型内部 I/O过程; ・ 改变模型内部代码不影响模型之间的接口处理。

1.1.4 开发组织开发组织开发组织开发组织

OpenMI 是由 14 个组织和 7 个国家联合发起并通过欧洲委员会第五次框架计划资助的

Page 4: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

2

HamonIT 项目的一部分,由生态和水文中心牵头,成员包括内陆水管理与污水处理委员会(Inistitute for Inland Water Management and Waste Water Treatment RIZA)、DHI水环境所、WL Delft Hydraulics、HR Walling Group、Dortmund大学等。其设计和研发由三个主要模型开发公司承担,即 DHI水环境所、Deflt水力学所及 HR Wallingford。其他组织参与项目管理,并对设计和开发进行支持、对运行环境和标准进行测试。

1.2 OpenMI 概述概述概述概述 本结内容通过阐述 OpenMI接口功能及其测试过程来描述 OpenMI的主要必备条件。

1.2.1 基本要求基本要求基本要求基本要求 对于应用,OpenMI必须能连接在水框架指令下(Water Framework Directive)的相互作用模型,因而,对 OpenMI的基本要求有: ・ 连接不同领域(水文、水力学、生态、水质、经济等)和环境(大气圈、内陆水、海水、陆地、城市、乡村等)下的模型; ・ 基于不同的模型概念(确定性、随机性等)连接模型; ・ 对不同维数模型连接(0维、1维、2维、3维); ・ 连接不同尺度模型(从区域气候模型到集中径流模型); ・ 连接操作在不同时段方案模型(如:时、月甚至年); ・ 连接基于不同空间表达模型(如:网格、栅格、多边形); ・ 连接不同投影、单位、分类方式的模型; ・ 在不同数据源下连接模型(数据库、用户接口、操作工具等); ・ 在最小的工程量及不需要过高的 IT技术条件下连接新建的和已存在的模型; ・ 不削弱模型执行效率,尤其是对大模型; ・ 利用成熟的技术(其框架必须是基于组件及多层次结构); ・ 连接在不同平台的模型(如Windows、Unix、Linux); ・ 是开放的、公开的(接口规范说明应放在公共区域共享); ・ 允许组件开发至少可使用 C/C++、C#、Fortran、Delphi/Pascal、Java和 Visual Basic语言实现。 本节的以下内容介绍这些要求是如何实现的。

1.2.2 应用案例应用案例应用案例应用案例 为了检验这些要求是否正确表达及是否容易实现 OpenMI框架开发,在此采用案例或应用情景加以描述。以下列出了从全部的案例中选出的一些具体例子: ・ 连接两个一维水力学河流模型; ・ 对一个一维水力学模型和一个水质传输模型连接; ・ 连接一个一维河流模型和三维地下水模型; ・ 对一个一维水力学河流模型与植被环境模型连接; ・ 对一个三维海岸模型与一维河流模型连接; ・ 对一个基于多边形区域的二维模型与一个三维规则栅格地下水模型;

Page 5: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

3

・ 校正一个降雨径流模型连接至一个水力学排水(污水处理)模型; ・ 对不确定动植物链模型库连接; ・ 用不同的测量单位对模型数据交换; ・ 对代理模型(agent-based model)连接。

1.2.3 术语术语术语术语 对通用模型接口 OpenMI 标准进行描述需用到大量的术语,其基本术语包括,模型应用系统(model application)、用户接口(user interface)、引擎(engine)、模型(model)、引擎组件(engine component)、接收提供数据(accept and provide data)、连接组件(linkable

component)、合成体(Composition)、OpenMI标准(OpenMI compliant)、连接(link)、量值(quantities)、要素(elements),下面通过图例对部分术语说明。 如图,模型应用系统(model application)术语指的是安装于计算机的模型软件系统各部分总和,如Mike11、PHABSIM、InfoWorks-RS.

图 1-1模型应用基本结构 典型情况是系统包括用户接口和引擎。通常,引擎代表处理基本过程,是模拟计算或模型处理发生的地方。用户通过用户接口为引擎提供信息,这个过程包括用户、用户接口、计算引擎三个层次。 模型和引擎是需要区分的两个术语。模型是引擎的实例,在模拟处理过程,通过数据来描述所处理的特定情景,如莱茵河(Rhine)极端降雨期。用户通过用户接口选择或使用按钮命令启动引擎,引擎完成计算并输出结果至文件或进行显示。 当一个引擎完成其输入条件的读取就被认为是一个模型,如,一个用来计算明渠流的处理引擎,当它完成莱茵河网络边界条件及降雨数据的读取,那么就成为莱茵河情景模拟处理模型。 如果引擎代码可以独立分开并能通过接收和提供数据很好的定义接口,那么可将其作为引擎组件(引擎接口是对引擎输入输出数据处理的代码,不能和用户接口相混淆,用户接口是用户能看见的应用系统的一部分)。确保模型能成功交换数据的关键在于引擎接口标准的定义,可将其认为是连接组件,执行 OpenMI 接口的引擎称为遵循 OpenMI 标准

模型计算 所发生位置 读

计算引擎 输出文件

输入文件

用户接口

模型应用模型应用模型应用模型应用

运行

Page 6: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

4

(OpenMI-compliant)。

1.2.4 OpenMI标准接口标准接口标准接口标准接口

OpenMI定义的标准接口具有三方面功能: ・ 模型定义:允许其他连接组件找到这个模型模拟量值(quantities)交换的数据及模拟量所在的位置; ・ 配置:为了特定目标连接两个模型时可定义所交换的内容; ・ 运行时操作:使得模型在运行时能接收或提供数据。 下图 1-2中是遵循 OpenMI标准的两个模型应用系统,其整体结构保持不变,但每个引擎是采用 OpenMI接口的并能交换数据的组件

图 1-2植入 OpenMI标准后的两个模型应用系统 下图 1-3中描述了一些在两个模型之间进行信息交换时,接收或提供量的定义,箭头代表两个模型连接,在此是指降雨径流模型计算的径流作为河流演算模型的侧向入流,

获得值

用户接口 用户接口 数据输入 数据输入

数据输出 数据输出

降雨径流模型 河流演算模型

Page 7: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

5

图 1-3数据连接表示 图 1-4表示了河流模型与地下水模型的地理要素配置,河流模型是矢量模型,每个元素代表单一方向延伸,地下水模型以栅格网为基础,每个结点一要素。因而,为了连接这两个模型,河流模型的每个要素将与多个地下水模型要素关联。在通常计算场景中,一般需要配置成千上万个要素,而且该过程要求自动完成。在 OpenMI环境提供了工具用于模型之间数据连接和反连接,该工具是基于不同特定空间属性的,如向量、面积、网格等。

图 1-4 连接要素集

1.2.5 以以以以接口接口接口接口为为为为基础的开放标准基础的开放标准基础的开放标准基础的开放标准

OpenMI 提供一种智能处理机制,使得模型并行运行,且能逐时间步的交换数据,从而使得交互处理比串行连接更加准确,OpenMI不是普通的数据模型也不是集成模型系统,理解这点是重要的。

OpenMI是“以接口为基础”(interface-based),具有以下特点:

Page 8: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

6

・ 作为软件接口规范定义了相关的标准化内容; ・ 这接口是联系软件组件之间“协约”; ・ 这接口不限于特定技术平台或技术实施; ・ 通过执行这种接口组件就是遵循 OpenMI标准的组件。

OpenMI是“开放的”: ・ 该规范通过互联网公开(www.OpenMI.org); ・ 能在不同类型的模型、不同规则及不同领域之间连接; ・ 提供了完整的元数据结构用于描述数字数据,这些数据可以是语义术语、单位、尺度、空间、时段和操作数据; ・ 提供一种方式用于确切定义连接什么、怎样连接、什么时候连接; ・ 其默认采用的方式和软件使用是在开源许可下执行的。

OpenMI是一“标准”: ・ 它是标准化的数据传输处理; ・ 它允许任何模型与任何其他模型会话,而这种会话的实现是不需要模型开发者之间协作,也不需要集成人员与模型开发者之间的密切沟通; ・ 其基本特征是不限于在特定范围应用,水或环境领域均可使用。 当然,在 OpenMI量值连接计算时,通过尺度检查验证合法性,但 OpenMI不保证在组件内部处理或连接其他组件处理时是科学有效的,这需要模型开发者负责,模型集成及用户也应承担相应的责任。

Page 9: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

7

1.3 面向对象程序和面向对象程序和面向对象程序和面向对象程序和 UML 构建 OpenMI标准模型需要面向对象程序(OOP)知识为基础,熟悉对象和类之间的关系及继承规测等知识,统一构建模型语言(UML)知识也是必须。 这节对面向对象编程原理及 UML 进行解释,对于准备将现有的 Fortran 模型移植为OpenMI标准的 Fortran程序员会对这些信息更感兴趣。

1.3.1 面向对象程序面向对象程序面向对象程序面向对象程序 在开发模型时最常使用的是面向对象语言,如 C#、C++及 Java 等,这部分简要介绍面向对象程序中的主要术语。

1.3.1.1 对象对象对象对象 对象是面向对象技术基础,它代表现实生活中的实体。对象有状态和行为,一个对象主要状态通过变量来表示,行为则通过方法来实现(方法有多种称谓,如函数、过程、子程序等)。 考虑一个模拟现实世界自行车的例子,自行车的状态参量可表示为:车速、方向、踏板节奏、转动装置,你可能还想到了车的颜色、品牌等。一辆自行车还需要些方法用于表达它的行为,如应用方法实现刹车、改变踏板节奏或改变转动装置等。 因而,在程序开发中,对象是一串由变量和相关方法组成的软件代码。 典型情况是,在程序中方法包含并隐藏从其它对象来的对象状态,捆绑一个对象变量在它的方法保管下称为封装,在许多例子中对象可以显露一些变量或隐藏一些方法。 总之,面向对象程序主要益处在于以下两点: (1)模块化,对象源代码能独立于其它对象进行编写和修改,在系统中对象容易分发,好比把你的自行车给其它人,它同样能工作; (2)信息隐藏,一个对象有公共接口,其它对象能通过该接口交互通信,对象能修改私有信息和方法,任何时候修改均不会影响调用它的其它对象(你不需要明白在你自行车上使用的转动装置)。

1.3.1.2 类类类类 还是使用自行车例子说明,设想下在比赛中有多种类型的自行车,每辆都有自己的速度、方向等。在面向对象程序术语中,所有这些自行车对象是自行车类的实例。这些对象,不管有什么样的状态,虽然它们有相同的结构,但它们是相互独立、互相区别的,这种相同结构通常使用自行车类来表达。一个类是定义了变量和该类对象通用方法的原型。 类和对象之间细微差别经常使得它们容易被混淆,这些术语经常被交替错误使用,因而需抓住其中内涵。如在自行车例子中关键概念是,自行车类指的是通常的、总的概要描述,而不是实际存在的有指定速度、颜色等的自行车。

1.3.1.3 继承继承继承继承 大概 OOP 中最重要的特点是继承,继承允许类在其它类中定义。考虑一个山地车和比

Page 10: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

8

赛车的例子,它们都是自行车,并有自行车通常的特征,如能刹车、有速度等;同时它们又不同,山地车需要有暂停控制功能,而比赛车需要考虑空气动力学因素。 如果重写表示比赛车和山地车代码那将是件浪费时间的工作,OOP语言通过继承避免这项工作。山地车和比赛车都是自行车,它们各自继承自行车类,这使得它们能自动继承自行车的状态(变量)和行为(方法)。 不同的 OOP语言有不同的术语表示对象之间的关系,在 C#和 C++中山地自行车类是从自行车基类继承的衍生类,然而,这些术语也会被描述为子类、父类(亚类、超类)。 亚类也可重载继承的方法,并为这些方法提供特殊的执行方式,例如,你有一辆带额外转动装置的山地自行车,你想重装这些“改变转动装置”方法,以便骑车人能使用新的转动装置。这种情况在现实中经常出现,设想下有人已经开发了一个自行车类和使用自行车对象的方法库,你可以从自行车类继承并定义山地自行车类。虽然山地自行车的实例可能比简单的自行车需要更多的功能,但仍可以让山地自行车具有简单自行车功能,因为山地自行车是自行车,当“改变转动装置”方法在函数中被调用时,重写山地自行车的代码将被调用。

1.3.1.4 接口接口接口接口

OpenMI 标准都是通过接口定义来实现。前面说明了类是用于定义所代表对象的状态和行为,虽然对象经常要使用不同的术语进行通信,如,一个零售店存货清单程序,只要对象能提供关于价格的信息,对象程序不关心也不要关心其所包含的对象类别,它可提供类必须全面遵从的通信协议实现,在此是存货结算协议。通过一些包含于接口的方法进行定义这些协议,如“取价方法”,接口定义这些方法但不执行,对于执行这些方法那是类的工作。 总之,接口定义行为协议,它可被任何类及继承类执行,通常用于以下情形: ・ 没有人为干涉的类关系中,找到不相关类的相似处; ・ 申明为一个或多个类期待执行的方法; ・ 启动一个对象程序接口而不启动它的类。

1.3.2 UML 统一建模语言(Unified Modeling Language)是用于描述和设计软件系统的图形符号族,尤其在建立面向对象程序软件系统中更为有用,是由开放合作组织创建的开放标准,以统一面向对象程序图形模型语言形式于 1997年诞生的。

UML正式版给出了 13种图表描述,每一种都有自身的特点,在此仅给出两种图表描述,类图表和顺序过程图表,下面内容介绍这些图表主要属性,并以简单例子加以说明,这些代码是由 C#形式给出,但只要你对面向对象语言了解,如 Java、C++,就能很容易理解这些代码。

1.3.2.1 类图表类图表类图表类图表 类图表是最通用 UML图表,类图表描述系统中的对象类型及其内部多种变量静态关系,类图表也用于显示属性、类操作及对象连接方法约束。 考虑一下用于描述自行车的简单例子(C#)。

Page 11: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

9

图 1-5 UML图表表示的 SimpleBike类 对该例子使用 UML类图表可表示为如下形式,使用单线框表示类,但线框分为三部分,上面部分为类名,中间部分为属性,表示类的结构特点,属性格式表示为: 标记名称: 类型=默认值(visibility name : type=default) 标记表明是公共变量(public +)、私有变量(private -)、保护变量(protected #),变量名称的使用与具体所采用的编程语言相关,冒号后面紧接着数据类型,最后是该属性的默认值,使用等号(=)连接。 类型框的下面部分是类的操作(在 Java、C++/C#的术语为方法或函数),该操作描述的格式为: 标记名称(参数列表):返回类型 以上提到“标记”“名称”都是为属性定义用,返回类型表示了操作对象的返回值。参数列表为如下形式:

class SimpleBike { private float _speed; private float _direction; private int _gear; public void ChangeDirection(float degrees)

{ // Do stuff to change direction

} public void Break(float time) {

// Break for some time } public void Accelerate(float time) {

// Accelerate for some time } public void ChangeGear(int gear) {

// Change gear } public float GetSpeed() { return _speed; }

}

SimpleBike

_speed : float _direction : private _gear : int

+SimpleBike() +ChangeDirection(in +degrees : float) +Break(in time : float) +Accelerate(in time : float) +GetSpeed() : float

Page 12: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

10

方向名称:类型=默认值 “方向”指的是参数输入(in)、输出(out)或两者都具备(inout),如果没有指定方向,则假定为输入(in),在 UML类图中可能还可遇到其它几种语法修饰形式。

1.3.2.2 顺序连接图顺序连接图顺序连接图顺序连接图 在面向对象程序分析设计中,对象实例能在对象群中协作完成某些特定任务,不同类型的对象通过开发设计出的不同函数实现相应的功能,在 OOP术语中,对象通过发送消息进行交互,类图描述一个系统静态结构,而顺序连接图描述类之间随着时间顺序交换消息。 顺序图实例表示对象,而不是类,展示这些对象之间通过消息通信(方法调用、事件触发等),为了理解这些图表的作用和功能,需要对顺序连接图的符号和标志进行了解。 类角色类角色类角色类角色 类角色描述对象行为,类角色使用不带属性和方法的 UML对象符号表示(带下划线的对象名称和类型矩形框),每个对象下面都带破折号线,这线表示对象的作用时间,时间从对象位置线头至线的另一头结束,如下图。

图 1-6 类角色例子

激活激活激活激活 在对象作用时间线上的矩形框是指该对象具有控制焦点,这些矩形框称为激活框,表示该对象需要完成一具体任务,如下图

图 1-7激活框例子

消息消息消息消息 消息使用箭头线表示,代表对象之间通信,在图 1-8中共有 7种消息,在顺序连接图中描述的任何信息必须确保其他图中包括同样的对象类型,每一消息必须在类中有相应的操作。

Page 13: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

11

图 1-8 七种不同类型的消息

建立和终止建立和终止建立和终止建立和终止 在一个顺序连接图中,不是所有的对象都是一开始就建立的,在图 1-9的例子中有对象创建及为垃圾收集而释放的连接图。使用从创建者对象至创建的对象时间线的消息表示一个对象被创建,在对象时间线停止处标记×表示对象终止。

图 1-9 建立及终止对象

循环循环循环循环

Page 14: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

12

UML 为往复循环提供了标示方法,顺序连接图表中的一个循环描述为一个矩形框,循环条件通常使用[ ]置于作下角。 下面对一个 ATM处理的顺序图例子进行说明,假如一顾客要从 ATM机取钱,那么需要定义大量的类: ・ 客户控制台类:类对象代表一个 ATM 控制台,客户通过用户接口输入 PIN 进行交互操作; ・ ATM类:类对象表示 ATM控制者; ・ 会话类:每次客户使用的 ATM实例被创建,并为客户服务; ・ 读卡类:读卡对象仅读取客户卡; ・ 事务处理类:为了完成事务,事物实例必须创建和终止。 基于上述类的顺序连接图 1-10描述了对象之间是如何相互作用的。这顺序连接图仅表示了一件事务处理成功的情景,而实际上每种可能情景都应在顺序连接图中体现。

图 1-10 客户从 ATM取款操作顺序图

1.4 连接模型连接模型连接模型连接模型

OpenMI 标准定义了用于模型运行中数据交换的接口,只有参与的模型是遵循 OpenMI标准且要交换的数据一致相配时,这种交换才能发生,模型才能在运行时连接。 该部分内容讲述模型连接方法及对现有模型修改为遵循 OpenMI标准的操作,还将介绍数据在模型运行传输请求回应机制,并对数据交换处理的核心方法 GetValues进行介绍。

1.4.1 时间步内时间步内时间步内时间步内连接模型连接模型连接模型连接模型 计算模型经常被认为是输入数据转换为输出数据的软件实体,例如,降雨数据转换为径流数据,这点在 OpenMI也同样适用,即认为模型是数据接收和数据提供者实体。连接模型可认为是在两个模型引擎之间交换数据,需关心从模型输出数据到适合其他模型要求的输入

Page 15: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

13

数据的过程,这种“适合”包括数据格式和科学语义的适合。 目前许多模型是通过读写数据文件进行数据交换,这种过程在顺序连接的模型中经常被采用,即一个模型计算一个完整的时间系列,并将该系列输入下一模型。然而,为了能交互处理循环计算,模型必须在一个时间步基础上交换数据运行模拟,这种操作在顺序连接的模型是不可能实现的,虽然,在以时间系列计算的数据交换处理中,采用数据文件交换方法一直在使用,但在许多案例中导致执行效果不可承受。因而,在 OpenMI中选择了另一种解决方法。

OpenMI 以组件为基础,采用该方法可使得模型运行时直接交互访问,而不需要文件进行数据交换,这种方法以同样的的属性、方法、事件集成了模型、数据库、工具到组件。 在设计 OpenMI面临提供接口标准的挑战,该接口应满足在需求时允许模型交换数据。为了解决该问题,经过分析处理,连接和运行连接的模型可采用四步骤实现,如下所述: ・ 定义:定义可连接的组件和可交换的数据(接收或提供,接收模型只接收需要的量); ・ 配置:配置需要连接的组件并指定需要在组件交换的数据; ・ 分发:在目标计算系统内存运行创建已经植入模型数据的组件; ・ 执行:运行连接计算(即通过已连接模型模拟交互处理过程)。 为了保证这四步能执行,需要下面方法及功能进行支持: ・ 数据定义:为了用户能在模型之间建立连接,需要定义模型接受和提供的量,这种定义在程序和用户层必须是可供访问的,也必须包括足够的信息以便用户能采取科学有效连接并使得程序有效传递; ・ 基本模型通道:为了任何模型都能传递数据至其他模型,接口必须独立于模型或其概念建立在模型基础的上层,从而必须有通用基本接口用于连接所有可连接的组件; ・ 原数据:原数据是用于通知连接组件提供和接收的其他数据; ・ 数据交换定义:为了在模型之间建立连接需要对在两个连接组件传输的数据进行描述; ・ 故障修复:监视信息流并对问题识别及出错原因分析的工具。 开放模型接口及环境都是需求的,前面定义了 OpenMI做什么、是什么,也可用 OpenMI不是什么进行描述,它不是通用数据模型规范,在交互处理不包含抽象的科学知识,当然也不是集成模型系统,然而 OpenMI能用于建立集成系统。

1.4.2 请求回应机制请求回应机制请求回应机制请求回应机制 为 OpenMI选定的解决方法是请求响应机制,即模型“对请求响应”,因而,OpenMI标准采用后,模型需要转换为能响应不同问题的对象或组件,通过执行大量的关系方法和属性,使得组件可以连接。对现有模型,通过嵌入标准引擎代码实现;新模型或代码能直接作为方法接口组件开发。 通过请求响应机制连接组件可以交换数据,请求输入模型要求在一定位置或指定时间给出要素变量集,这些需要提供模型(数据提供者)给出,提供模型计算这些值并返回,这节详细解释这一机制。

1.4.2.1 牵引机制牵引机制牵引机制牵引机制

OpenMI 允许组件去“牵引”需要从其它经过连接的组件获取数据,这是一个非常简单的机制,只是两个组件通过单个连接完成。通过多个组件连接构成复杂相互连接组件集,每个在连接中,“牵引”数据的组件需要从连接的另一端获取数据,牵引竞争处理方法是为数据请求指定特定输入点。 经过交叉连接的数据是输出数据或提供模型的结果,并形成输入数据或接收模型的边界

Page 16: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

14

条件,“结果”可以是降雨、水位、底高、水质浓度、鱼群数量、植被或水价,值得一提的是采用同样的机制也可从数据库中提取数据,这将在后面进行更详细解释。

OpenMI能使得模型引擎计算和交换数据在自身的时间步完成,而不需要外部控制机制,通过禁止组件不停返回数据提供了防死锁处理,当一个模型被请求数据,需要说明如何提供给它,因为前一个方法模拟使得缓存中可能已经有模型数据,可能使得其自行模拟计算,导致一个最好的估算被篡改,或者不能提供请求的数据,在运行时交换数据是自动完成,由先前定义的连接驱动,而不需要人为干预。 一个重要特点是组件为了接收总要处理请求,计算顺序可能变的超过考虑的复杂性,这种方法必须稳定,而且它对开发人员是简单灵活的,包括专业和 IT技术,对于接收处理也具有自由特点,开发者对决定如何模拟处理在何处请求数据负责,认为数据提供者将能知道有效的数据要处理,代码开发者决定内插或外延获得请求值。 下图给出模型如何连接并用双向连接表示循环返回提供的例子。

图 1-11 采用牵引机制的不同链

1.4.2.2 其它特点其它特点其它特点其它特点 当然连接机制的其他特点也需要提及。 有些情形,组件不需调用计算,仅是起监视或可视化作用。此时,可使用“监听”机制,当新的变量生效时模型向信号发送事件,基于该信号基本工具用牵引机制重新等待数据,如图形开发包能用这特点更新图形。 在运行前组件之间连接需要创建(使用代码或配置),对于每个模型都需要知道模型输入请求是什么、输出什么,在配置过程中在模型专有部分定义连接,包括哪些数据通过连接交换及传输方向,配置连接信息是通过运行过程处理,当指定连接时需要人为干预,然而,有些工具是可有效支持该过程。

OpenMI 描述了源组件和目标组件两方面的连接,然而不同数量和变量名称在两方都能使用,数据维数定义为不容易产生歧义和矛盾的形式。

OpenMI标准模型能支持控制自身状态,OpenMI提供了模型请求保存状态方法并能返回所保存的状态,这特点使得反复和优化选择成为可能,下面给出的应用代码可支持这些特点,例外的情况是调用了不被支持的方法。

OpenMI 环境允许你在编辑时做连接集,可以将创建、修改、存储、处理和应用于情景分析。

A请求 B,B请求 C,C请求 D

D工作传递数据给 C,

C工作传递数据给 B,依次类推

A请求 B,B请求 C,C请求 D

B传递最可能值给客户 C,

C工作传递数据给 B,B工作传递数据给 A

Page 17: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

15

1.4.3 GetValues方法方法方法方法 运行时进行数据交换关键是使用 Getvalues方法,如图 1-12所示,当一个模型需要从另一个模型获取数据时,首先要调用 GetValues 方法,下面给出在不同模型状态下 GetValues方法应用,各例子显示了模型能被连接,并循环提供反馈。在连接模型运行中,一个模型被指定为开始运行的触发子,当计算达到数据请求点时,GetValues方法被用来请求数据-在图中为不同方向的连接链(Uni-directional Linear Chain)。

图 1-12 模型之间数据交换

可以看出,在计算过程中有几种状态,如果模型已经计算了被请求的数据,它将返回给请求的模型;如果没计算完,模型将在返回数据前一直计算,在计算过程中必要时从其它模型获得数据,然而模型可能因为等待数据而不能继续运行,如等待域中的指令,为了返回结果,模型必须外推。 当模型回应一个从请求模型来的数据请求时,将出现一个相似状态,如在回水计算时,为了计算河流出口出流量需要知道下游水位,然而下游水位是由上游来水决定的,在这种情况下需要用往复计算来解决,要求能够保存状态点,并能返回前一保存的状态,OpenMI标准模型能够完成往复计算。 另一个重要状态应提及是,即请求模型要求的数据在空间时间与请求模型中计算点不相配的状态,如,一个模型能按小时步长运行,而其他模型按天步长运行,这种情况下要求模型插值返回请求值,在任何情况下,返回值都要符合要求以便请求模型能顺利进行。 在返回值前,请求模型将使用任意要求的单位,它将使得从被请求模型元素到请求模型的数据相配,因为 GetValues方法总是处理接收到的请求,从而使得计算顺序不会变的混乱,如图 1-13显示了处理过程描述。

Page 18: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

16

图 1-13 使用 GetValues函数处理

1.5 开发开发开发开发 OpenMI 系统系统系统系统 为了使模型遵循 OpenMI标准,其引擎必须转为支持 OpenMI标准接口的组件,该部分内容介绍开发 OpenMI模型和对现有模型移植为 OpenMI标准模型的过程,这些内容将在第3章、第 4章详细介绍。

1.5.1 OpenMI标准概述标准概述标准概述标准概述 该节内容给出 OpenMI系统和 OMI文件介绍,该文件是用于存储 OpenMI组件信息。

1.5.1.1 OpenMI系统系统系统系统 一个 OpenMI系统是包括一个或多个 OpenMI标准组件的软件应用系统,通过标准接口该系统可以连接其它 OpenMI标准模型,为此,OpenMI系统必须具有以下信息和功能: ・ 系统必须知道在哪可以找到连接的组件; ・ 系统必须知道在连接的组件之间存在什么连接; ・ 系统必须能够实例化、分发并运行连接的组件。 一个可配置的 OpenMI系统是能在连接的组件中检查交换条目,如为模型连接提供拖放风格。

1.5.1.2 OMI文件文件文件文件 系统定义信息存储于 OpenMI组件的 OMI文件中,一个 OMI文件是包含需要实例化组件信息和输入数据的信息。 如图 1-14是一个 OMI文件简单例子,只需要知道存在 OMI文件,理解具体内容并不重

Page 19: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

17

图 1-14 一个 OMI文件简单例子

1.5.2 分发步骤分发步骤分发步骤分发步骤

OpenMI连接组件分发包括下列步骤: (1) 实例和初始化,应用系统读取 OMI文件构建连接组件,对组件输入数据; (2) 检查和配置,可交换条目检验,连接和其他对象创建并添加组件,组件和连接的状态是有效的; (3) 准备,这一阶段完成主要计算前的所有准备工作,例如,数据库和网络连接的建立,输出文件的打开、缓冲区的组织; (4) 计算处理,包括每一时间步处理循环,每步通过循环完成,包括所有需要的计算、与其它连接组件之间的数据交换; (5) 完工处理,这是在计算处理完成后的工作,有文件和网络连接关闭、内存清理等工作; (6) 布置分发,当应用系统关闭后进入该步骤,多余对象被删除,内存重新分配。

1.5.3 移植现有模型移植现有模型移植现有模型移植现有模型 该节内容介绍成为 OpenMI连接组件的现有模型必须是安全的有关准则,在移植过程中也有概要介绍。

1.5.3.1 成为连接组件的准则成为连接组件的准则成为连接组件的准则成为连接组件的准则 如前所述,OpenMI 定义了模型之间数据交换的接口。为此,原有引擎需要转为遵循OpenMI接口标准引擎组件,使得由组件完成的数量计算可被其它组件访问,引擎组件成为OpenMI标准连接组件。 一个相似模式能应用于数据库或其他数据源,通过将其转换为适合OpenMI接口的组件,该连接组件能在运行时提供直接访问的数据。 为了成为 OpenMI连接组件,一个模型必须符合下列准则: ・ 模型必须以初值从计算分开的方式构建,边界条件在计算阶段而不是在初始收集; ・ 模型必须能向外部模型提供数据; ・ 模型必须能在任何请求时间空间点提供模型要求的数据值;

<?XML version="1.0"?>

<LinkableComponent Type="wlDelft.OpenMI.WLLinkableComponent" Assembly="wlDelft.OpenMI,

Version=1.0.0.0, Culture=neutral, PublicKeyToken=8384b9b46466c568"

XMLns="http://openmi.org/LinkableComponent.xsd">

<Arguments>

<Argument Key="Model" ReadOnly="true" Value="RR" />

<Argument Key="Schematization" ReadOnly="true"

Value="D:\RainRRCF\Model\Cmtwork\sobek_3b.fnm" />

</Arguments>

</LinkableComponent>

Page 20: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

18

・ 模型必须能回应请求,甚至当组件本身是时间独立的时候。如果数据请求来自其他组件,组件必须能及时回应对自身的请求; ・ 模型运行时必须能通过外部实体交出控制。 当请求符合下列条件时,因为组件及时处理,请求“总是”能返回值: ・ 传递组件必须知道什么时间它将到达,必须知道是否为请求时间没有到达,在请求时间或通过请求时间,依靠模型和其内容,模型知道是否为外推计算请求时间或请求缓冲区; ・ 如果请求时间不在它们自身的时间步或空间内组件必须能内插; ・ 组件必须知道什么时间在等待数据,在那中情形它们将返回外延值。 最好的办法是让模型使用 OpenMI 标准,控件运行时推动数据交叉连接活动,OpenMI环境提供了优化的工具包,已经可完好地控制许多冗长的任务。

1.5.3.2 移植步骤移植步骤移植步骤移植步骤 在OpenMI环境(OpenMI Environment)中包含了对现有模型引擎简易完成转换为OpenMI连接组件的使用工具,虽然在转换过程中并不是必须使用这些工具,但它确实可使得任务变的简单。 在开始移植处理前,应该清楚模型的用途及怎样连接到其他 OpenMI组件,为此,需要为组件定义交换数据条目,输入数据需要哪些,要为其它模型输出哪些数据。 移植过程可通过七个步骤来描述: (1)改变引擎核心。模型引擎需要由 EXE文件转为 DLL,以便其它组件可以访问,如图 1-15;

图 1-15 转换引擎内核

(2)建立.NET汇编代码。安装 OpenMI环境后,对类包进行汇编并在.NET开发环境中测试(如图 1-16);

Page 21: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

19

图 1-16 Wrapper类 (3)访问引擎内核函数。引擎需要在.NET 下汇编,MyEngineDllAcesss 类完成所有在引擎核心代码的输出函数逐步转换为.NET公共方法; (4)MyEngineDotNetAccess工具。该类将调用协议转为 C#协议,将错误信息转为.NET表达式; (5)执行打包类。MyEngineWrapper类执行 IlinkableEngine接口; (6)执行连接组件。MyModelLinkableComponent类必须执行,该类定义的连接组件是可被其它模型访问; (7)执行其它 IEngine 方法。在 MyEngineWrapper 类的其他方法也必须执行,在许多情况下你可能需要对引擎核心改变,即对 IEngine方法增加代码。 这些步骤的详细描述和例子将在第四章给出。

1.5.4 OpenMI执行执行执行执行

OpenMI被作为接口定义为 org.OpenMI.Standard命名空间,允许任何人采用自己的方式执行 OpenMI,执行和使用这些接口的软件组件称为 OpenMI标准(OpenMI-compliant)组件。 然而,为了更容易使用 OpenMI标准,在.NET框架下可将 C#定义了默认语言环境,这些执行过程在 Lesser GPL协议条件下是开源的,在 OpenMI计划中,使用 Java建立的执行过程也将完成。 这些默认的执行过程称为 OpenMI环境,被封装为软件包,如图 1-17: ・ org.OpenMI.Backbone包提供了完成标准接口需求的最小集合类; ・ org.OpenMI.Utilities 命名空间提供了对遗产代码打包的支持,操作数据集、配置和分发组件; ・ org.OpenMI.DevelopmentSupport 命名空间包括含有 OpenMI 组件可对 XML文件分析的基本软件; ・ org.OpenMI.Tools命名空间包括与系统交互的前后处理工具。 然而,需要强调的是开发 OpenMI标准组件 OpenMI环境(OpenMI Environment)并不是必需的。

Page 22: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

20

图 1-17 OpenMI 框架命名空间

Page 23: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

21

Page 24: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

22

第二章第二章第二章第二章 数据交换数据交换数据交换数据交换

2.1 运行时数据交换运行时数据交换运行时数据交换运行时数据交换

GetValues函数是 OpenMI数据交换机制中的基本函数,这个函数允许两个连接组件之间进行数据交换。 该节讨论 GetValues 函数语法和连接两个 OpenMI 标准模型具体细节信息,分析定义数据交换位置的元素集角色,这种方法在双向连接也能被使用。

2.1.1 数据交换机制数据交换机制数据交换机制数据交换机制 对两个可连接的组件进行连接是个复杂过程,为了成功有效完成连接要求满足七个方面条件,数据交换操作触发子和信息交换处理是该过程的关键内容,由此形成的 OpenMI基本操作规则:“牵引机制”。 在每次数据传输操作中包含三部分:请求组件、提供组件及它们之间的连接。根据OpenMI 准则,当请求组件在必须从提供组件获得信息的工作点时,就得发出 GetValues 调用,提供组件将计算处理被请求的值并通过连接传递出去。

GetValues 函 数 定 义 在 IlinkableComponent 接 口 中 ( 如 图 2-1) , 即GetValues(time:Itime,linked:string):IvalueSet,语法简单而精确,可解释为“在请求处为请求时间步(或时间跨度)提供被请求值”。

图 2-1 OpenMI 连接组件接口定义

GetValues函数参数意义如下:

+ «property» ComponentID() : string

+ «property» ComponentDescription() : string

+ «property» ModelID() : string

+ «property» ModelDescription() : string

+ «property» InputExchangeItemCount() : int

+ «property» OutputExchangeItemCount() : int

+ «property» TimeHorizon() : ITimeSpan

+ «property» EarliestInputTime() : ITimeStamp

+ Initialize(properties :IArgument[]) : void

+ GetInputExchangeItem(inputExchangeItemIndex :int) : IInputExchangeItem

+ GetOutputExchangeItem(outputExchangeItemIndex :int) : IOutputExchangeItem

+ AddLink(link :ILink) : void

+ RemoveLink(linkID :string) : void

+ Validate() : string

+ Prepare() : void

+ GetValues(time :ITime, linkID :string) : IValueSet

+ Finish() : void

+ Dispose() : void

«interface»

ILinkableComponent

Page 25: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

23

・ 时间步或时间跨度(timestep or time span)被描述为时间参数。根据结构规范,它的数据类型是 Itime,该类型可使用改进的 Julian日期格式的时间游标或时间跨度(注:Julian日期格式共 5位,前 2位为年份,后 3位为天数),用开始时间和结束时间表示的时间跨度,也可使用改进的 Julian时间格式下表示; ・ 组件包含了所在位置和请求值的数量,它们蕴含在连接规范中(ILink); ・ 包含的组件有源组件和目标组件(SourceComponent、TargetComponent)。当数据值从源流到目标时,目标就请求到数据源; ・ 用于交换的数据包含连接的源数据和目标数据属性(SourceQuantity、TargetQuantity); ・值的位置通过连接的源要素集和目标要素集属性描述 (SourceElementSet、

TargetElementSet); ・ 返回值是 IvalueSet格式,该格式对于一个或多个标量、向量均是有效的。 显然 GetValues 函数语法是明了清楚的,需要的只是必需的参数,内部处理均隐藏在连接定义中。 在任意连接中提供组件都需考虑能为接收者提供所请求的数据,另外,为了区别组件,目标数据和目标属性集是必需的,连接对象也包含了源数据和源属性集,以保证最终用户能控制信息源,通过包含源信息,创建别名表映射语义,而不需要对变量名直接操作。 在通过 OpenMI.Standard.ILinkableComponent接口实类化实现 GetValues函数时,函数重载定义为:

Public override IValueSet GetValues(ITime time,string LinkID) 该函数在 ConfigurationEditor中通过运行(run)菜单启动,其启动流程如图 2-2,且只执行了 TriggerInvokeTime一个时间步。

public IValueSet GetValues(string QuantityID, string ElementSetID) { if (QuantityID == "Water Level") { return new ScalarSet(_groundWaterLevel); } else if (QuantityID == "Storage") { return new ScalarSet(_storage); } else { throw new Exception("failed to find output exchange item: " + QuantityID + "," + ElementSetID); } }

Page 26: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

24

图 2-2 在 ConfigurationEditor中通过运行(run)菜单启动流程 在 OpenMI.Sdk.Wrapper.LinkableRunEngine模块中定义的 GetValues函数,该函数按时间步执行了全部时段,每一步调用 MyName.RiverModelWrapper.EngineWrapper 模块的Getvalues函数(MyName.RiverModelWrapper.EngineWrapper类继承了 IEngine接口),并将结果存储于 UpdateBuffer内,其启动流程如图 2-3所示。

GetValues函数通过 OpenMI.Sdk.Wrapper.IEngine接口实类化实现时,函数重载定义为:

Public override IValueSet GetValues(string QuantityID,string ElementID),

RunBox模块

StartSimulation函数

_composition.Run()

CompositionManager模块

Run函数

_runThresd.Start()

CompositionManager模块

RunThreadFunction函数

_trigger.Run()

Trigger模块

Run函数

_link.SourceCompon

ent.GetValues()

MylinkComponent模块

GetValues函数

Page 27: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

25

图 2-3 在 ConfigurationEditor中启动Wrapper类对象流程

2.1.2 数据交换中要素集数据交换中要素集数据交换中要素集数据交换中要素集角色角色角色角色 要素集在两个模型模拟信息交换点承担重要角色,该节内容描述要素集定义的方法。 在 OpenMI概念中两个连接组件的连接不仅是信息的通道,更是两个准确定义的位置之间智能数据路径,这些位置使用 IElementSet接口描述,但是,每个要素集实际代表什么呢? 首先考虑要素集的物理意义,在现实生活问题中两个或更多物理实体之间相互作用通常不局限于单个点交换,而是延伸到交叉的多个位置,不同的作用方式(点、线、面),进行数量交换,例如,地下水模型可以提供对单个特定点地下水位(单个值),或特定多边形的平均值,因此,当对交互作用模型的提取定义,必须指定的不仅是所在位置而且包括类型和交互作用的其他属性。

OpenMI的 IElementSet目标是数据交换位置提供灵活的描述器,因而,一个要素集应是一个有序的要素集合,包括 ID号及描述文字。每个要素可以是没有任何地理属性的简单节点或者是点、线、多边形甚至是三维几何体,也还可以有空间意义。然而,一个要素集仅能包含同样类型的要素。 要素集不仅是用于描述复杂物理交互作用需要,而且为计算提供了有意义的优化:在调用 GetValues 方法时可以对大量交叉的多个位置同时进行,而不必每个单独完成。每个

RunBox模块

StartSimulation函数

_composition.Run()

CompositionManager模块

Run函数

_runThresd.Start()

CompositionManager模块

RunThreadFunction函数

_trigger.Run()

Trigger模块

Run函数

_link.SourceCompon

ent.GetValues()

LinkableRunEngine模块

GetValues函数

smartOutputLink.Update

Buffer()

SmartOutputLink模块

UpdateBuffer函数

This.Engine.GetValues()

MyName.RiverModelWra

pper.EngineWrapper模块

Getvalues函数

Page 28: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

26

ValueSet的来源是这样定义的:每个 ElementSet具有相应的 ValueSet,而且它们是被定义了与 ElementSet 相同的序号,使用这张一对一的映射图,从而使得访问大量的特定位置变的容易而有效。

2.1.3 双向连接双向连接双向连接双向连接 虽然 OpenMI连接是无方向的,但许多模拟要求双向数据交换,这节描述一些典型使用双向连接的例子,并简要讨论 OpenMI的处理方法。 在 OpenMI体系中两个连接组件的连接是作为源和目标组件之间无方向数据的通道,然而,在许多实例中两个连接的组件需要双向相互交换数据。

2.1.3.1 例例例例 1两个动态河流水流模型的连接两个动态河流水流模型的连接两个动态河流水流模型的连接两个动态河流水流模型的连接 河流水流模型用来模拟河水流动(水位和流量变化),通常是基于圣维南方程,开发这样的模型是项复杂任务,且需要为多个河流开发相应的模型。扩展使用单个模型用于完成流域大部分区域,通过连接不同区域模型实现,或许是种不错选择,使用 OpenMI可以实现这点。这种连接保持了区域模型单独使用的有效性,并且新的或引入区域模型能简单集成至大尺度模型中。 在单个区域模型中入流时间序列通常在上边界是必需的,即模型上游的入口,水位需要计算;在模型出流点水位时间序列通常是必需的(下边界)。如果两个模型被连接,上游模型的下边界水位时间序列需要下游模型计算,而下游模型的入流时间序列由上游模型计算得出,这就意味着上游模型需要水位值与下游模型需要入流值同时发生,如图 2-4。这种在同时间步内相互依赖现象需要双向连接。

图 2-4 两个河流演算模型之间连接

2.1.3.2 例例例例 2伴有植物生长模型的河流模型连接伴有植物生长模型的河流模型连接伴有植物生长模型的河流模型连接伴有植物生长模型的河流模型连接 动态河流模型的关键特点是河床糙率,即河床或漫滩阻力,糙率起决于植物生长,而植物生长情况又由流速和其它因素决定,连接这两类模型意味着在计算中的同一时间步水流模型需要糙率,而植物生长模型同时需要流速。 这种同一时间步相互依赖结果的需要双向连接。

Page 29: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

27

2.1.3.3 例例例例 3伴有堰坝控制模块伴有堰坝控制模块伴有堰坝控制模块伴有堰坝控制模块的河流模型连接的河流模型连接的河流模型连接的河流模型连接 动态河流模型常用于实时洪水预测,基于模型预测计算而采取相应的措施,如对堰削低或加高。控制模型从河流模型获取水位计算结果,河流模型需要堰的高度。如果数据使用是瞬时的,那么这又是一个需要双向连接的例子。 双向连接精确定义能用公式表示,即在同一个时间步两个组件彼此需要对方的输出来完成计算,为此而建立的连接。 很明显双向连接导致数据计算死锁,然而,OpenMI 架构提供解决方法:使用外推,连接中的一个组件能计算出被请求的数值,从而解除死锁。

2.2 描述交换数据描述交换数据描述交换数据描述交换数据 使用 GetValues 函数必须定义所要交换的数据,数据所在位置和时间周期,该部分内容给出这些参数的详细定义,该部分内容还将介绍 ExchangeItems概念,它是交换数据的纽带,定义了交换数据的位置。

2.2.1 应用实例介绍应用实例介绍应用实例介绍应用实例介绍 让我们基于通用的应用实例对这部分内容介绍(图 2-5)。区域降雨产流模型用于计算河流系统的侧向入流,降雨产流模型从监测数据库中获取雨量数据,河流模型计算水位及其变化过程,该章内容使用预报数据对例子进行了扩展,地下水模型与降雨径流模型和河流模型交互。

图 2-5 一个通用的例子

Page 30: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

28

2.2.2 描述内容描述内容描述内容描述内容 模型连接意味着数据交互在数据提供模型和接收模型对被交互的值具有相同理解。对不能理解的数据值交互是没有意义的,如图 2-6描述 OpenMI基本实体对值的意义通常表述方法。

图 2-6 值与语义关系

值本身是有标量或向量之分,其意义可用三轴来定义,即何值、何地、何时(What Where

When)。 ・ 值表示的什么,单位是什么,通过量和单位表示,一维数据可确保该值有效; ・ 这些值在什么地方通过 ElementSet类表示,它包括了有序要素集,每一要素通过节点序号定义,这些节点可以是具有坐标的地理位置; ・ 值应用的时间通过 Time表示,可以表示瞬时值(时间步)或者时间周期(时间跨度)。

2.2.3 对值对值对值对值意意意意定义定义定义定义 在模型世界里,大量的术语用于表达值的意义(what),典型的术语应用有变量或参数,当应用这些术语时可有不同的视角表达于其语义中,在 OpenMI 中选择使用数量(quantity)术语作为典型的数量值的表示(是否为一决定变量,一个输入变量,一个输入参数或输出变量)。一个扩展元数据结构用于定义能够完成并显示表达值代表意义,如图 2-7,作为 OpenMI允许科学有效语义相似数量的连接,而不需强迫使用标准数据词典,可以使用元数据结构的扩展。虽然个人设置的连接表达是需要的,但其它要素检查,如维数,也是必须的。

Page 31: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

29

图 2-7 OpenMI中量及元数据关系接口定义

量和单位的 ID值包含缩写名或对它理解描述,(单位具有量值,且作为其他度量的基础,毫米是一个单位,米是个不同的单位,因为它们有不同的量级),更多的关于数量和单位解释由描述属性说明。 目前,OpenMI支持两种数量类型:标量(表示为双精度)和矢量(表示为 X,Y,Z单元)。 在模型之间数据交换通常需要进行单位转换,当不需要一直强制单位转换时,OpenMI方法中提供了单位转换选择,单位对象包含了足够表达数量之间转换需要的信息,如给定一定数量的 V值,需转换为 SI值(SI为国际单位制简称),可使用以下公式计算。

s = Unit.GetConversionFactorToSI() × v + Unit.GetOffsetToSI() 为了量之间(物理)维数检查,明确的维数定义是需要的,(一维描述的测量数据类型不需要特别申明,如厘米和米都是长度单位),区别于 SI系统,一维数据作为基本量进行表达,为通用单位的次要扩展。 接口提供了获得每个基本量的方法,而且还要检查两个维数是否相等。如出流单位是m

3/s,有方向,即长度维为 3,时间维为-1;表 2-1描述了基本数量和 SI单位的相关信息。 有些单位是没有方向维,表示逻辑尺度或表达为 SI 系统单位有困难,为此,需要特别注意这些单位的描述,可以表示为“0”维值。 表 2-1 OpenMI中基本单位类型 量的名称量的名称量的名称量的名称 单位单位单位单位名称名称名称名称 单位单位单位单位符号符号符号符号 长度(Length) 米(metre) m 质量(Mass) 千克(kilogram) kg

«interface»

IQuantity

+ «property» ID() : string

+ «property» Description() : string

+ «property» ValueType() : ValueType

+ «property» Dimension() : IDimension

+ «property» Unit() : IUnit

«enumeration»

DimensionBase

«interface»

IUnit

+ «property» ID() : string

+ «property» Description() : string

+ «property» ConversionFactorToSI() : double

+ «property» OffSetToSI() : double

«interface»

IDimension

+ Length: int = 0

+ Mass: int = 1

+ Time: int = 2

+ ElectricCurrent: int = 3

+ Temperature: int = 4

+ AmountOfSubstance: int = 5

+ LuminousIntensity: int = 6

+ Currency: int = 7

+ NUM_BASE_DIMENSIONS: int

+ Equals(otherDimension :IDimension) : bool

+ GetPower(baseQuantity :DimensionBase) : int

+ Scalar: int = 1

+ Vector: int = 2

«enumeration»

ValueType

Page 32: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

30

时间(Time) 秒(second) s 电流(ElectricCurrent) 安培(ampere) A 热力学温度(Temperature) 开尔文(Kelvin) K 物质的量(AmountOfSubstance) 摩尔(mole) mol 发光强度(Luminousintensity) 坎德拉(candela) cd 货币(Currency) 欧元(Euro) E

图 2-8提供了怎样使用类描述不同量的例子。

图 2-8 对一个实例量的描述

2.2.4 定义值的应用位置定义值的应用位置定义值的应用位置定义值的应用位置 为理解正负值如何直接转换应用,这部分内容解释怎样定义值的应用位置(where),并介绍 ElementSet概念。

2.2.4.1 OpenMI ElementSets-要素集要素集要素集要素集 理解值的应用位置对连接的使用是极为重要的,模型具有自身的空间表达,有些模型不是一直占有空间的,其他的应用不释放计算单元,而主要可合并应用是通过空间地理来表达的,如网络、标准网格、非结构网格。一个结构化网格可使用 2D或 3D表示,它矩阵的每个要素总能通过自身的(i,j)位置决定相邻要素的位置,一个非结构化网格要素在矩阵中则不具有(i,j)位置。如上表中的拓扑信息可以检索相邻要素。 在模型计算中不使用固定数据结构对通用空间表达,更多可选方法应用用于计算大量数据交换,如模型边界或全地理要素。

Page 33: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

31

模型采用的一系列计算单元,成为要素集,作为一个开始点。在一个要素集中,所有的个别要素都需要相同的类型,如定义的 ID 基类、XYPiont、XYLine(线段)、XYPolyLine、XYPolygon、XYZPoint、XYZLine、XYZPolyLine、XYZPolygon、XYZPolyhedron。ID基类要素可没有地理引用,而基于GIS类型要素类型是地理引用,它需要空间引用系统坐标。(GIS类型要素可向其他要素集一样有 ID值) 表 2-2 描述包括坐标要素的有序要素转换的细节。 XY-ElenmentTypes 是XYZ-ElementTypes 简化。 表 2-2 OpenMI中要素类型列表 要素类型要素类型要素类型要素类型 一般解释一般解释一般解释一般解释

IDBased 基本ID (字符串形式)

XYPoint 水平面上的地理引用点(XY)

XYLine 地理引用中水平面上的两个顶点的连接线段(由起点和终点决定方向)

XYPolyLine 地理引用中至少连接水平面上两个顶点,且不封闭的线段(起点和终点不是同一个点,且表示出方向)

XYPolygon 地理引用中水平面上的封闭多边形,逆时针定义顶点顺序(起点和终点为同一个点)

XYZPoint 地理引用中三维空间点(XYZ)

XYZLine 地理引用中连接三维空间两个点的线段(起点和终点决定方向)

XYZPolyLine 地理引用中至少连接三维空间两个点不封闭线段(起点和终点不是同一个点,且表示出方向)

XYZPolygon 地理引用中三维空间的多边形,逆时针定义顶点顺序(起点和终点为同一个点)

XYZPolyhedron 地理引用中三维空间多面体(任一面都是封闭的),每一面的顶点均采用逆时针定义

OpenMI接口相关的更多附加接口如图 2-9所示,IElementSet可用于检索模型系统的地理描述,且一个执行不需要提供所有的拓扑交叉连接信息,因而,你不能假定 IElementSet接口能够在默认情况完成模型网格继承。

Page 34: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

32

图 2-9 OpenMI接口要素集定义

2.2.4.2 使用不同的要素类型使用不同的要素类型使用不同的要素类型使用不同的要素类型 相同类型的要素可绑定在要素集中(Elementset),当网格通过 XYPolygon要素表达时网络可定义为 XYLine或 XYPolyLine要素集合,一个含有网格网络水力图表最少有两个要素集(即一个网络和一个网格),一个非地理引用模型能作为 ID基类要素来表达。 图 2-10说明了不同要素类型在空间表达中能用于提供信息,包括河流与内部属性。

«interface»

IElementSet

+ «property» ID() : string

+ «property» Description() : string

+ «property» SpatialReference() : ISpatialReference

+ «property» ElementType() : ElementType

+ «property» ElementCount() : int

+ «property» Version() : int

+ GetElementIndex(elementID :string) : int

+ GetElementID(elementIndex :int) : string

+ GetVertexCount(elementIndex :int) : int

+ GetFaceCount(elementIndex :int) : int

+ GetFaceVertexIndices(elementIndex :int, faceIndex :int) : int[]

+ GetXCoordinate(elementIndex :int, vertexIndex :int) : double

+ GetYCoordinate(elementIndex :int, vertexIndex :int) : double

+ GetZCoordinate(elementIndex :int, vertexIndex :int) : double

«enumeration»

ElementType

+ IDBased: int = 0

+ XYPoint: int = 1

+ XYLine: int = 2

+ XYPolyLine: int = 3

+ XYPolygon: int = 4

+ XYZPoint: int = 5

+ XYZLine: int = 6

+ XYZPolyLine: int = 7

+ XYZPolygon: int = 8

+ XYZPolyhedron: int = 9

«interface»

ISpatialReference

+ «property» ID() : string

Page 35: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

33

图 2-10 要素集变量类型

降雨径流模型的子区域通过三个 XYPolygon 要素的要素集表达,即 C1、C2和 C3。从两个 XYPoint 要素的要素集产生的区域出流,即 O1 和 O2,虽然连接不是必须的,区域的支流(T1、T2、T3 和 T4)通过 XYLine 类型要素表达,河流模型中仅有一个 XYPolyLine要素。 图 2-11和图 2-12描述了这些属性要素,在图 2-11中精确的坐标(x,y)通过节点坐标表述。图 2-12使用另一种方法描述了 XYPolygon内部结构。

Page 36: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

34

图 2-11 要素属性图示(例 1)

图 2-12 要素属性图示(例 2)

Page 37: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

35

规则网格将用于其他内部信息表达(如行数、列数,单元格的 x 和 y 方向),通过使用可执行接口定义,OpenMI让开发者自己选择智能存储和管理方法。

2.2.4.3 选择要素类型选择要素类型选择要素类型选择要素类型(ElementType) 选择什么要素类型与模型连接方法有很大关系,代码开发者和模型开发者需要决定怎样表达数据及如何提供要素。 可由下列因素来做出决定: ・ 你提供 ID基类要素(非地理引用信息)或地理引用要素集吗(空间地图方法)? ・ 地理引用要素集是否包括拓扑信息(XYLine/XYPolyLine/Polygon)或没有拓扑信息(用XYPoint)?

对要素类型一个更重要表达关系是量表达的地方和怎样说明正值和负值。 为解析这点可通过区分具有流向量(如出流)和没有流向的量(如水位)说明。 总之,值在从源组件进入目标组件是正向。 ・ 通过平面或多边形的流向,可应用“右手法则”,如图 2-13a,(按平面或多边形节点序号握着右手,大拇指的方向为正向); ・ 沿着线或折线的方向定义为从起始点到终止点为正向;如图 2-13b。 ・ 右手法则应用于线或折线垂直流向(如图 2-13c为垂直平面,图 2-13d为水平平面)。(沿线正方向垂直伸平手,向胸部旋转,大拇指将正向垂直指向线或折线); ・ 对于立体,流向为离开源到目标为正向; ・ 远离地球中心为高度的正向(如图 2-13e),指向球心的深度方向为正(如图 2-13f)。

图 2-13 流量、水准(水位)、深度正向值的定义

2.2.4.4 动态要素集动态要素集动态要素集动态要素集 一般情况一个模型整个计算周期都是静态的已知网格,然而先进的模型可使用自适应网格,如波浪模型有自适应的垂直方向,岸垮堤模型河道网格与岸的外形适应。

Page 38: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

36

为了处理这些先进特点,在 IElementSet 接口中介绍了版本数据。源组件(SourceComponents),用于处理这种自适应要素集,能用这属性确定是否它们的目标要素集(TargetElementSet)改变了时间,如果是,源组件必须重新引用该要素集,并更新自己数据地图。

2.2.5 使用数据操作使用数据操作使用数据操作使用数据操作实现实现实现实现数据数据数据数据映射映射映射映射

OpenMI提供了描述有效数据操作方法,以下为数据操作接口及数据操作定义。 在许多情形下,数据交换需要映射源组件现有数据至目标组件请求的格式,数据交换可通过通知空间形式、时间形式或其他形式实现,数据信息由提供数据的组件确定(如源组件),每个组件开发者采用的实现方法可以不同,例如,一个组件可提供优先插值处理法,而另一个可能仅提供邻近有效插值法,第三个组件可能两种方法都提供(甚至更多)。 一个或更多参数可用于数据操作指定准确设置,图 2-14介绍了这种概念,在配制中,一个值被指定为特定数据操作设置参数。

图 2-14 数据操作和关联参数定义 为说明操作设置方法,大量蕴含数据操作的描述在表 2-3(时间形式)、表 2-4(空间形式)、表 2-5(混合形式)中,这些表反映的仅是一种描述数据操作方法,而并不是仅有的方法。 表 2-3 时间形式实时数据操作 数据操作 变量参数

ID Arg.Count Key Description Value Read

Only

NoDataOperation

0 Null

ProvideException 0 Null

ProvideAllValues 0 Null

TimeSpanAggregationbyAveraging 0

TimeSpanAggregationbyAccumulation 0

TemporalMappingByTakeNearest 0

«interface»

IDataOperation

+ «property» ID() : string

+ «property» ArgumentCount() : int

+ GetArgument(argumentIndex :int) : IArgument

+ IsValid(inputExchangeItem :IInputExchangeItem, outputExchangeItem :IOutputExchangeItem, SelectedDataOperations :IDataOperation[ ]) : bool

«interface»

IArgument

+ «property» Key() : string

+ «property» Value() : string

+ «property» ReadOnly() : bool

+ «property» Description() : string

Page 39: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

37

TemporalMappingByBeginValue 0

TemporalMappingByEndValue 0

TemporalMappingByLinearInterpolation 0

TemporalCompletionByMissingValue 1 MissingValue Define

TemporalCompletionByLinear

Extrapolation

2 Multiplier missing

value

Offset Define

offset

TemporalCompletionByExtrapolateWith

LastGradient

0

表 2-4 空间数据操作 数据操作 变量参数

ID Arg.Count Key Description Value Read

Only

NoDataOperation 0

ProvideException 0

ProvideAllValues 0

SpatialAggregationbyAccumulation 0

SpatialAggregationbyAveraging 0

SpatialMappingByKriging 0

SpatialMappingByInterpolation 0

SpatialMapppingByInverseDistance 0

SpatialMappingByTakeNearest 0

SpatialCompletionByMissingValue 1 MissingValue Define

numerical

missing

value

SpatialCompletionByLinear

Extrapolation

2 Multiplier

Offset

UseDefinedSpatialMappingMatrix 1 File name Reference

to

mapping

matrix

表 2-5 多情势数据操作 数据操作 变量参数

ID Arg.Count ID Arg.Count ID Arg.Count

ApplyVerticalShift 1 VerticalShift Define numerical value

(negative is towards

earth centre)

Page 40: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

38

从这些定义的名称可看出,数据操作可包括了数据集结、数据交换/映射或数据完结处理,不是所有的数据操作都可彼此相连,一些数据操作可转换为一定的单位和维度数据,如时间集合可影响时间维。 用户接口应可以支持终端用户选择有效的数据操作连接方法。

IsValid方法(InputExchangeItem,OutputExchangeItem,SelectedDataOperations)能在数据操作连接中集中检查,修改单位和维可使时间集合适合要求,其他更有效的方法检查同样也可实现。

2.2.6 并入并入并入并入 ExchangeItems 作为在 ElementSet中的典型数据交换,可并入为 ExchangeItem,一个模型可有作为输入的 ExchangeItems(InputExchangeItem)或作为输出的 ExchangeItems(OutputExchangeItem),模型 ExchangeItems列表有时作为一个交换供模型引用,虽然这不是作为 OpenMI标准的一部分。

2.2.6.1 ExchangeItems 前一节讨论了需要对外部提供交换数据的多个不同的处理块,量是为一定位置的典型交换内容(如要素集 ElementSet),并联合形成交换单元(ExchangeItem),这样的一个交换单元也能作为模型输入或输出,如图 2-15。

图 2-15 量要素集成方式:ExchangeItems 由于提供组件必须进行数据操作,它的交换单元(ExchangeItems)需要描述现有的数据操作。 与特定软件组件相关的模型可交换多个交换单元(ExchangeItems),为了集体组织的目标,有时交换单元群可能作为交换模型引用。 使用河流与降雨径流模型为例,图 2-16 描述了多个组件的交换单元,在降雨模型中MyRainGrid是 500×500m网格(定义为 XYPolygon要素集),在河流演算模型计算节点中侧向入流是 XYPoint要素集。

«interface»

IExchangeItem

+ «property» Quantity() : IQuantity

+ «property» ElementSet() : IElementSet

«interface»

IInputExchangeItem

«interface»

IOutputExchangeItem

+ «property» DataOperationDescriptionCount() : int

+ GetDataOperationDescription(dataOperDescrIndex :int) : IDataOperationDescriptor

Page 41: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

39

图 2-16 ExchangesItems应用实例

2.2.6.2 初始化不确定交换单元初始化不确定交换单元初始化不确定交换单元初始化不确定交换单元(ExchangeItems) 模型中的连接组件交换单元,不是所有的实例都是具有预先完全知道内容。从预知到完全不知可通过六种基本案例表述 InputExchangeItems 和 OutpuExchangeItems (这完全动态依赖于输入连接),如表 2-6所示。 表 2-6 ExchangesItems相关例子 案例 1 数据源-如:数据库

InputExchangeItem OutputExchangeItem

Quantity ElementSet Quantity ElementSet

Null Null 预知 预知 案例 2 模型(引擎+系统)-如 SOBEK莱茵河实例

InputExchangeItem OutputExchangeItem

Quantity ElementSet Quantity ElementSet 预知 (封装在引擎中) 预知(通过输入数据)

预知(封装在引擎中)

预知(通过输入数据) 案例 3 模型引擎(系统不加载)-如 SOBEK-CF

InputExchangeItem OutputExchangeItem

Quantity ElementSet Quantity ElementSet 预知 (封装在引擎中) 未知/要素类型已知

预知 (封装在引擎中)

未知/要素类型已知 案例 4 模型引擎配置-如 SOBEK-WQ

Page 42: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

40

InputExchangeItem OutputExchangeItem

Quantity ElementSet Quantity ElementSet 预知 (通过输入配置)

未知/通过连接知道要素类型

预知(通过输入配置)

未知/通过要素集知道要素类型 案例 5 配置数据处理引擎(与集成不相关)-如:频率分析或数学脚本

InputExchangeItem OutputExchangeItem

Quantity ElementSet Quantity ElementSet 未知,由连接决定

未知, 由连接决定,要素类型可配置

知道来源,由输入量决定

未知,由输入要素集决定、要素类型可配置 案例 6 数据沉淀-如可视化或文件输出

InputExchangeItem OutputExchangeItem

Quantity ElementSet Quantity ElementSet 未知,由连接决定

未知,由连接决定 Null Null

在案例 4之前,组件从连接的源组件继承它们的要素集,因而,模型可通过动态请求源组件要素集,仅传输全部移植的交换单元,从例 5开始是使用数据。 然而,只要没有连接建立,将一直为能指定是否接受输入和提供输出的组件使用,表 2-7给出了在初始化配置中推荐使用的返回交换单元。 表 2-7 推荐使用的 ExchangeItems

量量量量 要素集要素集要素集要素集 案例3模型引擎(非植入)

(列出的量) 选自: ・未知要素集 ・ 未知要素集类型 <指定的要素类型> 案例4模型引擎配置(非植入)

(列出的量) 选自: ・未知要素集 ・ 未知要素集类型 <指定的要素类型> 案例5配置数据处理引擎 (输入的)任意量,源量(输出)

选自: ・未知要素集 ・ 未知要素集类型 <指定的要素类型> 案例6数据沉淀 任意量 选自: ・任何要素集 ・ 任何要素集类型 <指定的要素类型>

被推荐关键词为: ・ 量:任意量 ・ 要素集:任意要素集(XYPoints、XYZPoints、XYLines、XYZLines、XYPolyLines、XYZPolyLines、XYPolygons、XYZPolygons、XYZpolyhedrons、unknown) 如果没有交换单元可接收或提供关键词“nothing”不需要作为 Null返回。 最后,如果“anything”或“unknown”能接受或提供,返回一个空交换单元可能也能接受,但使用关键词将更容易理解。

Page 43: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

41

2.2.7 一个高级例子一个高级例子一个高级例子一个高级例子 这节介绍怎样在一维水动力河流模型和三维水动力海岸模型建立高级连接,图 2-17显示模型之间的连接,河流模型所包含的断面用红色显示,海岸模型包含规则网格,两个模型之间互相要求边界条件。三维模型要求单元格面上有入流条件,通过 F1、F2、F3、F4等表示,一维河流模型要求末断面的水位作为边界条件,在这个例子是节点17和18之间的平均水位,两个模型在垂直平面上边界相交,两个模型引用水位相差 12厘米。

图 2-17 一维水动力河流模型和三维水动力海岸模型连接 这个例子模型组件非常强大,可提供多种要素集类型数据,这些要素集如图 2-18 和图2-19所示。

Page 44: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

42

图 2-18 一维河流模型要素集

图 2-19 三维海岸模型要素集 在这个例子中,模型共享相同语义数量的相同名称,表 2-8描述了可交换的数据。

Page 45: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

43

表 2-8 河流模型与海岸模型的计算量

ID 描述 值类型 维 单位 水位 以某一参考平面的相对水面高度

标量 长度=1 m 潮汐流 河流出口处上游流向的潮汐流

标量 长度=3 时间= -1 m3/s 流量 河流入海的出流 标量 长度=3 时间= -1 m

3/s 速度 通过垂直方向的速度

向量 长度=1 时间= -1 m/s

在各种要素集类型中许多数据是有效的,如表所述的输入要素集(InputExchangeItems)和输出要素集(OutputExchangeitems),(关于一维模型有表 2-9 和表 2-10 所示,三维海岸模型有表 2-11和表 2-12所示)。 表 2-9 河流模型输入要素 量量量量 要素集要素集要素集要素集 水位 河流输出-点 水位 河流输出-线 水位 河流输出-面 表 2-10 河流模型输出要素 量量量量 要素集要素集要素集要素集 数据操作数据操作数据操作数据操作((((变量变量变量变量)))) 输出流量 河流输出-点 - 潮汐流量 河流输出-点 - 速度 河流输出-点 - 输出流量 河流输出-面 空间插值 潮汐流量 河流输出-面 空间插值 速度 河流输出-面 空间插值

表 2-11 海岸模型输入要素 量量量量 要素集要素集要素集要素集 输出流量 3D岸线-面单元 潮汐输入流量 3D岸线-面单元 速度 3D岸线-面单元 输出流量 3D岸线-单元-ID 潮汐输入流量 3D岸线-单元-ID 速度 3D岸线-单元-ID

表 2-12 海岸模型输出要素 量量量量 要素集要素集要素集要素集 数据操作数据操作数据操作数据操作((((变量变量变量变量)))) 水位 3D岸线-单元-ID 垂直变换、值筛选 水位 3D岸线-线 垂直变换、值筛选\空间平均 水位 3D岸线-多段线 垂直变换、值筛选\空间平均

Page 46: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

44

2.3 配置连接形成合成体配置连接形成合成体配置连接形成合成体配置连接形成合成体 一个连接是两个模型结合的方法,当两个或更多的 OpenMI标准模型连接到一起时,它们就形成了模型合成体,合成体的连接必须包含系统中模型配置。 这节介绍 OpenMI连接定义和属性配置。

2.3.1 配置一个简单连接配置一个简单连接配置一个简单连接配置一个简单连接 一个连接是两个连接组件之间的数据途径,通过使用 ID 进行唯一标识,并使用描述(Description)属性说明,它连接一个(仅一个)源组件和一个(仅一个)目标组件,另外,使用连接一个量在一个方向交换,由于这个量可通过连接组件进行不同的命名,连接指定源量和目标量,如图 2-20。

图 2-20 OpenMI连接接口定义 为确保使用不同单位(空间引用或时间步)的模型之间通信,在传输接收组件要求的值之前,连接还需要指定由提供组件完成的数据操作。 最后,还必须指定数据交换的位置,即源要素集和目标要素集,在这两个要素集之间存在影射关系,这种关系是随着要素集的自然属性而改变(如可定义节点之间的一对一影射关系或线到多边形的函数影射)。 连接配置可能是个复杂处理过程,通常需要人为干涉,在 OpenMI标准中不对连接的数据进行兼容性和逻辑性检查,而依赖模型开发者确定相应的数据和位置,这意味着开发者必须预先知道有效的位置和相应有效的数据。 为了使得连接配置变得更容易些,OpenMI 提供一些支持工具帮助快速完成连接,如在地理引用数据中自动指定源和目标要素,而且使用图形配置编辑器,可达到对连接和属性可视编辑的目的。 总之,连接配置需要完成下列几步: ・ 选择源和目标连接组件; ・ 选择源和目标连接量; ・ 选择源和目标要素集; ・ 选择数据操作。

«interface»

ILink

+ «property» ID() : string

+ «property» Description() : string

+ «property» TargetComponent() : ILinkableComponent

+ «property» TargetQuantity() : IQuantity

+ «property» TargetElementSet() : IElementSet

+ «property» SourceComponent() : ILinkableComponent

+ «property» SourceQuantity() : IQuantity

+ «property» SourceElementSet() : IElementSet

+ «property» DataOperationsCount() : int

+ GetDataOperation(dataOperationIndex :int) : IDataOperation

Page 47: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

45

以河流与降雨径流模型配置过程为例,图 2-21描述雨量模块与降雨径流模型和河流模型之间连接的配置,图 2-22提供了指定连接属性定义。

图 2-21 在河流演算模型、降雨产流模型中建立的连接

Page 48: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

46

图 2-22 河流演算模型、降雨产流模型中的连接完整定义

2.3.2 建立模型合成建立模型合成建立模型合成建立模型合成体体体体 有了连接组件(LinkComponent)和连接(Link)后,就可建立完整集成的合成体(Composition),合成体信息可使用 opr为后缀的 XML标记文件存储。 在 OpenMI语义中,合成体是连接组件的一个集合,通常包括模型数据和内部连接。可认为它是运行集成模拟的最后阶段,在实施方面,是输入实体,通常作为分发者引用,它包括所有相关模型和连接,并设置了所有必需参数,最后完成初始模拟。 建立合成体过程可分为四个步骤: ・ 选择所有相关连接组件或图表组; ・ 建立交互组件之间的连接; ・ 配置连接; ・ 设置其它模拟参数。 最简单建立合成体的方法是使用图形工具,如在 2.4介绍的 OmiEd配置编辑器。 首先需要选择所有相关的连接组件,并放入配置编辑器的工作区,选择处理是存储组件和属性的所有描述信息建立过程。 第二步是连接组件,通过使用鼠标画出两个模型之间连接,如果两个组件之间有两个或多个数据交换或有双向数据交换,此时要分别建立连接。 定义好每个连接后,需要设置连接的属性值,双击连接将显示的属性对话框,包含变量数据、要素集和数据操作列表。 最后,任何模型指定的或模拟相关的参数必须设置完成。 鉴于以下原因合成体建立后需要保存: ・ 设置复杂的合成体通常需要付出不少精力;

Page 49: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

47

・ 模拟经常是需要重复频繁进行,且每次使用不同参数,直到得出所期望的有效结果; ・ 一个集成模型模拟可能使用需要运行远程或本地不存在数据的模型引擎。 一个连接组件使用 XML文件标识,它包括引用软件单元和相适应的数据,通过调用和初始组件,在能提供和接收量和位置处,提供元数据,基于这些元数据,模型构建者能建立组件之间的连接,建立合成体,并保存为 XML文件,当然,每一次模拟运行或修改时仍可打开并编辑这个文件。

2.4 使用使用使用使用 OpenMI 配置编辑器配置编辑器配置编辑器配置编辑器

OpenMI环境包括 OmiEd,建立和运行 OpenMI系统的可视工具,系统细节作为合成体存储。 建立 OpenMI系统包括步骤如下: (1) 运行配置编辑器; (2) 增加模型至合成体; (3) 在模型之间建立连接; (4) 配置连接; (5) 增加触发子; (6) 运行合成体。 这节给出编辑器及其使用简介。

2.4.1 运行配置编辑器运行配置编辑器运行配置编辑器运行配置编辑器 使用标准的Windows安装程序,将 OmiEd应用安装于程序文件目录(Program Files)。 从Windows开始菜单选择 ProgramFiles/OpenMI/OpenMI ConfigurationEditor,OmiEd窗口显示如下:

Page 50: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

48

图 2-23 OmiEd运行主界面 在编辑器中有三个菜单项: ・ File 菜单有创建新合成体、重载合成体(自上次保存后的所有更改将丢失)、打开一个存在的合成体,保存当前合成体(使用现有的名字或新命名),退出程序,合成体保存的扩展名为 OPR; ・ Composition菜单可以增加模型、连接、触发子,编辑连接和模型属性,运行合成体; ・ Help菜单提供了使用 OmiEd的指导信息及关于程序信息。 随着增加模型,这些内容将显示在窗体的顶部。

2.4.2 增加模型到合成体增加模型到合成体增加模型到合成体增加模型到合成体 合成体必须包含两个或更多的 OpenMI标准模型,每个模型有相应的 OMI文件,加载模型至合成体步骤如下: (1) 从 Composition菜单选择 Add Model; (2) 定位模型 OMI文件,点击 Open; (3) 一个包含模型名字的方框被添加至编辑器窗口,拖动方框至合适位置; (4) 添加其它需要的模型。

Page 51: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

49

图 2-24 增加模型至配置环境中 使用模型右键菜单 Model Properties 可查看模型属性,属性对话框提供了模型交换项的详细信息,在左手边顶部方框列出了输出数据,方框底部列出输入数据,可以扩展列表以便显示每个项的有效要素集,要素集扩展后可显示有效的操作,点击任意项可显示相应的属性于右侧,如图 2-25。

Page 52: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

50

图 2-25 模型属性对话框 在底部对话框的下拉列表选择中可选择查看其它模型属性,增加模型后保存合成体。

2.4.3 模型之间建立连接模型之间建立连接模型之间建立连接模型之间建立连接 通过模型之间增加连接将模型联系在一起,步骤可为: (1) 从 Composition菜单使用 Add Connection; (2) 从一个模型到另一模型拖动指针,连接被添加在模型之间,如图 2-26; (3) 重复以上操作添加其它连接。

Page 53: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

51

图 2-26 模型之间建立连接

2.4.4 配置连接配置连接配置连接配置连接 每个连接必须配置联系属性: (1) 右击连接中间的箭头,选择 Connection Properties,弹出属性对话框; (2) 在 Output Exchange Items框中,扩展需求输出数据和要素集,点击需要数操作(这决定什么数据被输出、输出位置及表现形式); (3) 在 Input Exchange Items框中,扩展需要输入数据,点击要素集设置接受的数据; (4) 点击 Apply 按钮,新的连接添加至对话框的底部列表中,点击该连接可再现交换项属性; (5) 点击 Close。

Page 54: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

52

图 2-27 连接属性对话框 在模型属性对话框中,通过鼠标点击可以看到数据、要素集、操作的属性,这些属性显示在右侧的方框中。 点击选择连接列表中的连接,使用 Remove按钮可以移动任何连接。 增加连接后记住保存合成体。

2.4.5 增加触发子增加触发子增加触发子增加触发子 每个合成体需要一个触发子引发过程处理,操作步骤如下: (1) 从 Composition 菜单选择 Add Trigger,一个蓝色的触发子框增加至合成体,可以移动至合适的位置; (2) 从首先运行的模型增加连接至触发子; (3) 设置触发子连接属性。

Page 55: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

53

图 2-28 增加触发器 完成触发子设置后合成体可以准备运行了。

2.4.6 运行合成体运行合成体运行合成体运行合成体 运行合成体步骤如下: (1)从 Composition菜单选择 Run; (2)在运行属性对话框中选择需要运行时监视的事件,还可以指定触发子被调用时间、日志文件名等;如图 2-29;

Page 56: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

54

图 2-29 运行属性 (3)点击运行,运行过程对话框将出现;如图 2-30;

图 2-30 模拟计算进程 (4)当模拟结束,点击 Close按钮,并确保是否想要重载项目的消息框弹出,在 OmiEd窗口底部显示了运行日志,如图 2-31,日志也可作为文本文件打开。

Page 57: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

55

图 2-31 运行后的主界面显示 可以扩大窗口尺寸以便更方便浏览运行日志。 在运行结束后,可以对合成体进一步更改再运行。

Page 58: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

56

第三章第三章第三章第三章 开发开发开发开发 OpenMI 系统系统系统系统

3.1 OpenMI 标准系统标准系统标准系统标准系统

OpenMI系统是集成两个或多个 OpenMI标准组件的软件系统,这章介绍 OpenMI系统,并对 OpenMI组件的定义文件-OMI文件介绍。

3.1.1 什么是什么是什么是什么是 OpenMI系统系统系统系统

OpenMI 系统可被认为是包括一系列 OpenMI 标准组件的软件系统,也可同时包括非OpenMI标准组件,通过标准接口这种系统可以配置和运行 OpenMI组件。 为此,需要具备以下要求:

OpenMI系统需要知道哪里可以找到连接组件;

OpenMI系统需要知道哪个连接组件被连接及怎样连接,即需要知道连接本身;

OpenMI系统需要能实例化,可分发和运行连接的组件。

OpenMI系统可有两种类型: 由代码编写的系统,可称为纯代码系统; 通过配置而成的系统,可称为配置系统。 代码编写的系统仅是功能上的实现,配置的系统还能对 OpenMI连接组件的交换项进行表述,在深入分析纯代码系统和配置系统前,先对建立连接和运行 OpenMI组件全部动态过程进行概览。

3.1.2 定位组件定位组件定位组件定位组件 一个 OpenMI组件能通过 OMI文件定义,这是个包含足够定义组件信息的 XML文件,组件本身是以二进制代码编译并注入了输入数据,(如汇编及类的实例化)。一个 XML定义内容能表示用于解释信息的默认工具。 在规则上,OMI 文件能存放在系统的任何地方,用户可自由组织自己的文件库,只要在需要时能找到相应的 OMI文件即可。 如图 3-1是一个 OMI文件例子,在图 3-2给出了 XML结构定义(XSD)

Page 59: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

57

图 3-1 OMI文件例子

图 3-2 OMI文件 XML结构定义

<?XML version="1.0"?>

<LinkableComponent Type="wlDelft.OpenMI.WLLinkableComponent" Assembly="wlDelft.OpenMI,

Version=1.0.0.0, Culture=neutral, PublicKeyToken=8384b9b46466c568"

XMLns="http://openmi.org/LinkableComponent.xsd">

<Arguments>

<Argument Key="Model" ReadOnly="true" Value="RR" />

<Argument Key="Schematization" ReadOnly="true"

Value="D:\RainRRCF\Model\Cmtwork\sobek_3b.fnm" />

</Arguments>

</LinkableComponent>

<?XML version="1.0" ?>

<xs:schema id="LinkableComponent"

targetNamespace="http://www.openmi.org/LinkableComponent.xsd"

XMLns:mstns="http://www.openmi.org/LinkableComponent.xsd"

XMLns="http://www.openmi.org/LinkableComponent.xsd"

XMLns:xs="http://www.w3.org/2001/XMLSchema" XMLns:msdata="urn:schemasmicrosoft

com:XMLmsdata" attributeFormDefault="qualified" elementFormDefault="qualified">

<xs:element name="LinkableComponent">

<xs:complexType>

<xs:sequence>

<xs:element name="Arguments" minOccurs="1" maxOccurs="1">

<xs:complexType>

<xs:sequence>

<xs:element name="Argument" minOccurs="0" maxOccurs="unbounded">

<xs:complexType>

<xs:attribute name="Key" form="unqualified" type="xs:string" />

<xs:attribute name="ReadOnly" form="unqualified" type="xs:boolean" use="optional" />

<xs:attribute name="Value" form="unqualified" type="xs:string" />

</xs:complexType>

</xs:element>

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:sequence>

<xs:attribute name="Type" form="unqualified" type="xs:string" />

<xs:attribute name="Assembly" form="unqualified" type="xs:string" use="optional" />

</xs:complexType>

</xs:element>

</xs:schema>

Page 60: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

58

3.2 建立建立建立建立 OpenMI 系统系统系统系统

OpenMI标准给出六个步骤定义建立和运行一个 OpenMI连接组件合成体的过程,这节对每个过程进行说明。

3.2.1 使用连接组件接口使用连接组件接口使用连接组件接口使用连接组件接口 可通过一定方法使用 OpenMI 组件构成 OpenMI 系统,OpenMI 标准给出使用 OpenMI连接组件的一系列过程,在图 3-3提供了可能包含于每个过程中的概要内容。本节按顺序给出过程描述,但这个顺序在每个过程不是固定的。每个阶段的动态内容在以下各节进行详细讨论。

图 3-3 分发 OpenMI连接组件阶段过程

Initialize()

ComponentID

ComponentDescription

ModelID

ModelDescription

InputExchangeItemsCount

OutputExchangeItemsCount

GetInputExchangeItem()

GetOutputExchangeItem()

TimeHorizon

AddLink()

RemoveLink()

Validate()

DGetValues()

EarliestInputTime

SaveState() **

RestoreState() **

ClearState() **

AddLink() ^

RemoveLink() ^

GetPublishedEventTypeCount #

GetPublishedEventType() #

SubScribe() #

UnSubscribe() #

SendEvent() #

HasDiscreteTimes() *

GetDiscreteTimesCount() *

GetDiscreteTime() *

Prepare()

Finish()

Dispose()

# Methods from IPublisher interface

Implementation is optional

* if component implements

IDiscreteTimes interface

** if component implements

IManageState interface

^ if component supports dynamic

adding/removing links

initialization

inspection

&configuration

phase

preparation phase

computation/

execution phase

completion phase

disposure phase

Page 61: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

59

3.2.2 阶段阶段阶段阶段 1::::实例和初始化实例和初始化实例和初始化实例和初始化 该阶段是建立 OpenMI系统的处理入口点,这阶段结束后连接组件就有足够的信息装入模型数据并提供交换项,连接组件在该步是否完成模型数据装入取决于代码开发者。 我们用河流与地下水模型连接对实例化说明,步骤如下,如图 3-4。 实例化:在该阶段应用软件读取 OMI 文件,它指向一个执行连接组件(LinkableComponent)软件单元(如汇编)使用连接组件的引用将被建立。 初始化:连接组件可通过调用 Initialize()方法装入输入数据,该方法的参数列表存于 OMI文件中,其典型的参数是包括数据文件的指向。

图 3-4 对象实例化和初始化

3.2.3 阶段阶段阶段阶段 2::::检查与配置检查与配置检查与配置检查与配置 经过这个阶段,连接将被定义并且每个组件将处于有效状态。 在一些案例中这一阶段或许非常简单,如直接使用代码编写,但在一个开放系统有效项的检查是至关重要的。处理交换项的最简单方法是请求交换项的数据,并通过列表循环检查,如果交换项是静态并预先知道则提供组件只要按这一方法直接执行;在那些交换项是预先不知时(如依赖连接组件),将采用动态请求处理机制,图 3-5显示怎样处理请求交换项(如,通过验证其它组件交换项)

Page 62: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

60

图 3-5 获得交换源项(活动图框) 一旦交换项通过验证,就可将连接加入组件中,图 3-6说明降雨产流/河流模型处理过程。

询查

OutputExchangeItems

重复检查所有的

OutputExchangeItems

询查 InputExchangeItems

初始状态/询查组件 1的 InputExchangeItems

有效的InputLinks 终止 询查每个连接组件的OutputExchangeItems 返回每个组件的OutputExchangeItems

创建并移植InputExchangeItems 返回InputExchangeItems 得到OutputExchangeItem 属性

移植OutputExchangeItem

返回OutputExchangeItem

初始状态 询查组件 1

OutputExchangeItems

OutputExchangeItem 预知

InputExchangeItem 预知

[yes] [no]

[no]

[no]

[yes]

any

得到InputExchangeItem属性

[yes]

重复检查所有

InputExchangeItems

Page 63: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

61

图 3-6 在降雨产流模型与河流模型实例中增加连接(顺序处理图框) (1)建立相关对象(连接、数据、要素集、数据操作),检查数据操作和对象执行的有效性; (2)在组件间增加连接:

LinkRainToCatchm(连接降雨至集水模块):目标组件(RRmodel)需要知道从那个组件获得降雨,源组件(RainModule)需要知道传输雨量的目标要素集。

LinkRunoffToInflow:目标组件(RiverModel)需要知道从那个组件获得侧向入流,源组件(RRmodel)需要知道传输侧向入流要素集,注意指向目标地(RiverModel)是正向。

TriggerLink:指向河流模型的触发子-在数据链上的下游组件-被创建移入,这个连接的目的是使的第一个 GetValues()方法生效并调用河流模型,这是计算链中的触发子。 (3)使用 Validate()方法验证组件和它们连接的状态。

3.2.4 阶段阶段阶段阶段 3::::准备准备准备准备 这一阶段是在计算和数据修复处理开始前执行,其主要目的是在大量工作加入前定义一个空白的取回位置,该阶段仅包含一个方法:Prepare()。 在这阶段数据库或网络连接(或两者)需要建立,可能监测站被调用或可能需要通过移入系统输入数据(如果之前没准备)准备模型引擎,打开输出文件,组织缓冲区,为(空间)插值目的建立数据映射等。 注意,这阶段最后必须对连接组件状态进行有效性检查。

3.2.5 阶段阶段阶段阶段 4::::计算计算计算计算/执行执行执行执行 在这阶段由大量的装载工作要处理,相关的数据传输量也变得很大,OpenMI数据传输机制被定义为请求-回应服务机制,它是在不需要任何额外工具参与下两个连接组件之间直

Page 64: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

62

接交互,在标准的 3.3节解释了非直接数据交换、双向数据交换及往复数据交换是如何进行的。 经过一个连接调用 GetValues方法,并开始计算,这个连接可链接至触发子对象(一个连接组件的“空”接口方法)或链接到“实”组件,如可视工具或输出文件。 当 OpenMI连接组件挑选出自己的数据会话和时间步时,系统开发人员应注意处理控制问题。 系统开发人员能很容易开发一个将组件联系的结束时间作为 GetValues方法参数的应用程序,然而,接下来的问题是模型组件直到结束运行前不能返回控制给主应用程序,使得任何合理的中断也变得困难了,另外,“整个”计算步都是“不可视”,就象是由不明组件控制一样。 由于那些不利因素使得需要执行一些返回完整模拟周期至时间步循环的处理工具(在Org.OpenMI.Configuration包中这个处理工具称为“配置者”),在整个模拟周期处理,每个时间步 GetValues方法都可调用,在每次调用之间,应用程序可回应外部事件,而处理工具仍控制整个处理过程。图 3-7给出一个循环处理功能。

图 3-7 一个时间循环

3.2.6 阶段阶段阶段阶段 5::::完成完成完成完成 这阶段发生在计算和数据恢复处理完成之后,代码开发者可在这阶段关闭文件和网络连接,清除内存等,这阶段包括的仅是一个方法调用的步骤:Finish方法

3.2.7 阶段阶段阶段阶段 6::::布置布置布置布置 进入这一阶段在应用程序关闭的时候,所有剩余对象被清理、内存(非管理代码)被重新分配;在 Dispose方法调用后代码开发者不必对连接组件重初始化处理。

//-Run -

try

{

MyRainModule.Prepare();

MyRRModel.Prepare();

MyRiverModel.Prepare();

int nrsteps=100;

DateTimestep = (end – start)/nrsteps;

DateTime stop = end + 0.000001;

DateTime _time = start;

while (_time <= stop)

{

Application.DoEvents();

IValueSet Values = _trigger.GetValues(new TimeStamp(_time),

_triggerLink.ID);

_time = _time.AddSeconds(step);

}

GermanRhineModel.Finish();

NethRhineModel.Finish();

} // end try

Page 65: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

63

3.3 纯代码纯代码纯代码纯代码系统系统系统系统 纯代码系统是指在建立连接、布置及组件联合处理完全通过源代码封装处理的系统。这部分包括实例化组件、连接建立和运行时布置执行各阶段内容。分析纯代码建立的 OpenMI系统有利于理解 OpenMI组件连接及多模型之间时序处理过程,纯代码编写 OpenMI系统可代替在 OmiED可视工具处理过程,有利于大型系统整体集成。

3.3.1 一个纯一个纯一个纯一个纯代码编写系统例子代码编写系统例子代码编写系统例子代码编写系统例子 当开发一个纯代码系统,对 OpenMI组件和输入输出项的内部机制需要清楚,纯代码可按下列步骤完成: (1)读取 OMI文件; (2)通过适当的输入数据设置对连接组件进行实例化和初始化; (3)通过索引交换项创建量和要素集对象; (4)创建连接对象,并利用数据和要素对象对其实例化; (5)增加连接对象至组件并使其有效; (6)准备事件监听器捕获事件; (7)运行模拟(包括准备和结束阶段); (8)布置组件。 在所有这些步骤中还需要考虑例外情况。 以下代码提供了 C#代码编写的 OpenMI 组件应用所需的各阶段代码,注意,这个例子不包括数据操作和有效关联检查,C#的日期事件数据类型和 OpenMI 时间对象的日期转换也被删除。

// -Read the OMI files -

// Note for namespaces: the abbreviation MC refers to Model Components

// -MyRainmodule hardcoded OMI file information -

String myRainModuleAssemblyFile =

"C:\\OpenMI\\Examples\\MC\\SimpleRain\\org.OpenMI.Examples.MC.DLL";

string myRainModuleClass = "org.OpenMI.Examples.MC.SimpleRain";

string myRainArguments = new Argument[1];

myRainArguments[0] = new Argument("FilePath","C:\\OpenMI\\Examples\\MC\\SimpleRain\\Data",true,"");

// -MyRainfallRunoffmodel hardcoded OMI file information -

String myRRModelAssemblyFile =

"C:\\OpenMI\\Examples\\MC\\SimpleRR\\org.OpenMI.Examples.MC.DLL";

string myRRModelClass = "org.OpenMI.EXamples.MC.SimpleRainfallRunoff";

string myRRArguments = new Argument[1];

myRRArguments[0] = new Argument("FilePath",

"C:\\OpenMI\\Examples\\MC\\SimpleRainfallRunoff\\Data",true,"");

// -MyRiverModel hardcoded OMI file information -

String myRiverModelAssemblyFile =

"C:\\OpenMI\\Examples\\MC\\SimpleRiver\\org.OpenMI.Examples.MC.DLL";

string myRiverModelClass = "org.OpenMI.Examples.MC.SimpleRiver";

string myRiverArguments = new Argument[1];

Page 66: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

64

myRiverArguments[0] = new Argument("FilePath",

"C:\\OpenMI\\Examples\\MC\\SimpleRiver\\Data",true,"");

// - Create LinkableComponents -

ILinkableComponent MyRainModule = new SimpleRainModuleWrapper();

ILinkableComponent MyRRModel = new SimpleRREngineWrapper();

ILinkableComponent MyRiverModel = new SimpleRiverEngineWrapper();

ILinkableComponent trigger = new Trigger();

MyRainModule.Initialize(myRainArguments);

MyRRModel.Initialize(myRRArguments);

MyRiverModel.Initialize(myRiverArguments);

// -Query Quantities and ElementSets

// Outputs

IQuantity Rain_Precipitation = (MyRainModule).GetOutputExchangeItem(0).Quantity;

IQuantity RR_Outflows = (MyRRModel).GetOutputExchangeItem(0).Quantity;

IQuantity Riv_WaterLevels = (MyRiverModel).GetOutputExchangeItem(0).Quantity;

IElementSet Rain_MyRainGrid = (MyRainModule).GetOutputExchangeItem(0).ElementSet;

IElementSet RR_Outlets = (MyRRModel).GetOutputExchangeItem(0).ElementSet;

IElementSet Riv_RiverNetwork = (MyRiverModel).GetOutputExchangeItem(0).ElementSet;

IDataOperation Rain_TmAvg = (MyRainModule).GetOutputExchangeItem(0).DataOperation(0);

IDataOperation Rain_TmAccu = (MyRainModule).GetOutputExchangeItem(0).DataOperation(1);

IDataOperation Rain_SptAvg = (MyRainModule).GetOutputExchangeItem(0).DataOperation(2);

IDataOperation RR_TmAvg = (MyRRModel).GetOutputExchangeItem(0).DataOperation(0);

IDataOperation RR_TmMaxVal = (MyRRModel).GetOutputExchangeItem(0).DataOperation(1);

IDataOperation Riv_SpatIntp =

(MyRiverModel).GetOutputExchangeItem(0).DataOperation(0);

//Inputs

IQuantity RR_Rainfall = (MyRRModel).GetInputExchangeItem(0).Quantity;

IQuantity Riv_LateralInflows = (MyRiverModel).GetInputExchangeItem(0).Quantity;

IElementSet RR_SubCatchments = (MyRRModel).GetInputExchangeItem(0).ElementSet;

IElementSet Riv_LateralInlets = (MyRiverModel).GetInputExchangeItem(0).ElementSet;

// TimeHorizon

DateTime start = MyRainModule.TimeHorizon.Start;

if (start < MyRRModel.TimeHorizon.Start)

{

start = (DateTime)MyRRModel.TimeHorizon.Start;

}

if (start < MyRiverModel.TimeHorizon.Start)

{

start= (DateTime)MyRiverModel.TimeHorizon.Start;

}

DateTime end = MyRainModule.TimeHorizon.End;

if (end < MyRRModel.TimeHorizon.End)

{

end = (DateTime)MyRRModel.TimeHorizon.End;

Page 67: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

65

}

if (end < MyRiverModel.TimeHorizon.End)

{

end= (DateTime)MyRiverModel.TimeHorizon.End;

}

DateTime stop = end + 0.000001;

// -Create Links -

// create data operations here

IDataOperation Rain_DataOperations[] = new Rain_DataOperation[1];

Rain_DataOperation(0) = new Rain_TmAccu;

Rain_DataOperation(1) = new Rain_SpatAvg;

// check validity: to be done raise exception

// Rain_DataOperation(1).IsValid((MyRainModule).GetOutputExchangeItem(0),

(MyRRModel).GetInputExchangeItem(0), Rain_DataOperation[0])

ILink triggerLink = new Link(MyRiverModel, Riv_RiverNetwork, Riv_WaterLevels, trigger,

"", "", "RiverModel to Trigger Link", "RiverModelToTrigger", new ArrayList());

ILink LinkRunoffToInflow = new Link(MyRRModel, RR_Outlets, RR_Outflow, MyRiverModel,

Riv_LateralInlets, Riv_LateralInflows, "Link Runoff to River Inflow",

"LinkRunoffToInflow", new ArrayList());

ILink LinkRainToCatchm = new Link(MyRainModule, MyRainGrid, Rain_Precipitation,

MyRRModel, RR_SubCatchments, RR_Rainfall, "Link rainfall to catchment",

"LinkRainToCatchm", Rain_DataOperations[]);

// -Add Links -

MyRiverModel.AddLink(triggerLink);

trigger.AddLink(triggerLink);

MyRainModule.AddLink(LinkRainToCatchm);

MyRRModel.AddLink(LinkRainToCatchm);

MyRRModel.AddLink(LinkRunoffToInflow);

MyRiverModel.AddLink(LinkRunoffToInflow);

// -Validate Components -

trigger.Validate;

MyRainModule.Validate;

MyRRModel.Validate;

MyRiverModel.Validate;

//-Prepare Event listener -

org.OpenMI.Standard.IListener myListener = new EventListener();

for (int i = 0; i < myListener.GetAcceptedEventTypeCount(); i++)

{

for (int n = 0; n < MyRainModule.GetPublishedEventTypeCount(); n++)

{

if (myListener.GetAcceptedEventType(i) ==

MyRainModule.GetPublishedEventType(n))

{

MyRainModule.Subscribe(myListener,

Page 68: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

66

myListener.GetAcceptedEventType(i));

}

}

for (int n = 0; n < MyRRModel.GetPublishedEventTypeCount(); n++)

{

if (myListener.GetAcceptedEventType(i) ==

MyRRModel.GetPublishedEventType(n))

{

MyRRModel.Subscribe(myListener, myListener.GetAcceptedEventType(i));

}

}

for (int n = 0; n < MyRiverModel.GetPublishedEventTypeCount(); n++)

{

if (myListener.GetAcceptedEventType(i) ==

MyRiverModel.GetPublishedEventType(n))

{

MyRiverModel.Subscribe(myListener,

myListener.GetAcceptedEventType(i));

}

}

}

//-Run -

try

{

MyRainModule.Prepare();

MyRRModel.Prepare();

MyRiverModel.Prepare();

int nrsteps=100;

DateTimestep = (end – start)/nrsteps;

DateTime stop = end + 0.000001;

DateTime _time = start;

while (_time <= stop)

{

Application.DoEvents();

IValueSet Values = _trigger.GetValues(new TimeStamp(_time),

_triggerLink.ID);

_time = _time.AddSeconds(step);

}

GermanRhineModel.Finish();

NethRhineModel.Finish();

} // end try

//-Clean up -

MyRainModule.Dispose();

MyRRModel.Dispose();

Page 69: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

67

MyRiverModel.Dispose();

}

//-Exception Handling -

catch(Exception e)

{

// write exception to screen;

Console.WriteLine(e);

}

3.4 配置系统支持配置系统支持配置系统支持配置系统支持 在模型开发是“产品”式的工具情形,模型集成应尽可能少使用资源,标准接口是前进的重要一步,但要实现最小化操作,其代价是将阻止为每次集成新模型使用纯代码,如果当开发模型连接时全部使用元数据提供,OpenMI将变得非常强大。 这部分讨论配置系统主要内容,并使用 OpenMI环境中提供的工具进行详细介绍。

3.4.1 配置系统主要内容配置系统主要内容配置系统主要内容配置系统主要内容 如果开发模型合成体时使用元数据开发工具,应注意不同的人通过自己的方法组织处理过程完成不同的工作(或不同的计算系统使用),复杂工作可分为模型系统开发、组织配置模型合成体、分发和运行模型等,每一工作对使用工具有不同要求,批处理运行、或在不同机器上运行不同工作的能力,要求相关管理部分(如模型配置)不应与特定用户界面关联。 因而在开发任何支撑工具时应考虑到各种不同概念,以下功能需要区别考虑: 组件定义:能区分和定位组件; 配置(管理/连接组件的合成体):能创建、配置和激活模型合成体,能保存和加载那些永久性存储配置; 分发:能使用基本方法实例化组件及运行它们; 执行以上功能的用户接口组件。 所有这些条目在改进 OpenMI应用能力方面扮演重要角色。 当然,组件定义通过 OMI文件实现(如 3.1.2所述),其它条目在这节的以下内容讨论,如何使用开源 OpenMI 配置编辑器 (OmiEd)在 2.4 节已说明,以下两节分别介绍org.OpenMI.Utilities.Configuration包下的处理逻辑和 GUI。

3.4.2 配置和维持组件合成体配置和维持组件合成体配置和维持组件合成体配置和维持组件合成体 配置是在相关的组件间定义连接任务,为了能重使用这样的配置,要求有个永久存储体,这节内容介绍在 OpenMI环境中 org.OpenMI.Utilities.Configuration包提供的该实体。 为了能在模型之间永久存储和交换模型配置,需要存储相关组件(如 OMI文件)及其之间连接的详细配置,这个包保存的配置称为一个合成体,为了分发(如运行)这样的合成体,需要连接组件和增加连接。 合成体处理包括下列步骤: (1)创建新的合成体对象或加载现有的合成体; (2)选择相关的连接组件(如通过 OMI 文件加载),如果需要,可对他们属性进行必要修改并保存;

Page 70: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

68

(3)创建连接并将其加入组件之间,定义连接属性; (4)当注意到选择数据操作的有效性时,植入连接属性; (5)检查连接和组件的有效性; (6)制定时间框架(开始、结束、步长); (7)保存合成体; (8)如果需要,可分发合成体。 在配置阶段有效性检查是重要一步,通常有效性检查将产生一串消息,通知连接和组件使用的有效性。 在 OpenMI环境中,合成体类代表了合成体全部细节,如图 3-8。

图 3-8 合成体类 合成体的代表属性能保存在 XML文件中,如图 3-9及以下代码,XML文件包括两部分信息: ・ 相关组件(指向 OMI文件); ・ 连接定义。 这个文件能通过类自动生成或手工建立及操作。

OpenMI 环境包括一个生成器、XML定义器和系列文件,XML定义器允许 XML文件要素(如组件、连接、量、要素集)可定义成“一致的”或“引用的”,引用能做为 XML元素定义在文件的前面,或它指向一个能通过实例化相关类生成的对象,这引用的特性是允许可变的组件共享相同的要素集或数据,如果需要,可提供其它信息。

Composition

+ Composition()

+ «property» ID() : string

+ «property» DetailedDescription() : string

+ «property» Description() : string

+ «property» LinkableComponents() : IList

+ «property» Links() : IList

+ «property» Trigger() : ILinkableComponent

+ «property» TimeStepping() : TimeStepping

+ AddModel(model :ILinkableComponent) : void

+ RemoveModel(model :ILinkableComponent) : void

+ AddLink(link :ILink) : void

+ RemoveLink(id :string) : void

+ RemoveLink(link :ILink) : void

+ Validate() : string

+ Dispose() : void

+ ToString() : string

Page 71: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

69

图 3-9 组装可视表示

<?XML version="1.0"?>

<Composition XMLns="http://www.openmi.org/Composition.xsd"

Type="org.OpenMI.Utilities.Configuration.Composition"

Assembly="org.OpenMI.Utilities.Configuration, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" Description="Example Composition"

DetailedDescription="" ID="65adab37ac7d423a8c41c42dc216c0a3">

<LinkableComponents>

<LinkableComponent Type="org.OpenMI.Examples.MC.SimpleRain"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRain.omi" />

<LinkableComponent Type="org.OpenMI.Examples.MC.SimpleRR"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRR.omi" />

<LinkableComponent Type="org.OpenMI.Examples.MC.SimpleRiver"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRiver.omi" />

</LinkableComponents>

<Links>

<Link Description="Link Rainfall to Catchment">

<DataOperations>

<DataOperation Type="org.OpenMI.Examples.MC.Interpolator"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

ID="Rain_TmAccu">

<Arguments />

</DataOperation>

<DataOperation Type="org.OpenMI.Examples.MC.Interpolator"

Page 72: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

70

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

ID="Rain_SpatAvg">

<Arguments />

</DataOperation>

</DataOperations>

<SourceComponent Type="org.OpenMI.Examples.MC.SimpleRain"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRain.omi" />

<SourceElementSet Type="org.OpenMI.Backbone.ElementSet"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" File="..\data\SimpleRain.omi"

RefID="Rain_MyRainGrid" />

<SourceQuantity Type="org.OpenMI.Backbone.Quantity"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" Description="Rainfall /

Precipitation"

ID="Rain_Precipitation" ValueType="Scalar">

<Dimension AmountOfSubstance="0" Currency="0"

ElectricCurrent="0" Length="1" LuminousIntensity="0" Mass="0"

Temperature="0" Time="-1"/>

<Unit ConversionFactorToSI="2.778e7" Description="mm per hour"

ID="mm/h" OffSetToSI="0" />

</SourceQuantity>

<TargetComponent Type="org.OpenMI.Examples.MC.SimpleRR"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRR.omi" />

<TargetElementSet Type="org.OpenMI.Backbone.ElementSet"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" File="..\data\SimpleRR.omi"

RefID="RR_SubCatchments" />

<TargetQuantity Type="org.OpenMI.Backbone.Quantity"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568"

Description="Rainfall on catchment"

ID="RR_Rainfall" ValueType="Scalar">

<Dimension AmountOfSubstance="0" Currency="0"

ElectricCurrent="0" Length="1" LuminousIntensity="0" Mass="0"

Temperature="0" Time="-1"/>

<Unit ConversionFactorToSI="2.778e7" Description="" ID="m3/s"

OffSetToSI="0" />

</TargetQuantity>

</Link>

<Link Description="Link Runoff To River Inflow" ID="LinkRunoffToInflow">

</DataOperations>

Page 73: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

71

<SourceComponent Type="org.OpenMI.Examples.MC.SimpleRR"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRR.omi" />

<SourceElementSet Type="org.OpenMI.Backbone.ElementSet"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" File="..\data\SimpleRR.omi"

RefID="RR_Outlets" />

<SourceQuantity Type="org.OpenMI.Backbone.Quantity"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" Description="Runoff Outflows"

ID="RR_Outflows " ValueType="Scalar">

<Dimension AmountOfSubstance="0" Currency="0"

ElectricCurrent="0" Length="3" LuminousIntensity="0" Mass="0"

Temperature="0" Time="-1" />

<Unit ConversionFactorToSI="1" Description="m3/s" ID="m3/s"

OffSetToSI="0"/>

</SourceQuantity>

<TargetComponent Type="org.OpenMI.Examples.MC.SimpleRiver"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRiver.omi" />

<TargetElementSet Type="org.OpenMI.Backbone.ElementSet"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568" File="..\data\SimpleRiver.omi"

RefID="Riv_LateralInlets" />

<TargetQuantity Type="org.OpenMI.Backbone.Quantity"

Assembly="org.OpenMI.Backbone, Version=1.0.0.0, Culture=neutral,

PublicKeyToken=8384b9b46466c568"

Description="Lateral Inflows into River"

ID="Riv_LateralInflows" ValueType="Scalar">

<Dimension AmountOfSubstance="0" Currency="0"

ElectricCurrent="0" Length="3" LuminousIntensity="0" Mass="0"

Temperature="0" Time="-1"/>

<Unit ConversionFactorToSI="1" Description="" ID="m3/s"

OffSetToSI="0" />

</TargetQuantity>

</Link>

</Links>

<TimeStepping End="46097" Start="46066" Step="10800" />

<Trigger Type="org.OpenMI.Examples.MC.SimpleRiver"

Assembly="C:\OpenMI\Examples\MC\org.OpenMI.Examples.MC.DLL"

File="..\data\SimpleRiver.omi" />

</Composition>

为了确保文件及其内容的有效性,需要创建 XML计划表格(在配置包技术文档中给出

Page 74: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

72

了详细说明),使用这个计划表格,确保一个合适的配置对象能被实例化和移植,文件在解释中应是有效的。 以下代码提供了如何装载一个合成体,并将其保存。

// -Create LinkableComponents -

//... see hardcoded example ...

// Reads composition from file

Composition MyComposition = (Composition) XMLFile.GetRead (new

FileInfo("mycomposition.XML"));

// -alternative: Create Composition -

//Composition MyComposition = new Composition();

// -Add LinkableComponents to Composition -

MyComposition. AddModel(MyRiverModel);

MyComposition.AddModel(MyRRModel);

MyCompositon.AddModel(MyRainModule);

// -Create Links -

//..... see hardcodedexample ...

// -Add Links to Composition -

MyComposition. AddLink(triggerLink);

// Composition updates internal administration,

// calls MyRiverModel.AddLink(triggerLink)

// and calls trigger.AddLink(triggerLink);

MyComposition.AddLink(LinkRainToCatchm);

// Composition updates internal administration,

// calls MyRainModule.AddLink(LinkRainToCatchm)

// and calls MyRRModel.AddLink(LinkRainToCatchm)

MyComposition.AddLink(LinkRunoffToInflow);

// Composition updates internal administration,

// calls MyRRModel.AddLink(LinkRunoffToInflow)

// and calls MyRiverModel.AddLink(LinkRunoffToInflow)

// -Create and add Time information –

TimeStepping MyTimeInfo = new TimeStepping();

MyTimeInfo.Start = 46066.0; //01011985

MyTimeInfo.End = 46097.0; //01021985

myTimeInfo.Step = 60; // 60 seconds

MyComposition.timeStepping = MytimeInfo;

// -Assigning the trigger -MyComposition.

Trigger = MyRiverModel;

// -Write Composition to file -XMLFile.

Write (MyComposition, new FileInfo("mycomposition.XML");

3.4.3 分发和运行系统分发和运行系统分发和运行系统分发和运行系统 为了运行集成后的模型集,可以使用分发器组件,分发器的任务有:实例化连接组件,对连接组件提供初始化方,在所有的连接组件中调用 AddLink 方法,通过对连接组件调用

Page 75: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

73

一个或多个 GetValues方法用于准备组件,结束开始计算/数据传输;分发器也是负责连接相互之间的事件生成器和事件监听器,事件监听器能包括一个值或事件日志的图形演示,在模拟完成后,分发器对所有的连接组件调用 Finalize方法。 更有益的是分发器组件被设计成在不关心是否有用户接口的情况同样能进行操作,作为输入的组件对象,下列函数是必须的: “Create”建立一个在内存中移植组件:方法是在实例化后使用 Initialize 和 AddLinks函数; “Start”和“Stop”运行计算处理:其方法包括 Prepare、GetValues和 Finish; “Pause”和“Resume”在计算处理时从外部中断:当需要时捕获事件并掌握/返回控制权; 信息处理函数,如果没有处理成功将返回消息给用户。 当执行这些函数时应注意 OpenMI 被设计为数据传输处理是在相同的线程中(如GetValues调用堆栈)完成,然而,这并不意味着连接组件需要在相同的线程下执行计算。 在标准文档用了多种方式介绍停止、暂停或重新计算的内容,在 3.2.5 节描述了应用于管理处理的时间步循环,不能解决的表述,将最终在分发中弹出,通过用户接口提供人工处理方法。

OpenMI环境下的分发器组件可使用图 3-13的函数来描述其设计。

图 3-13 OpenMI实用配置包中的分发类

图 3-14 提供了怎样分发合成体的代码处理方法,由于分发器在事件循环中捕获事件,能简单地通过调用 Pause方法暂定(或终止)计算。

// precondition: the MyCompositionobject is available

// this example communicates with the user via a consoleobject

// -Validate composition -

If (!MyComposition.Validate().Equals(""))

{

Console.Write ("Composition cannot be run: ");

Console.WriteLine (MyComposition.Validate());

Wait();

return;

}

SystemDeployer

+ SystemDeployer()

+ «property» Composition() : Composition

+ «property» Blocking() : bool

+ «property» Paused() : bool

+ «property» Running() : bool

+ Create(composition :Composition) : void

+ Start() : void

+ Stop() : void

+ Pause() : void

+ Resume() : void

+ Dispose() : void

Page 76: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

74

// -Create system deployer -

SystemDeployer MyDeployer = new SystemDeployer();

MyDeployer.Blocking = true;

// -Assign Composition -

MyDeployer.Create (MyComposition);

// -Start Computation -

//Composition will run for period as indicated in timestepping object

try

{

MyDeployer.Start();

}

catch (Exception e)

{

// raise exception

Console.WriteLine (e.Message);

Wait();

return;

}

以下代码提供了用于从命令行运行合成体的函数完整代码。

using System;

using System.IO;

using org.OpenMI.Utilities.Configuration;

using org.OpenMI.Utilities.Configuration.XML;

using org.OpenMI.Standard;

using org.OpenMI.DevelopmentSupport;

namespace org.OpenMI.Configuration.RunOpenMI

{

/// <summary>

/// Console application to run an OpenMI composition from the command line

/// </summary>

class RunOpenMI

{

private static bool _wait = false;

/// <summary>

/// Console application for running an OpenMI composition

/// </summary>

[STAThread]

static void Main(string[] args)

{

if (args.Length == 0)

{

Console.WriteLine ("Usage : RunOpenMI <file> [-wait]");

Page 77: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

75

Console.WriteLine ("");

Console.WriteLine ("<file> = full path to XML file containing

composition");

Console.WriteLine ("-wait

= After run application waits to

terminate until user presses <Enter>");

Console.WriteLine ("");

_wait = true;

Wait();

return;

}

for (int i = 1; i < args.Length; i++)

{

if (args[i].Equals ("-wait"))

{

_wait = true;

}

}

// -Check file availability -

FileInfo file = new FileInfo (args[0]);

if (!file.Exists)

{

Console.WriteLine ("File {0} not found", file.FullName);

Wait();

return;

}

// -Initialize XMLparser-

XMLConfiguration.Initialize();

// -Parse XML file -

Object fileObject;

try

{

fileObject = XMLFile.GetRead (file);

}

catch (Exception e)

{

Console.WriteLine (e.Message);

Wait();

return;

}

if (!(fileObject is Composition))

{

Console.WriteLine ("File {0} does not contain a composition",

file.FullName);

Page 78: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

76

Wait();

return;

}

// -Create Compositionobject from file and validate composition -

Composition composition = (Composition) fileObject;

if (!composition.Validate().Equals(""))

{

Console.Write ("Composition cannot be run: ");

Console.WriteLine (composition.Validate());

Wait();

return;

}

// -Create Deployerobject and assign composition to be deployed -

SystemDeployer deployer = new SystemDeployer();

deployer.Blocking = true;

try

{

deployer.Create (composition);

}

catch (Exception e)

{

Console.WriteLine (e.Message);

Wait();

return;

}

// -Start Computation -

Console.WriteLine ("Starting composition {0}", file.FullName);

try

{

deployer.Start();

}

catch (Exception e)

{

Console.WriteLine (e.Message);

Wait();

return;

}

Console.WriteLine ("Finished composition {0}", file.FullName);

Wait();

}

private static void Wait()

{

if (_wait)

{

Page 79: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

77

Console.WriteLine ("Press <Enter> to continue");

int key = Console.Read();

}

}

}

}

3.5 图形用户接口图形用户接口图形用户接口图形用户接口 可视工具帮助完成配置阶段工作,可视工具可单独运行,它是非常简单成熟的完全嵌入在软件产品的默认环境中,更好的工具要能够支持前面所提到的所有配置步骤。

OpenMI 已经从可视工具独立出来采用了这种方法完成所有功能,org.OpenMI.Tools 命名空间仅包括可视窗口命名,其他命名空间不含可视窗口,这点从本书的代码例子也可知。 然而,可视工具是组件配置、分发、可视化的便捷助手,这部分内容简要讨论如何连接用户接口至合成体,另外,再讨论集成到 OpenMI环境的用户接口。

3.5.1 建立可视工具建立可视工具建立可视工具建立可视工具

org.OpenMI.Utilities.Configuration 包是按照可采用多种方式重用方法开发的,当然OpenMI环境可视工具不是强迫要求使用的。 首先,以 XML文件存放的一个默认合成体,能作为活动模型运行模板使用。在默认合成体中包含了一系列软件单元,软件单元指向 OMI文件和可能的默认连接列表,连接列表为数据和要素集提供了默认名称(如侧向入流),例如,在图 3-11中的合成体文件可作为一个模板,OMI文件中的典型属性能用于初始化,及系统地决定要素集相关的计算点。 一个默认合成体能为你的代码提供一个好的开始点,使用代码可以增加或删除组件、修改输入数据引用、修改连接及时间步信息。如,用代码管理情景决定是直接适应基于用户选择的合成体,在图 3-12和 3.4.2节代码实际是操作合成体代码例子可选方式。

3.5.2 OmiEd,OpenMI环境简单前端工具环境简单前端工具环境简单前端工具环境简单前端工具

OpenMI 提供了两种配置编辑器,第一个 OpenMI 配置编辑器是使用基于描述信息的org.OpenMI.Utilities.Configuration包。 第二个编辑器是使用开源方式的 OmiEd,已经正式作为可直接使用的工具,图 3-16 显示了简单的 OmiEd 界面,这个轻量级工具更多依赖对连接组件运行时的检查功能,相关的配置文件(图 3-17)具有更好的可读性。

Page 80: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

78

图 3-16 OpenMI环境中简单前端工具

<guiComposition version="1.0">

<models>

<model omi="D:\openmidemo\omi\SobekRRhills.omi" rect_x="30" rect_y="30"

rect_width="100" rect_height="51" />

<model omi="D:\openmidemo\omi\SobekCFriver_remote.omi" rect_x="231"

rect_y="33" rect_width="100" rect_height="51" />

<model omi="org.OpenMI.Tools.GUI.Trigger" rect_x="436" rect_y="59"

rect_width="100" rect_height="51" />

</models>

<links>

<uilink model_providing="RRD:\openmidemo\data\sobekrrhills\sobek_3b.fnm"

model_accepting="CFD:\openmidemo\data\sobekcfriver\sobeksim.fnm">

<link id="1" source_elementset="RRBoundaries"source_quantity="Flow"

target_elementset="Laterals" target_quantity="Discharge" />

</uilink>

<uilink model_providing="CFD:\openmidemo\data\sobekcfriver\sobeksim.fnm"

model_accepting="org.OpenMI.Tools.GUI.Trigger">

<link id="2" source_elementset="HBoundaries" source_quantity="Discharge"

target_elementset="TriggerElementID" target_quantity="TriggerQuantityID" />

</uilink>

</links>

<runproperties listenedeventtypes="11111111111" triggerinvoke="1/2/2000 12:00:00

Page 81: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

79

AM" runinsamethread="0" showeventsinlistbox="1" logfilename="CompositionRun.log" />

</guiComposition>

Page 82: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

80

第四章第四章第四章第四章 移植移植移植移植 OpenMI 模型模型模型模型

4.1 概要概要概要概要 虽然将模型引擎改为OpenMI标准连接组件面临巨大挑战,但似乎也没想象得那么困难,因为 OpenMI环境中提供了大量的软件工具使得移植变得更容易,这些工具能用在任何被移植的模型,当然,仅为了遵从 OpenMI标准,并不是一定要使用这些工具。实用工具可以全部或选择部分使用,可以将这些工具作为你自己工具库的基础部分。 这章假设你需要使用 OpenMI工具完成所有移植任务,将从 OpenMI组件需求定义、设计、测试等一步一步介绍整个移植过程。 该部分内容将描述建立 OpenMI标准组件的要求,并通过介绍简单河流模型说明移植过程。

4.1.1 OpenMI标准标准标准标准

OpenMI 标准具体要求在接口文档(org.OpenMI.Standard 接口标准)中给出,OpenMI工具关心的是标准协议中的大量要求。 要满足标准有三部分基本要求: (1)组件必须执行 org.OpenMI.Standard.ILinkableComponent接口,如图 4-1。

Page 83: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

81

图 4-1 ILinkableComponent 接口 (2)组件必须与包含分发信息的 XML文件相关联,XML文件如连接组件格式,如图4-2。

图 4-2 连接组件 XML文件图解 (3)组件必须能按照图前一章 3-3所示的顺序处理相应的方法。

«interface»

org.OpenMI.Standard::IPublisher

+ Subscribe(listener :IListener, eventType :EventType) : void

+ UnSubscribe(listener :IListener, eventType :EventType) : void

+ SendEvent(Event :IEvent) : void

+ GetPublishedEventTypeCount() : int

+ GetPublishedEventType(providedEventTypeIndex :int) : EventType

«interface»

org.OpenMI.Standard::ILinkableComponent

+ Initialize(properties :IArgument[]) : void

+ «property» ComponentID() : string

+ «property» ComponentDescription() : string

+ «property» ModelID() : string

+ «property» ModelDescription() : string

+ «property» InputExchangeItemCount() : int

+ GetInputExchangeItem(inputExchangeItemIndex :int) :

IInputExchangeItem

+ «property» OutputExchangeItemCount() : int

+ GetOutputExchangeItem(outputExchangeItemIndex :int) :

IOutputExchangeItem

+ «property» TimeHorizon() : ITimeSpan

+ AddLink(link :ILink) : void

+ RemoveLink(linkID :string) : void

+ Validate() : string

+ Prepare() : void

+ GetValues(time :ITime, linkID :string) : IValueSet

+ «property» EarliestInputTime() : ITimeStamp

+ Finish() : void

+ Dispose() : void

Page 84: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

82

4.1.2 简单河流例子简单河流例子简单河流例子简单河流例子 使用一个简单河流模型引擎作为模型移植例子,该模型使用 Fortran 编写,是个非常简单概念河流模型。 如图 4-3所示,简单河流模型包括节点和支流,每一时间步的每一节点的入流从边界输入条件文件获取,依照时间步长对流量数据处理并存入每个节点,从上游端点开始,水流向下游节点,并对每个支流的流量计算。

图 4-3 简单河网 这个简单河流引擎从三个输入文件读入数据,包括河流节点的入流(边界文件)、模拟周期时间步长(模拟文件)及河网结构(网络文件),如图 4-4。

图 4-4 简单河流计算输入输出文件 该简单河流模型的源代码、相关的打包文件及用于模型移植测试类在 www.OpenMI.org均可获取。

4.2 计划移植计划移植计划移植计划移植 在开始移植模型前,清楚当模型作为 OpenMI标准组件运行时倾向于如何使用是非常重要的,需要考虑在任何情形下使用该模型与其它 OpenMI标准组件连接,这些组件可以是其它模型、数据提供者、优化工具或校正工具,甚至在同一个配置中对该移植模型使用两次模型实例。 该节介绍在计划模型移植中的方法,包括使用实例开发及交换项定义。

边界文件 模拟文件 河网文件 简单河网引擎 输出文件

Page 85: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

83

4.2.1 应用实例应用实例应用实例应用实例 应用实例(软件使用的例子)在软件开发中经常使用,定义应用实例没有规定的形式要求。然而,使得应用实例不同于一般例子的原因在于应用实例具有更详细及更好的定义,最重要的是应用实例必须是简洁明确的,在软件开发完成后能够明确应用实例是否需要。应用实例较大的益处在于软件开发者和使用者都能容易地理解其内容。 在开发处理开始,需要定义大量的应用实例,应用实例仓库的实例随时都能在各方面反应出软件开发的目标,这点是很重要的。如果应用实例不能执行则应进行修改或移除。 下面给出两个移植简单河流模型的实例,应用实例给出如何一步一步使用模型的过程。 4.2.1.1 应用实例应用实例应用实例应用实例 1::::连接其它河流连接其它河流连接其它河流连接其它河流 在这实例中,简单的河流模型用于连接其它 OpenMI标准河流模型,如图 4-5。

图 4-5 简单河流模型连接其它河流模型

前提条件: ・ 在模型用户 PC机器中已经安装了 OpenMI简单河流模型; ・ 模型用户有简单河流模型的有效输入文件; ・ 模型用户有 OpenMI配置用户接口; ・ 模型用户有另一个 OpenMI标准河流模型(包括所要求的数据文件)。 成功的保证(后期条件): ・ 所有模型产生出正确结果。 主要成功场景: (1)模型用户加载 OpenMI GUI至计算机中; (2)模型用户使用 GUI浏览有效的连接组件; (3)模型用户找到简单河流模型的 OMI文件及 OMI文件对应的其它河流模型; (4)模型用户加载两个文件(组件)至 GUI; (5)模型用户建立从其它河流模型的下游节点至简单河流模型的上游节点的单向及具有 ID的连接;

Page 86: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

84

(6)模型用户为连接选择输入输出交换项(简单河流模型的入流是输入数据); (7)模型定义模拟周期; (8)模型运行模拟。 对应用实例提供可交换流程图属于对实例的外延,这里从第 5 步还可分为两个可选过程。 第一个可选过程是: (5)模型用户建立从简单河流模型的下游支流至其它河流模型的上游节点的单向及具有 ID的连接; (6)模型用户为连接选择输入输出交换项(简单河流模型的入流是输出数据); (7)模型定义模拟周期; (8)模型运行模拟。 第二个可选过程是: (5)模型用户建立从其它河流模型的下游支流至简单河流模型的内部节点的单向及具有 ID的连接; (6)模型用户为连接选择输入输出交换项(简单河流模型的入流是输入数据); (7)模型定义模拟周期; (8)模型运行模拟。

4.2.1.2 应用实例应用实例应用实例应用实例 2::::从地理特征集水数据获取入流从地理特征集水数据获取入流从地理特征集水数据获取入流从地理特征集水数据获取入流 在第二个应用实例中,简单河流模型入流从一个 OpenMI标准径流数据库中获取,如图4-6。

图 4-6 简单河流模型从区域计算模型中获得入流 前提条件 ・ 模型用户在计算机中安装了 OpenMI标准的简单河流模型; ・ 在模型用户计算中已经有了有效的简单河流模型输入文件; ・ 模型用户计算机中已经安装了 OpenMI配置用户接口; ・ 模型用户有 OpenMI标准径流数据库(包括需要的数据文件)。 成功保证(后条件) ・ 所有模型均有正确结果输出。

Page 87: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

85

主要成功环节: (1)模型用户加载 OpenMI GUI至 PC中; (2)模型用户使用 GUI浏览有效的连接组件; (3)模型用户找到简单河流模型的 OMI文件; (4)模型用户为径流数据库找到 OMI文件; (5)模型用户加载两个文件(组件)至 GUI; (6)模型用户建立一个从径流数据库至简单河流模型所有支流输入交换项的单向地理引用连接; (7)模型用户为连接选择输入输出交换项(简单河流入流输入数据); (8)模型用户定义模拟周期; (9)模型用户运行模拟。 注意,特定多边形径流分配至河流支流多少取决于支流包含于多边形内的大小,边界条件类型是水汇集点,在原先的简单河流模型引擎是不存在的,这简单河流引擎扩展了该特征(作为移植的结果),仅是因为这样的边界条件在 OpenMI环境下变得也可能存在。

4.2.2 定义交换项定义交换项定义交换项定义交换项 交换项集成了关于什么被交换及交换项应用位置信息,一个输入交换项可以定义流量在节点接收或支流接收,一个输出交换项可定义流量在支流被提供,数据 ID定义了交换的内容(如流量)和要素集 ID定义了数据应用位置(如节点 1)。 下一步是定义输入输出交换项,如表 4-1给出了运行应用实例所要的交换项。

表 4-1 实例 1实例 2中需要交换的数据项

ElementSet.ID 类型类型类型类型 Quantity.ID 单位单位单位单位 输入输入输入输入 输出输出输出输出 应用例子应用例子应用例子应用例子 支流 0 Polyline Flow m3/s No Yes 1 支流 1 Polyline Flow m

3/s No Yes 1 支流 2 Polyline Flow m

3/s No Yes 1 节点 0 IDBased Inflow m

3/s Yes No 1 节点 1 IDBased Inflow m

3/s Yes No 1 节点 2 IDBased Inflow m

3/s Yes No 1 节点 3 IDBased Inflow m

3/s Yes No 1 支流 0 Polyline Inflow m

3/s Yes No 支流 1 Polyline Inflow m

3/s Yes No 支流 2 Polyline Inflow m

3/s Yes No 所有支流 Polyline Inflow m

3/s Yes No 2

通常交换项不应限制于特定网络,但是为了移植计划目的,从特定的实例开始会简单些,且当得到更多的设计细节后总结这些实例会有更好效果。

4.3 打包打包打包打包

OpenMI标准的设计允许较容易完成模型移植工作,该标准可在.NET 框架下的 C#语言执行,几乎所有存在的模型引擎可使用其它语言执行,如 Fortran、Pascal、C和 C++,为了

Page 88: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

86

在不同的技术间建立桥梁并通过最小的变更实现,需要建立在大多数案例均有效的引擎核心打包模式。 这节内容描述了打包处理过程及 OpenMI环境提供通用包。

4.3.1 基本打包模式基本打包模式基本打包模式基本打包模式 打包基本意味着建立能执行连接组件接口的 C#类,包是与模型引擎内部会话并对用户而言是个“黑盒子”,所有的会话操作均通过接口发生。

图 4-7 OpenMI打包模式 使用包模式更有利的一面是可以保持 OpenMI标准的执行与模型引擎分开,典型的是引擎可作为 OpenMI不在的地方单独应用,通常是比采用其他方法的引擎更有益于使用,这意味着即使是建立新的模型引擎使用包模式同样是最好的选择。

4.3.2 连接引擎连接引擎连接引擎连接引擎 以时间步为基础的计算模型引擎通常具有较多的事件,因而开发一个通用包供这些引擎使用是必要的,这个包称为连接引擎,位于 org.OpenMI.Utilities.Wrapper包中,连接引擎提供了连接组件接口默认的执行方式,通常,连接引擎不清楚模型引擎的具体特征,这些信息可通过引擎接口获得。 当使用连接引擎时建议使用模型引擎移植设计模式,如图 4-8所示,该设计中有下列一些类:

MyEngineDLL类是编译过的内核引擎代码(如 Fortran);

MyEngineDLLAccess类是用于从MyEngineDLL到.NET(C#)转换的Win32API; 调用约定和表达处理在.NET和 Fortran是不同的,MyEngineDotNetAccess类保证这些操作遵循.NET约定;

MyEnginewrapper类执行 IEngineAccess接口,可以被 LinkableEngine类访问;

MyLinkableEngine 类负责 MyEngineWrapper 类创建及在连接引擎类中分配引用这个类保护域变量。 关于这些类的更多细节在接下的几节说明。

OpenMI 标准提供了许多约定处理连接组件,主要思想是当 GetValues 方法在提供组件调用时必须能处理被请求值,以便这些值应用于请求时间和请求位置,为了能处理连接组件可能需要内插、外延或在时间和空间合并处理,这些和其它事件由连接引擎处理。 连接引擎类包括下列特征: 缓冲区(Buffering):当模型运行于 OpenMI 环境可能请求模型当前时间的前一时间的值,许多模型将仅保存当前时间步和前一时间步在内存中,这就需要存储与 OpenMI连接相关的数据于缓冲区中,连接引擎可处理这些缓冲区; 实时内插和外插(Temporal interpolation and extrapolation):许多模型是仅能传输与内部时间步相一致的结果,连接引擎类可处理连接组件要求的实时操作; 空间操作(Spatial operations):连接引擎提供空间数据操作范围; 连接书签(Link book-keeping):连接引擎为组件增加连接处理书签; 时间操作(Event handling):连接引擎发出事件以便运行时监听事件能监视连接系统处

Page 89: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

87

理过程。 关于连接引擎工作的更多细节在 org.OpenMI.Utilities技术文档中说明。

4.4 一步一步操作一步一步操作一步一步操作一步一步操作移植移植移植移植 移植模型最好的办法是将处理过程分为若干步进行,在每一步结束时可编译代码并运行测试。这节介绍移植步骤。

4.4.1 步骤步骤步骤步骤 1::::改变引擎核心改变引擎核心改变引擎核心改变引擎核心 移植目的是开发一个能执行 IEgine接口的类,如图 4-8。执行 IEgine接口的类被其它类和引擎 DLL支持。

图 4-8 打包类及引擎内核 DLL 模型引擎常编译成执行文件(EXE),这种执行文件不能被其他组件对其内部访问,也不适应在 OpenMI环境运行,因而需要将引擎编译成动态连接库形式(DLL)。 理想情况应使得引擎既可在 OpenMI环境下运行又能在独立的应用程序下使用,同样的引擎保留两个版本将导致不必要的维护工作增加,因而,应使得新应用(EXE)调用引擎内核 DLL函数,并确保引擎能完成所有模拟任务。 图 4-9 描述了需要作为独立应用运行引擎的软件,这个 SimpleRiverApplication.EXE 文件是不会运行在 OpenMI环境的。

Page 90: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

88

图 4-9 独立应用的运行引擎 需要以下步骤完成该引擎核心转换: 改变引擎核心编译成 DLL; 增加需要运行全部模拟的函数至引擎核心:logical function RunSimulation(); 建立一个引擎应用(EXE)用于从主程序调用引擎核心 DLL的 RunSimulation函数; 通过分发引擎应用运行引擎并检查直至引擎产生正确的结果。 当引擎运行在 OpenMI环境时必须能初始化,完成单个时间步、结束及作为独立操作布置,这意味着引擎核心需要重新组织,在满足用逻辑方法建立的四个函数下可以使用任意方式实现:

Logical function initialize();(打开文件及用初始数据实例化引擎)

Logical function PerformTimeStep(); (完成单个时间步)

Logical function Finish();(关闭文件)

Logical function Dispose(); (释放内存)

RunSimulation函数应改变为可调用 Initialize函数,然后重复 PerformTimeStep函数直到模拟结束,最后调用 Finish、Dispose函数。 对此需要再次运行应用程序,并测试引擎,确保仍是产生正确的结果。 现在需完成对引擎的重构,剩下的修改工作是使得引擎变得更小,修改是否顺利依赖于指定的引擎。至此,可开始建立打包代码了。

4.4.2 步骤步骤步骤步骤 2::::创建创建创建创建.NET配件配件配件配件 下一步是建立打包类,如图 4-10,在这步,需要确保 OpenMI环境已安装在计算中。

Page 91: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

89

图 4-10 执行 C#打包类 加载.NET开发环境,创建打包类配件,建议同时创建相应的测试类配件。 在打包配件中常使用下列命名习惯: 配件名:MyOrganisation.OpenMI.MyModel 配件 DLL名:MyOrganisation.OpenMI.MyModel.DLL 命名空间:MyOrganisation.OpenMI.MyModel 类 名 : MyModelEngineWrpper 、 MyModelEngineDotNetAccess 、MyModelEngineDLLAccess、MyModelLinkableComponent; 测试配件常使用的命名习惯: 配件名:MyOrganisation.OpenMITest.MyModel 配件 DLL名:MyOrganisation.OpenMITest.MyModel.DLL 命名空间:MyOrganisation.OpenMI.MyModel 类 名 : MyModelEngineWrpperTest 、 MyModelEngineDotNetAccessTest 、MyModelEngineDLLAccessTest、MyModelLinkableComponentTest; 至此可安装 NUnit测试软件(参见 4.6节) 对于打包配件需增加下列引用:

org.OpenMI.Standard

org.OpenMI.BankBone

org.OpenMI.Utilities.Wrapper 测试配件需增加下列引用:

org.OpenMI.Standard

org.OpenMI.BankBone

org.OpenMI.Utilities.Wrapper

NUnit.framework

MyOrganisation.OpenMI.MyModel 建立配件和类后,就可对第一个类MyEngineDLLAccess工作了,在下节进行介绍。

Page 92: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

90

4.4.3 步骤步骤步骤步骤 3::::访问引擎内核函数访问引擎内核函数访问引擎内核函数访问引擎内核函数 第三步是执行MyEngineDLLAccess类,如图 4-11。

图 4-11 执行MyEngineDLLAccess类 因使用 C#执行 OpenMI,需要确保引擎能从.NET访问,实现以上模式需在两个包操作:MyEngineDLLAccess、MyEngineDotNetAccess。MyEngineDLLAccess 类一步一步完成将所有在引擎内核代码的输出函数转为公共.NET方法,MyEngineDotNetAccess类修改一些调用习惯。

MyEngineDLLAccess 类的特定执行方式依赖于所使用的编译器,通过 Initialize、

PerformTimeStep、 Finish、Dispose函数的导出方法开始执行。 图 4-12 显示了简单河流 Fortran 引擎执行例子,注意这执行是与特定 Fortran 编译相适应的,在不同编译器语法可能不同。

Page 93: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

91

图4-12 执行简单河网模型Fortran引擎

4.4.4 步骤步骤步骤步骤 4::::执行执行执行执行MyEngineDotNetAccess 如图 4-13,第四步是执行MyEngineDotNetAccess类。

using System;

using System.Runtime.InteropServices;

using System.Text;

namespace MyOrganisation.OpenMI.MyModel

{

public class MyEngineDLLAccess

{

[DLLImport(@’C:\MyEngine\bin\MyEngine.DLL’,

EntryPoint = ‘INITIALIZE’,

SetLastError=true,

ExactSpelling = true,

CallingConvention=CallingConvention.Cdecl)]

public static extern bool Initialize(string filePath, uint length);

[DLLImport(@’C:\MyEngine\bin\MyEngine.DLL’,

EntryPoint = ‘PERFORMTIMESTEP’,

SetLastError=true,

ExactSpelling = true,

CallingConvention=CallingConvention.Cdecl)]

public static extern bool PerformTimeStep();

[DLLImport(@’C:\MyEngine\bin\MyEngine.DLL’,

EntryPoint = ‘FINISH’,

SetLastError=true,

ExactSpelling = true,

CallingConvention=CallingConvention.Cdecl)]

public static extern bool Finish();

}

}

Page 94: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

92

图 4-13 执行MyEngineDotNetAccess类

MyEngineDotNetAccess 类有两个目的,即改变调用方式为 C#形式及将出错消息转为.NET处理形式。 图 4-14 给出简单河流模型例子的 MyEngineDotNetAccess 类,包括 Initialize、

PerformTimeStep、Finish方法,在 MyEngineDotNetAccess类中每个相应的方法被调用,如果返回错误,从引擎发出的错误消息通过 GetMessage 方法取得查询(意外处理被创建并抛出消息)。 注意 MyEngineDLLAccess 类没有实例化,在该类的所有方法都是静态的,并可通过引用类进行访问(使用的例子较简单,并不是所有的 DLL输入语句都是这样)。 通常 Fortran DLL一般是通过函数返回值(通过引用验证确定有效性),C#结果通过值验证。因而,需要明确表达 C#参数指向的经引用验证 Fortran规测;在 Fortran中索引常是从 1开始,而在 C#中习惯从 0开始,这些不同处在MyEngineDotnetAccess类中处理。 当完成下面显示的方法执行时,可建立并运行相应的测试类并运行单元测试。

Page 95: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

93

图 4-14 MyEngineDotNetAccess类代码

4.4.5 步骤步骤步骤步骤 5::::执行执行执行执行MyEngineWrapper类类类类 第五步是执行MyEngineWrapper类,如图 4-15。

using System;

using System.Text;

namespace MyOrganisation.OpenMI.MyModel

{

public class MyEngineDotNetAccess

{

public void Initialize(string filePath)

{

if(!(MyModelDLL.Initialize(filePath, ((uint)

filePath.Length))))

{

CreateAndThrowException();

}

}

public void PerformTimeStep()

{

if(!(MyModelDLL.PerformTimeStep()))

{

CreateAndThrowException();

}

}

public void Finish()

{

if(!(MyModel.Finish()))

{

CreateAndThrowException();

}

}

private void CreateAndThrowException()

{

int numberOfMessages = 0;

numberOfMessages = MyModelDLL.GetNumberOfMessages();

string message = ‘Error Message from MyModel ‘;

for (int i = 0; i < numberOfMessages; i++)

{

int n = i;

StringBuilder messageFromCore

= new StringBuilder(‘ ‘);

MyModelDLL.GetMessage(ref n, messageFromCore,

(uint) messageFromCore.Length);

message +=‘; ‘;

message += messageFromCore.ToString().Trim();

}

throw new Exception(message);

}

}

}

Page 96: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

94

图 4-15 执行MyEngineWrapper类

MyEngineWrapper 类 必 须 执 行 ILinkableEngine 接 口(org.OpenMI.Utilities.Wrapper.ILinkableEngine),获得执行最容易方法是使得开发环境自动生成这个接口代码。 第一步是执行 Initialize和 Finish方法。

MyEngineWrapper 有私有变量(_myEngine)利用引用指向 MyEngineDotNetAccess 类,Initialize方法将实例化MyEngineDotNetAccess对象,并分配引用对象给_myEngine变量。 如图 4-16给出这些示例代码。

图 4-16 MyEngineWrapper类代码示例

4.4.6 步骤步骤步骤步骤 6::::执行执行执行执行MyModelLinkableComponent 第六步是执行MyModelLinkableComponent类,如图 4-18。

using System;

using System.Collections

namespace MyOrganisation.OpenMI.MyModel

{

public class MyEngineWrapper : org.OpenMI.Utilities.Wrapper.IEngine

{

private MyEngineDotNetAccess _myEngine;

public void Initialize(Hashtable properties)

{

_myEngine = new MyEngineDotNetAccess();

_myEngine.Initialize((string)properties[‘FilePath’]);

}

public void Finish()

{

_simpleRiverEngine.Finish();

}

}

}

Page 97: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

95

图 4-17 执行MyLinkableEngine类

MyModelLinkableComponent 是 OpenMI 标准连接组件,可被其他模型访问,执行这个类非常简单,图 4-18给出了完整的执行简单河流模型例子。

图 4-18 简单河流模型完成执行代码 这个类从 LinkableEngine 类继承,建立了 EngineWrapper 函数并分配给保护变量_engineApiAccess。

4.4.7 步骤步骤步骤步骤 7::::执行其余的执行其余的执行其余的执行其余的 IEngine方法方法方法方法 至此,引擎基本结构及打包代码已完成,目前任务是测试 MyEngineWrapper 类和完善当前自动生成的代码执行方法,这些方法中有些仅能通过改变 MyEngineWrapper 类代码完成,有些还需要修改其他类和引擎核心(MyEngineDLL),完成每个方法后需要更新测试类并运行单元测试。 对于每个方法必须确定是否需要大量执行位于MyEngineWrappe类或引擎内核的代码,对于该问题没有统一标准。将大量执行置于引擎内核可能有利于修改维护,因为有大量的事件位于同一地方;而另一方面,需要保持引擎内核尽可能与 OpenMI关联代码一样自由,而

using System;

namespace MyOrganisation.OpenMI.MyModel

{

public class MyModelOpenMIComponent :

org.OpenMI.Utilities.Wrapper.LinkableEngine

{

protected override void SetEngineApiAccess()

{

_engineApiAccess = new MyEngineWrapper();

}

}

}

Page 98: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

96

将大量的执行置于 MyEngineWrapper 类中;最后,考虑到程序完整性,引擎内核可能是Fortran、C或 Pascal程序,需将MyEngineWrapper类改为 C#程序。 执行 IEngine接口依赖引擎内核,对于单个方法应如何执行给不出一个基本解释,不过,通过下节介绍的 IEngine接口用于执行简单河流模型,可帮助理解相关方法的处理过程。图4-19给出了 IEngine接口。

图 4-19 IEngine接口

4.5 简单河流模型移植简单河流模型移植简单河流模型移植简单河流模型移植 前面介绍了移植模型至 OpenMI标准的步骤,这节细说开发简单河流(Simple River)模型移植代码例子。

4.5.1 简单河流模型包简单河流模型包简单河流模型包简单河流模型包 简单河流模型(Simple River)使用的移植模式如图 4-8所示,图 4-20给出了简单河流模型包中的打包类更细的工作方式。

//== The org.OpenMI.Utilities.Wrapper.IEngine interface ==

// -Execution control methods (Inherited from IRunEngine) -

Void Initialize(Hashtable properties);

bool PerformTimeStep();

void Finish();

//-Time methods (Inherited from IRunEngine) -

ITime GetCurrentTime();

ITime GetInputTime(string QuantityID, string ElementSetID);

ITimeStamp GetEarliestNeededTime();

//-Data access methods (Inherited from IRunEngine) -

Void SetValues(string QuantityID, string ElementSetID, IValueSet values);

IValueSet GetValues(string QuantityID, string ElementSetID);

//-Component description methods (Inherited from IRunEngine) -

Double GetMissingValueDefinition();

string GetComponentID();

string GetComponentDescription();

// -Model description methods -

String GetModelID();

string GetModelDescription();

double GetTimeHorizon();

// -Exchange items -

Int GetInputExchangeItemCount();

int GetOutputExchangeItemCount();

org.OpenMI.Backbone GetInputExchangeItem(int exchangeItemIndex);

org.OpenMI.Backbone GetOutputExchangeItem(int exchangeItemIndex);

Page 99: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

97

图 4-20 简单河网模型打包类

4.5.2 执行执行执行执行 Initialize方法方法方法方法

SimpleRiverEngineWrapper有两个私有域变量:

Arraylist _inputExchangeItems;

org.OpenMI.Utilities.Wrapper.LinkableEngine

SimpleRiv erOpenMIComponent

+ SimpleRiverOpenMIComponent()

# SetEngineApiAccess() : void

SimpleRiverEngineDllAccess

org.OpenMI.Utilities.Wrapper.IEngine

SimpleRiverEngineWrapper

-_simpleRiverEngine: SimpleRiverEngineDotNetAccess

-_simulationStartTime: double

-_inputExchangeItems: ArrayList

-_outputExchangeItems: ArrayList

+ SetValues(QuantityID :string, ElementSetID :string, values :org.OpenMI.Standard.IValueSet) : void

+ GetMissingValueDefinition() : double

+ GetTimeHorizon() : org.OpenMI.Standard.ITimeSpan

+ GetCurrentTime() : org.OpenMI.Standard.ITime

+ GetValues(QuantityID :string, ElementSetID :string) : org.OpenMI.Standard.IValueSet

+ GetComponentID() : string

+ GetComponentDescription() : string

+ GetModelID() : string

+ GetModelDescription() : string

+ Finish() : void

+ Dispose() : void

+ GetEarliestNeededTime() : org.OpenMI.Standard.ITimeStamp

+ Initialize(properties :System.Collections.Hashtable) : void

+ PerformTimeStep() : bool

+ GetInputTime(QuantityID :string, ElementSetID :string) : org.OpenMI.Standard.ITime

+ GetInputExchangeItemCount() : int

+ GetOutputExchangeItemCount() : int

+ GetOutputExchangeItem(exchangeItemIndex :int) : OutputExchangeItem

+ GetInputExchangeItem(exchangeItemIndex :int) : InputExchangeItem

SimpleRiverEngineDotNetAccess

+ AddInflow(index :int, inflow :double) : void

+ Initialize(filePath :string) : void

+ Finish() : void

+ GetCurrentTime() : double

+ GetModelDescription() : string

+ GetFlow(index :int) : double

+ GetModelID() : string

+ GetInputTime() : double

+ GetNumberOfNodes() : int

+ GetSimulationStartDate() : string

+ GetXCoordinate(nodeIndex :int) : double

+ GetYCoordinate(nodeIndex :int) : double

+ PerformTimeStep() : void

+ GetTimeStepLength() : double

+ GetNumberOfTimeSteps() : int

-CreateAndThrowException() : void

+ AddInflow(index :int, inflow :double) : bool

+ Initialize(filePath :string, length :uint) : bool

+ Finish() : bool

+ GetCurrentTime(time :double) : bool

+ GetModelDescription(description :StringBuilder, length :uint) : bool

+ GetSimulationStartDate(simulationStartDate :StringBuilder, length :uint) : bool

+ GetFlow(index :int, flow :double) : bool

+ GetModelID(id :StringBuilder, length :uint) : bool

+ GetInputTime(inputTime :double) : bool

+ GetMessage(index :int, message :StringBuilder, length :uint) : void

+ GetNumberOfNodes(numberOfNodes :int) : bool

+ GetXCoordinate(index :int, xCoordinate :double) : bool

+ GetYCoordinate(index :int, yCoordinate :double) : bool

+ GetNumberOfMessages() : int

+ PerformTimeStep() : bool

+ GetTimeStepLength(timeStepLength :double) : bool

+ GetNumberOfTimeSteps(numberOfTimeSteps :int) : bool

-_simpleRiverEngine

Page 100: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

98

ArrayList _outputExchangeItem;

_inputExchangeItems 是 org.OpenMI.Backbone.InputExchangeItem 对 象 列 表 ,_outputExchangeItems是 org.OpenMI.Backbone.OutputExchangeItem对象列表,这些列表数组在初始化(Initialize)方法中实例化。 简单河流包必须满足在 4.2.1 节描述应用实例定义的要求,这意味着输入输出交换项是基于表 4-1列表条目。 在 SimpleRiverEngineWarpper执行初始化方法的源代码如下。

public void Initialize(System.Collections.Hashtable properties)

{

_inputExchangeItems = new ArrayList(); //ArrayList of

org.OpenMI.Backbone.InputExchangeItem objects

_outputExchangeItems = new ArrayList(); //ArrayList of

org.OpenMI.Backbone.OutputExchangeItem objects

// -

Create and initialize the engine -_

simpleRiverEngine = new SimpleRiverEngineDotNetAccess();

_simpleRiverEngine.Initialize((string)properties[‘FilePath’]);

// -

Simulation start time –

// The start time is obtained from the engine core as a string. This string is

// passed and converted to a System.DateTime. Then the

// org.OpenMI.DevelopmentSupport.CalendarConverter class is used to convert

// this time into the ModifiedJulianDay (this is the OpenMI standard time)

char [] delimiter = new char[]{'-','',':'};

string[] strings = _simpleRiverEngine.GetSimulationStartDate().Split(delimiter);

int StartYear = Convert.ToInt32(strings[0]);

int StartMonth = Convert.ToInt32(strings[1]);

int StartDay = Convert.ToInt32(strings[2]);

int StartHour = Convert.ToInt32(strings[3]);

int StartMinute = Convert.ToInt32(strings[4]);

int StartSecond = Convert.ToInt32(strings[5]);

DateTime startDate = new DateTime(StartYear,StartMonth,StartDay,StartHour,

StartMinute,StartSecond);

_simulationStartTime = org.OpenMI.DevelopmentSupport.CalendarConverter.

Gregorian2ModifiedJulian(startDate);

// -

Build exchange items -Dimension

flowDimension = new Dimension();

Unit flowUnit = new Unit(‘m3/sec’,1,0,’m3/sec’); //The Simple River only uses

// quantities with the unit m3/sec.

Quantity flowQuantity = new Quantity(flowUnit,’description’,’Flow’,

org.OpenMI.Standard.ValueType.Scalar,flowDimension);

Quantity inFlowQuantity = new Quantity(flowUnit,’description’,’InFlow’,

org.OpenMI.Standard.ValueType.Scalar,flowDimension);

Page 101: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

99

int numberOfNodes = _simpleRiverEngine.GetNumberOfNodes();

for (int i = 0; i < numberOfNodes -1;

i++) //For each branch

{

OutputExchangeItem flowFromBranch = new OutputExchangeItem();

InputExchangeItem inFlowToBranch = new InputExchangeItem();

// One ElementSet is created for each branch. The ElementID’s are

// Branch:<Branch number>. E.g. ‘Branch:3’

ElementSet branch = new ElementSet(‘description’,’Branch:’ +i.ToString(),ElementType.XYPolyLine,new

SpatialReference(‘ref’));

branch.AddElement(new Element(‘Branch:’ + i.ToString()));

branch.Elements[0].AddVertex(new

Vertex(_simpleRiverEngine.GetXCoordinate(i),_simpleRiverEngine.GetYCoordinate(i),0));

branch.Elements[0].AddVertex(new

Vertex(_simpleRiverEngine.GetXCoordinate(i+1),_simpleRiverEngine.GetYCoordinate(i+1),0));

flowFromBranch.ElementSet = branch;

flowFromBranch.Quantity = flowQuantity;

inFlowToBranch.ElementSet = branch;

inFlowToBranch.Quantity = inFlowQuantity;

_outputExchangeItems.Add(flowFromBranch);

_inputExchangeItems.Add(inFlowToBranch);

}

for (int i = 0; i < numberOfNodes; i++) //For all nodes

{

InputExchangeItem inflowToNode = new InputExchangeItem();

// Each node is a IDbased

ElementSet. The ElementSet ID are

// Node:<node number>. E.g. ‘Node:3’

ElementSet node = new ElementSet(‘description’,’Node:’ +i.ToString(),ElementType.IDBased,new

SpatialReference(‘ref’));

node.AddElement(new Element(‘Node:’ + i.ToString()));

inflowToNode.Quantity = inFlowQuantity;

inflowToNode.ElementSet = node;

_inputExchangeItems.Add(inflowToNode);

}

ElementSet Branches = new ElementSet(‘description’,’AllBranches’,

ElementType.XYPolyLine,new SpatialReference(‘ref’));

for (int i = 0; i < numberOfNodes -

1;i++) //Create an InputExchangeItem that

// has all branches in one ElementSet

{

Element branch = new Element(‘Branch: ‘ + i.ToString());

branch.AddVertex(new Vertex(_simpleRiverEngine.GetXCoordinate(i),_simpleRiverEngine.GetYCoordinate(i),0));

branch.AddVertex(new

Page 102: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

100

Vertex(_simpleRiverEngine.GetXCoordinate(i+1),_simpleRiverEngine.GetYCoordinate(i+1),0));

Branches.AddElement(branch);

}

InputExchangeItem inFlowToBranches = new InputExchangeItem();

inFlowToBranches.ElementSet = Branches;

inFlowToBranches.Quantity = inFlowQuantity;

_inputExchangeItems.Add(inFlowToBranches);

从执行初始化方法可看出,有些方法需要执行 MyEngineDotNetAccess 类、MyEngineDLLAccess类和引擎核心。 在下面图 4-21 描述当初始化方法调用时与其他类的通信关系,EngineDLL 不在该图表中,是由于在 EngineDLL 和 EngineDLLAccess 类存在一对一会话,即每次调用EngineDLLAccess方法相应的会调用 EngineDLL方法。

图 4-21 初始化调用顺序 注意没有 DataOperations(数据操作)增加到 OutputExchangeItems(输出交换项)中,LinkableEngine 类将通过增加空间和实时数据操作至 OutputExchangeItems 来完成OutputExchangeItems赋值,当然还可以增加自己的数据操作。

Page 103: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

101

4.5.3 执行执行执行执行 SetValues方法方法方法方法

SetValues方法调用顺序如图 4-22所示。

图 4-22 SetValues方法执行顺序

Enginewrapper类所完成的内容由 QuantityID和 ElementSetID决定,在简单河流模型引擎核心只能有一个变量承担输入,它存储节点的水信息,对简单河流模型中入流作为增加流量解释,即入流已经从其它源接收(边界入流),而不必重写。入流被增加至当前存储节点,水流向信息决定 ElementSetID及节点数量。 如果入流是走向支流,水增加至每个支流下游节点,如果是流向节点,水可简单增加至节点,在移植模型中理解 QuantityID 和 ElementSetID 的角色是非常重要的。对于每个ExchengeItem需要定义 ElementSetID和 QuantityID,当用户使用模型配置系统时这些 ID包含在连接中,当系统运行时,在 GetValues方法中调用相同的 ElementSetID和 QuantityID将返回模型组建,组建将使用这些信息导航至正确的引擎变量。 可以使用任意约定方法命名这些 ID,在简单河流模型中 ElementSetID,支流使用约定为:〈支流:编号〉或“所有支流”(如‘Branch:3’,QuantityID为‘Flow’和‘Inflow’。 4.5.4 执行执行执行执行 GetValues方法方法方法方法 对 IEngine接口 GetValues方法实现的部分源代码如图 4-23所示。

图 4-23 GetValues方法代码 支流编号从 ElementSetID中获取,使用GetValues索引调用 SimpleRiverDotnetAccess类。

public org.OpenMI.Standard.IValueSet GetValues(string QuantityID, string ElementSetID)

{

double[] returnValues;

Char[] separator = new char[]{':'};

if (QuantityID == ‘Flow’)

{

int index = Convert.ToInt32((ElementSetID.Split(separator))[1]);

returnValues = new double[1];

returnValues[0] = _simpleRiverEngine.GetFlow(index);

}

else

{

throw new Exception(‘Illegal QuantityID in GetValues method in

SimpleRiverEngine’);

}

Page 104: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

102

GetValues方法调用顺序如图 4-24所示。

图 4-24 GetValues方法调用顺序

4.5.5 执行其余的方法执行其余的方法执行其余的方法执行其余的方法 执行 IEgine接口中的其余方法不太复杂,在图 4-25顺序中可以看到每个方法是如何访问其它类包的。

Page 105: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

103

图 4-25 简单河网执行顺序 在图 4-25 中不包括图 4-21、图 4-22、图 4-24 的方法调用顺序,注意在SimpleRiverEngineWrapper 类中完整地执行一些方法,在 SimpleRiverDotNetAccess 类中GetCurrentTime,、GetInputTime 、GetEarliestNeededTime方法均在 GetCurrentTime调用,返回时间是引擎当地时间,这时间在 SimpleRiverEngineWrapper 中转化为 ModifiedJulianTime如图 4-26。

图4-26 时间转换代码

public org.OpenMI.Standard.ITime GetCurrentTime()

{

double time = _simulationStartTime + _simpleRiverEngine.GetCurrentTime() /

((double)(24*3600));

return new org.OpenMI.Backbone.TimeStamp(time);

}

Page 106: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

104

4.6 测试测试测试测试组件组件组件组件 检查组件是否能正常工作,对其测试是非常重要的。传统方式是在完成编制后,运行引擎检查结果是否正确。然而,近年来一些新的方法应用到测试中,面向对象程序主要测试方法是单元测试法,单元测试法是在运行中平行进行,这样有助于发现错误后,为及时修改代码节省时间。这节将讨论移植组件测试。

4.6.1 单元测试单元测试单元测试单元测试 在此叙述的测试过程是假设你已经有了 NUnit 测试工具,该工具及类库可通过http://www.NUnit.org 下载,并可从该网站中获得更多有关 NUnit 信息。首先,需要为每个打包类创建测试类,在测试类中为每个公共方法执行测试。 这部分介绍针对 OpenMI的测试,在 NUnit主页中给了更多的单元测试信息。 在 4.4.2节中介绍了如何创建测试脚本,简单河网例子的测试类使用如图 4-29所示。

图 4-29 简单河网模型打包和测试类 该图描述了打包类和测试类之间的一一对应关系,其中 SimpleRiverEngineDLLAccess、UseCaseTests. 两 个 类 没 有 测 试 类 , 因 为 SimpleRiverEngineDLLAccess 类 方 法 在SimpleRiverEngineDotNetAccess 类 都 有 相 应 的 方 法 调 用 , 因 而 测 试SimpleRiverEngineDotNetAccess类所有方法即可。 单元测试的主要思想是使用简单的代码测试类的每个方法,然而,也可是使用更好的测

访问

访问 访问

访问

-_simpleRiverEngine

SimpleRiverOpenMIComponentTest

SimpleRiverEngineWrapperTest

SimpleRiv erEngineDotNetAccessTest

UseCaseTests

org.OpenMI.Utilities.Wrapper.LinkableEngine

Wrapper::SimpleRiv erOpenMIComponent

org.OpenMI.Utilities.Wrapper.IEngine

Wrapper::SimpleRiverEngineWrapper

Wrapper:: SimpleRiv erEngineDotNetAccess

Wrapper::SimpleRiverEngineDllAccess

Page 107: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

105

试办法去运行全部的模拟过程,这些在 UseCaseTests类完成了,这个类确保在 4.2.1描述的实例运行不出错。 同前面所描述一样,通过执行 IEngine接口实现模型集成,对MyEngineWrapper类的每个 IEngine方法你选择决定是否在打包类需要执行,你将执行的这些方法或函数需在引擎核心中,并执行相应的MyEngineDLLAccess类和MyEngineDotNetAccess类的方法。每次你完成这些方法后,可在 MyEngineDotNetAccessTest 类创建测试方法并运行单元测试,然后执行MyEngineAccess的方法及相关的测试。 图 4-30包括简单河网模型的 GetModelID方法的示例测试代码,图 4-31为 NUnit界面。

图4-30 简单河网模型的GetModelID方法

using System;

using org.OpenMI.Examples.ModelComponents.SimpleRiver.Wrapper;

using NUnit.Framework;

namespace org.OpenMITest.Examples.ModelComponents.SimpleRiver.Wrapper

{

[TestFixture]

public class SimpleRiverEngineDotNetAccessTest

{

[Test]

public void GetModelID()

{

SimpleRiverEngineDotNetAccess _simpleRiverEngineDotNetAccess;

String _filePath;

_simpleRiverEngineDotNetAccess = new SimpleRiverEngineDotNetAccess();

_filePath = ‘C:\\SimpleRiver\\UnitTest\\Data\\Rhine’;

_simpleRiverEngineDotNetAccess.Initialize(_filePath);

Assert.AreEqual(‘The river Rhine’,

_simpleRiverEngineDotNetAccess.GetModelID());

_simpleRiverEngineDotNetAccess.Finish();

}

}

}

Page 108: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

106

图4-31 加装简单河网打包类的NUnit界面

4.7 实现实现实现实现 IManageState 接口接口接口接口 调用 OpenMI组件并不一定需要执行 IManageState接口,然而,如果所使用的模型需多次执行配置或需要校正和优化控制器时,是需要该接口的。正常情况下,应该将这些执行方法放在引擎核心,并将需要的数据存储以便从内存加载。

4.7.1 IManageState接口接口接口接口

IManageState接口执行界面见图 4-32所示。 连接引擎类已经执行了 IManageState接口需要的方法,但这些并不是执行 IManageState接口专用的方法。 使用连接引擎时执行 IManageState接口顺序如下: (1)在MyLinkableEngine中指定要执行的 IManageState接口; (2)在MyEngineWrapper中执行要执行的 IManageState接口; (3)在所有打包类中执行 IManageState 方法,执行过程较简单并有一定代表性,可重定向至下一个打包类,在引擎核心中完成,也就是执行过程代码所在处。

Page 109: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

107

图 4-32 IManageState执行过程

4.8 OMI 文件结构文件结构文件结构文件结构

OMI 文件用于定义连接组件的进入点,包含了软件单元实例化及参量初始信息,这个文件使得用户接口可执行你的模型。这部分介绍 OMI文件内容。

OMI文件结构在 org.OpenMI.Standared.LinkableComponent.XSD中给出了格式定义。图4-33提供了可视的图表定义,图 4-34提供了 OMI文件例子。

Page 110: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

108

图 4-33连接组件 XML文件定义图表

图 4-34连接组件 XML文件例子

4.9 模型移植模式模型移植模式模型移植模式模型移植模式设计设计设计设计 在 HarmonIT项目中有许多软件包移植成 OpenMI形式,这部分给出每个案例移植处理简要过程。

4.9.1 ISIS移植模式移植模式移植模式移植模式设计设计设计设计

ISIS是明渠设计系统模型包,包括环流、支流、洪泛区、蓄洪区等。软件集成了通用公式和构建堰、水闸、桥梁、管路、泵站、弯管、洞孔及河口等模型技术,还提供了移动结构的逻辑控制,系统能完全模拟不稳定模式或全稳定状态模拟。 不需要任何其它工具就可直接从 OpenMI 的连接组件中得到 ISIS 的打包类,这意味者ISIS打包类本身可操作连接处理、插值、缓冲及空间映射。因为这是 HarmonIT项目中的 ISIS打包类第一个版本,且在其它工具开发之前实施,为此,当设计打包类时,决定使得 ISIS

Fortran代码最优化且是采用 C#写的最好的打包函数。ISIS设计模式如图 4-35所示。

<?XML version=‘1.0’?>

<LinkableComponent Type=‘org.OpenMI.Examples.MC.SimpleRain’ Assembly=

‘org.OpenMI.Examples.MC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=

8384b9b46466c568’ XMLns=‘http://www.openmi.org/LinkableComponent.xsd’>

<Arguments>

<Argument Key=‘Data’ ReadOnly=‘true’

Value=‘c:\OpenMI\Examples\Data\SimpleRain.txt’ />

</Arguments>

</LinkableComponent>

Page 111: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

109

图 4-35 ISIS设计模式 从图可知 FortranWrapper不是严格必需的,ISISWrapper能与 Fortran代码直接会话。然而,这将意味着所有的代码不得不运行一个过程,象许多 Fortran程序,ISIS有大量的全局变量,这些变量只能有一个实例同时运行,不可能去连接两个 ISIS模型,并使得 Fortran代码在同一过程中。为了解决该问题,FortranWrapper 能运行不同 ISISWrapper 过程,并使得连接多个 ISIS模型成为可能。在 ISISWrapper和 FortranWrpper之间会话采用.NET调用,且任何内部会话机制都能被使用。

4.9.2 InfoWorks RS移植模式移植模式移植模式移植模式设计设计设计设计

InfoWorks RS是一维河网模型软件包,集成 ISIS河流模拟模型、地理信息系统和关系数据库于单一环境中。InfoWorks RS使用测量和时间系列数据进行详细和准确的模拟,包括了明渠、洪泛区、堤防及水力学结构模拟解决方案,降雨产流模拟是基于事件和水力学方法概念实现,模型所需数据均可通过地理信息及图形界面输入。 通过 OpenMI运行 RS模型需要以下三步实现: (1)从 RS中获得输入输出量; (2)为模型运行 RS引擎,设置及获得所需的量; (3)输入结果给 RS。

RS C++代码必须修改以便提供函数给第一步和第三步操作使用,这些函数通过从LinkableRunEngine继承的 RSLinkableRunEngine类调用。

RS引擎 Fortran代码也必须修改以便引擎运行初始及结束操作时间步集合,修改其它函数以便能从 DLL调用,RSRunEngine执行 IRunEngine接口,它是用于打包 RS引擎及调用的接口。 使用.NET 在 RSLinkableRunEngine 创建 RSRunEngine 对象,以便 RS 在内部运行,这要求在同时运行两个连接的 RS 模型时,RS 引擎内部全局变量不产生冲突。InfoWorks RS设计模式如图 4-36所示。

Page 112: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

110

图 4-36 InfoWorks RS设计模式

4.9.3 Mike11移植模式设计移植模式设计移植模式设计移植模式设计

Mike11是个模型系统,包括了许多水力学河流模型管理功能,Mike11主要组件是: 一维水动力学河流河网模型; 一维河网水平面离散模型; 一维河网水质模型; 一维河网沉积转播及形态变迁模型; 八种内置的区域降雨产流模型; 从简单的管道至堰坝的一套结构控制及大坝断裂结构破损模拟模型。

Mike11引擎代码采用面向对象设计语音 Delphi编写。Mike11组件移植已经编写入打包模 式 包 含 于 org.OpenMI.Utilities.Wrapper 中 , 包 括 org.OpenMI.Utilities.Buffer 和org.OpenMI.Utilites.Spatial两个包,其模式见图 4-37所示。

Page 113: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

111

图 4-37 Mike11设计模式

移植是通过打包Mike11生成 COM对象,接口类似 IEngine,COM接口是围绕Mike11本身主要类再次打包,COM接口、COM包及Mike11主要类均采用 Delphi编写,逻辑上对于 TMike11类没有Mike11专用代码,因而完成移植不需要变换Mike11引擎核心逻辑。 表 4-2和表 4-3包含了可用的量和要素集。 表 4-2 可交换的量和要素集

量量量量 要素要素要素要素 角色角色角色角色 产流 所有的流量点 支流的流量点 单个流量点 产流边界

输入、输出

水位 所有水位点 输入、输出

«interface»

ILinkableComponent

LinkableEngine

Mike11LinkableComponent

«interface»

IEngine

«interface»

M11EngineAccess

Mike11Engine

TStateManaged

TMike11

Mike11COMServ

«interface»

IManagedState

«interface»

IManagedState

实例化

实例化

实例化

实例化

实例化

Page 114: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

112

支流水位点 单个水位点 水位边界 相应序号 所有的水位点 支流水位点 单个水位点

输入、输出 地下水基流 速度 表面坡度 断面面积 断面宽 半径 传输 序号 水位坡度 能量水平 能量水平坡度 河床压力 容积

所有的水位点 支流水位点 单个水位点

输出

入流系数 所有的水位点 支流水位点 单个水位点 边界点

输入

地下水位 所有的水位点 支流水位点 单个水位点

输入 专用控制结构的时间系列 单个流量点 表 4-3 量和要素集 量量量量 要素集要素集要素集要素集 角色角色角色角色 产流 净降雨

每个区块的 ID 输出

4.9.4 SOBEK移植模式设计移植模式设计移植模式设计移植模式设计

SOBEK 模型系统主要内容是强大的水力学计算引擎,集成了管流计算、明渠计算及溢流计算等组件。可支持实时系统控制、降雨产流处理、水质处理、沉积传输及形态变迁等分析。因所有的模型是WL Delft水力学研究所采用 Fortran90开发,开发解决方案能很容易应用到所有引擎。 类结构如图 4-38 所示,这个设计模式基于前面的 OpenMI 开发阶段的 C#格式,WLExchangeModel操作输入输出交换,及通过WLModel类相互作用的模型系统,功能集成于 ILinkableEngine接口。

Page 115: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

113

图 4-38 移植 SOBEK引擎的类结构

WLEngineAPIAccess类执行 IRunEngine接口,并提供 F90代码和 OpenMI包之间的数据运行交换,图 4-39描述主要方法及 F90引擎模块与打包类之间交换处理。

Page 116: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

114

图 4-39 打包类、中间缓存及引擎之间主要交换

4.10 完成移植的其它问题完成移植的其它问题完成移植的其它问题完成移植的其它问题 影响模型移植至 OpenMI工作完成,需要注意的主要有内存消耗及系统处理问题。

4.10.1 内存消耗内存消耗内存消耗内存消耗 当在一台计算机上运行连接后的模型集时,多个模型同时在内存,并且全面计算时间是单个模型计算的总时间,实现这种并行计算是重要的。因而使得单个模型尽量消耗更少的内存是至关重要,当大量内存被程序使用,超过计算机物理内存数量时,计算机开始在内存与硬盘之间来回处理,产生抖动,这将使得系统非常慢,并可能导致系统崩溃。

4.10.2 系统处理系统处理系统处理系统处理 虽然所有连接组件运行在同一个系统处理,实际计算能在同一处理或不同处理执行,最好是在同一运行处理计算,因为在处理之间会话是处理内部会话耗时的百倍。然而,处理内部会话不是每次都能实现,尤其在 Fortran 代码有许多全局变量时是如此,因而没有比运行Fortran代码分开处理更好的方法。

Page 117: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

115

第五章第五章第五章第五章 非模型组件非模型组件非模型组件非模型组件

5.1 桌面及数据库应用软件桌面及数据库应用软件桌面及数据库应用软件桌面及数据库应用软件 前面几章讨论了 OpenMI环境中模型系统使用,虽然连接模型是 OpenMI标准的首要目标,但 OpenMI也不排斥连接其它系统,如在线测量系统、数据库系统、决策支持系统等也能使用 OpenMI接口实现相互连接或与模型连接。

OpenMI 接口设计目的是促进组件之间数据交换,并不一定是模型组件,只要符合OpenMI标准就可运行在 OpenMI环境中。这章将介绍可能遇到的 OpenMI标准不同类型执行应用软件。

5.1.1 ASCII文件文件文件文件 模型系统输入经常包含简单的 ASCII 文件,这些文件需要进行一定的打包以适合OpenMI标准系统的数据需要。 例如,你可以对一个组件的输出文件打包以便适合另一个组件的输入要求,当这样的文件打包后,使用通用的方法可被任何其它 OpenMI组件访问。对打包后的输出文件测试,可很容易地使用需要输入这些文件的 OpenMI组件进行,也可直接使用数据运行组件,并不一定需要经过其它组件传输。 为了遵循 OpenMI 标准,组件需要遵照两个接口,即 IPulisher 和 ILinkableComponent接口,同样读取 ASCII 文件也需要遵照这些接口;象模型系统一样,可以从org.OpenMI.Utilities.Wrapper.LinkableEngine继承并执行相应的方法。 打包 ASCII文件与模型组件使用之间的不同在于执行交换项(GetOutputExchangeItem)和 GetValues调用,在模型组件中,交换项通过移植的模型内核提供,当打包 ASCII文件,交换项信息必须包含于 ASCII文件本身。

Page 118: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

116

图 5-1 ASCII文件例子 图 5-1给出的 ASCII文件例子中,有四行说明语句,后面接着是指定量和三个地点值,这些信息可使用 OutputExchangeItems定义,定义格式如下:

OutputExchangeItem[0] = { “Flow”, “Loc1”}

OutputExchangeItem[1] = { “Flow”, “Loc2”}

OutputExchangeItem[2] = { “Flow”, “Loc3”} 执行一个采用ASCII文件输入的OpenMI标准连接组件并通过输出交换项实现获得文件内容需要以下几步: (1)首先采用 org.OpenMI.Utilities.Wrapper.LinkableEngine开发组件; (2)编写函数方法,如 Initialize, Finalize, GetModelID 和 GetModelDescription等; (3)编写 SetValues, GetInputExchangeItem 和 GetInputExchangeItemCount方法代码,因为 ASCII读取不需接收数据,因而这些方法是空的。 (4)编写 GetOutputExchangeItem代码,使得 ASCII文件能被读到,从文件中获得交换项,定义输出交换项 (5)编写 GetValues 方法,确保被调用的时间步、交换项从 ASCII 文件获得正确的数据

GetOutputExchangeItem源代码如下所示。

public IOutputExchangeItem GetOutputExchangeItem(int outputExchangeItemIndex)

{

return _output;

}

// Lines starting with // are comment

// The first uncommented line defines the quantity

// The second uncommented line defines the locations

// All next lines consist of a timestamp and values of the quantity for each location

"Flow"

"Loc1";"Loc2";"Loc3"

"2005-01-01 00:00";"15.4";"18.2";"22.4"

"2005-01-01 03:00";"15.3";"18.5";"22.5"

"2005-01-01 06:00";"15.4";"18.9";"22.4"

"2005-01-01 09:00";"15.2";"19.0";"22.6"

"2005-01-01 12:00";"15.1";"18.8";"22.7"

"2005-01-01 15:00";"14.8";"18.6";"22.9"

"2005-01-01 18:00";"14.7";"18.4";"23.4"

"2005-01-01 21:00";"14.7";"18.2";"23.8"

"2005-01-02 00:00";"14.6";"18.2";"23.9"

"2005-01-02 03:00";"14.1";"18.1";"24.0"

"2005-01-02 06:00";"13.8";"18.2";"23.5"

"2005-01-02 09:00";"13.9";"18.0";"23.6"

"2005-01-02 12:00";"13.6";"17.8";"23.5"

"2005-01-02 15:00";"13.2";"17.3";"23.3"

"2005-01-02 18:00";"12.8";"17.4";"23.2"

"2005-01-02 21:00";"12.7";"17.2";"23.1"

"2005-01-03 00:00";"12.6";"17.2";"22.9"

"2005-01-03 03:00";"12.1";"16.8";"22.7"

"2005-01-03 06:00";"12.2";"16.6";"22.5"

"2005-01-03 09:00";"11.4";"16.5";"22.4"

"2005-01-03 12:00";"11.6";"16.4";"22.2"

"2005-01-03 15:00";"11.7";"16.3";"21.8"

Page 119: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

117

private void ReadFile()

{

StreamReader reader = new StreamReader(_inputFile);

bool quantityRead = false;

bool elementsRead = false;

_timeStamps.Clear();

_elementValues.Clear();

string line;

while ((line = reader.ReadLine()) != null)

{

if (line.StartsWith("//"))

{

// ignore

}

else if (!quantityRead)

{

_quantity = new Quantity(line.Trim(' ', '"'));

_output = new OutputExchangeItem();

_output.Quantity = _quantity;

quantityRead = true;

}

else if (!elementsRead)

{

string[] elements = line.Split(';');

_elementSet = new ElementSet();

_elementSet.ID = "File Contents";

_output.ElementSet = _elementSet;

for (int i = 0; i < elements.Length; i++)

{

_elementSet.AddElement (new Element(elements[i].Trim('"')));

}

elementsRead = true;

}

else

{

string[] values = line.Split(';');

DateTime timestamp = Convert.ToDateTime (values[0].Trim('"'),

_culture);

double modifiedJulianDateTime =

CalendarConverter.Gregorian2ModifiedJulian (timestamp);

double[] locationValues = new double[values.Length -1];

for (int i = 1; i < values.Length; i++)

{

locationValues[i -1] = Convert.ToDouble (values[i].Trim('"'),_culture);

Page 120: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

118

}

_timeStamps.Add (modifiedJulianDateTime);

_elementValues.Add (locationValues);

}

}

}

GetValues方法源代码如图 5-2所示。

图 5-2 GetValues方法例子

5.1.2 电子表格电子表格电子表格电子表格 有许多方法连接电子表格应用软件,如连接 Excel,这部分讨论一些实现方法。

5.1.2.1 生成生成生成生成 ASCII文件文件文件文件 连接电子表格的一种方法是修改OpenMI数据监测器通过重定向能被桌面系统读取的输出文件,例如带逗号分隔的 CSV格式可被 Excel读取。

5.1.2.2使用微软办公系统的使用微软办公系统的使用微软办公系统的使用微软办公系统的 Visual Studio工具访问工具访问工具访问工具访问 Excel 使用办公系统的可视工具可访问工作文档,如 Word 或 Excel,下面例子给出一种方法是从 Visual Studio .NET 2003生成输出数据至 Excel,即 Excel文档。 就像Microsoft Visual Studio .NET 2003 和 Microsoft Office 2003一样,必须为微软办公系统安装 Visual Studio Tools。 第一步是在项目中创建引用指向 Excel x.x对象库(版本因安装Microsoft Office不同而

public IValueSet GetValues(ITime time, string linkID)

{

ILink outgoingLink = (Link) _links[linkID];

if (outgoingLink == null)

{

throw new Exception ("Unknown link or quantity");

}

if (time is TimeStamp)

{

TimeStamp timestamp = (TimeStamp) time;

double[] results;

for (int i = 0; i < _timeStamps.Count; i++)

{

if ( (double)_timeStamps[i] + _delta > timestamp.ModifiedJulianDay)

{

results = (double[]) _elementValues[i];

return new ScalarSet(results);

}

}

throw new Exception ("No appropriate values found");

}

throw new Exception ("Time should be of type TimeStamp");

}

Page 121: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

119

异),鼠标右击解决方案管理器的文件夹,选择引用,选择 COM标签,然后选出 Microsoft

Excel x.x Object Library (如图 5-4)。

图5-4 添加Excel引用 在这个例子中,便于生成 MS-Excel 文档,数据监测器应用被修改,其操作同前一节修改数据监测器方法相同(OpenMI.Tools.Datamonitor.csproj)。代码分别如下:

� 增加“using”语句

� 定义工作簿、工作表等

using System;

using System.Windows.Forms;

using org.OpenMI.Standard;

using org.OpenMI.Backbone;

using System.Diagnostics;

using org.OpenMI.DevelopmentSupport;

using org.OpenMI.Tools.DataMonitor;

using System.Collections;

using System.Threading;

using System.Reflection;

using System.Runtime.InteropServices;

using Excel=Microsoft.Office.Interop.Excel;

Page 122: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

120

� 增加代码初始化方法,创建工作簿、工作表

� 修改数据监测器的OnEvent代码,写数据值至各工作表

namespace riza.OpenMI.Tools.DataMonitorPlus

{

/// <summary>

/// The DataMonitorPlus class

/// </summary>

public class DataMonitorPlus:LinkableComponent, IListener

{

private Excel.Application ExcelObj = new Excel.Application();

private Excel.Workbook _workbook;

private Excel.Sheets _sheets;

private Excel.Worksheet _sheet;

if (ExcelObj == null)

{

throw new Exception("Excel object not loaded");

}

// Make Excel object visible and

// add a workbook to populate

ExcelObj.Visible=true;

_workbook = ExcelObj.Workbooks.Add(Type.Missing);

// Get the sheets collection from the workbook

_sheets =_workbook.Worksheets;

// Get the first (and only) sheet

_sheet = (Excel.Worksheet)_sheets.get_Item(1);

Page 123: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

121

定义电子表格各部分内容是费时的工作,Excel可使用范围方式实现,如(A1:C1);在我们例子中这样的范围通过基于行号和子项位置数组 ValueSet(B3:B3)创建每个值。 这些代码展示了如何在.NET代码中集成实现 Excel文档,在通过保存 Excel文档至指定文件并关闭文件后,至此,输出任务完成。

5.1.3 报表引擎报表引擎报表引擎报表引擎 通过开发集成于.NET 环境的报表引擎 OpenMI 标准工具生成报表,可自定义输出以下

/// <summary>

/// OnEvent

/// </summary>

/// <param name="Event">Event</param>

public static int rownumber;

public void OnEvent (IEvent Event)

{

ILink[] links = GetAcceptingLinks();

Excel.Range range;

foreach (ILink link in links)

{

if (link.SourceComponent==Event.Sender)

{

IValueSet values =

Event.Sender.GetValues(Event.SimulationTime,link.ID);

if (values is IScalarSet)

{

IScalarSet scalarSet = (IScalarSet)values;

string[] subitems = new string[4+scalarSet.Count];

subitems[0] =

CalendarConverter.ModifiedJulian2Gregorian(

Event.SimulationTime.ModifiedJulianDay).

ToString();

subitems[1] = Event.Sender.ModelID;

subitems[2] = link.SourceQuantity.ID;

subitems[3] = link.SourceElementSet.ID;

rownumber++; // need rownumber in sheet

for (int i=0;i<scalarSet.Count;i++)

subitems[i+4] =

scalarSet.GetScalar(i).ToString();

ListViewItem item = new ListViewItem(subitems);

_form.listView1.Items.Add(item);

// write all cells to next row in Excel Worksheet

for (int i=0;i<scalarSet.Count;i++)

{

char rangeChar = (char)(i+65);

string strCell = rangeChar +

Convert.ToString(rownumber);

range = _sheet.get_Range(strCell,strCell);

range.Value2=subitems[i];

}

}

}

}

}

Page 124: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

122

工业标准的报表: ・ Adobe Acrobat (.pdf) ・ Crystal for Visual Studio .NET (.rpt) ・ HTML 3.2 and 4.0 (.html) ・ Microsoft Excel (.xls) ・ Microsoft Rich Text (.rtf) ・ Microsoft Word (.doc)

5.1.4 数据库数据库数据库数据库 与 ASCII读取器一样,使用该方法可将数据库中的数据输出至 OpenMI环境,即修改交换项内容及 GetValues 调用的方法,另外,通过 SetValues 调用可将数据写入数据库中。通过 SQL语句也可实现。

5.1.4.1 访问数据库访问数据库访问数据库访问数据库 在 OpenMI 中,进行数据传递的组件为了请求时间步的需要而返回数据集,每次GetValues请求都要初始化处理,像许多与水相关的模型一样,以时间步为周期的处理过程,时间参数是所有处理活动的控制变量。不是在时间步处理的连接组件可忽略时间参数,它们也能处理请求并返回数据;然而,如果通过 GetValues函数内部调用,它们必须能传送时间参数给其它组件。 如果在计算中请求的时间与时间步不配备,并且计算已经在前面,那么一个内插值必须提供。如果计算仍没达到计算请求时间,则有两种选择: ・计算请求时间的值 ・外推解决 正常情况下选择第一种情况处理,对于双向连接,组件之一需要外延以免出现死循环。 在时间步中不需及时处理的组件,如数据库,也应能返回一个内插或外延值,不管是否处于活动状态。这种处理方法在处理准确时间信息是需要的,OpenMI 提供了额外的接口(IDiscrete Times)用于提供获得离散时间游标,可选择执行这个接口处理时间。

5.1.4.2 使用使用使用使用 ADO.NET访问数据库访问数据库访问数据库访问数据库 在.NET环境中提供了类用于访问不同的数据库(MS Access、SQL-Server、Oracle),在SetValues函数中编写代码保存数据至数据库的开发并不难,其步骤如下: (1)连接至SQL Server数据库(如图5-5)

图5-5 连接至SQL Server (2)处理SQL命令

// C#

this.sqlConnection1 = new System.Data.SqlClient.SqlConnection();

this.sqlConnection1.ConnectionString = "data source=riz02\\NETSDK; " +

"initial catalog=OpenMI;" +

"user id=User;password=Open;" +

"persist security info=True; " +

"workstation id=riz02; " +

"packet size=4096";

Page 125: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

123

图5-6 处理SQL命令 这个例子是访问 SQL Server 数据库,在.NET 环境中提供了许多访问数据的类,包括MS Access等。

5.1.5 GIS 地理信息系统(GIS)在处理模型输入及输出处理与展示均有广泛应用,在这节给出一些建议怎样连接 GIS系统至 OpenMI组件。

5.1.5.1 通过软件库访问通过软件库访问通过软件库访问通过软件库访问 GIS 许多 GIS系统支持功能集成于客户开发包。如 ESRI GIS软件套件,开发者能根据功能需要选择使用MapObjects或 ArcObjects。MapObjects软件库功能可实现在.NET环境中展现地图,使用具有完整 GIS功能的 ArcObjects(是一个独立平台)内嵌至客户应用系统也是可行的,如嵌入OpenMI组件应用系统。因而,使用这些库可以建立包括全部GIS功能的OpenMI标准组件。

5.1.5.2 通过通过通过通过 ASCII文件访问文件访问文件访问文件访问 GIS 在 GIS环境中生成(或输入)ASCII文件,是 OpenMI组件和 GIS系统之间实现数据交换的一个非常容易方法,以下给出两个例子。 从从从从 GIS输出数据至输出数据至输出数据至输出数据至 ASCII文件文件文件文件 从 GIS系统输出数据至 ASCII文件,使用在 5.1.1讨论的 ASCII阅读器工具,你能将这文件包含在 OpenMI组件中。

ArcInfo是 GIS系统之一,图 5-7展示了 ArcInfo的 AML代码的三个量集成在一个网格,通过其中的一个量“krwdeelstr”排序,并输出表至逗号分隔的 ASCII文件。

//

// SQL command Select

//

this.sqlSelectCommand.CommandText = " select * from measurement";

this.sqlSelectCommand.Connection=this.sqlConnection1;

//

// SQL command Insert

//

this.sqlInsertCommand.CommandText= " insert into OpenMI.measurement

(Quantity, Time, Value)

VALUES (QuantityID, Timestamp, Values[0])

this.sqlSelectCommand.Connection=this.sqlConnection1;

krwmaxima = combine(..\..\krwdeelstr, krwmax74, krwmax74gt0)

setmask off

arc tables

select krwmaxima.vat

sort krwdeelstr

unload krwmaxima.csv krwdeelstr krwmax74 krwmax74gt0 delimited init

q

Page 126: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

124

图5-7 ArcInfo AML(输出) 从从从从 ASCII文件输入数据至文件输入数据至文件输入数据至文件输入数据至GIS 如果你已经开发了基于 OpenMI组件的 ASCII文件结果生成工具,就可以将这文件数据输入至 GIS系统,图 5-8展示了输入图 5-9格式的 ASCII文件数据的 ArcInfo代码。

图5-8 AcrInfo AML(输入)

图5-9 输入的ASCII文件 这个 ASCII文件包括两列,第一列为网格数,第二列为乘以 1000000后的量值(为了获得整数值,必须乘以 1000000)。 这个“reclass”命令处理输入指定 ASCII文件,使得输入的值除以 1000000,并转为“浮点”型。 以上例子只是对 GIS系统输入输出数据处理的一种方法,还有许多方法可实现该功能。 5.2 可视化可视化可视化可视化 这节提供如何展现结果数据功能的相关信息。

&echo &brief

setwindow 0 300000 300000 625000

setcell 500

&do p &list g3 d3 b3

/* &do p &list f1 f2 f3 f4 f5

arc w m:\national_calculation_2005\%p%\

&r kill gvg2-%p% glg2-%p% ghg2-%p% dgvg2-%p% dglg2-%p% dghg2-%p%

setmask m:\national_calculation_2005\g3\gwsrecharge\ghg2

gvg2-%p% = ( float(reclass ( m:\mona\data\droogtebasis\plotcode_500 , gvg.rmp )) /1000000 )

glg2-%p% = ( float(reclass ( m:\mona\data\droogtebasis\plotcode_500 , glg.rmp )) /1000000 )

ghg2-%p% = ( float(reclass ( m:\mona\data\droogtebasis\plotcode_500 , ghg.rmp )) /1000000 )

/*dgvg2-%p% = gvg2-%p% -m:\national_calculation_2005\%p%\gwsrecharge\gvg2

/*dglg2-%p% = glg2%p% -m:\national_calculation_2005\%p%\gwsrecharge\glg2

/*dghg2-%p% = ghg2%p% -m:\national_calculation_2005\%p%\gwsrecharge\ghg2

&end

16612 : 1398699

16613 : 3730433

16614 : 4181700

16615 : 3039099

16616 : 1606600

16617 : 3452666

16618 : 3256366

16619 : 2974466

16620 : 2237799

16621 : 1531333

16622 : 1693533

16623 : 2394033

16624 : 1874899

etc.

Page 127: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

125

5.2.1 OpenMI数据监视器数据监视器数据监视器数据监视器 在 OpenMI研发及推广应用中,开发了许多成熟工具用于辅助设计,虽然设计了这些工具,但这并不是 HarmonIT及 OpenMI标准内容。作为 OpenMI使用者当然需要应用工具展示结果及统计分析,对此,可开发多种应用系统实现。在开发 OpenMI 标准组件时,建立OpenMI数据监视器是较好的开始。 在 OpenMI中,组件通过 GetValues调用触发,像数据监视器这些应用同样需要数据,该数据可从其它 GetValues调用获得,一定要仔细确定调用所在位置,这是需要考虑的一个重要设计内容。另外,传输处理应用并不意味着触发器模型应用是一个新计算开始。 数据转换事件可能存在隐患,数据监视器连接至组件,并作为事件监听器被组件识别,当传输组件回应了从另一个连接组件传来的GetValues调用时,它将抛出一个数据转换事件,数据监视器将回应这个事件,通过发出 GetValues 调用给传输组件,该组件能立即返回GetValues调用,因为它缓冲中有数据请求。在图 5-10中展示了这个过程,其中可视化组件是数据监视器。

图5-10 数据转换事件(该图的下划线需要修改) 另一个要注意的问题是连接组件可能执行 IManageState接口内容,这意味着这些组件可能在时间步内回退,使得通过这些组件 GetValues接收的数据将不连续。处理这些情形的方法是通过操作执行中的缓冲,检查接收的数据是否覆盖了缓冲的数据或添加在缓冲中。

5.3 HarmonIT 定做的控件定做的控件定做的控件定做的控件 在 HarmonIT项目执行期间开发了许多高级控件,这部分内容给予介绍。

5.3.1 叠演叠演叠演叠演连接连接连接连接控件控件控件控件 在使用叠演连接前,强烈建议先试用双向连接,只有确实使用不了时再使用叠演控件连接。通常在使用短时间步时双向连接可以正常工作,在下面例子中使用双向连接可得出同样结果,双向连接更容易建立并能有较高的运行效率,而且,要支持叠演模型时必须将状态存

Page 128: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

126

储至前一时段,有些内容不能在 OpenMI标准模型下实现。在使用控件前,应该检查模型提供情况,以确保模型能支持这种存储能力。 叠演控件应在能进行叠演计算的模型之间,只有通过叠演控件才能访问这些模型组件。叠演控件有许多数据通道,并标号为 1、2、3等,为了通过叠演控件连接这些量,提供组件的输出交换项应被连接至确定的数据通道,接收组件的输入交换项应连接至同样的通道,一个数据通道只能被一个连接使用。 图 5-11 展示了两个河流演算模型使用叠演控件连接的例子,可以看出两个模型之间没有直接连接,以及所有的连接都是使用叠演控件。图 5-12,图 5-13,图 5-14,图 5-15,展示了连接使用情况,在这个例子中叠演控件应作为首选组件。 在 OpenMI用户接口中选择设置开始和结束时间及时间步,使得模拟能正常运行。

图5-11 通过叠演控件连接两个河流演算模型

Page 129: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

127

图5-12 从模型1连接输出项至数据通道1

Page 130: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

128

图5-13 从通道1连接输出项至模型2的输入

Page 131: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

129

图5-14 连接模型2(阶段)输出至数据通道2

Page 132: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

130

图5-15 连接数据通道2输出至模型1阶段输入

5.3.2 优化组件优化组件优化组件优化组件 因为优化目标函数的必要,目标函数有许多参数和计算值,优化器提供参数值至目标函数,目标函数返回值至优化器,优化器尽可能使得目标函数最大化或最小化,从而达到优化目的。 需要优化的参数个数、最大值、最小值及初始值等信息需要在 OMI文件提供。图 5-16 展示了两个参数 OMI文件例子,两个参数的最小值都是-100,最大值是 100,初始值为 3.5。虽然对大量的参数优化需要很长时间,但是对需要优化的参数个数理论上没有限制。

图5-16 带两个参数的优化控件OMI文件例子 下一步是在 OpenMI图形界面下连接目标函数和优化器,如图 5-17,图 5-18,图 5-19,给出目标函数如何连接至优化器。 模拟正常计算,在图 5-17中消息窗中有计算结果,目标函数实际最小值初值是(0,0),实际最小值结果为-1,因而优化器在该例子中取得了效果。

<?XML version="1.0"?>

<LinkableComponent Type="org.OpenMI.Utilities.AdvancedControl.OptimizationController"

Assembly="org.OpenMI.Utilities.AdvancedControl.DLL">

<Arguments>

<Argument Key="Parameter" ReadOnly="true" Value="P0,-100,100,3.5"/>

<Argument Key="Parameter" ReadOnly="true" Value="P1,-100,100,3.5"/>

</Arguments>

</LinkableComponent>

Page 133: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

131

优化器基于遗传代数学,在大多是目标中都能得出合理解。

图5-17 连接优化器至目标函数

Page 134: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

132

图5-18 从优化器至目标函数的连接

图5-19 从目标函数至优化器的连接

5.3.3 校正控件校正控件校正控件校正控件 通过选择特定的目标函数使用优化器可以达到校正目的,目标函数可反应出标准值与计算值的不同。使用该控件,可提供计算平方差分总值的组件。 为了校正处理,在 SSD.OMI文件应提供开始时间、结束时间及时间步。图 5-20给出该文件例子,图 5-21 给出如何建立校正控件,顶部的模型代表标准值,第二个模型为计算值,第三个区域分析标准值与计算值的差异,并返回结果给优化器,它为计算模型返回参数设置值。参数实际值为(0.83,0.42),可见优化器产生了较好的结果。

图5-20 SSD.OMI文件例子(指定了开始时间、结束时间及时间步)

<?XML version="1.0"?>

<LinkableComponent Type="org.OpenMI.Utilities.AdvancedControl.SumSquaredDifference"

Assembly="org.OpenMI.Utilities.AdvancedControl.DLL">

<Arguments>

<Argument Key="BeginTime" ReadOnly="true" Value="0.0" />

<Argument Key="EndTime" ReadOnly="true" Value="1.0" />

<Argument Key="TimeStep" ReadOnly="true" Value="0.041666666666666666666" />

</Arguments>

</LinkableComponent>

Page 135: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

133

图5-21 设置校正器

5.3.4 UML图解图解图解图解 图 5-22 展示了统一建模语言(UML)的预装控件结构,基本控件类由连接组件衍生,叠演控件和优化控件类由控件类衍生。

Page 136: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

134

图5-22 已定做控件框图 定做的控件含有内部缓存,UML图解如图 5-23.

图5-23 内部缓存 优化控件和校正控件使用参数描述符标识参数的最大、最小和默认值,图 5-24给出UML

LinkableComponent

Controller

IterationController

+ Prepare() : void

+ «property» ComponentDescription() : string

+ «property» ComponentID() : string

+ «property» ModelID() : string

+ «property» ModelDescription() : string

+ «property» EarliestInputTime() : ITimeStamp

+ «property» TimeHorizon() : ITimeSpan

+ Finish() : void

+ GetPublishedEventType(int) : EventType

+ GetPublishedEventTypeCount() : int

+ Validate() : string

+ Initialize(IArgument) : void

+ GetValues(ITime, string) : IValueSet

OptimizationController

+ Prepare() : void

+ «property» ComponentDescription() : string

+ «property» ComponentID() : string

+ «property» ModelID() : string

+ «property» ModelDescription() : string

+ «property» EarliestInputTime() : ITimeStamp

+ «property» TimeHorizon() : ITimeSpan

+ GetPublishedEventType(int) : EventType

+ GetPublishedEventTypeCount() : int

+ Validate() : string

+ Finish() : void

+ AddParameter(ParameterDescriptor) : void

+ GetParameters() : ArrayList

+ Initialize(IArgument) : void

+ EvaluateCostFunction(ITime, Solution) : double

+ GetValues(ITime, string) : IValueSet

Buffer

+ Clear() : void

+ Get(string) : IValueSet

+ Add(string, IValueSet) : void

BufferElement

+ BufferElement(string, IValueSet)

+ «property» ID() : string

+ «property» ValueSet() : IValueSet

Page 137: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

135

图解的参数描述符图解。

图5-24 描述符图解 优化控件和叠演控件使用解决方案类存储候选方案,图 5-25给出相应的 UML图解。

图5-25 解决方案类 图 5-26显示了平面差分计算组件图解

图5-26 平方差分计算类

LinkableComponent

SumSquaredDifference

+ Prepare() : void

+ «property» ComponentDescription() : string

+ «property» ComponentID() : string

+ «property» ModelID() : string

+ «property» ModelDescription() : string

+ «property» EarliestInputTime() : ITimeStamp

+ «property» TimeHorizon() : ITimeSpan

+ GetPublishedEventType(int) : EventType

+ GetPublishedEventTypeCount() : int

+ Validate() : string

+ Finish() : void

+ Initialize(IArgument) : void

+ GetValues(ITime, string) : IValueSet

+ GetInputExchangeItem(int) : IInputExchangeItem

+ «property» InputExchangeItemCount() : int

+ GetOutputExchangeItem(int) : IOutputExchangeItem

+ «property» OutputExchangeItemCount() : int

IComparable

Solution

+ Solution(double, double, double, double)

+ Solution(Solution, Solution)

+ randomize() : void

+ mutate() : void

+ CompareTo(object) : int

+ _values: double ([])

+ _minimum: double ([])

+ _maximum: double ([])

+ _cost: double

+ random: Random = new Random()

ParameterDescriptor

+ ParameterDescriptor(string, double, double, double)

+ «property» ID() : string

+ «property» Minimum() : double

+ «property» Maximum() : double

+ «property» CurrentValue() : double

Page 138: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

136

使用叠演控件连接两个模型例子如图 5-27.

图5-27 使用叠演控件将两个模型连接

图 5-28,图 5-29,如 5-30分别展示了叠演控件、优化控件和校正控件执行顺序,Q和H是简化量。

Page 139: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

137

图5-28 叠演控件执行顺序图解

Page 140: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

138

图5-29 优化控件执行顺序图解

Page 141: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

139

图5-30 校正控件执行顺序

Page 142: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

140

附录 org.OpenMI.Standard 接口规范

Page 143: 时序计算通用模型接口 OpenMI - fluidearth.netfluidearth.net/Lists/Announcements/Attachments/41... · 0 时序计算通用模型接口 OpenMI 开发技术及应用 目 录

141