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