lundi 30 octobre 2017

How to do the Unpack to convert the 1D array to 2d array in c++?

I have the code that generate a no of files that are the values in the heat simulation for each time step. I would like to parallelize the main loop which performs the simulation. I want to parallelize my code by dividing up the heat simulation by splicing it into the specified number of rectangles. I may want to use the MPI_recv/send to do what is sometimes called a "halo" transfer and i need to mention that each rectangle needs the surrounding values to be able to calculate it's values for the next time step. I making each process to initialize it's own smaller sized array. To validate my results, I need to transfer data from each other process using MPI_Gatherv and then write the entire simulation to the output file. I have done the pack (2D->1D)and now i want to know how can i dot the unpack (1D->2D). Note: Still my MPI_Gatherv is has issue for displacement (displacement: where the data is going to be sent from in the array to each process). In my code i considered to not using the MPI_Rec/Send. Please let me know if i am wrong by not using. My goal in this programming is to use the MPI_Gather.

For compiling, i am doing with mpicxx mpi_code.cxx -o mip_code -Wall and For executing i am doing with mpirun -np #(which is: height*width) mip_code

example of executing: mpirun -np 4 mip_code simtest 20 20 2 2 10 simtest: is the output file.

Please fill free to let me know if you have any code or idea that help me to do the unpack (1D -> 2D) in a way that the order of the output 2d will be the same as input 2d,.Please include you c++ program that i can use it for improve my code.

Thanks a lot.

Below is my code. Please let me know if there is any other informations that i need to provide. Please do not down vote if you find any mistake from my side. Please comment the mistake and i will definetly fix it ASAP.

#include <iomanip>
using std::fixed;
using std::setprecision;
using std::setw;

#include <iostream>
using std::cout;
using std::endl;

#include <fstream>
using std::ofstream;

#include <sstream>
using std::ostringstream;

#include <string>
using std::string;

#include "mpi.h"

//write the state of the smulation to a file
void write_simulation_state(string name, int height, int width, int time_step, double **values) {
    ostringstream filename;
    filename << name << "_" << height << "x" << width << "_" << time_step;

    ofstream outfile(filename.str());
    //Integer type with a width of exactly 32 bits.
    for (uint32_t i = 0; i < height; i++) {
        for (uint32_t j = 0; j < width; j++) {
            outfile << setw(10) << fixed << setprecision(5) << values[i][j];
        }
        outfile << endl;
    }
}

//Void function for Packing
//void pack(double **my_values, double *my_pack, int my_rank, int halo_width, int halo_height){

