/*!\file Vertex.c
 * \brief: implementation of the Vertex object
 */

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

#include <string.h>
#include "./objects.h"
#include "../EnumDefinitions/EnumDefinitions.h"
#include "../shared/shared.h"
#include "../include/include.h"
/*}}}*/

/*Vertex constructors and destructor:*/
/*FUNCTION Vertex::Vertex() {{{1*/
Vertex::Vertex(){
	return;
}
/*}}}*/
/*FUNCTION Vertex::Vertex(int vertex_id, double vertex_x, double vertex_y, double vertex_z, double vertex_sigma){{{1*/
Vertex::Vertex(int vertex_id, int vertex_sid,double vertex_x, double vertex_y, double vertex_z, double vertex_sigma,int vertex_connectivity){
	this->Init(vertex_id, vertex_sid,vertex_x, vertex_y, vertex_z, vertex_sigma,vertex_connectivity);
}
/*}}}*/
/*FUNCTION Vertex::Vertex(int vertex_id, int vertex_sid,int i, IoModel* iomodel) {{{1*/
Vertex::Vertex(int vertex_id, int vertex_sid,int i, IoModel* iomodel){

	_assert_(iomodel->Data(MeshXEnum) && iomodel->Data(MeshYEnum) && iomodel->Data(MeshZEnum));
	_assert_(iomodel->Data(BedEnum) && iomodel->Data(ThicknessEnum) && iomodel->numbernodetoelementconnectivity);

	this->Init(vertex_id, vertex_sid, iomodel->Data(MeshXEnum)[i],iomodel->Data(MeshYEnum)[i],iomodel->Data(MeshZEnum)[i],(iomodel->Data(MeshZEnum)[i]-iomodel->Data(BedEnum)[i])/(iomodel->Data(ThicknessEnum)[i]),iomodel->numbernodetoelementconnectivity[i]);

}
/*}}}*/
/*FUNCTION Vertex::~Vertex() {{{1*/
Vertex::~Vertex(){
	return;
}
/*}}}*/
/*FUNCTION Vertex::Init{{{1*/
void Vertex::Init(int vertex_id, int vertex_sid,double vertex_x, double vertex_y, double vertex_z, double vertex_sigma,int vertex_connectivity){

	/*all the initialization has been done by the initializer, just fill in the id: */
	this->id=vertex_id;
	this->sid=vertex_sid;
	this->x=vertex_x;
	this->y=vertex_y;
	this->z=vertex_z;
	this->sigma=vertex_sigma;
	this->connectivity=vertex_connectivity;
	this->dof=UNDEF;

	return;
}
/*}}}*/

