| |
Следующие примеры демонстрируют использование производных типов данных
Пример 3.30 Передача и прием секции 3D массива.
REAL a(100,100,100), e(9,9,9) INTEGER oneslice, twoslice, threeslice, sizeofreal, myrank, ierr INTEGER status(MPI_STATUS_SIZE) C извлекает секцию a(1:17:2, 3:11, 2:10) C и запоминает ее в e(:,:,:). CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank) CALL MPI_TYPE_EXTENT(MPI_REAL, sizeofreal, ierr) C создает тип данных для секции 1D CALL MPI_TYPE_VECTOR(9, 1, 2, MPI_REAL, oneslice, ierr) C создает тип данных для секции 2D CALL MPI_TYPE_HVECTOR(9, 1, 100*sizeofreal, oneslice, twoslice, ierr) C создает тип данных для секции в целом CALL MPI_TYPE_HVECTOR(9, 1, 100*100*sizeofreal, twoslice, threeslice, ierr) CALL MPI_TYPE_COMMIT(threeslice, ierr) CALL MPI_SENDRECV(a(1,3,2), 1, threeslice, myrank, 0, e, 9*9*9, MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr)
Пример 3.31 Копирование (строгое) нижней треугольной части матрицы
REAL a(100,100), b(100,100) INTEGER disp(100), blocklen(100), ltype, myrank, ierr INTEGER status(MPI_STATUS_SIZE) C копирует нижнюю треугольную часть массива a C в нижнюю треугольную часть массива b CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank) C вычисляет начало и размер каждого столбца DO i=1, 100 disp(i) = 100*(i-1) + i block(i) = 100-i END DO C создает тип данных для нижней треугольной части CALL MPI_TYPE_INDEXED(100, block, disp, MPI_REAL, ltype, ierr) CALL MPI_TYPE_COMMIT(ltype, ierr) CALL MPI_SENDRECV(a, 1, ltype, myrank, 0, b, 1, ltype, myrank, 0, MPI_COMM_WORLD, status, ierr)
Пример 3.32 Транспонирование матрицы.
REAL a(100,100), b(100,100) INTEGER row, xpose, sizeofreal, myrank, ierr INTEGER status(MPI_STATUS_SIZE) C транспонирование матрицы a в матрицу b CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank) CALL MPI_TYPE_EXTENT(MPI_REAL, sizeofreal, ierr) C создание типа данных для одной строки CALL MPI_TYPE_VECTOR(100, 1, 100, MPI_REAL, row, ierr) C создание типа данных для матрицы с расположением по строкам CALL MPI_TYPE_HVECTOR(100, 1, sizeofreal, row, xpose, ierr) CALL MPI_TYPE_COMMIT(xpose, ierr) C посылка матрицы с расположением по строкам и получение матрицы С с расположением по столбцам CALL MPI_SENDRECV(a, 1, xpose, myrank, 0, b, 100*100, MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr)
Пример 3.33 Другой подход к проблеме транспонирования:
REAL a(100,100), b(100,100) INTEGER disp(2), blocklen(2), type(2), row, row1, sizeofreal INTEGER myrank, ierr INTEGER status(MPI_STATUS_SIZE) CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank) C транспонирование матрицы a в матрицу b CALL MPI_TYPE_EXTENT(MPI_REAL, sizeofreal, ierr) C создание типа данных для одной строки CALL MPI_TYPE_VECTOR(100, 1, 100, MPI_REAL, row, ierr) C создание типа данных для одной строки disp(1) = 0 disp(2) = sizeofreal type(1) = row type(2) = MPI_UB blocklen(1) = 1 blocklen(2) = 1 CALL MPI_TYPE_STRUCT(2, blocklen, disp, type, row1, ierr) CALL MPI_TYPE_COMMIT(row1, ierr) C посылка 100 строк и получение с расположением по столбцам CALL MPI_SENDRECV(a, 100, row1, myrank, 0, b, 100*100, MPI_REAL, myrank, 0, MPI_COMM_WORLD, status, ierr)
Пример 3.34 Манипуляция с массивом структур.
struct Partstruct { int class; /* класс частицы */ double d[6]; /* координаты частицы */ char b[7]; /* некоторая дополнительная информация */ }; struct Partstruct particle[1000]; int i, dest, rank; MPI_Comm comm; /* построение типа данных описываемой структуры */ MPI_Datatype Particletype; MPI_Datatype type[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR}; int blocklen[3] = {1, 6, 7}; MPI_Aint disp[3]; int base; /* вычисление смещений элементов структуры */ MPI_Address(particle, disp); MPI_Address(particle[0].d, disp+1); MPI_Address(particle[0].b, disp+2); base = disp[0]; for (i=0; i <3; i++) disp[i] -= base; MPI_Type_struct(3, blocklen, disp, type, &Particletype); MPI_Datatype type1[4] = {MPI_INT, MPI_DOUBLE, MPI_CHAR, MPI_UB}; int blocklen1[4] = {1, 6, 7, 1}; MPI_Aint disp1[4]; /* вычисление смещений элементов структуры */ MPI_Address(particle, disp1); MPI_Address(particle[0].d, disp1+1); MPI_Address(particle[0].b, disp1+2); MPI_Address(particle+1, disp1+3); base = disp1[0]; for (i=0; i <4; i++) disp1[i] -= base; /* построение типа данных описываемой структуры */ MPI_Type_struct(4, blocklen1, disp1, type1, &Particletype); /* 4.1: посылка массива целиком */ MPI_Type_commit(&Particletype); MPI_Send(particle, 1000, Particletype, dest, tag, comm); /* 4.2: посылка только элементов класса нулевых частиц, предваряемых количеством таких элементов */ MPI_Datatype Zparticles; /* тип данных, описывающий все частицы класса нуль (необходимо повторное вычисление , если класс изменяется) */ MPI_Datatype Ztype; MPI_Aint zdisp[1000]; int zblock[1000], j, k; int zzblock[2] = {1,1}; MPI_Aint zzdisp[2]; MPI_Datatype zztype[2]; /* вычисление смещений класса нулевых частиц */ j = 0; for(i=0; i < 1000; i++) if (particle[i].class==0) { zdisp[j] = i; zblock[j] = 1; j++; } /* создание типа данных для класса нулевых частиц */ MPI_Type_indexed(j, zblock, zdisp, Particletype, &Zparticles); /* количество частиц */ MPI_Address(&j, zzdisp); MPI_Address(particle, zzdisp+1); zztype[0] = MPI_INT; zztype[1] = Zparticles; MPI_Type_struct(2, zzblock, zzdisp, zztype, &Ztype); MPI_Type_commit(&Ztype); MPI_Send(MPI_BOTTOM, 1, Ztype, dest, tag, comm); /* возможно более эффективный путь определения Zparticles */ /* последовательные частицы с индексом нуль обрабатываются как один блок */ j=0; for (i=0; i < 1000; i++) if (particle[i].index==0) { for (k=i+1; (k < 1000)&&(particle[k].index == 0) ; k++); zdisp[j] = i; zblock[j] = k-i; j++; i = k; } MPI_Type_indexed(j, zblock, zdisp, Particletype, &Zparticles); /* 4.3: посылка первых двух координат всем элементам */ MPI_Datatype Allpairs; /* datatype for all pairs of coordinates */ MPI_Aint sizeofentry; MPI_Type_extent(Particletype, &sizeofentry); /* размер элемента также может быть вычислен вычитанием адреса particle[0] из адреса particle[1] */ MPI_Type_hvector(1000, 2, sizeofentry, MPI_DOUBLE, &Allpairs); MPI_Type_commit(&Allpairs); MPI_Send(particle[0].d, 1, Allpairs, dest, tag, comm); /* альтернативное решение для 4.3 */ MPI_Datatype Onepair; /* тип данных для одной пары координат */ MPI_Aint disp2[3]; MPI_Datatype type2[3] = {MPI_LB, MPI_DOUBLE, MPI_UB}; int blocklen2[3] = {1, 2, 1}; MPI_Address(particle, disp2); MPI_Address(particle[0].d, disp2+1); MPI_Address(particle+1, disp2+2); base = disp2[0]; for (i=0; i<2; i++) disp2[i] -= base; MPI_Type_struct(3, blocklen2, disp2, type2, &Onepair); MPI_Type_commit(&Onepair); MPI_Send(particle[0].d, 1000, Onepair, dest, tag, comm);
Пример 3.35 Те же манипуляции, как и в предыдущем примере, но с использованием абсолютных адресов в типах данных.
struct Partstruct { int class; double d[6]; char b[7]; }; struct Partstruct particle[1000]; /* строится тип данных, описывающий первый элемент массива */ MPI_Datatype Particletype; MPI_Datatype type[3] = {MPI_INT, MPI_DOUBLE, MPI_CHAR}; int block[3] = {1, 6, 7}; MPI_Aint disp[3]; MPI_Address(particle, disp); MPI_Address(particle[0].d, disp+1); MPI_Address(particle[0].b, disp+2); MPI_Type_struct(3, block, disp, type, &Particletype); /* тип частицы описывает первый элемент массива - используя абсолютные адреса */ /* 5.1: посылка массива целиком */ MPI_Type_commit(&Particletype); MPI_Send(MPI_BOTTOM, 1000, Particletype, dest, tag, comm); /* 5.2: посылка элементов класса нуль, предваряемых числом таких элементов */ MPI_Datatype Zparticles, Ztype; MPI_Aint zdisp[1000] int zblock[1000], i, j, k; int zzblock[2] = {1,1}; MPI_Datatype zztype[2]; MPI_Aint zzdisp[2]; j=0; for (i=0; i < 1000; i++) if (particle[i].index==0) { for (k=i+1; (k < 1000)&&(particle[k].index = 0) ; k++); zdisp[j] = i; zblock[j] = k-i; j++; i = k; } MPI_Type_indexed(j, zblock, zdisp, Particletype, &Zparticles); /* Zparticles описывают частицы класса нуль, используя их абсолютные адреса*/ /* количество частиц */ MPI_Address(&j, zzdisp); zzdisp[1] = MPI_BOTTOM; zztype[0] = MPI_INT; zztype[1] = Zparticles; MPI_Type_struct(2, zzblock, zzdisp, zztype, &Ztype); MPI_Type_commit(&Ztype); MPI_Send(MPI_BOTTOM, 1, Ztype, dest, tag, comm);
Пример 3.36 Обработка объединений (unions).
union { int ival; float fval; } u[1000] int utype; /* все элементы uмеют идентичный тип; переменная utype хранит трек их текущего типа */ MPI_Datatype type[2]; int blocklen[2] = {1,1}; MPI_Aint disp[2]; MPI_Datatype mpi_utype[2]; MPI_Aint i,j; /* вычисляет тип данных MPI для каждого возможного типа union; считаем, что значения в памяти union выровнены по левой границе. */ MPI_Address(u, &i); MPI_Address(u+1, &j); disp[0] = 0; disp[1] = j-i; type[1] = MPI_UB; type[0] = MPI_INT; MPI_Type_struct(2, blocklen, disp, type, &mpi_utype[0]); type[0] = MPI_FLOAT; MPI_Type_struct(2, blocklen, disp, type, &mpi_utype[1]); for(i=0; i<2; i++) MPI_Type_commit(&mpi_utype[i]); /* фактический обмен */ MPI_Send(u, 1000, mpi_utype[utype], dest, tag, comm);
Закладки на сайте Проследить за страницей |
Created 1996-2024 by Maxim Chirkov Добавить, Поддержать, Вебмастеру |