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

/*Include files: {{{*/
#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() {{{*/
Vertex::Vertex(){
	return;
}
/*}}}*/
/*FUNCTION Vertex::Vertex(int vertex_id, IssmDouble vertex_x, IssmDouble vertex_y, IssmDouble vertex_z, IssmDouble vertex_sigma){{{*/
Vertex::Vertex(int vertex_id, int vertex_sid,IssmDouble vertex_x, IssmDouble vertex_y, IssmDouble vertex_z, IssmDouble 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) {{{*/
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() {{{*/
Vertex::~Vertex(){
	return;
}
/*}}}*/
/*FUNCTION Vertex::Init{{{*/
void Vertex::Init(int vertex_id, int vertex_sid,IssmDouble vertex_x, IssmDouble vertex_y, IssmDouble vertex_z, IssmDouble 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{{{*/
void Vertex::Echo(void){

	_printLine_("Vertex:");
	_printLine_("   id: " << id);
	_printLine_("   sid: " << sid);
	_printLine_("   x: " << x);
	_printLine_("   y: " << y);
	_printLine_("   z: " << z);
	_printLine_("   sigma: " << sigma);
	_printLine_("   connectivity: " << connectivity);
	_printLine_("   dof: " << dof);
	_printLine_("   clone: " << clone);

	return;
}
/*}}}*/
/*FUNCTION Vertex::DeepEcho{{{*/
void Vertex::DeepEcho(void){
	this->Echo();
}
/*}}}*/
/*FUNCTION Vertex::Id{{{*/
int    Vertex::Id(void){ return id; }
/*}}}*/
/*FUNCTION Vertex::MyRank {{{*/
int    Vertex::MyRank(void){ 
	extern int my_rank;
	return my_rank; 
}
/*}}}*/
/*FUNCTION Vertex::ObjectEnum{{{*/
int Vertex::ObjectEnum(void){

	return VertexEnum;

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

	return new Vertex(*this); 

}
/*}}}*/

/* DofObject routines: */
/*FUNCTION Vertex::DistributeDofs{{{*/
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{{{*/
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{{{*/
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{{{*/
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 {{{*/
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{{{*/
int    Vertex::Connectivity(void){return connectivity;}
/*}}}*/
/*FUNCTION Vertex::Sid{{{*/
int    Vertex::Sid(void){ return sid; }
/*}}}*/
/*FUNCTION Vertex::UpdateVertexPosition {{{*/
void  Vertex::UpdatePosition(Vector* vz,Parameters* parameters,IssmDouble* thickness,IssmDouble* bed){

	IssmDouble oldz,newz;
	IssmDouble 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*/
	vz->SetValue(this->dof,velz,INS_VAL);
}
/*}}}*/
