基于 MPI/OpenMP 混合编程的大规模多体(N-Body)问题仿真实验

完整代码:

#include <iostream>
#include <ctime>
#include <mpi.h>
#include <omp.h>
#include <cstdlib>
#include <iomanip>
#include <Windows.h>
#include <cmath>
#include <algorithm>

using namespace std;
const long double G = 6.67 * pow(10, -11);
const int STAR_NUM = 32;
const int THREAD_NUM = 4;
const long int TIME_STEP = 3600;
const int MAX_PROCESS = 128;

struct Star
{
    long double x, y, z; // Position
    long double vx, vy, vz; // Speed
    long double ax, ay, az; // Acceleration
    long double nax, nay, naz; // Acceleration of next iteration
    long double m; // Mass
};

Star stars[STAR_NUM];
Star temp[STAR_NUM];
Star buffer[STAR_NUM];

void updateNextAcceration(Star& a, Star& b) {
    long double dx = a.x - b.x;
    long double dy = a.y - b.y;
    long double dz = a.z - b.z;
    long double r2 = pow(dx, 2) + pow(dy, 2) + pow(dz, 2);
    long double A = G * a.m / r2;
    long double r = sqrt(r2);
    long double k = A / r;
    b.nax += k * dx;
    b.nay += k * dy;
    b.naz += k * dz;
}

void updateAcceration(Star& star) {
    star.ax = star.nax;
    star.ay = star.nay;
    star.az = star.naz;
    star.nax = 0;
    star.nay = 0;
    star.naz = 0;
}

void updateSpeed(Star& star) {
    star.vx += star.ax * TIME_STEP;
    star.vy += star.ay * TIME_STEP;
    star.vz += star.az * TIME_STEP;
}

void updatePosition(Star& star) {
    star.x += star.vx * TIME_STEP;
    star.y += star.vy * TIME_STEP;
    star.z += star.vz * TIME_STEP;
}

void print(Star* stars, int num=STAR_NUM) {
    cout << setiosflags(ios::left) << setw(4) << "Num" << setw(16) << "x" << setw(16) << "y" << setw(16) << "z"
        << setw(16) << "Speed x" << setw(16) << "Speed y" << setw(16) << "Speed z"
        << setw(16) << "Acceleration x" << setw(16) << "Acceleration y" << setw(16) << "Acceleration z"
        << setw(16) << "Next a x" << setw(16) << "Next a y" << setw(16) << "Next a z"
        << setw(16) << "Mass" << endl;
    for (int i = 0; i < num; i++) {
        cout << setiosflags(ios::left) << setw(4) << i << setw(16) << stars[i].x << setw(16) << stars[i].y << setw(16) << stars[i].z
            << setw(16) << stars[i].vx << setw(16) << stars[i].vy << setw(16) << stars[i].vz
            << setw(16) << stars[i].ax << setw(16) << stars[i].ay << setw(16) << stars[i].az
            << setw(16) << stars[i].nax << setw(16) << stars[i].nay << setw(16) << stars[i].naz
            << setw(16) << stars[i].m << endl;
    }
}

