#include "pargrid.h"

/*+ main - the main routine for this grid program

     Input Parameters:
     argc, argv - the usual
     argv[1] - the number of processors in the x direction
     argv[2] - the number of processors in the y direction
     argv[3] - the number of processors in the z direction
     argv[4] - the number of points in the x direction on each processor
               do not use less than 3 points
     argv[5] - the number of points in the y direction on each processor
               do not use less than 3 points
     argv[6] - the number of points in the z direction on each processor
               do not use less than 3 points
     argv[7] - symmetric matrix = 0, nonsymmetric matrix = 1
     argv[8] - number of components per grid point
     argv[9] - 0 = do not use, 1 = use inode/clique stuff
     argv[10] - 0 = ICC, 1 = ILU 
     argv[11] - 0 => method = CG, 1 => method = GMRES 

     Notes: The grid program solves a linear system associated with
            a 3-D grid distributed across the processors.  The 3-D
            grid is partitioned in all three dimensions among the
            processors.  A 7pt stencil is used.

 +*/

int main(int argc, char **argv)
{
	par_grid grid;
	BSprocinfo *procinfo;
	int	inode, method, scaling, num_rhs;
	int	nonsym_storage, nonsymmetric;

	/* Call BSinit() to initialize BlocklSolve and MPI */
    BSinit(&argc,&argv);

	/* set up the context for BlockSolve */
	procinfo = BScreate_ctx(); CHKERRN(0);
	/* tell it to print out some information on the reordering */
	BSctx_set_pr(procinfo,TRUE); CHKERRN(0);

	if(procinfo->my_id==0) {
		printf("\n");
		printf("************** Blocksolve Example Grid5 *******************\n");
	}

	/* read in grid parameters */
	if (argc < 14) {
		SETERRC(ARG_ERR,"Argument list too small\n");
		if(procinfo->my_id==0) {
		printf("Example: mpirun -np P grid5.ARCH PX PY PZ NX NY NZ SYM NC IN PRE METHOD SCALE NUM_RHS\n");
		printf("ARCH = Machine architecture\n");
		printf("P = number of processors\n");
		printf("PX = the number of processors in the x direction\n");
		printf("PY = the number of processors in the y direction\n");
		printf("PZ = the number of processors in the z direction\n");
		printf("NX = number of points in the x direction on each processor\n");
		printf("NY = number of points in the y direction on each processor\n");
		printf("NZ = number of points in the z direction on each processor\n");
		printf("SYM = 0, generate symmetric matrix, = 1, generate nonsymmetric\n");
		printf("NC = number of components per grid point\n");
		printf("IN = 0, do not use, = 1, use inode/clique stuff\n");
		printf("PRE = 0, compute ICC factor, = 1, compute ILU factor\n");
		printf("METHOD = 0, use PCG, = 1, use GMRES\n");
		printf("SCALE = 0, do not scale matrix, = 1, scale matrix\n");
		printf("NUM_RHS = number of RHS to solve for\n");
		}
		return(-1);
	}
	sscanf(argv[1],"%d",&grid.worker_x);
	sscanf(argv[2],"%d",&grid.worker_y);
	sscanf(argv[3],"%d",&grid.worker_z);
	if (procinfo->my_id == 0) {
		printf("o  ");
		printf("Number of workers (x,y,z): %d %d %d\n",
			grid.worker_x,grid.worker_y,grid.worker_z);
	}
	if (procinfo->nprocs != grid.worker_x*grid.worker_y*grid.worker_z) {
		SETERRC(ARG_ERR,"Number of processors is not correct\n");
		return(-1);
	}
	sscanf(argv[4],"%d",&grid.l_num_x);
	sscanf(argv[5],"%d",&grid.l_num_y);
	sscanf(argv[6],"%d",&grid.l_num_z);
	sscanf(argv[7],"%d",&nonsymmetric);
	sscanf(argv[8],"%d",&grid.ncomp);
	sscanf(argv[9],"%d",&inode);
	sscanf(argv[10],"%d",&nonsym_storage);
	sscanf(argv[11],"%d",&method);
	sscanf(argv[12],"%d",&scaling);
	sscanf(argv[13],"%d",&num_rhs);
	if(grid.ncomp<1) grid.ncomp = 1;
	if(grid.ncomp>20) grid.ncomp = 20;
	grid.symmetric = (!nonsymmetric);
	grid.icc_storage = (!nonsym_storage);
	grid.positive = FALSE;

	/* tell it to use the nonsymmetric matrix data structure */
	if (procinfo->my_id == 0) {
		printf("o  ");
		if(nonsymmetric) 
			printf("Generating nonsymmetric matrix\n");
		else 
			printf("Generating symmetric matrix\n");
	}

	if (procinfo->my_id == 0) {
		printf("o  ");
		printf("Multi component grid, %d components per point\n",grid.ncomp);
	}

	/* decide whether to look for i-nodes or cliques */
	if(inode) {
		BSctx_set_si(procinfo,FALSE); CHKERRN(0);
	} else {
		BSctx_set_si(procinfo,TRUE); CHKERRN(0);
	}

	/* decide on preconditioner */
	if(nonsym_storage) {
		BSctx_set_pre(procinfo,PRE_ILU); CHKERRN(0);
	} else {
		BSctx_set_pre(procinfo,PRE_ICC); CHKERRN(0);
	}

	/* decide on iterative method */
	if(method) {
		BSctx_set_method(procinfo,GMRES); CHKERRN(0);
	} else {
		BSctx_set_method(procinfo,CG); CHKERRN(0);
	}

	BSctx_set_scaling(procinfo,scaling); CHKERRN(0);
	BSctx_set_num_rhs(procinfo,num_rhs); CHKERRN(0);

	/* local grid size and type */
	grid.type = 7;
	if (procinfo->my_id == 0) {
		printf("o  ");
		printf("Local discretizations (x,y,z): %d %d %d\n",
			grid.l_num_x,grid.l_num_y,grid.l_num_z);
	}

	/* call the worker */
	worker(&grid,procinfo); 

	/* print out the log info (if desired) */
	/* MLOG_PRINT(procinfo); */
	
	if(procinfo->my_id==0) {
		printf("************ End Blocksolve Example Grid5 *****************\n");
		printf("\n");
	}

	/* print logging if enabled */
	BSprint_log(procinfo); CHKERRN(0);

	/* free the context */
	BSfree_ctx(procinfo); CHKERRN(0);

	/* finalize BlockSolve and MPI */
	BSfinalize();

	exit(0);
}


syntax highlighted by Code2HTML, v. 0.9.1