int main(int argc, char **argv) {
    int comm_sz;
    int my_rank;
    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &comm_sz);
    cout << "process just got comm_sz: " << comm_sz <<endl;
    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    cout << "process just got my_rank: " << my_rank <<endl;
    int height, width;
    int my_height;
    int my_width;
    int vertical_slices, horizontal_slices;
    int time_steps;
    int np;
    int base_width;
    int base_height;

    if (argc != 7) {
        cout << "ERROR, incorrect arguments." << endl;
        cout << "usage:" << endl;
        cout << "\t" << argv[0] << " <simulation name : string> <height : int> <width : int> <vertical slices : int> <horizontal slices : int> <time steps : int>" << endl;
        exit(1);
    }

    string simulation_name(argv[1]);
    //the height and width of the simulation
    height = atoi(argv[2]);
    width = atoi(argv[3]);

    //horizontal and vertical slices will be used to determine how to divide up your MPI processes
    vertical_slices = atoi(argv[4]);
    horizontal_slices = atoi(argv[5]);
    np = vertical_slices * horizontal_slices;
    cout << "The No of process at first is :  " << np << endl;
    //how long to run the simulation for
    time_steps = atoi(argv[6]);
    // widths and height initializing

    int *block_width = new int[vertical_slices];
    base_width = width / vertical_slices;
    int remaining_width = width % vertical_slices;
    for(int i=0; i< vertical_slices; i++){
        block_width[i] = base_width;
        if(i < remaining_width )
            block_width[i]++;
    }

    int *block_height = new int[horizontal_slices];
    base_height = height / horizontal_slices;
    int remaining_height = height % horizontal_slices;
    for(int i=0; i< horizontal_slices; i++){
        block_height[i] = base_height;
        if(i < remaining_height )
            block_height[i]++;
    }

    my_width = block_width[my_rank % vertical_slices];
    my_height = block_height[my_rank / vertical_slices];

    double **my_values = new double*[my_height];
    double **my_values_next = new double*[my_height];
    for (uint32_t i = 0; i < my_height; i++) {
        my_values[i] = new double[my_width];
        my_values_next[i] = new double[my_width];
        for (uint32_t j = 0; j < my_width; j++) {
            my_values[i][j] = 0.0;
            my_values_next[i][j] = 0.0;
        }
    }
    // width including halo
    int halo_width = my_width;

    if(vertical_slices != 1 && my_rank % vertical_slices == 0){ //this means we are on the left edge and we will have a halo on the right edge. this means we need to increase halo width by one
        halo_width++;
        cout << "left slice done " << endl;
    } else if (vertical_slices != 1 && my_rank % vertical_slices == (vertical_slices -1)) {
        halo_width++;
        cout << "right slice done" << endl;
    } else if (vertical_slices != 1){
        halo_width +=2;
        cout << "middle one done "<< endl;
    }

    int halo_height = my_height;

    if(horizontal_slices != 1 && my_rank / vertical_slices == 0){
        halo_height++;
        cout << "left slice done " << endl;
    } else if (horizontal_slices != 1 && my_rank / vertical_slices == (horizontal_slices -1)) {
        halo_height++;
        cout << "right slice done" << endl;
    } else if (horizontal_slices != 1){
        halo_height +=2;
        cout << "middle one done "<< endl;
    }
    //put a heat source on the left column of the simulation
    if(my_rank % vertical_slices == 0){
        for (uint32_t i = 0; i < my_height; i++) {
            my_values[i][0] = 1.0;
            my_values_next[i][0] = 1.0;
        }
    }
    //put a cold source on the left column of the simulation
    if(my_rank % vertical_slices == vertical_slices -1){
        for (uint32_t i = 0; i < my_height; i++) {
            my_values[i][my_width - 1] = -1.0;
            my_values_next[i][my_width - 1] = -1.0;
        }
    }
    int sx;
    if(my_rank % vertical_slices == 0){
        sx=0;
    } else {
        sx =1;
    }
    int sy;
    if(my_rank / vertical_slices == 0){
        sy=0;
    } else {
        sy =1;
    }
    int ex;
    if(my_rank % vertical_slices == (vertical_slices -1)){
        ex=0;
    } else {
        ex =1;
    }
    int ey;
    if(my_rank / vertical_slices == (horizontal_slices -1)){
        ey=0;
    } else {
        ey =1;
    }
    int p = 0;
    double *my_pack = new double[my_height * my_width];
    for(int i=sy; i < ey; i++){
        for(int j= sx; j < ex; j++){
            my_pack[p++] = my_values[i][j];
        }
    }
    //initialize all values to 0
    double **values;// = new double*[height];
    double *big_values; //So this is the 1D arrey that holding all values that comes from the values.
    big_values = new double[height * width];
    if (my_rank == 0){
        values = new double*[height];
        // big_values = new double[height * width];
        //double **values_next = new double*[height];
        for (uint32_t i = 0; i < height; i++) {
            values[i] = new double[width];
            //            for (uint32_t j = 0; j < width; j++) {
            //                values[i][j] = 0.0;
            //
            //            }
        }
    }

    int *displacements = new int[comm_sz];
    int *slice_sizes = new int[comm_sz];
    // loop to fill the inside of slice size
    int count = 0.0; // i think i may need to start with this
    int x=0;
    for (int i =0; i < vertical_slices; i++) { // my geuss is (int i = 0; i < comm_sz; i++)
        for(int j =0; j< horizontal_slices; j++){
            slice_sizes[x] =block_width[i] * block_height[j];
            x++;
            displacements[x] = ????? // I dont know how to go through count??

        }
    }
    MPI_Gatherv( my_pack /* the data we're gathering*/,
                slice_sizes[my_rank] /* the size of the data we're
                                      sending to the target process */,
                MPI_DOUBLE /* the data type we're sending */,
                big_values /* where we're receiving the data */,
                slice_sizes /* the amount of data we’re receiving
                             per process*/,
                displacements /* where the data from each process is
                               going to be stored in the array */,
                MPI_DOUBLE /* the data type we're receiving */,
                0 /* the process we're sending from*/,
                MPI_COMM_WORLD);

    //    //put a heat source on the left column of the simulation
    //    for (uint32_t i = 0; i < height; i++) {
    //        values[i][0] = 1.0;
    //        //values_next[i][0] = 1.0;
    //    }
    //
    //    //put a cold source on the left column of the simulation
    //    for (uint32_t i = 0; i < height; i++) {
    //        values[i][width - 1] = -1.0;
    //
    //    }
    if (my_rank == 0)
        write_simulation_state(simulation_name, height, width, 0, values);
    int np2;
    np2 = vertical_slices * horizontal_slices;
    cout << "The No of process at middle is :  " << np2 << endl;
    //update the heat values at each step of the simulation for all internal values
    for (uint32_t time_step = 1; time_step <= time_steps; time_step++) {
        //the border values are sources/sinks of heat
        for (uint32_t i = 1; i < height - 1; i++) {
            for (uint32_t j = 1; j < width - 1; j++) {
                /*double up = values[i - 1][j];
                 double down = values[i + 1][j];
                 double left = values[i][j - 1];
                 double right = values[i][j + 1];

                 //set the values of the next time step of the heat simulation
                 values_next[i][j] = (up + down + left + right) / 4.0;*/
            }
        }

        //swap the values arrays
        //double **temp = values_next;
        //values_next = values;
        //values = temp;

        //// Unpack

        //store the simulation state so you can compare this to your MPI version
        if (my_rank == 0){
            write_simulation_state(simulation_name, height, width, time_step, values);
        }
    }

    //free the memory
    //delete[] big_values;
    //    for (<#initialization#>; <#condition#>; <#increment#>) {
    //        delete[] values[i];
    //    }
    //    delete[] values;
    MPI_Finalize();
    return 0;
}

Aucun commentaire:

Enregistrer un commentaire