Untitled

                Never    
C
       
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <math.h>

#define a 1e5
#define EPSILON 1e-6
#define SQUARE_SIDE_LENGTH 2.0
#define X_NULL -1
#define Y_NULL -1
#define Z_NULL -1

#define X_SIZE_NODES 384
#define Y_SIZE_NODES 384
#define Z_SIZE_NODES 384

#define UP Y_SIZE_NODES * Z_SIZE_NODES
#define DOWN 0

#define arr(a,b,c) (a) * Y_SIZE_NODES * Z_SIZE_NODES + (b) * Z_SIZE_NODES + (c)


int wsize, wrank, xThrNodesSize;
double xStride, yStride, zStride;

double realPhi(double x, double y, double z){
    return x*x + y*y + z*z;
}

double realRo(double x, double y, double z){
    return 6 - a * realPhi(x, y, z);
}

void initBorders(double* nodePhi, int xStart){
    for(int i = 0, localStart = xStart; i < xThrNodesSize; ++i, ++localStart){
        for(int j = 0; j < Y_SIZE_NODES ; ++j){
            for(int k = 0; k < Z_SIZE_NODES; ++k){
                if(localStart*j*k == 0 || localStart == (X_SIZE_NODES - 1) || j == (Y_SIZE_NODES - 1) || k == (Z_SIZE_NODES - 1))
                    nodePhi[arr(i,j,k)] = realPhi(X_NULL + localStart*xStride, Y_NULL + j*yStride, Z_NULL + k*zStride);
            }
        }
    }
}

double getConstant(){
    return 1.0 / ((2.0 / (xStride * xStride)) + (2.0 / (yStride * yStride)) + (2.0 / (zStride * zStride)) + a);
}

void setLocalRo (double* nodeRo, int xstart){
    for(int i = 0; i < xThrNodesSize; ++i){
        for(int j = 0; j < Y_SIZE_NODES; ++j){
            for(int k = 0; k < Z_SIZE_NODES; ++k){
                nodeRo[arr(i,j,k)] = realRo(X_NULL + (xstart + i) * xStride, Y_NULL + j*yStride, Z_NULL + k*zStride);
            }
        }
    }
}

void sendRecvData(double* localNodePhi , MPI_Request* request, double* borders){
    if(wrank){
        MPI_Isend(&localNodePhi[0], Y_SIZE_NODES * Z_SIZE_NODES,MPI_DOUBLE, wrank - 1,UP, MPI_COMM_WORLD, &request[0]);
        MPI_Irecv(&borders[UP], Y_SIZE_NODES * Z_SIZE_NODES, MPI_DOUBLE, wrank - 1, DOWN,MPI_COMM_WORLD, &request[1]);
    }

    if(wrank != wsize - 1){
        MPI_Isend(&localNodePhi[xThrNodesSize - 1], Y_SIZE_NODES * Z_SIZE_NODES,MPI_DOUBLE, wrank + 1, DOWN, MPI_COMM_WORLD, &request[2]);
        MPI_Irecv(&borders[DOWN], Y_SIZE_NODES * Z_SIZE_NODES, MPI_DOUBLE, wrank + 1, UP, MPI_COMM_WORLD, &request[3]);
    }
}

void waitDataSendRecv(MPI_Request* request){
    if(wrank){
        MPI_Wait(&request[0],MPI_STATUS_IGNORE);
        MPI_Wait(&request[1], MPI_STATUS_IGNORE);
    }

    if(wrank != wsize - 1){
        MPI_Wait(&request[2],MPI_STATUS_IGNORE);
        MPI_Wait(&request[3], MPI_STATUS_IGNORE);
    }

}

void refreshBorders (double* borders, double* localNodePhi, double* nodeRo, double constantBeforePhi){
    int phiX, phiY, phiZ, i;

    for(int j = 1; j < Y_SIZE_NODES - 1; ++j){
        for(int k = 1; k < Z_SIZE_NODES - 1; ++k){
            if(wrank){
                phiX = (localNodePhi[arr(1,j,k)] + (&borders[UP])[j * Z_SIZE_NODES + k])/(xStride * xStride);
                phiY = (localNodePhi[arr(0,j+1,k)] + localNodePhi[arr(0 ,j- 1,k)])/(yStride * yStride);
                phiZ = (localNodePhi[arr(0,j,k+1)] + localNodePhi[arr(0 ,j,k - 1)])/(zStride * zStride);
                localNodePhi[arr(0,j,k)] = constantBeforePhi * (phiX + phiY + phiZ - nodeRo[arr(0,j,k)]);
            }
            if(wrank != wsize - 1){
                i = xThrNodesSize - 1;
                phiX = (localNodePhi[arr(i - 1,j,k )] + (&borders[DOWN])[j * Z_SIZE_NODES + k])/(xStride * xStride);
                phiY = (localNodePhi[arr(i,j+1,k )] + localNodePhi[arr(i ,j- 1,k)])/(yStride * yStride);
                phiZ = (localNodePhi[arr(i,j,k+1 )] + localNodePhi[arr(i ,j,k - 1)])/(zStride * zStride);
                localNodePhi[arr(i,j,k)] = constantBeforePhi * (phiX + phiY + phiZ - nodeRo[arr(i,j,k)]);
            }
        }
    }

}