/*Object virtual functions definitions:*/
/*FUNCTION Vertex::Echo{{{1*/
void Vertex::Echo(void){

	printf("Vertex:\n");
	printf("   id: %i\n",id);
	printf("   sid: %i\n",sid);
	printf("   x: %g\n",x);
	printf("   y: %g\n",y);
	printf("   z: %g\n",z);
	printf("   sigma: %g\n",sigma);
	printf("   connectivity: %i\n",connectivity);
	printf("   dof: %i\n",dof);
	printf("   clone: %i\n",clone);

	return;
}
/*}}}*/
/*FUNCTION Vertex::DeepEcho{{{1*/
void Vertex::DeepEcho(void){
	this->Echo();
}
/*}}}*/
/*FUNCTION Vertex::Id{{{1*/
int    Vertex::Id(void){ return id; }
/*}}}*/
/*FUNCTION Vertex::MyRank {{{1*/
int    Vertex::MyRank(void){ 
	extern int my_rank;
	return my_rank; 
}
/*}}}*/
#ifdef _SERIAL_
/*FUNCTION Vertex::Marshall {{{1*/
void  Vertex::Marshall(char** pmarshalled_dataset){

	char* marshalled_dataset=NULL;
	int   enum_type=0;

	/*recover marshalled_dataset: */
	marshalled_dataset=*pmarshalled_dataset;

	/*get enum type of Vertex: */
	enum_type=VertexEnum;

	/*marshall enum: */
	memcpy(marshalled_dataset,&enum_type,sizeof(enum_type));marshalled_dataset+=sizeof(enum_type);

	/*marshall Vertex data: */
	memcpy(marshalled_dataset,&id,sizeof(id));marshalled_dataset+=sizeof(id);
	memcpy(marshalled_dataset,&sid,sizeof(sid));marshalled_dataset+=sizeof(sid);
	memcpy(marshalled_dataset,&x,sizeof(x));marshalled_dataset+=sizeof(x);
	memcpy(marshalled_dataset,&y,sizeof(y));marshalled_dataset+=sizeof(y);
	memcpy(marshalled_dataset,&z,sizeof(z));marshalled_dataset+=sizeof(z);
	memcpy(marshalled_dataset,&sigma,sizeof(sigma));marshalled_dataset+=sizeof(sigma);
	memcpy(marshalled_dataset,&connectivity,sizeof(connectivity));marshalled_dataset+=sizeof(connectivity);
	memcpy(marshalled_dataset,&dof,sizeof(dof));marshalled_dataset+=sizeof(dof);
	memcpy(marshalled_dataset,&clone,sizeof(clone));marshalled_dataset+=sizeof(clone);

	*pmarshalled_dataset=marshalled_dataset;
	return;
}
/*}}}*/
/*FUNCTION Vertex::MarshallSize {{{1*/
int   Vertex::MarshallSize(){
	
	return sizeof(id)+
		sizeof(sid)+
		sizeof(x)+
		sizeof(y)+
		sizeof(z)+
		sizeof(sigma)+
		sizeof(connectivity)+
		sizeof(dof)+
		sizeof(clone)+
		+sizeof(int); //sizeof(int) for enum type
}
/*}}}*/
/*FUNCTION Vertex::Demarshall {{{1*/
void  Vertex::Demarshall(char** pmarshalled_dataset){

	char* marshalled_dataset=NULL;
	int   i;

	/*recover marshalled_dataset: */
	marshalled_dataset=*pmarshalled_dataset;

	/*this time, no need to get enum type, the pointer directly points to the beginning of the 
	 *object data (thanks to DataSet::Demarshall):*/

	memcpy(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
	memcpy(&sid,marshalled_dataset,sizeof(sid));marshalled_dataset+=sizeof(sid);
	memcpy(&x,marshalled_dataset,sizeof(x));marshalled_dataset+=sizeof(x);
	memcpy(&y,marshalled_dataset,sizeof(y));marshalled_dataset+=sizeof(y);
	memcpy(&z,marshalled_dataset,sizeof(z));marshalled_dataset+=sizeof(z);
	memcpy(&sigma,marshalled_dataset,sizeof(sigma));marshalled_dataset+=sizeof(sigma);
	memcpy(&connectivity,marshalled_dataset,sizeof(connectivity));marshalled_dataset+=sizeof(connectivity);
	memcpy(&dof,marshalled_dataset,sizeof(dof));marshalled_dataset+=sizeof(dof);
	memcpy(&clone,marshalled_dataset,sizeof(clone));marshalled_dataset+=sizeof(clone);

	/*return: */
	*pmarshalled_dataset=marshalled_dataset;
	return;
}
/*}}}*/
#endif
/*FUNCTION Vertex::ObjectEnum{{{1*/
int Vertex::ObjectEnum(void){

	return VertexEnum;

}
/*}}}*/
/*FUNCTION Vertex::copy {{{1*/
Object* Vertex::copy() {

	return new Vertex(*this); 

}
/*}}}*/

/* DofObject routines: */
/*FUNCTION Vertex::DistributeDofs{{{1*/
void  Vertex::DistributeDofs(int* pdofcount){

	int i;
	extern int my_rank;
	int dofcount;

	dofcount=*pdofcount;
	
	if(this->clone){
		/*This vertex is a clone! Don't distribute dofs, it will get them from another cpu!*/
		return;
	}

	/*This vertex should distribute his dof, go ahead: */
	this->dof=dofcount;
	dofcount++;

	/*Assign output pointers: */
	*pdofcount=dofcount;

}
/*}}}*/
/*FUNCTION Vertex::OffsetDofs{{{1*/
void  Vertex::OffsetDofs(int dofcount){
	
	int i;
	extern int my_rank;
	
	if(this->clone){
		/*This vertex is a clone, don't offset the dofs!: */
		return;
	}

	/*This vertex should offset his dof, go ahead: */
	this->dof+=dofcount;
}
/*}}}*/
/*FUNCTION Vertex::ShowTrueDofs{{{1*/
void  Vertex::ShowTrueDofs(int* truedofs){

	int j;
	extern int my_rank;
	
	/*Are we a clone? : */
	if(this->clone)return;

	/*Ok, we are not a clone, just plug our dof into truedofs: */
	truedofs[this->id-1]=this->dof;

}
/*}}}*/
/*FUNCTION Vertex::UpdateCloneDofs{{{1*/
void  Vertex::UpdateCloneDofs(int* alltruedofs){

	int j;
	extern int my_rank;
	
	/*If we are not a clone, don't update, we already have dofs!: */
	if(this->clone==0)return;

	/*Ok, we are a clone node, but we did not create the dof for this vertex 
	 * Therefore, our dof is garbage right now. Go pick it up in the alltruedofs: */
	this->dof=alltruedofs[id-1];
}
/*}}}*/
/*FUNCTION Vertex::SetClone {{{1*/
void  Vertex::SetClone(int* minranks){

	extern int my_rank;

	if (minranks[id-1]==my_rank){
		this->clone=0;
	}
	else{
		/*!there is a cpu with lower rank that has the same vertex, 
		therefore, I am a clone*/
		this->clone=1; 	
	}

}
/*}}}*/

/*Vertex management: */
/*FUNCTION Vertex::Connectivity{{{1*/
int    Vertex::Connectivity(void){return connectivity;}
/*}}}*/
/*FUNCTION Vertex::Sid{{{1*/
int    Vertex::Sid(void){ return sid; }
/*}}}*/
/*FUNCTION Vertex::UpdateVertexPosition {{{1*/
void  Vertex::UpdatePosition(Vec vz,Parameters* parameters,double* thickness,double* bed){

	double oldz,newz;
	double dt,velz;

	/*Get time stepping*/
	parameters->FindParam(&dt,TimesteppingTimeStepEnum);

	/*sigma remains constant. z=bed+sigma*thickness*/
	oldz = this->z;
	newz = bed[this->dof]+sigma*thickness[this->dof];
	velz = (newz-oldz)/dt;
	this->z = newz;

	/*put vz in vector*/
	VecSetValue(vz,this->dof,velz,INSERT_VALUES);
}
/*}}}*/
