#include "mpi.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define STRIP 0
#define BLOCK 1
#define NO 1
#define YES 0
#define TRUE 1
#define FALSE 0
#define EDGE 1
#define INTERIOR 0
#define NORTH 0
#define SOUTH 1
#define WEST 2
#define EAST 3
#define THRESHOLD 0.05f
#define AMBIENT 20.0f
#define FIRE 100.0f
int p, kp, mode;
int height, width;
int roomSizeX, roomSizeY;
float maxChange = 0.0f;
int main(int argc, char **argv)
{
//simulation configuraton:
int roomSizeX = 16, roomSizeY = 16;
int change = YES, loop = YES;
float room[roomSizeX][roomSizeY];
// fireplace = 1/5th of roomsize, placed center
int fireplaceA = (roomSizeX*2)/5;
int fireplaceB = (roomSizeX*3)/5;
int myid;
float maxchange;
char name[16];
int length;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &p);
kp = (int)sqrt((float)p);
if (p != (kp * kp)) //the number of processes must have an integer square root
return 1; //nonzero return
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Get_processor_name(name, &length);
//calculate dimensions of blocks/strips
if(mode == STRIP)
{
width = roomSizeX/p;
height = roomSizeY;
}
else if(mode == BLOCK)
{
width = roomSizeX/kp;
height = roomSizeY/kp;
}
float sauna[width][height]; //strip or block
float tempSauna[width+2][height+2]; //temp array with space for "invisible" line
float west[height], east[height], south[width], north[width];
// set an ambient temperature
int i, j;
for(i=0; i<width; i++)
{
for(j=0; j<height; j++)
{
sauna[i][j] = AMBIENT;
}
}
// main loop
int count=0;
if (myid == 0)
{
printf("Sauna Simulator v0.1 by Truls and Jon for IPDC F2010 assignment 1.\n");
printf("Running %dx%d room simulation using %d procs with a threshold value of %g.\n", roomSizeX, roomSizeY, p, THRESHOLD);
if (mode == BLOCK)
printf("Block mode set, %dx%d grid per proc.\n", width, height);
else
printf("Strip mode set, %dx%d grid per proc.\n", width, height);
}
printf("%c: rank %d ready.\n", name[0], myid);
while(loop == YES)
{
count++;
// temp working copy
for(i=0; i<width; i++)
{
for(j=0; j<height; j++)
{
tempSauna [i+1][j+1] = sauna[i][j];
}
}
// fill outer boundary with temperatures, move out of loop FIXME
for(i=0;i<width;i++)
{
if (EDGE == getBound(myid, NORTH))
{
int temp = (myid * width) + i; // position in room
if ((fireplaceA <= temp) && (temp <= fireplaceB)) //fireplace between point A and B
tempSauna[i+1][0] = FIRE;
else
tempSauna[i+1][0] = AMBIENT;
// if ((temp+1)%10==0) printf("%d:%g ",temp,tempSauna[i+1][0]);
// fflush(stdout);
}
else
{
north[i]=sauna[i][0];
}
}
for(i=0;i<width;i++)
{
if (EDGE == getBound(myid, SOUTH))
{
tempSauna[i+1][height+1] = AMBIENT;
}
else
{
south[i]=sauna[i][height-1];
}
}
for(j=0;j<height;j++)
{
if (EDGE == getBound(myid, WEST))
{
tempSauna[0][j+1] = AMBIENT;
}
else
{
west[j]=sauna[0][j];
}
}
for(j=0;j<height;j++)
{
if (EDGE == getBound(myid, EAST))
{
tempSauna[width+1][j+1] = AMBIENT;
}
else
{
east[j]=sauna[width-1][j];
}
}
// distribute border arrays
MPI_Request request;
int tag = 35634;
int interiordebug = FALSE;
if(INTERIOR == getBound(myid,NORTH))
{
if (interiordebug == TRUE) printf("%s/%d sending size %d array to %d\n",name, myid, width, myid-kp);
MPI_Isend(&north, width, MPI_FLOAT, myid-kp, tag, MPI_COMM_WORLD, &request);
//printf("%c#%d: sender nord array med size %d, til rank %d \n ", name[0], count, width, myid-kp);
}
if(INTERIOR == getBound(myid,SOUTH))
{
if (interiordebug == TRUE) printf("%s/%d sending size %d array to %d\n",name, myid, width, myid+kp);
MPI_Isend(&south, width, MPI_FLOAT, myid+kp, tag, MPI_COMM_WORLD, &request);
//printf("%c#%d: sender syd array med size %d, til rank %d \n ", name[0], count, width, myid+kp);
}
if(INTERIOR == getBound(myid,WEST))
{
if (interiordebug == TRUE) printf("%s/%d sending size %d array to %d\n",name, myid, height, myid-1);
MPI_Isend(&west, height, MPI_FLOAT, myid-1, tag, MPI_COMM_WORLD, &request);
/*
int l;
for (l = 0; l < height; l++)
{
printf("%c#%d: venstre no %d: %g \n ", name[0], count, l, west[l]);
}
printf("\n");
*/
}
if(INTERIOR == getBound(myid,EAST))
{
if (interiordebug == TRUE) printf("%s/%d sending size %d array to %d\n",name, myid, height, myid+1);
MPI_Isend(&east, height, MPI_FLOAT, myid+1, tag, MPI_COMM_WORLD, &request);
/*
if(myid == 0)
{
int l;
for (l = 0; l < height; l++)
{
printf("SENDT %c#%d: hoejre no %d: %g \n", name[0], count, l,east[l]);
}
printf("\n");
}
*/
}
// recieve border arrays
MPI_Status status;
if(INTERIOR == getBound(myid,NORTH))
{
MPI_Recv(&north, width, MPI_FLOAT, myid-kp, tag, MPI_COMM_WORLD, &status);
for (i = 0; i < width; i++)
{
tempSauna[i+1][0] = north[i];
}
}
if(INTERIOR == getBound(myid,SOUTH))
{
MPI_Recv(&south, width, MPI_FLOAT, myid+kp, tag, MPI_COMM_WORLD, &status);
for (i = 0; i < width; i++)
{
tempSauna[i+1][height+1] = south[i];
}
}
if(INTERIOR == getBound(myid,WEST))
{
MPI_Recv(&west, height, MPI_FLOAT, myid-1, tag, MPI_COMM_WORLD, &status);
//printf("%s/%d ", name, myid);
for (i = 0; i < height; i++)
{
tempSauna[0][i+1] = west[i];
//printf("w%d:%f ", i, west[i]);
}
//printf("\n");
}
if(INTERIOR == getBound(myid,EAST))
{
MPI_Recv(&east, height, MPI_FLOAT, myid+1, tag, MPI_COMM_WORLD, &status);
for (i = 0; i < height; i++)
{
tempSauna[width+1][i+1] = east[i];
}
if(myid == 0)
{
int l;
//for (l = 0; l < height; l++)
//{
//printf("MODTAGET: %c#%d: fra venstre no %d: %g \n", name[0], count, l,east[l]);
//}
}
}
// calculate temperatures
float temp, dif;
for (i = 0; i < width; i++)
{
//printf("%c: ", name[0]);
for (j = 0; j < height; j++)
{
temp = sauna[i][j];
sauna[i][j] = ( tempSauna[i+1][j] +
tempSauna[i][j+1] +
tempSauna[i+2][j+1] +
tempSauna[i+1][j+2] ) / 4.0f;
//printf("%g ", sauna[i][j]);
temp -= sauna[i][j];
// because apparently math.h doesnt work (abs)
if (temp < 0.0f)
temp *= -1.0f;
if (temp > maxChange)
maxChange = temp;
}
}
if (maxChange < THRESHOLD)
{
change = NO;
}
maxChange = 0.0f;
MPI_Barrier(MPI_COMM_WORLD);
MPI_Reduce(&change, &loop, 1, MPI_INT, MPI_PROD,0, MPI_COMM_WORLD); //multiply changes, put to loop
MPI_Bcast(&loop,1, MPI_INT, 0, MPI_COMM_WORLD); //broadcast loop from master process
if(loop == NO)
{
printf("%c#%d: stopping.\n", name[0], count);
float sendarray[width*height];
int m;
for(m=0;m<width*height;m++)
{
sendarray[m] = sauna[m%width][m/height];
// printf("%c#%d: sendarray plads %d, værdi: %g \n", name[0], count, m, sendarray[m]);
}
float temparray[roomSizeX*roomSizeY];
MPI_Barrier(MPI_COMM_WORLD);
MPI_Gather(&sendarray, width*height, MPI_FLOAT, &temparray, width*height, MPI_FLOAT,0,MPI_COMM_WORLD);
if(myid==0)
{
if(mode == STRIP)
{
//printf("%c#: width er: %d, heighth er %d \n", name[0], width, height);
int n;
for(n=0;n < roomSizeX*roomSizeY; n++)
{
int xval = n%width +(n/(height*width))*width;
int yval = (n/width)%height;
//printf("%c#: x = %d, y = %d \n", name[0], xval, yval);
room[xval][yval]=temparray[n];
}
}
else if(mode == BLOCK)
{
//printf("%c#: block width %d, heigth %d.\n", name[0], width, height);
int n;
for(n=0;n < roomSizeX*roomSizeY; n++)
{
int xval = n%width +(((n/(height*width))%kp)*width);
int yval = (n/width)%(height)+(n/(width*height*kp))*height;
// printf("%c#: x = %d, y = %d \n", name[0], xval, yval);
room[xval][yval]=temparray[n];
}
}
printf("%c#%d: room array done.\n", name[0], count);
int x,y;
//begin bitmap write vars
int r, g, b;
int rgb;
// printf ("writing bitmap to file bitmap.raw\n");
int rawbitmap[roomSizeX*roomSizeY];
float scale = 256 / (FIRE - AMBIENT);
// printf("scale:%g\n\n\n",scale);
int c = 0;
float btemp;
FILE * pFile;
pFile = fopen ("bitmap.raw", "wb");
//end bitmap write vars
sleep(1); // to get nice text output
printf("Printing out results:\n");
for(x=0;x<roomSizeX;x++)
{
printf("%d;", x);
for(y=0;y<roomSizeY;y++)
{
printf("%g;", room[x][y]);
//printf("%X%X", 0, 0);
btemp = room[x][y] - AMBIENT;
r = (int) (scale * btemp); r = r << 16;
//printf("r=%d ",r);
//printf("%X", (int) (scale * btemp));
g = 30; g = g << 8;
//printf("g=%d ",g);
//printf("%X", 30);
b = (int) (256.0f - scale * btemp);
//printf("b=%d ",b);
//printf("%X", (int) (256.0f - scale * btemp));
rawbitmap[c] = (r + g + b);
//printf("0x%X ", rawbitmap[c]);
c++;
}
printf("\n");
fflush(stdout);
}
fwrite (rawbitmap, sizeof(rgb), roomSizeX*roomSizeY, pFile);
fclose (pFile);
//writeFloatArrayToRawBitmap(&room, roomSizeX, roomSizeY);
}
}
}
// second make the updated array
// calculate if we need too continue loop (gange loop sammen hvis nul bliv ved)
//printf("\n\n");
MPI_Finalize();
}
//returns EDGE if the boundary is facing a wall/the fireplace, INTERIOR otherwise
int getBound(int id,int dir)
{
if(mode == STRIP)
{
if((dir == NORTH) || (dir == SOUTH))
return EDGE;
else if ((dir == WEST) && (id == 0))
return EDGE;
else if ((dir == EAST) && (id == p - 1))
return EDGE;
}
else if (mode == BLOCK)
{
if ((dir == NORTH) && (0 == id/kp))
return EDGE;
else if ((dir == SOUTH) && (kp-1) == ((id)/kp))
return EDGE;
else if ((dir == WEST) && ((id % kp) == 0))
return EDGE;
else if ((dir == EAST) && ((id % kp) == kp - 1))
return EDGE;
}
return INTERIOR;
}
void writeFloatArrayToRawBitmap(float** fDblArr, int x, int y)
{
char r, g, b;
int rgb;
// printf ("writing bitmap to file bitmap.raw\n");
int rawbitmap[x*y];
int i, j;
float scale = 256 / (FIRE - AMBIENT);
int c = 0;
float temp;
// FILE * pFile;
// pFile = fopen ("bitmap.raw", "wb");
for (i = 0; i < x; i++)
{
for (j = 0; j < y; j++)
{
temp = fDblArr[i][j];//fejl her
r = (char) scale * temp;
g = (char) 0;
b = (char) (1.0f/scale) * temp;
rawbitmap[c] = r << 16 + g << 8 + b;
printf("%c ", rawbitmap[c]);
c++;
}
}
// fwrite (rawbitmap, sizeof(rgb), x*y, pFile);
// fclose (pFile);
}