Index: /issm/trunk/src/c/objects/Elements/Penta.cpp
===================================================================
--- /issm/trunk/src/c/objects/Elements/Penta.cpp	(revision 6409)
+++ /issm/trunk/src/c/objects/Elements/Penta.cpp	(revision 6410)
@@ -27,5 +27,5 @@
 #define NDOF4 4
 
-/*Penta constructors and destructor*/
+/*Constructors/destructor/copy*/
 /*FUNCTION Penta::Penta(){{{1*/
 Penta::Penta(){
@@ -85,6 +85,4 @@
 }
 /*}}}*/
-
-/*Object virtual functions definitions: */
 /*FUNCTION Penta::copy {{{1*/
 Object* Penta::copy() {
@@ -135,99 +133,6 @@
 }
 /*}}}*/
-/*FUNCTION Penta::DeepEcho{{{1*/
-void Penta::DeepEcho(void){
-
-	int i;
-	
-	printf("Penta:\n");
-	printf("   id: %i\n",id);
-	nodes[0]->DeepEcho();
-	nodes[1]->DeepEcho();
-	nodes[2]->DeepEcho();
-	nodes[3]->DeepEcho();
-	nodes[4]->DeepEcho();
-	nodes[5]->DeepEcho();
-	matice->DeepEcho();
-	matpar->DeepEcho();
-	printf("   neighbor ids: %i-%i\n",neighbors[0]->Id(),neighbors[1]->Id());
-	printf("   parameters\n");
-	parameters->DeepEcho();
-	printf("   inputs\n");
-	inputs->DeepEcho();
-	printf("   results\n");
-	results->DeepEcho();
-	return;
-}
-/*}}}*/
-/*FUNCTION Penta::Demarshall {{{1*/
-void  Penta::Demarshall(char** pmarshalled_dataset){
-
-	char* marshalled_dataset=NULL;
-	int   i;
-	int flaghook;
-
-	/*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(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
-
-	/*demarshall Ref: */
-	this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
-	for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
-
-	/*allocate dynamic memory: */
-	this->hnodes=new Hook*[this->numanalyses];
-	/*demarshall hooks: */
-	for(i=0;i<numanalyses;i++){
-		memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
-		if(flaghook){ // there is a hook so demarshall it
-			hnodes[i]=new Hook();
-			hnodes[i]->Demarshall(&marshalled_dataset);
-		}
-		else hnodes[i]=NULL; //There is no hook so it is NULL
-	}
-	hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
-	hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
-	hneighbors=new Hook(); hneighbors->Demarshall(&marshalled_dataset);
-
-	/*pointers are garbage, until configuration is carried out: */
-	nodes=NULL;
-	matice=NULL;
-	matpar=NULL;
-	neighbors=NULL;
-	
-	/*demarshall inputs and results: */
-	inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset); 
-	results=(Results*)DataSetDemarshallRaw(&marshalled_dataset); 
-
-	/*parameters: may not exist even yet, so let Configure handle it: */
-	this->parameters=NULL;
-
-	/*return: */
-	*pmarshalled_dataset=marshalled_dataset;
-	return;
-}
-/*}}}*/
-/*FUNCTION Penta::Echo{{{1*/
-
-void Penta::Echo(void){
-	this->DeepEcho();
-}
-/*}}}*/
-/*FUNCTION Penta::Enum {{{1*/
-int Penta::Enum(void){
-
-	return PentaEnum;
-
-}
-/*}}}*/
-/*FUNCTION Penta::Id {{{1*/
-int    Penta::Id(void){
-	return id; 
-}
-/*}}}*/
+
+/*Marshall*/
 /*FUNCTION Penta::Marshall {{{1*/
 void  Penta::Marshall(char** pmarshalled_dataset){
@@ -321,333 +226,85 @@
 }
 /*}}}*/
-/*FUNCTION Penta::MyRank {{{1*/
-int    Penta::MyRank(void){ 
-	extern int my_rank;
-	return my_rank; 
-}
-/*}}}*/
-
-/*Update virtual functions definitions: */
-/*FUNCTION Penta::InputUpdateFromConstant(bool value, int name);{{{1*/
-void  Penta::InputUpdateFromConstant(bool constant, int name){
-
-	/*Check that name is an element input*/
-	if (!IsInput(name)) return;
-
-	/*update input*/
-	this->inputs->AddInput(new BoolInput(name,constant));
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromConstant(double value, int name);{{{1*/
-void  Penta::InputUpdateFromConstant(double constant, int name){
-	/*Check that name is an element input*/
-	if (!IsInput(name)) return;
-
-	/*update input*/
-	this->inputs->AddInput(new DoubleInput(name,constant));
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromConstant(int value, int name);{{{1*/
-void  Penta::InputUpdateFromConstant(int constant, int name){
-	/*Check that name is an element input*/
-	if (!IsInput(name)) return;
-
-	/*update input*/
-	this->inputs->AddInput(new IntInput(name,constant));
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolution {{{1*/
-void  Penta::InputUpdateFromSolution(double* solution){
-
-	int analysis_type;
-
-	/*retreive parameters: */
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-
-	/*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
-	if (analysis_type==DiagnosticHorizAnalysisEnum){
-		InputUpdateFromSolutionDiagnosticHoriz( solution);
-	}
-	else if (analysis_type==DiagnosticHutterAnalysisEnum){
-		InputUpdateFromSolutionDiagnosticHutter( solution);
-	}
-	else if (analysis_type==DiagnosticVertAnalysisEnum){
-		InputUpdateFromSolutionDiagnosticVert( solution);
-	}
-	else if (analysis_type==AdjointHorizAnalysisEnum){
-		int approximation;
-		inputs->GetParameterValue(&approximation,ApproximationEnum);
-		if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
-			InputUpdateFromSolutionAdjointStokes( solution);
-		}
-		else{
-			InputUpdateFromSolutionAdjointHoriz( solution);
-		}
-	}
-	else if (analysis_type==BedSlopeXAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeXEnum);
-	}
-	else if (analysis_type==BedSlopeYAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeYEnum);
-	}
-	else if (analysis_type==SurfaceSlopeXAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeXEnum);
-	}
-	else if (analysis_type==SurfaceSlopeYAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeYEnum);
-	}
-	else if (analysis_type==PrognosticAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
-	}
-	else if (analysis_type==BalancedthicknessAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
-	}
-	else if (analysis_type==BalancedvelocitiesAnalysisEnum){
-		InputUpdateFromSolutionOneDofCollapsed(solution,VelEnum);
-	}
-	else if (analysis_type==ThermalAnalysisEnum){
-		InputUpdateFromSolutionThermal( solution);
-	}
-	else if (analysis_type==MeltingAnalysisEnum){
-		InputUpdateFromSolutionOneDof(solution,MeltingRateEnum);
-	}
-	else{
-		ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromVector(double* vector, int name, int type);{{{1*/
-void  Penta::InputUpdateFromVector(double* vector, int name, int type){
-
-	/*Check that name is an element input*/
-	if (!IsInput(name)) return;
-
-	/*Penta update B in InputUpdateFromSolutionThermal, so don't look for B update here.*/
-
-	switch(type){
-
-		case VertexEnum:
-
-			/*New PentaVertexInpu*/
-			double values[6];
-
-			/*Get values on the 6 vertices*/
-			for (int i=0;i<6;i++){
-				values[i]=vector[this->nodes[i]->GetVertexDof()];
-			}
-
-			/*update input*/
-			this->inputs->AddInput(new PentaVertexInput(name,values));
-			return;
-
-		default:
-
-			ISSMERROR("type %i (%s) not implemented yet",type,EnumToString(type));
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromVector(int* vector, int name, int type);{{{1*/
-void  Penta::InputUpdateFromVector(int* vector, int name, int type){
-	ISSMERROR(" not supported yet!");
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromVector(bool* vector, int name, int type);{{{1*/
-void  Penta::InputUpdateFromVector(bool* vector, int name, int type){
-	ISSMERROR(" not supported yet!");
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromVectorDakota(double* vector, int name, int type);{{{1*/
-void  Penta::InputUpdateFromVectorDakota(double* vector, int name, int type){
-	ISSMERROR(" not supported yet!");
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromVectorDakota(int* vector, int name, int type);{{{1*/
-void  Penta::InputUpdateFromVectorDakota(int* vector, int name, int type){
-	ISSMERROR(" not supported yet!");
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{1*/
-void  Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type){
-	ISSMERROR(" not supported yet!");
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromIoModel(int index,IoModel* iomodel) {{{1*/
-void Penta::InputUpdateFromIoModel(int index,IoModel* iomodel){ 
-
-	/*Intermediaries*/
-	IssmInt i,j;
-	int     penta_vertex_ids[6];
-	double  nodeinputs[6];
-
-	/*Checks if debuging*/
-	/*{{{2*/
-	ISSMASSERT(iomodel->elements);
-	/*}}}*/
-
-	/*Recover vertices ids needed to initialize inputs*/
-	for(i=0;i<6;i++){ 
-		penta_vertex_ids[i]=(int)iomodel->elements[6*index+i]; //ids for vertices are in the elements array from Matlab
-	}
-
-	//add as many inputs per element as requested: 
-	if (iomodel->thickness) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->thickness[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(ThicknessEnum,nodeinputs));
-	}
-	if (iomodel->surface) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->surface[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(SurfaceEnum,nodeinputs));
-	}
-	if (iomodel->bed) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->bed[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(BedEnum,nodeinputs));
-	}
-	if (iomodel->drag_coefficient) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->drag_coefficient[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(DragCoefficientEnum,nodeinputs));
-
-		if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
-		if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
-		this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
-
-	}
-	if (iomodel->melting_rate) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->melting_rate[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(MeltingRateEnum,nodeinputs));
-	}
-	if (iomodel->accumulation_rate) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->accumulation_rate[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(AccumulationRateEnum,nodeinputs));
-	}
-	if (iomodel->geothermalflux) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->geothermalflux[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(GeothermalFluxEnum,nodeinputs));
-	}	
-	if (iomodel->pressure) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->pressure[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(PressureEnum,nodeinputs));
-	}
-	if (iomodel->temperature) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->temperature[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,nodeinputs));
-	}
-	if (iomodel->dhdt) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->dhdt[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(DhDtEnum,nodeinputs));
-	}
-	/*vx,vy and vz: */
-	if (iomodel->vx) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(VxEnum,nodeinputs));
-		this->inputs->AddInput(new PentaVertexInput(VxOldEnum,nodeinputs));
-		if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVxEnum,nodeinputs));
-	}
-	if (iomodel->vy) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(VyEnum,nodeinputs));
-		this->inputs->AddInput(new PentaVertexInput(VyOldEnum,nodeinputs));
-		if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVyEnum,nodeinputs));
-	}
-	if (iomodel->vz) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(VzEnum,nodeinputs));
-		this->inputs->AddInput(new PentaVertexInput(VzOldEnum,nodeinputs));
-		if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVzEnum,nodeinputs));
-	}
-	if (iomodel->vx_obs) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx_obs[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(VxObsEnum,nodeinputs));
-	}
-	if (iomodel->vy_obs) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy_obs[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(VyObsEnum,nodeinputs));
-	}
-	if (iomodel->vz_obs) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz_obs[penta_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new PentaVertexInput(VzObsEnum,nodeinputs));
-	}
-	if (iomodel->weights) {
-		for(i=0;i<6;i++)nodeinputs[i]=iomodel->weights[penta_vertex_ids[i]-1];
-		this->inputs->AddInput(new PentaVertexInput(WeightsEnum,nodeinputs));
-	}
-	if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
-	if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
-	if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
-	if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
-
-	/*time: */
-	this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
-
-	/*Control Inputs*/
-	if (iomodel->control_analysis && iomodel->control_type){
-		for(i=0;i<iomodel->num_control_type;i++){
-			switch((int)iomodel->control_type[i]){
-				case DhDtEnum:
-					if (iomodel->dhdt){
-						for(j=0;j<6;j++)nodeinputs[j]=iomodel->dhdt[penta_vertex_ids[j]-1]/iomodel->yts;
-						this->inputs->AddInput(new ControlInput(DhDtEnum,PentaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case VxEnum:
-					if (iomodel->vx){
-						for(j=0;j<6;j++)nodeinputs[j]=iomodel->vx[penta_vertex_ids[j]-1]/iomodel->yts;
-						this->inputs->AddInput(new ControlInput(VxEnum,PentaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case VyEnum:
-					if (iomodel->vy){
-						for(j=0;j<6;j++)nodeinputs[j]=iomodel->vy[penta_vertex_ids[j]-1]/iomodel->yts;
-						this->inputs->AddInput(new ControlInput(VyEnum,PentaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case DragCoefficientEnum:
-					if (iomodel->drag_coefficient){
-						for(j=0;j<6;j++)nodeinputs[j]=iomodel->drag_coefficient[penta_vertex_ids[j]-1];
-						this->inputs->AddInput(new ControlInput(DragCoefficientEnum,PentaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case RheologyBbarEnum:
-					/*Matice will take care of it*/ break;
-				default:
-					ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
-			}
-		}
-	}
-
-	//Need to know the type of approximation for this element
-	if(iomodel->elements_type){
-		if (*(iomodel->elements_type+index)==MacAyealApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealApproximationEnum));
-		}
-		else if (*(iomodel->elements_type+index)==PattynApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,PattynApproximationEnum));
-		}
-		else if (*(iomodel->elements_type+index)==MacAyealPattynApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealPattynApproximationEnum));
-		}
-		else if (*(iomodel->elements_type+index)==HutterApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,HutterApproximationEnum));
-		}
-		else if (*(iomodel->elements_type+index)==StokesApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,StokesApproximationEnum));
-		}
-		else if (*(iomodel->elements_type+index)==PattynStokesApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,PattynStokesApproximationEnum));
-		}
-		else if (*(iomodel->elements_type+index)==NoneApproximationEnum){
-			this->inputs->AddInput(new IntInput(ApproximationEnum,NoneApproximationEnum));
-		}
-		else{
-			ISSMERROR("Approximation type %s not supported yet",EnumToString((int)*(iomodel->elements_type+index)));
-		}
-	}
-
-}
-/*}}}*/
-
-/*Element virtual functions definitions: */
+/*FUNCTION Penta::Demarshall {{{1*/
+void  Penta::Demarshall(char** pmarshalled_dataset){
+
+	char* marshalled_dataset=NULL;
+	int   i;
+	int flaghook;
+
+	/*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(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
+
+	/*demarshall Ref: */
+	this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
+	for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
+
+	/*allocate dynamic memory: */
+	this->hnodes=new Hook*[this->numanalyses];
+	/*demarshall hooks: */
+	for(i=0;i<numanalyses;i++){
+		memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
+		if(flaghook){ // there is a hook so demarshall it
+			hnodes[i]=new Hook();
+			hnodes[i]->Demarshall(&marshalled_dataset);
+		}
+		else hnodes[i]=NULL; //There is no hook so it is NULL
+	}
+	hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
+	hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
+	hneighbors=new Hook(); hneighbors->Demarshall(&marshalled_dataset);
+
+	/*pointers are garbage, until configuration is carried out: */
+	nodes=NULL;
+	matice=NULL;
+	matpar=NULL;
+	neighbors=NULL;
+
+	/*demarshall inputs and results: */
+	inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset); 
+	results=(Results*)DataSetDemarshallRaw(&marshalled_dataset); 
+
+	/*parameters: may not exist even yet, so let Configure handle it: */
+	this->parameters=NULL;
+
+	/*return: */
+	*pmarshalled_dataset=marshalled_dataset;
+	return;
+}
+/*}}}*/
+
+/*Other*/
 /*FUNCTION Penta::AverageOntoPartition {{{1*/
 void  Penta::AverageOntoPartition(Vec partition_contributions,Vec partition_areas,double* vertex_response,double* qmu_part){
 	ISSMERROR("Not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::BedNormal {{{1*/
+void Penta::BedNormal(double* bed_normal, double xyz_list[3][3]){
+
+	int i;
+	double v13[3],v23[3];
+	double normal[3];
+	double normal_norm;
+
+	for (i=0;i<3;i++){
+		v13[i]=xyz_list[0][i]-xyz_list[2][i];
+		v23[i]=xyz_list[1][i]-xyz_list[2][i];
+	}
+
+	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
+	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
+	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
+	normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
+
+	/*Bed normal is opposite to surface normal*/
+	*(bed_normal)=-normal[0]/normal_norm;
+	*(bed_normal+1)=-normal[1]/normal_norm;
+	*(bed_normal+2)=-normal[2]/normal_norm;
 }
 /*}}}*/
@@ -837,61 +494,4 @@
 
 }/*}}}*/
-/*FUNCTION Penta::RegularizeInversion {{{1*/
-double Penta::RegularizeInversion(void){
-
-	double J;
-	Tria* tria=NULL;
-
-	/*recover some inputs: */
-	int  approximation;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Not MacAyeal and not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute RegularizeInversion*/
-
-		/*Depth Average B*/
-		this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
-
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		J=tria->RegularizeInversion();
-		delete tria->matice; delete tria;
-
-		/*delete B average*/
-		this->matice->inputs->DeleteInput(RheologyBbarEnum);
-
-		return J;
-	}
-	else{
-
-		/*Depth Average B and put it in inputs*/
-		Penta* penta=GetBasalElement();
-		penta->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
-		Input* B_input=penta->matice->inputs->GetInput(RheologyBbarEnum);
-		Input* B_copy=(Input*)B_input->copy();
-		this->matice->inputs->AddInput((Input*)B_copy);
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		J=tria->RegularizeInversion();
-		delete tria->matice; delete tria;
-
-		/*delete B average*/
-		this->matice->inputs->DeleteInput(RheologyBbarEnum);
-		penta->matice->inputs->DeleteInput(RheologyBbarEnum);
-
-		return J;
-	}
-}
-/*}}}*/
 /*FUNCTION Penta::CreateKMatrix {{{1*/
 void  Penta::CreateKMatrix(Mat Kgg, Mat Kff, Mat Kfs){
@@ -944,4 +544,1011 @@
 		delete Ke;
 	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixBalancedthickness {{{1*/
+ElementMatrix* Penta::CreateKMatrixBalancedthickness(void){
+
+	/*Figure out if this penta is collapsed. If so, then bailout, except if it is at the 
+	  bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	/*Spawn Tria element from the base of the Penta: */
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixBalancedthickness();
+	delete tria->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixBalancedvelocities {{{1*/
+ElementMatrix* Penta::CreateKMatrixBalancedvelocities(void){
+
+	/*Figure out if this penta is collapsed. If so, then bailout, except if it is at the 
+	  bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	/*Spawn Tria element from the base of the Penta: */
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixBalancedvelocities();
+	delete tria->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattyn{{{1*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattyn(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixCouplingMacAyealPattynViscous();
+	ElementMatrix* Ke2=CreateKMatrixCouplingMacAyealPattynFriction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynViscous{{{1*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynViscous(void){
+
+	/*Constants*/
+	const int    numdofm=NDOF2*NUMVERTICES2D;
+	const int    numdofp=NDOF2*NUMVERTICES;
+	const int    numdoftotal=2*NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int         i,j,ig;
+	double      Jdet;
+	double      viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
+	double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	double      xyz_list[NUMVERTICES][3];
+	double      B[3][numdofp];
+	double      Bprime[3][numdofm];
+	double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
+	double      D_scalar;
+	double      Ke_gg[numdofp][numdofm]={0.0}; //local element stiffness matrix 
+	double      Ke_gg_gaussian[numdofp][numdofm]; //stiffness matrix evaluated at the gaussian point.
+	GaussPenta *gauss=NULL;
+	GaussTria  *gauss_tria=NULL;
+
+	/*Find penta on bed as pattyn must be coupled to the dofs on the bed: */
+	Penta* pentabase=GetBasalElement();
+	Tria* tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke1=new ElementMatrix(pentabase->nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+	ElementMatrix* Ke2=new ElementMatrix(this->nodes     ,NUMVERTICES,this->parameters,PattynApproximationEnum);
+	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
+	delete Ke1; delete Ke2;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
+	Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	gauss_tria=new GaussTria();
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		gauss->SynchronizeGaussTria(gauss_tria);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBMacAyealPattyn(&B[0][0], &xyz_list[0][0], gauss);
+		tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity3d(&viscosity, &epsilon[0]);
+		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
+
+		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+		D_scalar=2*newviscosity*gauss->weight*Jdet;
+		for (i=0;i<3;i++) D[i][i]=D_scalar;
+
+		TripleMultiply( &B[0][0],3,numdofp,1,
+					&D[0][0],3,3,0,
+					&Bprime[0][0],3,numdofm,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		for( i=0; i<numdofp; i++) for(j=0;j<numdofm; j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
+	} 
+	for(i=0;i<numdofp;i++) for(j=0;j<numdofm;j++) Ke->values[(i+2*numdofm)*numdoftotal+j]+=Ke_gg[i][j];
+	for(i=0;i<numdofm;i++) for(j=0;j<numdofp;j++) Ke->values[i*numdoftotal+(j+2*numdofm)]+=Ke_gg[j][i];
+
+	/*Clean-up and return*/
+	delete tria->matice; delete tria;
+	delete gauss;
+	delete gauss_tria;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynFriction{{{1*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynFriction(void){
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixCouplingMacAyealPattynFriction();
+	delete tria->matice; delete tria;
+
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingPattynStokes{{{1*/
+ElementMatrix* Penta::CreateKMatrixCouplingPattynStokes(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+	ElementMatrix* Ke2=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
+	delete Ke1;
+	delete Ke2;
+	Ke1=CreateKMatrixDiagnosticPattyn();
+	Ke2=CreateKMatrixDiagnosticStokes();
+
+	/*Constants*/
+	const int    numdofp=NDOF2*NUMVERTICES;
+	const int    numdofs=NDOF4*NUMVERTICES;
+	const int    numdoftotal=(NDOF2+NDOF4)*NUMVERTICES;
+	int          i,j;
+
+	for(i=0;i<numdofs;i++) for(j=0;j<NUMVERTICES;j++){
+		Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+0]+=Ke2->values[i*numdofs+NDOF4*j+0];
+		Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+1]+=Ke2->values[i*numdofs+NDOF4*j+1];
+	}
+	for(i=0;i<numdofp;i++) for(j=0;j<NUMVERTICES;j++){
+		Ke->values[i*numdoftotal+numdofp+NDOF4*j+0]+=Ke1->values[i*numdofp+NDOF2*j+0];
+		Ke->values[i*numdoftotal+numdofp+NDOF4*j+1]+=Ke1->values[i*numdofp+NDOF2*j+1];
+	}
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticHoriz(void){
+
+	int approximation;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreateKMatrixDiagnosticMacAyeal2d();
+		case PattynApproximationEnum:
+			return CreateKMatrixDiagnosticPattyn();
+		case StokesApproximationEnum:
+			return CreateKMatrixDiagnosticStokes();
+		case HutterApproximationEnum:
+			return NULL;
+		case NoneApproximationEnum:
+			return NULL;
+		case MacAyealPattynApproximationEnum:
+			return CreateKMatrixDiagnosticMacAyealPattyn();
+		case PattynStokesApproximationEnum:
+			return CreateKMatrixDiagnosticPattynStokes();
+		default:
+			ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticHutter(void){
+
+	/*Constants*/
+	const int numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int       connectivity[2];
+	int       i,i0,i1,j0,j1;
+	double    one0,one1;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Spawn 3 beam elements: */
+	for(i=0;i<3;i++){
+		/*2 dofs of first node*/
+		i0=2*i;
+		i1=2*i+1;
+		/*2 dofs of second node*/
+		j0=2*(i+3);
+		j1=2*(i+3)+1;
+
+		/*Find connectivity for the two nodes*/
+		connectivity[0]=nodes[i]->GetConnectivity();
+		connectivity[1]=nodes[i+3]->GetConnectivity();
+		one0=1/(double)connectivity[0];
+		one1=1/(double)connectivity[1];
+
+		/*Create matrix for these two nodes*/
+		if (IsOnBed() && IsOnSurface()){
+			Ke->values[i0*numdof+i0]=one0;
+			Ke->values[i1*numdof+i1]=one0;
+			Ke->values[j0*numdof+i0]=-one1;
+			Ke->values[j0*numdof+j0]=one1;
+			Ke->values[j1*numdof+i1]=-one1;
+			Ke->values[j1*numdof+j1]=one1;
+		}
+		else if (IsOnBed()){
+			Ke->values[i0*numdof+i0]=one0;
+			Ke->values[i1*numdof+i1]=one0;
+			Ke->values[j0*numdof+i0]=-2*one1;
+			Ke->values[j0*numdof+j0]=2*one1;
+			Ke->values[j1*numdof+i1]=-2*one1;
+			Ke->values[j1*numdof+j1]=2*one1;
+		}
+		else if (IsOnSurface()){
+			Ke->values[j0*numdof+i0]=-one1;
+			Ke->values[j0*numdof+j0]=one1;
+			Ke->values[j1*numdof+i1]=-one1;
+			Ke->values[j1*numdof+j1]=one1;
+		}
+		else{ //node is on two horizontal layers and beams include the values only once, so the have to use half of the connectivity
+			Ke->values[j0*numdof+i0]=-2*one1;
+			Ke->values[j0*numdof+j0]=2*one1;
+			Ke->values[j1*numdof+i1]=-2*one1;
+			Ke->values[j1*numdof+j1]=2*one1;
+		}
+	}
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal2d{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal2d(void){
+
+	/*Figure out if this penta is collapsed. If so, then bailout, except if it is at the 
+	  bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging B*/
+	this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyeal();
+	delete tria->matice; delete tria;
+
+	/*Delete B averaged*/
+	this->matice->inputs->DeleteInput(RheologyBbarEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3d{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3d(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3dViscous();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyeal3dFriction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dViscous{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dViscous(void){
+
+	/*Constants*/
+	const int    numdof2d=2*NUMVERTICES2D;
+
+	/*Intermediaries */
+	int         i,j,ig;
+	double      Jdet;
+	double      viscosity, oldviscosity, newviscosity, viscosity_overshoot;
+	double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	double      xyz_list[NUMVERTICES][3];
+	double      B[3][numdof2d];
+	double      Bprime[3][numdof2d];
+	double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
+	double      D_scalar;
+	double      Ke_gg_gaussian[numdof2d][numdof2d]; //stiffness matrix evaluated at the gaussian point.
+	Tria*       tria=NULL;
+	Penta*      pentabase=NULL;
+	GaussPenta *gauss=NULL;
+	GaussTria  *gauss_tria=NULL;
+
+	/*Find penta on bed as this is a macayeal elements: */
+	pentabase=GetBasalElement();
+	tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(tria->nodes,NUMVERTICES2D,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes,NUMVERTICES);
+	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
+	Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	gauss_tria=new GaussTria();
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		gauss->SynchronizeGaussTria(gauss_tria);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		tria->GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss_tria);
+		tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity3d(&viscosity, &epsilon[0]);
+		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
+
+		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+		D_scalar=2*newviscosity*gauss->weight*Jdet;
+		for (i=0;i<3;i++) D[i][i]=D_scalar;
+
+		TripleMultiply( &B[0][0],3,numdof2d,1,
+					&D[0][0],3,3,0,
+					&Bprime[0][0],3,numdof2d,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof2d+j]+=Ke_gg_gaussian[i][j];
+	}
+
+	/*Clean up and return*/
+	delete tria->matice;
+	delete tria;
+	delete gauss_tria;
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dFriction{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dFriction(void){
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
+
+	/*Build a tria element using the 3 grids of the base of the penta. Then use 
+	 * the tria functionality to build a friction stiffness matrix on these 3
+	 * grids: */
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyealFriction();
+	delete tria->matice; delete tria;
+
+	/*clean-up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyealPattyn{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyealPattyn(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3d();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticPattyn();
+	ElementMatrix* Ke3=CreateKMatrixCouplingMacAyealPattyn();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	delete Ke3;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattyn{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticPattyn(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticPattynViscous();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticPattynFriction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattynViscous{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticPattynViscous(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	int        approximation;
+	double     xyz_list[NUMVERTICES][3];
+	double     Jdet;
+	double     viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
+	double     epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	double     D_scalar;
+	double     D[5][5]={0.0};            // material matrix, simple scalar matrix.
+	double     B[5][numdof];
+	double     Bprime[5][numdof];
+	double     Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
+	Tria*      tria=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
+	Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBPattyn(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimePattyn(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity3d(&viscosity, &epsilon[0]);
+		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
+		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+
+		D_scalar=2*newviscosity*gauss->weight*Jdet;
+		for (i=0;i<5;i++) D[i][i]=D_scalar;
+
+		TripleMultiply( &B[0][0],5,numdof,1,
+					&D[0][0],5,5,0,
+					&Bprime[0][0],5,numdof,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattynFriction{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticPattynFriction(void){
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
+
+	/*Build a tria element using the 3 grids of the base of the penta. Then use 
+	 * the tria functionality to build a friction stiffness matrix on these 3
+	 * grids: */
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticPattynFriction();
+	delete tria->matice; delete tria;
+
+	/*clean-up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattynStokes{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticPattynStokes(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticPattyn();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticStokes();
+	ElementMatrix* Ke3=CreateKMatrixCouplingPattynStokes();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	delete Ke3;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticStokes{{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticStokes(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticStokesViscous();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticStokesFriction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticStokesViscous {{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticStokesViscous(void){
+
+	/*Intermediaries */
+	int        i,j,ig,approximation;
+	double     Jdet,viscosity,stokesreconditioning;
+	double     xyz_list[NUMVERTICES][3];
+	double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double     B[8][27];
+	double     B_prime[8][27];
+	double     D_scalar;
+	double     D[8][8]={0.0};
+	double     Ke_temp[27][27]={0.0}; //for the six nodes and the bubble 
+	double     Ke_gaussian[27][27];
+	GaussPenta *gauss=NULL;
+
+	/*If on water or not Stokes, skip stiffness: */
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(IsOnWater() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBStokes(&B[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0],gauss); 
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		D_scalar=gauss->weight*Jdet;
+		for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
+		for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
+
+		TripleMultiply( &B[0][0],8,27,1,
+					&D[0][0],8,8,0,
+					&B_prime[0][0],8,27,0,
+					&Ke_gaussian[0][0],0);
+
+		for(i=0;i<27;i++) for(j=0;j<27;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
+	}
+
+	/*Condensation*/
+	ReduceMatrixStokes(Ke->values, &Ke_temp[0][0]);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticStokesFriction {{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticStokesFriction(void){
+
+	/*Constants*/
+	const int numdof=NUMVERTICES*NDOF4;
+	const int numdof2d=NUMVERTICES2D*NDOF4;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	int        analysis_type,approximation;
+	double     stokesreconditioning;
+	double     viscosity,alpha2_gauss,Jdet2d;
+	double	  bed_normal[3];
+	double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double     xyz_list[NUMVERTICES][3];
+	double	  xyz_list_tria[NUMVERTICES2D][3];
+	double     LStokes[14][numdof2d];
+	double     LprimeStokes[14][numdof2d];
+	double     DLStokes[14][14]={0.0};
+	double     Ke_drag_gaussian[numdof2d][numdof2d];
+	Friction*  friction=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*If on water or not Stokes, skip stiffness: */
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(IsOnWater() || IsOnShelf() || !IsOnBed() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+
+	/*build friction object, used later on: */
+	friction=new Friction("3d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		GetLStokes(&LStokes[0][0], gauss);
+		GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		BedNormal(&bed_normal[0],xyz_list_tria);
+		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
+
+		DLStokes[0][0]=alpha2_gauss*gauss->weight*Jdet2d;
+		DLStokes[1][1]=alpha2_gauss*gauss->weight*Jdet2d;
+		DLStokes[2][2]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
+		DLStokes[3][3]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
+		DLStokes[4][4]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
+		DLStokes[5][5]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
+		DLStokes[6][6]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0];
+		DLStokes[7][7]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1];
+		DLStokes[8][8]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[2];
+		DLStokes[9][9]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0]/2.0;
+		DLStokes[10][10]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1]/2.0;
+		DLStokes[11][11]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[0];
+		DLStokes[12][12]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[1];
+		DLStokes[13][13]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[2];
+
+		TripleMultiply( &LStokes[0][0],14,numdof2d,1,
+					&DLStokes[0][0],14,14,0,
+					&LprimeStokes[0][0],14,numdof2d,0,
+					&Ke_drag_gaussian[0][0],0);
+
+		for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof+j]+=Ke_drag_gaussian[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticVert(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticVertVolume();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticVertSurface();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticVertVolume {{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticVertVolume(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int         i,j,ig;
+	double      Jdet;
+	double      xyz_list[NUMVERTICES][3];
+	double      B[NDOF1][NUMVERTICES];
+	double      Bprime[NDOF1][NUMVERTICES];
+	double      DL_scalar;
+	double      Ke_gg[numdof][numdof]={0.0};
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBVert(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimeVert(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		DL_scalar=gauss->weight*Jdet;
+
+		TripleMultiply( &B[0][0],1,NUMVERTICES,1,
+					&DL_scalar,1,1,0,
+					&Bprime[0][0],1,NUMVERTICES,0,
+					&Ke_gg[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
+	} 
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticVertSurface {{{1*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticVertSurface(void){
+
+	if (!IsOnSurface() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(3,4,5); //nodes 3,4 and 5 are on the surface
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticVertSurface();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixMelting {{{1*/
+ElementMatrix* Penta::CreateKMatrixMelting(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixMelting();
+
+	delete tria->matice; delete tria;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixPrognostic {{{1*/
+ElementMatrix* Penta::CreateKMatrixPrognostic(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixPrognostic();
+	delete tria->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixSlope {{{1*/
+ElementMatrix* Penta::CreateKMatrixSlope(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixSlope();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixThermal {{{1*/
+ElementMatrix* Penta::CreateKMatrixThermal(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixThermalVolume();
+	ElementMatrix* Ke2=CreateKMatrixThermalShelf();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixThermalVolume {{{1*/
+ElementMatrix* Penta::CreateKMatrixThermalVolume(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        artdiff;
+	int        i,j,ig,found=0;
+	double     Jdet,u,v,w,epsvel;
+	double     gravity,rho_ice,rho_water;
+	double     heatcapacity,thermalconductivity,dt;
+	double     tau_parameter,diameter;
+	double     xyz_list[NUMVERTICES][3];
+	double     B[3][numdof];
+	double     Bprime[3][numdof];
+	double     B_conduct[3][numdof];
+	double     B_advec[3][numdof];
+	double     B_artdiff[2][numdof];
+	double     Bprime_advec[3][numdof];
+	double     L[numdof];
+	double     dh1dh6[3][6];
+	double     D_scalar_conduct,D_scalar_advec;
+	double     D_scalar_trans,D_scalar_artdiff;
+	double     D[3][3];
+	double     K[2][2]={0.0};
+	double     Ke_gaussian_conduct[numdof][numdof];
+	double     Ke_gaussian_advec[numdof][numdof];
+	double     Ke_gaussian_artdiff[numdof][numdof];
+	double     Ke_gaussian_transient[numdof][numdof];
+	Tria*      tria=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	heatcapacity=matpar->GetHeatCapacity();
+	thermalconductivity=matpar->GetThermalConductivity();
+	this->inputs->GetParameterValue(&dt,DtEnum);
+	this->parameters->FindParam(&artdiff,ArtDiffEnum);
+	this->parameters->FindParam(&epsvel,EpsVelEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
+	if (artdiff==2) diameter=MinEdgeLength(xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Conduction: */
+
+		GetBConduct(&B_conduct[0][0],&xyz_list[0][0],gauss); 
+
+		D_scalar_conduct=gauss->weight*Jdet*(thermalconductivity/(rho_ice*heatcapacity));
+		if(dt) D_scalar_conduct=D_scalar_conduct*dt;
+
+		D[0][0]=D_scalar_conduct; D[0][1]=0; D[0][2]=0;
+		D[1][0]=0; D[1][1]=D_scalar_conduct; D[1][2]=0;
+		D[2][0]=0; D[2][1]=0; D[2][2]=D_scalar_conduct;
+
+		TripleMultiply(&B_conduct[0][0],3,numdof,1,
+					&D[0][0],3,3,0,
+					&B_conduct[0][0],3,numdof,0,
+					&Ke_gaussian_conduct[0][0],0);
+
+		/*Advection: */
+
+		GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss); 
+
+		vx_input->GetParameterValue(&u, gauss);
+		vy_input->GetParameterValue(&v, gauss);
+		vz_input->GetParameterValue(&w, gauss);
+
+		D_scalar_advec=gauss->weight*Jdet;
+		if(dt) D_scalar_advec=D_scalar_advec*dt;
+
+		D[0][0]=D_scalar_advec*u;D[0][1]=0;         D[0][2]=0;
+		D[1][0]=0;         D[1][1]=D_scalar_advec*v;D[1][2]=0;
+		D[2][0]=0;         D[2][1]=0;         D[2][2]=D_scalar_advec*w;
+
+		TripleMultiply(&B_advec[0][0],3,numdof,1,
+					&D[0][0],3,3,0,
+					&Bprime_advec[0][0],3,numdof,0,
+					&Ke_gaussian_advec[0][0],0);
+
+		/*Transient: */
+
+		if(dt){
+			GetNodalFunctionsP1(&L[0], gauss);
+			D_scalar_trans=gauss->weight*Jdet;
+			D_scalar_trans=D_scalar_trans;
+
+			TripleMultiply(&L[0],numdof,1,0,
+						&D_scalar_trans,1,1,0,
+						&L[0],1,numdof,0,
+						&Ke_gaussian_transient[0][0],0);
+		}
+		else{
+			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_transient[i][j]=0;
+		}
+
+		/*Artifficial diffusivity*/
+
+		if(artdiff==1){
+			/*Build K: */
+			D_scalar_artdiff=gauss->weight*Jdet/(pow(u,2)+pow(v,2)+epsvel);
+			if(dt) D_scalar_artdiff=D_scalar_artdiff*dt;
+			K[0][0]=D_scalar_artdiff*pow(u,2);       K[0][1]=D_scalar_artdiff*fabs(u)*fabs(v);
+			K[1][0]=D_scalar_artdiff*fabs(u)*fabs(v);K[1][1]=D_scalar_artdiff*pow(v,2);
+
+			GetBArtdiff(&B_artdiff[0][0],&xyz_list[0][0],gauss); 
+
+			TripleMultiply(&B_artdiff[0][0],2,numdof,1,
+						&K[0][0],2,2,0,
+						&B_artdiff[0][0],2,numdof,0,
+						&Ke_gaussian_artdiff[0][0],0);
+		}
+		else if(artdiff==2){
+
+			GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
+
+			tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
+
+			for(i=0;i<numdof;i++){
+				for(j=0;j<numdof;j++){
+					Ke_gaussian_artdiff[i][j]=tau_parameter*D_scalar_advec*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i])*(u*dh1dh6[0][j]+v*dh1dh6[1][j]+w*dh1dh6[2][j]);
+				}
+			}
+			if(dt){
+				for(i=0;i<numdof;i++){
+					for(j=0;j<numdof;j++){
+						Ke_gaussian_artdiff[i][j]+=tau_parameter*D_scalar_trans*L[j]*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
+					}
+				}
+			}
+		}
+		else{
+			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_artdiff[i][j]=0;
+		}
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian_conduct[i][j]+Ke_gaussian_advec[i][j]+Ke_gaussian_transient[i][j]+Ke_gaussian_artdiff[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixThermalShelf {{{1*/
+ElementMatrix* Penta::CreateKMatrixThermalShelf(void){
+
+	if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2);
+	ElementMatrix* Ke=tria->CreateKMatrixThermal();
+	delete tria->matice; delete tria;
+
+	return Ke;
 }
 /*}}}*/
@@ -1001,4 +1608,887 @@
 }
 /*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointHoriz{{{1*/
+ElementVector* Penta::CreatePVectorAdjointHoriz(void){
+
+	int approximation;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreatePVectorAdjointMacAyeal();
+		case PattynApproximationEnum:
+			return CreatePVectorAdjointPattyn();
+		case NoneApproximationEnum:
+			return NULL;
+		case StokesApproximationEnum:
+			return CreatePVectorAdjointStokes();
+		default:
+			ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointMacAyeal{{{1*/
+ElementVector* Penta::CreatePVectorAdjointMacAyeal(){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorAdjointHoriz();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointPattyn{{{1*/
+ElementVector* Penta::CreatePVectorAdjointPattyn(void){
+
+	if (!IsOnSurface() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+	ElementVector* pe=tria->CreatePVectorAdjointHoriz();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorBalancedthickness {{{1*/
+ElementVector* Penta::CreatePVectorBalancedthickness(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorBalancedthickness();
+	delete tria->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorBalancedvelocities {{{1*/
+ElementVector* Penta::CreatePVectorBalancedvelocities(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorBalancedvelocities();
+	delete tria->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingPattynStokes {{{1*/
+ElementVector* Penta::CreatePVectorCouplingPattynStokes(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorCouplingPattynStokesViscous();
+	ElementVector* pe2=CreatePVectorCouplingPattynStokesFriction();
+	ElementVector* pe =new ElementVector(pe1,pe2);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingPattynStokesViscous {{{1*/
+ElementVector* Penta::CreatePVectorCouplingPattynStokesViscous(void){
+
+	/*Constants*/
+	const int   numdof=NUMVERTICES*NDOF4;
+
+	/*Intermediaries */
+	int         i,j,ig;
+	int         approximation;
+	double      viscosity,Jdet;
+	double      stokesreconditioning;
+	double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double      dw[3];
+	double      xyz_list[NUMVERTICES][3];
+	double      l1l6[6]; //for the six nodes of the penta
+	double      dh1dh6[3][6]; //for the six nodes of the penta
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(&l1l6[0], gauss);
+		GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
+
+		vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		for(i=0;i<NUMVERTICES;i++){
+			pe->values[i*NDOF4+0]+=-Jdet*gauss->weight*viscosity*dw[0]*dh1dh6[2][i];
+			pe->values[i*NDOF4+1]+=-Jdet*gauss->weight*viscosity*dw[1]*dh1dh6[2][i];
+			pe->values[i*NDOF4+2]+=-Jdet*gauss->weight*viscosity*(dw[0]*dh1dh6[0][i]+dw[1]*dh1dh6[1][i]+2*dw[2]*dh1dh6[2][i]);
+			pe->values[i*NDOF4+3]+=Jdet*gauss->weight*stokesreconditioning*dw[2]*l1l6[i];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingPattynStokesFriction{{{1*/
+ElementVector* Penta::CreatePVectorCouplingPattynStokesFriction(void){
+
+	/*Constants*/
+	const int numdof=NUMVERTICES*NDOF4;
+
+	/*Intermediaries*/
+	int         i,j,ig;
+	int         approximation,analysis_type;
+	double      Jdet,Jdet2d;
+	double      stokesreconditioning;
+	double	   bed_normal[3];
+	double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double      viscosity, w, alpha2_gauss;
+	double      dw[3];
+	double	   xyz_list_tria[NUMVERTICES2D][3];
+	double      xyz_list[NUMVERTICES][3];
+	double      l1l6[6]; //for the six nodes of the penta
+	Tria*       tria=NULL;
+	Friction*   friction=NULL;
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater() || !IsOnBed() || IsOnShelf()) return NULL;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
+
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+
+	/*build friction object, used later on: */
+	friction=new Friction("3d",inputs,matpar,analysis_type);
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(l1l6, gauss);
+
+		vzpattyn_input->GetParameterValue(&w, gauss);
+		vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
+
+		BedNormal(&bed_normal[0],xyz_list_tria);
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
+
+		for(i=0;i<NUMVERTICES2D;i++){
+			pe->values[i*NDOF4+0]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[0]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[0])*l1l6[i];
+			pe->values[i*NDOF4+1]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[1]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[1])*l1l6[i];
+			pe->values[i*NDOF4+2]+=Jdet2d*gauss->weight*2*viscosity*(dw[0]*bed_normal[0]+dw[1]*bed_normal[1]+dw[2]*bed_normal[2])*l1l6[i];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticHoriz{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticHoriz(void){
+
+	int approximation;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreatePVectorDiagnosticMacAyeal();
+		case PattynApproximationEnum:
+			return CreatePVectorDiagnosticPattyn();
+		case HutterApproximationEnum:
+			return NULL;
+		case NoneApproximationEnum:
+			return NULL;
+		case StokesApproximationEnum:
+			return CreatePVectorDiagnosticStokes();
+		case MacAyealPattynApproximationEnum:
+			return CreatePVectorDiagnosticMacAyealPattyn();
+		case PattynStokesApproximationEnum:
+			return CreatePVectorDiagnosticPattynStokes();
+		default:
+			ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticMacAyealPattyn{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticMacAyealPattyn(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorDiagnosticMacAyeal();
+	ElementVector* pe2=CreatePVectorDiagnosticPattyn();
+	ElementVector* pe =new ElementVector(pe1,pe2);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticPattynStokes{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticPattynStokes(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorDiagnosticPattyn();
+	ElementVector* pe2=CreatePVectorDiagnosticStokes();
+	ElementVector* pe3=CreatePVectorCouplingPattynStokes();
+	ElementVector* pe =new ElementVector(pe1,pe2,pe3);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	delete pe3;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticHutter{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticHutter(void){
+
+	/*Constants*/
+	const int numdofs=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int          i,j,k,ig;
+	int          node0,node1;
+	int          connectivity[2];
+	double       Jdet;
+	double       xyz_list[NUMVERTICES][3];
+	double       xyz_list_segment[2][3];
+	double       z_list[NUMVERTICES];
+	double       z_segment[2],slope[2];
+	double       slope2,constant_part;
+	double       rho_ice,gravity,n,B;
+	double       ub,vb,z_g,surface,thickness;
+	GaussPenta*  gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	n=matice->GetN();
+	B=matice->GetB();
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
+	Input* surface_input=inputs->GetInput(SurfaceEnum);      ISSMASSERT(surface_input);
+	Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
+	Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
+	for(i=0;i<NUMVERTICES;i++)z_list[i]=xyz_list[i][2];
+
+	/*Loop on the three segments*/
+	for(i=0;i<3;i++){
+		node0=i;
+		node1=i+3;
+
+		for(j=0;j<3;j++){
+			xyz_list_segment[0][j]=xyz_list[node0][j];
+			xyz_list_segment[1][j]=xyz_list[node1][j];
+		}
+
+		connectivity[0]=nodes[node0]->GetConnectivity();
+		connectivity[1]=nodes[node1]->GetConnectivity();
+
+		/*Loop on the Gauss points: */
+		gauss=new GaussPenta(node0,node1,3);
+		for(ig=gauss->begin();ig<gauss->end();ig++){
+			gauss->GaussPoint(ig);
+
+			slopex_input->GetParameterValue(&slope[0],gauss);
+			slopey_input->GetParameterValue(&slope[1],gauss);
+			surface_input->GetParameterValue(&surface,gauss);
+			thickness_input->GetParameterValue(&thickness,gauss);
+
+			slope2=pow(slope[0],2)+pow(slope[1],2);
+			constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
+
+			PentaRef::GetParameterValue(&z_g,&z_list[0],gauss);
+			GetSegmentJacobianDeterminant(&Jdet,&xyz_list_segment[0][0],gauss);
+
+			if (IsOnSurface()){
+				for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight/(double)connectivity[1];
+			}
+			else{//connectivity is too large, should take only half on it
+				for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight*2/(double)connectivity[1];
+			}
+		}
+		delete gauss;
+
+		//Deal with lower surface
+		if (IsOnBed()){
+			constant_part=-1.58*pow((double)10.0,-(double)10.0)*rho_ice*gravity*thickness;
+			ub=constant_part*slope[0];
+			vb=constant_part*slope[1];
+
+			pe->values[2*node0]+=ub/(double)connectivity[0];
+			pe->values[2*node0+1]+=vb/(double)connectivity[0];
+		}
+	}
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticMacAyeal{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticMacAyeal(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorDiagnosticMacAyeal();
+	delete tria->matice; delete tria;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticPattyn{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticPattyn(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int         i,j,ig;
+	double      Jdet;
+	double      slope[3]; //do not put 2! this goes into GetParameterDerivativeValue, which addresses slope[3] also!
+	double      driving_stress_baseline,thickness;
+	double      xyz_list[NUMVERTICES][3];
+	double      l1l6[6];
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
+	Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,3);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(l1l6, gauss);
+
+		thickness_input->GetParameterValue(&thickness, gauss);
+		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+
+		driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG();
+
+		for(i=0;i<NUMVERTICES;i++) for(j=0;j<NDOF2;j++) pe->values[i*NDOF2+j]+= -driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l6[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticStokes(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorDiagnosticStokesViscous();
+	ElementVector* pe2=CreatePVectorDiagnosticStokesShelf();
+	ElementVector* pe =new ElementVector(pe1,pe2);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticStokesViscous {{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticStokesViscous(void){
+
+	/*Constants*/
+	const int numdofbubble=NDOF4*NUMVERTICES+NDOF3*1;
+
+	/*Intermediaries*/
+	int        i,j,ig;
+	int        approximation;
+	double     Jdet,viscosity;
+	double     gravity,rho_ice,stokesreconditioning;
+	double     xyz_list[NUMVERTICES][3];
+	double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	double     l1l7[7]; //for the six nodes and the bubble 
+	double     B[8][numdofbubble];
+	double     B_prime[8][numdofbubble];
+	double     B_prime_bubble[8][3];
+	double     D[8][8]={0.0};
+	double     D_scalar;
+	double     Pe_gaussian[numdofbubble]={0.0}; //for the six nodes and the bubble 
+	double     Ke_temp[numdofbubble][3]={0.0}; //for the six nodes and the bubble 
+	double     Ke_gaussian[numdofbubble][3];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);   ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);   ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);   ISSMASSERT(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBStokes(&B[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss); 
+		GetNodalFunctionsMINI(&l1l7[0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		for(i=0;i<NUMVERTICES+1;i++){
+			Pe_gaussian[i*NDOF4+2]+=-rho_ice*gravity*Jdet*gauss->weight*l1l7[i];
+		}
+
+		/*Get bubble part of Bprime */
+		for(i=0;i<8;i++) for(j=0;j<3;j++) B_prime_bubble[i][j]=B_prime[i][j+24];
+
+		D_scalar=gauss->weight*Jdet;
+		for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
+		for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
+
+		TripleMultiply(&B[0][0],8,numdofbubble,1,
+					&D[0][0],8,8,0,
+					&B_prime_bubble[0][0],8,3,0,
+					&Ke_gaussian[0][0],0);
+
+		for(i=0;i<numdofbubble;i++) for(j=0;j<NDOF3;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
+	}
+
+	/*Condensation*/
+	ReduceVectorStokes(pe->values, &Ke_temp[0][0], &Pe_gaussian[0]);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticStokesShelf{{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticStokesShelf(void){
+
+	/*Intermediaries*/
+	int         i,j,ig;
+	int         approximation;
+	double      gravity,rho_water,bed,water_pressure;
+	double		xyz_list_tria[NUMVERTICES2D][3];
+	double      xyz_list[NUMVERTICES][3];
+	double		bed_normal[3];
+	double      l1l6[6]; //for the six nodes of the penta
+	double      Jdet2d;
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater() || !IsOnBed() || !IsOnShelf()) return NULL;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	rho_water=matpar->GetRhoWater();
+	gravity=matpar->GetG();
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* bed_input=inputs->GetInput(BedEnum); ISSMASSERT(bed_input);
+
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(l1l6, gauss);
+
+		bed_input->GetParameterValue(&bed, gauss);
+		BedNormal(&bed_normal[0],xyz_list_tria);
+		water_pressure=gravity*rho_water*bed;
+
+		for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) pe->values[i*NDOF4+j]+=water_pressure*gauss->weight*Jdet2d*l1l6[i]*bed_normal[j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointStokes{{{1*/
+ElementVector* Penta::CreatePVectorAdjointStokes(void){
+
+	if (!IsOnSurface() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+	ElementVector* pe=tria->CreatePVectorAdjointStokes();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticVert {{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticVert(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorDiagnosticVertVolume();
+	ElementVector* pe2=CreatePVectorDiagnosticVertBase();
+	ElementVector* pe =new ElementVector(pe1,pe2);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticVertVolume {{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticVertVolume(void){
+
+	/*Constants*/
+	const int  numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,ig;
+	int        approximation;
+	double     Jdet;
+	double     xyz_list[NUMVERTICES][3];
+	double     dudx,dvdy,dwdz;
+	double     du[3],dv[3],dw[3];
+	double     l1l6[6];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+	Input* vzstokes_input=NULL;
+	if(approximation==PattynStokesApproximationEnum){
+		vzstokes_input=inputs->GetInput(VzStokesEnum); ISSMASSERT(vzstokes_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(l1l6, gauss);
+
+		vx_input->GetParameterDerivativeValue(&du[0],&xyz_list[0][0],gauss);
+		vy_input->GetParameterDerivativeValue(&dv[0],&xyz_list[0][0],gauss);
+		if(approximation==PattynStokesApproximationEnum){
+			vzstokes_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
+			dwdz=dw[2];
+		}
+		else dwdz=0;
+		dudx=du[0];
+		dvdy=dv[1];
+
+		for (i=0;i<numdof;i++) pe->values[i] += (dudx+dvdy+dwdz)*Jdet*gauss->weight*l1l6[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticVertBase {{{1*/
+ElementVector* Penta::CreatePVectorDiagnosticVertBase(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorDiagnosticBaseVert();
+	delete tria->matice; delete tria;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorMelting {{{1*/
+ElementVector* Penta::CreatePVectorMelting(void){
+	return NULL;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorPrognostic {{{1*/
+ElementVector* Penta::CreatePVectorPrognostic(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorPrognostic();
+	delete tria->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorSlope {{{1*/
+ElementVector* Penta::CreatePVectorSlope(void){
+
+	if (!IsOnBed() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorSlope();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermal {{{1*/
+ElementVector* Penta::CreatePVectorThermal(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorThermalVolume();
+	ElementVector* pe2=CreatePVectorThermalSheet();
+	ElementVector* pe3=CreatePVectorThermalShelf();
+	ElementVector* pe =new ElementVector(pe1,pe2,pe3);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	delete pe3;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermalVolume {{{1*/
+ElementVector* Penta::CreatePVectorThermalVolume(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries*/
+	int    i,j,ig,found=0;
+	int    friction_type,artdiff;
+	double Jdet,phi,dt;
+	double rho_ice,heatcapacity;
+	double thermalconductivity;
+	double viscosity,temperature;
+	double tau_parameter,diameter;
+	double u,v,w;
+	double scalar_def,scalar_transient;
+	double temperature_list[NUMVERTICES];
+	double xyz_list[NUMVERTICES][3];
+	double L[numdof];
+	double dh1dh6[3][6];
+	double epsilon[6];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	thermalconductivity=matpar->GetThermalConductivity();
+	this->inputs->GetParameterValue(&dt,DtEnum);
+	this->parameters->FindParam(&artdiff,ArtDiffEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
+	Input* temperature_input=NULL;
+	if (dt) temperature_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(inputs);
+	if (artdiff==2) diameter=MinEdgeLength(xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,3);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(&L[0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		GetPhi(&phi, &epsilon[0], viscosity);
+
+		scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss->weight;
+		if(dt) scalar_def=scalar_def*dt;
+
+		for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
+
+		/* Build transient now */
+		if(dt){
+			temperature_input->GetParameterValue(&temperature, gauss);
+			scalar_transient=temperature*Jdet*gauss->weight;
+			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_transient*L[i];
+		}
+
+		if(artdiff==2){
+			GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
+
+			vx_input->GetParameterValue(&u, gauss);
+			vy_input->GetParameterValue(&v, gauss);
+			vz_input->GetParameterValue(&w, gauss);
+
+			tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
+
+			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_def*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
+			if(dt){
+				for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_transient*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermalShelf {{{1*/
+ElementVector* Penta::CreatePVectorThermalShelf(void){
+
+	/* Ice/ocean heat exchange flux on ice shelf base */
+	if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorThermalShelf();
+	delete tria->matice; delete tria;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermalSheet {{{1*/
+ElementVector* Penta::CreatePVectorThermalSheet(void){
+
+	/* Geothermal flux on ice sheet base and basal friction */
+	if (!IsOnBed() || IsOnShelf() || IsOnWater()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorThermalSheet();
+	delete tria->matice; delete tria;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::DeepEcho{{{1*/
+void Penta::DeepEcho(void){
+
+	int i;
+	
+	printf("Penta:\n");
+	printf("   id: %i\n",id);
+	nodes[0]->DeepEcho();
+	nodes[1]->DeepEcho();
+	nodes[2]->DeepEcho();
+	nodes[3]->DeepEcho();
+	nodes[4]->DeepEcho();
+	nodes[5]->DeepEcho();
+	matice->DeepEcho();
+	matpar->DeepEcho();
+	printf("   neighbor ids: %i-%i\n",neighbors[0]->Id(),neighbors[1]->Id());
+	printf("   parameters\n");
+	parameters->DeepEcho();
+	printf("   inputs\n");
+	inputs->DeepEcho();
+	printf("   results\n");
+	results->DeepEcho();
+	return;
+}
+/*}}}*/
 /*FUNCTION Penta::DeleteResults {{{1*/
 void  Penta::DeleteResults(void){
@@ -1008,4 +2498,180 @@
 	this->results=new Results();
 
+}
+/*}}}*/
+/*FUNCTION Penta::Echo{{{1*/
+
+void Penta::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION Penta::Enum {{{1*/
+int Penta::Enum(void){
+
+	return PentaEnum;
+
+}
+/*}}}*/
+/*FUNCTION Penta::Gradj {{{1*/
+void  Penta::Gradj(Vec gradient,int control_type){
+
+	/*If on water, skip grad (=0): */
+	if(IsOnWater())return;
+
+	if (control_type==DragCoefficientEnum){
+		GradjDrag(gradient);
+	}
+	else if (control_type==RheologyBbarEnum){
+		GradjB(gradient);
+	}
+	else ISSMERROR("control type %s not supported yet: ",EnumToString(control_type));
+}
+/*}}}*/
+/*FUNCTION Penta::GradjB {{{1*/
+void  Penta::GradjB(Vec gradient){
+
+	int              i;
+	int              approximation;
+	Tria*            tria           =NULL;
+	TriaVertexInput* triavertexinput=NULL;
+
+	/*If on water, skip: */
+	if(IsOnWater())return;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	if (approximation==MacAyealApproximationEnum){
+		/*Bail out element if MacAyeal (2d) and not on bed*/
+		if (!IsOnBed()) return;
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute gardj*/
+
+		/*Depth Average B*/
+		this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
+
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		tria->GradjB(gradient);
+		delete tria->matice; delete tria;
+
+		/*delete B average*/
+		this->matice->inputs->DeleteInput(RheologyBbarEnum);
+	}
+	else{
+		/*Gradient is computed on bed only (Bbar)*/
+		if (!IsOnBed()) return;
+
+		/*Depth Average B*/
+		this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
+
+		/*B is a 2d field, use MacAyeal(2d) gradient even if it is Stokes or Pattyn*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		tria->GradjB(gradient);
+		delete tria->matice; delete tria;
+
+		/*delete B average*/
+		this->matice->inputs->DeleteInput(RheologyBbarEnum);
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::GradjDrag {{{1*/
+void  Penta::GradjDrag(Vec gradient){
+
+	int              i,approximation;
+	double           temp_gradient[6]={0,0,0,0,0,0};
+	Tria*            tria=NULL;
+	TriaVertexInput* triavertexinput=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, on shelf or not on bed, skip: */
+	if(IsOnWater()|| IsOnShelf() || !IsOnBed())return;
+
+	if (approximation==MacAyealApproximationEnum || approximation==PattynApproximationEnum){
+		/*MacAyeal or Pattyn*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+		tria->GradjDrag(gradient);
+		delete tria->matice; delete tria;
+	}
+	else if (approximation==StokesApproximationEnum){
+		/*Stokes*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
+		tria->GradjDragStokes(gradient);
+		delete tria->matice; delete tria;
+	}
+	else if (approximation==NoneApproximationEnum){
+		return;
+	}
+	else ISSMERROR("approximation %s not supported yet",EnumToString(approximation));
+}
+/*}}}*/
+/*FUNCTION Penta::GetBasalElement{{{1*/
+Penta* Penta::GetBasalElement(void){
+
+	/*Output*/
+	Penta* penta=NULL;
+
+	/*Go through all elements till the bed is reached*/
+	penta=this;
+	for(;;){
+		/*Stop if we have reached the surface, else, take lower penta*/
+		if (penta->IsOnBed()) break;
+
+		/* get lower Penta*/
+		penta=penta->GetLowerElement();
+		ISSMASSERT(penta->Id()!=this->id);
+	}
+
+	/*return output*/
+	return penta;
+}
+/*}}}*/
+/*FUNCTION Penta::GetDofList {{{1*/
+void  Penta::GetDofList(int** pdoflist,int approximation_enum,int setenum){
+
+	int  i,j,count=0;
+	int  numberofdofs=0;
+	int* doflist=NULL;
+
+	/*First, figure out size of doflist: */
+	for(i=0;i<6;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+
+	/*Allocate: */
+	doflist=(int*)xmalloc(numberofdofs*sizeof(int));
+
+	/*Populate: */
+	count=0;
+	for(i=0;i<6;i++){
+		nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
+		count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+	}
+
+	/*Assign output pointers:*/
+	*pdoflist=doflist;
+}
+/*}}}*/
+/*FUNCTION Penta::GetDofList1 {{{1*/
+void  Penta::GetDofList1(int* doflist){
+
+	int i;
+	for(i=0;i<6;i++) doflist[i]=nodes[i]->GetDofList1();
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetElementType {{{1*/
+int Penta::GetElementType(){
+
+	/*return PentaRef field*/
+	return this->element_type;
+}
+/*}}}*/
+/*FUNCTION Penta::GetLowerElement{{{1*/
+Penta* Penta::GetLowerElement(void){
+
+	Penta* upper_penta=NULL;
+
+	upper_penta=(Penta*)neighbors[0]; //first one (0) under, second one (1) above
+
+	return upper_penta;
 }
 /*}}}*/
@@ -1019,4 +2685,117 @@
 	}
 	ISSMERROR("Node provided not found among element nodes");
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
+void Penta::GetParameterListOnVertices(double* pvalue,int enumtype){
+
+	/*Intermediaries*/
+	double     value[NUMVERTICES];
+	GaussPenta *gauss              = NULL;
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+	if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
+
+	/*Checks in debugging mode*/
+	ISSMASSERT(pvalue);
+
+	/* Start looping on the number of vertices: */
+	gauss=new GaussPenta();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+		input->GetParameterValue(&pvalue[iv],gauss);
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
+void Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
+
+	/*Intermediaries*/
+	double     value[NUMVERTICES];
+	GaussPenta *gauss              = NULL;
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	ISSMASSERT(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		gauss=new GaussPenta();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetParameterValue(&pvalue[iv],gauss);
+		}
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
+void Penta::GetParameterValue(double* pvalue,Node* node,int enumtype){
+
+	Input* input=inputs->GetInput(enumtype);
+	if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
+
+	GaussPenta* gauss=new GaussPenta();
+	gauss->GaussVertex(this->GetNodeIndex(node));
+
+	input->GetParameterValue(pvalue,gauss);
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GetPhi {{{1*/
+void Penta::GetPhi(double* phi, double*  epsilon, double viscosity){
+	/*Compute deformational heating from epsilon and viscosity */
+
+	double epsilon_matrix[3][3];
+	double epsilon_eff;
+	double epsilon_sqr[3][3];
+
+	/* Build epsilon matrix */
+	epsilon_matrix[0][0]=*(epsilon+0);
+	epsilon_matrix[1][0]=*(epsilon+3);
+	epsilon_matrix[2][0]=*(epsilon+4);
+	epsilon_matrix[0][1]=*(epsilon+3);
+	epsilon_matrix[1][1]=*(epsilon+1);
+	epsilon_matrix[2][1]=*(epsilon+5);
+	epsilon_matrix[0][2]=*(epsilon+4);
+	epsilon_matrix[1][2]=*(epsilon+5);
+	epsilon_matrix[2][2]=*(epsilon+2);
+
+	/* Effective value of epsilon_matrix */
+	epsilon_sqr[0][0]=pow(epsilon_matrix[0][0],2);
+	epsilon_sqr[1][0]=pow(epsilon_matrix[1][0],2);
+	epsilon_sqr[2][0]=pow(epsilon_matrix[2][0],2);
+	epsilon_sqr[0][1]=pow(epsilon_matrix[0][1],2);
+	epsilon_sqr[1][1]=pow(epsilon_matrix[1][1],2);
+	epsilon_sqr[2][1]=pow(epsilon_matrix[2][1],2);
+	epsilon_sqr[0][2]=pow(epsilon_matrix[0][2],2);
+	epsilon_sqr[1][2]=pow(epsilon_matrix[1][2],2);
+	epsilon_sqr[2][2]=pow(epsilon_matrix[2][2],2);
+	epsilon_eff=1/pow(2,0.5)*pow((epsilon_sqr[0][0]+epsilon_sqr[0][1]+ epsilon_sqr[0][2]+ epsilon_sqr[1][0]+ epsilon_sqr[1][1]+ epsilon_sqr[1][2]+ epsilon_sqr[2][0]+ epsilon_sqr[2][1]+ epsilon_sqr[2][2]),0.5);
+
+	/*Phi = Tr(sigma * eps) 
+	 *    = Tr(sigma'* eps)
+	 *    = 2 * eps_eff * sigma'_eff
+	 *    = 4 * eps_eff ^2*/
+	*phi=4*pow(epsilon_eff,2.0)*viscosity;
+}
+/*}}}*/
+/*FUNCTION Penta::GetSidList{{{1*/
+void  Penta::GetSidList(int* sidlist){
+
+	int i;
+	for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
 
 }
@@ -1056,4 +2835,272 @@
 		ISSMERROR("analysis: %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
 	}
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{1*/
+void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int          i;
+	int          approximation;
+	int*         doflist=NULL;
+	double       vx,vy;
+	double       values[numdof];
+	GaussPenta*  gauss;
+
+	/*Get approximation enum and dof list: */
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+
+	/*If the element is a coupling, do nothing: every grid is also on an other elements 
+	 * (as coupling is between MacAyeal and Pattyn) so the other element will take care of it*/
+	GetDofList(&doflist,approximation,GsetEnum);
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	/*P1 element only for now*/
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+
+		/*Recover vx and vy*/
+		gauss->GaussVertex(i);
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	/*Add value to global vector*/
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{1*/
+void  Penta::GetSolutionFromInputsDiagnosticHutter(Vec solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	double       vx,vy;
+	double       values[numdof];
+	GaussPenta*  gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	/*P1 element only for now*/
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+		/*Recover vx and vy*/
+		gauss->GaussVertex(i);
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	/*Add value to global vector*/
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{1*/
+void  Penta::GetSolutionFromInputsDiagnosticVert(Vec solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	double       vz;
+	double       values[numdof];
+	GaussPenta*  gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	/*P1 element only for now*/
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+		/*Recover vz */
+		gauss->GaussVertex(i);
+		vz_input->GetParameterValue(&vz,gauss);
+		values[i]=vz;
+	}
+
+	/*Add value to global vector*/
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{1*/
+void  Penta::GetSolutionFromInputsDiagnosticStokes(Vec solution){
+
+	const int    numdof=NDOF4*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	double       vx,vy,vz,p;
+	double       stokesreconditioning;
+	double       values[numdof];
+	GaussPenta   *gauss;
+
+	/*Get dof list: */
+	GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);       ISSMASSERT(vz_input);
+	Input* p_input =inputs->GetInput(PressureEnum); ISSMASSERT(p_input);
+
+	/*Recondition pressure: */
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+
+	/*Ok, we have vx vy vz and P in values, fill in vx vy vz P arrays: */
+	/*P1 element only for now*/
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+		gauss->GaussVertex(i);
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		vz_input->GetParameterValue(&vz,gauss);
+		p_input ->GetParameterValue(&p ,gauss);
+		values[i*NDOF4+0]=vx;
+		values[i*NDOF4+1]=vy;
+		values[i*NDOF4+2]=vz;
+		values[i*NDOF4+3]=p/stokesreconditioning;
+	}
+
+	/*Add value to global vector*/
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsThermal{{{1*/
+void  Penta::GetSolutionFromInputsThermal(Vec solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	double       values[numdof];
+	double       temp;
+	GaussPenta   *gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* t_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(t_input);
+
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+		/*Recover temperature*/
+		gauss->GaussVertex(i);
+		t_input->GetParameterValue(&temp,gauss);
+		values[i]=temp;
+	}
+
+	/*Add value to global vector*/
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetStabilizationParameter {{{1*/
+double Penta::GetStabilizationParameter(double u, double v, double w, double diameter, double rho_ice, double heatcapacity, double thermalconductivity){
+	/*Compute stabilization parameter*/
+
+	double normu;
+	double tau_parameter;
+
+	normu=pow(pow(u,2)+pow(v,2)+pow(w,2),0.5);
+	if(normu*diameter/(3*2*thermalconductivity/(rho_ice*heatcapacity))<1){
+		tau_parameter=pow(diameter,2)/(3*2*2*thermalconductivity/(rho_ice*heatcapacity));
+	}
+	else tau_parameter=diameter/(2*normu);
+
+	return tau_parameter;
+}
+/*}}}*/
+/*FUNCTION Penta::GetStrainRate3dPattyn{{{1*/
+void Penta::GetStrainRate3dPattyn(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input){
+	/*Compute the 3d Blatter/PattynStrain Rate (5 components):
+	 *
+	 * epsilon=[exx eyy exy exz eyz]
+	 *
+	 * with exz=1/2 du/dz
+	 *      eyz=1/2 dv/dz
+	 *
+	 * the contribution of vz is neglected
+	 */
+
+	int i;
+	double epsilonvx[5];
+	double epsilonvy[5];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input){
+		ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
+	}
+
+	/*Get strain rate assuming that epsilon has been allocated*/
+	vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
+	vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
+
+	/*Sum all contributions*/
+	for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
+}
+/*}}}*/
+/*FUNCTION Penta::GetStrainRate3d{{{1*/
+void Penta::GetStrainRate3d(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input, Input* vz_input){
+	/*Compute the 3d Strain Rate (6 components):
+	 *
+	 * epsilon=[exx eyy ezz exy exz eyz]
+	 */
+
+	int i;
+	double epsilonvx[6];
+	double epsilonvy[6];
+	double epsilonvz[6];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input || !vz_input){
+		ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p, vz: %p\n",vx_input,vy_input,vz_input);
+	}
+
+	/*Get strain rate assuming that epsilon has been allocated*/
+	vx_input->GetVxStrainRate3d(epsilonvx,xyz_list,gauss);
+	vy_input->GetVyStrainRate3d(epsilonvy,xyz_list,gauss);
+	vz_input->GetVzStrainRate3d(epsilonvz,xyz_list,gauss);
+
+	/*Sum all contributions*/
+	for(i=0;i<6;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i]+epsilonvz[i];
+}
+/*}}}*/
+/*FUNCTION Penta::GetUpperElement{{{1*/
+Penta* Penta::GetUpperElement(void){
+
+	Penta* upper_penta=NULL;
+
+	upper_penta=(Penta*)neighbors[1]; //first one under, second one above
+
+	return upper_penta;
 }
 /*}}}*/
@@ -1076,17 +3123,35 @@
 }
 /*}}}*/
-/*FUNCTION Penta::Gradj {{{1*/
-void  Penta::Gradj(Vec gradient,int control_type){
-
-	/*If on water, skip grad (=0): */
-	if(IsOnWater())return;
-
-	if (control_type==DragCoefficientEnum){
-		GradjDrag(gradient);
-	}
-	else if (control_type==RheologyBbarEnum){
-		GradjB(gradient);
-	}
-	else ISSMERROR("control type %s not supported yet: ",EnumToString(control_type));
+/*FUNCTION Penta::GetZcoord {{{1*/
+double Penta::GetZcoord(GaussPenta* gauss){
+
+	int    i;
+	double z;
+	double xyz_list[NUMVERTICES][3];
+	double z_list[NUMVERTICES];
+
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	for(i=0;i<NUMVERTICES;i++) z_list[i]=xyz_list[i][2];
+	PentaRef::GetParameterValue(&z,z_list,gauss);
+
+	return z;
+}
+/*}}}*/
+/*FUNCTION Penta::Id {{{1*/
+int    Penta::Id(void){
+	return id; 
+}
+/*}}}*/
+/*FUNCTION Penta::InputArtificialNoise{{{1*/
+void  Penta::InputArtificialNoise(int enum_type,double min,double max){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
+
+	/*ArtificialNoise: */
+	input->ArtificialNoise(min,max);
 }
 /*}}}*/
@@ -1271,15 +3336,54 @@
 }
 /*}}}*/
-/*FUNCTION Penta::InputArtificialNoise{{{1*/
-void  Penta::InputArtificialNoise(int enum_type,double min,double max){
-
-	Input* input=NULL;
-
-	/*Make a copy of the original input: */
-	input=(Input*)this->inputs->GetInput(enum_type);
-	if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
-
-	/*ArtificialNoise: */
-	input->ArtificialNoise(min,max);
+/*FUNCTION Penta::InputExtrude {{{1*/
+void  Penta::InputExtrude(int enum_type,int object_type){
+
+	Penta *penta          = NULL;
+	Input *original_input = NULL;
+
+	/*Are we on the base, not on the surface?:*/
+	if(IsOnBed()){
+		/*OK, we are on bed. we will follow the steps:
+		 * 1: find input and extrude it.
+		 * 2: follow the upper element until we reach the surface
+		 * 3: for each element, we will add a copy of the extruded input*/
+
+		/*Step1: Extrude the original input: */
+		if (object_type==ElementsEnum)
+		 original_input=(Input*)this->inputs->GetInput(enum_type);
+		else if (object_type==MaterialsEnum)
+		 original_input=(Input*)matice->inputs->GetInput(enum_type);
+		else
+		 ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
+		if(!original_input) ISSMERROR("%s%s"," could not find input with enum:",EnumToString(enum_type));
+		original_input->Extrude();
+
+		/*Stop if there is only one layer of element*/
+		if (this->IsOnSurface()) return;
+
+		/*Step 2: this input has been extruded for this element, now follow the upper element*/
+		penta=this;
+		for(;;){
+
+			/* get upper Penta*/
+			penta=penta->GetUpperElement();
+			ISSMASSERT(penta->Id()!=this->id);
+
+			/*Add input of the basal element to penta->inputs*/
+			Input* copy=NULL;
+			copy=(Input*)original_input->copy();
+			if (object_type==ElementsEnum)
+			 penta->inputs->AddInput((Input*)copy);
+			else if (object_type==MaterialsEnum)
+			 penta->matice->inputs->AddInput((Input*)copy);
+			else
+			 ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
+
+			/*Stop if we have reached the surface*/
+			if (penta->IsOnSurface()) break;
+		}
+	}
+
+	return;
 }
 /*}}}*/
@@ -1316,4 +3420,1246 @@
 }
 /*}}}*/
+/*FUNCTION Penta::InputUpdateFromConstant(bool value, int name);{{{1*/
+void  Penta::InputUpdateFromConstant(bool constant, int name){
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	this->inputs->AddInput(new BoolInput(name,constant));
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromConstant(double value, int name);{{{1*/
+void  Penta::InputUpdateFromConstant(double constant, int name){
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	this->inputs->AddInput(new DoubleInput(name,constant));
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromConstant(int value, int name);{{{1*/
+void  Penta::InputUpdateFromConstant(int constant, int name){
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	this->inputs->AddInput(new IntInput(name,constant));
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromIoModel {{{1*/
+void Penta::InputUpdateFromIoModel(int index,IoModel* iomodel){ 
+
+	/*Intermediaries*/
+	IssmInt i,j;
+	int     penta_vertex_ids[6];
+	double  nodeinputs[6];
+
+	/*Checks if debuging*/
+	/*{{{2*/
+	ISSMASSERT(iomodel->elements);
+	/*}}}*/
+
+	/*Recover vertices ids needed to initialize inputs*/
+	for(i=0;i<6;i++){ 
+		penta_vertex_ids[i]=(int)iomodel->elements[6*index+i]; //ids for vertices are in the elements array from Matlab
+	}
+
+	//add as many inputs per element as requested: 
+	if (iomodel->thickness) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->thickness[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(ThicknessEnum,nodeinputs));
+	}
+	if (iomodel->surface) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->surface[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(SurfaceEnum,nodeinputs));
+	}
+	if (iomodel->bed) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->bed[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(BedEnum,nodeinputs));
+	}
+	if (iomodel->drag_coefficient) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->drag_coefficient[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(DragCoefficientEnum,nodeinputs));
+
+		if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
+		if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
+		this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
+
+	}
+	if (iomodel->melting_rate) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->melting_rate[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(MeltingRateEnum,nodeinputs));
+	}
+	if (iomodel->accumulation_rate) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->accumulation_rate[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(AccumulationRateEnum,nodeinputs));
+	}
+	if (iomodel->geothermalflux) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->geothermalflux[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(GeothermalFluxEnum,nodeinputs));
+	}	
+	if (iomodel->pressure) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->pressure[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(PressureEnum,nodeinputs));
+	}
+	if (iomodel->temperature) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->temperature[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,nodeinputs));
+	}
+	if (iomodel->dhdt) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->dhdt[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(DhDtEnum,nodeinputs));
+	}
+	/*vx,vy and vz: */
+	if (iomodel->vx) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(VxEnum,nodeinputs));
+		this->inputs->AddInput(new PentaVertexInput(VxOldEnum,nodeinputs));
+		if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVxEnum,nodeinputs));
+	}
+	if (iomodel->vy) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(VyEnum,nodeinputs));
+		this->inputs->AddInput(new PentaVertexInput(VyOldEnum,nodeinputs));
+		if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVyEnum,nodeinputs));
+	}
+	if (iomodel->vz) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(VzEnum,nodeinputs));
+		this->inputs->AddInput(new PentaVertexInput(VzOldEnum,nodeinputs));
+		if(iomodel->qmu_analysis)this->inputs->AddInput(new PentaVertexInput(QmuVzEnum,nodeinputs));
+	}
+	if (iomodel->vx_obs) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vx_obs[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(VxObsEnum,nodeinputs));
+	}
+	if (iomodel->vy_obs) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vy_obs[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(VyObsEnum,nodeinputs));
+	}
+	if (iomodel->vz_obs) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->vz_obs[penta_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new PentaVertexInput(VzObsEnum,nodeinputs));
+	}
+	if (iomodel->weights) {
+		for(i=0;i<6;i++)nodeinputs[i]=iomodel->weights[penta_vertex_ids[i]-1];
+		this->inputs->AddInput(new PentaVertexInput(WeightsEnum,nodeinputs));
+	}
+	if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
+	if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
+	if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
+	if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
+
+	/*time: */
+	this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
+
+	/*Control Inputs*/
+	if (iomodel->control_analysis && iomodel->control_type){
+		for(i=0;i<iomodel->num_control_type;i++){
+			switch((int)iomodel->control_type[i]){
+				case DhDtEnum:
+					if (iomodel->dhdt){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->dhdt[penta_vertex_ids[j]-1]/iomodel->yts;
+						this->inputs->AddInput(new ControlInput(DhDtEnum,PentaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case VxEnum:
+					if (iomodel->vx){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->vx[penta_vertex_ids[j]-1]/iomodel->yts;
+						this->inputs->AddInput(new ControlInput(VxEnum,PentaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case VyEnum:
+					if (iomodel->vy){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->vy[penta_vertex_ids[j]-1]/iomodel->yts;
+						this->inputs->AddInput(new ControlInput(VyEnum,PentaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case DragCoefficientEnum:
+					if (iomodel->drag_coefficient){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->drag_coefficient[penta_vertex_ids[j]-1];
+						this->inputs->AddInput(new ControlInput(DragCoefficientEnum,PentaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case RheologyBbarEnum:
+					/*Matice will take care of it*/ break;
+				default:
+					ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
+			}
+		}
+	}
+
+	//Need to know the type of approximation for this element
+	if(iomodel->elements_type){
+		if (*(iomodel->elements_type+index)==MacAyealApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealApproximationEnum));
+		}
+		else if (*(iomodel->elements_type+index)==PattynApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,PattynApproximationEnum));
+		}
+		else if (*(iomodel->elements_type+index)==MacAyealPattynApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealPattynApproximationEnum));
+		}
+		else if (*(iomodel->elements_type+index)==HutterApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,HutterApproximationEnum));
+		}
+		else if (*(iomodel->elements_type+index)==StokesApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,StokesApproximationEnum));
+		}
+		else if (*(iomodel->elements_type+index)==PattynStokesApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,PattynStokesApproximationEnum));
+		}
+		else if (*(iomodel->elements_type+index)==NoneApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,NoneApproximationEnum));
+		}
+		else{
+			ISSMERROR("Approximation type %s not supported yet",EnumToString((int)*(iomodel->elements_type+index)));
+		}
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolution {{{1*/
+void  Penta::InputUpdateFromSolution(double* solution){
+
+	int analysis_type;
+
+	/*retreive parameters: */
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
+	if (analysis_type==DiagnosticHorizAnalysisEnum){
+		InputUpdateFromSolutionDiagnosticHoriz( solution);
+	}
+	else if (analysis_type==DiagnosticHutterAnalysisEnum){
+		InputUpdateFromSolutionDiagnosticHutter( solution);
+	}
+	else if (analysis_type==DiagnosticVertAnalysisEnum){
+		InputUpdateFromSolutionDiagnosticVert( solution);
+	}
+	else if (analysis_type==AdjointHorizAnalysisEnum){
+		int approximation;
+		inputs->GetParameterValue(&approximation,ApproximationEnum);
+		if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
+			InputUpdateFromSolutionAdjointStokes( solution);
+		}
+		else{
+			InputUpdateFromSolutionAdjointHoriz( solution);
+		}
+	}
+	else if (analysis_type==BedSlopeXAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeXEnum);
+	}
+	else if (analysis_type==BedSlopeYAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeYEnum);
+	}
+	else if (analysis_type==SurfaceSlopeXAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeXEnum);
+	}
+	else if (analysis_type==SurfaceSlopeYAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeYEnum);
+	}
+	else if (analysis_type==PrognosticAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
+	}
+	else if (analysis_type==BalancedthicknessAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
+	}
+	else if (analysis_type==BalancedvelocitiesAnalysisEnum){
+		InputUpdateFromSolutionOneDofCollapsed(solution,VelEnum);
+	}
+	else if (analysis_type==ThermalAnalysisEnum){
+		InputUpdateFromSolutionThermal( solution);
+	}
+	else if (analysis_type==MeltingAnalysisEnum){
+		InputUpdateFromSolutionOneDof(solution,MeltingRateEnum);
+	}
+	else{
+		ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
+
+	int  approximation;
+
+	/*Recover inputs*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*MacAyeal, everything is done by the element on bed*/
+	if (approximation==MacAyealApproximationEnum){
+		if (!IsOnBed()){
+			/*Do nothing. Element on bed will take care of it*/
+			return;
+		}
+		else{
+			InputUpdateFromSolutionDiagnosticMacAyeal(solution);
+			return;
+		}
+	}
+	else if (approximation==PattynApproximationEnum){
+		InputUpdateFromSolutionDiagnosticPattyn(solution);
+	}
+	else if (approximation==PattynStokesApproximationEnum){
+		InputUpdateFromSolutionDiagnosticPattynStokes(solution);
+	}
+	else if (approximation==MacAyealStokesApproximationEnum){
+		InputUpdateFromSolutionDiagnosticMacAyealStokes(solution);
+	}
+	else if (approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
+		InputUpdateFromSolutionDiagnosticStokes(solution);
+	}
+	else if (approximation==MacAyealPattynApproximationEnum){
+		InputUpdateFromSolutionDiagnosticMacAyealPattyn(solution);
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyeal {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticMacAyeal(double* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int     i,dummy;
+	double  rho_ice,g;
+	double  values[numdof];
+	double  vx[NUMVERTICES];
+	double  vy[NUMVERTICES];
+	double  vz[NUMVERTICES];
+	double  vel[NUMVERTICES];
+	double  pressure[NUMVERTICES];
+	double  surface[NUMVERTICES];
+	double  xyz_list[NUMVERTICES][3];
+	int    *doflist = NULL;
+	double *vz_ptr  = NULL;
+	Penta  *penta   = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,MacAyealApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays and extrude */
+	for(i=0;i<3;i++){
+		vx[i]  =values[i*NDOF2+0];
+		vy[i]  =values[i*NDOF2+1];
+		vx[i+3]=vx[i];
+		vy[i+3]=vy[i];
+	}
+
+	/*Get parameters fro pressure computation*/
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+
+	/*Start looping over all elements above current element and update all inputs*/
+	penta=this;
+	for(;;){
+
+		/*Get node data: */
+		GetVerticesCoordinates(&xyz_list[0][0],penta->nodes,NUMVERTICES);
+
+		/*Now Compute vel*/
+		Input* vz_input=inputs->GetInput(VzEnum);
+		if (vz_input){
+			if (vz_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
+			vz_input->GetValuesPtr(&vz_ptr,&dummy);
+			for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
+		}
+		else{for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;}
+		for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+		/*Now compute pressure*/
+		GetParameterListOnVertices(&surface[0],SurfaceEnum);
+		for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
+
+		/*Now, we have to move the previous Vx and Vy inputs  to old 
+		 * status, otherwise, we'll wipe them off: */
+		penta->inputs->ChangeEnum(VxEnum,VxOldEnum);
+		penta->inputs->ChangeEnum(VyEnum,VyOldEnum);
+		penta->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+		/*Add vx and vy as inputs to the tria element: */
+		penta->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+		penta->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+		penta->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+		penta->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
+	}
+	
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn(double* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+	const int    numdof2d=NDOF2*NUMVERTICES2D;
+
+	int     i,dummy;
+	double  rho_ice,g;
+	double  macayeal_values[numdof];
+	double  pattyn_values[numdof];
+	double  vx[NUMVERTICES];
+	double  vy[NUMVERTICES];
+	double  vz[NUMVERTICES];
+	double  vel[NUMVERTICES];
+	double  pressure[NUMVERTICES];
+	double  surface[NUMVERTICES];
+	double  xyz_list[NUMVERTICES][3];
+	int*    doflistp = NULL;
+	int*    doflistm = NULL;
+	double  *vz_ptr  = NULL;
+	Penta   *penta   = NULL;
+
+	/*OK, we have to add results of this element for pattyn 
+	 * and results from the penta at base for macayeal. Now recover results*/
+	penta=GetBasalElement();
+
+	/*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
+	GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
+	penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof2d;i++){
+		pattyn_values[i]=solution[doflistp[i]];
+		macayeal_values[i]=solution[doflistm[i]];
+	}
+	for(i=numdof2d;i<numdof;i++){
+		pattyn_values[i]=solution[doflistp[i]];
+		macayeal_values[i]=macayeal_values[i-numdof2d];
+	}
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=macayeal_values[i*NDOF2+0]+pattyn_values[i*NDOF2+0];
+		vy[i]=macayeal_values[i*NDOF2+1]+pattyn_values[i*NDOF2+1];
+	}
+
+	/*Get Vz*/
+	Input* vz_input=inputs->GetInput(VzEnum);
+	if (vz_input){
+		if (vz_input->Enum()!=PentaVertexInputEnum){
+			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
+		}
+		vz_input->GetValuesPtr(&vz_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
+	}
+	else{
+		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
+	 *so the pressure is just the pressure at the z elevation: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetParameterListOnVertices(&surface[0],SurfaceEnum);
+	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflistp);
+	xfree((void**)&doflistm);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes(double* solution){
+
+	const int    numdofm=NDOF2*NUMVERTICES;
+	const int    numdofs=NDOF4*NUMVERTICES;
+	const int    numdof2d=NDOF2*NUMVERTICES2D;
+
+	int     i,dummy;
+	double  stokesreconditioning;
+	double  macayeal_values[numdofm];
+	double  stokes_values[numdofs];
+	double  vx[NUMVERTICES];
+	double  vy[NUMVERTICES];
+	double  vz[NUMVERTICES];
+	double  vzmacayeal[NUMVERTICES];
+	double  vzstokes[NUMVERTICES];
+	double  vel[NUMVERTICES];
+	double  pressure[NUMVERTICES];
+	double  xyz_list[NUMVERTICES][3];
+	int*    doflistm        = NULL;
+	int*    doflists        = NULL;
+	double  *vzmacayeal_ptr = NULL;
+	Penta   *penta          = NULL;
+
+	/*OK, we have to add results of this element for macayeal 
+	 * and results from the penta at base for macayeal. Now recover results*/
+	penta=GetBasalElement();
+
+	/*Get dof listof this element (macayeal dofs) and of the penta at base (macayeal dofs): */
+	penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
+	GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof2d;i++){
+		macayeal_values[i]=solution[doflistm[i]];
+		macayeal_values[i+numdof2d]=solution[doflistm[i]];
+	}
+	for(i=0;i<numdofs;i++){
+		stokes_values[i]=solution[doflists[i]];
+	}
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=stokes_values[i*NDOF4+0]+macayeal_values[i*NDOF2+0];
+		vy[i]=stokes_values[i*NDOF4+1]+macayeal_values[i*NDOF2+1];
+		vzstokes[i]=stokes_values[i*NDOF4+2];
+		pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
+	}
+
+	/*Get Vz*/
+	Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);
+	if (vzmacayeal_input){
+		if (vzmacayeal_input->Enum()!=PentaVertexInputEnum){
+			ISSMERROR("Cannot compute Vel as VzMacAyeal is of type %s",EnumToString(vzmacayeal_input->Enum()));
+		}
+		vzmacayeal_input->GetValuesPtr(&vzmacayeal_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vzmacayeal[i]=vzmacayeal_ptr[i];
+	}
+	else{
+		ISSMERROR("Cannot update solution as VzMacAyeal is not present");
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) {
+		vz[i]=vzmacayeal[i]+vzstokes[i];
+		vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+	}
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
+	this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
+	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflistm);
+	xfree((void**)&doflists);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattyn {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticPattyn(double* solution){
+	
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int    i,dummy;
+	double rho_ice,g;
+	double values[numdof];
+	double vx[NUMVERTICES];
+	double vy[NUMVERTICES];
+	double vz[NUMVERTICES];
+	double vel[NUMVERTICES];
+	double pressure[NUMVERTICES];
+	double surface[NUMVERTICES];
+	double xyz_list[NUMVERTICES][3];
+	int*   doflist = NULL;
+	double *vz_ptr = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,PattynApproximationEnum,GsetEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=values[i*NDOF2+0];
+		vy[i]=values[i*NDOF2+1];
+	}
+
+	/*Get Vz*/
+	Input* vz_input=inputs->GetInput(VzEnum);
+	if (vz_input){
+		if (vz_input->Enum()!=PentaVertexInputEnum){
+			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
+		}
+		vz_input->GetValuesPtr(&vz_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
+	}
+	else{
+		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
+	 *so the pressure is just the pressure at the z elevation: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetParameterListOnVertices(&surface[0],SurfaceEnum);
+	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattynStokes {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticPattynStokes(double* solution){
+
+	const int    numdofp=NDOF2*NUMVERTICES;
+	const int    numdofs=NDOF4*NUMVERTICES;
+
+	int    i,dummy;
+	double pattyn_values[numdofp];
+	double stokes_values[numdofs];
+	double vx[NUMVERTICES];
+	double vy[NUMVERTICES];
+	double vz[NUMVERTICES];
+	double vzpattyn[NUMVERTICES];
+	double vzstokes[NUMVERTICES];
+	double vel[NUMVERTICES];
+	double pressure[NUMVERTICES];
+	double xyz_list[NUMVERTICES][3];
+	double stokesreconditioning;
+	int*   doflistp      = NULL;
+	int*   doflists      = NULL;
+	double *vzpattyn_ptr = NULL;
+	Penta  *penta        = NULL;
+
+	/*OK, we have to add results of this element for pattyn 
+	 * and results from the penta at base for macayeal. Now recover results*/
+	penta=GetBasalElement();
+
+	/*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
+	GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
+	GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdofp;i++) pattyn_values[i]=solution[doflistp[i]];
+	for(i=0;i<numdofs;i++) stokes_values[i]=solution[doflists[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=stokes_values[i*NDOF4+0]+pattyn_values[i*NDOF2+0];
+		vy[i]=stokes_values[i*NDOF4+1]+pattyn_values[i*NDOF2+1];
+		vzstokes[i]=stokes_values[i*NDOF4+2];
+		pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
+	}
+
+	/*Get Vz*/
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);
+	if (vzpattyn_input){
+		if (vzpattyn_input->Enum()!=PentaVertexInputEnum){
+			ISSMERROR("Cannot compute Vel as VzPattyn is of type %s",EnumToString(vzpattyn_input->Enum()));
+		}
+		vzpattyn_input->GetValuesPtr(&vzpattyn_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vzpattyn[i]=vzpattyn_ptr[i];
+	}
+	else{
+		ISSMERROR("Cannot update solution as VzPattyn is not present");
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) {
+		vz[i]=vzpattyn[i]+vzstokes[i];
+		vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+	}
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
+	this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
+	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflistp);
+	xfree((void**)&doflists);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHutter {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticHutter(double* solution){
+	
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int     i,dummy;
+	double  rho_ice,g;
+	double  values[numdof];
+	double  vx[NUMVERTICES];
+	double  vy[NUMVERTICES];
+	double  vz[NUMVERTICES];
+	double  vel[NUMVERTICES];
+	double  pressure[NUMVERTICES];
+	double  surface[NUMVERTICES];
+	double  xyz_list[NUMVERTICES][3];
+	int*    doflist = NULL;
+	double* vz_ptr  = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=values[i*NDOF2+0];
+		vy[i]=values[i*NDOF2+1];
+	}
+
+	/*Get Vz*/
+	Input* vz_input=inputs->GetInput(VzEnum);
+	if (vz_input){
+		if (vz_input->Enum()!=PentaVertexInputEnum){
+			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
+		}
+		vz_input->GetValuesPtr(&vz_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
+	}
+	else{
+		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
+	 *so the pressure is just the pressure at the z elevation: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetParameterListOnVertices(&surface[0],SurfaceEnum);
+	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticVert {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticVert(double* solution){
+
+	const int numdof=NDOF1*NUMVERTICES;
+	
+	int      i,dummy;
+	int      approximation;
+	double   rho_ice,g;
+	double   values[numdof];
+	double   vx[NUMVERTICES];
+	double   vy[NUMVERTICES];
+	double   vz[NUMVERTICES];
+	double   vzmacayeal[NUMVERTICES];
+	double   vzpattyn[NUMVERTICES];
+	double   vzstokes[NUMVERTICES];
+	double   vel[NUMVERTICES];
+	double   pressure[NUMVERTICES];
+	double   surface[NUMVERTICES];
+	double   xyz_list[NUMVERTICES][3];
+	int*     doflist      = NULL;
+	double*  vx_ptr       = NULL;
+	double*  vy_ptr       = NULL;
+	double*  vzstokes_ptr = NULL;
+
+
+	/*Get the approximation and do nothing if the element in Stokes or None*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
+		return;
+	}
+
+	/*Get dof list and vertices coordinates: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector vz: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+	for(i=0;i<NUMVERTICES;i++) vz[i]=values[i*NDOF1+0];
+
+	/*Get Vx and Vy*/
+	Input* vx_input=inputs->GetInput(VxEnum);
+	if (vx_input){
+		if (vx_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vx is of type %s",EnumToString(vx_input->Enum()));
+		vx_input->GetValuesPtr(&vx_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vx[i]=vx_ptr[i];
+	}
+	else for(i=0;i<NUMVERTICES;i++) vx[i]=0.0;
+
+	Input* vy_input=inputs->GetInput(VyEnum);
+	if (vy_input){
+		if (vy_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vy is of type %s",EnumToString(vy_input->Enum()));
+		vy_input->GetValuesPtr(&vy_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vy[i]=vy_ptr[i];
+	}
+	else for(i=0;i<NUMVERTICES;i++) vy[i]=0.0;
+
+	/*Do some modifications if we actually have a PattynStokes or MacAyealStokes element*/
+	if(approximation==PattynStokesApproximationEnum){
+		Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
+		if (vzstokes_input){
+			if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
+			vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
+			for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
+		}
+		else ISSMERROR("Cannot compute Vz as VzStokes in not present in PattynStokes element");
+		for(i=0;i<NUMVERTICES;i++){
+			vzpattyn[i]=vz[i];
+			vz[i]=vzpattyn[i]+vzstokes[i];
+		}
+	}
+	else if(approximation==MacAyealStokesApproximationEnum){
+		Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
+		if (vzstokes_input){
+			if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
+			vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
+			for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
+		}
+		else ISSMERROR("Cannot compute Vz as VzStokes in not present in MacAyealStokes element");
+		for(i=0;i<NUMVERTICES;i++){
+			vzmacayeal[i]=vz[i];
+			vz[i]=vzmacayeal[i]+vzstokes[i];
+		}
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
+	 *so the pressure is just the pressure at the z elevation: except it this is a PattynStokes element */
+	if(approximation!=PattynStokesApproximationEnum &&  approximation!=MacAyealStokesApproximationEnum){
+		rho_ice=matpar->GetRhoIce();
+		g=matpar->GetG();
+		GetParameterListOnVertices(&surface[0],SurfaceEnum);
+		for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
+	}
+
+	/*Now, we have to move the previous Vz inputs to old 
+	 * status, otherwise, we'll wipe them off and add the new inputs: */
+	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
+
+	if(approximation!=PattynStokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum){
+		this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+		this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+	}
+	else if(approximation==PattynStokesApproximationEnum){
+		this->inputs->AddInput(new PentaVertexInput(VzPattynEnum,vzpattyn));
+	}
+	else if(approximation==MacAyealStokesApproximationEnum){
+		this->inputs->AddInput(new PentaVertexInput(VzMacAyealEnum,vzpattyn));
+	}
+
+	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
+	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticStokes {{{1*/
+void  Penta::InputUpdateFromSolutionDiagnosticStokes(double* solution){
+	
+	const int numdof=NDOF4*NUMVERTICES;
+
+	int     i;
+	double  values[numdof];
+	double  vx[NUMVERTICES];
+	double  vy[NUMVERTICES];
+	double  vz[NUMVERTICES];
+	double  vel[NUMVERTICES];
+	double  pressure[NUMVERTICES];
+	double  stokesreconditioning;
+	int*    doflist=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in all arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=values[i*NDOF4+0];
+		vy[i]=values[i*NDOF4+1];
+		vz[i]=values[i*NDOF4+2];
+		pressure[i]=values[i*NDOF4+3];
+	}
+
+	/*Recondition pressure and compute vel: */
+	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
+	for(i=0;i<NUMVERTICES;i++) pressure[i]=pressure[i]*stokesreconditioning;
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+	
+	/*Now, we have to move the previous inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
+	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionAdjointStokes {{{1*/
+void  Penta::InputUpdateFromSolutionAdjointStokes(double* solution){
+
+	const int    numdof=NDOF4*NUMVERTICES;
+
+	int    i;
+	double values[numdof];
+	double lambdax[NUMVERTICES];
+	double lambday[NUMVERTICES];
+	double lambdaz[NUMVERTICES];
+	double lambdap[NUMVERTICES];
+	int*   doflist=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		lambdax[i]=values[i*NDOF4+0];
+		lambday[i]=values[i*NDOF4+1];
+		lambdaz[i]=values[i*NDOF4+2];
+		lambdap[i]=values[i*NDOF4+3];
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
+	this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
+	this->inputs->AddInput(new PentaVertexInput(AdjointzEnum,lambdaz));
+	this->inputs->AddInput(new PentaVertexInput(AdjointpEnum,lambdap));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionAdjointHoriz {{{1*/
+void  Penta::InputUpdateFromSolutionAdjointHoriz(double* solution){
+
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int    i;
+	double values[numdof];
+	double lambdax[NUMVERTICES];
+	double lambday[NUMVERTICES];
+	int*   doflist=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		lambdax[i]=values[i*NDOF2+0];
+		lambday[i]=values[i*NDOF2+1];
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
+	this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionThermal {{{1*/
+void  Penta::InputUpdateFromSolutionThermal(double* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	bool   converged;
+	int    i;
+	double values[numdof];
+	double B[numdof];
+	double B_average;
+	int*   doflist=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	this->inputs->GetParameterValue(&converged,ConvergedEnum);
+	if(converged){
+		this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,values));
+
+		/*Update Rheology only if convreged (we must make sure that the temperature is below melting point
+		 * otherwise the rheology could be negative*/
+		B_average=Paterson((values[0]+values[1]+values[2]+values[3]+values[4]+values[5])/6.0);
+		for(i=0;i<numdof;i++) B[i]=B_average;
+		this->matice->inputs->AddInput(new PentaVertexInput(RheologyBEnum,B));
+	}
+	else{
+		this->inputs->AddInput(new PentaVertexInput(TemporaryTemperatureEnum,values));
+	}
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionOneDof{{{1*/
+void  Penta::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
+
+	const int numdof = NDOF1*NUMVERTICES;
+
+	double values[numdof];
+	int*   doflist=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new PentaVertexInput(enum_type,values));
+	
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionOneDofCollpased{{{1*/
+void  Penta::InputUpdateFromSolutionOneDofCollapsed(double* solution,int enum_type){
+
+	const int  numdof   = NDOF1*NUMVERTICES;
+	const int  numdof2d = NDOF1*NUMVERTICES2D;
+
+	double  values[numdof];
+	int*    doflist = NULL;
+	Penta  *penta   = NULL;
+
+	/*If not on bed, return*/
+	if (!IsOnBed()) return;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector and extrude it */
+	for(int i=0;i<numdof2d;i++){
+		values[i]         =solution[doflist[i]];
+		values[i+numdof2d]=values[i];
+	}
+
+	/*Start looping over all elements above current element and update all inputs*/
+	penta=this;
+	for(;;){
+		/*Add input to the element: */
+		penta->inputs->AddInput(new PentaVertexInput(enum_type,values));
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
+	}
+	
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(double* vector, int name, int type);{{{1*/
+void  Penta::InputUpdateFromVector(double* vector, int name, int type){
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	/*Penta update B in InputUpdateFromSolutionThermal, so don't look for B update here.*/
+
+	switch(type){
+
+		case VertexEnum:
+
+			/*New PentaVertexInpu*/
+			double values[6];
+
+			/*Get values on the 6 vertices*/
+			for (int i=0;i<6;i++){
+				values[i]=vector[this->nodes[i]->GetVertexDof()];
+			}
+
+			/*update input*/
+			this->inputs->AddInput(new PentaVertexInput(name,values));
+			return;
+
+		default:
+
+			ISSMERROR("type %i (%s) not implemented yet",type,EnumToString(type));
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(int* vector, int name, int type);{{{1*/
+void  Penta::InputUpdateFromVector(int* vector, int name, int type){
+	ISSMERROR(" not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(bool* vector, int name, int type);{{{1*/
+void  Penta::InputUpdateFromVector(bool* vector, int name, int type){
+	ISSMERROR(" not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVectorDakota(double* vector, int name, int type);{{{1*/
+void  Penta::InputUpdateFromVectorDakota(double* vector, int name, int type){
+	ISSMERROR(" not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVectorDakota(int* vector, int name, int type);{{{1*/
+void  Penta::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	ISSMERROR(" not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{1*/
+void  Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	ISSMERROR(" not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnBed{{{1*/
+bool Penta::IsOnBed(void){
+
+	bool onbed;
+	inputs->GetParameterValue(&onbed,ElementOnBedEnum);
+	return onbed;
+}
+/*}}}*/
+/*FUNCTION Penta::IsInput{{{1*/
+bool Penta::IsInput(int name){
+	if (
+				name==ThicknessEnum ||
+				name==SurfaceEnum ||
+				name==BedEnum ||
+				name==DtEnum ||
+				name==SurfaceSlopeXEnum ||
+				name==SurfaceSlopeYEnum ||
+				name==MeltingRateEnum ||
+				name==AccumulationRateEnum ||
+				name==GeothermalFluxEnum ||
+				name==SurfaceAreaEnum||
+				name==PressureEnum ||
+				name==VxEnum ||
+				name==VyEnum ||
+				name==VzEnum ||
+				name==VxObsEnum ||
+				name==VyObsEnum ||
+				name==VzObsEnum ||
+				name==TemperatureEnum ||
+				name==CmResponseEnum ||
+				name==DragCoefficientEnum ||
+				name==GradientEnum ||
+				name==OldGradientEnum  ||
+				name==ConvergedEnum
+				) {
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnShelf {{{1*/
+bool   Penta::IsOnShelf(){
+
+	bool onshelf;
+	inputs->GetParameterValue(&onshelf,ElementOnIceShelfEnum);
+	return onshelf;
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnSurface{{{1*/
+bool Penta::IsOnSurface(void){
+
+	bool onsurface;
+	inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
+	return onsurface;
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnWater {{{1*/
+bool   Penta::IsOnWater(){
+
+	bool onwater;
+	inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
+	return onwater;
+}
+/*}}}*/
 /*FUNCTION Penta::MassFlux {{{1*/
 double Penta::MassFlux( double* segment,bool process_units){
@@ -1413,4 +4759,26 @@
 }
 /*}}}*/
+/*FUNCTION Penta::MinEdgeLength{{{1*/
+double Penta::MinEdgeLength(double xyz_list[6][3]){
+	/*Return the minimum lenght of the nine egdes of the penta*/
+
+	int    i,node0,node1;
+	int    edges[9][2]={{0,1},{0,2},{1,2},{3,4},{3,5},{4,5},{0,3},{1,4},{2,5}}; //list of the nine edges
+	double length;
+	double minlength=-1;
+
+	for(i=0;i<9;i++){
+		/*Find the two nodes for this edge*/
+		node0=edges[i][0];
+		node1=edges[i][1];
+
+		/*Compute the length of this edge and compare it to the minimal length*/
+		length=pow(pow(xyz_list[node0][0]-xyz_list[node1][0],2.0)+pow(xyz_list[node0][1]-xyz_list[node1][1],2.0)+pow(xyz_list[node0][2]-xyz_list[node1][2],2.0),0.5);
+		if(length<minlength || minlength<0) minlength=length;
+	}
+
+	return minlength;
+}
+/*}}}*/
 /*FUNCTION Penta::MinVel{{{1*/
 void  Penta::MinVel(double* pminvel, bool process_units){
@@ -1463,4 +4831,517 @@
 	/*Assign output pointers:*/
 	*pminvz=minvz;
+}
+/*}}}*/
+/*FUNCTION Penta::MyRank {{{1*/
+int    Penta::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION Penta::PatchFill{{{1*/
+void  Penta::PatchFill(int* pcount, Patch* patch){
+
+	int i,count;
+	int vertices_ids[6];
+
+	/*recover pointer: */
+	count=*pcount;
+		
+	/*will be needed later: */
+	for(i=0;i<6;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
+
+	for(i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+
+		/*For this result,fill the information in the Patch object (element id + vertices ids), and then hand 
+		 *it to the result object, to fill the rest: */
+		patch->fillelementinfo(count,this->id,vertices_ids,6);
+		elementresult->PatchFill(count,patch);
+
+		/*increment counter: */
+		count++;
+	}
+
+	/*Assign output pointers:*/
+	*pcount=count;
+}/*}}}*/
+/*FUNCTION Penta::PatchSize{{{1*/
+void  Penta::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
+
+	int     i;
+	int     numrows  = 0;
+	int     numnodes = 0;
+
+	/*Go through all the results objects, and update the counters: */
+	for (i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+		/*first, we have one more result: */
+		numrows++;
+		/*now, how many vertices and how many nodal values for this result? :*/
+		numnodes=elementresult->NumberOfNodalValues(); //ask result object.
+	}
+
+	/*Assign output pointers:*/
+	*pnumrows=numrows;
+	*pnumvertices=NUMVERTICES;
+	*pnumnodes=numnodes;
+}
+/*}}}*/
+/*FUNCTION Penta::ProcessResultsUnits{{{1*/
+void  Penta::ProcessResultsUnits(void){
+
+	int i;
+
+	for(i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+		elementresult->ProcessUnits(this->parameters);
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::ReduceMatrixStokes {{{1*/
+void Penta::ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp){
+
+	int    i,j;
+	double Kii[24][24];
+	double Kib[24][3];
+	double Kbb[3][3];
+	double Kbi[3][24];
+	double Kbbinv[3][3];
+	double Kright[24][24];
+
+	/*Create the four matrices used for reduction */
+	for(i=0;i<24;i++){
+		for(j=0;j<24;j++){
+			Kii[i][j]=*(Ke_temp+27*i+j);
+		}
+		for(j=0;j<3;j++){
+			Kib[i][j]=*(Ke_temp+27*i+j+24);
+		}
+	}
+	for(i=0;i<3;i++){
+		for(j=0;j<24;j++){
+			Kbi[i][j]=*(Ke_temp+27*(i+24)+j);
+		}
+		for(j=0;j<3;j++){
+			Kbb[i][j]=*(Ke_temp+27*(i+24)+j+24);
+		}
+	}
+
+	/*Inverse the matrix corresponding to bubble part Kbb */
+	Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
+
+	/*Multiply matrices to create the reduce matrix Ke_reduced */
+	TripleMultiply(&Kib[0][0],24,3,0,
+				&Kbbinv[0][0],3,3,0,
+				&Kbi[0][0],3,24,0,
+				&Kright[0][0],0);
+
+	/*Affect value to the reduced matrix */
+	for(i=0;i<24;i++) for(j=0;j<24;j++) *(Ke_reduced+24*i+j)=Kii[i][j]-Kright[i][j];
+}
+/*}}}*/
+/*FUNCTION Penta::ReduceVectorStokes {{{1*/
+void Penta::ReduceVectorStokes(double* Pe_reduced, double* Ke_temp, double* Pe_temp){
+
+	int    i,j;
+	double Pi[24];
+	double Pb[3];
+	double Kbb[3][3];
+	double Kib[24][3];
+	double Kbbinv[3][3];
+	double Pright[24];
+
+	/*Create the four matrices used for reduction */
+	for(i=0;i<24;i++) Pi[i]=*(Pe_temp+i);
+	for(i=0;i<3;i++) Pb[i]=*(Pe_temp+i+24);
+	for(j=0;j<3;j++){
+		for(i=0;i<24;i++){
+			Kib[i][j]=*(Ke_temp+3*i+j);
+		}
+		for(i=0;i<3;i++){
+			Kbb[i][j]=*(Ke_temp+3*(i+24)+j);
+		}
+	}
+
+	/*Inverse the matrix corresponding to bubble part Kbb */
+	Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
+
+	/*Multiply matrices to create the reduce matrix Ke_reduced */
+	TripleMultiply(&Kib[0][0],24,3,0,
+				&Kbbinv[0][0],3,3,0,
+				&Pb[0],3,1,0,&Pright[0],0);
+
+	/*Affect value to the reduced matrix */
+	for(i=0;i<24;i++) *(Pe_reduced+i)=Pi[i]-Pright[i];
+}
+/*}}}*/
+/*FUNCTION Penta::RegularizeInversion {{{1*/
+double Penta::RegularizeInversion(void){
+
+	double J;
+	Tria* tria=NULL;
+
+	/*recover some inputs: */
+	int  approximation;
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Not MacAyeal and not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute RegularizeInversion*/
+
+		/*Depth Average B*/
+		this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
+
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		J=tria->RegularizeInversion();
+		delete tria->matice; delete tria;
+
+		/*delete B average*/
+		this->matice->inputs->DeleteInput(RheologyBbarEnum);
+
+		return J;
+	}
+	else{
+
+		/*Depth Average B and put it in inputs*/
+		Penta* penta=GetBasalElement();
+		penta->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
+		Input* B_input=penta->matice->inputs->GetInput(RheologyBbarEnum);
+		Input* B_copy=(Input*)B_input->copy();
+		this->matice->inputs->AddInput((Input*)B_copy);
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		J=tria->RegularizeInversion();
+		delete tria->matice; delete tria;
+
+		/*delete B average*/
+		this->matice->inputs->DeleteInput(RheologyBbarEnum);
+		penta->matice->inputs->DeleteInput(RheologyBbarEnum);
+
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SetClone {{{1*/
+void  Penta::SetClone(int* minranks){
+
+	ISSMERROR("not implemented yet");
+}
+/*}}}1*/
+/*FUNCTION Penta::SetCurrentConfiguration {{{1*/
+void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+
+	int analysis_counter;
+
+	/*go into parameters and get the analysis_counter: */
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*Pick up nodes */
+	if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
+	else this->nodes=NULL;
+}
+/*}}}*/
+/*FUNCTION Penta::SpawnTria {{{1*/
+Tria*  Penta::SpawnTria(int g0, int g1, int g2){
+
+	int   i,analysis_counter;
+	int   indices[3];
+	int   zero=0;
+	Tria*       tria            = NULL;
+	Inputs*     tria_inputs     = NULL;
+	Results*    tria_results    = NULL;
+	Parameters* tria_parameters = NULL;
+
+	/*go into parameters and get the analysis_counter: */
+	this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	indices[0]=g0;
+	indices[1]=g1;
+	indices[2]=g2;
+
+	tria_parameters=this->parameters;
+	tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
+	tria_results=(Results*)this->results->SpawnTriaResults(indices);
+
+	tria=new Tria();
+	tria->id=this->id;
+	tria->inputs=tria_inputs;
+	tria->results=tria_results;
+	tria->parameters=tria_parameters;
+	tria->element_type=P1Enum; //Only P1 CG for now (TO BE CHANGED)
+	this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
+
+	/*Spawn matice*/
+	tria->matice=NULL;
+	tria->matice=(Matice*)this->matice->copy();
+	delete tria->matice->inputs;
+	tria->matice->inputs=(Inputs*)this->matice->inputs->SpawnTriaInputs(indices);
+
+	/*recover nodes, matice and matpar: */
+	tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
+	tria->matpar=(Matpar*)tria->hmatpar->delivers();
+
+	return tria;
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceArea {{{1*/
+double Penta::SurfaceArea(void){
+
+	int    approximation;
+	double S;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Non MacAyeal not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute SurfaceArea*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		S=tria->SurfaceArea();
+		delete tria->matice; delete tria;
+		return S;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		S=tria->SurfaceArea();
+		delete tria->matice; delete tria;
+		return S;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceAverageVelMisfit {{{1*/
+double Penta::SurfaceAverageVelMisfit(bool process_units){
+
+	int    approximation;
+	double J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Non MacAyeal and not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute SurfaceAverageVelMisfit*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceAverageVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceAverageVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceAbsVelMisfit {{{1*/
+double Penta::SurfaceAbsVelMisfit(bool process_units){
+
+	int    approximation;
+	double J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Non MacAyeal and not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute SurfaceAbsVelMisfit*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceAbsVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceAbsVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceLogVelMisfit {{{1*/
+double Penta::SurfaceLogVelMisfit(bool process_units){
+
+	int    approximation;
+	double J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Non MacAyeal and not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute SurfaceLogVelMisfit*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceLogVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceLogVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceLogVxVyMisfit {{{1*/
+double Penta::SurfaceLogVxVyMisfit(bool process_units){
+
+	double J;
+	Tria* tria=NULL;
+
+	/*inputs: */
+	int  approximation;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Non MacAyeal and not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute SurfaceLogVxVyMisfit*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceLogVxVyMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceLogVxVyMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceNormal {{{1*/
+void Penta::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
+
+	int    i;
+	double v13[3],v23[3];
+	double normal[3];
+	double normal_norm;
+
+	for (i=0;i<3;i++){
+		v13[i]=xyz_list[0][i]-xyz_list[2][i];
+		v23[i]=xyz_list[1][i]-xyz_list[2][i];
+	}
+
+	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
+	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
+	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
+
+	normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
+
+	*(surface_normal)=normal[0]/normal_norm;
+	*(surface_normal+1)=normal[1]/normal_norm;
+	*(surface_normal+2)=normal[2]/normal_norm;
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceRelVelMisfit {{{1*/
+double Penta::SurfaceRelVelMisfit(bool process_units){
+
+	int    approximation;
+	double J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Bail out if this element if:
+	 * -> Non MacAyeal and not on the surface
+	 * -> MacAyeal (2d model) and not on bed) */
+	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
+		return 0;
+	}
+	else if (approximation==MacAyealApproximationEnum){
+
+		/*This element should be collapsed into a tria element at its base. Create this tria element, 
+		 * and compute SurfaceRelVelMisfit*/
+		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceRelVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceRelVelMisfit(process_units);
+		delete tria->matice; delete tria;
+		return J;
+	}
 }
 /*}}}*/
@@ -1527,304 +5408,4 @@
 	delete tria->matice; delete tria;
 	return J;
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceAbsVelMisfit {{{1*/
-double Penta::SurfaceAbsVelMisfit(bool process_units){
-
-	int    approximation;
-	double J;
-	Tria*  tria=NULL;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Non MacAyeal and not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute SurfaceAbsVelMisfit*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		J=tria->SurfaceAbsVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-	else{
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		J=tria->SurfaceAbsVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceRelVelMisfit {{{1*/
-double Penta::SurfaceRelVelMisfit(bool process_units){
-
-	int    approximation;
-	double J;
-	Tria*  tria=NULL;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Non MacAyeal and not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute SurfaceRelVelMisfit*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		J=tria->SurfaceRelVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-	else{
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		J=tria->SurfaceRelVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceLogVelMisfit {{{1*/
-double Penta::SurfaceLogVelMisfit(bool process_units){
-
-	int    approximation;
-	double J;
-	Tria*  tria=NULL;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Non MacAyeal and not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute SurfaceLogVelMisfit*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		J=tria->SurfaceLogVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-	else{
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		J=tria->SurfaceLogVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceLogVxVyMisfit {{{1*/
-double Penta::SurfaceLogVxVyMisfit(bool process_units){
-
-	double J;
-	Tria* tria=NULL;
-
-	/*inputs: */
-	int  approximation;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Non MacAyeal and not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute SurfaceLogVxVyMisfit*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		J=tria->SurfaceLogVxVyMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-	else{
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		J=tria->SurfaceLogVxVyMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceAverageVelMisfit {{{1*/
-double Penta::SurfaceAverageVelMisfit(bool process_units){
-
-	int    approximation;
-	double J;
-	Tria*  tria=NULL;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Non MacAyeal and not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute SurfaceAverageVelMisfit*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		J=tria->SurfaceAverageVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-	else{
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		J=tria->SurfaceAverageVelMisfit(process_units);
-		delete tria->matice; delete tria;
-		return J;
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::PatchFill{{{1*/
-void  Penta::PatchFill(int* pcount, Patch* patch){
-
-	int i,count;
-	int vertices_ids[6];
-
-	/*recover pointer: */
-	count=*pcount;
-		
-	/*will be needed later: */
-	for(i=0;i<6;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
-
-	for(i=0;i<this->results->Size();i++){
-		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
-
-		/*For this result,fill the information in the Patch object (element id + vertices ids), and then hand 
-		 *it to the result object, to fill the rest: */
-		patch->fillelementinfo(count,this->id,vertices_ids,6);
-		elementresult->PatchFill(count,patch);
-
-		/*increment counter: */
-		count++;
-	}
-
-	/*Assign output pointers:*/
-	*pcount=count;
-}/*}}}*/
-/*FUNCTION Penta::PatchSize{{{1*/
-void  Penta::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
-
-	int     i;
-	int     numrows  = 0;
-	int     numnodes = 0;
-
-	/*Go through all the results objects, and update the counters: */
-	for (i=0;i<this->results->Size();i++){
-		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
-		/*first, we have one more result: */
-		numrows++;
-		/*now, how many vertices and how many nodal values for this result? :*/
-		numnodes=elementresult->NumberOfNodalValues(); //ask result object.
-	}
-
-	/*Assign output pointers:*/
-	*pnumrows=numrows;
-	*pnumvertices=NUMVERTICES;
-	*pnumnodes=numnodes;
-}
-/*}}}*/
-/*FUNCTION Penta::ProcessResultsUnits{{{1*/
-void  Penta::ProcessResultsUnits(void){
-
-	int i;
-
-	for(i=0;i<this->results->Size();i++){
-		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
-		elementresult->ProcessUnits(this->parameters);
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::SetCurrentConfiguration {{{1*/
-void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
-
-	int analysis_counter;
-
-	/*go into parameters and get the analysis_counter: */
-	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
-
-	/*Get Element type*/
-	this->element_type=this->element_type_list[analysis_counter];
-
-	/*Pick up nodes */
-	if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
-	else this->nodes=NULL;
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceArea {{{1*/
-double Penta::SurfaceArea(void){
-
-	int    approximation;
-	double S;
-	Tria*  tria=NULL;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/*Bail out if this element if:
-	 * -> Non MacAyeal not on the surface
-	 * -> MacAyeal (2d model) and not on bed) */
-	if ((approximation!=MacAyealApproximationEnum && !IsOnSurface()) || (approximation==MacAyealApproximationEnum && !IsOnBed())){
-		return 0;
-	}
-	else if (approximation==MacAyealApproximationEnum){
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute SurfaceArea*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		S=tria->SurfaceArea();
-		delete tria->matice; delete tria;
-		return S;
-	}
-	else{
-
-		tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-		S=tria->SurfaceArea();
-		delete tria->matice; delete tria;
-		return S;
-	}
 }
 /*}}}*/
@@ -1980,3587 +5561,2 @@
 }
 /*}}}*/
-
-/*Penta specific routines: */
-/*FUNCTION Penta::BedNormal {{{1*/
-void Penta::BedNormal(double* bed_normal, double xyz_list[3][3]){
-
-	int i;
-	double v13[3],v23[3];
-	double normal[3];
-	double normal_norm;
-
-	for (i=0;i<3;i++){
-		v13[i]=xyz_list[0][i]-xyz_list[2][i];
-		v23[i]=xyz_list[1][i]-xyz_list[2][i];
-	}
-
-	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
-	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
-	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
-	normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
-
-	/*Bed normal is opposite to surface normal*/
-	*(bed_normal)=-normal[0]/normal_norm;
-	*(bed_normal+1)=-normal[1]/normal_norm;
-	*(bed_normal+2)=-normal[2]/normal_norm;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixBalancedthickness {{{1*/
-ElementMatrix* Penta::CreateKMatrixBalancedthickness(void){
-
-	/*Figure out if this penta is collapsed. If so, then bailout, except if it is at the 
-	  bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build 
-	  the stiffness matrix. */
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging Vx and Vy*/
-	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
-	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
-
-	/*Spawn Tria element from the base of the Penta: */
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixBalancedthickness();
-	delete tria->matice; delete tria;
-
-	/*Delete Vx and Vy averaged*/
-	this->inputs->DeleteInput(VxAverageEnum);
-	this->inputs->DeleteInput(VyAverageEnum);
-
-	/*clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixBalancedvelocities {{{1*/
-ElementMatrix* Penta::CreateKMatrixBalancedvelocities(void){
-
-	/*Figure out if this penta is collapsed. If so, then bailout, except if it is at the 
-	  bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build 
-	  the stiffness matrix. */
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging Vx and Vy*/
-	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
-	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
-
-	/*Spawn Tria element from the base of the Penta: */
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixBalancedvelocities();
-	delete tria->matice; delete tria;
-
-	/*Delete Vx and Vy averaged*/
-	this->inputs->DeleteInput(VxAverageEnum);
-	this->inputs->DeleteInput(VyAverageEnum);
-
-	/*clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattyn{{{1*/
-ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattyn(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixCouplingMacAyealPattynViscous();
-	ElementMatrix* Ke2=CreateKMatrixCouplingMacAyealPattynFriction();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynViscous{{{1*/
-ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynViscous(void){
-
-	/*Constants*/
-	const int    numdofm=NDOF2*NUMVERTICES2D;
-	const int    numdofp=NDOF2*NUMVERTICES;
-	const int    numdoftotal=2*NDOF2*NUMVERTICES;
-
-	/*Intermediaries */
-	int         i,j,ig;
-	double      Jdet;
-	double      viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
-	double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
-	double      xyz_list[NUMVERTICES][3];
-	double      B[3][numdofp];
-	double      Bprime[3][numdofm];
-	double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
-	double      D_scalar;
-	double      Ke_gg[numdofp][numdofm]={0.0}; //local element stiffness matrix 
-	double      Ke_gg_gaussian[numdofp][numdofm]; //stiffness matrix evaluated at the gaussian point.
-	GaussPenta *gauss=NULL;
-	GaussTria  *gauss_tria=NULL;
-
-	/*Find penta on bed as pattyn must be coupled to the dofs on the bed: */
-	Penta* pentabase=GetBasalElement();
-	Tria* tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke1=new ElementMatrix(pentabase->nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
-	ElementMatrix* Ke2=new ElementMatrix(this->nodes     ,NUMVERTICES,this->parameters,PattynApproximationEnum);
-	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
-	delete Ke1; delete Ke2;
-
-	/* Get node coordinates and dof list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
-	Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
-	Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(5,5);
-	gauss_tria=new GaussTria();
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-		gauss->SynchronizeGaussTria(gauss_tria);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetBMacAyealPattyn(&B[0][0], &xyz_list[0][0], gauss);
-		tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
-
-		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
-		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
-		matice->GetViscosity3d(&viscosity, &epsilon[0]);
-		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
-
-		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
-		D_scalar=2*newviscosity*gauss->weight*Jdet;
-		for (i=0;i<3;i++) D[i][i]=D_scalar;
-
-		TripleMultiply( &B[0][0],3,numdofp,1,
-					&D[0][0],3,3,0,
-					&Bprime[0][0],3,numdofm,0,
-					&Ke_gg_gaussian[0][0],0);
-
-		for( i=0; i<numdofp; i++) for(j=0;j<numdofm; j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
-	} 
-	for(i=0;i<numdofp;i++) for(j=0;j<numdofm;j++) Ke->values[(i+2*numdofm)*numdoftotal+j]+=Ke_gg[i][j];
-	for(i=0;i<numdofm;i++) for(j=0;j<numdofp;j++) Ke->values[i*numdoftotal+(j+2*numdofm)]+=Ke_gg[j][i];
-
-	/*Clean-up and return*/
-	delete tria->matice; delete tria;
-	delete gauss;
-	delete gauss_tria;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynFriction{{{1*/
-ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynFriction(void){
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
-
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixCouplingMacAyealPattynFriction();
-	delete tria->matice; delete tria;
-
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixCouplingPattynStokes{{{1*/
-ElementMatrix* Penta::CreateKMatrixCouplingPattynStokes(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
-	ElementMatrix* Ke2=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
-	delete Ke1;
-	delete Ke2;
-	Ke1=CreateKMatrixDiagnosticPattyn();
-	Ke2=CreateKMatrixDiagnosticStokes();
-
-	/*Constants*/
-	const int    numdofp=NDOF2*NUMVERTICES;
-	const int    numdofs=NDOF4*NUMVERTICES;
-	const int    numdoftotal=(NDOF2+NDOF4)*NUMVERTICES;
-	int          i,j;
-
-	for(i=0;i<numdofs;i++) for(j=0;j<NUMVERTICES;j++){
-		Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+0]+=Ke2->values[i*numdofs+NDOF4*j+0];
-		Ke->values[(i+numdofp)*numdoftotal+NDOF2*j+1]+=Ke2->values[i*numdofs+NDOF4*j+1];
-	}
-	for(i=0;i<numdofp;i++) for(j=0;j<NUMVERTICES;j++){
-		Ke->values[i*numdoftotal+numdofp+NDOF4*j+0]+=Ke1->values[i*numdofp+NDOF2*j+0];
-		Ke->values[i*numdoftotal+numdofp+NDOF4*j+1]+=Ke1->values[i*numdofp+NDOF2*j+1];
-	}
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticHoriz(void){
-
-	int approximation;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	switch(approximation){
-		case MacAyealApproximationEnum:
-			return CreateKMatrixDiagnosticMacAyeal2d();
-		case PattynApproximationEnum:
-			return CreateKMatrixDiagnosticPattyn();
-		case StokesApproximationEnum:
-			return CreateKMatrixDiagnosticStokes();
-		case HutterApproximationEnum:
-			return NULL;
-		case NoneApproximationEnum:
-			return NULL;
-		case MacAyealPattynApproximationEnum:
-			return CreateKMatrixDiagnosticMacAyealPattyn();
-		case PattynStokesApproximationEnum:
-			return CreateKMatrixDiagnosticPattynStokes();
-		default:
-			ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticHutter(void){
-
-	/*Constants*/
-	const int numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries*/
-	int       connectivity[2];
-	int       i,i0,i1,j0,j1;
-	double    one0,one1;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Spawn 3 beam elements: */
-	for(i=0;i<3;i++){
-		/*2 dofs of first node*/
-		i0=2*i;
-		i1=2*i+1;
-		/*2 dofs of second node*/
-		j0=2*(i+3);
-		j1=2*(i+3)+1;
-
-		/*Find connectivity for the two nodes*/
-		connectivity[0]=nodes[i]->GetConnectivity();
-		connectivity[1]=nodes[i+3]->GetConnectivity();
-		one0=1/(double)connectivity[0];
-		one1=1/(double)connectivity[1];
-
-		/*Create matrix for these two nodes*/
-		if (IsOnBed() && IsOnSurface()){
-			Ke->values[i0*numdof+i0]=one0;
-			Ke->values[i1*numdof+i1]=one0;
-			Ke->values[j0*numdof+i0]=-one1;
-			Ke->values[j0*numdof+j0]=one1;
-			Ke->values[j1*numdof+i1]=-one1;
-			Ke->values[j1*numdof+j1]=one1;
-		}
-		else if (IsOnBed()){
-			Ke->values[i0*numdof+i0]=one0;
-			Ke->values[i1*numdof+i1]=one0;
-			Ke->values[j0*numdof+i0]=-2*one1;
-			Ke->values[j0*numdof+j0]=2*one1;
-			Ke->values[j1*numdof+i1]=-2*one1;
-			Ke->values[j1*numdof+j1]=2*one1;
-		}
-		else if (IsOnSurface()){
-			Ke->values[j0*numdof+i0]=-one1;
-			Ke->values[j0*numdof+j0]=one1;
-			Ke->values[j1*numdof+i1]=-one1;
-			Ke->values[j1*numdof+j1]=one1;
-		}
-		else{ //node is on two horizontal layers and beams include the values only once, so the have to use half of the connectivity
-			Ke->values[j0*numdof+i0]=-2*one1;
-			Ke->values[j0*numdof+j0]=2*one1;
-			Ke->values[j1*numdof+i1]=-2*one1;
-			Ke->values[j1*numdof+j1]=2*one1;
-		}
-	}
-
-	/*Clean up and return*/
-	return Ke;
-}
-/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal2d{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal2d(void){
-	
-	/*Figure out if this penta is collapsed. If so, then bailout, except if it is at the 
-	  bedrock, in which case we spawn a tria element using the 3 first grids, and use it to build 
-	  the stiffness matrix. */
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging B*/
-	this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyeal();
-	delete tria->matice; delete tria;
-
-	/*Delete B averaged*/
-	this->matice->inputs->DeleteInput(RheologyBbarEnum);
-
-	/*clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3d{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3d(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3dViscous();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyeal3dFriction();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dViscous{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dViscous(void){
-
-	/*Constants*/
-	const int    numdof2d=2*NUMVERTICES2D;
-
-	/*Intermediaries */
-	int         i,j,ig;
-	double      Jdet;
-	double      viscosity, oldviscosity, newviscosity, viscosity_overshoot;
-	double      epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
-	double      xyz_list[NUMVERTICES][3];
-	double      B[3][numdof2d];
-	double      Bprime[3][numdof2d];
-	double      D[3][3]={0.0};            // material matrix, simple scalar matrix.
-	double      D_scalar;
-	double      Ke_gg_gaussian[numdof2d][numdof2d]; //stiffness matrix evaluated at the gaussian point.
-	Tria*       tria=NULL;
-	Penta*      pentabase=NULL;
-	GaussPenta *gauss=NULL;
-	GaussTria  *gauss_tria=NULL;
-
-	/*Find penta on bed as this is a macayeal elements: */
-	pentabase=GetBasalElement();
-	tria=pentabase->SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(tria->nodes,NUMVERTICES2D,this->parameters,MacAyealApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes,NUMVERTICES);
-	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
-	Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
-	Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(5,5);
-	gauss_tria=new GaussTria();
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-		gauss->SynchronizeGaussTria(gauss_tria);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		tria->GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss_tria);
-		tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
-
-		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
-		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
-		matice->GetViscosity3d(&viscosity, &epsilon[0]);
-		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
-
-		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
-		D_scalar=2*newviscosity*gauss->weight*Jdet;
-		for (i=0;i<3;i++) D[i][i]=D_scalar;
-
-		TripleMultiply( &B[0][0],3,numdof2d,1,
-					&D[0][0],3,3,0,
-					&Bprime[0][0],3,numdof2d,0,
-					&Ke_gg_gaussian[0][0],0);
-
-		for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof2d+j]+=Ke_gg_gaussian[i][j];
-	}
-
-	/*Clean up and return*/
-	delete tria->matice;
-	delete tria;
-	delete gauss_tria;
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dFriction{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dFriction(void){
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
-
-	/*Build a tria element using the 3 grids of the base of the penta. Then use 
-	 * the tria functionality to build a friction stiffness matrix on these 3
-	 * grids: */
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyealFriction();
-	delete tria->matice; delete tria;
-
-	/*clean-up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyealPattyn{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyealPattyn(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3d();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticPattyn();
-	ElementMatrix* Ke3=CreateKMatrixCouplingMacAyealPattyn();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	delete Ke3;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticPattyn{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticPattyn(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticPattynViscous();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticPattynFriction();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticPattynViscous{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticPattynViscous(void){
-
-	/*Constants*/
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	int        approximation;
-	double     xyz_list[NUMVERTICES][3];
-	double     Jdet;
-	double     viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
-	double     epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
-	double     D_scalar;
-	double     D[5][5]={0.0};            // material matrix, simple scalar matrix.
-	double     B[5][numdof];
-	double     Bprime[5][numdof];
-	double     Ke_gg_gaussian[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
-	Tria*      tria=NULL;
-	GaussPenta *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
-	Input* vxold_input=inputs->GetInput(VxOldEnum); ISSMASSERT(vxold_input);
-	Input* vyold_input=inputs->GetInput(VyOldEnum); ISSMASSERT(vyold_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(5,5);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetBPattyn(&B[0][0], &xyz_list[0][0], gauss);
-		GetBprimePattyn(&Bprime[0][0], &xyz_list[0][0], gauss);
-
-		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
-		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
-		matice->GetViscosity3d(&viscosity, &epsilon[0]);
-		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
-		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
-
-		D_scalar=2*newviscosity*gauss->weight*Jdet;
-		for (i=0;i<5;i++) D[i][i]=D_scalar;
-
-		TripleMultiply( &B[0][0],5,numdof,1,
-					&D[0][0],5,5,0,
-					&Bprime[0][0],5,numdof,0,
-					&Ke_gg_gaussian[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticPattynFriction{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticPattynFriction(void){
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || IsOnShelf() || !IsOnBed()) return NULL;
-
-	/*Build a tria element using the 3 grids of the base of the penta. Then use 
-	 * the tria functionality to build a friction stiffness matrix on these 3
-	 * grids: */
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticPattynFriction();
-	delete tria->matice; delete tria;
-
-	/*clean-up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticPattynStokes{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticPattynStokes(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticPattyn();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticStokes();
-	ElementMatrix* Ke3=CreateKMatrixCouplingPattynStokes();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	delete Ke3;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticStokes{{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticStokes(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticStokesViscous();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticStokesFriction();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticStokesViscous {{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticStokesViscous(void){
-
-	/*Intermediaries */
-	int        i,j,ig,approximation;
-	double     Jdet,viscosity,stokesreconditioning;
-	double     xyz_list[NUMVERTICES][3];
-	double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
-	double     B[8][27];
-	double     B_prime[8][27];
-	double     D_scalar;
-	double     D[8][8]={0.0};
-	double     Ke_temp[27][27]={0.0}; //for the six nodes and the bubble 
-	double     Ke_gaussian[27][27];
-	GaussPenta *gauss=NULL;
-
-	/*If on water or not Stokes, skip stiffness: */
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(IsOnWater() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(5,5);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetBStokes(&B[0][0],&xyz_list[0][0],gauss); 
-		GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0],gauss); 
-
-		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
-		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
-
-		D_scalar=gauss->weight*Jdet;
-		for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
-		for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
-
-		TripleMultiply( &B[0][0],8,27,1,
-					&D[0][0],8,8,0,
-					&B_prime[0][0],8,27,0,
-					&Ke_gaussian[0][0],0);
-
-		for(i=0;i<27;i++) for(j=0;j<27;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
-	}
-
-	/*Condensation*/
-	ReduceMatrixStokes(Ke->values, &Ke_temp[0][0]);
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticStokesFriction {{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticStokesFriction(void){
-
-	/*Constants*/
-	const int numdof=NUMVERTICES*NDOF4;
-	const int numdof2d=NUMVERTICES2D*NDOF4;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	int        analysis_type,approximation;
-	double     stokesreconditioning;
-	double     viscosity,alpha2_gauss,Jdet2d;
-	double	  bed_normal[3];
-	double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
-	double     xyz_list[NUMVERTICES][3];
-	double	  xyz_list_tria[NUMVERTICES2D][3];
-	double     LStokes[14][numdof2d];
-	double     LprimeStokes[14][numdof2d];
-	double     DLStokes[14][14]={0.0};
-	double     Ke_drag_gaussian[numdof2d][numdof2d];
-	Friction*  friction=NULL;
-	GaussPenta *gauss=NULL;
-
-	/*If on water or not Stokes, skip stiffness: */
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(IsOnWater() || IsOnShelf() || !IsOnBed() || (approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum)) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
-	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
-
-	/*build friction object, used later on: */
-	friction=new Friction("3d",inputs,matpar,analysis_type);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(0,1,2,2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
-		GetLStokes(&LStokes[0][0], gauss);
-		GetLprimeStokes(&LprimeStokes[0][0], &xyz_list[0][0], gauss);
-
-		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
-		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
-
-		BedNormal(&bed_normal[0],xyz_list_tria);
-		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
-
-		DLStokes[0][0]=alpha2_gauss*gauss->weight*Jdet2d;
-		DLStokes[1][1]=alpha2_gauss*gauss->weight*Jdet2d;
-		DLStokes[2][2]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
-		DLStokes[3][3]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
-		DLStokes[4][4]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
-		DLStokes[5][5]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
-		DLStokes[6][6]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0];
-		DLStokes[7][7]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1];
-		DLStokes[8][8]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[2];
-		DLStokes[9][9]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0]/2.0;
-		DLStokes[10][10]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1]/2.0;
-		DLStokes[11][11]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[0];
-		DLStokes[12][12]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[1];
-		DLStokes[13][13]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[2];
-
-		TripleMultiply( &LStokes[0][0],14,numdof2d,1,
-					&DLStokes[0][0],14,14,0,
-					&LprimeStokes[0][0],14,numdof2d,0,
-					&Ke_drag_gaussian[0][0],0);
-
-		for(i=0;i<numdof2d;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdof+j]+=Ke_drag_gaussian[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	delete friction;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticVert(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticVertVolume();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticVertSurface();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticVertVolume {{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticVertVolume(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int         i,j,ig;
-	double      Jdet;
-	double      xyz_list[NUMVERTICES][3];
-	double      B[NDOF1][NUMVERTICES];
-	double      Bprime[NDOF1][NUMVERTICES];
-	double      DL_scalar;
-	double      Ke_gg[numdof][numdof]={0.0};
-	GaussPenta  *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(2,2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetBVert(&B[0][0], &xyz_list[0][0], gauss);
-		GetBprimeVert(&Bprime[0][0], &xyz_list[0][0], gauss);
-
-		DL_scalar=gauss->weight*Jdet;
-
-		TripleMultiply( &B[0][0],1,NUMVERTICES,1,
-					&DL_scalar,1,1,0,
-					&Bprime[0][0],1,NUMVERTICES,0,
-					&Ke_gg[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
-	} 
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixDiagnosticVertSurface {{{1*/
-ElementMatrix* Penta::CreateKMatrixDiagnosticVertSurface(void){
-
-	if (!IsOnSurface() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(3,4,5); //nodes 3,4 and 5 are on the surface
-	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticVertSurface();
-	delete tria->matice; delete tria;
-
-	/*clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixMelting {{{1*/
-ElementMatrix* Penta::CreateKMatrixMelting(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixMelting();
-
-	delete tria->matice; delete tria;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixPrognostic {{{1*/
-ElementMatrix* Penta::CreateKMatrixPrognostic(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging Vx and Vy*/
-	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
-	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
-
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixPrognostic();
-	delete tria->matice; delete tria;
-
-	/*Delete Vx and Vy averaged*/
-	this->inputs->DeleteInput(VxAverageEnum);
-	this->inputs->DeleteInput(VyAverageEnum);
-
-	/*clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixSlope {{{1*/
-ElementMatrix* Penta::CreateKMatrixSlope(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementMatrix* Ke=tria->CreateKMatrixSlope();
-	delete tria->matice; delete tria;
-
-	/*clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixThermal {{{1*/
-ElementMatrix* Penta::CreateKMatrixThermal(void){
-
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixThermalVolume();
-	ElementMatrix* Ke2=CreateKMatrixThermalShelf();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixThermalVolume {{{1*/
-ElementMatrix* Penta::CreateKMatrixThermalVolume(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        artdiff;
-	int        i,j,ig,found=0;
-	double     Jdet,u,v,w,epsvel;
-	double     gravity,rho_ice,rho_water;
-	double     heatcapacity,thermalconductivity,dt;
-	double     tau_parameter,diameter;
-	double     xyz_list[NUMVERTICES][3];
-	double     B[3][numdof];
-	double     Bprime[3][numdof];
-	double     B_conduct[3][numdof];
-	double     B_advec[3][numdof];
-	double     B_artdiff[2][numdof];
-	double     Bprime_advec[3][numdof];
-	double     L[numdof];
-	double     dh1dh6[3][6];
-	double     D_scalar_conduct,D_scalar_advec;
-	double     D_scalar_trans,D_scalar_artdiff;
-	double     D[3][3];
-	double     K[2][2]={0.0};
-	double     Ke_gaussian_conduct[numdof][numdof];
-	double     Ke_gaussian_advec[numdof][numdof];
-	double     Ke_gaussian_artdiff[numdof][numdof];
-	double     Ke_gaussian_transient[numdof][numdof];
-	Tria*      tria=NULL;
-	GaussPenta *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	rho_water=matpar->GetRhoWater();
-	rho_ice=matpar->GetRhoIce();
-	gravity=matpar->GetG();
-	heatcapacity=matpar->GetHeatCapacity();
-	thermalconductivity=matpar->GetThermalConductivity();
-	this->inputs->GetParameterValue(&dt,DtEnum);
-	this->parameters->FindParam(&artdiff,ArtDiffEnum);
-	this->parameters->FindParam(&epsvel,EpsVelEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
-	if (artdiff==2) diameter=MinEdgeLength(xyz_list);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(2,2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-
-		/*Conduction: */
-
-		GetBConduct(&B_conduct[0][0],&xyz_list[0][0],gauss); 
-
-		D_scalar_conduct=gauss->weight*Jdet*(thermalconductivity/(rho_ice*heatcapacity));
-		if(dt) D_scalar_conduct=D_scalar_conduct*dt;
-
-		D[0][0]=D_scalar_conduct; D[0][1]=0; D[0][2]=0;
-		D[1][0]=0; D[1][1]=D_scalar_conduct; D[1][2]=0;
-		D[2][0]=0; D[2][1]=0; D[2][2]=D_scalar_conduct;
-
-		TripleMultiply(&B_conduct[0][0],3,numdof,1,
-					&D[0][0],3,3,0,
-					&B_conduct[0][0],3,numdof,0,
-					&Ke_gaussian_conduct[0][0],0);
-
-		/*Advection: */
-
-		GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss); 
-		GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss); 
-
-		vx_input->GetParameterValue(&u, gauss);
-		vy_input->GetParameterValue(&v, gauss);
-		vz_input->GetParameterValue(&w, gauss);
-
-		D_scalar_advec=gauss->weight*Jdet;
-		if(dt) D_scalar_advec=D_scalar_advec*dt;
-
-		D[0][0]=D_scalar_advec*u;D[0][1]=0;         D[0][2]=0;
-		D[1][0]=0;         D[1][1]=D_scalar_advec*v;D[1][2]=0;
-		D[2][0]=0;         D[2][1]=0;         D[2][2]=D_scalar_advec*w;
-
-		TripleMultiply(&B_advec[0][0],3,numdof,1,
-					&D[0][0],3,3,0,
-					&Bprime_advec[0][0],3,numdof,0,
-					&Ke_gaussian_advec[0][0],0);
-
-		/*Transient: */
-
-		if(dt){
-			GetNodalFunctionsP1(&L[0], gauss);
-			D_scalar_trans=gauss->weight*Jdet;
-			D_scalar_trans=D_scalar_trans;
-
-			TripleMultiply(&L[0],numdof,1,0,
-						&D_scalar_trans,1,1,0,
-						&L[0],1,numdof,0,
-						&Ke_gaussian_transient[0][0],0);
-		}
-		else{
-			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_transient[i][j]=0;
-		}
-
-		/*Artifficial diffusivity*/
-
-		if(artdiff==1){
-			/*Build K: */
-			D_scalar_artdiff=gauss->weight*Jdet/(pow(u,2)+pow(v,2)+epsvel);
-			if(dt) D_scalar_artdiff=D_scalar_artdiff*dt;
-			K[0][0]=D_scalar_artdiff*pow(u,2);       K[0][1]=D_scalar_artdiff*fabs(u)*fabs(v);
-			K[1][0]=D_scalar_artdiff*fabs(u)*fabs(v);K[1][1]=D_scalar_artdiff*pow(v,2);
-
-			GetBArtdiff(&B_artdiff[0][0],&xyz_list[0][0],gauss); 
-
-			TripleMultiply(&B_artdiff[0][0],2,numdof,1,
-						&K[0][0],2,2,0,
-						&B_artdiff[0][0],2,numdof,0,
-						&Ke_gaussian_artdiff[0][0],0);
-		}
-		else if(artdiff==2){
-
-			GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
-
-			tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
-
-			for(i=0;i<numdof;i++){
-				for(j=0;j<numdof;j++){
-					Ke_gaussian_artdiff[i][j]=tau_parameter*D_scalar_advec*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i])*(u*dh1dh6[0][j]+v*dh1dh6[1][j]+w*dh1dh6[2][j]);
-				}
-			}
-			if(dt){
-				for(i=0;i<numdof;i++){
-					for(j=0;j<numdof;j++){
-						Ke_gaussian_artdiff[i][j]+=tau_parameter*D_scalar_trans*L[j]*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
-					}
-				}
-			}
-		}
-		else{
-			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gaussian_artdiff[i][j]=0;
-		}
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian_conduct[i][j]+Ke_gaussian_advec[i][j]+Ke_gaussian_transient[i][j]+Ke_gaussian_artdiff[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreateKMatrixThermalShelf {{{1*/
-ElementMatrix* Penta::CreateKMatrixThermalShelf(void){
-
-	if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2);
-	ElementMatrix* Ke=tria->CreateKMatrixThermal();
-	delete tria->matice; delete tria;
-
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorAdjointHoriz{{{1*/
-ElementVector* Penta::CreatePVectorAdjointHoriz(void){
-
-	int approximation;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	switch(approximation){
-		case MacAyealApproximationEnum:
-			return CreatePVectorAdjointMacAyeal();
-		case PattynApproximationEnum:
-			return CreatePVectorAdjointPattyn();
-		case NoneApproximationEnum:
-			return NULL;
-		case StokesApproximationEnum:
-			return CreatePVectorAdjointStokes();
-		default:
-			ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorAdjointMacAyeal{{{1*/
-ElementVector* Penta::CreatePVectorAdjointMacAyeal(){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorAdjointHoriz();
-	delete tria->matice; delete tria;
-
-	/*clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorAdjointPattyn{{{1*/
-ElementVector* Penta::CreatePVectorAdjointPattyn(void){
-
-	if (!IsOnSurface() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-	ElementVector* pe=tria->CreatePVectorAdjointHoriz();
-	delete tria->matice; delete tria;
-
-	/*clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorBalancedthickness {{{1*/
-ElementVector* Penta::CreatePVectorBalancedthickness(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging Vx and Vy*/
-	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
-	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorBalancedthickness();
-	delete tria->matice; delete tria;
-
-	/*Delete Vx and Vy averaged*/
-	this->inputs->DeleteInput(VxAverageEnum);
-	this->inputs->DeleteInput(VyAverageEnum);
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorBalancedvelocities {{{1*/
-ElementVector* Penta::CreatePVectorBalancedvelocities(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging Vx and Vy*/
-	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
-	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorBalancedvelocities();
-	delete tria->matice; delete tria;
-
-	/*Delete Vx and Vy averaged*/
-	this->inputs->DeleteInput(VxAverageEnum);
-	this->inputs->DeleteInput(VyAverageEnum);
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorCouplingPattynStokes {{{1*/
-ElementVector* Penta::CreatePVectorCouplingPattynStokes(void){
-
-	/*compute all load vectors for this element*/
-	ElementVector* pe1=CreatePVectorCouplingPattynStokesViscous();
-	ElementVector* pe2=CreatePVectorCouplingPattynStokesFriction();
-	ElementVector* pe =new ElementVector(pe1,pe2);
-
-	/*clean-up and return*/
-	delete pe1;
-	delete pe2;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorCouplingPattynStokesViscous {{{1*/
-ElementVector* Penta::CreatePVectorCouplingPattynStokesViscous(void){
-
-	/*Constants*/
-	const int   numdof=NUMVERTICES*NDOF4;
-
-	/*Intermediaries */
-	int         i,j,ig;
-	int         approximation;
-	double      viscosity,Jdet;
-	double      stokesreconditioning;
-	double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
-	double      dw[3];
-	double      xyz_list[NUMVERTICES][3];
-	double      l1l6[6]; //for the six nodes of the penta
-	double      dh1dh6[3][6]; //for the six nodes of the penta
-	GaussPenta *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(approximation!=PattynStokesApproximationEnum) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
-	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(5,5);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctionsP1(&l1l6[0], gauss);
-		GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
-
-		vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
-
-		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
-		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
-
-		for(i=0;i<NUMVERTICES;i++){
-			pe->values[i*NDOF4+0]+=-Jdet*gauss->weight*viscosity*dw[0]*dh1dh6[2][i];
-			pe->values[i*NDOF4+1]+=-Jdet*gauss->weight*viscosity*dw[1]*dh1dh6[2][i];
-			pe->values[i*NDOF4+2]+=-Jdet*gauss->weight*viscosity*(dw[0]*dh1dh6[0][i]+dw[1]*dh1dh6[1][i]+2*dw[2]*dh1dh6[2][i]);
-			pe->values[i*NDOF4+3]+=Jdet*gauss->weight*stokesreconditioning*dw[2]*l1l6[i];
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorCouplingPattynStokesFriction{{{1*/
-ElementVector* Penta::CreatePVectorCouplingPattynStokesFriction(void){
-
-	/*Constants*/
-	const int numdof=NUMVERTICES*NDOF4;
-
-	/*Intermediaries*/
-	int         i,j,ig;
-	int         approximation,analysis_type;
-	double      Jdet,Jdet2d;
-	double      stokesreconditioning;
-	double	   bed_normal[3];
-	double      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
-	double      viscosity, w, alpha2_gauss;
-	double      dw[3];
-	double	   xyz_list_tria[NUMVERTICES2D][3];
-	double      xyz_list[NUMVERTICES][3];
-	double      l1l6[6]; //for the six nodes of the penta
-	Tria*       tria=NULL;
-	Friction*   friction=NULL;
-	GaussPenta  *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater() || !IsOnBed() || IsOnShelf()) return NULL;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(approximation!=PattynStokesApproximationEnum) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);               ISSMASSERT(vz_input);
-	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   ISSMASSERT(vzpattyn_input);
-
-	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
-
-	/*build friction object, used later on: */
-	friction=new Friction("3d",inputs,matpar,analysis_type);
-
-	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
-	gauss=new GaussPenta(0,1,2,2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
-		GetNodalFunctionsP1(l1l6, gauss);
-
-		vzpattyn_input->GetParameterValue(&w, gauss);
-		vzpattyn_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
-
-		BedNormal(&bed_normal[0],xyz_list_tria);
-		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
-		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
-		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
-
-		for(i=0;i<NUMVERTICES2D;i++){
-			pe->values[i*NDOF4+0]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[0]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[0])*l1l6[i];
-			pe->values[i*NDOF4+1]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[1]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[1])*l1l6[i];
-			pe->values[i*NDOF4+2]+=Jdet2d*gauss->weight*2*viscosity*(dw[0]*bed_normal[0]+dw[1]*bed_normal[1]+dw[2]*bed_normal[2])*l1l6[i];
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticHoriz{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticHoriz(void){
-
-	int approximation;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	switch(approximation){
-		case MacAyealApproximationEnum:
-			return CreatePVectorDiagnosticMacAyeal();
-		case PattynApproximationEnum:
-			return CreatePVectorDiagnosticPattyn();
-		case HutterApproximationEnum:
-			return NULL;
-		case NoneApproximationEnum:
-			return NULL;
-		case StokesApproximationEnum:
-			return CreatePVectorDiagnosticStokes();
-		case MacAyealPattynApproximationEnum:
-			return CreatePVectorDiagnosticMacAyealPattyn();
-		case PattynStokesApproximationEnum:
-			return CreatePVectorDiagnosticPattynStokes();
-		default:
-			ISSMERROR("Approximation %s not supported yet",EnumToString(approximation));
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticMacAyealPattyn{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticMacAyealPattyn(void){
-
-	/*compute all load vectors for this element*/
-	ElementVector* pe1=CreatePVectorDiagnosticMacAyeal();
-	ElementVector* pe2=CreatePVectorDiagnosticPattyn();
-	ElementVector* pe =new ElementVector(pe1,pe2);
-
-	/*clean-up and return*/
-	delete pe1;
-	delete pe2;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticPattynStokes{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticPattynStokes(void){
-
-	/*compute all load vectors for this element*/
-	ElementVector* pe1=CreatePVectorDiagnosticPattyn();
-	ElementVector* pe2=CreatePVectorDiagnosticStokes();
-	ElementVector* pe3=CreatePVectorCouplingPattynStokes();
-	ElementVector* pe =new ElementVector(pe1,pe2,pe3);
-
-	/*clean-up and return*/
-	delete pe1;
-	delete pe2;
-	delete pe3;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticHutter{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticHutter(void){
-
-	/*Constants*/
-	const int numdofs=NDOF2*NUMVERTICES;
-
-	/*Intermediaries*/
-	int          i,j,k,ig;
-	int          node0,node1;
-	int          connectivity[2];
-	double       Jdet;
-	double       xyz_list[NUMVERTICES][3];
-	double       xyz_list_segment[2][3];
-	double       z_list[NUMVERTICES];
-	double       z_segment[2],slope[2];
-	double       slope2,constant_part;
-	double       rho_ice,gravity,n,B;
-	double       ub,vb,z_g,surface,thickness;
-	GaussPenta*  gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	rho_ice=matpar->GetRhoIce();
-	gravity=matpar->GetG();
-	n=matice->GetN();
-	B=matice->GetB();
-	Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
-	Input* surface_input=inputs->GetInput(SurfaceEnum);      ISSMASSERT(surface_input);
-	Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
-	Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
-	for(i=0;i<NUMVERTICES;i++)z_list[i]=xyz_list[i][2];
-
-	/*Loop on the three segments*/
-	for(i=0;i<3;i++){
-		node0=i;
-		node1=i+3;
-
-		for(j=0;j<3;j++){
-			xyz_list_segment[0][j]=xyz_list[node0][j];
-			xyz_list_segment[1][j]=xyz_list[node1][j];
-		}
-
-		connectivity[0]=nodes[node0]->GetConnectivity();
-		connectivity[1]=nodes[node1]->GetConnectivity();
-
-		/*Loop on the Gauss points: */
-		gauss=new GaussPenta(node0,node1,3);
-		for(ig=gauss->begin();ig<gauss->end();ig++){
-			gauss->GaussPoint(ig);
-
-			slopex_input->GetParameterValue(&slope[0],gauss);
-			slopey_input->GetParameterValue(&slope[1],gauss);
-			surface_input->GetParameterValue(&surface,gauss);
-			thickness_input->GetParameterValue(&thickness,gauss);
-
-			slope2=pow(slope[0],2)+pow(slope[1],2);
-			constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
-
-			PentaRef::GetParameterValue(&z_g,&z_list[0],gauss);
-			GetSegmentJacobianDeterminant(&Jdet,&xyz_list_segment[0][0],gauss);
-
-			if (IsOnSurface()){
-				for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight/(double)connectivity[1];
-			}
-			else{//connectivity is too large, should take only half on it
-				for(j=0;j<NDOF2;j++) pe->values[2*node1+j]+=constant_part*pow((surface-z_g)/B,n)*slope[j]*Jdet*gauss->weight*2/(double)connectivity[1];
-			}
-		}
-		delete gauss;
-
-		//Deal with lower surface
-		if (IsOnBed()){
-			constant_part=-1.58*pow((double)10.0,-(double)10.0)*rho_ice*gravity*thickness;
-			ub=constant_part*slope[0];
-			vb=constant_part*slope[1];
-
-			pe->values[2*node0]+=ub/(double)connectivity[0];
-			pe->values[2*node0+1]+=vb/(double)connectivity[0];
-		}
-	}
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticMacAyeal{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticMacAyeal(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorDiagnosticMacAyeal();
-	delete tria->matice; delete tria;
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticPattyn{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticPattyn(void){
-
-	/*Constants*/
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries*/
-	int         i,j,ig;
-	double      Jdet;
-	double      slope[3]; //do not put 2! this goes into GetParameterDerivativeValue, which addresses slope[3] also!
-	double      driving_stress_baseline,thickness;
-	double      xyz_list[NUMVERTICES][3];
-	double      l1l6[6];
-	GaussPenta  *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
-	Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(2,3);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctionsP1(l1l6, gauss);
-
-		thickness_input->GetParameterValue(&thickness, gauss);
-		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-
-		driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG();
-
-		for(i=0;i<NUMVERTICES;i++) for(j=0;j<NDOF2;j++) pe->values[i*NDOF2+j]+= -driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l6[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticStokes(void){
-
-	/*compute all load vectors for this element*/
-	ElementVector* pe1=CreatePVectorDiagnosticStokesViscous();
-	ElementVector* pe2=CreatePVectorDiagnosticStokesShelf();
-	ElementVector* pe =new ElementVector(pe1,pe2);
-
-	/*clean-up and return*/
-	delete pe1;
-	delete pe2;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticStokesViscous {{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticStokesViscous(void){
-
-	/*Constants*/
-	const int numdofbubble=NDOF4*NUMVERTICES+NDOF3*1;
-
-	/*Intermediaries*/
-	int        i,j,ig;
-	int        approximation;
-	double     Jdet,viscosity;
-	double     gravity,rho_ice,stokesreconditioning;
-	double     xyz_list[NUMVERTICES][3];
-	double     epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
-	double     l1l7[7]; //for the six nodes and the bubble 
-	double     B[8][numdofbubble];
-	double     B_prime[8][numdofbubble];
-	double     B_prime_bubble[8][3];
-	double     D[8][8]={0.0};
-	double     D_scalar;
-	double     Pe_gaussian[numdofbubble]={0.0}; //for the six nodes and the bubble 
-	double     Ke_temp[numdofbubble][3]={0.0}; //for the six nodes and the bubble 
-	double     Ke_gaussian[numdofbubble][3];
-	GaussPenta *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-	rho_ice=matpar->GetRhoIce();
-	gravity=matpar->GetG();
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* vx_input=inputs->GetInput(VxEnum);   ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);   ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);   ISSMASSERT(vz_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(5,5);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetBStokes(&B[0][0],&xyz_list[0][0],gauss); 
-		GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss); 
-		GetNodalFunctionsMINI(&l1l7[0], gauss);
-
-		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
-		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
-
-		for(i=0;i<NUMVERTICES+1;i++){
-			Pe_gaussian[i*NDOF4+2]+=-rho_ice*gravity*Jdet*gauss->weight*l1l7[i];
-		}
-
-		/*Get bubble part of Bprime */
-		for(i=0;i<8;i++) for(j=0;j<3;j++) B_prime_bubble[i][j]=B_prime[i][j+24];
-
-		D_scalar=gauss->weight*Jdet;
-		for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
-		for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
-
-		TripleMultiply(&B[0][0],8,numdofbubble,1,
-					&D[0][0],8,8,0,
-					&B_prime_bubble[0][0],8,3,0,
-					&Ke_gaussian[0][0],0);
-
-		for(i=0;i<numdofbubble;i++) for(j=0;j<NDOF3;j++) Ke_temp[i][j]+=Ke_gaussian[i][j];
-	}
-
-	/*Condensation*/
-	ReduceVectorStokes(pe->values, &Ke_temp[0][0], &Pe_gaussian[0]);
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticStokesShelf{{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticStokesShelf(void){
-
-	/*Intermediaries*/
-	int         i,j,ig;
-	int         approximation;
-	double      gravity,rho_water,bed,water_pressure;
-	double		xyz_list_tria[NUMVERTICES2D][3];
-	double      xyz_list[NUMVERTICES][3];
-	double		bed_normal[3];
-	double      l1l6[6]; //for the six nodes of the penta
-	double      Jdet2d;
-	GaussPenta  *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater() || !IsOnBed() || !IsOnShelf()) return NULL;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(approximation!=StokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	rho_water=matpar->GetRhoWater();
-	gravity=matpar->GetG();
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* bed_input=inputs->GetInput(BedEnum); ISSMASSERT(bed_input);
-
-	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
-
-	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
-	gauss=new GaussPenta(0,1,2,2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
-		GetNodalFunctionsP1(l1l6, gauss);
-
-		bed_input->GetParameterValue(&bed, gauss);
-		BedNormal(&bed_normal[0],xyz_list_tria);
-		water_pressure=gravity*rho_water*bed;
-
-		for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) pe->values[i*NDOF4+j]+=water_pressure*gauss->weight*Jdet2d*l1l6[i]*bed_normal[j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorAdjointStokes{{{1*/
-ElementVector* Penta::CreatePVectorAdjointStokes(void){
-
-	if (!IsOnSurface() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(3,4,5); //grids 3, 4 and 5 make the new tria (upper face).
-	ElementVector* pe=tria->CreatePVectorAdjointStokes();
-	delete tria->matice; delete tria;
-
-	/*clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticVert {{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticVert(void){
-
-	/*compute all load vectors for this element*/
-	ElementVector* pe1=CreatePVectorDiagnosticVertVolume();
-	ElementVector* pe2=CreatePVectorDiagnosticVertBase();
-	ElementVector* pe =new ElementVector(pe1,pe2);
-
-	/*clean-up and return*/
-	delete pe1;
-	delete pe2;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticVertVolume {{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticVertVolume(void){
-
-	/*Constants*/
-	const int  numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries*/
-	int        i,ig;
-	int        approximation;
-	double     Jdet;
-	double     xyz_list[NUMVERTICES][3];
-	double     dudx,dvdy,dwdz;
-	double     du[3],dv[3],dw[3];
-	double     l1l6[6];
-	GaussPenta *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-	Input* vzstokes_input=NULL;
-	if(approximation==PattynStokesApproximationEnum){
-		vzstokes_input=inputs->GetInput(VzStokesEnum); ISSMASSERT(vzstokes_input);
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(2,2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctionsP1(l1l6, gauss);
-
-		vx_input->GetParameterDerivativeValue(&du[0],&xyz_list[0][0],gauss);
-		vy_input->GetParameterDerivativeValue(&dv[0],&xyz_list[0][0],gauss);
-		if(approximation==PattynStokesApproximationEnum){
-			vzstokes_input->GetParameterDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
-			dwdz=dw[2];
-		}
-		else dwdz=0;
-		dudx=du[0];
-		dvdy=dv[1];
-
-		for (i=0;i<numdof;i++) pe->values[i] += (dudx+dvdy+dwdz)*Jdet*gauss->weight*l1l6[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorDiagnosticVertBase {{{1*/
-ElementVector* Penta::CreatePVectorDiagnosticVertBase(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorDiagnosticBaseVert();
-	delete tria->matice; delete tria;
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorMelting {{{1*/
-ElementVector* Penta::CreatePVectorMelting(void){
-	return NULL;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorPrognostic {{{1*/
-ElementVector* Penta::CreatePVectorPrognostic(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Depth Averaging Vx and Vy*/
-	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
-	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorPrognostic();
-	delete tria->matice; delete tria;
-
-	/*Delete Vx and Vy averaged*/
-	this->inputs->DeleteInput(VxAverageEnum);
-	this->inputs->DeleteInput(VyAverageEnum);
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorSlope {{{1*/
-ElementVector* Penta::CreatePVectorSlope(void){
-
-	if (!IsOnBed() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorSlope();
-	delete tria->matice; delete tria;
-
-	/*clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorThermal {{{1*/
-ElementVector* Penta::CreatePVectorThermal(void){
-
-	/*compute all load vectors for this element*/
-	ElementVector* pe1=CreatePVectorThermalVolume();
-	ElementVector* pe2=CreatePVectorThermalSheet();
-	ElementVector* pe3=CreatePVectorThermalShelf();
-	ElementVector* pe =new ElementVector(pe1,pe2,pe3);
-
-	/*clean-up and return*/
-	delete pe1;
-	delete pe2;
-	delete pe3;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorThermalVolume {{{1*/
-ElementVector* Penta::CreatePVectorThermalVolume(void){
-
-	/*Constants*/
-	const int  numdof=NUMVERTICES*NDOF1;
-
-	/*Intermediaries*/
-	int    i,j,ig,found=0;
-	int    friction_type,artdiff;
-	double Jdet,phi,dt;
-	double rho_ice,heatcapacity;
-	double thermalconductivity;
-	double viscosity,temperature;
-	double tau_parameter,diameter;
-	double u,v,w;
-	double scalar_def,scalar_transient;
-	double temperature_list[NUMVERTICES];
-	double xyz_list[NUMVERTICES][3];
-	double L[numdof];
-	double dh1dh6[3][6];
-	double epsilon[6];
-	GaussPenta *gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	rho_ice=matpar->GetRhoIce();
-	heatcapacity=matpar->GetHeatCapacity();
-	thermalconductivity=matpar->GetThermalConductivity();
-	this->inputs->GetParameterValue(&dt,DtEnum);
-	this->parameters->FindParam(&artdiff,ArtDiffEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
-	Input* temperature_input=NULL;
-	if (dt) temperature_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(inputs);
-	if (artdiff==2) diameter=MinEdgeLength(xyz_list);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussPenta(2,3);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctionsP1(&L[0], gauss);
-
-		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
-		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
-		GetPhi(&phi, &epsilon[0], viscosity);
-
-		scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss->weight;
-		if(dt) scalar_def=scalar_def*dt;
-
-		for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
-
-		/* Build transient now */
-		if(dt){
-			temperature_input->GetParameterValue(&temperature, gauss);
-			scalar_transient=temperature*Jdet*gauss->weight;
-			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_transient*L[i];
-		}
-
-		if(artdiff==2){
-			GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],&xyz_list[0][0], gauss);
-
-			vx_input->GetParameterValue(&u, gauss);
-			vy_input->GetParameterValue(&v, gauss);
-			vz_input->GetParameterValue(&w, gauss);
-
-			tau_parameter=GetStabilizationParameter(u,v,w,diameter,rho_ice,heatcapacity,thermalconductivity);
-
-			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_def*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
-			if(dt){
-				for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_transient*(u*dh1dh6[0][i]+v*dh1dh6[1][i]+w*dh1dh6[2][i]);
-			}
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorThermalShelf {{{1*/
-ElementVector* Penta::CreatePVectorThermalShelf(void){
-
-	/* Ice/ocean heat exchange flux on ice shelf base */
-	if (!IsOnBed() || !IsOnShelf() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorThermalShelf();
-	delete tria->matice; delete tria;
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::CreatePVectorThermalSheet {{{1*/
-ElementVector* Penta::CreatePVectorThermalSheet(void){
-
-	/* Geothermal flux on ice sheet base and basal friction */
-	if (!IsOnBed() || IsOnShelf() || IsOnWater()) return NULL;
-
-	/*Call Tria function*/
-	Tria* tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-	ElementVector* pe=tria->CreatePVectorThermalSheet();
-	delete tria->matice; delete tria;
-
-	/*Clean up and return*/
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Penta::GetDofList {{{1*/
-void  Penta::GetDofList(int** pdoflist,int approximation_enum,int setenum){
-
-	int  i,j,count=0;
-	int  numberofdofs=0;
-	int* doflist=NULL;
-
-	/*First, figure out size of doflist: */
-	for(i=0;i<6;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
-
-	/*Allocate: */
-	doflist=(int*)xmalloc(numberofdofs*sizeof(int));
-
-	/*Populate: */
-	count=0;
-	for(i=0;i<6;i++){
-		nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
-		count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
-	}
-
-	/*Assign output pointers:*/
-	*pdoflist=doflist;
-}
-/*}}}*/
-/*FUNCTION Penta::GetDofList1 {{{1*/
-void  Penta::GetDofList1(int* doflist){
-	
-	int i;
-	for(i=0;i<6;i++) doflist[i]=nodes[i]->GetDofList1();
-
-}
-/*}}}*/
-/*FUNCTION Penta::GetSidList{{{1*/
-void  Penta::GetSidList(int* sidlist){
-
-	int i;
-	for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
-
-}
-/*}}}*/
-/*FUNCTION Penta::GetElementType {{{1*/
-int Penta::GetElementType(){
-
-	/*return PentaRef field*/
-	return this->element_type;
-}
-/*}}}*/
-/*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
-void Penta::GetParameterListOnVertices(double* pvalue,int enumtype){
-
-	/*Intermediaries*/
-	double     value[NUMVERTICES];
-	GaussPenta *gauss              = NULL;
-
-	/*Recover input*/
-	Input* input=inputs->GetInput(enumtype);
-	if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
-
-	/*Checks in debugging mode*/
-	ISSMASSERT(pvalue);
-
-	/* Start looping on the number of vertices: */
-	gauss=new GaussPenta();
-	for (int iv=0;iv<NUMVERTICES;iv++){
-		gauss->GaussVertex(iv);
-		input->GetParameterValue(&pvalue[iv],gauss);
-	}
-
-	/*clean-up*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
-void Penta::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
-
-	/*Intermediaries*/
-	double     value[NUMVERTICES];
-	GaussPenta *gauss              = NULL;
-
-	/*Recover input*/
-	Input* input=inputs->GetInput(enumtype);
-
-	/*Checks in debugging mode*/
-	ISSMASSERT(pvalue);
-
-	/* Start looping on the number of vertices: */
-	if (input){
-		gauss=new GaussPenta();
-		for (int iv=0;iv<NUMVERTICES;iv++){
-			gauss->GaussVertex(iv);
-			input->GetParameterValue(&pvalue[iv],gauss);
-		}
-	}
-	else{
-		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
-	}
-
-	/*clean-up*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Penta::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
-void Penta::GetParameterValue(double* pvalue,Node* node,int enumtype){
-
-	Input* input=inputs->GetInput(enumtype);
-	if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
-
-	GaussPenta* gauss=new GaussPenta();
-	gauss->GaussVertex(this->GetNodeIndex(node));
-
-	input->GetParameterValue(pvalue,gauss);
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Penta::GetPhi {{{1*/
-void Penta::GetPhi(double* phi, double*  epsilon, double viscosity){
-	/*Compute deformational heating from epsilon and viscosity */
-
-	double epsilon_matrix[3][3];
-	double epsilon_eff;
-	double epsilon_sqr[3][3];
-
-	/* Build epsilon matrix */
-	epsilon_matrix[0][0]=*(epsilon+0);
-	epsilon_matrix[1][0]=*(epsilon+3);
-	epsilon_matrix[2][0]=*(epsilon+4);
-	epsilon_matrix[0][1]=*(epsilon+3);
-	epsilon_matrix[1][1]=*(epsilon+1);
-	epsilon_matrix[2][1]=*(epsilon+5);
-	epsilon_matrix[0][2]=*(epsilon+4);
-	epsilon_matrix[1][2]=*(epsilon+5);
-	epsilon_matrix[2][2]=*(epsilon+2);
-
-	/* Effective value of epsilon_matrix */
-	epsilon_sqr[0][0]=pow(epsilon_matrix[0][0],2);
-	epsilon_sqr[1][0]=pow(epsilon_matrix[1][0],2);
-	epsilon_sqr[2][0]=pow(epsilon_matrix[2][0],2);
-	epsilon_sqr[0][1]=pow(epsilon_matrix[0][1],2);
-	epsilon_sqr[1][1]=pow(epsilon_matrix[1][1],2);
-	epsilon_sqr[2][1]=pow(epsilon_matrix[2][1],2);
-	epsilon_sqr[0][2]=pow(epsilon_matrix[0][2],2);
-	epsilon_sqr[1][2]=pow(epsilon_matrix[1][2],2);
-	epsilon_sqr[2][2]=pow(epsilon_matrix[2][2],2);
-	epsilon_eff=1/pow(2,0.5)*pow((epsilon_sqr[0][0]+epsilon_sqr[0][1]+ epsilon_sqr[0][2]+ epsilon_sqr[1][0]+ epsilon_sqr[1][1]+ epsilon_sqr[1][2]+ epsilon_sqr[2][0]+ epsilon_sqr[2][1]+ epsilon_sqr[2][2]),0.5);
-
-	/*Phi = Tr(sigma * eps) 
-	 *    = Tr(sigma'* eps)
-	 *    = 2 * eps_eff * sigma'_eff
-	 *    = 4 * eps_eff ^2*/
-	*phi=4*pow(epsilon_eff,2.0)*viscosity;
-}
-/*}}}*/
-/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{1*/
-void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
-
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int          i;
-	int          approximation;
-	int*         doflist=NULL;
-	double       vx,vy;
-	double       values[numdof];
-	GaussPenta*  gauss;
-
-	/*Get approximation enum and dof list: */
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-
-	/*If the element is a coupling, do nothing: every grid is also on an other elements 
-	 * (as coupling is between MacAyeal and Pattyn) so the other element will take care of it*/
-	GetDofList(&doflist,approximation,GsetEnum);
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	/*P1 element only for now*/
-	gauss=new GaussPenta();
-	for(i=0;i<NUMVERTICES;i++){
-
-		/*Recover vx and vy*/
-		gauss->GaussVertex(i);
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		values[i*NDOF2+0]=vx;
-		values[i*NDOF2+1]=vy;
-	}
-
-	/*Add value to global vector*/
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{1*/
-void  Penta::GetSolutionFromInputsDiagnosticHutter(Vec solution){
-
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int          i;
-	int*         doflist=NULL;
-	double       vx,vy;
-	double       values[numdof];
-	GaussPenta*  gauss=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	/*P1 element only for now*/
-	gauss=new GaussPenta();
-	for(i=0;i<NUMVERTICES;i++){
-		/*Recover vx and vy*/
-		gauss->GaussVertex(i);
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		values[i*NDOF2+0]=vx;
-		values[i*NDOF2+1]=vy;
-	}
-
-	/*Add value to global vector*/
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{1*/
-void  Penta::GetSolutionFromInputsDiagnosticVert(Vec solution){
-
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	int          i;
-	int*         doflist=NULL;
-	double       vz;
-	double       values[numdof];
-	GaussPenta*  gauss=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-	Input* vz_input=inputs->GetInput(VzEnum); ISSMASSERT(vz_input);
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	/*P1 element only for now*/
-	gauss=new GaussPenta();
-	for(i=0;i<NUMVERTICES;i++){
-		/*Recover vz */
-		gauss->GaussVertex(i);
-		vz_input->GetParameterValue(&vz,gauss);
-		values[i]=vz;
-	}
-
-	/*Add value to global vector*/
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{1*/
-void  Penta::GetSolutionFromInputsDiagnosticStokes(Vec solution){
-
-	const int    numdof=NDOF4*NUMVERTICES;
-
-	int          i;
-	int*         doflist=NULL;
-	double       vx,vy,vz,p;
-	double       stokesreconditioning;
-	double       values[numdof];
-	GaussPenta   *gauss;
-
-	/*Get dof list: */
-	GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);       ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);       ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);       ISSMASSERT(vz_input);
-	Input* p_input =inputs->GetInput(PressureEnum); ISSMASSERT(p_input);
-
-	/*Recondition pressure: */
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-
-	/*Ok, we have vx vy vz and P in values, fill in vx vy vz P arrays: */
-	/*P1 element only for now*/
-	gauss=new GaussPenta();
-	for(i=0;i<NUMVERTICES;i++){
-		gauss->GaussVertex(i);
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		vz_input->GetParameterValue(&vz,gauss);
-		p_input ->GetParameterValue(&p ,gauss);
-		values[i*NDOF4+0]=vx;
-		values[i*NDOF4+1]=vy;
-		values[i*NDOF4+2]=vz;
-		values[i*NDOF4+3]=p/stokesreconditioning;
-	}
-
-	/*Add value to global vector*/
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::GetSolutionFromInputsThermal{{{1*/
-void  Penta::GetSolutionFromInputsThermal(Vec solution){
-
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	int          i;
-	int*         doflist=NULL;
-	double       values[numdof];
-	double       temp;
-	GaussPenta   *gauss=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-	Input* t_input=inputs->GetInput(TemperatureEnum); ISSMASSERT(t_input);
-
-	gauss=new GaussPenta();
-	for(i=0;i<NUMVERTICES;i++){
-		/*Recover temperature*/
-		gauss->GaussVertex(i);
-		t_input->GetParameterValue(&temp,gauss);
-		values[i]=temp;
-	}
-
-	/*Add value to global vector*/
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-	
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::GetStabilizationParameter {{{1*/
-double Penta::GetStabilizationParameter(double u, double v, double w, double diameter, double rho_ice, double heatcapacity, double thermalconductivity){
-	/*Compute stabilization parameter*/
-
-	double normu;
-	double tau_parameter;
-
-	normu=pow(pow(u,2)+pow(v,2)+pow(w,2),0.5);
-	if(normu*diameter/(3*2*thermalconductivity/(rho_ice*heatcapacity))<1){
-		tau_parameter=pow(diameter,2)/(3*2*2*thermalconductivity/(rho_ice*heatcapacity));
-	}
-	else tau_parameter=diameter/(2*normu);
-
-	return tau_parameter;
-}
-/*}}}*/
-/*FUNCTION Penta::GetStrainRate3dPattyn{{{1*/
-void Penta::GetStrainRate3dPattyn(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input){
-	/*Compute the 3d Blatter/PattynStrain Rate (5 components):
-	 *
-	 * epsilon=[exx eyy exy exz eyz]
-	 *
-	 * with exz=1/2 du/dz
-	 *      eyz=1/2 dv/dz
-	 *
-	 * the contribution of vz is neglected
-	 */
-
-	int i;
-	double epsilonvx[5];
-	double epsilonvy[5];
-
-	/*Check that both inputs have been found*/
-	if (!vx_input || !vy_input){
-		ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
-	}
-
-	/*Get strain rate assuming that epsilon has been allocated*/
-	vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
-	vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
-
-	/*Sum all contributions*/
-	for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
-}
-/*}}}*/
-/*FUNCTION Penta::GetStrainRate3d{{{1*/
-void Penta::GetStrainRate3d(double* epsilon,double* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input, Input* vz_input){
-	/*Compute the 3d Strain Rate (6 components):
-	 *
-	 * epsilon=[exx eyy ezz exy exz eyz]
-	 */
-
-	int i;
-	double epsilonvx[6];
-	double epsilonvy[6];
-	double epsilonvz[6];
-
-	/*Check that both inputs have been found*/
-	if (!vx_input || !vy_input || !vz_input){
-		ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p, vz: %p\n",vx_input,vy_input,vz_input);
-	}
-
-	/*Get strain rate assuming that epsilon has been allocated*/
-	vx_input->GetVxStrainRate3d(epsilonvx,xyz_list,gauss);
-	vy_input->GetVyStrainRate3d(epsilonvy,xyz_list,gauss);
-	vz_input->GetVzStrainRate3d(epsilonvz,xyz_list,gauss);
-
-	/*Sum all contributions*/
-	for(i=0;i<6;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i]+epsilonvz[i];
-}
-/*}}}*/
-/*FUNCTION Penta::GetBasalElement{{{1*/
-Penta* Penta::GetBasalElement(void){
-
-	/*Output*/
-	Penta* penta=NULL;
-
-	/*Go through all elements till the bed is reached*/
-	penta=this;
-	for(;;){
-		/*Stop if we have reached the surface, else, take lower penta*/
-		if (penta->IsOnBed()) break;
-
-		/* get lower Penta*/
-		penta=penta->GetLowerElement();
-		ISSMASSERT(penta->Id()!=this->id);
-	}
-
-	/*return output*/
-	return penta;
-}
-/*}}}*/
-/*FUNCTION Penta::GetLowerElement{{{1*/
-Penta* Penta::GetLowerElement(void){
-
-	Penta* upper_penta=NULL;
-
-	upper_penta=(Penta*)neighbors[0]; //first one (0) under, second one (1) above
-	
-	return upper_penta;
-}
-/*}}}*/
-/*FUNCTION Penta::GetUpperElement{{{1*/
-Penta* Penta::GetUpperElement(void){
-
-	Penta* upper_penta=NULL;
-	
-	upper_penta=(Penta*)neighbors[1]; //first one under, second one above
-
-	return upper_penta;
-}
-/*}}}*/
-/*FUNCTION Penta::GetZcoord {{{1*/
-double Penta::GetZcoord(GaussPenta* gauss){
-
-	int    i;
-	double z;
-	double xyz_list[NUMVERTICES][3];
-	double z_list[NUMVERTICES];
-
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	for(i=0;i<NUMVERTICES;i++) z_list[i]=xyz_list[i][2];
-	PentaRef::GetParameterValue(&z,z_list,gauss);
-
-	return z;
-}
-/*}}}*/
-/*FUNCTION Penta::GradjB {{{1*/
-void  Penta::GradjB(Vec gradient){
-
-	int              i;
-	int              approximation;
-	Tria*            tria           =NULL;
-	TriaVertexInput* triavertexinput=NULL;
-
-	/*If on water, skip: */
-	if(IsOnWater())return;
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	if (approximation==MacAyealApproximationEnum){
-		/*Bail out element if MacAyeal (2d) and not on bed*/
-		if (!IsOnBed()) return;
-
-		/*This element should be collapsed into a tria element at its base. Create this tria element, 
-		 * and compute gardj*/
-
-		/*Depth Average B*/
-		this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
-
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		tria->GradjB(gradient);
-		delete tria->matice; delete tria;
-
-		/*delete B average*/
-		this->matice->inputs->DeleteInput(RheologyBbarEnum);
-	}
-	else{
-		/*Gradient is computed on bed only (Bbar)*/
-		if (!IsOnBed()) return;
-
-		/*Depth Average B*/
-		this->InputDepthAverageAtBase(RheologyBEnum,RheologyBbarEnum,MaterialsEnum);
-
-		/*B is a 2d field, use MacAyeal(2d) gradient even if it is Stokes or Pattyn*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria (lower face).
-		tria->GradjB(gradient);
-		delete tria->matice; delete tria;
-
-		/*delete B average*/
-		this->matice->inputs->DeleteInput(RheologyBbarEnum);
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::GradjDrag {{{1*/
-void  Penta::GradjDrag(Vec gradient){
-
-	int              i,approximation;
-	double           temp_gradient[6]={0,0,0,0,0,0};
-	Tria*            tria=NULL;
-	TriaVertexInput* triavertexinput=NULL;
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*If on water, on shelf or not on bed, skip: */
-	if(IsOnWater()|| IsOnShelf() || !IsOnBed())return;
-
-	if (approximation==MacAyealApproximationEnum || approximation==PattynApproximationEnum){
-		/*MacAyeal or Pattyn*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-		tria->GradjDrag(gradient);
-		delete tria->matice; delete tria;
-	}
-	else if (approximation==StokesApproximationEnum){
-		/*Stokes*/
-		tria=(Tria*)SpawnTria(0,1,2); //grids 0, 1 and 2 make the new tria.
-		tria->GradjDragStokes(gradient);
-		delete tria->matice; delete tria;
-	}
-	else if (approximation==NoneApproximationEnum){
-		return;
-	}
-	else ISSMERROR("approximation %s not supported yet",EnumToString(approximation));
-}
-/*}}}*/
-/*FUNCTION Penta::InputExtrude {{{1*/
-void  Penta::InputExtrude(int enum_type,int object_type){
-
-	Penta *penta          = NULL;
-	Input *original_input = NULL;
-
-	/*Are we on the base, not on the surface?:*/
-	if(IsOnBed()){
-		/*OK, we are on bed. we will follow the steps:
-		 * 1: find input and extrude it.
-		 * 2: follow the upper element until we reach the surface
-		 * 3: for each element, we will add a copy of the extruded input*/
-
-		/*Step1: Extrude the original input: */
-		if (object_type==ElementsEnum)
-		 original_input=(Input*)this->inputs->GetInput(enum_type);
-		else if (object_type==MaterialsEnum)
-		 original_input=(Input*)matice->inputs->GetInput(enum_type);
-		else
-		 ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
-		if(!original_input) ISSMERROR("%s%s"," could not find input with enum:",EnumToString(enum_type));
-		original_input->Extrude();
-
-		/*Stop if there is only one layer of element*/
-		if (this->IsOnSurface()) return;
-
-		/*Step 2: this input has been extruded for this element, now follow the upper element*/
-		penta=this;
-		for(;;){
-
-			/* get upper Penta*/
-			penta=penta->GetUpperElement();
-			ISSMASSERT(penta->Id()!=this->id);
-
-			/*Add input of the basal element to penta->inputs*/
-			Input* copy=NULL;
-			copy=(Input*)original_input->copy();
-			if (object_type==ElementsEnum)
-			 penta->inputs->AddInput((Input*)copy);
-			else if (object_type==MaterialsEnum)
-			 penta->matice->inputs->AddInput((Input*)copy);
-			else
-			 ISSMERROR("object of type %s not supported yet",EnumToString(object_type));
-
-			/*Stop if we have reached the surface*/
-			if (penta->IsOnSurface()) break;
-		}
-	}
-
-	return;
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
-
-	int  approximation;
-
-	/*Recover inputs*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-
-	/*MacAyeal, everything is done by the element on bed*/
-	if (approximation==MacAyealApproximationEnum){
-		if (!IsOnBed()){
-			/*Do nothing. Element on bed will take care of it*/
-			return;
-		}
-		else{
-			InputUpdateFromSolutionDiagnosticMacAyeal(solution);
-			return;
-		}
-	}
-	else if (approximation==PattynApproximationEnum){
-		InputUpdateFromSolutionDiagnosticPattyn(solution);
-	}
-	else if (approximation==PattynStokesApproximationEnum){
-		InputUpdateFromSolutionDiagnosticPattynStokes(solution);
-	}
-	else if (approximation==MacAyealStokesApproximationEnum){
-		InputUpdateFromSolutionDiagnosticMacAyealStokes(solution);
-	}
-	else if (approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
-		InputUpdateFromSolutionDiagnosticStokes(solution);
-	}
-	else if (approximation==MacAyealPattynApproximationEnum){
-		InputUpdateFromSolutionDiagnosticMacAyealPattyn(solution);
-	}
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyeal {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticMacAyeal(double* solution){
-
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int     i,dummy;
-	double  rho_ice,g;
-	double  values[numdof];
-	double  vx[NUMVERTICES];
-	double  vy[NUMVERTICES];
-	double  vz[NUMVERTICES];
-	double  vel[NUMVERTICES];
-	double  pressure[NUMVERTICES];
-	double  surface[NUMVERTICES];
-	double  xyz_list[NUMVERTICES][3];
-	int    *doflist = NULL;
-	double *vz_ptr  = NULL;
-	Penta  *penta   = NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,MacAyealApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays and extrude */
-	for(i=0;i<3;i++){
-		vx[i]  =values[i*NDOF2+0];
-		vy[i]  =values[i*NDOF2+1];
-		vx[i+3]=vx[i];
-		vy[i+3]=vy[i];
-	}
-
-	/*Get parameters fro pressure computation*/
-	rho_ice=matpar->GetRhoIce();
-	g=matpar->GetG();
-
-	/*Start looping over all elements above current element and update all inputs*/
-	penta=this;
-	for(;;){
-
-		/*Get node data: */
-		GetVerticesCoordinates(&xyz_list[0][0],penta->nodes,NUMVERTICES);
-
-		/*Now Compute vel*/
-		Input* vz_input=inputs->GetInput(VzEnum);
-		if (vz_input){
-			if (vz_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
-			vz_input->GetValuesPtr(&vz_ptr,&dummy);
-			for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
-		}
-		else{for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;}
-		for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-		/*Now compute pressure*/
-		GetParameterListOnVertices(&surface[0],SurfaceEnum);
-		for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
-
-		/*Now, we have to move the previous Vx and Vy inputs  to old 
-		 * status, otherwise, we'll wipe them off: */
-		penta->inputs->ChangeEnum(VxEnum,VxOldEnum);
-		penta->inputs->ChangeEnum(VyEnum,VyOldEnum);
-		penta->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-		/*Add vx and vy as inputs to the tria element: */
-		penta->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-		penta->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-		penta->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-		penta->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-		/*Stop if we have reached the surface*/
-		if (penta->IsOnSurface()) break;
-
-		/* get upper Penta*/
-		penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
-	}
-	
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn(double* solution){
-
-	const int    numdof=NDOF2*NUMVERTICES;
-	const int    numdof2d=NDOF2*NUMVERTICES2D;
-
-	int     i,dummy;
-	double  rho_ice,g;
-	double  macayeal_values[numdof];
-	double  pattyn_values[numdof];
-	double  vx[NUMVERTICES];
-	double  vy[NUMVERTICES];
-	double  vz[NUMVERTICES];
-	double  vel[NUMVERTICES];
-	double  pressure[NUMVERTICES];
-	double  surface[NUMVERTICES];
-	double  xyz_list[NUMVERTICES][3];
-	int*    doflistp = NULL;
-	int*    doflistm = NULL;
-	double  *vz_ptr  = NULL;
-	Penta   *penta   = NULL;
-
-	/*OK, we have to add results of this element for pattyn 
-	 * and results from the penta at base for macayeal. Now recover results*/
-	penta=GetBasalElement();
-
-	/*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
-	GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
-	penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
-
-	/*Get node data: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof2d;i++){
-		pattyn_values[i]=solution[doflistp[i]];
-		macayeal_values[i]=solution[doflistm[i]];
-	}
-	for(i=numdof2d;i<numdof;i++){
-		pattyn_values[i]=solution[doflistp[i]];
-		macayeal_values[i]=macayeal_values[i-numdof2d];
-	}
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=macayeal_values[i*NDOF2+0]+pattyn_values[i*NDOF2+0];
-		vy[i]=macayeal_values[i*NDOF2+1]+pattyn_values[i*NDOF2+1];
-	}
-
-	/*Get Vz*/
-	Input* vz_input=inputs->GetInput(VzEnum);
-	if (vz_input){
-		if (vz_input->Enum()!=PentaVertexInputEnum){
-			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
-		}
-		vz_input->GetValuesPtr(&vz_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
-	}
-	else{
-		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
-	 *so the pressure is just the pressure at the z elevation: */
-	rho_ice=matpar->GetRhoIce();
-	g=matpar->GetG();
-	GetParameterListOnVertices(&surface[0],SurfaceEnum);
-	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflistp);
-	xfree((void**)&doflistm);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes(double* solution){
-
-	const int    numdofm=NDOF2*NUMVERTICES;
-	const int    numdofs=NDOF4*NUMVERTICES;
-	const int    numdof2d=NDOF2*NUMVERTICES2D;
-
-	int     i,dummy;
-	double  stokesreconditioning;
-	double  macayeal_values[numdofm];
-	double  stokes_values[numdofs];
-	double  vx[NUMVERTICES];
-	double  vy[NUMVERTICES];
-	double  vz[NUMVERTICES];
-	double  vzmacayeal[NUMVERTICES];
-	double  vzstokes[NUMVERTICES];
-	double  vel[NUMVERTICES];
-	double  pressure[NUMVERTICES];
-	double  xyz_list[NUMVERTICES][3];
-	int*    doflistm        = NULL;
-	int*    doflists        = NULL;
-	double  *vzmacayeal_ptr = NULL;
-	Penta   *penta          = NULL;
-
-	/*OK, we have to add results of this element for macayeal 
-	 * and results from the penta at base for macayeal. Now recover results*/
-	penta=GetBasalElement();
-
-	/*Get dof listof this element (macayeal dofs) and of the penta at base (macayeal dofs): */
-	penta->GetDofList(&doflistm,MacAyealApproximationEnum,GsetEnum);
-	GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-
-	/*Get node data: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof2d;i++){
-		macayeal_values[i]=solution[doflistm[i]];
-		macayeal_values[i+numdof2d]=solution[doflistm[i]];
-	}
-	for(i=0;i<numdofs;i++){
-		stokes_values[i]=solution[doflists[i]];
-	}
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=stokes_values[i*NDOF4+0]+macayeal_values[i*NDOF2+0];
-		vy[i]=stokes_values[i*NDOF4+1]+macayeal_values[i*NDOF2+1];
-		vzstokes[i]=stokes_values[i*NDOF4+2];
-		pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
-	}
-
-	/*Get Vz*/
-	Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);
-	if (vzmacayeal_input){
-		if (vzmacayeal_input->Enum()!=PentaVertexInputEnum){
-			ISSMERROR("Cannot compute Vel as VzMacAyeal is of type %s",EnumToString(vzmacayeal_input->Enum()));
-		}
-		vzmacayeal_input->GetValuesPtr(&vzmacayeal_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vzmacayeal[i]=vzmacayeal_ptr[i];
-	}
-	else{
-		ISSMERROR("Cannot update solution as VzMacAyeal is not present");
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) {
-		vz[i]=vzmacayeal[i]+vzstokes[i];
-		vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-	}
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
-	this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
-	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflistm);
-	xfree((void**)&doflists);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattyn {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticPattyn(double* solution){
-	
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int    i,dummy;
-	double rho_ice,g;
-	double values[numdof];
-	double vx[NUMVERTICES];
-	double vy[NUMVERTICES];
-	double vz[NUMVERTICES];
-	double vel[NUMVERTICES];
-	double pressure[NUMVERTICES];
-	double surface[NUMVERTICES];
-	double xyz_list[NUMVERTICES][3];
-	int*   doflist = NULL;
-	double *vz_ptr = NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,PattynApproximationEnum,GsetEnum);
-
-	/*Get node data: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=values[i*NDOF2+0];
-		vy[i]=values[i*NDOF2+1];
-	}
-
-	/*Get Vz*/
-	Input* vz_input=inputs->GetInput(VzEnum);
-	if (vz_input){
-		if (vz_input->Enum()!=PentaVertexInputEnum){
-			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
-		}
-		vz_input->GetValuesPtr(&vz_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
-	}
-	else{
-		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
-	 *so the pressure is just the pressure at the z elevation: */
-	rho_ice=matpar->GetRhoIce();
-	g=matpar->GetG();
-	GetParameterListOnVertices(&surface[0],SurfaceEnum);
-	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattynStokes {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticPattynStokes(double* solution){
-
-	const int    numdofp=NDOF2*NUMVERTICES;
-	const int    numdofs=NDOF4*NUMVERTICES;
-
-	int    i,dummy;
-	double pattyn_values[numdofp];
-	double stokes_values[numdofs];
-	double vx[NUMVERTICES];
-	double vy[NUMVERTICES];
-	double vz[NUMVERTICES];
-	double vzpattyn[NUMVERTICES];
-	double vzstokes[NUMVERTICES];
-	double vel[NUMVERTICES];
-	double pressure[NUMVERTICES];
-	double xyz_list[NUMVERTICES][3];
-	double stokesreconditioning;
-	int*   doflistp      = NULL;
-	int*   doflists      = NULL;
-	double *vzpattyn_ptr = NULL;
-	Penta  *penta        = NULL;
-
-	/*OK, we have to add results of this element for pattyn 
-	 * and results from the penta at base for macayeal. Now recover results*/
-	penta=GetBasalElement();
-
-	/*Get dof listof this element (pattyn dofs) and of the penta at base (macayeal dofs): */
-	GetDofList(&doflistp,PattynApproximationEnum,GsetEnum);
-	GetDofList(&doflists,StokesApproximationEnum,GsetEnum);
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-
-	/*Get node data: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdofp;i++) pattyn_values[i]=solution[doflistp[i]];
-	for(i=0;i<numdofs;i++) stokes_values[i]=solution[doflists[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=stokes_values[i*NDOF4+0]+pattyn_values[i*NDOF2+0];
-		vy[i]=stokes_values[i*NDOF4+1]+pattyn_values[i*NDOF2+1];
-		vzstokes[i]=stokes_values[i*NDOF4+2];
-		pressure[i]=stokes_values[i*NDOF4+3]*stokesreconditioning;
-	}
-
-	/*Get Vz*/
-	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);
-	if (vzpattyn_input){
-		if (vzpattyn_input->Enum()!=PentaVertexInputEnum){
-			ISSMERROR("Cannot compute Vel as VzPattyn is of type %s",EnumToString(vzpattyn_input->Enum()));
-		}
-		vzpattyn_input->GetValuesPtr(&vzpattyn_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vzpattyn[i]=vzpattyn_ptr[i];
-	}
-	else{
-		ISSMERROR("Cannot update solution as VzPattyn is not present");
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) {
-		vz[i]=vzpattyn[i]+vzstokes[i];
-		vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-	}
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
-	this->inputs->AddInput(new PentaVertexInput(VzStokesEnum,vzstokes));
-	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflistp);
-	xfree((void**)&doflists);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHutter {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticHutter(double* solution){
-	
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int     i,dummy;
-	double  rho_ice,g;
-	double  values[numdof];
-	double  vx[NUMVERTICES];
-	double  vy[NUMVERTICES];
-	double  vz[NUMVERTICES];
-	double  vel[NUMVERTICES];
-	double  pressure[NUMVERTICES];
-	double  surface[NUMVERTICES];
-	double  xyz_list[NUMVERTICES][3];
-	int*    doflist = NULL;
-	double* vz_ptr  = NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Get node data: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=values[i*NDOF2+0];
-		vy[i]=values[i*NDOF2+1];
-	}
-
-	/*Get Vz*/
-	Input* vz_input=inputs->GetInput(VzEnum);
-	if (vz_input){
-		if (vz_input->Enum()!=PentaVertexInputEnum){
-			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
-		}
-		vz_input->GetValuesPtr(&vz_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
-	}
-	else{
-		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
-	 *so the pressure is just the pressure at the z elevation: */
-	rho_ice=matpar->GetRhoIce();
-	g=matpar->GetG();
-	GetParameterListOnVertices(&surface[0],SurfaceEnum);
-	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticVert {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticVert(double* solution){
-
-	const int numdof=NDOF1*NUMVERTICES;
-	
-	int      i,dummy;
-	int      approximation;
-	double   rho_ice,g;
-	double   values[numdof];
-	double   vx[NUMVERTICES];
-	double   vy[NUMVERTICES];
-	double   vz[NUMVERTICES];
-	double   vzmacayeal[NUMVERTICES];
-	double   vzpattyn[NUMVERTICES];
-	double   vzstokes[NUMVERTICES];
-	double   vel[NUMVERTICES];
-	double   pressure[NUMVERTICES];
-	double   surface[NUMVERTICES];
-	double   xyz_list[NUMVERTICES][3];
-	int*     doflist      = NULL;
-	double*  vx_ptr       = NULL;
-	double*  vy_ptr       = NULL;
-	double*  vzstokes_ptr = NULL;
-
-
-	/*Get the approximation and do nothing if the element in Stokes or None*/
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
-		return;
-	}
-
-	/*Get dof list and vertices coordinates: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Use the dof list to index into the solution vector vz: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-	for(i=0;i<NUMVERTICES;i++) vz[i]=values[i*NDOF1+0];
-
-	/*Get Vx and Vy*/
-	Input* vx_input=inputs->GetInput(VxEnum);
-	if (vx_input){
-		if (vx_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vx is of type %s",EnumToString(vx_input->Enum()));
-		vx_input->GetValuesPtr(&vx_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vx[i]=vx_ptr[i];
-	}
-	else for(i=0;i<NUMVERTICES;i++) vx[i]=0.0;
-
-	Input* vy_input=inputs->GetInput(VyEnum);
-	if (vy_input){
-		if (vy_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as Vy is of type %s",EnumToString(vy_input->Enum()));
-		vy_input->GetValuesPtr(&vy_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vy[i]=vy_ptr[i];
-	}
-	else for(i=0;i<NUMVERTICES;i++) vy[i]=0.0;
-
-	/*Do some modifications if we actually have a PattynStokes or MacAyealStokes element*/
-	if(approximation==PattynStokesApproximationEnum){
-		Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
-		if (vzstokes_input){
-			if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
-			vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
-			for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
-		}
-		else ISSMERROR("Cannot compute Vz as VzStokes in not present in PattynStokes element");
-		for(i=0;i<NUMVERTICES;i++){
-			vzpattyn[i]=vz[i];
-			vz[i]=vzpattyn[i]+vzstokes[i];
-		}
-	}
-	else if(approximation==MacAyealStokesApproximationEnum){
-		Input* vzstokes_input=inputs->GetInput(VzStokesEnum);
-		if (vzstokes_input){
-			if (vzstokes_input->Enum()!=PentaVertexInputEnum) ISSMERROR("Cannot compute Vel as VzStokes is of type %s",EnumToString(vy_input->Enum()));
-			vzstokes_input->GetValuesPtr(&vzstokes_ptr,&dummy);
-			for(i=0;i<NUMVERTICES;i++) vzstokes[i]=vzstokes_ptr[i];
-		}
-		else ISSMERROR("Cannot compute Vz as VzStokes in not present in MacAyealStokes element");
-		for(i=0;i<NUMVERTICES;i++){
-			vzmacayeal[i]=vz[i];
-			vz[i]=vzmacayeal[i]+vzstokes[i];
-		}
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 3D, 
-	 *so the pressure is just the pressure at the z elevation: except it this is a PattynStokes element */
-	if(approximation!=PattynStokesApproximationEnum &&  approximation!=MacAyealStokesApproximationEnum){
-		rho_ice=matpar->GetRhoIce();
-		g=matpar->GetG();
-		GetParameterListOnVertices(&surface[0],SurfaceEnum);
-		for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*(surface[i]-xyz_list[i][2]);
-	}
-
-	/*Now, we have to move the previous Vz inputs to old 
-	 * status, otherwise, we'll wipe them off and add the new inputs: */
-	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
-
-	if(approximation!=PattynStokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum){
-		this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-		this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-	}
-	else if(approximation==PattynStokesApproximationEnum){
-		this->inputs->AddInput(new PentaVertexInput(VzPattynEnum,vzpattyn));
-	}
-	else if(approximation==MacAyealStokesApproximationEnum){
-		this->inputs->AddInput(new PentaVertexInput(VzMacAyealEnum,vzpattyn));
-	}
-
-	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
-	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticStokes {{{1*/
-void  Penta::InputUpdateFromSolutionDiagnosticStokes(double* solution){
-	
-	const int numdof=NDOF4*NUMVERTICES;
-
-	int     i;
-	double  values[numdof];
-	double  vx[NUMVERTICES];
-	double  vy[NUMVERTICES];
-	double  vz[NUMVERTICES];
-	double  vel[NUMVERTICES];
-	double  pressure[NUMVERTICES];
-	double  stokesreconditioning;
-	int*    doflist=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in all arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=values[i*NDOF4+0];
-		vy[i]=values[i*NDOF4+1];
-		vz[i]=values[i*NDOF4+2];
-		pressure[i]=values[i*NDOF4+3];
-	}
-
-	/*Recondition pressure and compute vel: */
-	this->parameters->FindParam(&stokesreconditioning,StokesReconditioningEnum);
-	for(i=0;i<NUMVERTICES;i++) pressure[i]=pressure[i]*stokesreconditioning;
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-	
-	/*Now, we have to move the previous inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(VzEnum,VzOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new PentaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new PentaVertexInput(VzEnum,vz));
-	this->inputs->AddInput(new PentaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new PentaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionAdjointStokes {{{1*/
-void  Penta::InputUpdateFromSolutionAdjointStokes(double* solution){
-
-	const int    numdof=NDOF4*NUMVERTICES;
-
-	int    i;
-	double values[numdof];
-	double lambdax[NUMVERTICES];
-	double lambday[NUMVERTICES];
-	double lambdaz[NUMVERTICES];
-	double lambdap[NUMVERTICES];
-	int*   doflist=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		lambdax[i]=values[i*NDOF4+0];
-		lambday[i]=values[i*NDOF4+1];
-		lambdaz[i]=values[i*NDOF4+2];
-		lambdap[i]=values[i*NDOF4+3];
-	}
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
-	this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
-	this->inputs->AddInput(new PentaVertexInput(AdjointzEnum,lambdaz));
-	this->inputs->AddInput(new PentaVertexInput(AdjointpEnum,lambdap));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionAdjointHoriz {{{1*/
-void  Penta::InputUpdateFromSolutionAdjointHoriz(double* solution){
-
-	const int numdof=NDOF2*NUMVERTICES;
-
-	int    i;
-	double values[numdof];
-	double lambdax[NUMVERTICES];
-	double lambday[NUMVERTICES];
-	int*   doflist=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		lambdax[i]=values[i*NDOF2+0];
-		lambday[i]=values[i*NDOF2+1];
-	}
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new PentaVertexInput(AdjointxEnum,lambdax));
-	this->inputs->AddInput(new PentaVertexInput(AdjointyEnum,lambday));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionThermal {{{1*/
-void  Penta::InputUpdateFromSolutionThermal(double* solution){
-
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	bool   converged;
-	int    i;
-	double values[numdof];
-	double B[numdof];
-	double B_average;
-	int*   doflist=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	this->inputs->GetParameterValue(&converged,ConvergedEnum);
-	if(converged){
-		this->inputs->AddInput(new PentaVertexInput(TemperatureEnum,values));
-
-		/*Update Rheology only if convreged (we must make sure that the temperature is below melting point
-		 * otherwise the rheology could be negative*/
-		B_average=Paterson((values[0]+values[1]+values[2]+values[3]+values[4]+values[5])/6.0);
-		for(i=0;i<numdof;i++) B[i]=B_average;
-		this->matice->inputs->AddInput(new PentaVertexInput(RheologyBEnum,B));
-	}
-	else{
-		this->inputs->AddInput(new PentaVertexInput(TemporaryTemperatureEnum,values));
-	}
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionOneDof{{{1*/
-void  Penta::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
-
-	const int numdof = NDOF1*NUMVERTICES;
-
-	double values[numdof];
-	int*   doflist=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Add input to the element: */
-	this->inputs->AddInput(new PentaVertexInput(enum_type,values));
-	
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::InputUpdateFromSolutionOneDofCollpased{{{1*/
-void  Penta::InputUpdateFromSolutionOneDofCollapsed(double* solution,int enum_type){
-
-	const int  numdof   = NDOF1*NUMVERTICES;
-	const int  numdof2d = NDOF1*NUMVERTICES2D;
-
-	double  values[numdof];
-	int*    doflist = NULL;
-	Penta  *penta   = NULL;
-
-	/*If not on bed, return*/
-	if (!IsOnBed()) return;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector and extrude it */
-	for(int i=0;i<numdof2d;i++){
-		values[i]         =solution[doflist[i]];
-		values[i+numdof2d]=values[i];
-	}
-
-	/*Start looping over all elements above current element and update all inputs*/
-	penta=this;
-	for(;;){
-		/*Add input to the element: */
-		penta->inputs->AddInput(new PentaVertexInput(enum_type,values));
-
-		/*Stop if we have reached the surface*/
-		if (penta->IsOnSurface()) break;
-
-		/* get upper Penta*/
-		penta=penta->GetUpperElement(); ISSMASSERT(penta->Id()!=this->id);
-	}
-	
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Penta::IsInput{{{1*/
-bool Penta::IsInput(int name){
-	if (
-				name==ThicknessEnum ||
-				name==SurfaceEnum ||
-				name==BedEnum ||
-				name==DtEnum ||
-				name==SurfaceSlopeXEnum ||
-				name==SurfaceSlopeYEnum ||
-				name==MeltingRateEnum ||
-				name==AccumulationRateEnum ||
-				name==GeothermalFluxEnum ||
-				name==SurfaceAreaEnum||
-				name==PressureEnum ||
-				name==VxEnum ||
-				name==VyEnum ||
-				name==VzEnum ||
-				name==VxObsEnum ||
-				name==VyObsEnum ||
-				name==VzObsEnum ||
-				name==TemperatureEnum ||
-				name==CmResponseEnum ||
-				name==DragCoefficientEnum ||
-				name==GradientEnum ||
-				name==OldGradientEnum  ||
-				name==ConvergedEnum
-				) {
-		return true;
-	}
-	else return false;
-}
-/*}}}*/
-/*FUNCTION Penta::IsOnShelf {{{1*/
-bool   Penta::IsOnShelf(){
-
-	bool onshelf;
-	inputs->GetParameterValue(&onshelf,ElementOnIceShelfEnum);
-	return onshelf;
-}
-/*}}}*/
-/*FUNCTION Penta::IsOnWater {{{1*/
-bool   Penta::IsOnWater(){
-
-	bool onwater;
-	inputs->GetParameterValue(&onwater,ElementOnWaterEnum);
-	return onwater;
-}
-/*}}}*/
-/*FUNCTION Penta::IsOnSurface{{{1*/
-bool Penta::IsOnSurface(void){
-
-	bool onsurface;
-	inputs->GetParameterValue(&onsurface,ElementOnSurfaceEnum);
-	return onsurface;
-}
-/*}}}*/
-/*FUNCTION Penta::IsOnBed{{{1*/
-bool Penta::IsOnBed(void){
-
-	bool onbed;
-	inputs->GetParameterValue(&onbed,ElementOnBedEnum);
-	return onbed;
-}
-/*}}}*/
-/*FUNCTION Penta::MinEdgeLength{{{1*/
-double Penta::MinEdgeLength(double xyz_list[6][3]){
-	/*Return the minimum lenght of the nine egdes of the penta*/
-
-	int    i,node0,node1;
-	int    edges[9][2]={{0,1},{0,2},{1,2},{3,4},{3,5},{4,5},{0,3},{1,4},{2,5}}; //list of the nine edges
-	double length;
-	double minlength=-1;
-	
-	for(i=0;i<9;i++){
-		/*Find the two nodes for this edge*/
-		node0=edges[i][0];
-		node1=edges[i][1];
-
-		/*Compute the length of this edge and compare it to the minimal length*/
-		length=pow(pow(xyz_list[node0][0]-xyz_list[node1][0],2.0)+pow(xyz_list[node0][1]-xyz_list[node1][1],2.0)+pow(xyz_list[node0][2]-xyz_list[node1][2],2.0),0.5);
-		if(length<minlength || minlength<0) minlength=length;
-	}
-
-	return minlength;
-}
-/*}}}*/
-/*FUNCTION Penta::ReduceMatrixStokes {{{1*/
-void Penta::ReduceMatrixStokes(double* Ke_reduced, double* Ke_temp){
-
-	int    i,j;
-	double Kii[24][24];
-	double Kib[24][3];
-	double Kbb[3][3];
-	double Kbi[3][24];
-	double Kbbinv[3][3];
-	double Kright[24][24];
-
-	/*Create the four matrices used for reduction */
-	for(i=0;i<24;i++){
-		for(j=0;j<24;j++){
-			Kii[i][j]=*(Ke_temp+27*i+j);
-		}
-		for(j=0;j<3;j++){
-			Kib[i][j]=*(Ke_temp+27*i+j+24);
-		}
-	}
-	for(i=0;i<3;i++){
-		for(j=0;j<24;j++){
-			Kbi[i][j]=*(Ke_temp+27*(i+24)+j);
-		}
-		for(j=0;j<3;j++){
-			Kbb[i][j]=*(Ke_temp+27*(i+24)+j+24);
-		}
-	}
-
-	/*Inverse the matrix corresponding to bubble part Kbb */
-	Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
-
-	/*Multiply matrices to create the reduce matrix Ke_reduced */
-	TripleMultiply(&Kib[0][0],24,3,0,
-				&Kbbinv[0][0],3,3,0,
-				&Kbi[0][0],3,24,0,
-				&Kright[0][0],0);
-
-	/*Affect value to the reduced matrix */
-	for(i=0;i<24;i++) for(j=0;j<24;j++) *(Ke_reduced+24*i+j)=Kii[i][j]-Kright[i][j];
-}
-/*}}}*/
-/*FUNCTION Penta::ReduceVectorStokes {{{1*/
-void Penta::ReduceVectorStokes(double* Pe_reduced, double* Ke_temp, double* Pe_temp){
-
-	int    i,j;
-	double Pi[24];
-	double Pb[3];
-	double Kbb[3][3];
-	double Kib[24][3];
-	double Kbbinv[3][3];
-	double Pright[24];
-
-	/*Create the four matrices used for reduction */
-	for(i=0;i<24;i++) Pi[i]=*(Pe_temp+i);
-	for(i=0;i<3;i++) Pb[i]=*(Pe_temp+i+24);
-	for(j=0;j<3;j++){
-		for(i=0;i<24;i++){
-			Kib[i][j]=*(Ke_temp+3*i+j);
-		}
-		for(i=0;i<3;i++){
-			Kbb[i][j]=*(Ke_temp+3*(i+24)+j);
-		}
-	}
-
-	/*Inverse the matrix corresponding to bubble part Kbb */
-	Matrix3x3Invert(&Kbbinv[0][0], &Kbb[0][0]);
-
-	/*Multiply matrices to create the reduce matrix Ke_reduced */
-	TripleMultiply(&Kib[0][0],24,3,0,
-				&Kbbinv[0][0],3,3,0,
-				&Pb[0],3,1,0,&Pright[0],0);
-
-	/*Affect value to the reduced matrix */
-	for(i=0;i<24;i++) *(Pe_reduced+i)=Pi[i]-Pright[i];
-}
-/*}}}*/
-/*FUNCTION Penta::SetClone {{{1*/
-void  Penta::SetClone(int* minranks){
-
-	ISSMERROR("not implemented yet");
-}
-/*}}}1*/
-/*FUNCTION Penta::SpawnTria {{{1*/
-Tria*  Penta::SpawnTria(int g0, int g1, int g2){
-
-	int   i,analysis_counter;
-	int   indices[3];
-	int   zero=0;
-	Tria*       tria            = NULL;
-	Inputs*     tria_inputs     = NULL;
-	Results*    tria_results    = NULL;
-	Parameters* tria_parameters = NULL;
-	
-	/*go into parameters and get the analysis_counter: */
-	this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
-
-	indices[0]=g0;
-	indices[1]=g1;
-	indices[2]=g2;
-
-	tria_parameters=this->parameters;
-	tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
-	tria_results=(Results*)this->results->SpawnTriaResults(indices);
-	
-	tria=new Tria();
-	tria->id=this->id;
-	tria->inputs=tria_inputs;
-	tria->results=tria_results;
-	tria->parameters=tria_parameters;
-	tria->element_type=P1Enum; //Only P1 CG for now (TO BE CHANGED)
-	this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
-
-	/*Spawn matice*/
-	tria->matice=NULL;
-	tria->matice=(Matice*)this->matice->copy();
-	delete tria->matice->inputs;
-	tria->matice->inputs=(Inputs*)this->matice->inputs->SpawnTriaInputs(indices);
-
-	/*recover nodes, matice and matpar: */
-	tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
-	tria->matpar=(Matpar*)tria->hmatpar->delivers();
-	
-	return tria;
-}
-/*}}}*/
-/*FUNCTION Penta::SurfaceNormal {{{1*/
-void Penta::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
-
-	int    i;
-	double v13[3],v23[3];
-	double normal[3];
-	double normal_norm;
-
-	for (i=0;i<3;i++){
-		v13[i]=xyz_list[0][i]-xyz_list[2][i];
-		v23[i]=xyz_list[1][i]-xyz_list[2][i];
-	}
-
-	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
-	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
-	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
-
-	normal_norm=sqrt( pow(normal[0],2)+pow(normal[1],2)+pow(normal[2],2) );
-
-	*(surface_normal)=normal[0]/normal_norm;
-	*(surface_normal+1)=normal[1]/normal_norm;
-	*(surface_normal+2)=normal[2]/normal_norm;
-}
-/*}}}*/
Index: /issm/trunk/src/c/objects/Elements/Tria.cpp
===================================================================
--- /issm/trunk/src/c/objects/Elements/Tria.cpp	(revision 6409)
+++ /issm/trunk/src/c/objects/Elements/Tria.cpp	(revision 6410)
@@ -26,5 +26,5 @@
 #define NDOF4 4
 
-/*Tria constructors and destructor*/
+/*Constructors/destructor/copy*/
 /*FUNCTION Tria::Tria(){{{1*/
 Tria::Tria(){
@@ -67,6 +67,4 @@
 }
 /*}}}*/
-
-/*Object virtual functions definitions:*/
 /*FUNCTION Tria::copy {{{1*/
 Object* Tria::copy() {
@@ -104,5 +102,5 @@
 	/*point parameters: */
 	tria->parameters=this->parameters;
-	
+
 	/*recover objects: */
 	tria->nodes=(Node**)xmalloc(3*sizeof(Node*)); //we cannot rely on an analysis_counter to tell us which analysis_type we are running, so we just copy the nodes.
@@ -114,129 +112,6 @@
 }
 /*}}}*/
-/*FUNCTION Tria::DeepEcho{{{1*/
-void Tria::DeepEcho(void){
-
-	printf("Tria:\n");
-	printf("   id: %i\n",id);
-	if(nodes){
-		nodes[0]->DeepEcho();
-		nodes[1]->DeepEcho();
-		nodes[2]->DeepEcho();
-	}
-	else printf("nodes = NULL\n");
-
-	if (matice) matice->DeepEcho();
-	else printf("matice = NULL\n");
-
-	if (matpar) matpar->DeepEcho();
-	else printf("matpar = NULL\n");
-
-	printf("   parameters\n");
-	if (parameters) parameters->DeepEcho();
-	else printf("parameters = NULL\n");
-
-	printf("   inputs\n");
-	if (inputs) inputs->DeepEcho();
-	else printf("inputs=NULL\n");
-
-	if (results) results->DeepEcho();
-	else printf("results=NULL\n");
-	
-	return;
-}
-/*}}}*/
-/*FUNCTION Tria::Demarshall {{{1*/
-void  Tria::Demarshall(char** pmarshalled_dataset){
-
-	char* marshalled_dataset=NULL;
-	int i;
-	int flaghook;
-
-	/*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(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
-
-	/*demarshall Ref: */
-	this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
-	for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
-
-	/*allocate dynamic memory: */
-	this->hnodes=new Hook*[this->numanalyses];
-	/*demarshall hooks: */
-	for(i=0;i<numanalyses;i++){
-		memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
-		if(flaghook){ // there is a hook so demarshall it
-			hnodes[i]=new Hook();
-			hnodes[i]->Demarshall(&marshalled_dataset);
-		}
-		else hnodes[i]=NULL; //There is no hook so it is NULL
-	}
-	hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
-	hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
-
-	/*pointers are garbabe, until configuration is carried out: */
-	nodes=NULL;
-	matice=NULL;
-	matpar=NULL;
-	
-	/*demarshall inputs: */
-	inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset); 
-	results=(Results*)DataSetDemarshallRaw(&marshalled_dataset); 
-
-	/*parameters: may not exist even yet, so let Configure handle it: */
-	this->parameters=NULL;
-
-	/*return: */
-	*pmarshalled_dataset=marshalled_dataset;
-	return;
-}
-/*}}}*/
-/*FUNCTION Tria::Echo{{{1*/
-void Tria::Echo(void){
-	printf("Tria:\n");
-	printf("   id: %i\n",id);
-	if(nodes){
-		nodes[0]->Echo();
-		nodes[1]->Echo();
-		nodes[2]->Echo();
-	}
-	else printf("nodes = NULL\n");
-
-	if (matice) matice->Echo();
-	else printf("matice = NULL\n");
-
-	if (matpar) matpar->Echo();
-	else printf("matpar = NULL\n");
-
-	printf("   parameters\n");
-	if (parameters) parameters->Echo();
-	else printf("parameters = NULL\n");
-
-	printf("   inputs\n");
-	if (inputs) inputs->Echo();
-	else printf("inputs=NULL\n");
-
-	if (results) results->Echo();
-	else printf("results=NULL\n");
-}
-/*}}}*/
-/*FUNCTION Tria::Enum {{{1*/
-int Tria::Enum(void){
-
-	return TriaEnum;
-
-}
-/*}}}*/
-/*FUNCTION Tria::Id {{{1*/
-int    Tria::Id(){
-	
-	return id;
-
-}
-/*}}}*/
+
+/*Marshall*/
 /*FUNCTION Tria::Marshall {{{1*/
 void  Tria::Marshall(char** pmarshalled_dataset){
@@ -269,5 +144,5 @@
 	}
 
- /*Marshall hooks: */
+	/*Marshall hooks: */
 	for(i=0;i<numanalyses;i++){
 		if(hnodes[i]){
@@ -319,22 +194,3298 @@
 
 	return sizeof(id)
-		+hnodes_size
-		+sizeof(numanalyses)
-		+numanalyses*sizeof(int) //element_type_lists
-		+hmatice->MarshallSize()
-		+hmatpar->MarshallSize()
-		+inputs->MarshallSize()
-		+results->MarshallSize()
-		+sizeof(int); //sizeof(int) for enum type
-}
-/*}}}*/
-/*FUNCTION Tria::MyRank {{{1*/
-int    Tria::MyRank(void){ 
-	extern int my_rank;
-	return my_rank; 
-}
-/*}}}*/
-
-/*Update virtual functions definitions: */
+	  +hnodes_size
+	  +sizeof(numanalyses)
+	  +numanalyses*sizeof(int) //element_type_lists
+	  +hmatice->MarshallSize()
+	  +hmatpar->MarshallSize()
+	  +inputs->MarshallSize()
+	  +results->MarshallSize()
+	  +sizeof(int); //sizeof(int) for enum type
+}
+/*}}}*/
+/*FUNCTION Tria::Demarshall {{{1*/
+void  Tria::Demarshall(char** pmarshalled_dataset){
+
+	char* marshalled_dataset=NULL;
+	int i;
+	int flaghook;
+
+	/*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(&numanalyses,marshalled_dataset,sizeof(numanalyses));marshalled_dataset+=sizeof(numanalyses);
+
+	/*demarshall Ref: */
+	this->element_type_list=(int*)xmalloc(this->numanalyses*sizeof(int));
+	for(i=0;i<numanalyses;i++){ memcpy(&element_type_list[i],marshalled_dataset,sizeof(int));marshalled_dataset+=sizeof(int);}
+
+	/*allocate dynamic memory: */
+	this->hnodes=new Hook*[this->numanalyses];
+	/*demarshall hooks: */
+	for(i=0;i<numanalyses;i++){
+		memcpy(&flaghook,marshalled_dataset,sizeof(flaghook));marshalled_dataset+=sizeof(flaghook);
+		if(flaghook){ // there is a hook so demarshall it
+			hnodes[i]=new Hook();
+			hnodes[i]->Demarshall(&marshalled_dataset);
+		}
+		else hnodes[i]=NULL; //There is no hook so it is NULL
+	}
+	hmatice=new Hook(); hmatice->Demarshall(&marshalled_dataset);
+	hmatpar=new Hook(); hmatpar->Demarshall(&marshalled_dataset);
+
+	/*pointers are garbabe, until configuration is carried out: */
+	nodes=NULL;
+	matice=NULL;
+	matpar=NULL;
+	
+	/*demarshall inputs: */
+	inputs=(Inputs*)DataSetDemarshallRaw(&marshalled_dataset); 
+	results=(Results*)DataSetDemarshallRaw(&marshalled_dataset); 
+
+	/*parameters: may not exist even yet, so let Configure handle it: */
+	this->parameters=NULL;
+
+	/*return: */
+	*pmarshalled_dataset=marshalled_dataset;
+	return;
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION Tria::AverageOntoPartition {{{1*/
+void  Tria::AverageOntoPartition(Vec partition_contributions,Vec partition_areas,double* vertex_response,double* qmu_part){
+
+	bool      already=false;
+	int       i,j;
+	int       partition[NUMVERTICES];
+	int       offsetsid[NUMVERTICES];
+	int       offsetdof[NUMVERTICES];
+	double    area;
+	double    mean;
+	double    values[3];
+
+	/*First, get the area: */
+	area=this->GetArea();
+
+	/*Figure out the average for this element: */
+	this->GetSidList(&offsetsid[0]);
+	this->GetDofList1(&offsetdof[0]);
+	mean=0;
+	for(i=0;i<NUMVERTICES;i++){
+		partition[i]=(int)qmu_part[offsetsid[i]];
+		mean=mean+1.0/NUMVERTICES*vertex_response[offsetdof[i]];
+	}
+
+	/*Add contribution: */
+	for(i=0;i<NUMVERTICES;i++){
+		already=false;
+		for(j=0;j<i;j++){
+			if (partition[i]==partition[j]){
+				already=true;
+				break;
+			}
+		}
+		if(!already){
+			VecSetValue(partition_contributions,partition[i],mean*area,ADD_VALUES);
+			VecSetValue(partition_areas,partition[i],area,ADD_VALUES);
+		};
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrix {{{1*/
+void  Tria::CreateKMatrix(Mat Kgg, Mat Kff, Mat Kfs){
+
+	/*retreive parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging mode{{{2*/
+	ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticMacAyeal();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticHutter();
+			break;
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			Ke=CreateKMatrixSlope();
+			break;
+		case PrognosticAnalysisEnum:
+			Ke=CreateKMatrixPrognostic();
+			break;
+		case BalancedthicknessAnalysisEnum:
+			Ke=CreateKMatrixBalancedthickness();
+			break;
+		case AdjointBalancedthicknessAnalysisEnum:
+			Ke=CreateKMatrixAdjointBalancedthickness();
+			break;
+		case BalancedvelocitiesAnalysisEnum:
+			Ke=CreateKMatrixBalancedvelocities();
+			break;
+		default:
+			ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Kgg,Kff,Kfs);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixAdjointBalancedthickness {{{1*/
+ElementMatrix* Tria::CreateKMatrixAdjointBalancedthickness(void){
+
+	ElementMatrix* Ke=NULL;
+
+	/*Get Element Matrix of the forward model*/
+	switch(GetElementType()){
+		case P1Enum:
+			Ke=CreateKMatrixBalancedthickness_CG();
+			break;
+		case P1DGEnum:
+			Ke=CreateKMatrixBalancedthickness_DG();
+			break;
+		default:
+			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
+	}
+
+	/*Transpose and return Ke*/
+	Ke->Transpose();
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixBalancedthickness {{{1*/
+ElementMatrix* Tria::CreateKMatrixBalancedthickness(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreateKMatrixBalancedthickness_CG();
+		case P1DGEnum:
+			return CreateKMatrixBalancedthickness_DG();
+		default:
+			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixBalancedthickness_CG {{{1*/
+ElementMatrix* Tria::CreateKMatrixBalancedthickness_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        artdiff;
+	int        i,j,ig,dim;
+	double     Jdettria ,vx,vy,dvxdx,dvydy;
+	double     dvx[2],dvy[2];
+	double     xyz_list[NUMVERTICES][3];
+	double     L[NUMVERTICES];
+	double     B[2][NUMVERTICES];
+	double     Bprime[2][NUMVERTICES];
+	double     K[2][2]                          = {0.0};
+	double     KDL[2][2]                        = {0.0};
+	double     DL[2][2]                         = {0.0};
+	double     DLprime[2][2]                    = {0.0};
+	double     DL_scalar;
+	double     Ke_gg_gaussian[numdof][numdof]   = {0.0};
+	double     Ke_gg_thickness1[numdof][numdof] = {0.0};
+	double     Ke_gg_thickness2[numdof][numdof] = {0.0};
+	GaussTria *gauss                            = NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all Inputs and parameters: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&artdiff,ArtDiffEnum);
+	this->parameters->FindParam(&dim,DimEnum);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
+	}
+
+	/*Create Artificial diffusivity once for all if requested*/
+	if(artdiff){
+		gauss=new GaussTria();
+		gauss->GaussCenter();
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		delete gauss;
+
+		vxaverage_input->GetParameterAverage(&vx);
+		vyaverage_input->GetParameterAverage(&vy);
+		K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(vx);
+		K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(vy);
+	}
+
+	/*Start looping on the number of gaussian points:*/
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		vxaverage_input->GetParameterValue(&vx,gauss);
+		vyaverage_input->GetParameterValue(&vy,gauss);
+		vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+
+		dvxdx=dvx[0];
+		dvydy=dvy[1];
+		DL_scalar=gauss->weight*Jdettria;
+
+		DL[0][0]=DL_scalar*dvxdx;
+		DL[1][1]=DL_scalar*dvydy;
+
+		DLprime[0][0]=DL_scalar*vx;
+		DLprime[1][1]=DL_scalar*vy;
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&B[0][0],2,numdof,0,
+					&Ke_gg_thickness1[0][0],0);
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DLprime[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke_gg_thickness2[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
+
+		if(artdiff){
+			KDL[0][0]=DL_scalar*K[0][0];
+			KDL[1][1]=DL_scalar*K[1][1];
+
+			TripleMultiply( &Bprime[0][0],2,numdof,1,
+						&KDL[0][0],2,2,0,
+						&Bprime[0][0],2,numdof,0,
+						&Ke_gg_gaussian[0][0],0);
+
+			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixBalancedthickness_DG {{{1*/
+ElementMatrix* Tria::CreateKMatrixBalancedthickness_DG(void){
+
+	/*Constants*/
+	const int  numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,j,ig,dim;
+	double     vx,vy,Jdettria;
+	double     xyz_list[NUMVERTICES][3];
+	double     B[2][NUMVERTICES];
+	double     Bprime[2][NUMVERTICES];
+	double     DL[2][2]={0.0};
+	double     DL_scalar;
+	double     Ke_gg[numdof][numdof]={0.0};
+	GaussTria  *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&dim,DimEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+
+	/*Start looping on the number of gaussian points:*/
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		/*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
+		GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
+
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+
+		DL_scalar=-gauss->weight*Jdettria;
+		DL[0][0]=DL_scalar*vx;
+		DL[1][1]=DL_scalar*vy;
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke_gg[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixBalancedvelocities {{{1*/
+ElementMatrix* Tria::CreateKMatrixBalancedvelocities(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int     artdiff;
+	int     i,j,ig,dim;
+	double  nx,ny,norm,Jdettria;
+	double  dvx[2],dvy[2];
+	double  vx,vy,dvxdx,dvydy;
+	double  v_gauss[2]={0.0};
+	double  surface_normal[3];
+	double  surface_list[3];
+	double  xyz_list[NUMVERTICES][3];
+	double  B[2][NUMVERTICES];
+	double  Bprime[2][NUMVERTICES];
+	double  K[2][2]={0.0};
+	double  KDL[2][2]={0.0};
+	double  DLprime[2][2]={0.0};
+	double  DL_scalar;
+	double  Ke_gg_gaussian[numdof][numdof]   = {0.0}; 
+	double  Ke_gg_velocities[numdof][numdof] = {0.0}; 
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&artdiff,ArtDiffEnum);
+	this->parameters->FindParam(&dim,DimEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
+	}
+
+	/*Modify z so that it reflects the surface*/
+	GetParameterListOnVertices(&surface_list[0],SurfaceEnum);
+	for(i=0;i<NUMVERTICES;i++) xyz_list[i][2]=surface_list[i];
+
+	/*Get normal vector to the surface*/
+	vxaverage_input->GetParameterAverage(&nx);
+	vyaverage_input->GetParameterAverage(&ny);
+	if(nx==0 && ny==0){
+		SurfaceNormal(&surface_normal[0],xyz_list);
+		nx=surface_normal[0];
+		ny=surface_normal[1];
+	}
+	if(nx==0 && ny==0){
+		nx=0; ny=1;
+	}
+	norm=pow( pow(nx,2)+pow(ny,2) , (double).5);
+	nx=nx/norm; ny=ny/norm;
+
+	//Create Artificial diffusivity once for all if requested
+	if(artdiff){
+		gauss=new GaussTria();
+		gauss->GaussCenter();
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		delete gauss;
+
+		vxaverage_input->GetParameterAverage(&v_gauss[0]);
+		vyaverage_input->GetParameterAverage(&v_gauss[1]);
+		K[0][0]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]); //pow should be zero!!
+		K[1][1]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		vxaverage_input->GetParameterValue(&vx,gauss);
+		vyaverage_input->GetParameterValue(&vy,gauss);
+		vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+
+		dvxdx=dvx[0];
+		dvydy=dvy[1];
+		DL_scalar=gauss->weight*Jdettria;
+
+		DLprime[0][0]=DL_scalar*nx;
+		DLprime[1][1]=DL_scalar*ny;
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DLprime[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke_gg_velocities[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_velocities[i][j];
+
+		if(artdiff){
+			KDL[0][0]=DL_scalar*K[0][0];
+			KDL[1][1]=DL_scalar*K[1][1];
+
+			TripleMultiply( &Bprime[0][0],2,numdof,1,
+						&KDL[0][0],2,2,0,
+						&Bprime[0][0],2,numdof,0,
+						&Ke_gg_gaussian[0][0],0);
+
+			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyeal {{{1*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyeal(void){
+	
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyealViscous();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyealFriction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealViscous{{{1*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealViscous(void){
+
+	/*Constants*/
+	const int  numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,j,ig;
+	double     xyz_list[NUMVERTICES][3];
+	double     viscosity,newviscosity,oldviscosity;
+	double     viscosity_overshoot,thickness,Jdet;
+	double     epsilon[3],oldepsilon[3];    /* epsilon=[exx,eyy,exy];    */
+	double     B[3][numdof];
+	double     Bprime[3][numdof];
+	double     D[3][3]   = {0.0};
+	double     D_scalar;
+	double     Ke_g[numdof][numdof];
+	GaussTria *gauss = NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
+	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
+	Input* vxold_input=inputs->GetInput(VxOldEnum);         ISSMASSERT(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyOldEnum);         ISSMASSERT(vyold_input);
+	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate2d(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity2d(&viscosity, &epsilon[0]);
+		matice->GetViscosity2d(&oldviscosity, &oldepsilon[0]);
+		thickness_input->GetParameterValue(&thickness, gauss);
+
+		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+		D_scalar=2*newviscosity*thickness*gauss->weight*Jdet;
+		for (i=0;i<3;i++) D[i][i]=D_scalar;
+
+		TripleMultiply(&B[0][0],3,numdof,1,
+					&D[0][0],3,3,0,
+					&Bprime[0][0],3,numdof,0,
+					&Ke_g[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealFriction {{{1*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealFriction(void){
+
+	/*Constants*/
+	const int  numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,j,ig;
+	int        analysis_type,drag_type;
+	double     MAXSLOPE  = .06; // 6 %
+	double     MOUNTAINKEXPONENT = 10;
+	double     slope_magnitude,alpha2;
+	double     Jdet;
+	double     L[2][numdof];
+	double     DL[2][2]  = {{ 0,0 },{0,0}};
+	double     Ke_g[numdof][numdof];
+	double     DL_scalar;
+	double     slope[2]  = {0.0,0.0};
+	double     xyz_list[NUMVERTICES][3];
+	Friction  *friction = NULL;
+	GaussTria *gauss    = NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || IsOnShelf()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
+	Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*build friction object, used later on: */
+	if (drag_type!=2) ISSMERROR(" non-viscous friction not supported yet!");
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
+		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
+		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
+		if(slope_magnitude>MAXSLOPE) alpha2=pow((double)10,MOUNTAINKEXPONENT);
+		else friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
+
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		DL_scalar=alpha2*gauss->weight*Jdet;
+		for (i=0;i<2;i++) DL[i][i]=DL_scalar;
+		
+		TripleMultiply( &L[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&L[0][0],2,numdof,0,
+					&Ke_g[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j]; 
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixCouplingMacAyealPattynFriction {{{1*/
+ElementMatrix* Tria::CreateKMatrixCouplingMacAyealPattynFriction(void){
+
+	/*Constants*/
+	const int numdof        = NDOF2 *NUMVERTICES;
+	const int numdoftotal   = NDOF4 *NUMVERTICES;
+	
+	/*Intermediaries */
+	int       i,j,ig,analysis_type,drag_type;
+	double    Jdet,slope_magnitude,alpha2;
+	double    xyz_list[NUMVERTICES][3];
+	double    slope[2]={0.0,0.0};
+	double    MAXSLOPE=.06; // 6 %
+	double    MOUNTAINKEXPONENT=10;
+	double    L[2][numdof];
+	double    DL[2][2]                  ={{ 0,0 },{0,0}}; //for basal drag
+	double    DL_scalar;
+	double    Ke_gg[numdof][numdof]     ={0.0};
+	double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
+	Friction  *friction = NULL;
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || IsOnShelf()) return NULL;
+	ElementMatrix* Ke1=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+	ElementMatrix* Ke2=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
+	delete Ke1; delete Ke2;
+
+	/*retrieve inputs :*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
+	Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
+
+	/*build friction object, used later on: */
+	if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/*Friction: */
+		friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
+
+		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
+		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
+		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
+
+		if (slope_magnitude>MAXSLOPE){
+			alpha2=pow((double)10,MOUNTAINKEXPONENT);
+		}
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get L matrix: */
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
+
+		
+		DL_scalar=alpha2*gauss->weight*Jdet;
+		for (i=0;i<2;i++){
+			DL[i][i]=DL_scalar;
+		}
+		
+		/*  Do the triple producte tL*D*L: */
+		TripleMultiply( &L[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&L[0][0],2,numdof,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
+	}
+
+	for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdoftotal+(numdof+j)]+=Ke_gg[i][j];
+	for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[(i+numdof)*numdoftotal+j]+=Ke_gg[i][j];
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}	
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticPattynFriction {{{1*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticPattynFriction(void){
+
+	/*Constants*/
+	const int numdof   = NDOF2*NUMVERTICES;
+	
+	/*Intermediaries */
+	int       i,j,ig;
+	int       analysis_type,drag_type;
+	double    xyz_list[NUMVERTICES][3];
+	double    slope_magnitude,alpha2,Jdet;
+	double    slope[2]={0.0,0.0};
+	double    MAXSLOPE=.06; // 6 %
+	double    MOUNTAINKEXPONENT=10;
+	double    L[2][numdof];
+	double    DL[2][2]={{ 0,0 },{0,0}}; //for basal drag
+	double    DL_scalar;
+	double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
+	Friction  *friction = NULL;
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || IsOnShelf()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
+	Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
+
+	/*build friction object, used later on: */
+	if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
+
+		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum); // TO UNCOMMENT
+		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
+
+		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
+		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
+		if (slope_magnitude>MAXSLOPE){
+			alpha2=pow((double)10,MOUNTAINKEXPONENT);
+		}
+		
+		DL_scalar=alpha2*gauss->weight*Jdet;
+		for (i=0;i<2;i++) DL[i][i]=DL_scalar;
+		
+		TripleMultiply( &L[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&L[0][0],2,numdof,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}	
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticHutter{{{1*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticHutter(void){
+
+	/*Intermediaries*/
+	const int numdof=NUMVERTICES*NDOF2;
+	int    i,connectivity;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Create Element matrix*/
+	for(i=0;i<NUMVERTICES;i++){
+		connectivity=nodes[i]->GetConnectivity();
+		Ke->values[(2*i)*numdof  +(2*i)  ]=1/(double)connectivity;
+		Ke->values[(2*i+1)*numdof+(2*i+1)]=1/(double)connectivity;
+	}
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticVertSurface {{{1*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticVertSurface(void){
+
+	/*Constants*/
+	const int numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int       i,j,ig;
+	double    xyz_list[NUMVERTICES][3];
+	double    surface_normal[3];
+	double    Jdet,DL_scalar;
+	double    L[3];
+	GaussTria *gauss=NULL;
+	double Ke_g[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	SurfaceNormal(&surface_normal[0],xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		/**********************Do not forget the sign**********************************/
+		DL_scalar=- gauss->weight*Jdet*surface_normal[2]; 
+		/******************************************************************************/
+
+		TripleMultiply( L,1,3,1,
+					&DL_scalar,1,1,0,
+					L,1,3,0,
+					&Ke_g[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixMelting {{{1*/
+ElementMatrix* Tria::CreateKMatrixMelting(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	double     heatcapacity,latentheat;
+	double     Jdet,D_scalar;
+	double     xyz_list[NUMVERTICES][3];
+	double     L[3];
+	double     Ke_gaussian[numdof][numdof]={0.0};
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	latentheat=matpar->GetLatentHeat();
+	heatcapacity=matpar->GetHeatCapacity();
+
+	/* Start looping on the number of gauss  (nodes on the bedrock) */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
+
+		D_scalar=latentheat/heatcapacity*gauss->weight*Jdet;
+
+		TripleMultiply(&L[0],numdof,1,0,
+					&D_scalar,1,1,0,
+					&L[0],1,numdof,0,
+					&Ke_gaussian[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixPrognostic {{{1*/
+ElementMatrix* Tria::CreateKMatrixPrognostic(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreateKMatrixPrognostic_CG();
+		case P1DGEnum:
+			return CreateKMatrixPrognostic_DG();
+		default:
+			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixPrognostic_CG {{{1*/
+ElementMatrix* Tria::CreateKMatrixPrognostic_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        artdiff;
+	int        i,j,ig,dim;
+	double     Jdettria,DL_scalar,dt;
+	double     vx,vy,dvxdx,dvydy;
+	double     dvx[2],dvy[2];
+	double     v_gauss[2]={0.0};
+	double     xyz_list[NUMVERTICES][3];
+	double     L[NUMVERTICES];
+	double     B[2][NUMVERTICES];
+	double     Bprime[2][NUMVERTICES];
+	double     K[2][2]                        ={0.0};
+	double     KDL[2][2]                      ={0.0};
+	double     DL[2][2]                        ={0.0};
+	double     DLprime[2][2]                   ={0.0};
+	double     Ke_gg_gaussian[numdof][numdof]  ={0.0};
+	double     Ke_gg_thickness1[numdof][numdof]={0.0};
+	double     Ke_gg_thickness2[numdof][numdof]={0.0};
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->inputs->GetParameterValue(&dt,DtEnum);
+	this->parameters->FindParam(&dim,DimEnum);
+	this->parameters->FindParam(&artdiff,ArtDiffEnum);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
+	}
+
+	//Create Artificial diffusivity once for all if requested
+	if(artdiff){
+		gauss=new GaussTria();
+		gauss->GaussCenter();
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		delete gauss;
+
+		vxaverage_input->GetParameterAverage(&v_gauss[0]);
+		vyaverage_input->GetParameterAverage(&v_gauss[1]);
+
+		K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]);
+		K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		vxaverage_input->GetParameterValue(&vx,gauss);
+		vyaverage_input->GetParameterValue(&vy,gauss);
+		vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+
+		DL_scalar=gauss->weight*Jdettria;
+
+		TripleMultiply( &L[0],1,numdof,1,
+					&DL_scalar,1,1,0,
+					&L[0],1,numdof,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		dvxdx=dvx[0];
+		dvydy=dvy[1];
+		DL_scalar=dt*gauss->weight*Jdettria;
+
+		DL[0][0]=DL_scalar*dvxdx;
+		DL[1][1]=DL_scalar*dvydy;
+		DLprime[0][0]=DL_scalar*vx;
+		DLprime[1][1]=DL_scalar*vy;
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&B[0][0],2,numdof,0,
+					&Ke_gg_thickness1[0][0],0);
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DLprime[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke_gg_thickness2[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
+
+		if(artdiff){
+			KDL[0][0]=DL_scalar*K[0][0];
+			KDL[1][1]=DL_scalar*K[1][1];
+
+			TripleMultiply( &Bprime[0][0],2,numdof,1,
+						&KDL[0][0],2,2,0,
+						&Bprime[0][0],2,numdof,0,
+						&Ke_gg_gaussian[0][0],0);
+
+			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixPrognostic_DG {{{1*/
+ElementMatrix* Tria::CreateKMatrixPrognostic_DG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig,dim;
+	double     xyz_list[NUMVERTICES][3];
+	double     Jdettria,dt,vx,vy;
+	double     L[NUMVERTICES];
+	double     B[2][NUMVERTICES];
+	double     Bprime[2][NUMVERTICES];
+	double     DL[2][2]={0.0};
+	double     DLprime[2][2]={0.0};
+	double     DL_scalar;
+	double     Ke_gg1[numdof][numdof]={0.0};
+	double     Ke_gg2[numdof][numdof]={0.0};
+	GaussTria  *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->inputs->GetParameterValue(&dt,DtEnum);
+	this->parameters->FindParam(&dim,DimEnum);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		vxaverage_input->GetParameterValue(&vx,gauss);
+		vyaverage_input->GetParameterValue(&vy,gauss);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		DL_scalar=gauss->weight*Jdettria;
+
+		TripleMultiply( &L[0],1,numdof,1,
+					&DL_scalar,1,1,0,
+					&L[0],1,numdof,0,
+					&Ke_gg1[0][0],0);
+
+		/*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
+		GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
+
+		DL_scalar=-dt*gauss->weight*Jdettria;
+
+		DLprime[0][0]=DL_scalar*vx;
+		DLprime[1][1]=DL_scalar*vy;
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DLprime[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke_gg2[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg1[i][j];
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg2[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixSlope {{{1*/
+ElementMatrix* Tria::CreateKMatrixSlope(void){
+
+	/*constants: */
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/* Intermediaries */
+	int        i,j,ig;
+	double     DL_scalar,Jdet;
+	double     xyz_list[NUMVERTICES][3];
+	double     L[1][3];
+	double     Ke_g[numdof][numdof];
+	GaussTria *gauss = NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	GetVerticesCoordinates(&xyz_list[0][0],nodes,NUMVERTICES);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		DL_scalar=gauss->weight*Jdet;
+
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF1);
+
+		TripleMultiply(&L[0][0],1,3,1,
+					&DL_scalar,1,1,0,
+					&L[0][0],1,3,0,
+					&Ke_g[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixThermal {{{1*/
+ElementMatrix* Tria::CreateKMatrixThermal(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int       i,j,ig;
+	double    mixed_layer_capacity,thermal_exchange_velocity;
+	double    rho_ice,rho_water,heatcapacity;
+	double    Jdet,dt;
+	double    xyz_list[NUMVERTICES][3];
+	double    l1l2l3[NUMVERTICES];
+	double    D_scalar;
+	double    Ke_gaussian[numdof][numdof]={0.0};
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsOnWater() || !IsOnShelf()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->inputs->GetParameterValue(&dt,DtEnum);
+	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
+	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+
+	/* Start looping on the number of gauss (nodes on the bedrock) */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		
+		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
+		GetNodalFunctions(&l1l2l3[0], gauss);
+				
+		D_scalar=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity/(heatcapacity*rho_ice);
+		if(dt) D_scalar=dt*D_scalar;
+
+		TripleMultiply(&l1l2l3[0],numdof,1,0,
+					&D_scalar,1,1,0,
+					&l1l2l3[0],1,numdof,0,
+					&Ke_gaussian[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
+	}
+	
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVector {{{1*/
+void  Tria::CreatePVector(Vec pg, Vec pf){
+
+	/*retrive parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*asserts: {{{*/
+	/*if debugging mode, check that all pointers exist*/
+	ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Just branch to the correct load generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		case DiagnosticHorizAnalysisEnum:
+			pe=CreatePVectorDiagnosticMacAyeal();
+			break;
+		case AdjointHorizAnalysisEnum:
+			pe=CreatePVectorAdjointHoriz();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			pe=CreatePVectorDiagnosticHutter();
+			break;
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			pe=CreatePVectorSlope();
+			break;
+		case PrognosticAnalysisEnum:
+			pe=CreatePVectorPrognostic();
+			break;
+		case BalancedthicknessAnalysisEnum:
+			pe=CreatePVectorBalancedthickness();
+			break;
+		case AdjointBalancedthicknessAnalysisEnum:
+			pe=CreatePVectorAdjointBalancedthickness();
+			break;
+		case BalancedvelocitiesAnalysisEnum:
+			pe=CreatePVectorBalancedvelocities();
+			break;
+		default:
+			ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
+	}
+
+	/*Add to global Vector*/
+	if(pe){
+		pe->AddToGlobal(pg,pf);
+		delete pe;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancedthickness{{{1*/
+ElementVector* Tria::CreatePVectorBalancedthickness(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreatePVectorBalancedthickness_CG();
+			break;
+		case P1DGEnum:
+			return CreatePVectorBalancedthickness_DG();
+		default:
+			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancedthickness_CG{{{1*/
+ElementVector* Tria::CreatePVectorBalancedthickness_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+	
+	/*Intermediaries */
+	int        i,j,ig;
+	double     xyz_list[NUMVERTICES][3];
+	double     dhdt_g,melting_g,accumulation_g,Jdettria;
+	double     L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
+	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
+	Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
+	
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		accumulation_input->GetParameterValue(&accumulation_g,gauss);
+		melting_input->GetParameterValue(&melting_g,gauss);
+		dhdt_input->GetParameterValue(&dhdt_g,gauss);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancedthickness_DG {{{1*/
+ElementVector* Tria::CreatePVectorBalancedthickness_DG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	double     xyz_list[NUMVERTICES][3];
+	double     melting_g,accumulation_g,dhdt_g,Jdettria;
+	double     L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
+	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
+	Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		accumulation_input->GetParameterValue(&accumulation_g,gauss);
+		melting_input->GetParameterValue(&melting_g,gauss);
+		dhdt_input->GetParameterValue(&dhdt_g,gauss);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancedvelocities {{{1*/
+ElementVector* Tria::CreatePVectorBalancedvelocities(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	double     xyz_list[NUMVERTICES][3];
+	double     Jdettria,accumulation_g,melting_g;
+	double     L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
+	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		accumulation_input->GetParameterValue(&accumulation_g,gauss);
+		melting_input->GetParameterValue(&melting_g,gauss);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g)*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorDiagnosticBaseVert {{{1*/
+ElementVector* Tria::CreatePVectorDiagnosticBaseVert(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	int        approximation;
+	double     xyz_list[NUMVERTICES][3];
+	double     Jdet;
+	double     vx,vy,vz,dbdx,dbdy,meltingvalue;
+	double     slope[2];
+	double     L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	inputs->GetParameterValue(&approximation,ApproximationEnum);
+	Input* bed_input=inputs->GetInput(BedEnum);             ISSMASSERT(bed_input);
+	Input* melting_input=inputs->GetInput(MeltingRateEnum); ISSMASSERT(melting_input);
+	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
+	Input* vzstokes_input=NULL;
+	if(approximation==PattynStokesApproximationEnum){
+		vzstokes_input=inputs->GetInput(VzStokesEnum);       ISSMASSERT(vzstokes_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		melting_input->GetParameterValue(&meltingvalue, gauss);
+		bed_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		vx_input->GetParameterValue(&vx, gauss);
+		vy_input->GetParameterValue(&vy, gauss);
+		if(approximation==PattynStokesApproximationEnum){
+			vzstokes_input->GetParameterValue(&vz, gauss);
+		}
+		else vz=0;
+
+		dbdx=slope[0];
+		dbdy=slope[1];
+
+		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=-Jdet*gauss->weight*(vx*dbdx+vy*dbdy-vz-meltingvalue)*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorDiagnosticMacAyeal {{{1*/
+ElementVector* Tria::CreatePVectorDiagnosticMacAyeal(){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int            i,j,ig,drag_type;
+	double         plastic_stress,driving_stress_baseline,thickness;
+	double         Jdet;
+	double         xyz_list[NUMVERTICES][3];
+	double         slope[2];
+	double         l1l2l3[3];
+	double         pe_g_gaussian[numdof];
+	GaussTria*     gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input); 
+	Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
+	Input* drag_input=inputs->GetInput(DragCoefficientEnum);ISSMASSERT(drag_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+
+		thickness_input->GetParameterValue(&thickness,gauss);
+		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		
+		/*In case we have plastic basal drag, compute plastic stress at gaussian point from k1, k2 and k3 fields in the 
+		 * element itself: */
+		if(drag_type==1) drag_input->GetParameterValue(&plastic_stress,gauss);
+
+		driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG()*thickness;
+
+		/*Build pe_g_gaussian vector: */
+		if(drag_type==1){
+			for (i=0;i<NUMVERTICES;i++){
+				for (j=0;j<NDOF2;j++){
+					pe->values[i*NDOF2+j]+=(-driving_stress_baseline*slope[j]-plastic_stress)*Jdet*gauss->weight*l1l2l3[i]; 
+				}
+			}
+		}
+		else {
+			for (i=0;i<NUMVERTICES;i++){
+				for (j=0;j<NDOF2;j++){
+					pe->values[i*NDOF2+j]+=-driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l2l3[i];
+				}
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorAdjointBalancedthickness{{{1*/
+ElementVector* Tria::CreatePVectorAdjointBalancedthickness(void){
+
+	/*Constants*/
+	const int    numdof=1*NUMVERTICES;
+
+	/*Intermediaries */
+	int         i,ig;
+	double      Jdet;
+	double      thickness,thicknessobs,weight;
+	double      xyz_list[NUMVERTICES][3];
+	double      l1l2l3[3];
+	GaussTria*  gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
+	Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
+	Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+
+		thickness_input->GetParameterValue(&thickness, gauss);
+		thicknessobs_input->GetParameterValue(&thicknessobs, gauss);
+		weights_input->GetParameterValue(&weight, gauss);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=(thicknessobs-thickness)*weight*Jdet*gauss->weight*l1l2l3[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorAdjointHoriz{{{1*/
+ElementVector* Tria::CreatePVectorAdjointHoriz(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,ig,response;
+	double     Jdet;
+	double     obs_velocity_mag,velocity_mag;
+	double     dux,duy,meanvel,epsvel;
+	double     scalex=0,scaley=0,scale=0,S=0;
+	double     xyz_list[NUMVERTICES][3];
+	double     vx_list[NUMVERTICES];
+	double     vy_list[NUMVERTICES];
+	double     obs_vx_list[NUMVERTICES];
+	double     obs_vy_list[NUMVERTICES];
+	double     dux_list[NUMVERTICES];
+	double     duy_list[NUMVERTICES];
+	double     weights_list[NUMVERTICES];
+	double     l1l2l3[3];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&meanvel,MeanVelEnum);
+	this->parameters->FindParam(&epsvel,EpsVelEnum);
+	GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
+	GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
+	GetParameterListOnVertices(&vx_list[0],VxEnum);
+	GetParameterListOnVertices(&vy_list[0],VyEnum);
+	GetParameterListOnVertices(&weights_list[0],WeightsEnum);
+	inputs->GetParameterValue(&response,CmResponseEnum);
+	if(response==SurfaceAverageVelMisfitEnum){
+		inputs->GetParameterValue(&S,SurfaceAreaEnum);
+	}
+
+	/*Get Du at the 3 nodes (integration of the linearized function)
+	 * Here we integrate linearized functions:
+	 *               
+	 * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
+	 *
+	 *       d J                  dJ_i
+	 * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
+	 *       d u                  du_i
+	 *
+	 * where J_i are the misfits at the 3 nodes of the triangle
+	 *       Phi_i is the nodal function (P1) with respect to 
+	 *       the vertex i
+	 */
+	if(response==SurfaceAbsVelMisfitEnum){
+		/*We are using an absolute misfit:
+		 *
+		 *      1  [           2              2 ]
+		 * J = --- | (u - u   )  +  (v - v   )  |
+		 *      2  [       obs            obs   ]
+		 *
+		 *        dJ
+		 * DU = - -- = (u   - u )
+		 *        du     obs
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			dux_list[i]=obs_vx_list[i]-vx_list[i];
+			duy_list[i]=obs_vy_list[i]-vy_list[i];
+		}
+	}
+	else if(response==SurfaceRelVelMisfitEnum){
+		/*We are using a relative misfit: 
+		 *                        
+		 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
+		 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
+		 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
+		 *              obs                        obs                      
+		 *
+		 *        dJ     \bar{v}^2
+		 * DU = - -- = ------------- (u   - u )
+		 *        du   (u   + eps)^2    obs
+		 *               obs
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
+			scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
+			if(obs_vx_list[i]==0)scalex=0;
+			if(obs_vy_list[i]==0)scaley=0;
+			dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
+			duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
+		}
+	}
+	else if(response==SurfaceLogVelMisfitEnum){
+		/*We are using a logarithmic misfit:
+		 *                        
+		 *                 [        vel + eps     ] 2
+		 * J = 4 \bar{v}^2 | log ( -----------  ) |  
+		 *                 [       vel   + eps    ]
+		 *                            obs
+		 *
+		 *        dJ                 2 * log(...)
+		 * DU = - -- = - 4 \bar{v}^2 -------------  u
+		 *        du                 vel^2 + eps
+		 *            
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
+			obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
+			scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
+			dux_list[i]=scale*vx_list[i];
+			duy_list[i]=scale*vy_list[i];
+		}
+	}
+	else if(response==SurfaceAverageVelMisfitEnum){
+		/*We are using an spacially average absolute misfit:
+		 *
+		 *      1                    2              2
+		 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
+		 *      S                obs            obs
+		 *
+		 *        dJ      1       1 
+		 * DU = - -- = - --- ----------- * 2 (u - u   )
+		 *        du      S  2 sqrt(...)           obs
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
+			dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
+			duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
+		}
+	}
+	else if(response==SurfaceLogVxVyMisfitEnum){
+		/*We are using an logarithmic 2 misfit:
+		 *
+		 *      1            [        |u| + eps     2          |v| + eps     2  ]
+		 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   |  
+		 *      2            [       |u    |+ eps              |v    |+ eps     ]
+		 *                              obs                       obs
+		 *        dJ                              1      u                             1
+		 * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
+		 *        du                         |u| + eps  |u|                           u + eps
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			dux_list[i] = - pow(meanvel,(double)2)*(
+						log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
+			duy_list[i] = - pow(meanvel,(double)2)*(
+						log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
+		}
+	}
+	else{
+		/*Not supported yet! : */
+		ISSMERROR("response %s not supported yet",EnumToString(response));
+	}
+
+	/*Apply weights to DU*/
+	for (i=0;i<NUMVERTICES;i++){
+		dux_list[i]=weights_list[i]*dux_list[i];
+		duy_list[i]=weights_list[i]*duy_list[i];
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+
+		TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
+		TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
+
+		for (i=0;i<NUMVERTICES;i++){
+			pe->values[i*NDOF2+0]+=dux*Jdet*gauss->weight*l1l2l3[i]; 
+			pe->values[i*NDOF2+1]+=duy*Jdet*gauss->weight*l1l2l3[i]; 
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorAdjointStokes{{{1*/
+ElementVector* Tria::CreatePVectorAdjointStokes(void){
+
+	/*Intermediaries */
+	int        i,ig;
+	int        fit=-1;
+	int        response;
+	double     Jdet;
+	double     obs_velocity_mag,velocity_mag;
+	double     dux,duy,meanvel,epsvel;
+	double     scalex=0,scaley=0,scale=0,S=0;
+	double     xyz_list[NUMVERTICES][3];
+	double     vx_list[NUMVERTICES];
+	double     vy_list[NUMVERTICES];
+	double     obs_vx_list[NUMVERTICES];
+	double     obs_vy_list[NUMVERTICES];
+	double     dux_list[NUMVERTICES];
+	double     duy_list[NUMVERTICES];
+	double     weights_list[NUMVERTICES];
+	double     l1l2l3[3];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&meanvel,MeanVelEnum);
+	this->parameters->FindParam(&epsvel,EpsVelEnum);
+	GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
+	GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
+	GetParameterListOnVertices(&vx_list[0],VxEnum);
+	GetParameterListOnVertices(&vy_list[0],VyEnum);
+	GetParameterListOnVertices(&weights_list[0],WeightsEnum);
+	inputs->GetParameterValue(&response,CmResponseEnum);
+	if(response==SurfaceAverageVelMisfitEnum){
+		inputs->GetParameterValue(&S,SurfaceAreaEnum);
+	}
+
+	/*Get Du at the 3 nodes (integration of the linearized function)
+	 * Here we integrate linearized functions:
+	 *               
+	 * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
+	 *
+	 *       d J                  dJ_i
+	 * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
+	 *       d u                  du_i
+	 *
+	 * where J_i are the misfits at the 3 nodes of the triangle
+	 *       Phi_i is the nodal function (P1) with respect to 
+	 *       the vertex i
+	 */
+	if(response==SurfaceAbsVelMisfitEnum){
+		/*We are using an absolute misfit:
+		 *
+		 *      1  [           2              2 ]
+		 * J = --- | (u - u   )  +  (v - v   )  |
+		 *      2  [       obs            obs   ]
+		 *
+		 *        dJ             2
+		 * DU = - -- = (u   - u )
+		 *        du     obs
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			dux_list[i]=obs_vx_list[i]-vx_list[i];
+			duy_list[i]=obs_vy_list[i]-vy_list[i];
+		}
+	}
+	else if(response==SurfaceRelVelMisfitEnum){
+		/*We are using a relative misfit: 
+		 *                        
+		 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
+		 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
+		 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
+		 *              obs                        obs                      
+		 *
+		 *        dJ     \bar{v}^2
+		 * DU = - -- = ------------- (u   - u )
+		 *        du   (u   + eps)^2    obs
+		 *               obs
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
+			scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
+			if(obs_vx_list[i]==0)scalex=0;
+			if(obs_vy_list[i]==0)scaley=0;
+			dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
+			duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
+		}
+	}
+	else if(response==SurfaceLogVelMisfitEnum){
+		/*We are using a logarithmic misfit:
+		 *                        
+		 *                 [        vel + eps     ] 2
+		 * J = 4 \bar{v}^2 | log ( -----------  ) |  
+		 *                 [       vel   + eps    ]
+		 *                            obs
+		 *
+		 *        dJ                 2 * log(...)
+		 * DU = - -- = - 4 \bar{v}^2 -------------  u
+		 *        du                 vel^2 + eps
+		 *            
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
+			obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
+			scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
+			dux_list[i]=scale*vx_list[i];
+			duy_list[i]=scale*vy_list[i];
+		}
+	}
+	else if(response==SurfaceAverageVelMisfitEnum){
+		/*We are using an spacially average absolute misfit:
+		 *
+		 *      1                    2              2
+		 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
+		 *      S                obs            obs
+		 *
+		 *        dJ      1       1 
+		 * DU = - -- = - --- ----------- * 2 (u - u   )
+		 *        du      S  2 sqrt(...)           obs
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
+			dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
+			duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
+		}
+	}
+	else if(response==SurfaceLogVxVyMisfitEnum){
+		/*We are using an logarithmic 2 misfit:
+		 *
+		 *      1            [        |u| + eps     2          |v| + eps     2  ]
+		 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   |  
+		 *      2            [       |u    |+ eps              |v    |+ eps     ]
+		 *                              obs                       obs
+		 *        dJ                              1      u                             1
+		 * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
+		 *        du                         |u| + eps  |u|                           u + eps
+		 */
+		for (i=0;i<NUMVERTICES;i++){
+			dux_list[i] = - pow(meanvel,(double)2)*(
+						log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
+			duy_list[i] = - pow(meanvel,(double)2)*(
+						log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
+		}
+	}
+	else{
+		/*Not supported yet! : */
+		ISSMERROR("response %s not supported yet",EnumToString(response));
+	}
+
+	/*Apply weights to DU*/
+	for (i=0;i<NUMVERTICES;i++){
+		dux_list[i]=weights_list[i]*dux_list[i];
+		duy_list[i]=weights_list[i]*duy_list[i];
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+
+		TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
+		TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
+
+		for (i=0;i<NUMVERTICES;i++){
+			pe->values[i*NDOF4+0]+=dux*Jdet*gauss->weight*l1l2l3[i];
+			pe->values[i*NDOF4+1]+=duy*Jdet*gauss->weight*l1l2l3[i]; 
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorDiagnosticHutter{{{1*/
+ElementVector* Tria::CreatePVectorDiagnosticHutter(void){
+
+	/*Intermediaries */
+	int        i,connectivity;
+	double     constant_part,ub,vb;
+	double     rho_ice,gravity,n,B;
+	double     slope2,thickness;
+	double     slope[2];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	n=matice->GetN();
+	B=matice->GetBbar();
+	Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
+	Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
+
+	/*Spawn 3 sing elements: */
+	gauss=new GaussTria();
+	for(i=0;i<NUMVERTICES;i++){
+
+		gauss->GaussVertex(i);
+
+		connectivity=nodes[i]->GetConnectivity();
+
+		thickness_input->GetParameterValue(&thickness,gauss);
+		slopex_input->GetParameterValue(&slope[0],gauss);
+		slopey_input->GetParameterValue(&slope[1],gauss);
+		slope2=pow(slope[0],2)+pow(slope[1],2);
+
+		constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
+
+		ub=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[0];
+		vb=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[1];
+
+		pe->values[2*i]  =(ub-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[0])/(double)connectivity;
+		pe->values[2*i+1]=(vb-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[1])/(double)connectivity;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic{{{1*/
+ElementVector* Tria::CreatePVectorPrognostic(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreatePVectorPrognostic_CG();
+		case P1DGEnum:
+			return CreatePVectorPrognostic_DG();
+		default:
+			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic_CG {{{1*/
+ElementVector* Tria::CreatePVectorPrognostic_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	double     Jdettria,dt;
+	double     accumulation_g,melting_g,thickness_g;
+	double     xyz_list[NUMVERTICES][3];
+	double     L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	this->parameters->FindParam(&dt,DtEnum);
+	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
+	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		accumulation_input->GetParameterValue(&accumulation_g,gauss);
+		melting_input->GetParameterValue(&melting_g,gauss);
+		thickness_input->GetParameterValue(&thickness_g,gauss);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic_DG {{{1*/
+ElementVector* Tria::CreatePVectorPrognostic_DG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	double     Jdettria,dt;
+	double     accumulation_g,melting_g,thickness_g;
+	double     xyz_list[NUMVERTICES][3];
+	double     L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	this->parameters->FindParam(&dt,DtEnum);
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
+	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		accumulation_input->GetParameterValue(&accumulation_g,gauss);
+		melting_input->GetParameterValue(&melting_g,gauss);
+		thickness_input->GetParameterValue(&thickness_g,gauss);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorSlope {{{1*/
+ElementVector* Tria::CreatePVectorSlope(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+	
+	/*Intermediaries */
+	int        i,j,ig;
+	int        analysis_type;
+	double     Jdet;
+	double     xyz_list[NUMVERTICES][3];
+	double     slope[2];
+	double     l1l2l3[3];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	Input* slope_input=NULL;
+	if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==SurfaceSlopeYAnalysisEnum)){
+		slope_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(slope_input);
+	}
+	if ( (analysis_type==BedSlopeXAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
+		slope_input=inputs->GetInput(BedEnum);     ISSMASSERT(slope_input);
+	}
+		
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+
+		slope_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+
+		if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==BedSlopeXAnalysisEnum)){
+			for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[0]*l1l2l3[i];
+		}
+		if ( (analysis_type==SurfaceSlopeYAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
+			for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[1]*l1l2l3[i];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorThermalShelf {{{1*/
+ElementVector* Tria::CreatePVectorThermalShelf(void){
+	
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,ig;
+	double     Jdet;
+	double     mixed_layer_capacity,thermal_exchange_velocity;
+	double     rho_ice,rho_water,pressure,dt,scalar_ocean;
+	double     meltingpoint,beta,heatcapacity,t_pmp;
+	double     xyz_list[NUMVERTICES][3];
+	double     l1l2l3[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
+	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	beta=matpar->GetBeta();
+	meltingpoint=matpar->GetMeltingPoint();
+	this->parameters->FindParam(&dt,DtEnum);
+	Input* pressure_input=inputs->GetInput(PressureEnum); ISSMASSERT(pressure_input);
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
+		GetNodalFunctions(&l1l2l3[0], gauss);
+
+		pressure_input->GetParameterValue(&pressure,gauss);
+		t_pmp=meltingpoint-beta*pressure;
+
+		scalar_ocean=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity*(t_pmp)/(heatcapacity*rho_ice);
+		if(dt) scalar_ocean=dt*scalar_ocean;
+
+		for(i=0;i<numdof;i++) pe->values[i]+=scalar_ocean*l1l2l3[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorThermalSheet {{{1*/
+ElementVector* Tria::CreatePVectorThermalSheet(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,ig;
+	int        analysis_type,drag_type;
+	double     xyz_list[NUMVERTICES][3];
+	double     Jdet,dt;
+	double     rho_ice,heatcapacity,geothermalflux_value;
+	double     basalfriction,alpha2,vx,vy,pressure;
+	double     pressure_list[3];
+	double     scalar;
+	double     l1l2l3[NUMVERTICES];
+	Friction*  friction=NULL;
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	this->inputs->GetParameterValue(&dt,DtEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);                         ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                         ISSMASSERT(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                         ISSMASSERT(vz_input);
+	Input* geothermalflux_input=inputs->GetInput(GeothermalFluxEnum); ISSMASSERT(geothermalflux_input);
+
+	/*Build frictoin element, needed later: */
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
+	friction=new Friction("3d",inputs,matpar,analysis_type);
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
+		GetNodalFunctions(&l1l2l3[0], gauss);
+
+		geothermalflux_input->GetParameterValue(&geothermalflux_value,gauss);
+		friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		basalfriction=alpha2*(pow(vx,2.0)+pow(vy,2.0));
+		
+		scalar=gauss->weight*Jdet*(basalfriction+geothermalflux_value)/(heatcapacity*rho_ice);
+		if(dt) scalar=dt*scalar;
+
+		for(i=0;i<numdof;i++) pe->values[i]+=scalar*l1l2l3[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeBasalStress {{{1*/
+void  Tria::ComputeBasalStress(Vec eps){
+	ISSMERROR("Not Implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeStrainRate {{{1*/
+void  Tria::ComputeStrainRate(Vec eps){
+	ISSMERROR("Not Implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::Configure {{{1*/
+void  Tria::Configure(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+	
+	/*go into parameters and get the analysis_counter: */
+	int analysis_counter;
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective 
+	 * datasets, using internal ids and offsets hidden in hooks: */
+	if(this->hnodes[analysis_counter]) this->hnodes[analysis_counter]->configure(nodesin);
+	this->hmatice->configure(materialsin);
+	this->hmatpar->configure(materialsin);
+
+	/*Now, go pick up the objects inside the hooks: */
+	if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
+	else this->nodes=NULL;
+	this->matice=(Matice*)this->hmatice->delivers();
+	this->matpar=(Matpar*)this->hmatpar->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+
+}
+/*}}}*/
+/*FUNCTION Tria::ControlInputGetGradient{{{1*/
+void Tria::ControlInputGetGradient(Vec gradient,int enum_type){
+
+	int doflist1[NUMVERTICES];
+	Input* input=NULL;
+
+	if(enum_type==RheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
+	if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
+
+	this->GetDofList1(&doflist1[0]);
+	((ControlInput*)input)->GetGradient(gradient,&doflist1[0]);
+
+}/*}}}*/
+/*FUNCTION Tria::ControlInputScaleGradient{{{1*/
+void Tria::ControlInputScaleGradient(int enum_type,double scale){
+
+	Input* input=NULL;
+
+	if(enum_type==RheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
+	if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
+
+	((ControlInput*)input)->ScaleGradient(scale);
+}/*}}}*/
+/*FUNCTION Tria::ControlInputSetGradient{{{1*/
+void Tria::ControlInputSetGradient(double* gradient,int enum_type){
+
+	int    doflist1[NUMVERTICES];
+	double grad_list[NUMVERTICES];
+	Input* grad_input=NULL;
+	Input* input=NULL;
+
+	if(enum_type==RheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
+	if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
+
+	this->GetDofList1(&doflist1[0]);
+	for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[doflist1[i]];
+	grad_input=new TriaVertexInput(GradientEnum,grad_list);
+
+	((ControlInput*)input)->SetGradient(grad_input);
+
+}/*}}}*/
+/*FUNCTION Tria::DeepEcho{{{1*/
+void Tria::DeepEcho(void){
+
+	printf("Tria:\n");
+	printf("   id: %i\n",id);
+	if(nodes){
+		nodes[0]->DeepEcho();
+		nodes[1]->DeepEcho();
+		nodes[2]->DeepEcho();
+	}
+	else printf("nodes = NULL\n");
+
+	if (matice) matice->DeepEcho();
+	else printf("matice = NULL\n");
+
+	if (matpar) matpar->DeepEcho();
+	else printf("matpar = NULL\n");
+
+	printf("   parameters\n");
+	if (parameters) parameters->DeepEcho();
+	else printf("parameters = NULL\n");
+
+	printf("   inputs\n");
+	if (inputs) inputs->DeepEcho();
+	else printf("inputs=NULL\n");
+
+	if (results) results->DeepEcho();
+	else printf("results=NULL\n");
+	
+	return;
+}
+/*}}}*/
+/*FUNCTION Tria::DeleteResults {{{1*/
+void  Tria::DeleteResults(void){
+
+	/*Delete and reinitialize results*/
+	delete this->results;
+	this->results=new Results();
+
+}
+/*}}}*/
+/*FUNCTION Tria::Echo{{{1*/
+void Tria::Echo(void){
+	printf("Tria:\n");
+	printf("   id: %i\n",id);
+	if(nodes){
+		nodes[0]->Echo();
+		nodes[1]->Echo();
+		nodes[2]->Echo();
+	}
+	else printf("nodes = NULL\n");
+
+	if (matice) matice->Echo();
+	else printf("matice = NULL\n");
+
+	if (matpar) matpar->Echo();
+	else printf("matpar = NULL\n");
+
+	printf("   parameters\n");
+	if (parameters) parameters->Echo();
+	else printf("parameters = NULL\n");
+
+	printf("   inputs\n");
+	if (inputs) inputs->Echo();
+	else printf("inputs=NULL\n");
+
+	if (results) results->Echo();
+	else printf("results=NULL\n");
+}
+/*}}}*/
+/*FUNCTION Tria::Enum {{{1*/
+int Tria::Enum(void){
+
+	return TriaEnum;
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetArea {{{1*/
+double Tria::GetArea(void){
+
+	double area=0;
+	double xyz_list[NUMVERTICES][3];
+	double x1,y1,x2,y2,x3,y3;
+
+	/*Get xyz list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	x1=xyz_list[0][0]; y1=xyz_list[0][1];
+	x2=xyz_list[1][0]; y2=xyz_list[1][1];
+	x3=xyz_list[2][0]; y3=xyz_list[2][1];
+ 
+	return (x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
+}
+/*}}}*/
+/*FUNCTION Tria::GetDofList {{{1*/
+void  Tria::GetDofList(int** pdoflist, int approximation_enum,int setenum){
+
+	int i,j;
+	int count=0;
+	int numberofdofs=0;
+	int* doflist=NULL;
+
+	/*First, figure out size of doflist and create it: */
+	for(i=0;i<3;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+	doflist=(int*)xmalloc(numberofdofs*sizeof(int));
+
+	/*Populate: */
+	count=0;
+	for(i=0;i<3;i++){
+		nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
+		count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+	}
+
+	/*Assign output pointers:*/
+	*pdoflist=doflist;
+}
+/*}}}*/
+/*FUNCTION Tria::GetDofList1 {{{1*/
+void  Tria::GetDofList1(int* doflist){
+
+	int i;
+	for(i=0;i<3;i++) doflist[i]=nodes[i]->GetDofList1();
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetElementType {{{1*/
+int Tria::GetElementType(){
+
+	/*return TriaRef field*/
+	return this->element_type;
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetNodeIndex {{{1*/
+int Tria::GetNodeIndex(Node* node){
+
+	ISSMASSERT(nodes);
+	for(int i=0;i<NUMVERTICES;i++){
+		if(node==nodes[i])
+		 return i;
+	}
+	ISSMERROR("Node provided not found among element nodes");
+}
+/*}}}*/
+/*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
+void Tria::GetParameterListOnVertices(double* pvalue,int enumtype){
+
+	/*Intermediaries*/
+	double     value[NUMVERTICES];
+	GaussTria *gauss              = NULL;
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+	if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
+
+	/*Checks in debugging mode*/
+	ISSMASSERT(pvalue);
+
+	/* Start looping on the number of vertices: */
+	gauss=new GaussTria();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+		input->GetParameterValue(&pvalue[iv],gauss);
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
+void Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
+
+	double     value[NUMVERTICES];
+	GaussTria *gauss = NULL;
+	Input     *input = inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	ISSMASSERT(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		gauss=new GaussTria();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetParameterValue(&pvalue[iv],gauss);
+		}
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
+void Tria::GetParameterValue(double* pvalue,Node* node,int enumtype){
+
+	Input* input=inputs->GetInput(enumtype);
+	if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
+
+	GaussTria* gauss=new GaussTria();
+	gauss->GaussVertex(this->GetNodeIndex(node));
+
+	input->GetParameterValue(pvalue,gauss);
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GetSidList {{{1*/
+void  Tria::GetSidList(int* sidlist){
+
+	int i;
+	for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputs{{{1*/
+void  Tria::GetSolutionFromInputs(Vec solution){
+
+	/*retrive parameters: */
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
+	if (analysis_type==DiagnosticHorizAnalysisEnum)
+	 GetSolutionFromInputsDiagnosticHoriz(solution);
+	else if (analysis_type==DiagnosticHutterAnalysisEnum)
+	 GetSolutionFromInputsDiagnosticHutter(solution);
+	else
+	 ISSMERROR("analysis: %s not supported yet",EnumToString(analysis_type));
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHoriz{{{1*/
+void  Tria::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	double       vx,vy;
+	double       values[numdof];
+	GaussTria*   gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get inputs*/
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	/*P1 element only for now*/
+	gauss=new GaussTria();
+	for(i=0;i<NUMVERTICES;i++){
+
+		gauss->GaussVertex(i);
+
+		/*Recover vx and vy*/
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHutter{{{1*/
+void  Tria::GetSolutionFromInputsDiagnosticHutter(Vec solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int i,dummy;
+	int*         doflist=NULL;
+	double       vx,vy;
+	double       values[numdof];
+	GaussTria*   gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get inputs*/
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	/*P1 element only for now*/
+	gauss=new GaussTria();
+	for(i=0;i<NUMVERTICES;i++){
+
+		gauss->GaussVertex(i);
+
+		/*Recover vx and vy*/
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
+
+	/*Free ressources:*/
+	delete gauss;
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){{{1*/
+void Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){
+	/*Compute the 2d Strain Rate (3 components):
+	 * epsilon=[exx eyy exy] */
+
+	int i;
+	double epsilonvx[3];
+	double epsilonvy[3];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input){
+		ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
+	}
+
+	/*Get strain rate assuming that epsilon has been allocated*/
+	vx_input->GetVxStrainRate2d(epsilonvx,xyz_list,gauss);
+	vy_input->GetVyStrainRate2d(epsilonvy,xyz_list,gauss);
+
+	/*Sum all contributions*/
+	for(i=0;i<3;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
+}
+/*}}}*/
+/*FUNCTION Tria::GetVectorFromInputs{{{1*/
+void  Tria::GetVectorFromInputs(Vec vector,int NameEnum){
+
+	int doflist1[NUMVERTICES];
+
+	/*Find NameEnum input in the inputs dataset, and get it to fill in the vector: */
+	for(int i=0;i<this->inputs->Size();i++){
+		Input* input=(Input*)this->inputs->GetObjectByOffset(i);
+		if(input->EnumType()==NameEnum){
+			/*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
+			this->GetDofList1(&doflist1[0]);
+			input->GetVectorFromInputs(vector,&doflist1[0]);
+			break;
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::Gradj {{{1*/
+void  Tria::Gradj(Vec gradient,int control_type){
+
+	/*If on water, grad = 0: */
+	if(IsOnWater())return;
+
+	switch(control_type){
+		case DragCoefficientEnum:
+			GradjDrag(gradient);
+			break;
+		case RheologyBbarEnum:
+			GradjB(gradient);
+			break;
+		case DhDtEnum:
+			GradjDhDt(gradient);
+			break;
+		case VxEnum:
+			GradjVx(gradient);
+			break;
+		case VyEnum:
+			GradjVy(gradient);
+			break;
+		default:
+			ISSMERROR("%s%i","control type not supported yet: ",control_type);
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::GradjB{{{1*/
+void  Tria::GradjB(Vec gradient){
+
+	/*Intermediaries*/
+	int        i,ig;
+	int        doflist[NUMVERTICES];
+	double     vx,vy,lambda,mu,thickness,Jdet;
+	double     cm_noisedmp,viscosity_complement;
+	double     dvx[NDOF2],dvy[NDOF2],dadjx[NDOF2],dadjy[NDOF2],dB[NDOF2]; 
+	double     xyz_list[NUMVERTICES][3];
+	double     basis[3],epsilon[3];
+	double     dbasis[NDOF2][NUMVERTICES];
+	double     grad_g[NUMVERTICES];
+	double     grad[NUMVERTICES]={0.0};
+	GaussTria *gauss = NULL;
+
+	/*retrieve some parameters: */
+	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	GetDofList1(&doflist[0]);
+
+	/*Retrieve all inputs*/
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);            ISSMASSERT(thickness_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                          ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                          ISSMASSERT(vy_input);
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);              ISSMASSERT(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);              ISSMASSERT(adjointy_input);
+	Input* rheologyb_input=matice->inputs->GetInput(RheologyBbarEnum); ISSMASSERT(rheologyb_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		thickness_input->GetParameterValue(&thickness,gauss);
+		rheologyb_input->GetParameterDerivativeValue(&dB[0],&xyz_list[0][0],gauss);
+		vx_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vy_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+		adjointx_input->GetParameterDerivativeValue(&dadjx[0],&xyz_list[0][0],gauss);
+		adjointy_input->GetParameterDerivativeValue(&dadjy[0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		matice->GetViscosityComplement(&viscosity_complement,&epsilon[0]);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis,gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+
+		/*standard gradient dJ/dki*/
+		for (i=0;i<NUMVERTICES;i++){
+			grad_g[i]=-viscosity_complement*thickness*( (2*dvx[0]+dvy[1])*2*dadjx[0]+(dvx[1]+dvy[0])*(dadjx[1]+dadjy[0])+(2*dvy[1]+dvx[0])*2*dadjy[1])*Jdet*gauss->weight*basis[i]; 
+		}
+		/*Add regularization term*/
+		for (i=0;i<NUMVERTICES;i++) grad_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dB[0]+dbasis[1][i]*dB[1]);
+		for(i=0;i<NUMVERTICES;i++) grad[i]+=grad_g[i];
+	}
+
+	VecSetValues(gradient,NUMVERTICES,doflist,(const double*)grad,ADD_VALUES);
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDrag {{{1*/
+void  Tria::GradjDrag(Vec gradient){
+
+	int        i,ig;
+	int        drag_type,analysis_type;
+	int        doflist1[NUMVERTICES];
+	double     vx,vy,lambda,mu,alpha_complement,Jdet;
+	double     bed,thickness,Neff,drag,cm_noisedmp;
+	double     xyz_list[NUMVERTICES][3];
+	double     dh1dh3[NDOF2][NUMVERTICES];
+	double     dk[NDOF2]; 
+	double     grade_g[NUMVERTICES]={0.0};
+	double     grade_g_gaussian[NUMVERTICES];
+	double     l1l2l3[3];
+	double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
+	Friction*  friction=NULL;
+	GaussTria  *gauss=NULL;
+
+	/*retrive parameters: */
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*retrieve some parameters ands return if iceshelf: */
+	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
+	if(IsOnShelf())return;
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	GetDofList1(&doflist1[0]);
+
+	/*Build frictoin element, needed later: */
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);               ISSMASSERT(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);               ISSMASSERT(adjointy_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                           ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                           ISSMASSERT(vy_input);
+	Input* dragcoefficient_input=inputs->GetInput(DragCoefficientEnum); ISSMASSERT(dragcoefficient_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+		GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
+
+		/*Build alpha_complement_list: */
+		if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
+		else alpha_complement=0;
+	
+		dragcoefficient_input->GetParameterValue(&drag, gauss);
+		adjointx_input->GetParameterValue(&lambda, gauss);
+		adjointy_input->GetParameterValue(&mu, gauss);
+		vx_input->GetParameterValue(&vx,gauss);
+		vy_input->GetParameterValue(&vy,gauss);
+		dragcoefficient_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++){
+
+			//standard term dJ/dki
+			grade_g_gaussian[i]=-2*drag*alpha_complement*((lambda*vx+mu*vy))*Jdet*gauss->weight*l1l2l3[i];
+
+			//noise dampening d/dki(1/2*(dk/dx)^2)
+			grade_g_gaussian[i]+=-cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
+		}
+		
+		/*Add gradje_g_gaussian vector to gradje_g: */
+		for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
+	}
+
+	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDragStokes {{{1*/
+void  Tria::GradjDragStokes(Vec gradient){
+
+	int        i,ig;
+	int        drag_type,analysis_type;
+	int        doflist1[NUMVERTICES];
+	double     bed,thickness,Neff;
+	double     lambda,mu,xi,Jdet,vx,vy,vz;
+	double     alpha_complement,drag,cm_noisedmp;
+	double     surface_normal[3],bed_normal[3];
+	double     xyz_list[NUMVERTICES][3];
+	double     dh1dh3[NDOF2][NUMVERTICES];
+	double     dk[NDOF2]; 
+	double     l1l2l3[3];
+	double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
+	double     grade_g[NUMVERTICES]={0.0};
+	double     grade_g_gaussian[NUMVERTICES];
+	Friction*  friction=NULL;
+	GaussTria* gauss=NULL;
+
+	/*retrive parameters: */
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*retrieve inputs :*/
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	Input* drag_input    =inputs->GetInput(DragCoefficientEnum); ISSMASSERT(drag_input);
+	Input* vx_input      =inputs->GetInput(VxEnum);              ISSMASSERT(vx_input);
+	Input* vy_input      =inputs->GetInput(VyEnum);              ISSMASSERT(vy_input);
+	Input* vz_input      =inputs->GetInput(VzEnum);              ISSMASSERT(vz_input);
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);        ISSMASSERT(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);        ISSMASSERT(adjointy_input);
+	Input* adjointz_input=inputs->GetInput(AdjointzEnum);        ISSMASSERT(adjointz_input);
+
+	/*retrieve some parameters: */
+	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
+
+	/*Get out if shelf*/
+	if(IsOnShelf())return;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	GetDofList1(&doflist1[0]);
+
+	/*Build frictoin element, needed later: */
+	inputs->GetParameterValue(&drag_type,DragTypeEnum);
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/*Recover alpha_complement and drag: */
+		if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
+		else alpha_complement=0;
+		drag_input->GetParameterValue(&drag,gauss);
+
+		/*recover lambda mu and xi: */
+		adjointx_input->GetParameterValue(&lambda,gauss);
+		adjointy_input->GetParameterValue(&mu    ,gauss);
+		adjointz_input->GetParameterValue(&xi    ,gauss);
+
+		/*recover vx vy and vz: */
+		vx_input->GetParameterValue(&vx, gauss);
+		vy_input->GetParameterValue(&vy, gauss);
+		vz_input->GetParameterValue(&vz, gauss);
+
+		/*Get normal vector to the bed */
+		SurfaceNormal(&surface_normal[0],xyz_list);
+
+		bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
+		bed_normal[1]=-surface_normal[1];
+		bed_normal[2]=-surface_normal[2];
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
+
+		/* Get nodal functions value at gaussian point:*/
+		GetNodalFunctions(l1l2l3, gauss);
+
+		/*Get nodal functions derivatives*/
+		GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
+
+		/*Get k derivative: dk/dx */
+		drag_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++){
+			//standard gradient dJ/dki
+			grade_g_gaussian[i]=(
+						-lambda*(2*drag*alpha_complement*(vx - vz*bed_normal[0]*bed_normal[2]))
+						-mu    *(2*drag*alpha_complement*(vy - vz*bed_normal[1]*bed_normal[2]))
+						-xi    *(2*drag*alpha_complement*(-vx*bed_normal[0]*bed_normal[2]-vy*bed_normal[1]*bed_normal[2]))
+						)*Jdet*gauss->weight*l1l2l3[i]; 
+
+			//Add regularization term
+			grade_g_gaussian[i]+= - cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
+		}
+
+		/*Add gradje_g_gaussian vector to gradje_g: */
+		for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
+	}
+
+	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
+
+	delete friction;
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDhDt{{{1*/
+void  Tria::GradjDhDt(Vec gradient){
+
+	/*Intermediaries*/
+	int    doflist1[NUMVERTICES];
+	double lambda[NUMVERTICES];
+	double gradient_g[NUMVERTICES];
+
+	GetDofList1(&doflist1[0]);
+
+	/*Compute Gradient*/
+	GetParameterListOnVertices(&lambda[0],AdjointEnum);
+	for(int i=0;i<NUMVERTICES;i++) gradient_g[i]=-lambda[i];
+
+	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)gradient_g,INSERT_VALUES);
+}
+/*}}}*/
+/*FUNCTION Tria::GradjVx{{{1*/
+void  Tria::GradjVx(Vec gradient){
+
+	/*Intermediaries*/
+	int        i,ig;
+	int        doflist1[NUMVERTICES];
+	double     thickness,Jdet,cm_noisedmp;
+	double     l1l2l3[3];
+	double     dbasis[NDOF2][NUMVERTICES];
+	double     Dlambda[2],dp[2];
+	double     xyz_list[NUMVERTICES][3];
+	double     grade_g[NUMVERTICES] = {0.0};
+	GaussTria *gauss                = NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	GetDofList1(&doflist1[0]);
+
+	/*Retrieve all inputs we will be needing: */
+	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
+	Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+		
+		adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
+		thickness_input->GetParameterValue(&thickness, gauss);
+		thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[0]*Jdet*gauss->weight*l1l2l3[i];
+
+		//noise dampening d/dki(1/2*(dk/dx)^2)
+		//for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
+	}
+
+	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjVy{{{1*/
+void  Tria::GradjVy(Vec gradient){
+
+	/*Intermediaries*/
+	int        i,ig;
+	int        doflist1[NUMVERTICES];
+	double     thickness,Jdet,cm_noisedmp;
+	double     l1l2l3[3];
+	double     dbasis[NDOF2][NUMVERTICES];
+	double     Dlambda[2],dp[2];
+	double     xyz_list[NUMVERTICES][3];
+	double     grade_g[NUMVERTICES] = {0.0};
+	GaussTria *gauss                = NULL;
+
+	/* Get node coordinates and dof list: */
+	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+	GetDofList1(&doflist1[0]);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(l1l2l3, gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+
+		adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
+		thickness_input->GetParameterValue(&thickness, gauss);
+		thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[1]*Jdet*gauss->weight*l1l2l3[i];
+
+		//noise dampening d/dki(1/2*(dk/dx)^2)
+		//for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
+	}
+
+	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::Id {{{1*/
+int    Tria::Id(){
+	
+	return id;
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputArtificialNoise{{{1*/
+void  Tria::InputArtificialNoise(int enum_type,double min,double max){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
+
+	/*ArtificialNoise: */
+	input->ArtificialNoise(min,max);
+}
+/*}}}*/
+/*FUNCTION Tria::InputControlUpdate{{{1*/
+void  Tria::InputControlUpdate(double scalar,bool save_parameter){
+
+	/*Intermediary*/
+	int    num_controls;
+	int*   control_type=NULL;
+	Input* input=NULL;
+	double *cm_min=NULL;
+	double *cm_max=NULL;
+
+	/*retrieve some parameters: */
+	this->parameters->FindParam(&cm_min,NULL,CmMinEnum);
+	this->parameters->FindParam(&cm_max,NULL,CmMaxEnum);
+	this->parameters->FindParam(&num_controls,NumControlsEnum);
+	this->parameters->FindParam(&control_type,NULL,ControlTypeEnum);
+
+	for(int i=0;i<num_controls;i++){
+
+		if(control_type[i]==RheologyBbarEnum){
+			input=(Input*)matice->inputs->GetInput(control_type[i]); ISSMASSERT(input);
+		}
+		else{
+			input=(Input*)this->inputs->GetInput(control_type[i]);   ISSMASSERT(input);
+		}
+
+		if (input->Enum()!=ControlInputEnum){
+			ISSMERROR("input %s is not a ControlInput",EnumToString(control_type[i]));
+		}
+
+		((ControlInput*)input)->UpdateValue(scalar);
+		input->Constrain(cm_min[i],cm_max[i]);
+		if (save_parameter) ((ControlInput*)input)->SaveValue();
+
+	}
+
+	/*Clean up and return*/
+	xfree((void**)&control_type);
+	xfree((void**)&cm_min);
+	xfree((void**)&cm_max);
+}
+/*}}}*/
+/*FUNCTION Tria::InputConvergence{{{1*/
+bool Tria::InputConvergence(double* eps, int* enums,int num_enums,int* criterionenums,double* criterionvalues,int num_criterionenums){
+
+	bool    converged=true;
+	int     i;
+	Input** new_inputs=NULL;
+	Input** old_inputs=NULL;
+
+	new_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the new inputs
+	old_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the old inputs
+
+	for(i=0;i<num_enums/2;i++){
+		new_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+0]);
+		old_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+1]);
+		if(!new_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
+		if(!old_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
+	}
+
+	/*ok, we've got the inputs (new and old), now loop throught the number of criterions and fill the eps array:*/
+	for(i=0;i<num_criterionenums;i++){
+		IsInputConverged(eps+i,new_inputs,old_inputs,num_enums/2,criterionenums[i]);
+		if(eps[i]>criterionvalues[i]) converged=false; 
+	}
+
+	/*clean up and return*/
+	xfree((void**)&new_inputs);
+	xfree((void**)&old_inputs);
+	return converged;
+}
+/*}}}*/
+/*FUNCTION Tria::InputDepthAverageAtBase {{{1*/
+void  Tria::InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum){
+
+	/*New input*/
+	Input* oldinput=NULL;
+	Input* newinput=NULL;
+
+	/*copy input of enum_type*/
+	if (object_enum==ElementsEnum)
+	 oldinput=(Input*)this->inputs->GetInput(enum_type);
+	else if (object_enum==MaterialsEnum)
+	 oldinput=(Input*)this->matice->inputs->GetInput(enum_type);
+	else
+	 ISSMERROR("object %s not supported yet",EnumToString(object_enum));
+	if(!oldinput)ISSMERROR("%s%s"," could not find old input with enum: ",EnumToString(enum_type));
+	newinput=(Input*)oldinput->copy();
+
+	/*Assign new name (average)*/
+	newinput->ChangeEnum(average_enum_type);
+
+	/*Add new input to current element*/
+	if (object_enum==ElementsEnum)
+	 this->inputs->AddInput((Input*)newinput);
+	else if (object_enum==MaterialsEnum)
+	 this->matice->inputs->AddInput((Input*)newinput);
+	else
+	 ISSMERROR("object %s not supported yet",EnumToString(object_enum));
+}
+/*}}}*/
+/*FUNCTION Tria::InputDuplicate{{{1*/
+void  Tria::InputDuplicate(int original_enum,int new_enum){
+
+	/*Call inputs method*/
+	if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputScale{{{1*/
+void  Tria::InputScale(int enum_type,double scale_factor){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
+
+	/*Scale: */
+	input->Scale(scale_factor);
+}
+/*}}}*/
+/*FUNCTION Tria::InputToResult{{{1*/
+void  Tria::InputToResult(int enum_type,int step,double time){
+
+	int    i;
+	Input *input = NULL;
+
+	/*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
+	if (enum_type==RheologyBbarEnum) input=this->matice->inputs->GetInput(enum_type);
+	else input=this->inputs->GetInput(enum_type);
+	if (!input) ISSMERROR("Input %s not found in tria->inputs",EnumToString(enum_type));
+
+	/*If we don't find it, no big deal, just don't do the transfer. Otherwise, build a new Result 
+	 * object out of the input, with the additional step and time information: */
+	this->results->AddObject((Object*)input->SpawnResult(step,time));
+	if(input->Enum()==ControlInputEnum) this->results->AddObject((Object*)((ControlInput*)input)->SpawnGradient(step,time));
+}
+/*}}}*/
 /*FUNCTION Tria::InputUpdateFromConstant(int value, int name);{{{1*/
 void  Tria::InputUpdateFromConstant(int constant, int name){
@@ -362,4 +3513,151 @@
 	/*update input*/
 	this->inputs->AddInput(new BoolInput(name,constant));
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromIoModel{{{1*/
+void Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){ //i is the element index
+
+	/*Intermediaries*/
+	int    i,j;
+	int    tria_vertex_ids[3];
+	double nodeinputs[3];
+
+	/*Checks if debuging*/
+	/*{{{2*/
+	ISSMASSERT(iomodel->elements);
+	/*}}}*/
+
+	/*Recover vertices ids needed to initialize inputs*/
+	for(i=0;i<3;i++){ 
+		tria_vertex_ids[i]=(int)iomodel->elements[3*index+i]; //ids for vertices are in the elements array from Matlab
+	}
+
+	/*add as many inputs per element as requested:*/
+	if (iomodel->thickness) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(ThicknessEnum,nodeinputs));
+	}
+	if (iomodel->surface) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->surface[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(SurfaceEnum,nodeinputs));
+	}
+	if (iomodel->bed) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->bed[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(BedEnum,nodeinputs));
+	}
+	if (iomodel->drag_coefficient) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->drag_coefficient[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(DragCoefficientEnum,nodeinputs));
+
+		if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
+		if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
+		this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
+	}
+	if (iomodel->thickness_obs) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness_obs[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(ThicknessObsEnum,nodeinputs));
+	}
+	if (iomodel->melting_rate) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->melting_rate[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(MeltingRateEnum,nodeinputs));
+	}
+	if (iomodel->accumulation_rate) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->accumulation_rate[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(AccumulationRateEnum,nodeinputs));
+	}
+	if (iomodel->geothermalflux) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->geothermalflux[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(GeothermalFluxEnum,nodeinputs));
+	}
+	if (iomodel->dhdt){
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->dhdt[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(DhDtEnum,nodeinputs));
+	}
+	if (iomodel->pressure){
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->pressure[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(PressureEnum,nodeinputs));
+	}
+	if (iomodel->temperature) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->temperature[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(TemperatureEnum,nodeinputs));
+	}
+	/*vx,vy and vz: */
+	if (iomodel->vx) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(VxEnum,nodeinputs));
+		this->inputs->AddInput(new TriaVertexInput(VxOldEnum,nodeinputs));
+		if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVxEnum,nodeinputs));
+	}
+	if (iomodel->vy) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(VyEnum,nodeinputs));
+		this->inputs->AddInput(new TriaVertexInput(VyOldEnum,nodeinputs));
+		if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVyEnum,nodeinputs));
+	}
+	if (iomodel->vz) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(VzEnum,nodeinputs));
+		this->inputs->AddInput(new TriaVertexInput(VzOldEnum,nodeinputs));
+		if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVzEnum,nodeinputs));
+	}
+	if (iomodel->vx_obs) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx_obs[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(VxObsEnum,nodeinputs));
+	}
+	if (iomodel->vy_obs) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy_obs[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(VyObsEnum,nodeinputs));
+	}
+	if (iomodel->vz_obs) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz_obs[tria_vertex_ids[i]-1]/iomodel->yts;
+		this->inputs->AddInput(new TriaVertexInput(VzObsEnum,nodeinputs));
+	}
+	if (iomodel->weights) {
+		for(i=0;i<3;i++)nodeinputs[i]=iomodel->weights[tria_vertex_ids[i]-1];
+		this->inputs->AddInput(new TriaVertexInput(WeightsEnum,nodeinputs));
+	}
+	if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
+	if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
+	if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
+	if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
+
+	/*time: */
+	this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
+
+	/*Control Inputs*/
+	if (iomodel->control_analysis && iomodel->control_type){
+		for(i=0;i<iomodel->num_control_type;i++){
+			switch((int)iomodel->control_type[i]){
+				case DhDtEnum:
+					if (iomodel->dhdt){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->dhdt[tria_vertex_ids[j]-1]/iomodel->yts;
+						this->inputs->AddInput(new ControlInput(DhDtEnum,TriaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case VxEnum:
+					if (iomodel->vx){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->vx[tria_vertex_ids[j]-1]/iomodel->yts;
+						this->inputs->AddInput(new ControlInput(VxEnum,TriaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case VyEnum:
+					if (iomodel->vy){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->vy[tria_vertex_ids[j]-1]/iomodel->yts;
+						this->inputs->AddInput(new ControlInput(VyEnum,TriaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case DragCoefficientEnum:
+					if (iomodel->drag_coefficient){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->drag_coefficient[tria_vertex_ids[j]-1];
+						this->inputs->AddInput(new ControlInput(DragCoefficientEnum,TriaVertexInputEnum,nodeinputs,i+1));
+					}
+					break;
+				case RheologyBbarEnum:
+					/*Matice will take care of it*/ break;
+				default:
+					ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
+			}
+		}
+	}
 }
 /*}}}*/
@@ -411,4 +3709,209 @@
 }
 /*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionAdjointBalancedthickness {{{1*/
+void  Tria::InputUpdateFromSolutionAdjointBalancedthickness(double* solution){
+
+	const int numdof=NDOF1*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	double    values[numdof];
+	double    lambda[NUMVERTICES];
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<numdof;i++) lambda[i]=values[i];
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaVertexInput(AdjointEnum,lambda));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionAdjointHoriz {{{1*/
+void  Tria::InputUpdateFromSolutionAdjointHoriz(double* solution){
+
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	double    values[numdof];
+	double    lambdax[NUMVERTICES];
+	double    lambday[NUMVERTICES];
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		lambdax[i]=values[i*NDOF2+0];
+		lambday[i]=values[i*NDOF2+1];
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaVertexInput(AdjointxEnum,lambdax));
+	this->inputs->AddInput(new TriaVertexInput(AdjointyEnum,lambday));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
+void  Tria::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
+	
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int       i;
+	int       dummy;
+	int*      doflist=NULL;
+	double    rho_ice,g;
+	double    values[numdof];
+	double    vx[NUMVERTICES];
+	double    vy[NUMVERTICES];
+	double    vz[NUMVERTICES];
+	double    vel[NUMVERTICES];
+	double    pressure[NUMVERTICES];
+	double    thickness[NUMVERTICES];
+	
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=values[i*NDOF2+0];
+		vy[i]=values[i*NDOF2+1];
+	}
+
+	/*Get Vz and compute vel*/
+	GetParameterListOnVertices(&vz[0],VzEnum,0);
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D, 
+	 *so the pressure is just the pressure at the bedrock: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetParameterListOnVertices(&thickness[0],ThicknessEnum);
+	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHutter {{{1*/
+void  Tria::InputUpdateFromSolutionDiagnosticHutter(double* solution){
+	
+	const int numdof=NDOF2*NUMVERTICES;
+	
+	int       i;
+	int       dummy;
+	int*      doflist=NULL;
+	double    rho_ice,g;
+	double    values[numdof];
+	double    vx[NUMVERTICES];
+	double    vy[NUMVERTICES];
+	double    vz[NUMVERTICES];
+	double    vel[NUMVERTICES];
+	double    pressure[NUMVERTICES];
+	double    thickness[NUMVERTICES];
+	double*   vz_ptr=NULL;
+	Input*    vz_input=NULL;
+	
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=values[i*NDOF2+0];
+		vy[i]=values[i*NDOF2+1];
+	}
+
+	/*Get Vz*/
+	vz_input=inputs->GetInput(VzEnum);
+	if (vz_input){
+		if (vz_input->Enum()!=TriaVertexInputEnum){
+			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
+		}
+		vz_input->GetValuesPtr(&vz_ptr,&dummy);
+		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
+	}
+	else{
+		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
+	}
+
+	/*Now Compute vel*/
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D, 
+	 *so the pressure is just the pressure at the bedrock: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetParameterListOnVertices(&thickness[0],ThicknessEnum);
+	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
+
+	/*Now, we have to move the previous Vx and Vy inputs  to old 
+	 * status, otherwise, we'll wipe them off: */
+	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
+	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
+	this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
+	this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
+	this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionOneDof{{{1*/
+void  Tria::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
+
+	const int numdof          = NDOF1*NUMVERTICES;
+
+	int*      doflist=NULL;
+	double    values[numdof];
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new TriaVertexInput(enum_type,values));
+
+	/*Free ressources:*/
+	xfree((void**)&doflist);
+}
+/*}}}*/
 /*FUNCTION Tria::InputUpdateFromVector(double* vector, int name, int type);{{{1*/
 void  Tria::InputUpdateFromVector(double* vector, int name, int type){
@@ -535,305 +4038,327 @@
 }
 /*}}}*/
-/*FUNCTION Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){{{1*/
-void Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){ //i is the element index
-
-	/*Intermediaries*/
-	int    i,j;
-	int    tria_vertex_ids[3];
-	double nodeinputs[3];
-
-	/*Checks if debuging*/
-	/*{{{2*/
-	ISSMASSERT(iomodel->elements);
-	/*}}}*/
-
-	/*Recover vertices ids needed to initialize inputs*/
-	for(i=0;i<3;i++){ 
-		tria_vertex_ids[i]=(int)iomodel->elements[3*index+i]; //ids for vertices are in the elements array from Matlab
-	}
-
-	/*add as many inputs per element as requested:*/
-	if (iomodel->thickness) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(ThicknessEnum,nodeinputs));
-	}
-	if (iomodel->surface) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->surface[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(SurfaceEnum,nodeinputs));
-	}
-	if (iomodel->bed) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->bed[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(BedEnum,nodeinputs));
-	}
-	if (iomodel->drag_coefficient) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->drag_coefficient[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(DragCoefficientEnum,nodeinputs));
-
-		if (iomodel->drag_p) this->inputs->AddInput(new DoubleInput(DragPEnum,iomodel->drag_p[index]));
-		if (iomodel->drag_q) this->inputs->AddInput(new DoubleInput(DragQEnum,iomodel->drag_q[index]));
-		this->inputs->AddInput(new IntInput(DragTypeEnum,iomodel->drag_type));
-	}
-	if (iomodel->thickness_obs) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->thickness_obs[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(ThicknessObsEnum,nodeinputs));
-	}
-	if (iomodel->melting_rate) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->melting_rate[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(MeltingRateEnum,nodeinputs));
-	}
-	if (iomodel->accumulation_rate) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->accumulation_rate[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(AccumulationRateEnum,nodeinputs));
-	}
-	if (iomodel->geothermalflux) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->geothermalflux[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(GeothermalFluxEnum,nodeinputs));
-	}
-	if (iomodel->dhdt){
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->dhdt[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(DhDtEnum,nodeinputs));
-	}
-	if (iomodel->pressure){
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->pressure[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(PressureEnum,nodeinputs));
-	}
-	if (iomodel->temperature) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->temperature[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(TemperatureEnum,nodeinputs));
-	}
-	/*vx,vy and vz: */
-	if (iomodel->vx) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(VxEnum,nodeinputs));
-		this->inputs->AddInput(new TriaVertexInput(VxOldEnum,nodeinputs));
-		if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVxEnum,nodeinputs));
-	}
-	if (iomodel->vy) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(VyEnum,nodeinputs));
-		this->inputs->AddInput(new TriaVertexInput(VyOldEnum,nodeinputs));
-		if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVyEnum,nodeinputs));
-	}
-	if (iomodel->vz) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(VzEnum,nodeinputs));
-		this->inputs->AddInput(new TriaVertexInput(VzOldEnum,nodeinputs));
-		if(iomodel->qmu_analysis)this->inputs->AddInput(new TriaVertexInput(QmuVzEnum,nodeinputs));
-	}
-	if (iomodel->vx_obs) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vx_obs[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(VxObsEnum,nodeinputs));
-	}
-	if (iomodel->vy_obs) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vy_obs[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(VyObsEnum,nodeinputs));
-	}
-	if (iomodel->vz_obs) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->vz_obs[tria_vertex_ids[i]-1]/iomodel->yts;
-		this->inputs->AddInput(new TriaVertexInput(VzObsEnum,nodeinputs));
-	}
-	if (iomodel->weights) {
-		for(i=0;i<3;i++)nodeinputs[i]=iomodel->weights[tria_vertex_ids[i]-1];
-		this->inputs->AddInput(new TriaVertexInput(WeightsEnum,nodeinputs));
-	}
-	if (iomodel->elementoniceshelf) this->inputs->AddInput(new BoolInput(ElementOnIceShelfEnum,(IssmBool)iomodel->elementoniceshelf[index]));
-	if (iomodel->elementonbed) this->inputs->AddInput(new BoolInput(ElementOnBedEnum,(IssmBool)iomodel->elementonbed[index]));
-	if (iomodel->elementonwater) this->inputs->AddInput(new BoolInput(ElementOnWaterEnum,(IssmBool)iomodel->elementonwater[index]));
-	if (iomodel->elementonsurface) this->inputs->AddInput(new BoolInput(ElementOnSurfaceEnum,(IssmBool)iomodel->elementonsurface[index]));
-
-	/*time: */
-	this->inputs->AddInput(new DoubleInput(DtEnum,iomodel->dt*iomodel->yts));
-
-	/*Control Inputs*/
-	if (iomodel->control_analysis && iomodel->control_type){
-		for(i=0;i<iomodel->num_control_type;i++){
-			switch((int)iomodel->control_type[i]){
-				case DhDtEnum:
-					if (iomodel->dhdt){
-						for(j=0;j<3;j++)nodeinputs[j]=iomodel->dhdt[tria_vertex_ids[j]-1]/iomodel->yts;
-						this->inputs->AddInput(new ControlInput(DhDtEnum,TriaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case VxEnum:
-					if (iomodel->vx){
-						for(j=0;j<3;j++)nodeinputs[j]=iomodel->vx[tria_vertex_ids[j]-1]/iomodel->yts;
-						this->inputs->AddInput(new ControlInput(VxEnum,TriaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case VyEnum:
-					if (iomodel->vy){
-						for(j=0;j<3;j++)nodeinputs[j]=iomodel->vy[tria_vertex_ids[j]-1]/iomodel->yts;
-						this->inputs->AddInput(new ControlInput(VyEnum,TriaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case DragCoefficientEnum:
-					if (iomodel->drag_coefficient){
-						for(j=0;j<3;j++)nodeinputs[j]=iomodel->drag_coefficient[tria_vertex_ids[j]-1];
-						this->inputs->AddInput(new ControlInput(DragCoefficientEnum,TriaVertexInputEnum,nodeinputs,i+1));
-					}
-					break;
-				case RheologyBbarEnum:
-					/*Matice will take care of it*/ break;
-				default:
-					ISSMERROR("Control %s not implemented yet",EnumToString((int)iomodel->control_type[i]));
-			}
-		}
-	}
-}
-/*}}}*/
-
-/*Element virtual functions definitions: */
-/*FUNCTION Tria::AverageOntoPartition {{{1*/
-void  Tria::AverageOntoPartition(Vec partition_contributions,Vec partition_areas,double* vertex_response,double* qmu_part){
-
-	bool      already=false;
-	int       i,j;
-	int       partition[NUMVERTICES];
-	int       offsetsid[NUMVERTICES];
-	int       offsetdof[NUMVERTICES];
-	double    area;
-	double    mean;
-	double    values[3];
-
-	/*First, get the area: */
-	area=this->GetArea();
-
-	/*Figure out the average for this element: */
-	this->GetSidList(&offsetsid[0]);
-	this->GetDofList1(&offsetdof[0]);
-	mean=0;
-	for(i=0;i<NUMVERTICES;i++){
-		partition[i]=(int)qmu_part[offsetsid[i]];
-		mean=mean+1.0/NUMVERTICES*vertex_response[offsetdof[i]];
-	}
-
-	/*Add contribution: */
-	for(i=0;i<NUMVERTICES;i++){
-		already=false;
-		for(j=0;j<i;j++){
-			if (partition[i]==partition[j]){
-				already=true;
-				break;
-			}
-		}
-		if(!already){
-			VecSetValue(partition_contributions,partition[i],mean*area,ADD_VALUES);
-			VecSetValue(partition_areas,partition[i],area,ADD_VALUES);
-		};
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::ComputeBasalStress {{{1*/
-void  Tria::ComputeBasalStress(Vec eps){
-	ISSMERROR("Not Implemented yet");
-}
-/*}}}*/
-/*FUNCTION Tria::ComputeStrainRate {{{1*/
-void  Tria::ComputeStrainRate(Vec eps){
-	ISSMERROR("Not Implemented yet");
-}
-/*}}}*/
-/*FUNCTION Tria::SetCurrentConfiguration {{{1*/
-void  Tria::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+/*FUNCTION Tria::IsInput{{{1*/
+bool Tria::IsInput(int name){
+	if (
+				name==ThicknessEnum ||
+				name==SurfaceEnum ||
+				name==BedEnum ||
+				name==SurfaceSlopeXEnum ||
+				name==SurfaceSlopeYEnum ||
+				name==MeltingRateEnum ||
+				name==DtEnum ||
+				name==AccumulationRateEnum ||
+				name==SurfaceAreaEnum||
+				name==VxEnum ||
+				name==VyEnum ||
+				name==VxObsEnum ||
+				name==VyObsEnum ||
+				name==CmResponseEnum ||
+				name==DragCoefficientEnum ||
+				name==GradientEnum ||
+				name==OldGradientEnum
+		){
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Tria::IsOnBed {{{1*/
+bool Tria::IsOnBed(){
 	
-	/*go into parameters and get the analysis_counter: */
-	int analysis_counter;
-	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
-
-	/*Get Element type*/
-	this->element_type=this->element_type_list[analysis_counter];
-
-	/*Pick up nodes*/
-	if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
-	else this->nodes=NULL;
-
-}
-/*}}}*/
-/*FUNCTION Tria::Configure {{{1*/
-void  Tria::Configure(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
-	
-	/*go into parameters and get the analysis_counter: */
-	int analysis_counter;
-	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
-
-	/*Get Element type*/
-	this->element_type=this->element_type_list[analysis_counter];
-
-	/*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective 
-	 * datasets, using internal ids and offsets hidden in hooks: */
-	if(this->hnodes[analysis_counter]) this->hnodes[analysis_counter]->configure(nodesin);
-	this->hmatice->configure(materialsin);
-	this->hmatpar->configure(materialsin);
-
-	/*Now, go pick up the objects inside the hooks: */
-	if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
-	else this->nodes=NULL;
-	this->matice=(Matice*)this->hmatice->delivers();
-	this->matpar=(Matpar*)this->hmatpar->delivers();
-
-	/*point parameters to real dataset: */
-	this->parameters=parametersin;
-
-}
-/*}}}*/
-/*FUNCTION Tria::ControlInputGetGradient{{{1*/
-void Tria::ControlInputGetGradient(Vec gradient,int enum_type){
-
-	int doflist1[NUMVERTICES];
-	Input* input=NULL;
-
-	if(enum_type==RheologyBbarEnum){
-		input=(Input*)matice->inputs->GetInput(enum_type);
-	}
-	else{
-		input=inputs->GetInput(enum_type);
-	}
-	if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
-	if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
-
-	this->GetDofList1(&doflist1[0]);
-	((ControlInput*)input)->GetGradient(gradient,&doflist1[0]);
-
-}/*}}}*/
-/*FUNCTION Tria::ControlInputScaleGradient{{{1*/
-void Tria::ControlInputScaleGradient(int enum_type,double scale){
-
-	Input* input=NULL;
-
-	if(enum_type==RheologyBbarEnum){
-		input=(Input*)matice->inputs->GetInput(enum_type);
-	}
-	else{
-		input=inputs->GetInput(enum_type);
-	}
-	if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
-	if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
-
-	((ControlInput*)input)->ScaleGradient(scale);
-}/*}}}*/
-/*FUNCTION Tria::ControlInputSetGradient{{{1*/
-void Tria::ControlInputSetGradient(double* gradient,int enum_type){
-
-	int    doflist1[NUMVERTICES];
-	double grad_list[NUMVERTICES];
-	Input* grad_input=NULL;
-	Input* input=NULL;
-
-	if(enum_type==RheologyBbarEnum){
-		input=(Input*)matice->inputs->GetInput(enum_type);
-	}
-	else{
-		input=inputs->GetInput(enum_type);
-	}
-	if (!input) ISSMERROR("Input %s not found",EnumToString(enum_type));
-	if (input->Enum()!=ControlInputEnum) ISSMERROR("Input %s is not a ControlInput",EnumToString(enum_type));
-
-	this->GetDofList1(&doflist1[0]);
-	for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[doflist1[i]];
-	grad_input=new TriaVertexInput(GradientEnum,grad_list);
-
-	((ControlInput*)input)->SetGradient(grad_input);
-
-}/*}}}*/
+	bool onbed;
+	inputs->GetParameterValue(&onbed,ElementOnBedEnum);
+	return onbed;
+}
+/*}}}*/
+/*FUNCTION Tria::IsOnShelf {{{1*/
+bool   Tria::IsOnShelf(){
+
+	bool shelf;
+	inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
+	return shelf;
+}
+/*}}}*/
+/*FUNCTION Tria::IsOnWater {{{1*/
+bool   Tria::IsOnWater(){
+
+	bool water;
+	inputs->GetParameterValue(&water,ElementOnWaterEnum);
+	return water;
+}
+/*}}}*/
+/*FUNCTION Tria::MassFlux {{{1*/
+double Tria::MassFlux( double* segment,bool process_units){
+
+	const int    numdofs=2;
+
+	int        i;
+	double     mass_flux=0;
+	double     xyz_list[NUMVERTICES][3];
+	double     normal[2];
+	double     length,rho_ice;
+	double     x1,y1,x2,y2,h1,h2;
+	double     vx1,vx2,vy1,vy2;
+	GaussTria* gauss_1=NULL;
+	GaussTria* gauss_2=NULL;
+
+	/*Get material parameters :*/
+	rho_ice=matpar->GetRhoIce();
+
+	/*First off, check that this segment belongs to this element: */
+	if ((int)*(segment+4)!=this->id)ISSMERROR("%s%i%s%i","error message: segment with id ",(int)*(segment+4)," does not belong to element with id:",this->id);
+
+	/*Recover segment node locations: */
+	x1=*(segment+0); y1=*(segment+1); x2=*(segment+2); y2=*(segment+3);
+
+	/*Get xyz list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*get area coordinates of 0 and 1 locations: */
+	gauss_1=new GaussTria();
+	gauss_1->GaussFromCoords(x1,y1,&xyz_list[0][0]);
+	gauss_2=new GaussTria();
+	gauss_2->GaussFromCoords(x2,y2,&xyz_list[0][0]);
+
+	normal[0]=cos(atan2(x1-x2,y2-y1));
+	normal[1]=sin(atan2(x1-x2,y2-y1));
+
+	length=sqrt(pow(x2-x1,2.0)+pow(y2-y1,2));
+
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
+	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
+
+	thickness_input->GetParameterValue(&h1, gauss_1);
+	thickness_input->GetParameterValue(&h2, gauss_2);
+	vx_input->GetParameterValue(&vx1,gauss_1);
+	vx_input->GetParameterValue(&vx2,gauss_2);
+	vy_input->GetParameterValue(&vy1,gauss_1);
+	vy_input->GetParameterValue(&vy2,gauss_2);
+
+	mass_flux= rho_ice*length*(  
+				(ONETHIRD*(h1-h2)*(vx1-vx2)+0.5*h2*(vx1-vx2)+0.5*(h1-h2)*vx2+h2*vx2)*normal[0]+
+				(ONETHIRD*(h1-h2)*(vy1-vy2)+0.5*h2*(vy1-vy2)+0.5*(h1-h2)*vy2+h2*vy2)*normal[1]
+				);
+
+	/*Process units: */
+	mass_flux=UnitConversion(mass_flux,IuToExtEnum,MassFluxEnum,this->parameters);
+
+	/*clean up and return:*/
+	delete gauss_1;
+	delete gauss_2;
+	return mass_flux;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxAbsVx{{{1*/
+void  Tria::MaxAbsVx(double* pmaxabsvx, bool process_units){
+
+	/*Get maximum:*/
+	double maxabsvx=this->inputs->MaxAbs(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvx=UnitConversion(maxabsvx,IuToExtEnum,VxEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxabsvx=maxabsvx;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxAbsVy{{{1*/
+void  Tria::MaxAbsVy(double* pmaxabsvy, bool process_units){
+
+	/*Get maximum:*/
+	double maxabsvy=this->inputs->MaxAbs(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvy=UnitConversion(maxabsvy,IuToExtEnum,VyEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxabsvy=maxabsvy;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxAbsVz{{{1*/
+void  Tria::MaxAbsVz(double* pmaxabsvz, bool process_units){
+
+	/*Get maximum:*/
+	double maxabsvz=this->inputs->MaxAbs(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvz=UnitConversion(maxabsvz,IuToExtEnum,VyEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxabsvz=maxabsvz;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVel{{{1*/
+void  Tria::MaxVel(double* pmaxvel, bool process_units){
+
+	/*Get maximum:*/
+	double maxvel=this->inputs->Max(VelEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvel=UnitConversion(maxvel,IuToExtEnum,VelEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxvel=maxvel;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVx{{{1*/
+void  Tria::MaxVx(double* pmaxvx, bool process_units){
+
+	/*Get maximum:*/
+	double maxvx=this->inputs->Max(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvx=UnitConversion(maxvx,IuToExtEnum,VxEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxvx=maxvx;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVy{{{1*/
+void  Tria::MaxVy(double* pmaxvy, bool process_units){
+
+	/*Get maximum:*/
+	double maxvy=this->inputs->Max(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvy=UnitConversion(maxvy,IuToExtEnum,VyEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxvy=maxvy;
+
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVz{{{1*/
+void  Tria::MaxVz(double* pmaxvz, bool process_units){
+
+	/*Get maximum:*/
+	double maxvz=this->inputs->Max(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvz=UnitConversion(maxvz,IuToExtEnum,VzEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pmaxvz=maxvz;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVel{{{1*/
+void  Tria::MinVel(double* pminvel, bool process_units){
+
+	/*Get minimum:*/
+	double minvel=this->inputs->Min(VelEnum);
+
+	/*process units if requested: */
+	if(process_units) minvel=UnitConversion(minvel,IuToExtEnum,VelEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pminvel=minvel;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVx{{{1*/
+void  Tria::MinVx(double* pminvx, bool process_units){
+
+	/*Get minimum:*/
+	double minvx=this->inputs->Min(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) minvx=UnitConversion(minvx,IuToExtEnum,VxEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pminvx=minvx;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVy{{{1*/
+void  Tria::MinVy(double* pminvy, bool process_units){
+
+	/*Get minimum:*/
+	double minvy=this->inputs->Min(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) minvy=UnitConversion(minvy,IuToExtEnum,VyEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pminvy=minvy;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVz{{{1*/
+void  Tria::MinVz(double* pminvz, bool process_units){
+
+	/*Get minimum:*/
+	double minvz=this->inputs->Min(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) minvz=UnitConversion(minvz,IuToExtEnum,VzEnum,this->parameters);
+
+	/*Assign output pointers:*/
+	*pminvz=minvz;
+}
+/*}}}*/
+/*FUNCTION Tria::MyRank {{{1*/
+int    Tria::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION Tria::PatchFill{{{1*/
+void  Tria::PatchFill(int* prow, Patch* patch){
+
+	int i,row;
+	int vertices_ids[3];
+
+	/*recover pointer: */
+	row=*prow;
+		
+	for(i=0;i<3;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
+
+	for(i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+
+		/*For this result,fill the information in the Patch object (element id + vertices ids), and then hand 
+		 *it to the result object, to fill the rest: */
+		patch->fillelementinfo(row,this->id,vertices_ids,3);
+		elementresult->PatchFill(row,patch);
+
+		/*increment rower: */
+		row++;
+	}
+
+	/*Assign output pointers:*/
+	*prow=row;
+}
+/*}}}*/
+/*FUNCTION Tria::PatchSize{{{1*/
+void  Tria::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
+
+	int     i;
+	int     numrows     = 0;
+	int     numnodes    = 0;
+
+	/*Go through all the results objects, and update the counters: */
+	for (i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+		/*first, we have one more result: */
+		numrows++;
+		/*now, how many vertices and how many nodal values for this result? :*/
+		numnodes=elementresult->NumberOfNodalValues(); //ask result object.
+	}
+
+	/*Assign output pointers:*/
+	*pnumrows=numrows;
+	*pnumvertices=NUMVERTICES;
+	*pnumnodes=numnodes;
+}
+/*}}}*/
+/*FUNCTION Tria::ProcessResultsUnits{{{1*/
+void  Tria::ProcessResultsUnits(void){
+
+	int i;
+
+	for(i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+		elementresult->ProcessUnits(this->parameters);
+	}
+}
+/*}}}*/
 /*FUNCTION Tria::RegularizeInversion {{{1*/
 double Tria::RegularizeInversion(){
@@ -908,912 +4433,24 @@
 }
 /*}}}*/
-/*FUNCTION Tria::CreateKMatrix {{{1*/
-void  Tria::CreateKMatrix(Mat Kgg, Mat Kff, Mat Kfs){
-
-	/*retreive parameters: */
-	ElementMatrix* Ke=NULL;
-	int analysis_type;
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-
-	/*Checks in debugging mode{{{2*/
-	ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
-	/*}}}*/
-
-	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
-	switch(analysis_type){
-		case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
-			Ke=CreateKMatrixDiagnosticMacAyeal();
-			break;
-		case DiagnosticHutterAnalysisEnum:
-			Ke=CreateKMatrixDiagnosticHutter();
-			break;
-		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
-			Ke=CreateKMatrixSlope();
-			break;
-		case PrognosticAnalysisEnum:
-			Ke=CreateKMatrixPrognostic();
-			break;
-		case BalancedthicknessAnalysisEnum:
-			Ke=CreateKMatrixBalancedthickness();
-			break;
-		case AdjointBalancedthicknessAnalysisEnum:
-			Ke=CreateKMatrixAdjointBalancedthickness();
-			break;
-		case BalancedvelocitiesAnalysisEnum:
-			Ke=CreateKMatrixBalancedvelocities();
-			break;
-		default:
-			ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
-	}
-
-	/*Add to global matrix*/
-	if(Ke){
-		Ke->AddToGlobal(Kgg,Kff,Kfs);
-		delete Ke;
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVector {{{1*/
-void  Tria::CreatePVector(Vec pg, Vec pf){
-
-	/*retrive parameters: */
-	ElementVector* pe=NULL;
-	int analysis_type;
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-
-	/*asserts: {{{*/
-	/*if debugging mode, check that all pointers exist*/
-	ISSMASSERT(this->nodes && this->matice && this->matpar && this->parameters && this->inputs);
-	/*}}}*/
-
-	/*Just branch to the correct load generator, according to the type of analysis we are carrying out: */
-	switch(analysis_type){
-		case DiagnosticHorizAnalysisEnum:
-			pe=CreatePVectorDiagnosticMacAyeal();
-			break;
-		case AdjointHorizAnalysisEnum:
-			pe=CreatePVectorAdjointHoriz();
-			break;
-		case DiagnosticHutterAnalysisEnum:
-			pe=CreatePVectorDiagnosticHutter();
-			break;
-		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
-			pe=CreatePVectorSlope();
-			break;
-		case PrognosticAnalysisEnum:
-			pe=CreatePVectorPrognostic();
-			break;
-		case BalancedthicknessAnalysisEnum:
-			pe=CreatePVectorBalancedthickness();
-			break;
-		case AdjointBalancedthicknessAnalysisEnum:
-			pe=CreatePVectorAdjointBalancedthickness();
-			break;
-		case BalancedvelocitiesAnalysisEnum:
-			pe=CreatePVectorBalancedvelocities();
-			break;
-		default:
-			ISSMERROR("analysis %i (%s) not supported yet",analysis_type,EnumToString(analysis_type));
-	}
-
-	/*Add to global Vector*/
-	if(pe){
-		pe->AddToGlobal(pg,pf);
-		delete pe;
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::DeleteResults {{{1*/
-void  Tria::DeleteResults(void){
-
-	/*Delete and reinitialize results*/
-	delete this->results;
-	this->results=new Results();
-
-}
-/*}}}*/
-/*FUNCTION Tria::GetNodeIndex {{{1*/
-int Tria::GetNodeIndex(Node* node){
-
-	ISSMASSERT(nodes);
-	for(int i=0;i<NUMVERTICES;i++){
-		if(node==nodes[i])
-		 return i;
-	}
-	ISSMERROR("Node provided not found among element nodes");
-}
-/*}}}*/
-/*FUNCTION Tria::IsOnBed {{{1*/
-bool Tria::IsOnBed(){
+/*FUNCTION Tria::SetClone {{{1*/
+void  Tria::SetClone(int* minranks){
+
+	ISSMERROR("not implemented yet");
+}
+/*}}}1*/
+/*FUNCTION Tria::SetCurrentConfiguration {{{1*/
+void  Tria::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
 	
-	bool onbed;
-	inputs->GetParameterValue(&onbed,ElementOnBedEnum);
-	return onbed;
-}
-/*}}}*/
-/*FUNCTION Tria::IsOnShelf {{{1*/
-bool   Tria::IsOnShelf(){
-
-	bool shelf;
-	inputs->GetParameterValue(&shelf,ElementOnIceShelfEnum);
-	return shelf;
-}
-/*}}}*/
-/*FUNCTION Tria::IsOnWater {{{1*/
-bool   Tria::IsOnWater(){
-
-	bool water;
-	inputs->GetParameterValue(&water,ElementOnWaterEnum);
-	return water;
-}
-/*}}}*/
-/*FUNCTION Tria::GetSolutionFromInputs{{{1*/
-void  Tria::GetSolutionFromInputs(Vec solution){
-
-	/*retrive parameters: */
-	int analysis_type;
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	
-	/*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
-	if (analysis_type==DiagnosticHorizAnalysisEnum)
-	 GetSolutionFromInputsDiagnosticHoriz(solution);
-	else if (analysis_type==DiagnosticHutterAnalysisEnum)
-	 GetSolutionFromInputsDiagnosticHutter(solution);
-	else
-	 ISSMERROR("analysis: %s not supported yet",EnumToString(analysis_type));
-
-}
-/*}}}*/
-/*FUNCTION Tria::GetVectorFromInputs{{{1*/
-void  Tria::GetVectorFromInputs(Vec vector,int NameEnum){
-
-	int doflist1[NUMVERTICES];
-
-	/*Find NameEnum input in the inputs dataset, and get it to fill in the vector: */
-	for(int i=0;i<this->inputs->Size();i++){
-		Input* input=(Input*)this->inputs->GetObjectByOffset(i);
-		if(input->EnumType()==NameEnum){
-			/*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
-			this->GetDofList1(&doflist1[0]);
-			input->GetVectorFromInputs(vector,&doflist1[0]);
-			break;
-		}
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::Gradj {{{1*/
-void  Tria::Gradj(Vec gradient,int control_type){
-
-	/*If on water, grad = 0: */
-	if(IsOnWater())return;
-
-	switch(control_type){
-		case DragCoefficientEnum:
-			GradjDrag(gradient);
-			break;
-		case RheologyBbarEnum:
-			GradjB(gradient);
-			break;
-		case DhDtEnum:
-			GradjDhDt(gradient);
-			break;
-		case VxEnum:
-			GradjVx(gradient);
-			break;
-		case VyEnum:
-			GradjVy(gradient);
-			break;
-		default:
-			ISSMERROR("%s%i","control type not supported yet: ",control_type);
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::GradjB{{{1*/
-void  Tria::GradjB(Vec gradient){
-
-	/*Intermediaries*/
-	int        i,ig;
-	int        doflist[NUMVERTICES];
-	double     vx,vy,lambda,mu,thickness,Jdet;
-	double     cm_noisedmp,viscosity_complement;
-	double     dvx[NDOF2],dvy[NDOF2],dadjx[NDOF2],dadjy[NDOF2],dB[NDOF2]; 
-	double     xyz_list[NUMVERTICES][3];
-	double     basis[3],epsilon[3];
-	double     dbasis[NDOF2][NUMVERTICES];
-	double     grad_g[NUMVERTICES];
-	double     grad[NUMVERTICES]={0.0};
-	GaussTria *gauss = NULL;
-
-	/*retrieve some parameters: */
-	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
-
-	/* Get node coordinates and dof list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	GetDofList1(&doflist[0]);
-
-	/*Retrieve all inputs*/
-	Input* thickness_input=inputs->GetInput(ThicknessEnum);            ISSMASSERT(thickness_input);
-	Input* vx_input=inputs->GetInput(VxEnum);                          ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);                          ISSMASSERT(vy_input);
-	Input* adjointx_input=inputs->GetInput(AdjointxEnum);              ISSMASSERT(adjointx_input);
-	Input* adjointy_input=inputs->GetInput(AdjointyEnum);              ISSMASSERT(adjointy_input);
-	Input* rheologyb_input=matice->inputs->GetInput(RheologyBbarEnum); ISSMASSERT(rheologyb_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(4);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		thickness_input->GetParameterValue(&thickness,gauss);
-		rheologyb_input->GetParameterDerivativeValue(&dB[0],&xyz_list[0][0],gauss);
-		vx_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
-		vy_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
-		adjointx_input->GetParameterDerivativeValue(&dadjx[0],&xyz_list[0][0],gauss);
-		adjointy_input->GetParameterDerivativeValue(&dadjy[0],&xyz_list[0][0],gauss);
-
-		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
-		matice->GetViscosityComplement(&viscosity_complement,&epsilon[0]);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(basis,gauss);
-		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
-
-		/*standard gradient dJ/dki*/
-		for (i=0;i<NUMVERTICES;i++){
-			grad_g[i]=-viscosity_complement*thickness*( (2*dvx[0]+dvy[1])*2*dadjx[0]+(dvx[1]+dvy[0])*(dadjx[1]+dadjy[0])+(2*dvy[1]+dvx[0])*2*dadjy[1])*Jdet*gauss->weight*basis[i]; 
-		}
-		/*Add regularization term*/
-		for (i=0;i<NUMVERTICES;i++) grad_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dB[0]+dbasis[1][i]*dB[1]);
-		for(i=0;i<NUMVERTICES;i++) grad[i]+=grad_g[i];
-	}
-
-	VecSetValues(gradient,NUMVERTICES,doflist,(const double*)grad,ADD_VALUES);
-
-	/*clean-up*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::GradjDrag {{{1*/
-void  Tria::GradjDrag(Vec gradient){
-
-	int        i,ig;
-	int        drag_type,analysis_type;
-	int        doflist1[NUMVERTICES];
-	double     vx,vy,lambda,mu,alpha_complement,Jdet;
-	double     bed,thickness,Neff,drag,cm_noisedmp;
-	double     xyz_list[NUMVERTICES][3];
-	double     dh1dh3[NDOF2][NUMVERTICES];
-	double     dk[NDOF2]; 
-	double     grade_g[NUMVERTICES]={0.0};
-	double     grade_g_gaussian[NUMVERTICES];
-	double     l1l2l3[3];
-	double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
-	Friction*  friction=NULL;
-	GaussTria  *gauss=NULL;
-
-	/*retrive parameters: */
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-
-	/*retrieve some parameters ands return if iceshelf: */
-	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
-	if(IsOnShelf())return;
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	GetDofList1(&doflist1[0]);
-
-	/*Build frictoin element, needed later: */
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	friction=new Friction("2d",inputs,matpar,analysis_type);
-
-	/*Retrieve all inputs we will be needing: */
-	Input* adjointx_input=inputs->GetInput(AdjointxEnum);               ISSMASSERT(adjointx_input);
-	Input* adjointy_input=inputs->GetInput(AdjointyEnum);               ISSMASSERT(adjointy_input);
-	Input* vx_input=inputs->GetInput(VxEnum);                           ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);                           ISSMASSERT(vy_input);
-	Input* dragcoefficient_input=inputs->GetInput(DragCoefficientEnum); ISSMASSERT(dragcoefficient_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(4);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-		GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
-
-		/*Build alpha_complement_list: */
-		if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
-		else alpha_complement=0;
-	
-		dragcoefficient_input->GetParameterValue(&drag, gauss);
-		adjointx_input->GetParameterValue(&lambda, gauss);
-		adjointy_input->GetParameterValue(&mu, gauss);
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		dragcoefficient_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
-
-		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
-		for (i=0;i<NUMVERTICES;i++){
-
-			//standard term dJ/dki
-			grade_g_gaussian[i]=-2*drag*alpha_complement*((lambda*vx+mu*vy))*Jdet*gauss->weight*l1l2l3[i];
-
-			//noise dampening d/dki(1/2*(dk/dx)^2)
-			grade_g_gaussian[i]+=-cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
-		}
-		
-		/*Add gradje_g_gaussian vector to gradje_g: */
-		for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
-	}
-
-	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
-
-	/*Clean up and return*/
-	delete gauss;
-	delete friction;
-}
-/*}}}*/
-/*FUNCTION Tria::GradjDhDt{{{1*/
-void  Tria::GradjDhDt(Vec gradient){
-
-	/*Intermediaries*/
-	int    doflist1[NUMVERTICES];
-	double lambda[NUMVERTICES];
-	double gradient_g[NUMVERTICES];
-
-	GetDofList1(&doflist1[0]);
-
-	/*Compute Gradient*/
-	GetParameterListOnVertices(&lambda[0],AdjointEnum);
-	for(int i=0;i<NUMVERTICES;i++) gradient_g[i]=-lambda[i];
-
-	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)gradient_g,INSERT_VALUES);
-}
-/*}}}*/
-/*FUNCTION Tria::GradjVx{{{1*/
-void  Tria::GradjVx(Vec gradient){
-
-	/*Intermediaries*/
-	int        i,ig;
-	int        doflist1[NUMVERTICES];
-	double     thickness,Jdet,cm_noisedmp;
-	double     l1l2l3[3];
-	double     dbasis[NDOF2][NUMVERTICES];
-	double     Dlambda[2],dp[2];
-	double     xyz_list[NUMVERTICES][3];
-	double     grade_g[NUMVERTICES] = {0.0};
-	GaussTria *gauss                = NULL;
-
-	/* Get node coordinates and dof list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	GetDofList1(&doflist1[0]);
-
-	/*Retrieve all inputs we will be needing: */
-	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
-	Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
-		
-		adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
-		thickness_input->GetParameterValue(&thickness, gauss);
-		thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
-
-		for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[0]*Jdet*gauss->weight*l1l2l3[i];
-
-		//noise dampening d/dki(1/2*(dk/dx)^2)
-		//for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
-	}
-
-	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
-
-	/*Clean up and return*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::GradjVy{{{1*/
-void  Tria::GradjVy(Vec gradient){
-
-	/*Intermediaries*/
-	int        i,ig;
-	int        doflist1[NUMVERTICES];
-	double     thickness,Jdet,cm_noisedmp;
-	double     l1l2l3[3];
-	double     dbasis[NDOF2][NUMVERTICES];
-	double     Dlambda[2],dp[2];
-	double     xyz_list[NUMVERTICES][3];
-	double     grade_g[NUMVERTICES] = {0.0};
-	GaussTria *gauss                = NULL;
-
-	/* Get node coordinates and dof list: */
-	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	GetDofList1(&doflist1[0]);
-
-	/*Retrieve all inputs we will be needing: */
-	Input* adjoint_input=inputs->GetInput(AdjointEnum);     ISSMASSERT(adjoint_input);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
-
-		adjoint_input->GetParameterDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
-		thickness_input->GetParameterValue(&thickness, gauss);
-		thickness_input->GetParameterDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
-
-		for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[1]*Jdet*gauss->weight*l1l2l3[i];
-
-		//noise dampening d/dki(1/2*(dk/dx)^2)
-		//for (i=0;i<NUMVERTICES;i++) grade_g[i]-=cm_noisedmp*Jdet*gauss->weight*(dbasis[0][i]*dp[0]+dbasis[1][i]*dp[1]);
-	}
-
-	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
-
-	/*Clean up and return*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::InputControlUpdate{{{1*/
-void  Tria::InputControlUpdate(double scalar,bool save_parameter){
-
-	/*Intermediary*/
-	int    num_controls;
-	int*   control_type=NULL;
-	Input* input=NULL;
-	double *cm_min=NULL;
-	double *cm_max=NULL;
-
-	/*retrieve some parameters: */
-	this->parameters->FindParam(&cm_min,NULL,CmMinEnum);
-	this->parameters->FindParam(&cm_max,NULL,CmMaxEnum);
-	this->parameters->FindParam(&num_controls,NumControlsEnum);
-	this->parameters->FindParam(&control_type,NULL,ControlTypeEnum);
-
-	for(int i=0;i<num_controls;i++){
-
-		if(control_type[i]==RheologyBbarEnum){
-			input=(Input*)matice->inputs->GetInput(control_type[i]); ISSMASSERT(input);
-		}
-		else{
-			input=(Input*)this->inputs->GetInput(control_type[i]);   ISSMASSERT(input);
-		}
-
-		if (input->Enum()!=ControlInputEnum){
-			ISSMERROR("input %s is not a ControlInput",EnumToString(control_type[i]));
-		}
-
-		((ControlInput*)input)->UpdateValue(scalar);
-		input->Constrain(cm_min[i],cm_max[i]);
-		if (save_parameter) ((ControlInput*)input)->SaveValue();
-
-	}
-
-	/*Clean up and return*/
-	xfree((void**)&control_type);
-	xfree((void**)&cm_min);
-	xfree((void**)&cm_max);
-}
-/*}}}*/
-/*FUNCTION Tria::InputConvergence{{{1*/
-bool Tria::InputConvergence(double* eps, int* enums,int num_enums,int* criterionenums,double* criterionvalues,int num_criterionenums){
-
-	bool    converged=true;
-	int     i;
-	Input** new_inputs=NULL;
-	Input** old_inputs=NULL;
-
-	new_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the new inputs
-	old_inputs=(Input**)xmalloc(num_enums/2*sizeof(Input*)); //half the enums are for the old inputs
-
-	for(i=0;i<num_enums/2;i++){
-		new_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+0]);
-		old_inputs[i]=(Input*)this->inputs->GetInput(enums[2*i+1]);
-		if(!new_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
-		if(!old_inputs[i])ISSMERROR("%s%s"," could not find input with enum ",EnumToString(enums[2*i+0]));
-	}
-
-	/*ok, we've got the inputs (new and old), now loop throught the number of criterions and fill the eps array:*/
-	for(i=0;i<num_criterionenums;i++){
-		IsInputConverged(eps+i,new_inputs,old_inputs,num_enums/2,criterionenums[i]);
-		if(eps[i]>criterionvalues[i]) converged=false; 
-	}
-
-	/*clean up and return*/
-	xfree((void**)&new_inputs);
-	xfree((void**)&old_inputs);
-	return converged;
-}
-/*}}}*/
-/*FUNCTION Tria::InputDepthAverageAtBase {{{1*/
-void  Tria::InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum){
-
-	/*New input*/
-	Input* oldinput=NULL;
-	Input* newinput=NULL;
-
-	/*copy input of enum_type*/
-	if (object_enum==ElementsEnum)
-	 oldinput=(Input*)this->inputs->GetInput(enum_type);
-	else if (object_enum==MaterialsEnum)
-	 oldinput=(Input*)this->matice->inputs->GetInput(enum_type);
-	else
-	 ISSMERROR("object %s not supported yet",EnumToString(object_enum));
-	if(!oldinput)ISSMERROR("%s%s"," could not find old input with enum: ",EnumToString(enum_type));
-	newinput=(Input*)oldinput->copy();
-
-	/*Assign new name (average)*/
-	newinput->ChangeEnum(average_enum_type);
-
-	/*Add new input to current element*/
-	if (object_enum==ElementsEnum)
-	 this->inputs->AddInput((Input*)newinput);
-	else if (object_enum==MaterialsEnum)
-	 this->matice->inputs->AddInput((Input*)newinput);
-	else
-	 ISSMERROR("object %s not supported yet",EnumToString(object_enum));
-}
-/*}}}*/
-/*FUNCTION Tria::InputDuplicate{{{1*/
-void  Tria::InputDuplicate(int original_enum,int new_enum){
-
-	/*Call inputs method*/
-	if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
-
-}
-/*}}}*/
-/*FUNCTION Tria::InputScale{{{1*/
-void  Tria::InputScale(int enum_type,double scale_factor){
-
-	Input* input=NULL;
-
-	/*Make a copy of the original input: */
-	input=(Input*)this->inputs->GetInput(enum_type);
-	if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
-
-	/*Scale: */
-	input->Scale(scale_factor);
-}
-/*}}}*/
-/*FUNCTION Tria::InputArtificialNoise{{{1*/
-void  Tria::InputArtificialNoise(int enum_type,double min,double max){
-
-	Input* input=NULL;
-
-	/*Make a copy of the original input: */
-	input=(Input*)this->inputs->GetInput(enum_type);
-	if(!input)ISSMERROR(" could not find old input with enum: %s",EnumToString(enum_type));
-
-	/*ArtificialNoise: */
-	input->ArtificialNoise(min,max);
-}
-/*}}}*/
-/*FUNCTION Tria::InputToResult{{{1*/
-void  Tria::InputToResult(int enum_type,int step,double time){
-
-	int    i;
-	Input *input = NULL;
-
-	/*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
-	if (enum_type==RheologyBbarEnum) input=this->matice->inputs->GetInput(enum_type);
-	else input=this->inputs->GetInput(enum_type);
-	if (!input) ISSMERROR("Input %s not found in tria->inputs",EnumToString(enum_type));
-
-	/*If we don't find it, no big deal, just don't do the transfer. Otherwise, build a new Result 
-	 * object out of the input, with the additional step and time information: */
-	this->results->AddObject((Object*)input->SpawnResult(step,time));
-	if(input->Enum()==ControlInputEnum) this->results->AddObject((Object*)((ControlInput*)input)->SpawnGradient(step,time));
-}
-/*}}}*/
-/*FUNCTION Tria::MassFlux {{{1*/
-double Tria::MassFlux( double* segment,bool process_units){
-
-	const int    numdofs=2;
-
-	int        i;
-	double     mass_flux=0;
-	double     xyz_list[NUMVERTICES][3];
-	double     normal[2];
-	double     length,rho_ice;
-	double     x1,y1,x2,y2,h1,h2;
-	double     vx1,vx2,vy1,vy2;
-	GaussTria* gauss_1=NULL;
-	GaussTria* gauss_2=NULL;
-
-	/*Get material parameters :*/
-	rho_ice=matpar->GetRhoIce();
-
-	/*First off, check that this segment belongs to this element: */
-	if ((int)*(segment+4)!=this->id)ISSMERROR("%s%i%s%i","error message: segment with id ",(int)*(segment+4)," does not belong to element with id:",this->id);
-
-	/*Recover segment node locations: */
-	x1=*(segment+0); y1=*(segment+1); x2=*(segment+2); y2=*(segment+3);
-
-	/*Get xyz list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*get area coordinates of 0 and 1 locations: */
-	gauss_1=new GaussTria();
-	gauss_1->GaussFromCoords(x1,y1,&xyz_list[0][0]);
-	gauss_2=new GaussTria();
-	gauss_2->GaussFromCoords(x2,y2,&xyz_list[0][0]);
-
-	normal[0]=cos(atan2(x1-x2,y2-y1));
-	normal[1]=sin(atan2(x1-x2,y2-y1));
-
-	length=sqrt(pow(x2-x1,2.0)+pow(y2-y1,2));
-
-	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-
-	thickness_input->GetParameterValue(&h1, gauss_1);
-	thickness_input->GetParameterValue(&h2, gauss_2);
-	vx_input->GetParameterValue(&vx1,gauss_1);
-	vx_input->GetParameterValue(&vx2,gauss_2);
-	vy_input->GetParameterValue(&vy1,gauss_1);
-	vy_input->GetParameterValue(&vy2,gauss_2);
-
-	mass_flux= rho_ice*length*(  
-				(ONETHIRD*(h1-h2)*(vx1-vx2)+0.5*h2*(vx1-vx2)+0.5*(h1-h2)*vx2+h2*vx2)*normal[0]+
-				(ONETHIRD*(h1-h2)*(vy1-vy2)+0.5*h2*(vy1-vy2)+0.5*(h1-h2)*vy2+h2*vy2)*normal[1]
-				);
-
-	/*Process units: */
-	mass_flux=UnitConversion(mass_flux,IuToExtEnum,MassFluxEnum,this->parameters);
-
-	/*clean up and return:*/
-	delete gauss_1;
-	delete gauss_2;
-	return mass_flux;
-}
-/*}}}*/
-/*FUNCTION Tria::MaxAbsVx{{{1*/
-void  Tria::MaxAbsVx(double* pmaxabsvx, bool process_units){
-
-	/*Get maximum:*/
-	double maxabsvx=this->inputs->MaxAbs(VxEnum);
-
-	/*process units if requested: */
-	if(process_units) maxabsvx=UnitConversion(maxabsvx,IuToExtEnum,VxEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxabsvx=maxabsvx;
-}
-/*}}}*/
-/*FUNCTION Tria::MaxAbsVy{{{1*/
-void  Tria::MaxAbsVy(double* pmaxabsvy, bool process_units){
-
-	/*Get maximum:*/
-	double maxabsvy=this->inputs->MaxAbs(VyEnum);
-
-	/*process units if requested: */
-	if(process_units) maxabsvy=UnitConversion(maxabsvy,IuToExtEnum,VyEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxabsvy=maxabsvy;
-}
-/*}}}*/
-/*FUNCTION Tria::MaxAbsVz{{{1*/
-void  Tria::MaxAbsVz(double* pmaxabsvz, bool process_units){
-
-	/*Get maximum:*/
-	double maxabsvz=this->inputs->MaxAbs(VzEnum);
-
-	/*process units if requested: */
-	if(process_units) maxabsvz=UnitConversion(maxabsvz,IuToExtEnum,VyEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxabsvz=maxabsvz;
-}
-/*}}}*/
-/*FUNCTION Tria::MaxVel{{{1*/
-void  Tria::MaxVel(double* pmaxvel, bool process_units){
-
-	/*Get maximum:*/
-	double maxvel=this->inputs->Max(VelEnum);
-
-	/*process units if requested: */
-	if(process_units) maxvel=UnitConversion(maxvel,IuToExtEnum,VelEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxvel=maxvel;
-}
-/*}}}*/
-/*FUNCTION Tria::MaxVx{{{1*/
-void  Tria::MaxVx(double* pmaxvx, bool process_units){
-
-	/*Get maximum:*/
-	double maxvx=this->inputs->Max(VxEnum);
-
-	/*process units if requested: */
-	if(process_units) maxvx=UnitConversion(maxvx,IuToExtEnum,VxEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxvx=maxvx;
-}
-/*}}}*/
-/*FUNCTION Tria::MaxVy{{{1*/
-void  Tria::MaxVy(double* pmaxvy, bool process_units){
-
-	/*Get maximum:*/
-	double maxvy=this->inputs->Max(VyEnum);
-
-	/*process units if requested: */
-	if(process_units) maxvy=UnitConversion(maxvy,IuToExtEnum,VyEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxvy=maxvy;
-
-}
-/*}}}*/
-/*FUNCTION Tria::MaxVz{{{1*/
-void  Tria::MaxVz(double* pmaxvz, bool process_units){
-
-	/*Get maximum:*/
-	double maxvz=this->inputs->Max(VzEnum);
-
-	/*process units if requested: */
-	if(process_units) maxvz=UnitConversion(maxvz,IuToExtEnum,VzEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pmaxvz=maxvz;
-}
-/*}}}*/
-/*FUNCTION Tria::MinVel{{{1*/
-void  Tria::MinVel(double* pminvel, bool process_units){
-
-	/*Get minimum:*/
-	double minvel=this->inputs->Min(VelEnum);
-
-	/*process units if requested: */
-	if(process_units) minvel=UnitConversion(minvel,IuToExtEnum,VelEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pminvel=minvel;
-}
-/*}}}*/
-/*FUNCTION Tria::MinVx{{{1*/
-void  Tria::MinVx(double* pminvx, bool process_units){
-
-	/*Get minimum:*/
-	double minvx=this->inputs->Min(VxEnum);
-
-	/*process units if requested: */
-	if(process_units) minvx=UnitConversion(minvx,IuToExtEnum,VxEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pminvx=minvx;
-}
-/*}}}*/
-/*FUNCTION Tria::MinVy{{{1*/
-void  Tria::MinVy(double* pminvy, bool process_units){
-
-	/*Get minimum:*/
-	double minvy=this->inputs->Min(VyEnum);
-
-	/*process units if requested: */
-	if(process_units) minvy=UnitConversion(minvy,IuToExtEnum,VyEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pminvy=minvy;
-}
-/*}}}*/
-/*FUNCTION Tria::MinVz{{{1*/
-void  Tria::MinVz(double* pminvz, bool process_units){
-
-	/*Get minimum:*/
-	double minvz=this->inputs->Min(VzEnum);
-
-	/*process units if requested: */
-	if(process_units) minvz=UnitConversion(minvz,IuToExtEnum,VzEnum,this->parameters);
-
-	/*Assign output pointers:*/
-	*pminvz=minvz;
-}
-/*}}}*/
-/*FUNCTION Tria::TimeAdapt{{{1*/
-double  Tria::TimeAdapt(void){
-
-	/*intermediary: */
-	int    i;
-	double C,dt;
-	double dx,dy;
-	double maxx,minx;
-	double maxy,miny;
-	double maxabsvx,maxabsvy;
-	double xyz_list[NUMVERTICES][3];
-
-	/*get CFL coefficient:*/
-	this->parameters->FindParam(&C,CflCoefficientEnum);
-
-	/*Get for Vx and Vy, the max of abs value: */
-	this->MaxAbsVx(&maxabsvx,false);
-	this->MaxAbsVy(&maxabsvy,false);
-
-	/* Get node coordinates and dof list: */
-	GetVerticesCoordinates(&xyz_list[0][0], this->nodes, NUMVERTICES);
-
-	minx=xyz_list[0][0];
-	maxx=xyz_list[0][0];
-	miny=xyz_list[0][1];
-	maxy=xyz_list[0][1];
-	
-	for(i=1;i<NUMVERTICES;i++){
-		if (xyz_list[i][0]<minx)minx=xyz_list[i][0];
-		if (xyz_list[i][0]>maxx)maxx=xyz_list[i][0];
-		if (xyz_list[i][1]<miny)miny=xyz_list[i][1];
-		if (xyz_list[i][1]>maxy)maxy=xyz_list[i][1];
-	}
-	dx=maxx-minx;
-	dy=maxy-miny;
-
-	/*CFL criterion: */
-	dt=C/(maxabsvy/dx+maxabsvy/dy);
-
-	return dt;
-}
-/*}}}*/
-/*FUNCTION Tria::ThicknessAbsMisfit {{{1*/
-double Tria::ThicknessAbsMisfit(bool process_units){
-
-	/* Constants */
-	const int    numdof=1*NUMVERTICES;
-
-	/*Intermediaries*/
-	int        i,ig;
-	double     thickness,thicknessobs,weight;
-	double     Jdet;
-	double     Jelem = 0;
-	double     xyz_list[NUMVERTICES][3];
-	GaussTria *gauss = NULL;
-
-	/*If on water, return 0: */
-	if(IsOnWater())return 0;
-
-	/* Get node coordinates and dof list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-
-	/*Retrieve all inputs we will be needing: */
-	Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
-	Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
-	Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		/* Get Jacobian determinant: */
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-
-		/*Get parameters at gauss point*/
-		thickness_input->GetParameterValue(&thickness,gauss);
-		thicknessobs_input->GetParameterValue(&thicknessobs,gauss);
-		weights_input->GetParameterValue(&weight,gauss);
-
-		/*compute ThicknessAbsMisfit*/
-		Jelem+=0.5*pow(thickness-thicknessobs,2.0)*weight*Jdet*gauss->weight;
-	}
-
-	/* clean up and Return: */
-	delete gauss;
-	return Jelem;
+	/*go into parameters and get the analysis_counter: */
+	int analysis_counter;
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*Pick up nodes*/
+	if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
+	else this->nodes=NULL;
+
 }
 /*}}}*/
@@ -1896,14 +4533,44 @@
 }
 /*}}}*/
-/*FUNCTION Tria::SurfaceRelVelMisfit {{{1*/
-double Tria::SurfaceRelVelMisfit(bool process_units){
+/*FUNCTION Tria::SurfaceArea {{{1*/
+double Tria::SurfaceArea(void){
+
+	int    i;
+	double S;
+	double normal[3];
+	double v13[3],v23[3];
+	double xyz_list[NUMVERTICES][3];
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	for (i=0;i<3;i++){
+		v13[i]=xyz_list[0][i]-xyz_list[2][i];
+		v23[i]=xyz_list[1][i]-xyz_list[2][i];
+	}
+
+	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
+	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
+	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
+
+	S = 0.5 * sqrt(pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2));
+
+	/*Return: */
+	return S;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceAverageVelMisfit {{{1*/
+double Tria::SurfaceAverageVelMisfit(bool process_units){
 
 	const int    numdof=2*NUMVERTICES;
 
 	int        i,ig;
-	double     Jelem=0;
-	double     scalex=1,scaley=1;
-	double     meanvel, epsvel,misfit,Jdet;
-	double     velocity_mag,obs_velocity_mag;
+	int        fit=-1;
+	double     Jelem=0,S=0;
+	double     scalex=1, scaley=1;
+	double     meanvel, epsvel,Jdet;
+	double     velocity_mag,obs_velocity_mag,misfit;
 	double     xyz_list[NUMVERTICES][3];
 	double     vx_list[NUMVERTICES];
@@ -1923,4 +4590,5 @@
 
 	/* Recover input data: */
+	inputs->GetParameterValue(&S,SurfaceAreaEnum);
 	GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
 	GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
@@ -1933,5 +4601,5 @@
 	this->parameters->FindParam(&epsvel,EpsVelEnum);
 
-	/* Compute SurfaceRelVelMisfit at the 3 nodes
+	/* Compute SurfaceAverageVelMisfit at the 3 nodes
 	 * Here we integrate linearized functions:
 	 *               
@@ -1943,21 +4611,17 @@
 	 */
 
-	/*We are using a relative misfit: 
-	 *                        
-	 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
-	 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
-	 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
-	 *              obs                        obs                      
+	/*We are using a spacially average absolute misfit:
+	 *
+	 *      1                    2              2
+	 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
+	 *      S                obs            obs
 	 */
-	for (i=0;i<NUMVERTICES;i++){
-		scalex=pow(meanvel/(obs_vx_list[i]+epsvel),(double)2);
-		scaley=pow(meanvel/(obs_vy_list[i]+epsvel),(double)2);
-		if(obs_vx_list[i]==0)scalex=0;
-		if(obs_vy_list[i]==0)scaley=0;
-		misfit_list[i]=0.5*(scalex*pow((vx_list[i]-obs_vx_list[i]),2)+scaley*pow((vy_list[i]-obs_vy_list[i]),2));
-	}
+	for (i=0;i<NUMVERTICES;i++) misfit_square_list[i]=pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2);
 
 	/*Process units: */
-	if(process_units)UnitConversion(&misfit_list[0],NUMVERTICES,IuToExtEnum,SurfaceRelVelMisfitEnum,this->parameters);
+	if(process_units)UnitConversion(&misfit_square_list[0],NUMVERTICES,IuToExtEnum,SurfaceAverageVelMisfitEnum,this->parameters);
+
+	/*Take the square root, and scale by surface: */
+	for (i=0;i<NUMVERTICES;i++)misfit_list[i]=pow(misfit_square_list[i],2)/S;
 
 	/*Apply weights to misfits*/
@@ -1975,5 +4639,5 @@
 	}
 
-	/*clean up and Return: */
+	/*clean-up and Return: */
 	delete gauss;
 	return Jelem;
@@ -2145,15 +4809,38 @@
 }
 /*}}}*/
-/*FUNCTION Tria::SurfaceAverageVelMisfit {{{1*/
-double Tria::SurfaceAverageVelMisfit(bool process_units){
+/*FUNCTION Tria::SurfaceNormal{{{1*/
+void Tria::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
+
+	int i;
+	double v13[3],v23[3];
+	double normal[3];
+	double normal_norm;
+
+	for (i=0;i<3;i++){
+		v13[i]=xyz_list[0][i]-xyz_list[2][i];
+		v23[i]=xyz_list[1][i]-xyz_list[2][i];
+	}
+
+	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
+	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
+	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
+
+	normal_norm=sqrt( pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2) );
+
+	*(surface_normal)=normal[0]/normal_norm;
+	*(surface_normal+1)=normal[1]/normal_norm;
+	*(surface_normal+2)=normal[2]/normal_norm;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceRelVelMisfit {{{1*/
+double Tria::SurfaceRelVelMisfit(bool process_units){
 
 	const int    numdof=2*NUMVERTICES;
 
 	int        i,ig;
-	int        fit=-1;
-	double     Jelem=0,S=0;
-	double     scalex=1, scaley=1;
-	double     meanvel, epsvel,Jdet;
-	double     velocity_mag,obs_velocity_mag,misfit;
+	double     Jelem=0;
+	double     scalex=1,scaley=1;
+	double     meanvel, epsvel,misfit,Jdet;
+	double     velocity_mag,obs_velocity_mag;
 	double     xyz_list[NUMVERTICES][3];
 	double     vx_list[NUMVERTICES];
@@ -2173,5 +4860,4 @@
 
 	/* Recover input data: */
-	inputs->GetParameterValue(&S,SurfaceAreaEnum);
 	GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
 	GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
@@ -2184,5 +4870,5 @@
 	this->parameters->FindParam(&epsvel,EpsVelEnum);
 
-	/* Compute SurfaceAverageVelMisfit at the 3 nodes
+	/* Compute SurfaceRelVelMisfit at the 3 nodes
 	 * Here we integrate linearized functions:
 	 *               
@@ -2194,17 +4880,21 @@
 	 */
 
-	/*We are using a spacially average absolute misfit:
-	 *
-	 *      1                    2              2
-	 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
-	 *      S                obs            obs
+	/*We are using a relative misfit: 
+	 *                        
+	 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
+	 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
+	 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
+	 *              obs                        obs                      
 	 */
-	for (i=0;i<NUMVERTICES;i++) misfit_square_list[i]=pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2);
+	for (i=0;i<NUMVERTICES;i++){
+		scalex=pow(meanvel/(obs_vx_list[i]+epsvel),(double)2);
+		scaley=pow(meanvel/(obs_vy_list[i]+epsvel),(double)2);
+		if(obs_vx_list[i]==0)scalex=0;
+		if(obs_vy_list[i]==0)scaley=0;
+		misfit_list[i]=0.5*(scalex*pow((vx_list[i]-obs_vx_list[i]),2)+scaley*pow((vy_list[i]-obs_vy_list[i]),2));
+	}
 
 	/*Process units: */
-	if(process_units)UnitConversion(&misfit_square_list[0],NUMVERTICES,IuToExtEnum,SurfaceAverageVelMisfitEnum,this->parameters);
-
-	/*Take the square root, and scale by surface: */
-	for (i=0;i<NUMVERTICES;i++)misfit_list[i]=pow(misfit_square_list[i],2)/S;
+	if(process_units)UnitConversion(&misfit_list[0],NUMVERTICES,IuToExtEnum,SurfaceRelVelMisfitEnum,this->parameters);
 
 	/*Apply weights to misfits*/
@@ -2222,96 +4912,97 @@
 	}
 
-	/*clean-up and Return: */
+	/*clean up and Return: */
 	delete gauss;
 	return Jelem;
 }
 /*}}}*/
-/*FUNCTION Tria::PatchFill{{{1*/
-void  Tria::PatchFill(int* prow, Patch* patch){
-
-	int i,row;
-	int vertices_ids[3];
-
-	/*recover pointer: */
-	row=*prow;
-		
-	for(i=0;i<3;i++) vertices_ids[i]=nodes[i]->GetVertexId(); //vertices id start at column 3 of the patch.
-
-	for(i=0;i<this->results->Size();i++){
-		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
-
-		/*For this result,fill the information in the Patch object (element id + vertices ids), and then hand 
-		 *it to the result object, to fill the rest: */
-		patch->fillelementinfo(row,this->id,vertices_ids,3);
-		elementresult->PatchFill(row,patch);
-
-		/*increment rower: */
-		row++;
-	}
-
-	/*Assign output pointers:*/
-	*prow=row;
-}
-/*}}}*/
-/*FUNCTION Tria::PatchSize{{{1*/
-void  Tria::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
-
-	int     i;
-	int     numrows     = 0;
-	int     numnodes    = 0;
-
-	/*Go through all the results objects, and update the counters: */
-	for (i=0;i<this->results->Size();i++){
-		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
-		/*first, we have one more result: */
-		numrows++;
-		/*now, how many vertices and how many nodal values for this result? :*/
-		numnodes=elementresult->NumberOfNodalValues(); //ask result object.
-	}
-
-	/*Assign output pointers:*/
-	*pnumrows=numrows;
-	*pnumvertices=NUMVERTICES;
-	*pnumnodes=numnodes;
-}
-/*}}}*/
-/*FUNCTION Tria::ProcessResultsUnits{{{1*/
-void  Tria::ProcessResultsUnits(void){
-
-	int i;
-
-	for(i=0;i<this->results->Size();i++){
-		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
-		elementresult->ProcessUnits(this->parameters);
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::SurfaceArea {{{1*/
-double Tria::SurfaceArea(void){
-
-	int    i;
-	double S;
-	double normal[3];
-	double v13[3],v23[3];
-	double xyz_list[NUMVERTICES][3];
+/*FUNCTION Tria::ThicknessAbsMisfit {{{1*/
+double Tria::ThicknessAbsMisfit(bool process_units){
+
+	/* Constants */
+	const int    numdof=1*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,ig;
+	double     thickness,thicknessobs,weight;
+	double     Jdet;
+	double     Jelem = 0;
+	double     xyz_list[NUMVERTICES][3];
+	GaussTria *gauss = NULL;
 
 	/*If on water, return 0: */
 	if(IsOnWater())return 0;
 
+	/* Get node coordinates and dof list: */
 	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
 
-	for (i=0;i<3;i++){
-		v13[i]=xyz_list[0][i]-xyz_list[2][i];
-		v23[i]=xyz_list[1][i]-xyz_list[2][i];
-	}
-
-	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
-	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
-	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
-
-	S = 0.5 * sqrt(pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2));
-
-	/*Return: */
-	return S;
+	/*Retrieve all inputs we will be needing: */
+	Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
+	Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
+	Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get parameters at gauss point*/
+		thickness_input->GetParameterValue(&thickness,gauss);
+		thicknessobs_input->GetParameterValue(&thicknessobs,gauss);
+		weights_input->GetParameterValue(&weight,gauss);
+
+		/*compute ThicknessAbsMisfit*/
+		Jelem+=0.5*pow(thickness-thicknessobs,2.0)*weight*Jdet*gauss->weight;
+	}
+
+	/* clean up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::TimeAdapt{{{1*/
+double  Tria::TimeAdapt(void){
+
+	/*intermediary: */
+	int    i;
+	double C,dt;
+	double dx,dy;
+	double maxx,minx;
+	double maxy,miny;
+	double maxabsvx,maxabsvy;
+	double xyz_list[NUMVERTICES][3];
+
+	/*get CFL coefficient:*/
+	this->parameters->FindParam(&C,CflCoefficientEnum);
+
+	/*Get for Vx and Vy, the max of abs value: */
+	this->MaxAbsVx(&maxabsvx,false);
+	this->MaxAbsVy(&maxabsvy,false);
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0], this->nodes, NUMVERTICES);
+
+	minx=xyz_list[0][0];
+	maxx=xyz_list[0][0];
+	miny=xyz_list[0][1];
+	maxy=xyz_list[0][1];
+
+	for(i=1;i<NUMVERTICES;i++){
+		if (xyz_list[i][0]<minx)minx=xyz_list[i][0];
+		if (xyz_list[i][0]>maxx)maxx=xyz_list[i][0];
+		if (xyz_list[i][1]<miny)miny=xyz_list[i][1];
+		if (xyz_list[i][1]>maxy)maxy=xyz_list[i][1];
+	}
+	dx=maxx-minx;
+	dy=maxy-miny;
+
+	/*CFL criterion: */
+	dt=C/(maxabsvy/dx+maxabsvy/dy);
+
+	return dt;
 }
 /*}}}*/
@@ -2447,2697 +5138,2 @@
 }
 /*}}}*/
-
-/*Tria specific routines: */
-/*FUNCTION Tria::CreateKMatrixAdjointBalancedthickness {{{1*/
-ElementMatrix* Tria::CreateKMatrixAdjointBalancedthickness(void){
-
-	ElementMatrix* Ke=NULL;
-
-	/*Get Element Matrix of the forward model*/
-	switch(GetElementType()){
-		case P1Enum:
-			Ke=CreateKMatrixBalancedthickness_CG();
-			break;
-		case P1DGEnum:
-			Ke=CreateKMatrixBalancedthickness_DG();
-			break;
-		default:
-			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
-	}
-
-	/*Transpose and return Ke*/
-	Ke->Transpose();
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixBalancedthickness {{{1*/
-ElementMatrix* Tria::CreateKMatrixBalancedthickness(void){
-
-	switch(GetElementType()){
-		case P1Enum:
-			return CreateKMatrixBalancedthickness_CG();
-		case P1DGEnum:
-			return CreateKMatrixBalancedthickness_DG();
-		default:
-			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
-	}
-
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixBalancedthickness_CG {{{1*/
-ElementMatrix* Tria::CreateKMatrixBalancedthickness_CG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        artdiff;
-	int        i,j,ig,dim;
-	double     Jdettria ,vx,vy,dvxdx,dvydy;
-	double     dvx[2],dvy[2];
-	double     xyz_list[NUMVERTICES][3];
-	double     L[NUMVERTICES];
-	double     B[2][NUMVERTICES];
-	double     Bprime[2][NUMVERTICES];
-	double     K[2][2]                          = {0.0};
-	double     KDL[2][2]                        = {0.0};
-	double     DL[2][2]                         = {0.0};
-	double     DLprime[2][2]                    = {0.0};
-	double     DL_scalar;
-	double     Ke_gg_gaussian[numdof][numdof]   = {0.0};
-	double     Ke_gg_thickness1[numdof][numdof] = {0.0};
-	double     Ke_gg_thickness2[numdof][numdof] = {0.0};
-	GaussTria *gauss                            = NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all Inputs and parameters: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&artdiff,ArtDiffEnum);
-	this->parameters->FindParam(&dim,DimEnum);
-	Input* vxaverage_input=NULL;
-	Input* vyaverage_input=NULL;
-	if(dim==2){
-		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
-	}
-	else{
-		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
-	}
-
-	/*Create Artificial diffusivity once for all if requested*/
-	if(artdiff){
-		gauss=new GaussTria();
-		gauss->GaussCenter();
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		delete gauss;
-
-		vxaverage_input->GetParameterAverage(&vx);
-		vyaverage_input->GetParameterAverage(&vy);
-		K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(vx);
-		K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(vy);
-	}
-
-	/*Start looping on the number of gaussian points:*/
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
-		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
-
-		vxaverage_input->GetParameterValue(&vx,gauss);
-		vyaverage_input->GetParameterValue(&vy,gauss);
-		vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
-		vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
-
-		dvxdx=dvx[0];
-		dvydy=dvy[1];
-		DL_scalar=gauss->weight*Jdettria;
-
-		DL[0][0]=DL_scalar*dvxdx;
-		DL[1][1]=DL_scalar*dvydy;
-
-		DLprime[0][0]=DL_scalar*vx;
-		DLprime[1][1]=DL_scalar*vy;
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DL[0][0],2,2,0,
-					&B[0][0],2,numdof,0,
-					&Ke_gg_thickness1[0][0],0);
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DLprime[0][0],2,2,0,
-					&Bprime[0][0],2,numdof,0,
-					&Ke_gg_thickness2[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
-
-		if(artdiff){
-			KDL[0][0]=DL_scalar*K[0][0];
-			KDL[1][1]=DL_scalar*K[1][1];
-
-			TripleMultiply( &Bprime[0][0],2,numdof,1,
-						&KDL[0][0],2,2,0,
-						&Bprime[0][0],2,numdof,0,
-						&Ke_gg_gaussian[0][0],0);
-
-			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixBalancedthickness_DG {{{1*/
-ElementMatrix* Tria::CreateKMatrixBalancedthickness_DG(void){
-
-	/*Constants*/
-	const int  numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries*/
-	int        i,j,ig,dim;
-	double     vx,vy,Jdettria;
-	double     xyz_list[NUMVERTICES][3];
-	double     B[2][NUMVERTICES];
-	double     Bprime[2][NUMVERTICES];
-	double     DL[2][2]={0.0};
-	double     DL_scalar;
-	double     Ke_gg[numdof][numdof]={0.0};
-	GaussTria  *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&dim,DimEnum);
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-
-	/*Start looping on the number of gaussian points:*/
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		/*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
-		GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
-		GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
-
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-
-		DL_scalar=-gauss->weight*Jdettria;
-		DL[0][0]=DL_scalar*vx;
-		DL[1][1]=DL_scalar*vy;
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DL[0][0],2,2,0,
-					&Bprime[0][0],2,numdof,0,
-					&Ke_gg[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixBalancedvelocities {{{1*/
-ElementMatrix* Tria::CreateKMatrixBalancedvelocities(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int     artdiff;
-	int     i,j,ig,dim;
-	double  nx,ny,norm,Jdettria;
-	double  dvx[2],dvy[2];
-	double  vx,vy,dvxdx,dvydy;
-	double  v_gauss[2]={0.0};
-	double  surface_normal[3];
-	double  surface_list[3];
-	double  xyz_list[NUMVERTICES][3];
-	double  B[2][NUMVERTICES];
-	double  Bprime[2][NUMVERTICES];
-	double  K[2][2]={0.0};
-	double  KDL[2][2]={0.0};
-	double  DLprime[2][2]={0.0};
-	double  DL_scalar;
-	double  Ke_gg_gaussian[numdof][numdof]   = {0.0}; 
-	double  Ke_gg_velocities[numdof][numdof] = {0.0}; 
-	GaussTria *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&artdiff,ArtDiffEnum);
-	this->parameters->FindParam(&dim,DimEnum);
-	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
-	Input* vxaverage_input=NULL;
-	Input* vyaverage_input=NULL;
-	if(dim==2){
-		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
-	}
-	else{
-		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
-	}
-
-	/*Modify z so that it reflects the surface*/
-	GetParameterListOnVertices(&surface_list[0],SurfaceEnum);
-	for(i=0;i<NUMVERTICES;i++) xyz_list[i][2]=surface_list[i];
-
-	/*Get normal vector to the surface*/
-	vxaverage_input->GetParameterAverage(&nx);
-	vyaverage_input->GetParameterAverage(&ny);
-	if(nx==0 && ny==0){
-		SurfaceNormal(&surface_normal[0],xyz_list);
-		nx=surface_normal[0];
-		ny=surface_normal[1];
-	}
-	if(nx==0 && ny==0){
-		nx=0; ny=1;
-	}
-	norm=pow( pow(nx,2)+pow(ny,2) , (double).5);
-	nx=nx/norm; ny=ny/norm;
-
-	//Create Artificial diffusivity once for all if requested
-	if(artdiff){
-		gauss=new GaussTria();
-		gauss->GaussCenter();
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		delete gauss;
-
-		vxaverage_input->GetParameterAverage(&v_gauss[0]);
-		vyaverage_input->GetParameterAverage(&v_gauss[1]);
-		K[0][0]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]); //pow should be zero!!
-		K[1][1]=pow(10,2)*pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
-		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
-
-		vxaverage_input->GetParameterValue(&vx,gauss);
-		vyaverage_input->GetParameterValue(&vy,gauss);
-		vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
-		vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
-
-		dvxdx=dvx[0];
-		dvydy=dvy[1];
-		DL_scalar=gauss->weight*Jdettria;
-
-		DLprime[0][0]=DL_scalar*nx;
-		DLprime[1][1]=DL_scalar*ny;
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DLprime[0][0],2,2,0,
-					&Bprime[0][0],2,numdof,0,
-					&Ke_gg_velocities[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_velocities[i][j];
-
-		if(artdiff){
-			KDL[0][0]=DL_scalar*K[0][0];
-			KDL[1][1]=DL_scalar*K[1][1];
-
-			TripleMultiply( &Bprime[0][0],2,numdof,1,
-						&KDL[0][0],2,2,0,
-						&Bprime[0][0],2,numdof,0,
-						&Ke_gg_gaussian[0][0],0);
-
-			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyeal {{{1*/
-ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyeal(void){
-	
-	/*compute all stiffness matrices for this element*/
-	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyealViscous();
-	ElementMatrix* Ke2=CreateKMatrixDiagnosticMacAyealFriction();
-	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
-
-	/*clean-up and return*/
-	delete Ke1;
-	delete Ke2;
-	return Ke;
-
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealViscous{{{1*/
-ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealViscous(void){
-
-	/*Constants*/
-	const int  numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries*/
-	int        i,j,ig;
-	double     xyz_list[NUMVERTICES][3];
-	double     viscosity,newviscosity,oldviscosity;
-	double     viscosity_overshoot,thickness,Jdet;
-	double     epsilon[3],oldepsilon[3];    /* epsilon=[exx,eyy,exy];    */
-	double     B[3][numdof];
-	double     Bprime[3][numdof];
-	double     D[3][3]   = {0.0};
-	double     D_scalar;
-	double     Ke_g[numdof][numdof];
-	GaussTria *gauss = NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input);
-	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
-	Input* vxold_input=inputs->GetInput(VxOldEnum);         ISSMASSERT(vxold_input);
-	Input* vyold_input=inputs->GetInput(VyOldEnum);         ISSMASSERT(vyold_input);
-	this->parameters->FindParam(&viscosity_overshoot,ViscosityOvershootEnum);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss);
-		GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss);
-
-		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
-		this->GetStrainRate2d(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
-		matice->GetViscosity2d(&viscosity, &epsilon[0]);
-		matice->GetViscosity2d(&oldviscosity, &oldepsilon[0]);
-		thickness_input->GetParameterValue(&thickness, gauss);
-
-		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
-		D_scalar=2*newviscosity*thickness*gauss->weight*Jdet;
-		for (i=0;i<3;i++) D[i][i]=D_scalar;
-
-		TripleMultiply(&B[0][0],3,numdof,1,
-					&D[0][0],3,3,0,
-					&Bprime[0][0],3,numdof,0,
-					&Ke_g[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealFriction {{{1*/
-ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealFriction(void){
-
-	/*Constants*/
-	const int  numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries*/
-	int        i,j,ig;
-	int        analysis_type,drag_type;
-	double     MAXSLOPE  = .06; // 6 %
-	double     MOUNTAINKEXPONENT = 10;
-	double     slope_magnitude,alpha2;
-	double     Jdet;
-	double     L[2][numdof];
-	double     DL[2][2]  = {{ 0,0 },{0,0}};
-	double     Ke_g[numdof][numdof];
-	double     DL_scalar;
-	double     slope[2]  = {0.0,0.0};
-	double     xyz_list[NUMVERTICES][3];
-	Friction  *friction = NULL;
-	GaussTria *gauss    = NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || IsOnShelf()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
-	Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-
-	/*build friction object, used later on: */
-	if (drag_type!=2) ISSMERROR(" non-viscous friction not supported yet!");
-	friction=new Friction("2d",inputs,matpar,analysis_type);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
-		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
-		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
-		if(slope_magnitude>MAXSLOPE) alpha2=pow((double)10,MOUNTAINKEXPONENT);
-		else friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
-
-		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		DL_scalar=alpha2*gauss->weight*Jdet;
-		for (i=0;i<2;i++) DL[i][i]=DL_scalar;
-		
-		TripleMultiply( &L[0][0],2,numdof,1,
-					&DL[0][0],2,2,0,
-					&L[0][0],2,numdof,0,
-					&Ke_g[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j]; 
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	delete friction;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixCouplingMacAyealPattynFriction {{{1*/
-ElementMatrix* Tria::CreateKMatrixCouplingMacAyealPattynFriction(void){
-
-	/*Constants*/
-	const int numdof        = NDOF2 *NUMVERTICES;
-	const int numdoftotal   = NDOF4 *NUMVERTICES;
-	
-	/*Intermediaries */
-	int       i,j,ig,analysis_type,drag_type;
-	double    Jdet,slope_magnitude,alpha2;
-	double    xyz_list[NUMVERTICES][3];
-	double    slope[2]={0.0,0.0};
-	double    MAXSLOPE=.06; // 6 %
-	double    MOUNTAINKEXPONENT=10;
-	double    L[2][numdof];
-	double    DL[2][2]                  ={{ 0,0 },{0,0}}; //for basal drag
-	double    DL_scalar;
-	double    Ke_gg[numdof][numdof]     ={0.0};
-	double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
-	Friction  *friction = NULL;
-	GaussTria *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || IsOnShelf()) return NULL;
-	ElementMatrix* Ke1=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
-	ElementMatrix* Ke2=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
-	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
-	delete Ke1; delete Ke2;
-
-	/*retrieve inputs :*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
-	Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
-
-	/*build friction object, used later on: */
-	if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
-	friction=new Friction("2d",inputs,matpar,analysis_type);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		/*Friction: */
-		friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
-
-		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
-		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
-		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
-
-		if (slope_magnitude>MAXSLOPE){
-			alpha2=pow((double)10,MOUNTAINKEXPONENT);
-		}
-
-		/* Get Jacobian determinant: */
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-
-		/*Get L matrix: */
-		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
-
-		
-		DL_scalar=alpha2*gauss->weight*Jdet;
-		for (i=0;i<2;i++){
-			DL[i][i]=DL_scalar;
-		}
-		
-		/*  Do the triple producte tL*D*L: */
-		TripleMultiply( &L[0][0],2,numdof,1,
-					&DL[0][0],2,2,0,
-					&L[0][0],2,numdof,0,
-					&Ke_gg_gaussian[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
-	}
-
-	for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdoftotal+(numdof+j)]+=Ke_gg[i][j];
-	for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[(i+numdof)*numdoftotal+j]+=Ke_gg[i][j];
-
-	/*Clean up and return*/
-	delete gauss;
-	delete friction;
-	return Ke;
-}	
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixDiagnosticPattynFriction {{{1*/
-ElementMatrix* Tria::CreateKMatrixDiagnosticPattynFriction(void){
-
-	/*Constants*/
-	const int numdof   = NDOF2*NUMVERTICES;
-	
-	/*Intermediaries */
-	int       i,j,ig;
-	int       analysis_type,drag_type;
-	double    xyz_list[NUMVERTICES][3];
-	double    slope_magnitude,alpha2,Jdet;
-	double    slope[2]={0.0,0.0};
-	double    MAXSLOPE=.06; // 6 %
-	double    MOUNTAINKEXPONENT=10;
-	double    L[2][numdof];
-	double    DL[2][2]={{ 0,0 },{0,0}}; //for basal drag
-	double    DL_scalar;
-	double    Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
-	Friction  *friction = NULL;
-	GaussTria *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || IsOnShelf()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	Input* surface_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(surface_input);
-	Input* vx_input=inputs->GetInput(VxEnum);           ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);           ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);           ISSMASSERT(vz_input);
-
-	/*build friction object, used later on: */
-	if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
-	friction=new Friction("2d",inputs,matpar,analysis_type);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
-
-		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-		friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum); // TO UNCOMMENT
-		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
-
-		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
-		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
-		if (slope_magnitude>MAXSLOPE){
-			alpha2=pow((double)10,MOUNTAINKEXPONENT);
-		}
-		
-		DL_scalar=alpha2*gauss->weight*Jdet;
-		for (i=0;i<2;i++) DL[i][i]=DL_scalar;
-		
-		TripleMultiply( &L[0][0],2,numdof,1,
-					&DL[0][0],2,2,0,
-					&L[0][0],2,numdof,0,
-					&Ke_gg_gaussian[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	delete friction;
-	return Ke;
-}	
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixDiagnosticHutter{{{1*/
-ElementMatrix* Tria::CreateKMatrixDiagnosticHutter(void){
-
-	/*Intermediaries*/
-	const int numdof=NUMVERTICES*NDOF2;
-	int    i,connectivity;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Create Element matrix*/
-	for(i=0;i<NUMVERTICES;i++){
-		connectivity=nodes[i]->GetConnectivity();
-		Ke->values[(2*i)*numdof  +(2*i)  ]=1/(double)connectivity;
-		Ke->values[(2*i+1)*numdof+(2*i+1)]=1/(double)connectivity;
-	}
-
-	/*Clean up and return*/
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixDiagnosticVertSurface {{{1*/
-ElementMatrix* Tria::CreateKMatrixDiagnosticVertSurface(void){
-
-	/*Constants*/
-	const int numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int       i,j,ig;
-	double    xyz_list[NUMVERTICES][3];
-	double    surface_normal[3];
-	double    Jdet,DL_scalar;
-	double    L[3];
-	GaussTria *gauss=NULL;
-	double Ke_g[numdof][numdof]; //stiffness matrix evaluated at the gaussian point.
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	SurfaceNormal(&surface_normal[0],xyz_list);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		/**********************Do not forget the sign**********************************/
-		DL_scalar=- gauss->weight*Jdet*surface_normal[2]; 
-		/******************************************************************************/
-
-		TripleMultiply( L,1,3,1,
-					&DL_scalar,1,1,0,
-					L,1,3,0,
-					&Ke_g[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixMelting {{{1*/
-ElementMatrix* Tria::CreateKMatrixMelting(void){
-
-	/*Constants*/
-	const int  numdof=NUMVERTICES*NDOF1;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	double     heatcapacity,latentheat;
-	double     Jdet,D_scalar;
-	double     xyz_list[NUMVERTICES][3];
-	double     L[3];
-	double     Ke_gaussian[numdof][numdof]={0.0};
-	GaussTria *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	latentheat=matpar->GetLatentHeat();
-	heatcapacity=matpar->GetHeatCapacity();
-
-	/* Start looping on the number of gauss  (nodes on the bedrock) */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
-
-		D_scalar=latentheat/heatcapacity*gauss->weight*Jdet;
-
-		TripleMultiply(&L[0],numdof,1,0,
-					&D_scalar,1,1,0,
-					&L[0],1,numdof,0,
-					&Ke_gaussian[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixPrognostic {{{1*/
-ElementMatrix* Tria::CreateKMatrixPrognostic(void){
-
-	switch(GetElementType()){
-		case P1Enum:
-			return CreateKMatrixPrognostic_CG();
-		case P1DGEnum:
-			return CreateKMatrixPrognostic_DG();
-		default:
-			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
-	}
-
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixPrognostic_CG {{{1*/
-ElementMatrix* Tria::CreateKMatrixPrognostic_CG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        artdiff;
-	int        i,j,ig,dim;
-	double     Jdettria,DL_scalar,dt;
-	double     vx,vy,dvxdx,dvydy;
-	double     dvx[2],dvy[2];
-	double     v_gauss[2]={0.0};
-	double     xyz_list[NUMVERTICES][3];
-	double     L[NUMVERTICES];
-	double     B[2][NUMVERTICES];
-	double     Bprime[2][NUMVERTICES];
-	double     K[2][2]                        ={0.0};
-	double     KDL[2][2]                      ={0.0};
-	double     DL[2][2]                        ={0.0};
-	double     DLprime[2][2]                   ={0.0};
-	double     Ke_gg_gaussian[numdof][numdof]  ={0.0};
-	double     Ke_gg_thickness1[numdof][numdof]={0.0};
-	double     Ke_gg_thickness2[numdof][numdof]={0.0};
-	GaussTria *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->inputs->GetParameterValue(&dt,DtEnum);
-	this->parameters->FindParam(&dim,DimEnum);
-	this->parameters->FindParam(&artdiff,ArtDiffEnum);
-	Input* vxaverage_input=NULL;
-	Input* vyaverage_input=NULL;
-	if(dim==2){
-		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
-	}
-	else{
-		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
-	}
-
-	//Create Artificial diffusivity once for all if requested
-	if(artdiff){
-		gauss=new GaussTria();
-		gauss->GaussCenter();
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		delete gauss;
-
-		vxaverage_input->GetParameterAverage(&v_gauss[0]);
-		vyaverage_input->GetParameterAverage(&v_gauss[1]);
-
-		K[0][0]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[0]);
-		K[1][1]=pow(Jdettria,(double).5)/2.0*fabs(v_gauss[1]);
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		vxaverage_input->GetParameterValue(&vx,gauss);
-		vyaverage_input->GetParameterValue(&vy,gauss);
-		vxaverage_input->GetParameterDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
-		vyaverage_input->GetParameterDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
-
-		DL_scalar=gauss->weight*Jdettria;
-
-		TripleMultiply( &L[0],1,numdof,1,
-					&DL_scalar,1,1,0,
-					&L[0],1,numdof,0,
-					&Ke_gg_gaussian[0][0],0);
-
-		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
-		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
-
-		dvxdx=dvx[0];
-		dvydy=dvy[1];
-		DL_scalar=dt*gauss->weight*Jdettria;
-
-		DL[0][0]=DL_scalar*dvxdx;
-		DL[1][1]=DL_scalar*dvydy;
-		DLprime[0][0]=DL_scalar*vx;
-		DLprime[1][1]=DL_scalar*vy;
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DL[0][0],2,2,0,
-					&B[0][0],2,numdof,0,
-					&Ke_gg_thickness1[0][0],0);
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DLprime[0][0],2,2,0,
-					&Bprime[0][0],2,numdof,0,
-					&Ke_gg_thickness2[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness1[i][j];
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_thickness2[i][j];
-
-		if(artdiff){
-			KDL[0][0]=DL_scalar*K[0][0];
-			KDL[1][1]=DL_scalar*K[1][1];
-
-			TripleMultiply( &Bprime[0][0],2,numdof,1,
-						&KDL[0][0],2,2,0,
-						&Bprime[0][0],2,numdof,0,
-						&Ke_gg_gaussian[0][0],0);
-
-			for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg_gaussian[i][j];
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixPrognostic_DG {{{1*/
-ElementMatrix* Tria::CreateKMatrixPrognostic_DG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig,dim;
-	double     xyz_list[NUMVERTICES][3];
-	double     Jdettria,dt,vx,vy;
-	double     L[NUMVERTICES];
-	double     B[2][NUMVERTICES];
-	double     Bprime[2][NUMVERTICES];
-	double     DL[2][2]={0.0};
-	double     DLprime[2][2]={0.0};
-	double     DL_scalar;
-	double     Ke_gg1[numdof][numdof]={0.0};
-	double     Ke_gg2[numdof][numdof]={0.0};
-	GaussTria  *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->inputs->GetParameterValue(&dt,DtEnum);
-	this->parameters->FindParam(&dim,DimEnum);
-	Input* vxaverage_input=NULL;
-	Input* vyaverage_input=NULL;
-	if(dim==2){
-		vxaverage_input=inputs->GetInput(VxEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyEnum); ISSMASSERT(vyaverage_input);
-	}
-	else{
-		vxaverage_input=inputs->GetInput(VxAverageEnum); ISSMASSERT(vxaverage_input);
-		vyaverage_input=inputs->GetInput(VyAverageEnum); ISSMASSERT(vyaverage_input);
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		vxaverage_input->GetParameterValue(&vx,gauss);
-		vyaverage_input->GetParameterValue(&vy,gauss);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		DL_scalar=gauss->weight*Jdettria;
-
-		TripleMultiply( &L[0],1,numdof,1,
-					&DL_scalar,1,1,0,
-					&L[0],1,numdof,0,
-					&Ke_gg1[0][0],0);
-
-		/*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
-		GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
-		GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
-
-		DL_scalar=-dt*gauss->weight*Jdettria;
-
-		DLprime[0][0]=DL_scalar*vx;
-		DLprime[1][1]=DL_scalar*vy;
-
-		TripleMultiply( &B[0][0],2,numdof,1,
-					&DLprime[0][0],2,2,0,
-					&Bprime[0][0],2,numdof,0,
-					&Ke_gg2[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg1[i][j];
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gg2[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixSlope {{{1*/
-ElementMatrix* Tria::CreateKMatrixSlope(void){
-
-	/*constants: */
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/* Intermediaries */
-	int        i,j,ig;
-	double     DL_scalar,Jdet;
-	double     xyz_list[NUMVERTICES][3];
-	double     L[1][3];
-	double     Ke_g[numdof][numdof];
-	GaussTria *gauss = NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	GetVerticesCoordinates(&xyz_list[0][0],nodes,NUMVERTICES);
-
-	/* Start looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-		
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		DL_scalar=gauss->weight*Jdet;
-
-		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF1);
-
-		TripleMultiply(&L[0][0],1,3,1,
-					&DL_scalar,1,1,0,
-					&L[0][0],1,3,0,
-					&Ke_g[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g[i][j];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreateKMatrixThermal {{{1*/
-ElementMatrix* Tria::CreateKMatrixThermal(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int       i,j,ig;
-	double    mixed_layer_capacity,thermal_exchange_velocity;
-	double    rho_ice,rho_water,heatcapacity;
-	double    Jdet,dt;
-	double    xyz_list[NUMVERTICES][3];
-	double    l1l2l3[NUMVERTICES];
-	double    D_scalar;
-	double    Ke_gaussian[numdof][numdof]={0.0};
-	GaussTria *gauss=NULL;
-
-	/*Initialize Element matrix and return if necessary*/
-	if(IsOnWater() || !IsOnShelf()) return NULL;
-	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->inputs->GetParameterValue(&dt,DtEnum);
-	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
-	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
-	rho_water=matpar->GetRhoWater();
-	rho_ice=matpar->GetRhoIce();
-	heatcapacity=matpar->GetHeatCapacity();
-
-	/* Start looping on the number of gauss (nodes on the bedrock) */
-	gauss=new GaussTria(2);
-	for (ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-		
-		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
-		GetNodalFunctions(&l1l2l3[0], gauss);
-				
-		D_scalar=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity/(heatcapacity*rho_ice);
-		if(dt) D_scalar=dt*D_scalar;
-
-		TripleMultiply(&l1l2l3[0],numdof,1,0,
-					&D_scalar,1,1,0,
-					&l1l2l3[0],1,numdof,0,
-					&Ke_gaussian[0][0],0);
-
-		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_gaussian[i][j];
-	}
-	
-	/*Clean up and return*/
-	delete gauss;
-	return Ke;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorBalancedthickness{{{1*/
-ElementVector* Tria::CreatePVectorBalancedthickness(void){
-
-	switch(GetElementType()){
-		case P1Enum:
-			return CreatePVectorBalancedthickness_CG();
-			break;
-		case P1DGEnum:
-			return CreatePVectorBalancedthickness_DG();
-		default:
-			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorBalancedthickness_CG{{{1*/
-ElementVector* Tria::CreatePVectorBalancedthickness_CG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-	
-	/*Intermediaries */
-	int        i,j,ig;
-	double     xyz_list[NUMVERTICES][3];
-	double     dhdt_g,melting_g,accumulation_g,Jdettria;
-	double     L[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
-	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
-	Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
-	
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		accumulation_input->GetParameterValue(&accumulation_g,gauss);
-		melting_input->GetParameterValue(&melting_g,gauss);
-		dhdt_input->GetParameterValue(&dhdt_g,gauss);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorBalancedthickness_DG {{{1*/
-ElementVector* Tria::CreatePVectorBalancedthickness_DG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	double     xyz_list[NUMVERTICES][3];
-	double     melting_g,accumulation_g,dhdt_g,Jdettria;
-	double     L[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
-	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
-	Input* dhdt_input=inputs->GetInput(DhDtEnum);                     ISSMASSERT(dhdt_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		accumulation_input->GetParameterValue(&accumulation_g,gauss);
-		melting_input->GetParameterValue(&melting_g,gauss);
-		dhdt_input->GetParameterValue(&dhdt_g,gauss);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g-dhdt_g)*L[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorBalancedvelocities {{{1*/
-ElementVector* Tria::CreatePVectorBalancedvelocities(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	double     xyz_list[NUMVERTICES][3];
-	double     Jdettria,accumulation_g,melting_g;
-	double     L[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
-	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		accumulation_input->GetParameterValue(&accumulation_g,gauss);
-		melting_input->GetParameterValue(&melting_g,gauss);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(accumulation_g-melting_g)*L[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorDiagnosticBaseVert {{{1*/
-ElementVector* Tria::CreatePVectorDiagnosticBaseVert(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	int        approximation;
-	double     xyz_list[NUMVERTICES][3];
-	double     Jdet;
-	double     vx,vy,vz,dbdx,dbdy,meltingvalue;
-	double     slope[2];
-	double     L[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	inputs->GetParameterValue(&approximation,ApproximationEnum);
-	Input* bed_input=inputs->GetInput(BedEnum);             ISSMASSERT(bed_input);
-	Input* melting_input=inputs->GetInput(MeltingRateEnum); ISSMASSERT(melting_input);
-	Input* vx_input=inputs->GetInput(VxEnum);               ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);               ISSMASSERT(vy_input);
-	Input* vzstokes_input=NULL;
-	if(approximation==PattynStokesApproximationEnum){
-		vzstokes_input=inputs->GetInput(VzStokesEnum);       ISSMASSERT(vzstokes_input);
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		melting_input->GetParameterValue(&meltingvalue, gauss);
-		bed_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-		vx_input->GetParameterValue(&vx, gauss);
-		vy_input->GetParameterValue(&vy, gauss);
-		if(approximation==PattynStokesApproximationEnum){
-			vzstokes_input->GetParameterValue(&vz, gauss);
-		}
-		else vz=0;
-
-		dbdx=slope[0];
-		dbdy=slope[1];
-
-		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=-Jdet*gauss->weight*(vx*dbdx+vy*dbdy-vz-meltingvalue)*L[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorDiagnosticMacAyeal {{{1*/
-ElementVector* Tria::CreatePVectorDiagnosticMacAyeal(){
-
-	/*Constants*/
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries */
-	int            i,j,ig,drag_type;
-	double         plastic_stress,driving_stress_baseline,thickness;
-	double         Jdet;
-	double         xyz_list[NUMVERTICES][3];
-	double         slope[2];
-	double         l1l2l3[3];
-	double         pe_g_gaussian[numdof];
-	GaussTria*     gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum); ISSMASSERT(thickness_input); 
-	Input* surface_input=inputs->GetInput(SurfaceEnum);     ISSMASSERT(surface_input);
-	Input* drag_input=inputs->GetInput(DragCoefficientEnum);ISSMASSERT(drag_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-
-		thickness_input->GetParameterValue(&thickness,gauss);
-		surface_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-		
-		/*In case we have plastic basal drag, compute plastic stress at gaussian point from k1, k2 and k3 fields in the 
-		 * element itself: */
-		if(drag_type==1) drag_input->GetParameterValue(&plastic_stress,gauss);
-
-		driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG()*thickness;
-
-		/*Build pe_g_gaussian vector: */
-		if(drag_type==1){
-			for (i=0;i<NUMVERTICES;i++){
-				for (j=0;j<NDOF2;j++){
-					pe->values[i*NDOF2+j]+=(-driving_stress_baseline*slope[j]-plastic_stress)*Jdet*gauss->weight*l1l2l3[i]; 
-				}
-			}
-		}
-		else {
-			for (i=0;i<NUMVERTICES;i++){
-				for (j=0;j<NDOF2;j++){
-					pe->values[i*NDOF2+j]+=-driving_stress_baseline*slope[j]*Jdet*gauss->weight*l1l2l3[i];
-				}
-			}
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorAdjointBalancedthickness{{{1*/
-ElementVector* Tria::CreatePVectorAdjointBalancedthickness(void){
-
-	/*Constants*/
-	const int    numdof=1*NUMVERTICES;
-
-	/*Intermediaries */
-	int         i,ig;
-	double      Jdet;
-	double      thickness,thicknessobs,weight;
-	double      xyz_list[NUMVERTICES][3];
-	double      l1l2l3[3];
-	GaussTria*  gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* thickness_input   =inputs->GetInput(ThicknessEnum);   ISSMASSERT(thickness_input);
-	Input* thicknessobs_input=inputs->GetInput(ThicknessObsEnum);ISSMASSERT(thicknessobs_input);
-	Input* weights_input     =inputs->GetInput(WeightsEnum);     ISSMASSERT(weights_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-
-		thickness_input->GetParameterValue(&thickness, gauss);
-		thicknessobs_input->GetParameterValue(&thicknessobs, gauss);
-		weights_input->GetParameterValue(&weight, gauss);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=(thicknessobs-thickness)*weight*Jdet*gauss->weight*l1l2l3[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorAdjointHoriz{{{1*/
-ElementVector* Tria::CreatePVectorAdjointHoriz(void){
-
-	/*Constants*/
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,ig,response;
-	double     Jdet;
-	double     obs_velocity_mag,velocity_mag;
-	double     dux,duy,meanvel,epsvel;
-	double     scalex=0,scaley=0,scale=0,S=0;
-	double     xyz_list[NUMVERTICES][3];
-	double     vx_list[NUMVERTICES];
-	double     vy_list[NUMVERTICES];
-	double     obs_vx_list[NUMVERTICES];
-	double     obs_vy_list[NUMVERTICES];
-	double     dux_list[NUMVERTICES];
-	double     duy_list[NUMVERTICES];
-	double     weights_list[NUMVERTICES];
-	double     l1l2l3[3];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&meanvel,MeanVelEnum);
-	this->parameters->FindParam(&epsvel,EpsVelEnum);
-	GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
-	GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
-	GetParameterListOnVertices(&vx_list[0],VxEnum);
-	GetParameterListOnVertices(&vy_list[0],VyEnum);
-	GetParameterListOnVertices(&weights_list[0],WeightsEnum);
-	inputs->GetParameterValue(&response,CmResponseEnum);
-	if(response==SurfaceAverageVelMisfitEnum){
-		inputs->GetParameterValue(&S,SurfaceAreaEnum);
-	}
-
-	/*Get Du at the 3 nodes (integration of the linearized function)
-	 * Here we integrate linearized functions:
-	 *               
-	 * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
-	 *
-	 *       d J                  dJ_i
-	 * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
-	 *       d u                  du_i
-	 *
-	 * where J_i are the misfits at the 3 nodes of the triangle
-	 *       Phi_i is the nodal function (P1) with respect to 
-	 *       the vertex i
-	 */
-	if(response==SurfaceAbsVelMisfitEnum){
-		/*We are using an absolute misfit:
-		 *
-		 *      1  [           2              2 ]
-		 * J = --- | (u - u   )  +  (v - v   )  |
-		 *      2  [       obs            obs   ]
-		 *
-		 *        dJ
-		 * DU = - -- = (u   - u )
-		 *        du     obs
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			dux_list[i]=obs_vx_list[i]-vx_list[i];
-			duy_list[i]=obs_vy_list[i]-vy_list[i];
-		}
-	}
-	else if(response==SurfaceRelVelMisfitEnum){
-		/*We are using a relative misfit: 
-		 *                        
-		 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
-		 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
-		 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
-		 *              obs                        obs                      
-		 *
-		 *        dJ     \bar{v}^2
-		 * DU = - -- = ------------- (u   - u )
-		 *        du   (u   + eps)^2    obs
-		 *               obs
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
-			scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
-			if(obs_vx_list[i]==0)scalex=0;
-			if(obs_vy_list[i]==0)scaley=0;
-			dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
-			duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
-		}
-	}
-	else if(response==SurfaceLogVelMisfitEnum){
-		/*We are using a logarithmic misfit:
-		 *                        
-		 *                 [        vel + eps     ] 2
-		 * J = 4 \bar{v}^2 | log ( -----------  ) |  
-		 *                 [       vel   + eps    ]
-		 *                            obs
-		 *
-		 *        dJ                 2 * log(...)
-		 * DU = - -- = - 4 \bar{v}^2 -------------  u
-		 *        du                 vel^2 + eps
-		 *            
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
-			obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
-			scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
-			dux_list[i]=scale*vx_list[i];
-			duy_list[i]=scale*vy_list[i];
-		}
-	}
-	else if(response==SurfaceAverageVelMisfitEnum){
-		/*We are using an spacially average absolute misfit:
-		 *
-		 *      1                    2              2
-		 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
-		 *      S                obs            obs
-		 *
-		 *        dJ      1       1 
-		 * DU = - -- = - --- ----------- * 2 (u - u   )
-		 *        du      S  2 sqrt(...)           obs
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
-			dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
-			duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
-		}
-	}
-	else if(response==SurfaceLogVxVyMisfitEnum){
-		/*We are using an logarithmic 2 misfit:
-		 *
-		 *      1            [        |u| + eps     2          |v| + eps     2  ]
-		 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   |  
-		 *      2            [       |u    |+ eps              |v    |+ eps     ]
-		 *                              obs                       obs
-		 *        dJ                              1      u                             1
-		 * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
-		 *        du                         |u| + eps  |u|                           u + eps
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			dux_list[i] = - pow(meanvel,(double)2)*(
-						log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
-			duy_list[i] = - pow(meanvel,(double)2)*(
-						log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
-		}
-	}
-	else{
-		/*Not supported yet! : */
-		ISSMERROR("response %s not supported yet",EnumToString(response));
-	}
-
-	/*Apply weights to DU*/
-	for (i=0;i<NUMVERTICES;i++){
-		dux_list[i]=weights_list[i]*dux_list[i];
-		duy_list[i]=weights_list[i]*duy_list[i];
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-
-		TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
-		TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
-
-		for (i=0;i<NUMVERTICES;i++){
-			pe->values[i*NDOF2+0]+=dux*Jdet*gauss->weight*l1l2l3[i]; 
-			pe->values[i*NDOF2+1]+=duy*Jdet*gauss->weight*l1l2l3[i]; 
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorAdjointStokes{{{1*/
-ElementVector* Tria::CreatePVectorAdjointStokes(void){
-
-	/*Intermediaries */
-	int        i,ig;
-	int        fit=-1;
-	int        response;
-	double     Jdet;
-	double     obs_velocity_mag,velocity_mag;
-	double     dux,duy,meanvel,epsvel;
-	double     scalex=0,scaley=0,scale=0,S=0;
-	double     xyz_list[NUMVERTICES][3];
-	double     vx_list[NUMVERTICES];
-	double     vy_list[NUMVERTICES];
-	double     obs_vx_list[NUMVERTICES];
-	double     obs_vy_list[NUMVERTICES];
-	double     dux_list[NUMVERTICES];
-	double     duy_list[NUMVERTICES];
-	double     weights_list[NUMVERTICES];
-	double     l1l2l3[3];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&meanvel,MeanVelEnum);
-	this->parameters->FindParam(&epsvel,EpsVelEnum);
-	GetParameterListOnVertices(&obs_vx_list[0],VxObsEnum);
-	GetParameterListOnVertices(&obs_vy_list[0],VyObsEnum);
-	GetParameterListOnVertices(&vx_list[0],VxEnum);
-	GetParameterListOnVertices(&vy_list[0],VyEnum);
-	GetParameterListOnVertices(&weights_list[0],WeightsEnum);
-	inputs->GetParameterValue(&response,CmResponseEnum);
-	if(response==SurfaceAverageVelMisfitEnum){
-		inputs->GetParameterValue(&S,SurfaceAreaEnum);
-	}
-
-	/*Get Du at the 3 nodes (integration of the linearized function)
-	 * Here we integrate linearized functions:
-	 *               
-	 * J(E) = int_E   sum_{i=1}^3  J_i Phi_i
-	 *
-	 *       d J                  dJ_i
-	 * DU= - --- = sum_{i=1}^3  - ---  Phi_i = sum_{i=1}^3 DU_i Phi_i
-	 *       d u                  du_i
-	 *
-	 * where J_i are the misfits at the 3 nodes of the triangle
-	 *       Phi_i is the nodal function (P1) with respect to 
-	 *       the vertex i
-	 */
-	if(response==SurfaceAbsVelMisfitEnum){
-		/*We are using an absolute misfit:
-		 *
-		 *      1  [           2              2 ]
-		 * J = --- | (u - u   )  +  (v - v   )  |
-		 *      2  [       obs            obs   ]
-		 *
-		 *        dJ             2
-		 * DU = - -- = (u   - u )
-		 *        du     obs
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			dux_list[i]=obs_vx_list[i]-vx_list[i];
-			duy_list[i]=obs_vy_list[i]-vy_list[i];
-		}
-	}
-	else if(response==SurfaceRelVelMisfitEnum){
-		/*We are using a relative misfit: 
-		 *                        
-		 *      1  [     \bar{v}^2             2   \bar{v}^2              2 ]
-		 * J = --- | -------------  (u - u   ) + -------------  (v - v   )  |
-		 *      2  [  (u   + eps)^2       obs    (v   + eps)^2       obs    ]
-		 *              obs                        obs                      
-		 *
-		 *        dJ     \bar{v}^2
-		 * DU = - -- = ------------- (u   - u )
-		 *        du   (u   + eps)^2    obs
-		 *               obs
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			scalex=pow(meanvel/(obs_vx_list[i]+epsvel),2);
-			scaley=pow(meanvel/(obs_vy_list[i]+epsvel),2);
-			if(obs_vx_list[i]==0)scalex=0;
-			if(obs_vy_list[i]==0)scaley=0;
-			dux_list[i]=scalex*(obs_vx_list[i]-vx_list[i]);
-			duy_list[i]=scaley*(obs_vy_list[i]-vy_list[i]);
-		}
-	}
-	else if(response==SurfaceLogVelMisfitEnum){
-		/*We are using a logarithmic misfit:
-		 *                        
-		 *                 [        vel + eps     ] 2
-		 * J = 4 \bar{v}^2 | log ( -----------  ) |  
-		 *                 [       vel   + eps    ]
-		 *                            obs
-		 *
-		 *        dJ                 2 * log(...)
-		 * DU = - -- = - 4 \bar{v}^2 -------------  u
-		 *        du                 vel^2 + eps
-		 *            
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			velocity_mag=sqrt(pow(vx_list[i],2)+pow(vy_list[i],2))+epsvel; //epsvel to avoid velocity being nil.
-			obs_velocity_mag=sqrt(pow(obs_vx_list[i],2)+pow(obs_vy_list[i],2))+epsvel; //epsvel to avoid observed velocity being nil.
-			scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
-			dux_list[i]=scale*vx_list[i];
-			duy_list[i]=scale*vy_list[i];
-		}
-	}
-	else if(response==SurfaceAverageVelMisfitEnum){
-		/*We are using an spacially average absolute misfit:
-		 *
-		 *      1                    2              2
-		 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
-		 *      S                obs            obs
-		 *
-		 *        dJ      1       1 
-		 * DU = - -- = - --- ----------- * 2 (u - u   )
-		 *        du      S  2 sqrt(...)           obs
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			scale=1.0/(S*sqrt(pow(vx_list[i]-obs_vx_list[i],2)+pow(vy_list[i]-obs_vx_list[i],2))+epsvel);
-			dux_list[i]=scale*(obs_vx_list[i]-vx_list[i]);
-			duy_list[i]=scale*(obs_vy_list[i]-vy_list[i]);
-		}
-	}
-	else if(response==SurfaceLogVxVyMisfitEnum){
-		/*We are using an logarithmic 2 misfit:
-		 *
-		 *      1            [        |u| + eps     2          |v| + eps     2  ]
-		 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   |  
-		 *      2            [       |u    |+ eps              |v    |+ eps     ]
-		 *                              obs                       obs
-		 *        dJ                              1      u                             1
-		 * DU = - -- = - \bar{v}^2 log(u...) --------- ----  ~ - \bar{v}^2 log(u...) ------
-		 *        du                         |u| + eps  |u|                           u + eps
-		 */
-		for (i=0;i<NUMVERTICES;i++){
-			dux_list[i] = - pow(meanvel,(double)2)*(
-						log((fabs(vx_list[i])+epsvel)/(fabs(obs_vx_list[i])+epsvel)) * 1/(vx_list[i]+epsvel));
-			duy_list[i] = - pow(meanvel,(double)2)*(
-						log((fabs(vy_list[i])+epsvel)/(fabs(obs_vy_list[i])+epsvel)) * 1/(vy_list[i]+epsvel));
-		}
-	}
-	else{
-		/*Not supported yet! : */
-		ISSMERROR("response %s not supported yet",EnumToString(response));
-	}
-
-	/*Apply weights to DU*/
-	for (i=0;i<NUMVERTICES;i++){
-		dux_list[i]=weights_list[i]*dux_list[i];
-		duy_list[i]=weights_list[i]*duy_list[i];
-	}
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-
-		TriaRef::GetParameterValue(&dux, &dux_list[0],gauss);
-		TriaRef::GetParameterValue(&duy, &duy_list[0],gauss);
-
-		for (i=0;i<NUMVERTICES;i++){
-			pe->values[i*NDOF4+0]+=dux*Jdet*gauss->weight*l1l2l3[i];
-			pe->values[i*NDOF4+1]+=duy*Jdet*gauss->weight*l1l2l3[i]; 
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorDiagnosticHutter{{{1*/
-ElementVector* Tria::CreatePVectorDiagnosticHutter(void){
-
-	/*Intermediaries */
-	int        i,connectivity;
-	double     constant_part,ub,vb;
-	double     rho_ice,gravity,n,B;
-	double     slope2,thickness;
-	double     slope[2];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	rho_ice=matpar->GetRhoIce();
-	gravity=matpar->GetG();
-	n=matice->GetN();
-	B=matice->GetBbar();
-	Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); ISSMASSERT(slopex_input);
-	Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); ISSMASSERT(slopey_input);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum);  ISSMASSERT(thickness_input);
-
-	/*Spawn 3 sing elements: */
-	gauss=new GaussTria();
-	for(i=0;i<NUMVERTICES;i++){
-
-		gauss->GaussVertex(i);
-
-		connectivity=nodes[i]->GetConnectivity();
-
-		thickness_input->GetParameterValue(&thickness,gauss);
-		slopex_input->GetParameterValue(&slope[0],gauss);
-		slopey_input->GetParameterValue(&slope[1],gauss);
-		slope2=pow(slope[0],2)+pow(slope[1],2);
-
-		constant_part=-2*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2));
-
-		ub=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[0];
-		vb=-1.58*pow((double)10.0,(double)-10.0)*rho_ice*gravity*thickness*slope[1];
-
-		pe->values[2*i]  =(ub-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[0])/(double)connectivity;
-		pe->values[2*i+1]=(vb-2.0*pow(rho_ice*gravity,n)*pow(slope2,((n-1)/2.0))*pow(thickness,n)/(pow(B,n)*(n+1))*slope[1])/(double)connectivity;
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorPrognostic{{{1*/
-ElementVector* Tria::CreatePVectorPrognostic(void){
-
-	switch(GetElementType()){
-		case P1Enum:
-			return CreatePVectorPrognostic_CG();
-		case P1DGEnum:
-			return CreatePVectorPrognostic_DG();
-		default:
-			ISSMERROR("Element type %s not supported yet",EnumToString(GetElementType()));
-	}
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorPrognostic_CG {{{1*/
-ElementVector* Tria::CreatePVectorPrognostic_CG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	double     Jdettria,dt;
-	double     accumulation_g,melting_g,thickness_g;
-	double     xyz_list[NUMVERTICES][3];
-	double     L[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	this->parameters->FindParam(&dt,DtEnum);
-	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
-	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		accumulation_input->GetParameterValue(&accumulation_g,gauss);
-		melting_input->GetParameterValue(&melting_g,gauss);
-		thickness_input->GetParameterValue(&thickness_g,gauss);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorPrognostic_DG {{{1*/
-ElementVector* Tria::CreatePVectorPrognostic_DG(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-
-	/*Intermediaries */
-	int        i,j,ig;
-	double     Jdettria,dt;
-	double     accumulation_g,melting_g,thickness_g;
-	double     xyz_list[NUMVERTICES][3];
-	double     L[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	this->parameters->FindParam(&dt,DtEnum);
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* accumulation_input=inputs->GetInput(AccumulationRateEnum); ISSMASSERT(accumulation_input);
-	Input* melting_input=inputs->GetInput(MeltingRateEnum);           ISSMASSERT(melting_input);
-	Input* thickness_input=inputs->GetInput(ThicknessEnum);           ISSMASSERT(thickness_input);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
-		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
-
-		accumulation_input->GetParameterValue(&accumulation_g,gauss);
-		melting_input->GetParameterValue(&melting_g,gauss);
-		thickness_input->GetParameterValue(&thickness_g,gauss);
-
-		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(accumulation_g-melting_g))*L[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorSlope {{{1*/
-ElementVector* Tria::CreatePVectorSlope(void){
-
-	/*Constants*/
-	const int    numdof=NDOF1*NUMVERTICES;
-	
-	/*Intermediaries */
-	int        i,j,ig;
-	int        analysis_type;
-	double     Jdet;
-	double     xyz_list[NUMVERTICES][3];
-	double     slope[2];
-	double     l1l2l3[3];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	Input* slope_input=NULL;
-	if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==SurfaceSlopeYAnalysisEnum)){
-		slope_input=inputs->GetInput(SurfaceEnum); ISSMASSERT(slope_input);
-	}
-	if ( (analysis_type==BedSlopeXAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
-		slope_input=inputs->GetInput(BedEnum);     ISSMASSERT(slope_input);
-	}
-		
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
-		GetNodalFunctions(l1l2l3, gauss);
-
-		slope_input->GetParameterDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
-
-		if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==BedSlopeXAnalysisEnum)){
-			for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[0]*l1l2l3[i];
-		}
-		if ( (analysis_type==SurfaceSlopeYAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
-			for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[1]*l1l2l3[i];
-		}
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorThermalShelf {{{1*/
-ElementVector* Tria::CreatePVectorThermalShelf(void){
-	
-	/*Constants*/
-	const int  numdof=NUMVERTICES*NDOF1;
-
-	/*Intermediaries */
-	int        i,ig;
-	double     Jdet;
-	double     mixed_layer_capacity,thermal_exchange_velocity;
-	double     rho_ice,rho_water,pressure,dt,scalar_ocean;
-	double     meltingpoint,beta,heatcapacity,t_pmp;
-	double     xyz_list[NUMVERTICES][3];
-	double     l1l2l3[NUMVERTICES];
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
-	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
-	rho_water=matpar->GetRhoWater();
-	rho_ice=matpar->GetRhoIce();
-	heatcapacity=matpar->GetHeatCapacity();
-	beta=matpar->GetBeta();
-	meltingpoint=matpar->GetMeltingPoint();
-	this->parameters->FindParam(&dt,DtEnum);
-	Input* pressure_input=inputs->GetInput(PressureEnum); ISSMASSERT(pressure_input);
-
-	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0], gauss);
-		GetNodalFunctions(&l1l2l3[0], gauss);
-
-		pressure_input->GetParameterValue(&pressure,gauss);
-		t_pmp=meltingpoint-beta*pressure;
-
-		scalar_ocean=gauss->weight*Jdet*rho_water*mixed_layer_capacity*thermal_exchange_velocity*(t_pmp)/(heatcapacity*rho_ice);
-		if(dt) scalar_ocean=dt*scalar_ocean;
-
-		for(i=0;i<numdof;i++) pe->values[i]+=scalar_ocean*l1l2l3[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::CreatePVectorThermalSheet {{{1*/
-ElementVector* Tria::CreatePVectorThermalSheet(void){
-
-	/*Constants*/
-	const int  numdof=NUMVERTICES*NDOF1;
-
-	/*Intermediaries */
-	int        i,ig;
-	int        analysis_type,drag_type;
-	double     xyz_list[NUMVERTICES][3];
-	double     Jdet,dt;
-	double     rho_ice,heatcapacity,geothermalflux_value;
-	double     basalfriction,alpha2,vx,vy,pressure;
-	double     pressure_list[3];
-	double     scalar;
-	double     l1l2l3[NUMVERTICES];
-	Friction*  friction=NULL;
-	GaussTria* gauss=NULL;
-
-	/*Initialize Element vector and return if necessary*/
-	if(IsOnWater()) return NULL;
-	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
-
-	/*Retrieve all inputs and parameters*/
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-	rho_ice=matpar->GetRhoIce();
-	heatcapacity=matpar->GetHeatCapacity();
-	this->inputs->GetParameterValue(&dt,DtEnum);
-	Input* vx_input=inputs->GetInput(VxEnum);                         ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum);                         ISSMASSERT(vy_input);
-	Input* vz_input=inputs->GetInput(VzEnum);                         ISSMASSERT(vz_input);
-	Input* geothermalflux_input=inputs->GetInput(GeothermalFluxEnum); ISSMASSERT(geothermalflux_input);
-
-	/*Build frictoin element, needed later: */
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	if (drag_type!=2)ISSMERROR(" non-viscous friction not supported yet!");
-	friction=new Friction("3d",inputs,matpar,analysis_type);
-
-	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
-	gauss=new GaussTria(2);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
-		GetNodalFunctions(&l1l2l3[0], gauss);
-
-		geothermalflux_input->GetParameterValue(&geothermalflux_value,gauss);
-		friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		basalfriction=alpha2*(pow(vx,2.0)+pow(vy,2.0));
-		
-		scalar=gauss->weight*Jdet*(basalfriction+geothermalflux_value)/(heatcapacity*rho_ice);
-		if(dt) scalar=dt*scalar;
-
-		for(i=0;i<numdof;i++) pe->values[i]+=scalar*l1l2l3[i];
-	}
-
-	/*Clean up and return*/
-	delete gauss;
-	delete friction;
-	return pe;
-}
-/*}}}*/
-/*FUNCTION Tria::GetArea {{{1*/
-double Tria::GetArea(void){
-
-	double area=0;
-	double xyz_list[NUMVERTICES][3];
-	double x1,y1,x2,y2,x3,y3;
-
-	/*Get xyz list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	x1=xyz_list[0][0]; y1=xyz_list[0][1];
-	x2=xyz_list[1][0]; y2=xyz_list[1][1];
-	x3=xyz_list[2][0]; y3=xyz_list[2][1];
- 
-	return (x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
-}
-/*}}}*/
-/*FUNCTION Tria::GetElementType {{{1*/
-int Tria::GetElementType(){
-
-	/*return TriaRef field*/
-	return this->element_type;
-
-}
-/*}}}*/
-/*FUNCTION Tria::GetDofList {{{1*/
-void  Tria::GetDofList(int** pdoflist, int approximation_enum,int setenum){
-
-	int i,j;
-	int count=0;
-	int numberofdofs=0;
-	int* doflist=NULL;
-
-	/*First, figure out size of doflist and create it: */
-	for(i=0;i<3;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
-	doflist=(int*)xmalloc(numberofdofs*sizeof(int));
-
-	/*Populate: */
-	count=0;
-	for(i=0;i<3;i++){
-		nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
-		count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
-	}
-
-	/*Assign output pointers:*/
-	*pdoflist=doflist;
-}
-/*}}}*/
-/*FUNCTION Tria::GetDofList1 {{{1*/
-void  Tria::GetDofList1(int* doflist){
-
-	int i;
-	for(i=0;i<3;i++) doflist[i]=nodes[i]->GetDofList1();
-
-}
-/*}}}*/
-/*FUNCTION Tria::GetSidList {{{1*/
-void  Tria::GetSidList(int* sidlist){
-
-	int i;
-	for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
-
-}
-/*}}}*/
-/*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype) {{{1*/
-void Tria::GetParameterListOnVertices(double* pvalue,int enumtype){
-
-	/*Intermediaries*/
-	double     value[NUMVERTICES];
-	GaussTria *gauss              = NULL;
-
-	/*Recover input*/
-	Input* input=inputs->GetInput(enumtype);
-	if (!input) ISSMERROR("Input %s not found in element",EnumToString(enumtype));
-
-	/*Checks in debugging mode*/
-	ISSMASSERT(pvalue);
-
-	/* Start looping on the number of vertices: */
-	gauss=new GaussTria();
-	for (int iv=0;iv<NUMVERTICES;iv++){
-		gauss->GaussVertex(iv);
-		input->GetParameterValue(&pvalue[iv],gauss);
-	}
-
-	/*clean-up*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue) {{{1*/
-void Tria::GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue){
-
-	double     value[NUMVERTICES];
-	GaussTria *gauss = NULL;
-	Input     *input = inputs->GetInput(enumtype);
-
-	/*Checks in debugging mode*/
-	ISSMASSERT(pvalue);
-
-	/* Start looping on the number of vertices: */
-	if (input){
-		gauss=new GaussTria();
-		for (int iv=0;iv<NUMVERTICES;iv++){
-			gauss->GaussVertex(iv);
-			input->GetParameterValue(&pvalue[iv],gauss);
-		}
-	}
-	else{
-		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
-	}
-
-	/*clean-up*/
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::GetParameterValue(double* pvalue,Node* node,int enumtype) {{{1*/
-void Tria::GetParameterValue(double* pvalue,Node* node,int enumtype){
-
-	Input* input=inputs->GetInput(enumtype);
-	if(!input) ISSMERROR("No input of type %s found in tria",EnumToString(enumtype));
-
-	GaussTria* gauss=new GaussTria();
-	gauss->GaussVertex(this->GetNodeIndex(node));
-
-	input->GetParameterValue(pvalue,gauss);
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHoriz{{{1*/
-void  Tria::GetSolutionFromInputsDiagnosticHoriz(Vec solution){
-
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int          i;
-	int*         doflist=NULL;
-	double       vx,vy;
-	double       values[numdof];
-	GaussTria*   gauss=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Get inputs*/
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	/*P1 element only for now*/
-	gauss=new GaussTria();
-	for(i=0;i<NUMVERTICES;i++){
-
-		gauss->GaussVertex(i);
-
-		/*Recover vx and vy*/
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		values[i*NDOF2+0]=vx;
-		values[i*NDOF2+1]=vy;
-	}
-
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHutter{{{1*/
-void  Tria::GetSolutionFromInputsDiagnosticHutter(Vec solution){
-
-	const int    numdof=NDOF2*NUMVERTICES;
-
-	int i,dummy;
-	int*         doflist=NULL;
-	double       vx,vy;
-	double       values[numdof];
-	GaussTria*   gauss=NULL;
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Get inputs*/
-	Input* vx_input=inputs->GetInput(VxEnum); ISSMASSERT(vx_input);
-	Input* vy_input=inputs->GetInput(VyEnum); ISSMASSERT(vy_input);
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	/*P1 element only for now*/
-	gauss=new GaussTria();
-	for(i=0;i<NUMVERTICES;i++){
-
-		gauss->GaussVertex(i);
-
-		/*Recover vx and vy*/
-		vx_input->GetParameterValue(&vx,gauss);
-		vy_input->GetParameterValue(&vy,gauss);
-		values[i*NDOF2+0]=vx;
-		values[i*NDOF2+1]=vy;
-	}
-
-	VecSetValues(solution,numdof,doflist,(const double*)values,INSERT_VALUES);
-
-	/*Free ressources:*/
-	delete gauss;
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){{{1*/
-void Tria::GetStrainRate2d(double* epsilon,double* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){
-	/*Compute the 2d Strain Rate (3 components):
-	 * epsilon=[exx eyy exy] */
-
-	int i;
-	double epsilonvx[3];
-	double epsilonvy[3];
-
-	/*Check that both inputs have been found*/
-	if (!vx_input || !vy_input){
-		ISSMERROR("Input missing. Here are the input pointers we have for vx: %p, vy: %p\n",vx_input,vy_input);
-	}
-
-	/*Get strain rate assuming that epsilon has been allocated*/
-	vx_input->GetVxStrainRate2d(epsilonvx,xyz_list,gauss);
-	vy_input->GetVyStrainRate2d(epsilonvy,xyz_list,gauss);
-
-	/*Sum all contributions*/
-	for(i=0;i<3;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
-}
-/*}}}*/
-/*FUNCTION Tria::GradjDragStokes {{{1*/
-void  Tria::GradjDragStokes(Vec gradient){
-
-	int        i,ig;
-	int        drag_type,analysis_type;
-	int        doflist1[NUMVERTICES];
-	double     bed,thickness,Neff;
-	double     lambda,mu,xi,Jdet,vx,vy,vz;
-	double     alpha_complement,drag,cm_noisedmp;
-	double     surface_normal[3],bed_normal[3];
-	double     xyz_list[NUMVERTICES][3];
-	double     dh1dh3[NDOF2][NUMVERTICES];
-	double     dk[NDOF2]; 
-	double     l1l2l3[3];
-	double     epsilon[3]; /* epsilon=[exx,eyy,exy];*/
-	double     grade_g[NUMVERTICES]={0.0};
-	double     grade_g_gaussian[NUMVERTICES];
-	Friction*  friction=NULL;
-	GaussTria* gauss=NULL;
-
-	/*retrive parameters: */
-	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
-
-	/*retrieve inputs :*/
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	Input* drag_input    =inputs->GetInput(DragCoefficientEnum); ISSMASSERT(drag_input);
-	Input* vx_input      =inputs->GetInput(VxEnum);              ISSMASSERT(vx_input);
-	Input* vy_input      =inputs->GetInput(VyEnum);              ISSMASSERT(vy_input);
-	Input* vz_input      =inputs->GetInput(VzEnum);              ISSMASSERT(vz_input);
-	Input* adjointx_input=inputs->GetInput(AdjointxEnum);        ISSMASSERT(adjointx_input);
-	Input* adjointy_input=inputs->GetInput(AdjointyEnum);        ISSMASSERT(adjointy_input);
-	Input* adjointz_input=inputs->GetInput(AdjointzEnum);        ISSMASSERT(adjointz_input);
-
-	/*retrieve some parameters: */
-	this->parameters->FindParam(&cm_noisedmp,CmNoiseDmpEnum);
-
-	/*Get out if shelf*/
-	if(IsOnShelf())return;
-
-	/* Get node coordinates and dof list: */
-	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
-	GetDofList1(&doflist1[0]);
-
-	/*Build frictoin element, needed later: */
-	inputs->GetParameterValue(&drag_type,DragTypeEnum);
-	friction=new Friction("2d",inputs,matpar,analysis_type);
-
-	/* Start  looping on the number of gaussian points: */
-	gauss=new GaussTria(4);
-	for(ig=gauss->begin();ig<gauss->end();ig++){
-
-		gauss->GaussPoint(ig);
-
-		/*Recover alpha_complement and drag: */
-		if (drag_type==2) friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum);
-		else alpha_complement=0;
-		drag_input->GetParameterValue(&drag,gauss);
-
-		/*recover lambda mu and xi: */
-		adjointx_input->GetParameterValue(&lambda,gauss);
-		adjointy_input->GetParameterValue(&mu    ,gauss);
-		adjointz_input->GetParameterValue(&xi    ,gauss);
-
-		/*recover vx vy and vz: */
-		vx_input->GetParameterValue(&vx, gauss);
-		vy_input->GetParameterValue(&vy, gauss);
-		vz_input->GetParameterValue(&vz, gauss);
-
-		/*Get normal vector to the bed */
-		SurfaceNormal(&surface_normal[0],xyz_list);
-
-		bed_normal[0]=-surface_normal[0]; //Program is for surface, so the normal to the bed is the opposite of the result
-		bed_normal[1]=-surface_normal[1];
-		bed_normal[2]=-surface_normal[2];
-
-		/* Get Jacobian determinant: */
-		GetJacobianDeterminant3d(&Jdet, &xyz_list[0][0],gauss);
-
-		/* Get nodal functions value at gaussian point:*/
-		GetNodalFunctions(l1l2l3, gauss);
-
-		/*Get nodal functions derivatives*/
-		GetNodalFunctionsDerivatives(&dh1dh3[0][0],&xyz_list[0][0],gauss);
-
-		/*Get k derivative: dk/dx */
-		drag_input->GetParameterDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
-
-		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
-		for (i=0;i<NUMVERTICES;i++){
-			//standard gradient dJ/dki
-			grade_g_gaussian[i]=(
-						-lambda*(2*drag*alpha_complement*(vx - vz*bed_normal[0]*bed_normal[2]))
-						-mu    *(2*drag*alpha_complement*(vy - vz*bed_normal[1]*bed_normal[2]))
-						-xi    *(2*drag*alpha_complement*(-vx*bed_normal[0]*bed_normal[2]-vy*bed_normal[1]*bed_normal[2]))
-						)*Jdet*gauss->weight*l1l2l3[i]; 
-
-			//Add regularization term
-			grade_g_gaussian[i]+= - cm_noisedmp*Jdet*gauss->weight*(dh1dh3[0][i]*dk[0]+dh1dh3[1][i]*dk[1]);
-		}
-
-		/*Add gradje_g_gaussian vector to gradje_g: */
-		for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
-	}
-
-	VecSetValues(gradient,NUMVERTICES,doflist1,(const double*)grade_g,ADD_VALUES);
-
-	delete friction;
-	delete gauss;
-}
-/*}}}*/
-/*FUNCTION Tria::InputUpdateFromSolutionAdjointBalancedthickness {{{1*/
-void  Tria::InputUpdateFromSolutionAdjointBalancedthickness(double* solution){
-
-	const int numdof=NDOF1*NUMVERTICES;
-
-	int       i;
-	int*      doflist=NULL;
-	double    values[numdof];
-	double    lambda[NUMVERTICES];
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<numdof;i++) lambda[i]=values[i];
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new TriaVertexInput(AdjointEnum,lambda));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Tria::InputUpdateFromSolutionAdjointHoriz {{{1*/
-void  Tria::InputUpdateFromSolutionAdjointHoriz(double* solution){
-
-	const int numdof=NDOF2*NUMVERTICES;
-
-	int       i;
-	int*      doflist=NULL;
-	double    values[numdof];
-	double    lambdax[NUMVERTICES];
-	double    lambday[NUMVERTICES];
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		lambdax[i]=values[i*NDOF2+0];
-		lambday[i]=values[i*NDOF2+1];
-	}
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new TriaVertexInput(AdjointxEnum,lambdax));
-	this->inputs->AddInput(new TriaVertexInput(AdjointyEnum,lambday));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHoriz {{{1*/
-void  Tria::InputUpdateFromSolutionDiagnosticHoriz(double* solution){
-	
-	const int numdof=NDOF2*NUMVERTICES;
-
-	int       i;
-	int       dummy;
-	int*      doflist=NULL;
-	double    rho_ice,g;
-	double    values[numdof];
-	double    vx[NUMVERTICES];
-	double    vy[NUMVERTICES];
-	double    vz[NUMVERTICES];
-	double    vel[NUMVERTICES];
-	double    pressure[NUMVERTICES];
-	double    thickness[NUMVERTICES];
-	
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=values[i*NDOF2+0];
-		vy[i]=values[i*NDOF2+1];
-	}
-
-	/*Get Vz and compute vel*/
-	GetParameterListOnVertices(&vz[0],VzEnum,0);
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D, 
-	 *so the pressure is just the pressure at the bedrock: */
-	rho_ice=matpar->GetRhoIce();
-	g=matpar->GetG();
-	GetParameterListOnVertices(&thickness[0],ThicknessEnum);
-	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-
-}
-/*}}}*/
-/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHutter {{{1*/
-void  Tria::InputUpdateFromSolutionDiagnosticHutter(double* solution){
-	
-	const int numdof=NDOF2*NUMVERTICES;
-	
-	int       i;
-	int       dummy;
-	int*      doflist=NULL;
-	double    rho_ice,g;
-	double    values[numdof];
-	double    vx[NUMVERTICES];
-	double    vy[NUMVERTICES];
-	double    vz[NUMVERTICES];
-	double    vel[NUMVERTICES];
-	double    pressure[NUMVERTICES];
-	double    thickness[NUMVERTICES];
-	double*   vz_ptr=NULL;
-	Input*    vz_input=NULL;
-	
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
-	for(i=0;i<NUMVERTICES;i++){
-		vx[i]=values[i*NDOF2+0];
-		vy[i]=values[i*NDOF2+1];
-	}
-
-	/*Get Vz*/
-	vz_input=inputs->GetInput(VzEnum);
-	if (vz_input){
-		if (vz_input->Enum()!=TriaVertexInputEnum){
-			ISSMERROR("Cannot compute Vel as Vz is of type %s",EnumToString(vz_input->Enum()));
-		}
-		vz_input->GetValuesPtr(&vz_ptr,&dummy);
-		for(i=0;i<NUMVERTICES;i++) vz[i]=vz_ptr[i];
-	}
-	else{
-		for(i=0;i<NUMVERTICES;i++) vz[i]=0.0;
-	}
-
-	/*Now Compute vel*/
-	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
-
-	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D, 
-	 *so the pressure is just the pressure at the bedrock: */
-	rho_ice=matpar->GetRhoIce();
-	g=matpar->GetG();
-	GetParameterListOnVertices(&thickness[0],ThicknessEnum);
-	for(i=0;i<NUMVERTICES;i++) pressure[i]=rho_ice*g*thickness[i];
-
-	/*Now, we have to move the previous Vx and Vy inputs  to old 
-	 * status, otherwise, we'll wipe them off: */
-	this->inputs->ChangeEnum(VxEnum,VxOldEnum);
-	this->inputs->ChangeEnum(VyEnum,VyOldEnum);
-	this->inputs->ChangeEnum(PressureEnum,PressureOldEnum);
-
-	/*Add vx and vy as inputs to the tria element: */
-	this->inputs->AddInput(new TriaVertexInput(VxEnum,vx));
-	this->inputs->AddInput(new TriaVertexInput(VyEnum,vy));
-	this->inputs->AddInput(new TriaVertexInput(VelEnum,vel));
-	this->inputs->AddInput(new TriaVertexInput(PressureEnum,pressure));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Tria::InputUpdateFromSolutionOneDof{{{1*/
-void  Tria::InputUpdateFromSolutionOneDof(double* solution,int enum_type){
-
-	const int numdof          = NDOF1*NUMVERTICES;
-
-	int*      doflist=NULL;
-	double    values[numdof];
-
-	/*Get dof list: */
-	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
-
-	/*Use the dof list to index into the solution vector: */
-	for(int i=0;i<numdof;i++) values[i]=solution[doflist[i]];
-
-	/*Add input to the element: */
-	this->inputs->AddInput(new TriaVertexInput(enum_type,values));
-
-	/*Free ressources:*/
-	xfree((void**)&doflist);
-}
-/*}}}*/
-/*FUNCTION Tria::IsInput{{{1*/
-bool Tria::IsInput(int name){
-	if (
-				name==ThicknessEnum ||
-				name==SurfaceEnum ||
-				name==BedEnum ||
-				name==SurfaceSlopeXEnum ||
-				name==SurfaceSlopeYEnum ||
-				name==MeltingRateEnum ||
-				name==DtEnum ||
-				name==AccumulationRateEnum ||
-				name==SurfaceAreaEnum||
-				name==VxEnum ||
-				name==VyEnum ||
-				name==VxObsEnum ||
-				name==VyObsEnum ||
-				name==CmResponseEnum ||
-				name==DragCoefficientEnum ||
-				name==GradientEnum ||
-				name==OldGradientEnum
-		){
-		return true;
-	}
-	else return false;
-}
-/*}}}*/
-/*FUNCTION Tria::SetClone {{{1*/
-void  Tria::SetClone(int* minranks){
-
-	ISSMERROR("not implemented yet");
-}
-/*}}}1*/
-/*FUNCTION Tria::SurfaceNormal{{{1*/
-void Tria::SurfaceNormal(double* surface_normal, double xyz_list[3][3]){
-
-	int i;
-	double v13[3],v23[3];
-	double normal[3];
-	double normal_norm;
-
-	for (i=0;i<3;i++){
-		v13[i]=xyz_list[0][i]-xyz_list[2][i];
-		v23[i]=xyz_list[1][i]-xyz_list[2][i];
-	}
-
-	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
-	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
-	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
-
-	normal_norm=sqrt( pow(normal[0],(double)2)+pow(normal[1],(double)2)+pow(normal[2],(double)2) );
-
-	*(surface_normal)=normal[0]/normal_norm;
-	*(surface_normal+1)=normal[1]/normal_norm;
-	*(surface_normal+2)=normal[2]/normal_norm;
-}
-/*}}}*/
Index: /issm/trunk/src/c/objects/Elements/Tria.h
===================================================================
--- /issm/trunk/src/c/objects/Elements/Tria.h	(revision 6409)
+++ /issm/trunk/src/c/objects/Elements/Tria.h	(revision 6410)
@@ -166,5 +166,5 @@
 		void	  GetDofList(int** pdoflist,int approximation_enum,int setenum);
 		void	  GetDofList1(int* doflist);
-		void      GetSidList(int* sidlist);
+		void    GetSidList(int* sidlist);
 		void    GetParameterListOnVertices(double* pvalue,int enumtype);
 		void    GetParameterListOnVertices(double* pvalue,int enumtype,double defaultvalue);
