Advertisement
Guest User

Untitled

a guest
May 23rd, 2018
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.84 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #include <sys/time.h>
  6. #include <math.h>
  7. #include "/usr/include/mpich/mpi.h"
  8. #define ENABLE_GNUPLOT
  9. double dx;
  10. double dt;
  11. #define A 0.5
  12. #define LEFT_NODE 1
  13. #define RIGHT_NODE 2
  14. #define LENGTH_X 20
  15. #define LENGTH_T 100
  16.  
  17. double dx2;
  18. double dt2;
  19. double a2 ;
  20. FILE *out,*script;
  21. struct timeval tv1,tv2,dtv;
  22. struct timezone tz;
  23.  
  24. void writeInFile(double* Z,int lengthX, double currentTime) {
  25. int i;
  26. for(i = 0; i < lengthX; i++)
  27. fprintf(out,"%d\t%lf\n",i * (int)dx, Z[i]);
  28. fprintf(out,"\n");
  29. fprintf(out, "\n\n");
  30. }
  31.  
  32.  
  33. void generateGnuplotScript(int timeInterval) {
  34. out = fopen("out.txt","w");
  35. script = fopen("script.dat","w");
  36. fprintf(script, "set cbrange [0.9:1]\n");
  37. fprintf(script, "set xrange [0:%d]\n", (int)LENGTH_X - (int)dx);
  38. fprintf(script, "set yrange [-10:10]\n");
  39. fprintf(script, "set palette defined (1 '#ce4c7d')\n");
  40. fprintf(script, "set style line 1 lc rgb '#b90046' lt 1 lw 0.5\n");
  41. fprintf(script, "do for [i=0:%d]{\n", (int) LENGTH_T - 1);
  42. fprintf(script, "plot 'out.txt' index i using 1:2 smooth bezier title 'powered by Artur'\npause 0.1}\npause -1\n");
  43. }
  44.  
  45.  
  46.  
  47. void timerStart() {
  48. gettimeofday(&tv1, &tz);
  49. }
  50.  
  51.  
  52. int timerStop() {
  53. gettimeofday(&tv2, &tz);
  54. dtv.tv_sec = tv2.tv_sec -tv1.tv_sec;
  55. dtv.tv_usec = tv2.tv_usec-tv1.tv_usec;
  56. if (dtv.tv_usec < 0)
  57. dtv.tv_sec--;
  58. dtv.tv_usec += 1000000;
  59. return dtv.tv_sec * 1000 + dtv.tv_usec / 1000;
  60. }
  61.  
  62.  
  63. void setInitialValues(double* Z0, double* Z1, int lengthX) {
  64. int i; // номер столбца
  65. for(i = 0; i < lengthX; i++) {
  66. Z0[i] = Z1[i] = 0; //sin(i*dx*M_PI / (LENGTH_X-1));
  67. }
  68. writeInFile(Z0, lengthX, 0);
  69. }
  70.  
  71.  
  72. // Внешняя сила
  73. double F(int x, double curtime) {
  74. return (curtime <= 5 && (int)x == 3)
  75. }
  76.  
  77.  
  78. void calculate(double* Z0,double* Z1,int lengthX, double currentTime,int myRank, int totalProcesses, double* zleft, double* zright) {
  79. // Z0 всегда текущий, а Z1 - предыдущий
  80. // но Z0 может быть как z0 так и z1;
  81. int i;
  82. int index;
  83. if (myRank != 0) {
  84. index = 0;
  85. Z1[index] = dt2 * (a2*(*zleft-2*Z0[index]+Z0[index+1])/dx2 + F(myRank*lengthX + index, currentTime)) + 2*Z0[index]-Z1[index];
  86. *zleft = Z1[index];
  87. }
  88. for(i = 1; i < lengthX - 1; i++) { // левый и правый столбец тоже для него не хватает данных
  89. index = i;
  90. Z1[index] = dt2 * (a2*(Z0[index-1]-2*Z0[index]+Z0[index+1])/dx2 + F(myRank*lengthX + index, currentTime) ) + 2*Z0[index]-Z1[index];
  91. }
  92. if (myRank != totalProcesses - 1) {
  93. index = lengthX-1;
  94. Z1[index] = dt2 * (a2*(Z0[index-1]-2*Z0[index]+*zright)/dx2 + F(myRank*lengthX + index, currentTime) ) + 2*Z0[index]-Z1[index];
  95. *zright = Z1[index];
  96. }
  97. // высылаем крайние узлы
  98. if(myRank != totalProcesses - 1) { // если это не последний процесс, то нужен правый ряд
  99. // кидаем правую часть следующему процессу
  100. MPI_Send((void*)zright, 1, MPI_DOUBLE, myRank + 1, LEFT_NODE, MPI_COMM_WORLD);
  101. // ловим левую часть следующего процесса, для вычисляющего процесса это будет правой
  102. MPI_Recv((void*)zright, 1, MPI_DOUBLE, myRank + 1, RIGHT_NODE, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
  103. }
  104. if(myRank != 0) { // если это не нулевой процесс, то нужно получить левый ряд
  105. // кидаем левую часть предыдущему процессу
  106. MPI_Send((void*)zleft, 1, MPI_DOUBLE, myRank - 1, RIGHT_NODE,MPI_COMM_WORLD);
  107. // ловим правую часть предыдущего процесса, для вычисляющего процесса это будет левой
  108. MPI_Recv((void*)zleft, 1, MPI_DOUBLE, myRank-1, LEFT_NODE, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
  109. }
  110. }
  111.  
  112.  
  113. int main(int argc, char **argv) {
  114. int myRank, totalProcesses;
  115. if (argc < 3) {
  116. printf("./a.out lengthX timeInterval\n");
  117. exit(0);
  118. }
  119. int lengthX = atoi(argv[1]);
  120. double timeInterval = atof(argv[2]); // временной интервал моделирования
  121.  
  122. dx = (lengthX > LENGTH_X) ? dx = 1.0 : dx = LENGTH_X / lengthX;
  123.  
  124. dt = (timeInterval > LENGTH_T) ? dt = 1.0 : dt = timeInterval / LENGTH_T;
  125.  
  126. dx2 = dx * dx;
  127. dt2 = dt * dt;
  128. a2 = A * A;
  129.  
  130. double* Z0;
  131. double* Z1;
  132. double currentTime = dt; // текущий момент времени
  133. int znumber = 1; // в какой массив записывать
  134.  
  135. // Инициализация коммуникационных средств MPI
  136. MPI_Init (&argc, &argv);
  137. MPI_Comm_size (MPI_COMM_WORLD, &totalProcesses);
  138. MPI_Comm_rank (MPI_COMM_WORLD, &myRank);
  139.  
  140. int newlengthX = lengthX / totalProcesses; // узлов на один процесс
  141. int lengthXmod = lengthX % totalProcesses; // остаток
  142. double* z0;
  143. double* z1;
  144. double zleft;
  145. double zright;
  146. double* tmp;
  147.  
  148. if (myRank == 0) {
  149. generateGnuplotScript(timeInterval);
  150. Z0 = (double*) calloc (lengthX, sizeof(double)); // значение узлов в текущий момент времени
  151. Z1 = (double*) calloc (lengthX, sizeof(double)); // значение узлов в предыдущий момент времени
  152. setInitialValues(Z0, Z1, lengthX);
  153. }
  154.  
  155. if(myRank == totalProcesses - 1) {
  156. newlengthX += lengthXmod;
  157. }
  158.  
  159. // для каждого процесса выделяем память
  160. z0 = (double*) calloc (newlengthX, sizeof(double));
  161. z1 = (double*) calloc (newlengthX, sizeof(double));
  162.  
  163. // каждому процессу передадим необходимую часть
  164. int* sendArr;
  165. sendArr = (int *)calloc(totalProcesses,sizeof(int));
  166.  
  167. int i;
  168. for(i = 0; i < totalProcesses; i++)
  169. sendArr[i] = i * newlengthX;
  170.  
  171. int* sendArrCount;
  172. sendArrCount = (int *)calloc(totalProcesses,sizeof(int));
  173. for(i = 0; i < totalProcesses; i++)
  174. sendArrCount[i] = newlengthX;
  175. sendArrCount[totalProcesses - 1] += lengthXmod;
  176.  
  177. MPI_Scatterv((void *)(Z0), sendArrCount, sendArr, MPI_DOUBLE,(void *)(z0), newlengthX, MPI_DOUBLE, 0, MPI_COMM_WORLD); // разбрызгиватель
  178. MPI_Scatterv((void *)(Z1), sendArrCount, sendArr, MPI_DOUBLE,(void *)(z1), newlengthX, MPI_DOUBLE, 0, MPI_COMM_WORLD);
  179.  
  180. zleft = z0[0];
  181. zright = z0[newlengthX-1];
  182.  
  183. if(myRank != totalProcesses - 1) { // если это не последний процесс, то нужен правый ряд
  184. // кидаем правую часть следующему процессу
  185. MPI_Send((void*)&zright, 1, MPI_DOUBLE, myRank + 1, LEFT_NODE, MPI_COMM_WORLD);
  186. // ловим левую часть следующего процесса, для вычисляющего процесса это будет правой
  187. MPI_Recv((void*)&zright, 1, MPI_DOUBLE, myRank + 1, RIGHT_NODE, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
  188. }
  189.  
  190. if(myRank!= 0) { // если это не нулевой процесс, то нужно получить левый ряд
  191. // кидаем левую часть предыдущему процессу
  192. MPI_Send((void*)&zleft, 1, MPI_DOUBLE, myRank - 1, RIGHT_NODE, MPI_COMM_WORLD);
  193. // ловим правую часть предыдущего процесса, для вычисляющего процесса это будет левой
  194. MPI_Recv((void*)&zleft, 1, MPI_DOUBLE, myRank-1, LEFT_NODE, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
  195. }
  196.  
  197. if (myRank == 0)
  198. timerStart();
  199. while(currentTime < timeInterval) {
  200. if(znumber == 1)
  201. calculate(z0, z1, newlengthX, currentTime, myRank, totalProcesses, &zleft, &zright);
  202. else
  203. calculate(z1, z0, newlengthX, currentTime, myRank, totalProcesses, &zleft, &zright);
  204.  
  205. #ifdef ENABLE_GNUPLOT
  206. if(znumber == 1) {
  207. MPI_Gatherv((void *)z1, newlengthX, MPI_DOUBLE,(void *)(Z1),sendArrCount, sendArr, MPI_DOUBLE, 0, MPI_COMM_WORLD);
  208. if (myRank == 0)
  209. writeInFile(Z1, lengthX, currentTime); // запись в gnuplot
  210. }
  211. else {
  212. MPI_Gatherv((void *)z0, newlengthX, MPI_DOUBLE,(void *)(Z0),sendArrCount, sendArr, MPI_DOUBLE, 0, MPI_COMM_WORLD); // совок
  213. if (myRank == 0)
  214. writeInFile(Z0, lengthX, currentTime); // запись в gnuplot
  215. }
  216. MPI_Barrier(MPI_COMM_WORLD); // ждем запись
  217. #endif
  218.  
  219. if(!myRank) {
  220. znumber *= -1;
  221. currentTime += dt;
  222. }
  223.  
  224. MPI_Bcast((void *)&znumber, 1, MPI_INT, 0, MPI_COMM_WORLD);
  225. // Передаём текущее значение всем процессам на текущем шаге для того, чтобы правильно рассчитывалось внешнее воздействие на каждый узел, которое зависит от координаты и времени
  226. MPI_Bcast((void *)&currentTime, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
  227. }
  228.  
  229. // Вывод времени работы
  230. if (myRank == 0) {
  231. int ms = timerStop();
  232. printf("Time: %d milliseconds\n", ms);
  233. free(Z0);
  234. free(Z1);
  235. }
  236.  
  237. free(z0);
  238. free(z1);
  239. free(sendArr);
  240. free(sendArrCount);
  241. MPI_Finalize();
  242. exit(0);
  243. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement