/*
* 2D HEAT EQUATION SOLVER
*
* Copyright (c) 2008 Tony Saad <saadtony@gmail.com>
* (Written by Tony Saad <saadtony@gmail.com>)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*--------------------------------------------------------*/
/* INCLUDE HEADERS
/*--------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctime>
/*--------------------------------------------------------*/
/* STRUCTURES
/*--------------------------------------------------------*/
struct ProblemInfo {
int numberOfNodesX;
int numberOfNodesY;
double endSimulationTime;
double thermalDiffusivity;
double CFL;
};
/*--------------------------------------------------------*/
/* FUNCTION PROTOTYPES
/*--------------------------------------------------------*/
bool processUserInput(ProblemInfo &theProblemInfo);
void setupBoundaryConditions(double** theArray, int arraySizeX, int arraySizeY);
void initializeInteriorNodes(double** theArray, int arraySizeX, int arraySizeY);
void initializeArray(double** theArray, int arraySizeX, int arraySizeY);
int* makeIntArray(int arraySize);
int** make2DIntArray(int arraySizeX, int arraySizeY);
double* makeDoubleArray(int arraySize);
double** make2DDoubleArray(int arraySizeX, int arraySizeY);
void saveToFile(ProblemInfo theProblemInfo, double** theData,char* theFileName);
/*--------------------------------------------------------*/
/* MAIN PROGRAM
/*--------------------------------------------------------*/
int main(int argc, char* argv[]) {
/***********************************************************/
/* VARIABLES
/***********************************************************/
int nNodesX,
nNodesY;
int ix = 0,
jy =0;
double endSimulationTime = 1.0,
CFL = 0.25,
deltaT,
deltaX,
deltaY,
deltaXSquared,
deltaYSquared;
clock_t startCPUTime = 0,
endCPUTime = 0,
totalCPUTime = 0;
ProblemInfo probInfo;
/* process user input */
if (!processUserInput(probInfo)) return 0;
startCPUTime = clock();
nNodesX = probInfo.numberOfNodesX;
nNodesY = probInfo.numberOfNodesY;
deltaX =(double) 1.0/probInfo.numberOfNodesX;
deltaY =(double) 1.0/probInfo.numberOfNodesY;
deltaXSquared = deltaX*deltaX;
deltaYSquared = deltaY*deltaY;
CFL = probInfo.CFL;
deltaT = CFL*(deltaXSquared*deltaYSquared)/((deltaXSquared+deltaYSquared)*probInfo.thermalDiffusivity);
/* memory allocation */
double** uOld = make2DDoubleArray(nNodesX,nNodesY);
initializeArray(uOld,nNodesX,nNodesY);
double** uNew = make2DDoubleArray(nNodesX,nNodesY);
setupBoundaryConditions(uNew,nNodesX,nNodesY);
/***********************************************************/
/* COMPUTATION
/***********************************************************/
int iter = 0;
while(iter++*deltaT <= probInfo.endSimulationTime) {
if (iter % 100 == 0) {
printf("Iteration: %i - Current Time = %lf s\n", iter-1, (iter-1)*deltaT);
}
/* calculate the new values of the dependant variable */
for (ix = 1; ix < (nNodesX-1); ix++) {
for (jy = 1; jy < (nNodesY-1) ;jy++){
uNew[ix][jy] = uOld[ix][jy] + CFL*(uOld[ix+1][jy] + uOld[ix-1][jy] - 4*uOld[ix][jy] + uOld[ix][jy-1] + uOld[ix][jy+1]);
}
}
/* set uOld = uNew */
for (ix = 1; ix < (nNodesX-1); ix++) {
for (jy = 1; jy < (nNodesY-1) ;jy++){
uOld[ix][jy] = uNew[ix][jy];
}
}
}
endCPUTime = clock();
/* compute the total wall time */
totalCPUTime= endCPUTime-startCPUTime;
/* compute the maximum wall time */
printf("Wall clock time %lf s\n",(double) totalCPUTime/CLOCKS_PER_SEC);
saveToFile(probInfo,uNew,"C:\\2D Heat Equation.dat");
/* works only in Windows */
system("pause");
return 0;
}
/*--------------------------------------------------------*/
/* FUNCTIONS
/*--------------------------------------------------------*/
bool processUserInput(ProblemInfo &theProblemInfo) {
printf("Enter the number of nodes in the x direction:");
fflush(stdout);
scanf("%d",&theProblemInfo.numberOfNodesX);
printf("Enter the number of nodes in the y direction:");
fflush(stdout);
scanf("%d",&theProblemInfo.numberOfNodesY);
if (theProblemInfo.numberOfNodesX == 0 || theProblemInfo.numberOfNodesY==0) return 0;
printf("Enter thermalDiffusivity:");
fflush(stdout);
scanf("%lf",&theProblemInfo.thermalDiffusivity);
printf("Enter end simulation time:");
fflush(stdout);
scanf("%lf",&theProblemInfo.endSimulationTime);
printf("Enter the Courant-Friedrichs-Lewy (CFL) number \n (For stability, the CFL number should be less than 0.25 \n based on a different number of nodes in the X and Y directions):");
fflush(stdout);
scanf("%lf",&theProblemInfo.CFL);
return 1;
}
void setupBoundaryConditions(double** theArray,int arraySizeX, int arraySizeY) {
/* set boundary conditions for ix, jy = 0 and ix, jy = n-1 */
/* Here, we are using Dirichlet conditions */
int ix, jy;
double leftBC = 10,
rightBC = 10,
topBC = 20,
bottomBC = 20;
/* setup the bottom and top BCs, jy = 0 and jy = n-1 or arraySizeY - 1 */
for (ix = 0; ix < arraySizeX; ix++) {
theArray[ix][0] = bottomBC; //bottom BC
theArray[ix][arraySizeY-1] = topBC; //top BC
}
/* setup the left and right BCs, ix = 0 and ix = arraySizeX - 1 */
for (jy = 0; jy < arraySizeY; jy++) {
theArray[0][jy] = leftBC; //left BC
theArray[arraySizeX-1][jy] = rightBC; //right BC
}
/* set the values at the corner nodes as averages of both sides*/
// bottom left
theArray[0][0] = (leftBC + bottomBC)*0.5;
// top left
theArray[0][arraySizeY-1] = 0.5*(topBC + leftBC);
// top right
theArray[arraySizeX-1][arraySizeY-1] = 0.5*(topBC + rightBC);
// bottom right
theArray[arraySizeX-1][0] = 0.5*(bottomBC + rightBC);
}
void initializeInteriorNodes(double** theArray, int arraySizeX, int arraySizeY) {
int ix, jy;
for (ix = 1; ix <= arraySizeX - 2; ix++) {
for (jy = 1; jy <= arraySizeY - 2; jy++) {
theArray[ix][jy] = 0.0;
}
}
}
void initializeArray(double** theArray, int arraySizeX, int arraySizeY) {
setupBoundaryConditions(theArray,arraySizeX,arraySizeY);
initializeInteriorNodes(theArray,arraySizeX,arraySizeY);
}
double** make2DDoubleArray(int arraySizeX, int arraySizeY) {
double** theArray;
theArray = (double**) malloc(arraySizeX*sizeof(double*));
for (int ix = 0; ix < arraySizeX; ix++) {
theArray[ix] =(double*) malloc(arraySizeY*sizeof(double));
}
return theArray;
}
double* makeDoubleArray(int arraySize) {
double* theArray;
theArray = (double*) malloc(arraySize*sizeof(double));
return theArray;
}
int* makeIntArray(int arraySize) {
int* theArray;
theArray = (int*) malloc(arraySize*sizeof(int));
return theArray;
}
int** make2DIntArray(int arraySizeX, int arraySizeY) {
int** theArray;
theArray = (int**) malloc(arraySizeX*sizeof(int*));
for (int ix = 0; ix < arraySizeX; ix++) {
theArray[ix] =(int*) malloc(arraySizeY*sizeof(int));
}
return theArray;
}
void saveToFile(ProblemInfo theProblemInfo, double** theData, char* theFileName) {
int nNodesX = theProblemInfo.numberOfNodesX;
int nNodesY = theProblemInfo.numberOfNodesY;
double deltaX =(double) 1.0/theProblemInfo.numberOfNodesX;
double deltaY =(double) 1.0/theProblemInfo.numberOfNodesY;
FILE* theDataFile;
theDataFile = fopen(theFileName,"w");
for (int ix = 0; ix < nNodesX; ix++) {
for (int jy = 0; jy < nNodesY ;jy++){
fprintf(theDataFile,"%lf %lf %lf\n",ix*deltaX,jy*deltaY,theData[ix][jy]);
}
fprintf(theDataFile,"\n");
}
fclose(theDataFile);
}