/*!\file PetscMat.cpp
 * \brief: implementation of the PetscMat object
 */

/*Headers:*/
/*{{{*/
#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

#include <stdio.h>
#include <string.h>
#include "../petscincludes.h"
#include "../../../shared/shared.h"

/*}}}*/

/*PetscMat constructors and destructor*/
/*FUNCTION PetscMat::PetscMat(){{{*/
PetscMat::PetscMat(){
	this->matrix=NULL;
	#ifdef _HAVE_ADOLC_
	this->amatrix=NULL;
	#endif

}
/*}}}*/
/*FUNCTION PetscMat::PetscMat(int M,int N){{{*/
PetscMat::PetscMat(int M,int N){

	this->matrix=NewMat(M,N);
}
/*}}}*/
/*FUNCTION PetscMat::PetscMat(int M,int N, IssmDouble sparsity){{{*/
PetscMat::PetscMat(int M,int N, IssmDouble sparsity){

	this->matrix=NewMat(M,N,sparsity);
}
/*}}}*/
/*FUNCTION PetscMat(IssmDouble* serial_mat,int M,int N,IssmDouble sparsity){{{*/
PetscMat::PetscMat(IssmDouble* serial_mat,int M,int N,IssmDouble sparsity){

	int     i;
	int* idxm=NULL;
	int* idxn=NULL;
	
	if(M)idxm=xNew<int>(M);
	if(N)idxn=xNew<int>(N);

	for(i=0;i<M;i++)idxm[i]=i;
	for(i=0;i<N;i++)idxn[i]=i;


	this->matrix=NewMat(M,N,sparsity);
	MatSetValues(this->matrix,M,idxm,N,idxn,serial_mat,INSERT_VALUES);
	MatAssemblyBegin(this->matrix,MAT_FINAL_ASSEMBLY);
	MatAssemblyEnd(this->matrix,MAT_FINAL_ASSEMBLY);

	xDelete<int>(idxm);
	xDelete<int>(idxn);

}
/*}}}*/
/*FUNCTION PetscMat::PetscMat(int M,int N, int connectivity, int numberofdofspernode){{{*/
PetscMat::PetscMat(int M,int N, int connectivity,int numberofdofspernode){
	
	this->matrix=NewMat(M,N,connectivity,numberofdofspernode);

}
/*}}}*/
/*FUNCTION PetscMat::~PetscMat(){{{*/
PetscMat::~PetscMat(){
	MatFree(&this->matrix);
}
/*}}}*/

/*PetscMat specific routines: */
/*FUNCTION PetscMat::Echo{{{*/
void PetscMat::Echo(void){

	MatView(this->matrix,PETSC_VIEWER_STDOUT_WORLD);
}
/*}}}*/
/*FUNCTION PetscMat::Assemble{{{*/
void PetscMat::Assemble(void){

	_assert_(this->matrix);
	MatAssemblyBegin(this->matrix,MAT_FINAL_ASSEMBLY);
	MatAssemblyEnd(this->matrix,MAT_FINAL_ASSEMBLY);
	#if _PETSC_MAJOR_ == 2 
		MatCompress(this->matrix);
	#endif

}
/*}}}*/
/*FUNCTION PetscMat::Norm{{{*/
IssmDouble PetscMat::Norm(NormMode mode){


	IssmDouble norm=0;
	_assert_(this->matrix);
	MatNorm(this->matrix,ISSMToPetscNormMode(mode),&norm);
	
	return norm;

}
/*}}}*/
/*FUNCTION PetscMat::GetSize{{{*/
void PetscMat::GetSize(int* pM,int* pN){

	_assert_(this->matrix);
	MatGetSize(this->matrix,pM,pN);
}
/*}}}*/
/*FUNCTION PetscMat::GetLocalSize{{{*/
void PetscMat::GetLocalSize(int* pM,int* pN){

	_assert_(this->matrix);
	MatGetLocalSize(this->matrix,pM,pN);

}
/*}}}*/
/*FUNCTION PetscMat::MatMult{{{*/
void PetscMat::MatMult(PetscVec* X,PetscVec* AX){

	_assert_(this->matrix);
	_assert_(X->vector);
	MatMultPatch(this->matrix,X->vector,AX->vector);

}
/*}}}*/
/*FUNCTION PetscMat::Duplicate{{{*/
PetscMat* PetscMat::Duplicate(void){

	PetscMat* output=NULL;

	output=new PetscMat();
	_assert_(this->matrix);
	MatDuplicate(this->matrix,MAT_COPY_VALUES,&output->matrix);

	return output;

}
/*}}}*/
/*FUNCTION PetscMat::ToSerial{{{*/
IssmDouble* PetscMat::ToSerial(void){

	 IssmDouble* output=NULL;

	 MatToSerial(&output,this->matrix);
	 return output;

}
/*}}}*/
/*FUNCTION PetscMat::SetValues{{{*/
void PetscMat::SetValues(int m,int* idxm,int n,int* idxn,IssmDouble* values,InsMode mode){

	MatSetValues(this->matrix,m,idxm,n,idxn,values,ISSMToPetscInsertMode(mode));

}
/*}}}*/
/*FUNCTION PetscMat::Convert{{{*/
void PetscMat::Convert(MatrixType type){

	MatConvert(this->matrix,ISSMToPetscMatrixType(type),MAT_REUSE_MATRIX,&this->matrix);

}
/*}}}*/
