병렬계산을이용한열방정식풀기. 1. 처음 병렬계산을하기전에 C 언어를이용하여명시적유한차분법으로하나의열방정식을풀어본 다. 먼저 C 로열방정식을이해한다음초기조건만다르게하여클러스터로여러개의열방 정식을풀어보자. 2. C 를이용한명시적유한차분법으로열방적식풀기 열방정식을풀기위한자세한이론은앞서다룬 Finite-Difference method 을보기로하고 바로식 (1.10) 을적용한 matlabcode heatex.m(page10) 를 C 코드로바꾸어본다. Heat.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #define N 12 #define k 0.002 #define Nt 10 #define L 1 #define h 0.0909 #define pi 3.141596 int main() int i,j; double x ; double U[N][Nt]; FILE *fp; /*a*/ char filename[256]; char buffer[10]; for ( i = 0; i <= N-1 ; i++) x = h * i; U[i][0] = sin(( pi * x )); /* initial condition */ for (j=0; j< Nt ; j++) U[11][j]=0; U[0][j]=0; for ( j = 1; j < Nt ; j++) /*eqn 6.11*/ for ( i = 1; i < N -1 ; i++) U[i][j]=(k/(h*h))*U[i-1][j-1] + (1-2 * (k/(h*h)) )*U[i][j-1] + (k/(h*h))*u[i+1][j-1]; fp = fopen("test.m", "w"); /*b, create test.m file*/
fprintf(fp, "clf; clear; clc; \n"); fprintf(fp, "x = linspace(0, %d, %d)\n ", L, N); fprintf(fp, "U = [ "); for (i = 0; i <= (N - 1) ; i++) for (j = 0; j < Nt; j++) fprintf(fp, " %0.4f", U[i][j]); if (j == Nt-1 ) fprintf(fp, "\n"); fprintf(fp, "]; \n"); fprintf(fp, "plot(x, U, 'o-' ) \n"); fprintf(fp, "xlabel('x','fontsize',13) \n"); fprintf(fp, "ylabel('u(x,t)','fontsize',13) \n"); fclose(fp); return 0; /*c*/ C코드의 a FILE* fp 는파일을사용하기위한파일포인터이다. FILE 이라고하는파일구조체를가리키는포인터변수 fp를선언하고 bfopen() 로파일을사용하고 fprintf 함수는데이터를서식화하여파일로출력한다. 입력이끝나면 cfclose로닫아준다. 이파일을컴파일하고실행을해보면 test.m이라는 matlab파일이생성되는데그파일을열어보면아래와같이나온다.
이 matlab 코드를실행 (F5) 를하면아래와같은그래프가나온다. 3. 병렬계산하기 이제, 각 core별로다른초기조건을가지는열방적식을풀어보자. 먼저 C코드를보자. parallelheat.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include "mpi.h" #define N 12 #define k 0.002 #define Nt 10 #define L 1 #define h 0.0909 #define pi 3.141596 int main(int argc, char **argv) int i,j, t; int p, rank; double x ; double U[N][Nt+1]; FILE *fp; MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &p); MPI_Comm_rank(MPI_COMM_WORLD, &rank); char filename[256]; char buffer[10]; for ( i = 0; i <= N-1 ; i++) x = h * i; U[i][0] = sin(( pi * x ))* rank ; U[i][10]=0; for (j=0; j<= Nt ; j++) U[11][j]=0; U[0][j]=0; for ( j = 1; j < Nt ; j++) for ( i = 1; i < N -1 ; i++) U[i][j]=(k/(h*h))*U[i-1][j-1] + (1-2 * (k/(h*h)) )*U[i][j-1] + (k/(h*h))*u[i+1][j-1]; strcpy(filename, "heat"); sprintf(buffer, "%d", rank); strcat(filename, buffer); strcat(filename, ".m"); fp = fopen(filename, "wt"); fprintf(fp, "clf; clear; clc; \n"); fprintf(fp, "x = linspace(0, %d, %d)\n ", L, N); fprintf(fp, "U = [ "); for (i = 0; i <= (N - 1) ; i++) for (j = 0; j < Nt; j++) fprintf(fp, " %0.5f", U[i][j]); if (j == Nt ) fprintf(fp, "\n"); fprintf(fp, "]; \n"); fprintf(fp, "plot(x, U, 'o-' ) \n"); fprintf(fp, "xlabel('x','fontsize',13) \n"); fprintf(fp, "ylabel('u(x,t)','fontsize',13) \n"); fclose(fp); return 0; 병렬계산을위해앞의 C코드 heat.c에서전처리기 #include "mpi.h" 를추가해주고 int main을 int main(int argc, char **argv) 으로바꾸어주자. 그리고프로세서의수변수 p 와프로세서의고유번호 rank를선언해주고초기값을다르게해주기위해본래초기값에 rank를곱한값을각각의열방정식의초기값으로해둔다. 그러면병렬계산을위한코드는완성되었다. 다만출력되는파일을구별하기위해 strcpy와 strcat를이용하여출력되어나오는파일이름에 rank값을붙여준다. 4. 실행하기 앞의병렬계산을하는방법과같은방법으로한다. "scp 파일명.c st1@163.152.62.225:" 이라고
써서파일을클러스터에올리고 mpicc 로컴파일한후 mpirun 으로실행하면된다. mpirun np 4 heatnew.exe 를클러스터에실행시킨결과 heatpara0.m heatpara1.m heatpara2.m heatpara3.m 의 matlab 파일이생성되었다. Parallel programming with MPI 1. 개요. MPI_Send 와 MPI_Recv 를사용해서병렬계산을해본다. 2. 파일올리기병렬계산을하기위해서는파일이클러스터에올라가있어야한다. 파일을올리는방법은시그윈에서 "scp 파일명.c st1@163.152.62.225:" 이라고쓰면파일이클러스터에올라가게된다. 3. 컴파일하기 st1@hpc01:~]$ 에서 mpicc 대상파일이름.c o 컴파일된파일이름.exe 이라입력하면된다. 4. 실행하기컴파일이되었으면 mpirun np 24 컴파일된파일.exe 을입력하여실행한다. Mpirun np [ 프로세서의수를쓴다. ( 숫자, 예 4나 24)] 5. 예시파일
각 process가병렬연산하여결과값을보여주는예를보자. ------------------------------------------------------------- #include <stdio.h> #include <string.h> #include "mpi.h" main(int argc, char* argv[]) int my_rank; int p; int source; int dest; int tag=0; char message[100]; MPI_Status status; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); MPI_Comm_size(MPI_COMM_WORLD, &p); if (my_rank!=0) sprintf(message,"greeting from process %d!",my_rank); dest=0; MPI_Send(message,strlen(message)+1, MPI_CHAR, dest, tag, MPI_COMM_WORLD); else for (source =1; source < p; source++) MPI_Recv(message,100, MPI_CHAR, source, tag, MPI_COMM_WORLD, &status); printf("%s\n", message); MPI_Finalize(); ------------------------------------------------------- #include <string.h> 는 strlen을사용하기썼다. #include "mpi.h" MPI를쓰기위해서는반드시 mpi.h을기입하자. int my_rank; 는 MPI는 process를구별하기위해각각의 process에 rank라는고유한 (unique) integer를갖는다. rank값은 0번부터 n-1까지갖는다. int p; processes의개수를알려준다. int source; 는 send의 rank을의미한다. Source는메시지를보낸 process의 identification을위한것이다.
int dest; 받는곳의 rank 이다. (destination) int tag=0; sender 가보내는 tag 을 receiver 가같은 tag 로받게된다. Tag 는올바르게받은지 확인하기위한꼬리표로써 MPI_Send 와 MPI_Recv 의 tag 가같아야한다. char message[100]; 메시지를입력받는다. MPI_Init(&argc,&argv); mpi를시작하게하는데다른어떤함수보다먼저호출되어야하고한번만호출되어야한다. MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); commucator에서 rank를알려준다. (Find process rank) MPI_Comm_size(MPI_COMM_WORLD, &p); commucator내의 processes의수를알려준다. MPI_COMM_WORLD는 communicator이다. processor간에메시지를주고받을수있는 process들의집합이다. Default 값은 MPI_COMM_WORLD이다. 간단한프로그램에서는 MPI_COMM_WORLD도충분하다.] if (my_rank!=0) sprintf(message,"greeting from process %d!",my_rank); dest=0; rank가 0이아니면그 rank값의 message에 greeting from process을할당하고 %d에 rank값을넣는다. MPI_Send(amessage, bstrlen(message)+1, cmpi_char, ddest, etag, fmpi_comm_world); a: Address of send buffer b: Number of items to send c: datatype MPI_ 는잊지말고붙인다. d rank의 destination ( 도착지 ) e send의꼬리표 f communicator이다. for (source =1; source < p; source++) MPI_Recv(amessageb,100, cmpi_char, dsource, etag, fmpi_comm_world, g&status); printf("%s\n", message); 클러스터는계산을임의로하게되어서 source 순서로출력하는과정이다. a: Address of receive buffer b: Maximum Number of items to receive c: datatype이다. d rank의 source ( 출발지 ) e Message의꼬리표이다.
f communicator g status after operation이다. MPI_Finalize(); mpi 를종료시킨다. 6. 아래는이파일을실행시켰을때나오는결과이다. 20DEC08 contact: donsen2@hotmail.com