MPI решение волнового уравнения — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
(Новая страница: «Здесь представлено стохастическое решение волнового уравнения: :<math>T'' = c\ddot{T}</math> В конц…») |
|||
Строка 3: | Строка 3: | ||
:<math>T'' = c\ddot{T}</math> | :<math>T'' = c\ddot{T}</math> | ||
− | В конце программы добавлено однопроцессорное решение для проверки | + | В конце программы добавлено однопроцессорное решение для проверки результатов вычислений. |
+ | <div class="mw-collapsible mw-collapsed" style="width:100%" > | ||
+ | '''Текст программы на языке C++ (разработчик [[Цветков Денис]]):''' <div class="mw-collapsible-content"> | ||
<syntaxhighlight lang="cpp" line start="1" enclose="div"> | <syntaxhighlight lang="cpp" line start="1" enclose="div"> | ||
#include <iostream> | #include <iostream> | ||
#include <stdio.h> | #include <stdio.h> | ||
#include <math.h> | #include <math.h> | ||
+ | #include <ctime> | ||
#include "include/mpi.h" | #include "include/mpi.h" | ||
using namespace std; | using namespace std; | ||
Строка 28: | Строка 31: | ||
MPI_Get_processor_name(processor_name,&namelen); | MPI_Get_processor_name(processor_name,&namelen); | ||
− | int N = | + | int N = 20000 + 2; // количество частиц в цепочке, 2 частицы для г.у. |
− | double t = | + | double t = 200; // общее время расчета стержня |
− | double dt = 0.01; | + | double dt = 0.01; // шаг |
+ | |||
+ | // Измерение времени работы MPI | ||
+ | double startwtime, endwtime, duration_MPI; | ||
+ | if (myid == 0) { | ||
+ | startwtime = MPI_Wtime(); | ||
+ | } | ||
// здесь задаются начальные условия | // здесь задаются начальные условия | ||
− | double U[N], V[N]; | + | double U[N], V[N], UU[N], VV[N]; // переменные UU[N], VV[N] для сбора конечных результатов |
for (int i = 1; i < N - 1; i++) { | for (int i = 1; i < N - 1; i++) { | ||
− | U[i] = | + | U[i] = 1; |
− | if (i < N / | + | if (i < N / 4) V[i] = 0; |
else V[i] = 0.01; | else V[i] = 0.01; | ||
} | } | ||
− | int N_per_proc = ceil(N / numprocs); // количество частиц на каждый процессор | + | int N_per_proc = ceil((N - 2) / numprocs); // количество частиц на каждый процессор |
− | + | for (double tt = 0; tt < t; tt+= dt) { | |
− | for (double | ||
// зеркальные Г.У. | // зеркальные Г.У. | ||
U[0] = U[1]; | U[0] = U[1]; | ||
Строка 52: | Строка 60: | ||
// расчет скоростей для данного шага | // расчет скоростей для данного шага | ||
for (int j = 1 + N_per_proc * myid; j < 1 + N_per_proc * (myid + 1); j++) { | for (int j = 1 + N_per_proc * myid; j < 1 + N_per_proc * (myid + 1); j++) { | ||
− | + | V[j] += (U[j + 1] - 2 * U[j] + U[j - 1]) * dt; | |
− | |||
− | |||
} | } | ||
− | |||
− | |||
// расчет перемещений для данного шага | // расчет перемещений для данного шага | ||
for (int j = 1 + N_per_proc * myid; j < 1 + N_per_proc * (myid + 1); j++) { | for (int j = 1 + N_per_proc * myid; j < 1 + N_per_proc * (myid + 1); j++) { | ||
− | + | U[j] += V[j] * dt; | |
− | |||
− | |||
} | } | ||
− | + | if (numprocs > 1) | |
+ | if (myid == 0) { | ||
+ | MPI_Send(&U[N_per_proc], 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD); | ||
+ | MPI_Recv(&U[N_per_proc + 1], 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | ||
+ | } else if (myid == (numprocs - 1)) { | ||
+ | MPI_Recv(&U[N_per_proc * (numprocs - 1)], 1, MPI_DOUBLE, numprocs - 2, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | ||
+ | MPI_Send(&U[N_per_proc * (numprocs - 1) + 1], 1, MPI_DOUBLE, numprocs - 2, 0, MPI_COMM_WORLD); | ||
+ | } else { | ||
+ | MPI_Recv(&U[N_per_proc * myid], 1, MPI_DOUBLE, myid - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | ||
+ | MPI_Send(&U[N_per_proc * myid + 1], 1, MPI_DOUBLE, myid - 1, 0, MPI_COMM_WORLD); | ||
+ | MPI_Send(&U[N_per_proc * (myid + 1)], 1, MPI_DOUBLE, myid + 1, 0, MPI_COMM_WORLD); | ||
+ | MPI_Recv(&U[N_per_proc * (myid + 1) + 1], 1, MPI_DOUBLE, myid + 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | ||
+ | } | ||
} | } | ||
+ | |||
+ | MPI_Barrier(MPI_COMM_WORLD); // здесь происходит синхронизация потоков, чтобы избежать состояния гонки | ||
+ | MPI_Gather(&U[1 + N_per_proc * myid], N_per_proc, MPI_DOUBLE, &UU[1], N_per_proc, MPI_DOUBLE, 0, MPI_COMM_WORLD); | ||
+ | MPI_Gather(&V[1 + N_per_proc * myid], N_per_proc, MPI_DOUBLE, &VV[1], N_per_proc, MPI_DOUBLE, 0, MPI_COMM_WORLD); | ||
+ | MPI_Barrier(MPI_COMM_WORLD); // здесь происходит синхронизация потоков, чтобы избежать состояния гонки | ||
+ | |||
+ | // Измерение времени работы MPI | ||
+ | if (myid == 0) { | ||
+ | endwtime = MPI_Wtime(); | ||
+ | duration_MPI = (endwtime-startwtime); | ||
+ | } | ||
// Если это главный процесс, вывод полученного результата | // Если это главный процесс, вывод полученного результата | ||
Строка 73: | Строка 98: | ||
// здесь происходит расчет системы на одном процессоре, для сравнения результатов | // здесь происходит расчет системы на одном процессоре, для сравнения результатов | ||
+ | clock_t start; | ||
+ | double duration; | ||
+ | start = clock(); | ||
+ | |||
double U1[N], V1[N]; | double U1[N], V1[N]; | ||
for (int i = 1; i < N - 1; i++) { | for (int i = 1; i < N - 1; i++) { | ||
− | U1[i] = | + | U1[i] = 1; |
− | if (i < N / | + | if (i < N / 4) V1[i] = 0; |
else V1[i] = 0.01; | else V1[i] = 0.01; | ||
} | } | ||
Строка 92: | Строка 121: | ||
} | } | ||
− | // вывод | + | duration = ( clock() - start ) / (double) CLOCKS_PER_SEC; |
+ | |||
+ | // вывод перемещений (однопроцессорное решение и MPI) | ||
for (int i = 1; i < N - 1; i++) { | for (int i = 1; i < N - 1; i++) { | ||
− | printf("i = %d, | + | printf("i = %d, U1 = %f, U = %f\n", i, U1[i], UU[i]); |
} | } | ||
+ | |||
+ | cout <<"duration: "<< duration <<" duration_MPI: "<< duration_MPI <<'\n'; | ||
} | } | ||
Строка 103: | Строка 136: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
+ | </div> | ||
+ | </div> |
Версия 15:31, 29 апреля 2015
Здесь представлено стохастическое решение волнового уравнения:
В конце программы добавлено однопроцессорное решение для проверки результатов вычислений.
Текст программы на языке C++ (разработчик Цветков Денис):
1 #include <iostream>
2 #include <stdio.h>
3 #include <math.h>
4 #include <ctime>
5 #include "include/mpi.h"
6 using namespace std;
7
8 int main(int argc, char *argv[]) {
9
10 // Объявление переменных
11 int done = 0, n, myid, numprocs, i;
12 int namelen;
13 char processor_name[MPI_MAX_PROCESSOR_NAME];
14
15 // Инициализация подсистемы MPI
16 MPI_Init(&argc, &argv);
17 // Получить размер коммуникатора MPI_COMM_WORLD
18 // (общее число процессов в рамках задачи)
19 MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
20 // Получить номер текущего процесса в рамках
21 // коммуникатора MPI_COMM_WORLD
22 MPI_Comm_rank(MPI_COMM_WORLD,&myid);
23 MPI_Get_processor_name(processor_name,&namelen);
24
25 int N = 20000 + 2; // количество частиц в цепочке, 2 частицы для г.у.
26 double t = 200; // общее время расчета стержня
27 double dt = 0.01; // шаг
28
29 // Измерение времени работы MPI
30 double startwtime, endwtime, duration_MPI;
31 if (myid == 0) {
32 startwtime = MPI_Wtime();
33 }
34
35 // здесь задаются начальные условия
36 double U[N], V[N], UU[N], VV[N]; // переменные UU[N], VV[N] для сбора конечных результатов
37 for (int i = 1; i < N - 1; i++) {
38 U[i] = 1;
39 if (i < N / 4) V[i] = 0;
40 else V[i] = 0.01;
41 }
42
43 int N_per_proc = ceil((N - 2) / numprocs); // количество частиц на каждый процессор
44
45 for (double tt = 0; tt < t; tt+= dt) {
46 // зеркальные Г.У.
47 U[0] = U[1];
48 U[N-1] = U[N-2];
49
50 // циклы с 1 частицы до N - 1, т.к. первая и последняя частицы используются для г.у.
51
52 // расчет скоростей для данного шага
53 for (int j = 1 + N_per_proc * myid; j < 1 + N_per_proc * (myid + 1); j++) {
54 V[j] += (U[j + 1] - 2 * U[j] + U[j - 1]) * dt;
55 }
56
57 // расчет перемещений для данного шага
58 for (int j = 1 + N_per_proc * myid; j < 1 + N_per_proc * (myid + 1); j++) {
59 U[j] += V[j] * dt;
60 }
61
62 if (numprocs > 1)
63 if (myid == 0) {
64 MPI_Send(&U[N_per_proc], 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD);
65 MPI_Recv(&U[N_per_proc + 1], 1, MPI_DOUBLE, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
66 } else if (myid == (numprocs - 1)) {
67 MPI_Recv(&U[N_per_proc * (numprocs - 1)], 1, MPI_DOUBLE, numprocs - 2, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
68 MPI_Send(&U[N_per_proc * (numprocs - 1) + 1], 1, MPI_DOUBLE, numprocs - 2, 0, MPI_COMM_WORLD);
69 } else {
70 MPI_Recv(&U[N_per_proc * myid], 1, MPI_DOUBLE, myid - 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
71 MPI_Send(&U[N_per_proc * myid + 1], 1, MPI_DOUBLE, myid - 1, 0, MPI_COMM_WORLD);
72 MPI_Send(&U[N_per_proc * (myid + 1)], 1, MPI_DOUBLE, myid + 1, 0, MPI_COMM_WORLD);
73 MPI_Recv(&U[N_per_proc * (myid + 1) + 1], 1, MPI_DOUBLE, myid + 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
74 }
75 }
76
77 MPI_Barrier(MPI_COMM_WORLD); // здесь происходит синхронизация потоков, чтобы избежать состояния гонки
78 MPI_Gather(&U[1 + N_per_proc * myid], N_per_proc, MPI_DOUBLE, &UU[1], N_per_proc, MPI_DOUBLE, 0, MPI_COMM_WORLD);
79 MPI_Gather(&V[1 + N_per_proc * myid], N_per_proc, MPI_DOUBLE, &VV[1], N_per_proc, MPI_DOUBLE, 0, MPI_COMM_WORLD);
80 MPI_Barrier(MPI_COMM_WORLD); // здесь происходит синхронизация потоков, чтобы избежать состояния гонки
81
82 // Измерение времени работы MPI
83 if (myid == 0) {
84 endwtime = MPI_Wtime();
85 duration_MPI = (endwtime-startwtime);
86 }
87
88 // Если это главный процесс, вывод полученного результата
89 if(myid==0) {
90
91 // здесь происходит расчет системы на одном процессоре, для сравнения результатов
92 clock_t start;
93 double duration;
94 start = clock();
95
96 double U1[N], V1[N];
97 for (int i = 1; i < N - 1; i++) {
98 U1[i] = 1;
99 if (i < N / 4) V1[i] = 0;
100 else V1[i] = 0.01;
101 }
102 for (double i = 0; i < t; i+= dt) {
103 U1[0] = U1[1];
104 U1[N-1] = U1[N-2];
105
106 for (int j = 1; j < N - 1; j++) {
107 V1[j] += (U1[j + 1] - 2 * U1[j] + U1[j - 1]) * dt;
108 }
109
110 for (int j = 1; j < N - 1; j++) {
111 U1[j] += V1[j] * dt;
112 }
113 }
114
115 duration = ( clock() - start ) / (double) CLOCKS_PER_SEC;
116
117 // вывод перемещений (однопроцессорное решение и MPI)
118 for (int i = 1; i < N - 1; i++) {
119 printf("i = %d, U1 = %f, U = %f\n", i, U1[i], UU[i]);
120 }
121
122 cout <<"duration: "<< duration <<" duration_MPI: "<< duration_MPI <<'\n';
123 }
124
125 // Освобождение подсистемы MPI
126 MPI_Finalize();
127 return 0;
128 }