发现上一篇关于一维流体力学统御方程组和热力学量的内容发布后竟然还能被评为优质内容,可能知乎还是更偏爱偏理论的内容?
为了避免误导别人,我还是说明一下这个专栏主要内容还是计算流体力学涉及到的一些编程内容,一些理论的内容主要还是为了帮助理解。毋庸置疑理论是核心、是编程的基础,但确实从控制方程到编程实现之间的距离还是很大的,我想若是能编程实现一个CFD算法,也能检验自己对知识的掌握和理解,毕竟CFD是帮助理解流体动力学本质的工具嘛。
这次这个篇外用来记录我本学期选修的其他学院的并行计算程序设计课的平时作业,续篇应当也是避免不了的。老师要求使用的是gcc编译器,并行计算框架为openmp或MPI。
还有别看前面都是配置环境这种“软”文,后面有一丢丢代码的嘤嘤嘤。
1、一些基本的配置工作
首先是编辑器
强烈建议使用VS,至于是VS2019还是2017倒是不太重要,不过如果还想使用fortran的话可能需要安装2015,查一下了解一下然后就下载吧。在浏览器上搜索VS,打开网址下载安装文件,安装VS2019。
下载community版本就好,足够用了。
如果只是使用C/C++,就不需要下载太多组件,这些可以了。至于python,咱用个pycharm或者notebook哪个不好?
之后是openmp
在VS中新建一个C++的控制台项目,之后在上面的工具栏中点击“项目”
在打开的菜单栏中最下端为本项目的属性设置,点开。
按如下打开小分支
分别把“openmp支持”和“运行库”选为和我一样的选项。
另外建议在下图这个位置把x86改成x64。
此外还有一个MPI的配置需要一些下载安装的操作,但是目前用的电脑不是自己的,所以就暂时先少折腾一点,之后再提吧。
2、关于并行的一丢丢介绍
并行计算又称为高性能计算,是指同时对多个任务、多条指令,或多个数据项进行处理。
摩尔定律:大概每两年,随着晶体管越来越小,在硅晶上的排布越加密集, 计算机的处理能力将会翻一翻,性能更好,成本更低。
并行计算被大量应用于计算密集、数据密集、网络密集领域。
并行编程范式包括相并行(phase parallel)、分治并行(divide and conquer parallel)、流水线并行(pipeline parallel)、主从并行(master-slave parallel)和工作池并行(work pool parallel)。再多的不说了,感兴趣去B站或者找PDF或者看超级计算机纪录片就可以了。
3、关于openmp的一丢丢介绍
OpenMP是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受,用于共享内存并行系统的多处理器程序设计的一套指导性编译处理方案(Compiler Directive) [1] 。OpenMP支持的编程语言包括C、C++和Fortran;而支持OpenMp的编译器包括Sun Compiler,GNU Compiler和Intel Compiler等。OpenMp提供了对并行算法的高层的抽象描述,程序员通过在源代码中加入专用的pragma来指明自己的意图,由此编译器可以自动将程序进行并行化,并在必要之处加入同步互斥以及通信。当选择忽略这些pragma,或者编译器不支持OpenMp时,程序又可退化为通常的程序(一般为串行),代码仍然可以正常运作,只是不能利用多线程来加速程序执行。
openmp可以调用的线程一般不超过电脑的核数,比如我的小笔记本是8核16线程,一般用4或6或8个线程,如果使用得太多可能导致在信息传递上浪费太多时间,使得效率不升反降。
4、关于MPI的一丢丢介绍
MPI是一个跨语言的通讯协议,用于编写并行计算机。支持点对点和广播。MPI是一个信息传递应用程序接口,包括协议和和语义说明,他们指明其如何在各种实现中发挥其特性。MPI的目标是高性能,大规模性,和可移植性。MPI在今天仍为高性能计算的主要模型。与OpenMP并行程序不同,MPI是一种基于信息传递的并行编程技术。消息传递接口是一种编程接口标准,而不是一种具体的编程语言。简而言之,MPI标准定义了一组具有可移植性的编程接口。
5、每一篇不能没有的代码
这里当抛砖引石头,计算个
#include <iostream>
#include "stdio.h"
#define N 1000000
int main()
{
double local, pi = 0.0, w;
long i;
w = 1.0 / N;
for (i = 0; i < N; i++)
{
local = (i + 0.5) * w;
pi += 4.0 / (1.0 + local * local);
}
printf("pi is approximately %fn", pi * w);
return 0;
}
对应的,
PROGRAM PI
implicit none
real(kind=8) :: local
real(kind=8) :: pip = 0.0000000000
real(kind=8) :: w = 1.0000000000 / 1000000.0
integer(kind=8) :: i
real(kind=8) :: j = 0.0000000000
DO i = 1, 1000000
local = (j + 0.5000000000)*w
pip = pip + (4.0000000000 / (1.0000000000 + local*local))
j = j+1.0000000000
END DO
write(*,*) pip*w
END PROGRAM PI
忽略我的暴力定义,在fortran的强制数据类型面前,c就是个渣渣。至于那个j,是我的老师的建议。
kind=8是一个很关键的地方,不然结果误差会很大,大概在千分位就会失真。当然如果项目默认是x64的就应该不必加上了。
另外说明一下我用的是Simply-Fortran,也就是gfortran编译器。且因为知乎没有fortran 的渲染所以我用了ada的渲染(ada好像是美国军方开发控制系统的?)。
再多说一句,之后并行计算涉及到fortran的内容我都使用simply-fortran,设置起来蛮方便的。