int main(int argc, char* argv[]) {
    MPI_Init(&argc, &argv);
    int rank, size, real_size;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    real_size = min(STAR_NUM, size);
    // 每个进程的工作量
    int part = STAR_NUM / real_size;
    if (part * real_size < STAR_NUM) part++; // 每个进程的工作量已确定
    // 现在要剔除不需要的进程
    size = STAR_NUM / part;
    if (size * part < STAR_NUM) size++; // 进程数已确定

    MPI_Comm COMM_WORLD;
    if (rank < size) {
        MPI_Comm_split(MPI_COMM_WORLD, 1, rank, &COMM_WORLD);
    }else {
        MPI_Comm_split(MPI_COMM_WORLD, MPI_UNDEFINED, rank, &COMM_WORLD);
    }

    MPI_Comm_rank(COMM_WORLD, &rank);
    MPI_Comm_size(COMM_WORLD, &size);
    //int part = STAR_NUM / size;
    //if (part * size < STAR_NUM) part++;

    // Create custome mpi datatype.
    const int nitems = 13;
    int blocklengths[nitems] = { 1,1,1,1, 1,1, 1,1, 1,1, 1,1,1 };
    MPI_Datatype types[nitems] = { MPI_LONG_DOUBLE,MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE, MPI_LONG_DOUBLE };
    MPI_Datatype MPI_STAR;
    MPI_Aint offsets[nitems];
    offsets[0] = offsetof(Star, x);
    offsets[1] = offsetof(Star, y);
    offsets[2] = offsetof(Star, z);
    offsets[3] = offsetof(Star, vx);
    offsets[4] = offsetof(Star, vy);
    offsets[5] = offsetof(Star, vz);
    offsets[6] = offsetof(Star, ax);
    offsets[7] = offsetof(Star, ay);
    offsets[8] = offsetof(Star, az);
    offsets[9] = offsetof(Star, nax);
    offsets[10] = offsetof(Star, nay);
    offsets[11] = offsetof(Star, naz);
    offsets[12] = offsetof(Star, m);
    MPI_Type_create_struct(nitems, blocklengths, offsets, types, &MPI_STAR);
    MPI_Type_commit(&MPI_STAR);

    omp_set_num_threads(THREAD_NUM);

    if (rank == 0) {
        cout << "Generating origin data..." << endl;
        srand(time(NULL));
        for (int i = 0; i < STAR_NUM; i++) {
            stars[i].m = pow(10, 21) + ((long double)rand() / (RAND_MAX)) * pow(10, 22);
            stars[i].x = pow(10, 7) + ((long double)rand() / (RAND_MAX)) * pow(10, 8);
            stars[i].y = pow(10, 7) + ((long double)rand() / (RAND_MAX)) * pow(10, 8);
            stars[i].z = pow(10, 7) + ((long double)rand() / (RAND_MAX)) * pow(10, 8);
            stars[i].vx = 0;
            stars[i].vy = 0;
            stars[i].vz = 0;
            stars[i].ax = 0;
            stars[i].ay = 0;
            stars[i].az = 0;
            stars[i].nax = 0;
            stars[i].nay = 0;
            stars[i].naz = 0;
        }
    }

    MPI_Bcast(&stars, STAR_NUM, MPI_STAR, 0, COMM_WORLD);

    int loopstart = part * rank;
    int loopend = min(STAR_NUM, (rank + 1) * part);

    while (true)
    {
        // 利用 OpenMP 加速此循环
#pragma omp parallel for
        for (int i = loopstart; i < loopend; i++) {
            Star* s = &(stars[i]);
            updatePosition(*s);
        }

        // 计算下次的加速度需要来自其他进程的数据
        MPI_Request req;
        //MPI_Ibcast(&stars, STAR_NUM, MPI_STAR, rank, COMM_WORLD, &req);
        //MPI_Gather(&stars, STAR_NUM, MPI_STAR, &temp, STAR_NUM, MPI_STAR, rank, COMM_WORLD);
        int start = part * rank;
        int end = min(part * (rank + 1), STAR_NUM);
        int* displs, * rcounts;
        displs = (int*)malloc(size * sizeof(int));
        rcounts = (int*)malloc(size * sizeof(int));
        for (int i = 0; i < size; i++) {
            displs[i] = i * part;
            rcounts[i] = end - start;
        }
        //cout << "rank " << rank << "end - start" << end << " - " << start << endl;
        MPI_Gatherv(&stars[start], end - start, MPI_STAR, &temp, rcounts, displs, MPI_STAR, 0, COMM_WORLD);

        MPI_Bcast(&temp, STAR_NUM, MPI_STAR, 0, COMM_WORLD);

        // 现在 temp 中存的是更新后的数据
        for (int i = loopstart; i < loopend; i++) {
            for (int j = 0; j < STAR_NUM; j++) {
                if (i == j) continue;
                updateNextAcceration(temp[j], stars[i]);
            }
        }

        //print(stars);
        for (int i = loopstart; i < loopend; i++) {
            cout << rank<<" "<<setiosflags(ios::left) << setw(4) << i << setw(16) << stars[i].x << setw(16) << stars[i].y << setw(16) << stars[i].z
                << setw(16) << stars[i].vx << setw(16) << stars[i].vy << setw(16) << stars[i].vz
                << setw(16) << stars[i].ax << setw(16) << stars[i].ay << setw(16) << stars[i].az
                << setw(16) << stars[i].nax << setw(16) << stars[i].nay << setw(16) << stars[i].naz
                << setw(16) << stars[i].m << endl;
        }

        // 利用 OpenMP 加速此循环
#pragma omp parallel for
        for (int i = loopstart; i < loopend; i++) {
            Star* s = &(stars[i]);
            updateAcceration(*s);
        }

        // 利用 OpenMP 加速此循环
#pragma omp parallel for
        for (int i = loopstart; i < loopend; i++) {
            Star* s = &(stars[i]);
            updateSpeed(*s);
        }
    }
}

运行截图:

原文地址:https://www.cnblogs.com/justsong/p/12219743.html

时间: 2024-10-26 17:46:37

基于 MPI/OpenMP 混合编程的大规模多体(N-Body)问题仿真实验的相关文章

Matlab与.NET基于类型安全的接口混合编程入门

原文:[原创]Matlab与.NET基于类型安全的接口混合编程入门 如果这些文章对你有用,有帮助,期待更多开源组件介绍,请不要吝啬手中的鼠标. [原创分享]Matlab.NET混编调用Figure窗体 http://www.cnblogs.com/asxinyu/archive/2013/04/14/3020813.html [原创]开源.NET下的XML数据库介绍及入门  http://www.cnblogs.com/asxinyu/archive/2013/03/25/2980086.htm

用c/c++混合编程方式为ios/android实现一个自绘日期选择控件(一)

