Petsc入门基础篇

44 篇文章 29 订阅 ¥239.90 ¥99.00

欧拉常数的计算

本人之前讲述过在虚拟机环境中安装Petsc,下面都默认在已经有虚拟机的情况运行。
e = ∑ n = 0 1 n ! e=\sum_{n=0}\frac{1}{n!} e=n=0n!1
下面我们先通过一个简单的代码来介绍一些基础知识:

#include <petsc.h>

int main(int argc,char **argv)
{
    PetscErrorCode ierr;
    PetscMPIInt rank;
    PetscMPIInt i;
    PetscReal localval,globalsum;

    PetscInitialize(&argc,&argv,NULL,"compute e in parallel in petsc.\n");
    ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);

    localval = 1.0;
    for(i = 2; i < rank + 1; i++)
	localval = localval/i;

    ierr = MPI_Allreduce(&localval,&globalsum,1,MPIU_REAL,MPIU_SUM,
	PETSC_COMM_WORLD);CHKERRQ(ierr);
    ierr = PetscPrintf(PETSC_COMM_WORLD,"e is %17.15f\n",globalsum);CHKERRQ(ierr);
    ierr = PetscPrintf(PETSC_COMM_SELF,"rank %d did %d flops \n",
	rank,(rank > 0)? rank - 1:0);CHKERRQ(ierr);
    return PetscFinalize();
}


上面有一些换行涉及空格,本人复制过程容易混乱,读者自己注意
上来我们第一个看见的就是头文件petsc.h,这个就和C语言中的头文件stdio.h一样。
在main()函数里面有两个参数,第一个是整型变量,第二个是字符串型数组。所有的代码的参数都是传入PetscInitialize()里面,其中PetscInitialize()一般在主程序开头,用于启动Petsc环境,PetscFinalize()在主程序结尾,用于终止Petsc环境。误差捕捉宏CHKERRQ(ierr)。
在初始化环境之前,我们定义了一些变量,这些我们可以直接按照C语言风格来理解,PetscInt=int,PetscReal=double。下面把makefile文件内容也放上去。
上来我们第一个看见的就是头文件petsc.h,这个就和C语言中的头文件stdio.h一样。
然后定义一个main函数,在main函数里面有两个参数,第一个是整型int变量,第二个是字符串型数组char变量,这个框架和c语言中编写hello world一模一样。
然后开始申明变量,变量的类型分别是PetscErrorCode, PetscMPIInt, PetscReal,主要介绍后面两个变量类型,其中PetscMPIInt相当于c语言中的整型int,PetscReal相当于c语言中的双精度类型double。说明rank,i都是整数,localval,globalsum都是双精度浮点数。这里rank表示运行这个代码调用的进程数目,这里的rank表示的其实也是参与计算欧拉常数的整数数目。这里的i表示的是索引,localval在后面会发现这个变量其实记录的是1/n!,globalsum记录的是每一个进程存储的localval的求和。PetscErrorCode是误差捕捉宏。
申明完需要用到的变量以后,现在开始启动pestc环境,这里用的是PetscInitialize(),代码里面的是PetscInitialize()的标准用法,不管接下来的petsc代码如何编写,PetscInitialize()始终可以保持不变放在主程序的开头,启动petsc环境以后就可以运行代码,运行完以后需要调用PetscFinalize()终止petsc环境,PetscFinalize()只需要放在代码末尾就可以终止,这里需要注意的是PetscInitialize()和PetscFinalize()一定是成对出现的。
PETSC_COMM_WORLD表示MPI进程的通信器,是进程的集合,ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);这一句是在告诉程序调用多少个进程来执行这个代码,也就是告诉程序这里一共用了多少个求和项。代码的主要部分是是那个for循环,这里特别说明,每一个进程都会执行一个for循环:
localval = 1.0;
for(i = 2; i < rank + 1; i++)
localval = localval/i;
这里是在计算每个进程存储的localval数值,我们可以把一个进程看成一个独立的处理器,这个处理器可以独立做简单的四则运算,并且这个进程还有一定的存储能力,可以存储少量数据,这里详细介绍一下这个for循环:
首先需要说明,rank从0开始,如果我们传入的n=5,那么调用的rank只有0,1,2,3,4.
当rank=0时,无法进入循环,localval=1。
当rank=1时,仍让无法进入循环,localval=1。
当rank=2时,此时进入循环发现i只会取2,localval=1/2。
当rank=3时,此时进入循环发现i可以取2,3,当i=2时,根据localval = localval/i;得到此时localval=1/2,然后i=3,新的localval=1/2/3=1/6。
当rank=4时,此时进入循环发现i可以取2,3,4,根据rank=3的经验,我们会发现localval从1更新到了1/2(i=2),然后更新到了1/6(i=3),最后更新到了1/24(i=4)。
现在每一个进程的执行都结束了,我们发现0号进程(rank=0)存储的localval=1,1号进程(rank=1)存储的localval=1,2号进程(rank=2)存储的localval=1/2,3号进程(rank=3)存储的localval=1/6,4号进程(rank=4)存储的localval=1/24。现在每个进程上存储的localval都有了,那么问题就变成了怎么把不同进程上存储的信息做一个求和。
这个求和用的就是MPI里面的一个规约函数Allreduce,具体用法就是下面这行代码。
ierr = MPI_Allreduce(&localval,&globalsum,1,MPIU_REAL,MPIU_SUM,
PETSC_COMM_WORLD);CHKERRQ(ierr);
在这行代码里面,调用的时MPI_Allreduce函数,这个函数接受的参数分别是localval,globalsum的地址,MPIU_REAL表示参与规约运算的都是实数类型变量,MPIU_SUM表示这里的规约操作用的时求和。事实上MPI的规约操作还包括求平均值,求最大值最小值,这里不做具体介绍。这个MPI_Allreduce接受的最后一个参数PETSC_COMM_WORLD表示这里的规约操作是针对所有的进程。
后面两行代码都是负责打印输出,没有什么难点。

include ${PETSC_DIR}/lib/petsc/conf/variables
include ${PETSC_DIR}/lib/petsc/conf/rules
CFLAGS += -pedantic -std=c99

e: e.o
	-${CLINKER} -o e e.o  ${PETSC_LIB}
	${RM} e.o

# testing
rune_1:
	-@../testit.sh e "" 1 1

test_e: rune_1

test: test_e

.PHONY: distclean rune_1 test_e test

distclean:
	@rm -f *~ e *tmp

事实上,后面所有的petsc代码都是这个结构。
代码的编译和执行
输入:
make e
./e或者mpiexec -n 5 ./e
rank表示MPI的进程号。第二个mpiexec -n 5 ./e指的是调用5个MPI进程(process)来估算欧拉常数e。
其中flop表示float point operations,浮点数运算。
PETSC_COMM_WORLD表示MPI进程的通信器,是一个进程的集合。每一个MPI进程都只算了一个 1 n ! \frac{1}{n!} n!1,其中通过MPI_Comm()函数来返回n的取值。
如果我们使用N个进程,那么代码就调用MPI_Allreduce()函数来计算第N个部分和,然后把结果返回给每个进程。
在打印结果的时候,我们有两个打印过程,第一个打印只会在0号进程工作,所以只有一行输出。第二个打印在每个进程都工作。但是第二个打印PESTC_COMM_SELF的打印是随机的,换句话说,一般不会先打印1号进程,2号进程,顺序是随机的。如果想要按顺序打印,那么需要使用PetscSynchronizedPrintf()。但是这个需要额外在进程之间增加通信成本。
下面这个是mpiexec -n 7 ./e的结果
在这里插入图片描述

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Galerkin码农选手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值