1. 前言
科学计算可视化是当前计算机学科的一个重要研究方向。随着计算机软硬件技术的不断发展,CFD仿真的精度和复杂性越来越高,为了能够直观地观察和分析输入数据和计算结果三维流场状态,可视化技术已成为CFD研究领域重要的研究方向。
Fortran最适用于科学计算,在CFD领域编程语言中,Fortran与C语言的计算速度最快。虽然在最近一二十年C语言在开发应用编程方面成为主流,但国内外经典的CFD程序及函数库还有相当数量以Fortran程序形式存在。相较C语言,Fortran语言不仅具备相近的高速度,它的可读性和结构性更好,在大量浮点运算的科学计算中,Fortran比C语言更具优势。目前还有很多CFD软件开发人员在使用,包括美国航空航天局及波音公司等CFD设计部门。
基于以上原因,Fortran仍在开发中,最新的国际标准是Fortran 2018,ISO Fortran标准技术委员会已经开始制定下一个修订版。
Fortran语言在CFD结果可视化编程方面的困难:
Fortran在应用领域使用率落后于C语言的一个主要原因在于其面向对象功能的不完善。它虽然包含了一些常用的绘图函数库,但绘图效率较低,无法解决CFD高速计算过程中图形显示的速度延迟问题。另外对多线程并行计算显示和显卡兼容性问题也阻碍了Fortran可视化编程的实现。
OpenGL是图形硬件的一个软件接口,是国际通用的开放式三维图形标准。Windows操作系统和MS Visual Studio编程开发环境中加入了OpenGL标准,使得OpenGL库函数可以被多种编程语言调用,包括Fortran。
IVF是Fortran家族中发展较快的,它增加了面向对象的编程功能和较强的图形功能,并且逐渐在向C语言的功能靠近。IVF编程工具Intel Parallel Studio结合Visual Studio开发平台,已经具备了使用单一的Fortran语言,借助OpenGL绘图函数库,完成CFD整套程序的编制要求和条件。对于继续完善和发展过去由Fortran语言编制的CFD程序及函数库的工作,IVF + OpenGL的组合是一个合适的选择。
OpenGL函数库和使用环境较为复杂,对不同的编程语言要采用不同的函数库。对Fortran而言,在Visual Studio IA32系统和×64系统上,某些重要的函数调用参数格式还有区别。OpenGL开发机构发布的与Fortran接口的库函数,在IVF上使用时尚存在一些格式兼容性问题。很多CFD编程者只能实现在IA32平台上使用,在64位系统上无法编译通过。IVF和Visual Studio安装包没有提供与×64系统兼容的OpenGL例程。
2. 编译环境及CFD常用的Fortran版本OpenGL函数库
本文在VS2019 + Intel Parallel Studio2020 (IVF) + Windows 2019 (×64)编译环境下使用兼容的Fortran OpenGL函数库。安装好VS、IVF后,到如下目录查找和确认Fortran OpenGL函数库文件:
C:\Program Files (×86)\IntelSWTools\parallel_studio_xe_2020\compilers_and_libraries_2020\windows\ compiler\lib\intel64_win
这些函数库文件包括:f90GL.LIB,f90GLU.LIB,f90GLUT.LIB,opengl_gl.lib,opengl_glu.lib,opengl_glut.lib等。
3. CFD计算结果可视化常用的绘制方法
CFD数值计算结果反映的是目标区域内FVM网格上的流体速度(马赫数)、压力、温度、密度、湍流动能及耗散率等参量,这些量包括标量与矢量两类。
压力、温度、密度、马赫数等标量的可视化输出方法包括等值线、等值面、三维图,赋予相应颜色或黑白灰度云图。速度矢量流场的显示可以采用二维截面、三维曲面、区域三维速度矢量组合显示等方法。
而对于前处理相关的网格及边界条件可视化绘图,OpenGL的绘图方式更为多样化。
4. Fortran版本OPENGL的绘图函数及其应用
(1) OpenGL的点、线、面绘图函数:
绘制点
call fglpointsize(SIZE) - 定义节点的大小 call fglBegin(GL_POINTS) – 绘制节点
call fglVertex2f(X,Y) – 节点坐标(二维) call fglVertex3f(X,Y,Z) – 节点坐标(三维)
绘制直线
call fglBegin(GL_LINES) - 两点间画直线函数
call fglVertex2f(Xi,Yi) - (i=1,2 二维)
call fglVertex3f(Xi,Yi,Zi) - (i=1,2 三维)
call fglEnd()
绘制平面
call fglBegin(GL_QUADS) – 4点绘制四边形二维平面
call fglVertex2f(Xi,Yi) (i=1,4 二维)
call fglVertex3f(Xi,Yi,Zi) (i=1,4 三维)
call fglEnd()
更多功能的绘图函数,如:
GL_LINE_STRIP(连续多段线)、GL_LINE_LOOP(封闭多段线)、GL_POLYGON(多边形)、GL_TRIANGLES(三角形)
GL_TRIANGLE_STRIP(连续三角形)、GL_QUAD_STRIP(连续四边形)。详细的函数使用方法可参考文献[1]。
(2) 颜色函数及其应用
CFD计算结果显示颜色的设置非常重要,方便直观捕捉和分析CFD计算结果的合理性,是CFD计算和后处理过程的重要辅助工具。
颜色设定函数及其应用:
点线面的图形可以使用颜色函数赋予不同的颜色。直线颜色设定可以采用如下颜色选择函数:
call fglcolor3ub(R(n),G(n),B(n)) -(R(n),G(n),B(n)为RGB颜色码)
call fglBegin(GL_LINES)
call fglVertex2f(Xi,Yi) (i=1,2)
call fglEnd()
对于空间平面和曲面的颜色分布,对4个角点赋颜色值,然后利用四边形绘制函数的内置颜色插值功能实现(图1):
call fglBegin(GL_QUADS)
call fglcolor3ub(R(i),G(i),B(i)) (角点i的颜色值)
call fglVertex3f(Xi,Yi,Zi) (i=1,4)
call fglEnd()
Figure 1. Grid color interpolation
图1. 网格颜色插值
颜色的变化规律设定及RGB颜色分布函数(插值函数)的应用:
颜色范围选择包括彩色或单色,对颜色RGB分量进行线性或幂指数变化控制是一个简单有效的方法。
将线性及幂指数变化的规律总结成如下函数:
可以根据显示的流场参数的变化规律和分析要求,选择合适的幂指数。
本文实际计算流场的显示效果表明:指数q的选择在1 (线性变化)到2之间较为合适。
RGB颜色组合变化规律的控制:
R、G、B颜色分量的线性或幂指数变化组合可以改变颜色和两端极值的亮度对比,如下例(图2(a),图2(b)):
Figure 2. RGB combination variation
图2. RGB组合变化
连续彩虹光谱颜色的计算方法及建立调色板模型:
这种颜色分布在CFD计算领域应用非常广泛。对于彩色的连续光谱式变化,可以对RGB颜色分量进行独立或相关线性变化控制。图3的算例采用了颜色分布的线性分段函数形式,由RGB组合计算出设定的颜色谱。
Figure 3. Rainbow color segmentation function
图3. 彩虹条颜色分段函数
5. 建立显示的流场参数值与RGB颜色函数的对应关系
利用流场参数的数值范围与RGB颜色函数的连续变化特性建立线性或函数的对应关系,使OpenGL绘图函数输出的点线面具备直观的颜色或灰度效果。当对CFD计算程序进行运行调试时,可以非常方便地观察到最大和最小值出现的位置以及对中间计算结果的趋势合理性做出判断,对于程序的错误诊断是一个有效的工具。如果计算程序的调试过程中,由于缺乏可视化图形的帮助,仅通过某些点的数值显示难以做到全面和高效的问题排查。
根据颜色变化规律的设置,将流场物理量的数值范围在输出显示之前进行单位化,把最大最小极值与颜色条定义的两端对应好,将物理量的单位化量值与颜色值对应起来,这样可以简化OpenGL绘图编程:
上述公式中,n为流场参数显示颜色在定义条中的位置值,
和
为颜色条的两端限制值,
为节点流场显示参数值,
为参数区域最大值,
为区域最小值,
为单位化转换值。
颜色值按流场参数的幅值范围线性插值的计算结果的可视化符合多数场合的应用。但在一个数值范围分布极端不均衡的流场中,极值范围集中在很小的区域,线性插值会导致可视化下降,大面积颜色趋于相近的显示效果,掩盖了参数梯度变化剧烈的区域。
6. 应用OPENGL绘图函数及颜色分布函数的显示输出算例
(1) 灰度图的绘制(模拟纹影仪效果)
用同一种颜色的色调或灰度变化的图像能够更清楚表达CFD流场中特别关注的区域,如激波及换热强烈的区域,也能够给CFD计算人员带来最佳的计算结果分析效果。如根据前述图2(a)的黑白灰度变化关系,可以设计出包括纹影仪效果的计算结果视图,图4为本文计算的圆柱绕流速度图,明暗效果可以突出尾流涡的速度变化情况。
Figure 4. Grayscale image for flow around a cylinder
图4. 圆柱绕流灰度图
(2) 彩色等值面(云图)的计算与绘制
等值面的颜色值的计算与绘制使用单位化的输出流场物理量与颜色的对应关系,采用前述OpenGL函数fglBegin(GL_QUADS), fglcolor3ub(nr,ng,nb), fglVertex3f(X,Y,Z),对网格节点进行颜色赋值,面上各像素点的颜色由该函数自动插值完成。实际流场计算结果显示表明:OpenGL的内置颜色插值函数可以满足流场的显示要求。也可以根据实际需要插值计算各点的颜色值,如距离加权法、三线性插值法等。图5为圆柱绕流速度云图。
Figure 5. Velocity cloud map for flow around a cylinder
图5. 圆柱绕流速度云图
(3) 彩色等值线的计算与绘制
等值线的绘制可以使用GL_LINES,GL_LINE_STRIP、GL_LINE_LOOP等绘图函数,结合流场显示参数的对应颜色值采用fglcolor3ub(nr,ng,nb)颜色赋值函数给等值线上色(图6)。等值线的画法可参考[2]-[4]。还可以使用单色等值线结合GL_POLYGON、GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_QUADS、GL_QUAD_STRIP绘制背景颜色,根据CFD输出图形的要求显示不同的效果(图7)。这种画法布局也可参考文献[5] [6]。
(4) 网格点及边界条件的显示
计算域网格线的绘制可以使用GL_LINES,GL_LINE_STRIP、GL_LINE_LOOP、GL_POLYGON、GL_TRIANGLES
GL_TRIANGLE_STRIP等绘图函数结合(I,J,K)方向的循环语句(结构网格)或节点之间的关系(非结构网格)完成。
图8(a)和图8(b)为二维及三维结构网格的OpenGL绘制的网格图形。
Figure 6. Velocity contours for flow around a cylinder
图6. 圆柱绕流速度等值线
Figure 7. Cloud map of velocity contours for flow around a cylinder
图7. 圆柱绕流速度等值线云图
Figure 8. 2D Grids and 3D mesh graphics
图8. 网格图形
使用fglpointsize(size),设定绘制节点的大小,fglBegin(GL_POINTS)绘制节点,用fglBegin(GL_LINES)绘制网格,使用fglcolor3ub(nr,ng,nb)确定网格节点的边界条件颜色。图9为重叠网格挖洞及插值边界点显示,图10三维网格边界信息显示。
Figure 9. Overlapping grid digging and interpolation boundary points
图9. 重叠网格挖洞及插值边界点
(5) 速度矢量图的绘制
利用分段直线绘制函数fglBegin(GL_LINE_STRIP)和线宽设定函数fglLineWidth(width),将每一个节点的速度矢量的一端分成几段变宽度直线,即可形成箭头,根据节点流场参数对应的颜色值利用颜色函数确定该矢量的色彩,可以绘制出每一个网格点的速度矢量(图11,图12)。
Figure 10. 3D grid boundary condition display
图10. 三维网格边界条件显示
Figure 11. Velocity vectors
图11. 速度矢量
Figure 12. Velocity vectors field for flow around a cylinder
图12. 圆柱绕流的速度矢量图
7. CFD计算结果的动态可视化输出
CFD计算程序每一个计算周期完成后的结果输出为一次静态可视化输出。由于每一个循环计算结果的不同,在连续静态画面显示输出时能产生动画的效果,便于形象地分析气体的流动情况。
(1) IVF中使用兼容64位系统的OpenGL实现动态可视化输出的窗口设置参数:
IA32与×64系统环境下的绘图函数调用子程序变量的格式差异:
对Fortran兼容的OpenGL函数,大多数公开的论述都是对于IA32系统的,对于当前主流×64系统的CFD计算程序来说存在兼容性问题。应用在×64系统Fortran计算环境的OpenGL函数在使用前还需要修改一些函数变量格式。
经过调试计算得出,在×64系统环境下,窗口调用函数的几个基本参量的整数结构类型需要符合如下要求,否则编译通不过或者无法正常输出显示:
Integer Function MainWndProc( hwnd, message, wParam, lParam )
INTEGER(8) :: hwnd
INTEGER(4) :: message
INTEGER(8) :: wParam
INTEGER(8) :: lParam
INTEGER(4) :: glnWIDTH,glnHEIGHT
(2) 实现连续静态画面的动态输出:
使用下列OpenGL屏幕显示相关函数,清理和关闭上一个计算循环后的显示画面:
fwglMakeCurrent( NULL, NULL )
fwglDeleteContext( hRC)
ReleaseDC( hwnd, hdc )
DestroyWindow( hwnd )
PostQuitMessage( 0 )
CFD计算程序每完成预设的计算循环数后,输出要显示的流场参数到OpenGL数据接口程序、初始化屏幕显示。使用下列OpenGL函数,初始化屏幕显示的相关参数:
fglShadeModel(GL_SMOOTH)
fglClearColor (0.0, 0.0, 0.0, 0.0)
fglClear(ior(GL_COLOR_BUFFER_BIT,GL_DEPTH_BUFFER_BIT))
fglClearDepth(1.D0)
fglEnable(GL_DEPTH_TEST)
fglDepthFunc(GL_LEQUAL)
fglHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
(3) 三维画面的平移、旋转、显示比例变化:
以下几个OpenGL函数可以用来控制显示的三维流场区域的比例缩放、平移、旋转:
fglscalef(X_SCALE,Y_SCALE,1.0) -缩放 fgltranslatef(X_MOVE,Y_MOVE,XYZ_RANGE)-平移
fglRotatef(ANGLE_X, 0.5, 0.0, 0.0) -绕X轴旋转
fglRotatef(ANGLE_Y, 0.0, 0.5, 0.0) -绕Y轴旋转
fglRotatef(ANGLE_Z, 0.0, 0.0, 0.5) -绕Z轴旋转
8. 算例
本文经过大量调整和尝试后,采用前述方法绘制了流场的各种图形,在×64运行环境下实现了Fortran运算与OpenGL绘图的动态显示(如图13(a)~(d))。
Figure 13. Velocity contours dynamic display for flow around a cylinder
图13. 流场速度等值线动态显示图
9. 结论
IVF和Visual Studio的功能拓展,采用Intel Visual Fortran (IVF)编程语言可以实现CFD软件编程的高速动态可视化显示输出。采用兼容的×64 Fortran OpenGL绘图函数库,可实现同一编程语言的一体化编程目标,简化不同编程语言间的数据接口和数据转换过程,提高编程效率和程序运行速度。
本文通过使用IVF编制的CFD程序,调用Fortran版本OpenGL绘图函数库,调整参数格式,实现了CFD流场数据静态及结果的动态显示。本文的方法有助于发挥Fortran编程语言在其高速科学计算的功能基础上,增加可视化编程和面向对象的编程能力,具备CFD软件综合设计的整体功能。利用这个方法还可以继续发展和改造大量的现有基于Fortran语言的经典CFD计算程序,有利于提高Fortran语言的CFD软件图形化和一体化编程的能力。