Code

Two-Dimensional Heat Equation in C

/*
* 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);
}

Leave a Reply