/*!\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 "../classes.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->pid=UNDEF;
	this->x=vertex_x;
	this->y=vertex_y;
	this->z=vertex_z;
	this->sigma=vertex_sigma;
	this->connectivity=vertex_connectivity;

	return;
}
/*}}}*/

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

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

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

	return VertexEnum;

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

	return new Vertex(*this); 

}
/*}}}*/

/*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<IssmDouble>* 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->pid]+sigma*thickness[this->pid];
	velz = (newz-oldz)/dt;
	this->z = newz;

	/*put vz in vector*/
	vz->SetValue(this->pid,velz,INS_VAL);
}
/*}}}*/
/*FUNCTION Vertex::DistributePids{{{*/
void  Vertex::DistributePids(int* ppidcount){

	/*retrieve current pid*/
	int pidcount=*ppidcount;

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

	/*This vertex should distribute its pid*/
	this->pid=pidcount;
	pidcount++;

	/*Assign output pointers: */
	*ppidcount=pidcount;
}
/*}}}*/
/*FUNCTION Vertex::OffsetPids{{{*/
void  Vertex::OffsetPids(int pidcount){

	/*This vertex is a clone, don't offset the pids*/
	if(this->clone) return;

	/*This vertex should offset his pid, go ahead: */
	this->pid+=pidcount;
}
/*}}}*/
/*FUNCTION Vertex::ShowTruePids{{{*/
void  Vertex::ShowTruePids(int* truepids){

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

	/*Ok, we are not a clone, just plug our pid into truepids: */
	truepids[this->sid]=this->pid;
}
/*}}}*/
/*FUNCTION Vertex::UpdateClonePids{{{*/
void  Vertex::UpdateClonePids(int* alltruepids){

	/*If we are not a clone, don't update, we already have pids: */
	if(!this->clone)return;

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

	int my_rank;

	/*recover my_rank:*/
	my_rank=IssmComm::GetRank();

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

}
/*}}}*/
/*FUNCTION Vertex::ToXYZ {{{*/
void  Vertex::ToXYZ(Matrix<IssmDouble>* matrix){

	IssmDouble xyz[3];
	int        indices[3];
	
	if (this->clone==true) return;

	xyz[0]=x;
	xyz[1]=y; 
	xyz[2]=z;
	indices[0]=0;
	indices[1]=1; 
	indices[2]=2;

	matrix->SetValues(1,&sid,3,&indices[0],&xyz[0],INS_VAL);
}
/*}}}*/
