|
|
|
|
移动端

2.4.2 Hydro2D的结构

《高性能并行珠玑:多核和众核编程方法》第2章从正确到正确&高效:Godunov格式的Hydro2D案例学习,本章将探讨一段科学模拟代码,这段代码是一个以气体动力学为基础的模拟程序。这份程序的输出结果正确,但(初始版本)性能欠佳。本节为大家介绍Hydro2D的结构。

作者:张云泉 等译来源:机械工业出版社|2017-11-14 17:39

技术沙龙 | 邀您于8月25日与国美/AWS/转转三位专家共同探讨小程序电商实战

2.4.2 Hydro2D的结构

Hydro2D参考代码有近5000行,分布在19个header/c文件对中,但是核心计算例程非常紧凑。

计算方案

在每个时间步长中会执行下列步骤,以此推进到下一个时间步长所需要的解:

更新。根据维度分裂方法,更新可以在x→y/y→x维度模式中选择;每次更新包含单元格的流量计算(实际上就是在每个垂直于更新方向上的单元格中构建和求解黎曼问题)。在更新中,所有黎曼问题都是独立的。当一个单元格的流量计算出来时,时间上的积分就可以运算了。

时间步长计算。为了积分的稳定性,必须基于每个单元格中的状态计算和归约courant数。这是一个归约过程。

数据结构

Hydro2D的数据结构非常接单。为了简化一些边界计算,解状态存储在一个由两个单元格组成的普通单元格“halo层”中。网格被组织成[ρ, ρu, ρv, E]T的形式,变量都存储于各自的平面中。这是使用的是y-major空间维度排序。因为考虑到问题的对称性,x-major和y-major是等价的。

除了全局问题状态之外,参考版本的Hydro2D代码有一个次级数据结构用于存放中间状态的值。

slab。Hydro2D参考代码工作在单独的多层网格平台上,相比于全局网格,这些网络会有更小的维度。这种结构叫作slab,它允许格格不入的计算并作为构造和屏蔽结构。

在每个更新步中,一部分单元格复制进slab中。然后每个更新都在slab中进行,这些slab分别存储子域中每个交界处/单元格的中间态。当积分完成时,结果被写回结果网格,同时另外一个子区域的值复制进slab中,直到整个解网格更新结束。从图2-6可以看到整个过程。

值得注意的是,使用参考代码中x和y维度上的更新都能用slab,为了妥善处理边界值,更新x行和y列在并没有得到副本前完成。对于y轴来说,复制进/出slab的数据是原始数据的转置,因此slab总是必须足够宽以容纳网格的x和y维度(另外一个slab维度是用户可选择的参数)。

关键函数。对于这份参考代码中有11个关键函数;有些函数的实现很简单。这些函数都可以在自己的源文件中找到。简单的总结如下。

compute_deltat():这个函数用来计算在局部黎曼问题中的最大特征值,此特征值将在接下来的计算中求解最大稳定时间步长(compute_deltat.c:159)。

hydro_godunov():这是更新操作中的最高层例程,其调用几乎所有的下级函数以复制数据到slab,计算更新,写回。这个函数的一个参数控制哪一个维度将会被遍历(hydro_godunov.c:62)。

gatherConservativeVars():将解从子区域解网格复制到slab的conservation变量(conservar.c:48)中存储。

constoprim():(部分地)将slab中conservation变量转变为流量计算所需要的基本形式(constoprim.c:48)。

equation_of_state():使用constoprim()函数的结果加上conservative变量中保存的E项以完成最后初始的变量p,在slab的专用存储中完成这里所有操作(equation_of_state.c:48)。

slope():检查临接单元格的值,(以基本的形式)计算(或限制)斜率。此斜率将用于接下来的流量计算。这份代码使用了Leer的MC限制器(slope.c:52)。

trace():将计算出来的斜率应用到每个单元格上的终止点上(trace.c:51)。

qleftright():将trace()的结果复制于独立缓冲区上,为riemann()做准备(qleftright.c:48)。

riemann():riemann()函数是流量计算的核心;这个函数是一个用于解决中间态压力的标量非线性系统。这个函数用Newton-Raphson方法进行求解。余下的术语是从压力计算中产生的(riemann.c:80)。

cmpf?lx():使用Riemann()计算的中间态和周围状态计算差值,并转变为con-servation流量(cmpf?lx.c:51)。

updateConservativeVars():使用邻接的流量来积分单元格,同时将结果复制回全局解网格(conservar.c:122)中。

slab例程gatherConservativeVars()通过updateonservative-vars()能够使用“块同步并行”方式相继操作。这些函数能够组织成无数据相关性的形式(对于每个函数使用输入/输出存储),所以每个函数都暴露出线程和数据并行的可能性(通过OpenMP和自动向量化)。这就是计算这些块的地方,同时hydro_godunov()是这些单元格的调用框架。图2-7展示了在一维切片上计算时这些结构和数据流的情况。

compute_deltat()类似地使用slab去计算一系列中间状态(包括equation_of_state()),这些中间状态最终要得到最大特征值,这些特征值是归约得到的。这些slab步具有与上述相同的线程级和数据级并行性。

测试性能

当然,本章的目的是提升Hydro2D代码的性能而不是进行新的科学实验。我们最关注的是某些特定性能的值,这些性能需要能够代表在实验中程序的运行情况。

对于我们的程序来说,测量这些值非常简单:Hydro2D的性能很大程度上独立于初始值和边界条件的值,所以我们不必要对测试问题做出特定的限制。尽管在黎曼问题求解器中使用的Newton-Raphson迭代有控制流的出现,因为这些流量的计算会依赖于输入,所以这些控制流会增加流量计算的运行时间,但是这个只对极端情况有意义。

为了了解代码对问题规模的敏感度,我们将探索不同规模的问题,并且正规化我们的实验结果到每个单元格在每个时间步长所花的时间。每步所花的时间由稳定性条件所表述,而所谓稳定性条件就是解状态和网格空间的乘积。这就意味着两个不同的初始条件可能需要不同的步数以达到给定时间的仿真。

图2-8展示了参考代码中单元格步/秒的性能。处理器的性能是协处理器的两倍多,协处理器的并行效率非常差。


喜欢的朋友可以添加我们的微信账号:

51CTO读书频道二维码


51CTO读书频道活动讨论群:365934973

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

PHP5与MySQL5 Web开发技术详解

本书是目前中文版本第一个真正介绍PHP 5及MySQL 5新增语法与功能的权威宝典! 本书本着精、全、要三宗旨,从理论中延伸,从实践中深入,详...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