double calculate(double* nodesLocal, double* oldNodePhi, double* nodeRo, double constant ){
    double localMax = 0, phiX, phiY, phiZ, diff;
    for(int i = 1; i < xThrNodesSize - 1; ++i){
        for(int j = 0; j < Y_SIZE_NODES - 1; ++j){
            for(int k = 0; k < Z_SIZE_NODES - 1; ++k){
                oldNodePhi[arr(i,j,k)] = nodesLocal[arr(i,j,k)];
                phiX = (nodesLocal[arr(i+1,j,k)] + nodesLocal[arr(i - 1,j,k)])/(xStride * xStride);
                phiY = (nodesLocal[arr(i,j+1,k)] + nodesLocal[arr(i ,j- 1,k)])/(yStride * yStride);
                phiZ = (nodesLocal[arr(i,j,k+1)] + nodesLocal[arr(i ,j,k - 1)])/(zStride * zStride);
                nodesLocal[arr(i,j,k)] = constant * (phiX + phiY + phiZ - nodeRo[arr(i,j,k)]);
                diff = fabs(nodesLocal[arr(i,j,k)] - oldNodePhi[arr(i,j,k)]);
                if(diff > localMax){
                    localMax = diff;
                }
            }
        }
    }
    return localMax;
}

double getRealDiff(double* nodePhi,int xThrNodesSize,int xstart){
    double localMax = 0, globalMax, diff, realphi;

    for(int i = 1; i < xThrNodesSize - 1; ++i){
        for(int j = 1; j < Y_SIZE_NODES - 1; ++j){
            for(int k = 1; k < Z_SIZE_NODES - 1; ++k){
                realphi = realPhi(xstart + i*xStride, Y_NULL + j*yStride, Z_NULL + k*zStride);
                diff = nodePhi[arr(i,j,k)] - realphi;
                if(diff > localMax){
                    localMax = diff;
                }
            }
        }
    }
    MPI_Allreduce(&localMax,&globalMax,1,MPI_DOUBLE, MPI_MAX,MPI_COMM_WORLD);
    return globalMax;
}

void Jakobi(){
    MPI_Comm_size(MPI_COMM_WORLD, &wsize);
    MPI_Comm_rank(MPI_COMM_WORLD, &wrank);

    // SHARED
    xStride = SQUARE_SIDE_LENGTH / (X_SIZE_NODES - 1);
    yStride = SQUARE_SIDE_LENGTH / (Y_SIZE_NODES - 1);
    zStride = SQUARE_SIDE_LENGTH / (Z_SIZE_NODES - 1);

    // line count per thr
    xThrNodesSize = X_SIZE_NODES / wsize;
    // start line for thr
    int xStart = wrank * xThrNodesSize;

    int thrNodesSize = xThrNodesSize * Y_SIZE_NODES * Z_SIZE_NODES ;
    double* nodesLocal = calloc(thrNodesSize ,sizeof(double));
    double* nodeRo = calloc(thrNodesSize, sizeof(double));
    double* oldNodePhi = calloc(thrNodesSize, sizeof(double));

    initBorders(nodesLocal, xStart);

    double constant = getConstant();
    double* borders = malloc(sizeof(double) * 2 * Y_SIZE_NODES * Z_SIZE_NODES);

    double start = MPI_Wtime();
    setLocalRo(nodeRo,xStart);

    int cycleFlag = 0;

    //double phiX, phiY, phiZ;
    MPI_Request request[4];
    double localMax = 0, globalMax;

    do{
        sendRecvData(nodesLocal,request,borders);

        localMax = calculate(nodesLocal,oldNodePhi, nodeRo,constant);

        waitDataSendRecv(request);

        refreshBorders(borders,nodesLocal, nodeRo, constant);

        MPI_Allreduce(&localMax, &globalMax, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
        cycleFlag = globalMax > EPSILON;

        localMax = 0;

    } while (cycleFlag);

    double end = MPI_Wtime();

    double realDiff = getRealDiff(nodesLocal, xThrNodesSize, (X_NULL + xStart*xStride));
    if(!wrank){
        printf("realDiff: %lf\n", realDiff);
        printf("Time taken: %lf\n", end - start);
    }

    free(nodesLocal);
    free(borders);
    free(oldNodePhi);
    free(nodeRo);
}

int main(int argc, char* argv[]){
    MPI_Init(&argc, &argv);
    Jakobi();
    MPI_Finalize();
    return 0;
}

Raw Text