int main(int argc, char **argv) {

    physics    *phys = PhysicsCreate();
    structMesh *mesh = MeshCreate();
    double     **c   = ConcentrationCreate(mesh, phys);
    double     finalTime = 0.5;

    ConvectionSolve2d(mesh, phys, c, finalTime);

    double L2, Linf;
    NormErr(mesh, phys, finalTime, c, &L2, &Linf);
    printf("The Mesh Grid, [%d, %d]\n", mesh->ndim1, mesh->ndim2);
    printf("The Norm Error, L2=%f, Linf=%f\n", L2, Linf);

    free(phys);
    Matrix_free(c);
    MeshFree(mesh);
    return 0;
}
/////////////////////////////////////
// Name:	
// Purpose:	
// Output:	
// Return:	
/////////////////////////////////////
PUBLIC hMDL MDLGenMap(unsigned int newID, float mapSizeX, float mapSizeZ, float height, float r,
				 unsigned int numIter, hTXT texture, GFXMATERIAL *mat)
{
	int size = 1<<numIter;
	int numVtx = (size+1)*(size+1);

	//allocate the points
	float *points;

	//HACK for now...
	points = (float*)GFX_MALLOC(sizeof(float)*(numVtx+2));
	if(!points)
	{ ASSERT_MSG(0, "Unable to allocate points", "Error in MDLGenMap"); return 0; }

	//generate the points!
	_MapGeneratePoints(points, height, r, size);

	hMDL newMdl = (hMDL)GFX_MALLOC(sizeof(gfxModel));

	if(!newMdl)
	{ ASSERT_MSG(0, "Unable to allocate new model", "Error in ModelGenMap"); return 0; }

	//fill 'er up
	newMdl->ID = newID;
	newMdl->numMaterial = 1;

	if(texture)
	{
		newMdl->textures = (hTXT*)GFX_MALLOC(sizeof(hTXT)*newMdl->numMaterial);
		if(!newMdl->textures)
		{ ASSERT_MSG(0, "Unable to allocate model textures", "Error in ModelGenMap"); return 0; }

		newMdl->textures[0] = texture; 
		TextureAddRef(newMdl->textures[0]);
	}

	newMdl->materials = (GFXMATERIAL*)GFX_MALLOC(sizeof(GFXMATERIAL)*newMdl->numMaterial);
	if(!newMdl->materials)
	{ ASSERT_MSG(0, "Unable to allocate materials", "Error in ModelGenMap"); return 0; }

	if(!mat)
	{
		newMdl->materials[0].Diffuse.r = 1.0f;
		newMdl->materials[0].Diffuse.g = 1.0f;
		newMdl->materials[0].Diffuse.b = 1.0f;
		newMdl->materials[0].Diffuse.a = 1.0f;
		//newMdl->materials[0].Specular = newMdl->materials[0].Emissive = newMdl->materials[0].Ambient = newMdl->materials[0].Diffuse;
		newMdl->materials[0].Ambient = newMdl->materials[0].Diffuse;
		//newMdl->materials[0].Power = 1.0f;
	}
	else
		memcpy(newMdl->materials, mat, sizeof(GFXMATERIAL));	

	//////////////////////////////////////////////////////////////
	//now time to stuff it all in the D3D vertex buffer
	//create the mesh
	MeshCreate(&newMdl->mesh, 1, numVtx);
	MeshInitGroup(&newMdl->mesh, 0, "RANDOMMAP", 0, size*size*2);
	//////////////////////////////////////////////////////////////

	/////////////////
	//now fill 'er up
	gfxVtx *ptrVtx, *thisVtx;

	

	if(MeshLockVtx(&newMdl->mesh, 0, &ptrVtx) != RETCODE_SUCCESS)
	{ return 0; }

	int maxV = size+1;

	//fill in data, just go through the lists and fill in stuff
	for(int rowV = 0; rowV < maxV; rowV++)
	{
		for(int colV = 0; colV < maxV; colV++)
		{
			thisVtx = &CELL(ptrVtx, rowV, colV, maxV);

			thisVtx->x = colV*mapSizeX;
			thisVtx->y = CELL(points, rowV, colV, maxV);
			thisVtx->z = rowV*mapSizeZ;

			_GFXVtxSetTxtCoordAll(thisVtx, thisVtx->x/TextureGetWidth(texture), 
										   thisVtx->z/TextureGetHeight(texture));
		}
	}

	MeshUnlockVtx(&newMdl->mesh);
	/////////////////

	/////////////////
	//now fill the index buffer up
	unsigned short *ptrInd;

	if(MeshLockInd(&newMdl->mesh, 0, 0, &ptrInd) != RETCODE_SUCCESS)
	{ return 0; }

	//fill in data
	int numCol = size; //number of col
	int numRow = size; //number of row
	int max = numCol+1;
	int numDot = MeshGetNumVtx(&newMdl->mesh)-max; //number of dots to iterate (minus last row)
	int indIter = NUMPTFACE*2; //we are going to make two faces per cel

	for(int row = 0, ind = 0; row < numRow; row++)
	{
		for(int col = 0; col < numCol; col++)
		{
			/*
			0-----3
			|\    |
			|  \  |
			|    \|
			1-----2
			*/

			int dot = col+(row*max);
			
			//first face
			ptrInd[ind] = dot; ptrInd[ind+1] = dot+max; ptrInd[ind+2] = ptrInd[ind+1]+1;

			//second face
			ptrInd[ind+3] = ptrInd[ind+2]; ptrInd[ind+4] = dot+1; ptrInd[ind+5] = ptrInd[ind];
			
			ind += indIter;
		}
	}

	MeshUnlockInd(&newMdl->mesh, 0);
	/////////////////

	//This outta make lighting easy
	MeshComputeNormals(&newMdl->mesh);

	//clean up stuff
	GFX_FREE(points);

	//append to list
	g_MDLLIST.insert(g_MDLLIST.end(), (unsigned int)newMdl);

	return newMdl;
}