/*!\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,numberofvertices,elements,elements_width
	%Non-extruded 2d mesh info
	nel2d,nods2d,elements2d,
	%Extruded 2d mesh info
	nel2d_ext,nods2d_ext,elements2d_ext,
	%Diverse
	numberoflayers,dim)

	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: */
	int     dim;
	int     numberofelements;
	int     numberofvertices;
	double *elements         = NULL;
	int     elements_width;

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

	int numberoflayers;
	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(&dim,mxGetAssignedField(MODEL,0,"dimension"));
	FetchData(&numberofelements,mxGetAssignedField(MODEL,0,"numberofelements"));
	FetchData(&numberofvertices,mxGetAssignedField(MODEL,0,"numberofvertices"));
	FetchData(&elements,NULL,&elements_width,mxGetAssignedField(MODEL,0,"elements"));

	if (dim==3){
		FetchData(&numberofelements2d,mxGetAssignedField(MODEL,0,"numberofelements2d"));
		FetchData(&numberofvertices2d,mxGetAssignedField(MODEL,0,"numberofvertices2d"));
		FetchData(&elements2d,NULL,NULL,mxGetAssignedField(MODEL,0,"elements2d"));
	}
	FetchData(&numberoflayers,mxGetAssignedField(MODEL,0,"numberoflayers"));
	FetchData(&numareas,NUMAREAS);

	/*Run partitioning algorithm based on a "clever" use of the Metis partitioner: */
	MeshPartitionx(&int_element_partitioning,&int_node_partitioning,numberofelements,numberofvertices,elements,
		numberofelements2d,numberofvertices2d,elements2d,numberoflayers,elements_width,dim,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(numberofvertices*sizeof(double));
	for (i=0;i<numberofvertices;i++){
		node_partitioning[i]=(double)int_node_partitioning[i]+1; //Metis indexing from 0, matlab from 1.
	}

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

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

void MeshPartitionUsage(void){
	_printLine_("   usage:");
	_printString_("   [element_partitioning,node_partitioning]=MeshPartition(md.mesh,numpartitions)");
	_printLine_("   where:");
	_printLine_("      element_partitioning is a vector of partitioning area numbers, for every element.");
	_printLine_("      node_partitioning is a vector of partitioning area numbers, for every node.");
	_printLine_("");
}
