Следующие примеры демонстрируют использование производных типов данных
Пример 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);