/*!\file:  MeshPartition.cpp
 * \brief: partition mesh according to number of areas, using Metis library.

	usage:
	[element_partitioning,node_partitioning]=MeshPartition(model,numareas)
	
	%Info needed from model are the following: 
	%mesh info: 
	numberofelements,numberofgrids,elements,elements_width
	%Non-extruded 2d mesh info
	nel2d,nods2d,elements2d,
	%Extruded 2d mesh info
	nel2d_ext,nods2d_ext,elements2d_ext,
	%Diverse
	numlayers,meshtype)

	output:
	vector of partitioning area numbers, for every element.
	vector of partitioning area numbers, for every node.
*/
	
#include "./MeshPartition.h"


void mexFunction( int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) {


	/*Indexing: */
	int i,j;

	/* required input: */
	char* meshtype=NULL;
	int numberofelements;
	int numberofgrids;
	double* elements=NULL;
	int     elements_width;

	int numberofelements2d;
	int numberofgrids2d;
	double* elements2d=NULL;

	int numlayers;
	int numareas=1;

	/* output: */
	int*    int_element_partitioning=NULL;
	int*    int_node_partitioning   =NULL;
	double* element_partitioning    =NULL;
	double* node_partitioning       =NULL;


	/*Boot module: */
	MODULEBOOT();

	/*checks on arguments on the matlab side: */
	CheckNumMatlabArguments(nlhs,NLHS,nrhs,NRHS,__FUNCT__,&MeshPartitionUsage);

	/*Fetch data: */
	FetchData((void**)&meshtype,NULL,NULL,mxGetField(MODEL,0,"type"),"String",NULL);
	FetchData((void**)&numberofelements,NULL,NULL,mxGetField(MODEL,0,"numberofelements"),"Integer",NULL);
	FetchData((void**)&numberofgrids,NULL,NULL,mxGetField(MODEL,0,"numberofgrids"),"Integer",NULL);
	FetchData((void**)&elements,NULL,&elements_width,mxGetField(MODEL,0,"elements"),"Matrix","Mat");

	
	
	if (strcmp(meshtype,"3d")==0){
	
		FetchData((void**)&numberofelements2d,NULL,NULL,mxGetField(MODEL,0,"numberofelements2d"),"Integer",NULL);
		FetchData((void**)&numberofgrids2d,NULL,NULL,mxGetField(MODEL,0,"numberofgrids2d"),"Integer",NULL);
		FetchData((void**)&elements2d,NULL,NULL,mxGetField(MODEL,0,"elements2d"),"Matrix","Mat");

	}
	FetchData((void**)&numlayers,NULL,NULL,mxGetField(MODEL,0,"numlayers"),"Integer",NULL);
	FetchData((void**)&numareas,NULL,NULL,NUMAREAS,"Integer",NULL);

	/*Run partitioning algorithm based on a "clever" use of the Metis partitioner: */
	MeshPartitionx(&int_element_partitioning,&int_node_partitioning,numberofelements,numberofgrids,elements,
		numberofelements2d,numberofgrids2d,elements2d,numlayers,elements_width,meshtype,numareas);

	/*Post process node_partitioning and element_partitioning to be in double format. Metis needed them in int* format: */
	element_partitioning=(double*)xmalloc(numberofelements*sizeof(double));
	for (i=0;i<numberofelements;i++){
		element_partitioning[i]=(double)int_element_partitioning[i]+1; //Metis indexing from 0, matlab from 1.
	}
	
	node_partitioning=(double*)xmalloc(numberofgrids*sizeof(double));
	for (i=0;i<numberofgrids;i++){
		node_partitioning[i]=(double)int_node_partitioning[i]+1; //Metis indexing from 0, matlab from 1.
	}

	/*Write data:*/
	WriteData(ELEMENTPARTITIONING,element_partitioning,numberofelements,1,"Matrix","Mat");
	WriteData(NODEPARTITIONING,node_partitioning,numberofgrids,1,"Matrix","Mat");
	
	/*Free ressources:*/
	//don't! let matlab do it.


	/*end module: */
	MODULEEND();
}

void MeshPartitionUsage(void){
	printf("   usage:\n");
	printf("   [element_partitioning,node_partitioning]=MeshPartition(model,numareas)");
	printf("   where:\n");
	printf("      model is a @model class object instance,numareas is the number of processors on which partitioning will occur.\n");
	printf("      element_partitioning is a vector of partitioning area numbers, for every element.\n");
	printf("      node_partitioning is a vector of partitioning area numbers, for every node.\n");
	printf("\n");
}