本文为原创,如有转载,请注明出处:http://www.cnblogs.com/jackybu 前言 章节: 1.需求描述以及c/c++实现日期和月历的基本操作 2.ios实现自绘日期选择控件 3.android实现自绘日期选择控件 目的: 通过一个相对复杂的自定义自绘控件来分享: 1.ios以及android自定义自绘控件的开发流程 2.objc与c/c++混合编程 3.android ndk的环境配置,android studio ndk的编译模式,swig在android ndk开发中的作

【5.1送礼】国内第一部Matlab和C#.Net混合编程入门级视频教程【完全免费】

上一次写博客很久了,一直在忙彩票分析系统架构的事情,写博客真是件费神的事情,非常花时间.今天抽空发布这篇博客,是为了开源一部自己录制的视频教程-Matlab和C#.Net混合编程视频教程[入门级].下面说说这部视频教程的来由和一些事情,想获取的仔细看看,别忘了点[推荐]哦! 一.为啥要开源 1.1 视频的来源 这部视频教程是在2012年年底闲时比较多,当初也是很多朋友,网友提出这个Matlab.Net混合编程入门比较难,没有资料,所有就特意录制了一部比较简单的视频教程.并有条件的对广大网友免费开

Qt Quick 之 QML 与 C++ 混合编程详解

Qt Quick 技术的引入,使得你能够快速构建 UI ,具有动画.各种绚丽效果的 UI 都不在话下.但它不是万能的,也有很多局限性,原来 Qt 的一些技术,比如低阶的网络编程如 QTcpSocket ,多线程,又如 XML 文档处理类库 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可用,要么用起来不方便,所以呢,很多时候我们是会基于这样的原则来混合使用 QML 和 C++: QML 构建界面, C++ 实现非界面的业务逻辑和复杂运算. 请给

【新年送礼】国内第一部C#.Net调用Matlab进行混合编程的视频教程【彻底免费无注册码】

其他混合编程文章 1[原创]Matlab.NET混合编程技巧之——直接调用Matlab内置函数(附源码) 2.[原创]Matlab.NET混合编程技巧之——找出Matlab内置函数 3.[原创]Matlab与.NET混编解决人脸识别问题 4.[原创]Matlab与.NET基于类型安全的接口编程入门 5.[原创分享]Matlab.NET混编调用Figure窗体 一.视频说明 2014年的5.1,我将这套视频教程进行了免费下载,免费注册开放:[5.1送礼]国内第一部Matlab和C#.Net混合编程

[转] Matlab与C++混合编程(依赖OpenCV)

作者 [email protected],原文 Matlab与C++混合编程(依赖OpenCV) 之前在运行别人论文的代码的时候,经常有遇到Matlab与C++混合编程的影子.实际上就是通过Matlab的Mex工具将C++的代码编译成 Matlab支持调用的可执行文件和函数接口.这样一方面可以在Matlab中利用已经编写好的函数,尽管这个函数是用C++编写的.实现了交流无国界, 没有江山一统的谁,只有四海之内皆兄弟的豪气.另一方面,取C++所长补己之短.Matlab擅长矩阵运算,但对循环操作的效

蛋哥的学习笔记之-基于Unity的Shader编程:X-1 音乐水波特效

蛋哥的学习笔记之-基于Unity的Shader编程:X-1 音乐水波特效 热度 13728 2015-7-11 23:34 |个人分类:蛋哥的学习笔记之-基于Unity的Shader编程| 音乐, Unity, Shader, 水波, Shader, Shader, Shader, Shader 一.要干些啥: 很久很久没有写文档了,前段时间做了个个人很喜欢的,自认为比较原创的小特效,所以写个文档纪念下(本人特别喜欢音乐) 思路其实很简单,首先用顶点着色器实现一般的水波特效,然后解析音频数据(我

paip. 混合编程的实现resin4 (自带Quercus ) 配置 php 环境

#---混合编程的类型 1.代码inline 方式 2.使用库/api  解析方式. #----配置resin 支持php resin4默认自动支持php.. 也能手动配置了.web.xml加php的servlet解析..参考Quercus让你的PHP开心在Servlet容器奔跑 #----配置 php.ini路线 运行t.php,,看见 Configuration File (php.ini) Path => /D:/0watcheskof_0417/WEB-INF/php.ini #----

嵌入式Linux ARM汇编(七)——C语言与ARM汇编混合编程

嵌入式Linux ARM汇编(七)--C语言与ARM汇编混合编程 在嵌入式系统开发中,目前使用的主要编程语言是C和汇编.在大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较好,便于人的理解,而且有大量的支持库.但是很多地方还是要用到汇编语言,例如开机时硬件系统的初始化,包括CPU状态的设定,中断的使能,主频的设定,以及RAM的控制参数及初始化,一些中断处理方面也可能涉及汇编.另外一个使用汇编的地方就是一些对性能非常敏感的代码块,这是不能依靠C编译器的生成代