Index: /issm/trunk-jpl/src/c/Makefile.am
===================================================================
--- /issm/trunk-jpl/src/c/Makefile.am	(revision 15011)
+++ /issm/trunk-jpl/src/c/Makefile.am	(revision 15012)
@@ -22,42 +22,41 @@
 			   ./main/globals.h\
 					./classes/classes.h\
-					./classes/objects.h\
-					./classes/objects/Object.h\
+					./classes/Object.h\
 					./classes/gauss/GaussTria.h\
 					./classes/gauss/GaussTria.cpp\
-					./classes/objects/Update.h\
-					./classes/objects/Element.h\
+					./classes/Update.h\
+					./classes/Element.h\
 					./classes/FemModel.h\
 					./classes/FemModel.cpp\
-					./classes/objects/Material.h\
-					./classes/objects/Load.h\
-					./classes/objects/Contour.h\
-					./classes/objects/Loads/Friction.h\
-					./classes/objects/Loads/Friction.cpp\
-					./classes/objects/Inputs/TransientInput.h\
-					./classes/objects/Inputs/TransientInput.cpp\
-					./classes/objects/Constraints/SpcTransient.cpp\
-					./classes/objects/Constraints/SpcTransient.h\
-					./classes/objects/IndependentObject.h\
-					./classes/objects/IndependentObject.cpp\
-					./classes/objects/DependentObject.h\
-					./classes/objects/DependentObject.cpp\
+					./classes/Material.h\
+					./classes/Load.h\
+					./classes/Contour.h\
+					./classes/Loads/Friction.h\
+					./classes/Loads/Friction.cpp\
+					./classes/Inputs/TransientInput.h\
+					./classes/Inputs/TransientInput.cpp\
+					./classes/Constraints/SpcTransient.cpp\
+					./classes/Constraints/SpcTransient.h\
+					./classes/IndependentObject.h\
+					./classes/IndependentObject.cpp\
+					./classes/DependentObject.h\
+					./classes/DependentObject.cpp\
 					./classes/DofIndexing.h\
 					./classes/DofIndexing.cpp\
 					./classes/IoModel.h\
 					./classes/IoModel.cpp\
-					./classes/objects/DataSet.h\
-					./classes/objects/DataSet.cpp\
-					./classes/objects/Nodes.h\
-					./classes/objects/Nodes.cpp\
-					./classes/objects/Vertices.h\
-					./classes/objects/Vertices.cpp\
-					./classes/objects/Bucket.h\
-					./classes/objects/Node.h\
-					./classes/objects/Node.cpp\
-					./classes/objects/Segment.h\
-					./classes/objects/Vertex.h\
-					./classes/objects/Vertex.cpp\
-					./classes/objects/AdolcEdf.h\
+					./classes/DataSet.h\
+					./classes/DataSet.cpp\
+					./classes/Nodes.h\
+					./classes/Nodes.cpp\
+					./classes/Vertices.h\
+					./classes/Vertices.cpp\
+					./classes/Bucket.h\
+					./classes/Node.h\
+					./classes/Node.cpp\
+					./classes/Segment.h\
+					./classes/Vertex.h\
+					./classes/Vertex.cpp\
+					./classes/AdolcEdf.h\
 					./classes/ToolkitOptions.h\
 					./classes/ToolkitOptions.cpp\
@@ -66,62 +65,62 @@
 					./classes/Patch.h\
 					./classes/Patch.cpp\
-					./classes/objects/ElementResults/ElementResultLocal.h\
-					./classes/objects/ElementResults/DoubleElementResult.h\
-					./classes/objects/ElementResults/DoubleElementResult.cpp\
-					./classes/objects/ElementResults/TriaP1ElementResult.h\
-					./classes/objects/ElementResults/TriaP1ElementResult.cpp\
-					./classes/objects/ElementResults/BoolElementResult.h\
-					./classes/objects/ElementResults/BoolElementResult.cpp\
-					./classes/objects/ExternalResults/Results.h\
-					./classes/objects/ExternalResults/Results.cpp\
-					./classes/objects/ExternalResults/ExternalResult.h\
-					./classes/objects/ExternalResults/GenericExternalResult.h\
-					./classes/objects/Elements/Elements.h\
-					./classes/objects/Elements/Elements.cpp\
-					./classes/objects/Elements/Tria.h\
-					./classes/objects/Elements/Tria.cpp\
-					./classes/objects/Elements/TriaHook.h\
-					./classes/objects/Elements/TriaHook.cpp\
-					./classes/objects/Elements/TriaRef.h\
-					./classes/objects/Elements/TriaRef.cpp\
-					./classes/objects/Inputs/Inputs.h\
-					./classes/objects/Inputs/Inputs.cpp\
-					./classes/objects/Inputs/Input.h\
-					./classes/objects/Inputs/InputLocal.h\
-					./classes/objects/Inputs/TriaP1Input.h\
-					./classes/objects/Inputs/TriaP1Input.cpp\
-					./classes/objects/Inputs/BoolInput.h\
-					./classes/objects/Inputs/BoolInput.cpp\
-					./classes/objects/Inputs/IntInput.h\
-					./classes/objects/Inputs/IntInput.cpp\
-					./classes/objects/Inputs/DoubleInput.h\
-					./classes/objects/Inputs/DoubleInput.cpp\
-					./classes/objects/Inputs/DatasetInput.h\
-					./classes/objects/Inputs/DatasetInput.cpp\
-					./classes/objects/Materials/Materials.h\
-					./classes/objects/Materials/Materials.cpp\
-					./classes/objects/Materials/Matice.h\
-					./classes/objects/Materials/Matice.cpp\
-					./classes/objects/Materials/Matdamageice.h\
-					./classes/objects/Materials/Matdamageice.cpp\
-					./classes/objects/Materials/Matpar.h\
-					./classes/objects/Materials/Matpar.cpp\
-					./classes/objects/Constraints/Constraints.h\
-					./classes/objects/Constraints/Constraints.cpp\
-					./classes/objects/Constraints/Constraint.h\
-					./classes/objects/Constraints/SpcStatic.cpp\
-					./classes/objects/Constraints/SpcStatic.h\
-					./classes/objects/Constraints/SpcDynamic.cpp\
-					./classes/objects/Constraints/SpcDynamic.h\
-					./classes/objects/Loads/Loads.h\
-					./classes/objects/Loads/Loads.cpp\
-					./classes/objects/Loads/Penpair.cpp\
-					./classes/objects/Loads/Penpair.h\
-					./classes/objects/Loads/Pengrid.cpp\
-					./classes/objects/Loads/Pengrid.h\
-					./classes/objects/Loads/Icefront.cpp\
-					./classes/objects/Loads/Icefront.h\
-					./classes/objects/Loads/Numericalflux.cpp\
-					./classes/objects/Loads/Numericalflux.h\
+					./classes/ElementResults/ElementResultLocal.h\
+					./classes/ElementResults/DoubleElementResult.h\
+					./classes/ElementResults/DoubleElementResult.cpp\
+					./classes/ElementResults/TriaP1ElementResult.h\
+					./classes/ElementResults/TriaP1ElementResult.cpp\
+					./classes/ElementResults/BoolElementResult.h\
+					./classes/ElementResults/BoolElementResult.cpp\
+					./classes/ExternalResults/Results.h\
+					./classes/ExternalResults/Results.cpp\
+					./classes/ExternalResults/ExternalResult.h\
+					./classes/ExternalResults/GenericExternalResult.h\
+					./classes/Elements/Elements.h\
+					./classes/Elements/Elements.cpp\
+					./classes/Elements/Tria.h\
+					./classes/Elements/Tria.cpp\
+					./classes/Elements/TriaHook.h\
+					./classes/Elements/TriaHook.cpp\
+					./classes/Elements/TriaRef.h\
+					./classes/Elements/TriaRef.cpp\
+					./classes/Inputs/Inputs.h\
+					./classes/Inputs/Inputs.cpp\
+					./classes/Inputs/Input.h\
+					./classes/Inputs/InputLocal.h\
+					./classes/Inputs/TriaP1Input.h\
+					./classes/Inputs/TriaP1Input.cpp\
+					./classes/Inputs/BoolInput.h\
+					./classes/Inputs/BoolInput.cpp\
+					./classes/Inputs/IntInput.h\
+					./classes/Inputs/IntInput.cpp\
+					./classes/Inputs/DoubleInput.h\
+					./classes/Inputs/DoubleInput.cpp\
+					./classes/Inputs/DatasetInput.h\
+					./classes/Inputs/DatasetInput.cpp\
+					./classes/Materials/Materials.h\
+					./classes/Materials/Materials.cpp\
+					./classes/Materials/Matice.h\
+					./classes/Materials/Matice.cpp\
+					./classes/Materials/Matdamageice.h\
+					./classes/Materials/Matdamageice.cpp\
+					./classes/Materials/Matpar.h\
+					./classes/Materials/Matpar.cpp\
+					./classes/Constraints/Constraints.h\
+					./classes/Constraints/Constraints.cpp\
+					./classes/Constraints/Constraint.h\
+					./classes/Constraints/SpcStatic.cpp\
+					./classes/Constraints/SpcStatic.h\
+					./classes/Constraints/SpcDynamic.cpp\
+					./classes/Constraints/SpcDynamic.h\
+					./classes/Loads/Loads.h\
+					./classes/Loads/Loads.cpp\
+					./classes/Loads/Penpair.cpp\
+					./classes/Loads/Penpair.h\
+					./classes/Loads/Pengrid.cpp\
+					./classes/Loads/Pengrid.h\
+					./classes/Loads/Icefront.cpp\
+					./classes/Loads/Icefront.h\
+					./classes/Loads/Numericalflux.cpp\
+					./classes/Loads/Numericalflux.h\
 					./classes/matrix/matrixobjects.h\
 					./classes/matrix/ElementMatrix.h\
@@ -133,42 +132,42 @@
 					./classes/toolkits/Vector.h\
 					./classes/toolkits/Solver.h\
-					./classes/objects/Params/Parameters.h\
-					./classes/objects/Params/Parameters.cpp\
-					./classes/objects/Params/Param.h\
-					./classes/objects/Params/GenericParam.h\
-					./classes/objects/Params/BoolParam.cpp\
-					./classes/objects/Params/BoolParam.h\
-					./classes/objects/Params/IntParam.cpp\
-					./classes/objects/Params/IntParam.h\
-					./classes/objects/Params/IntVecParam.cpp\
-					./classes/objects/Params/IntVecParam.h\
-					./classes/objects/Params/IntMatParam.cpp\
-					./classes/objects/Params/IntMatParam.h\
-					./classes/objects/Params/DoubleParam.cpp\
-					./classes/objects/Params/DoubleParam.h\
-					./classes/objects/Params/FileParam.cpp\
-					./classes/objects/Params/FileParam.h\
-					./classes/objects/Params/StringArrayParam.cpp\
-					./classes/objects/Params/StringArrayParam.h\
-					./classes/objects/Params/DoubleMatParam.cpp\
-					./classes/objects/Params/DoubleMatParam.h\
-					./classes/objects/Params/DoubleTransientMatParam.cpp\
-					./classes/objects/Params/DoubleTransientMatParam.h\
-					./classes/objects/Params/DoubleMatArrayParam.cpp\
-					./classes/objects/Params/DoubleMatArrayParam.h\
-					./classes/objects/Params/DoubleVecParam.cpp\
-					./classes/objects/Params/DoubleVecParam.h\
-					./classes/objects/Params/StringParam.cpp\
-					./classes/objects/Params/StringParam.h\
-					./classes/objects/Params/MatrixParam.h\
-					./classes/objects/Params/MatrixParam.cpp\
-					./classes/objects/Params/VectorParam.h\
-					./classes/objects/Params/VectorParam.cpp\
-					./classes/objects/Params/TransientParam.h\
-					./classes/objects/Params/TransientParam.cpp\
-					./classes/objects/Params/DataSetParam.h\
-					./classes/objects/Params/DataSetParam.cpp\
-					./classes/objects/Profiler.h\
-					./classes/objects/Profiler.cpp\
+					./classes/Params/Parameters.h\
+					./classes/Params/Parameters.cpp\
+					./classes/Params/Param.h\
+					./classes/Params/GenericParam.h\
+					./classes/Params/BoolParam.cpp\
+					./classes/Params/BoolParam.h\
+					./classes/Params/IntParam.cpp\
+					./classes/Params/IntParam.h\
+					./classes/Params/IntVecParam.cpp\
+					./classes/Params/IntVecParam.h\
+					./classes/Params/IntMatParam.cpp\
+					./classes/Params/IntMatParam.h\
+					./classes/Params/DoubleParam.cpp\
+					./classes/Params/DoubleParam.h\
+					./classes/Params/FileParam.cpp\
+					./classes/Params/FileParam.h\
+					./classes/Params/StringArrayParam.cpp\
+					./classes/Params/StringArrayParam.h\
+					./classes/Params/DoubleMatParam.cpp\
+					./classes/Params/DoubleMatParam.h\
+					./classes/Params/DoubleTransientMatParam.cpp\
+					./classes/Params/DoubleTransientMatParam.h\
+					./classes/Params/DoubleMatArrayParam.cpp\
+					./classes/Params/DoubleMatArrayParam.h\
+					./classes/Params/DoubleVecParam.cpp\
+					./classes/Params/DoubleVecParam.h\
+					./classes/Params/StringParam.cpp\
+					./classes/Params/StringParam.h\
+					./classes/Params/MatrixParam.h\
+					./classes/Params/MatrixParam.cpp\
+					./classes/Params/VectorParam.h\
+					./classes/Params/VectorParam.cpp\
+					./classes/Params/TransientParam.h\
+					./classes/Params/TransientParam.cpp\
+					./classes/Params/DataSetParam.h\
+					./classes/Params/DataSetParam.cpp\
+					./classes/Profiler.h\
+					./classes/Profiler.cpp\
 					./shared/shared.h\
 					./shared/MemOps/MemOps.h\
@@ -331,10 +330,10 @@
 					./solutionsequences/solutionsequence_nonlinear.cpp\
 					./solutionsequences/solutionsequence_newton.cpp\
-					./classes/objects/Options/Options.h\
-					./classes/objects/Options/Options.cpp\
-					./classes/objects/Options/Option.h\
-					./classes/objects/Options/GenericOption.h\
-					./classes/objects/Options/OptionUtilities.cpp\
-					./classes/objects/Options/OptionUtilities.h\
+					./classes/Options/Options.h\
+					./classes/Options/Options.cpp\
+					./classes/Options/Option.h\
+					./classes/Options/GenericOption.h\
+					./classes/Options/OptionUtilities.cpp\
+					./classes/Options/OptionUtilities.h\
 					./classes/RiftStruct.cpp\
 					./classes/RiftStruct.h
@@ -428,6 +427,6 @@
 					  ./modules/RheologyBbarAbsGradientx/RheologyBbarAbsGradientx.cpp\
 					  ./modules/RheologyBbarAbsGradientx/RheologyBbarAbsGradientx.h\
-					  ./classes/objects/Inputs/ControlInput.h\
-					  ./classes/objects/Inputs/ControlInput.cpp\
+					  ./classes/Inputs/ControlInput.h\
+					  ./classes/Inputs/ControlInput.cpp\
 					  ./shared/Numerics/BrentSearch.cpp\
 					  ./shared/Numerics/OptimalSearch.cpp \
@@ -522,6 +521,6 @@
 #}}}
 #Rifts sources  {{{
-rifts_sources = ./classes/objects/Loads/Riftfront.cpp\
-				    ./classes/objects/Loads/Riftfront.h\
+rifts_sources = ./classes/Loads/Riftfront.cpp\
+				    ./classes/Loads/Riftfront.h\
 				    ./modules/ConstraintsStatex/RiftConstraintsState.cpp
 #}}}
@@ -532,14 +531,14 @@
 threed_sources = ./classes/gauss/GaussPenta.h\
 				     ./classes/gauss/GaussPenta.cpp\
-				     ./classes/objects/ElementResults/PentaP1ElementResult.h\
-				     ./classes/objects/ElementResults/PentaP1ElementResult.cpp\
-				     ./classes/objects/Inputs/PentaP1Input.h\
-				     ./classes/objects/Inputs/PentaP1Input.cpp\
-				     ./classes/objects/Elements/Penta.h\
-				     ./classes/objects/Elements/Penta.cpp\
-				     ./classes/objects/Elements/PentaHook.h\
-				     ./classes/objects/Elements/PentaHook.cpp\
-				     ./classes/objects/Elements/PentaRef.h\
-				     ./classes/objects/Elements/PentaRef.cpp
+				     ./classes/ElementResults/PentaP1ElementResult.h\
+				     ./classes/ElementResults/PentaP1ElementResult.cpp\
+				     ./classes/Inputs/PentaP1Input.h\
+				     ./classes/Inputs/PentaP1Input.cpp\
+				     ./classes/Elements/Penta.h\
+				     ./classes/Elements/Penta.cpp\
+				     ./classes/Elements/PentaHook.h\
+				     ./classes/Elements/PentaHook.cpp\
+				     ./classes/Elements/PentaRef.h\
+				     ./classes/Elements/PentaRef.cpp
 #}}}
 #Bamg sources  {{{
@@ -664,58 +663,58 @@
 			     ./modules/KMLOverlayx/KMLOverlayx.h\
 			     ./modules/KMLOverlayx/KMLOverlayx.cpp\
-			     ./classes/objects/KML/KML_Attribute.cpp\
-			     ./classes/objects/KML/KML_Attribute.h\
-			     ./classes/objects/KML/KML_Comment.cpp\
-			     ./classes/objects/KML/KML_Comment.h\
-			     ./classes/objects/KML/KML_ColorStyle.cpp\
-			     ./classes/objects/KML/KML_ColorStyle.h\
-			     ./classes/objects/KML/KML_Container.cpp\
-			     ./classes/objects/KML/KML_Container.h\
-			     ./classes/objects/KML/KML_Document.cpp\
-			     ./classes/objects/KML/KML_Document.h\
-			     ./classes/objects/KML/KML_Feature.cpp\
-			     ./classes/objects/KML/KML_Feature.h\
-			     ./classes/objects/KML/KML_File.cpp\
-			     ./classes/objects/KML/KML_File.h\
-			     ./classes/objects/KML/KML_Folder.cpp\
-			     ./classes/objects/KML/KML_Folder.h\
-			     ./classes/objects/KML/KML_Geometry.cpp\
-			     ./classes/objects/KML/KML_Geometry.h\
-			     ./classes/objects/KML/KML_GroundOverlay.cpp\
-			     ./classes/objects/KML/KML_GroundOverlay.h\
-			     ./classes/objects/KML/KML_Icon.cpp\
-			     ./classes/objects/KML/KML_Icon.h\
-			     ./classes/objects/KML/KML_LatLonBox.cpp\
-		  	     ./classes/objects/KML/KML_LatLonBox.h\
-			     ./classes/objects/KML/KML_LinearRing.cpp\
-			     ./classes/objects/KML/KML_LinearRing.h\
-			     ./classes/objects/KML/KML_LineString.cpp\
-			     ./classes/objects/KML/KML_LineString.h\
-			     ./classes/objects/KML/KML_LineStyle.cpp\
-			     ./classes/objects/KML/KML_LineStyle.h\
-			     ./classes/objects/KML/KML_MultiGeometry.cpp\
-			     ./classes/objects/KML/KML_MultiGeometry.h\
-			     ./classes/objects/KML/KML_Object.cpp\
-			     ./classes/objects/KML/KML_Object.h\
-			     ./classes/objects/KML/KML_Overlay.cpp\
-			     ./classes/objects/KML/KML_Overlay.h\
-			     ./classes/objects/KML/KML_Point.cpp\
-			     ./classes/objects/KML/KML_Point.h\
-			     ./classes/objects/KML/KML_Placemark.cpp\
-			     ./classes/objects/KML/KML_Placemark.h\
-			     ./classes/objects/KML/KML_Polygon.cpp\
-			     ./classes/objects/KML/KML_Polygon.h\
-			     ./classes/objects/KML/KML_PolyStyle.cpp\
-			     ./classes/objects/KML/KML_PolyStyle.h\
-			     ./classes/objects/KML/KML_Style.cpp\
-			     ./classes/objects/KML/KML_Style.h\
-			     ./classes/objects/KML/KML_StyleSelector.cpp\
-			     ./classes/objects/KML/KML_StyleSelector.h\
-			     ./classes/objects/KML/KML_SubStyle.cpp\
-			     ./classes/objects/KML/KML_SubStyle.h\
-			     ./classes/objects/KML/KML_Unknown.cpp\
-			     ./classes/objects/KML/KML_Unknown.h\
-			     ./classes/objects/KML/KMLFileReadUtils.cpp\
-			     ./classes/objects/KML/KMLFileReadUtils.h
+			     ./classes/KML/KML_Attribute.cpp\
+			     ./classes/KML/KML_Attribute.h\
+			     ./classes/KML/KML_Comment.cpp\
+			     ./classes/KML/KML_Comment.h\
+			     ./classes/KML/KML_ColorStyle.cpp\
+			     ./classes/KML/KML_ColorStyle.h\
+			     ./classes/KML/KML_Container.cpp\
+			     ./classes/KML/KML_Container.h\
+			     ./classes/KML/KML_Document.cpp\
+			     ./classes/KML/KML_Document.h\
+			     ./classes/KML/KML_Feature.cpp\
+			     ./classes/KML/KML_Feature.h\
+			     ./classes/KML/KML_File.cpp\
+			     ./classes/KML/KML_File.h\
+			     ./classes/KML/KML_Folder.cpp\
+			     ./classes/KML/KML_Folder.h\
+			     ./classes/KML/KML_Geometry.cpp\
+			     ./classes/KML/KML_Geometry.h\
+			     ./classes/KML/KML_GroundOverlay.cpp\
+			     ./classes/KML/KML_GroundOverlay.h\
+			     ./classes/KML/KML_Icon.cpp\
+			     ./classes/KML/KML_Icon.h\
+			     ./classes/KML/KML_LatLonBox.cpp\
+		  	     ./classes/KML/KML_LatLonBox.h\
+			     ./classes/KML/KML_LinearRing.cpp\
+			     ./classes/KML/KML_LinearRing.h\
+			     ./classes/KML/KML_LineString.cpp\
+			     ./classes/KML/KML_LineString.h\
+			     ./classes/KML/KML_LineStyle.cpp\
+			     ./classes/KML/KML_LineStyle.h\
+			     ./classes/KML/KML_MultiGeometry.cpp\
+			     ./classes/KML/KML_MultiGeometry.h\
+			     ./classes/KML/KML_Object.cpp\
+			     ./classes/KML/KML_Object.h\
+			     ./classes/KML/KML_Overlay.cpp\
+			     ./classes/KML/KML_Overlay.h\
+			     ./classes/KML/KML_Point.cpp\
+			     ./classes/KML/KML_Point.h\
+			     ./classes/KML/KML_Placemark.cpp\
+			     ./classes/KML/KML_Placemark.h\
+			     ./classes/KML/KML_Polygon.cpp\
+			     ./classes/KML/KML_Polygon.h\
+			     ./classes/KML/KML_PolyStyle.cpp\
+			     ./classes/KML/KML_PolyStyle.h\
+			     ./classes/KML/KML_Style.cpp\
+			     ./classes/KML/KML_Style.h\
+			     ./classes/KML/KML_StyleSelector.cpp\
+			     ./classes/KML/KML_StyleSelector.h\
+			     ./classes/KML/KML_SubStyle.cpp\
+			     ./classes/KML/KML_SubStyle.h\
+			     ./classes/KML/KML_Unknown.cpp\
+			     ./classes/KML/KML_Unknown.h\
+			     ./classes/KML/KMLFileReadUtils.cpp\
+			     ./classes/KML/KMLFileReadUtils.h
 #}}}
 #Petsc sources  {{{
Index: /issm/trunk-jpl/src/c/classes/Bucket.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Bucket.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Bucket.h	(revision 15012)
@@ -0,0 +1,243 @@
+/*!\file Bucket.h
+ * \brief: header file for Bucket object
+ */
+
+#ifndef _BUCKET_H
+#define _BUCKET_H
+
+/*Headers:*/
+/*{{{*/
+#include "./DataSet.h"
+#include "./Object.h"
+#include "../shared/MemOps/MemOps.h"
+#include "../toolkits/toolkitsenums.h"
+/*}}}*/
+
+/*how many MPI_Isend requests does it take to transfer the contents of a bucket to another cpu?*/
+#define MATRIXBUCKETSIZEOFREQUESTS 7 
+#define VECTORBUCKETSIZEOFREQUESTS 5 
+typedef enum {VECTOR_BUCKET, MATRIX_BUCKET} BucketType;
+template <class doubletype> class Bucket: public Object{
+
+	private: 
+		int type; //either a VECTOR_BUCKET or MATRIX_BUCKET
+		int m,n; /*size of local matrix we are storing*/
+		/*row and column indices of the matrix we are storing*/
+		int* idxm;
+		int* idxn; 
+		doubletype* values; /*local matrix*/
+		InsMode mode; /*mode of insertion for this bucket*/
+
+	public: 
+
+		/*constructors, destructors: */
+		Bucket(){ /*{{{*/
+			this->Initialize();
+		} /*}}}*/
+		Bucket(int min,int* idxmin,int nin,int* idxnin,doubletype* valuesin,InsMode modein){ /*{{{*/
+
+			this->Initialize();
+
+			this->type=MATRIX_BUCKET;
+			this->m=min;
+			this->n=nin;
+			this->mode=modein;
+			if(this->m){
+				this->idxm=xNew<int>(this->m); 
+				xMemCpy(this->idxm,idxmin,this->m);
+			}
+			if(this->n){
+				this->idxn=xNew<int>(this->n); 
+				xMemCpy(this->idxn,idxnin,this->n);
+			}
+			if(this->m*this->n){
+				this->values=xNew<doubletype>(this->n*this->m);
+				xMemCpy(this->values,valuesin,this->n*this->m);
+			}
+		} /*}}}*/
+		Bucket(int min,int* idxmin,doubletype* valuesin,InsMode modein){ /*{{{*/ 
+			this->Initialize();
+
+			this->type=VECTOR_BUCKET; 
+			this->m=min;
+			this->mode=modein;
+			if(this->m){
+				this->idxm=xNew<int>(this->m); 
+				xMemCpy(this->idxm,idxmin,this->m);
+
+				this->values=xNew<doubletype>(this->m);
+				xMemCpy(this->values,valuesin,this->m);
+			}
+		} /*}}}*/
+		~Bucket(){ /*{{{*/
+			xDelete<int>(idxm);
+			xDelete<int>(idxn);
+			xDelete<doubletype>(values);
+		} /*}}}*/
+		void Initialize(void){ /*{{{*/
+
+			this->type=0;
+			this->m=0;
+			this->n=0;
+			this->idxm=NULL;
+			this->idxn=NULL;
+			this->values=NULL;
+			mode=INS_VAL;
+
+		} /*}}}*/
+
+		/*object virtual functions definitions:*/
+		void    Echo(){ /*{{{*/
+			_printLine_("Bucket echo (cpu #: "<<IssmComm::GetRank()<<")");
+			_printLine_("bucket type: " << type);
+			_printLine_("num rows: "<<this->m<<" num cols: "<<this->n);
+		} /*}}}*/
+		void    DeepEcho(){ /*{{{*/
+			int i,j;
+
+			_printLine_("Bucket echo (cpu #: "<<IssmComm::GetRank()<<")");
+			_printLine_("bucket type: " << type);
+			_printLine_("num rows: "<<this->m<<" num cols: "<<this->n);
+			if(type==MATRIX_BUCKET){
+				for (i=0;i<this->m;i++){
+					_printLine_("row "<<this->idxm[i]<<", column indices: ");
+					for (j=0;j<this->n;j++){
+						_printLine_(" "<<this->idxn[j]);
+					}
+					_printLine_("values: ");
+					for (j=0;j<this->n;j++){
+						_printLine_(" "<<this->values[m*i+j]);
+					}
+				}
+			}
+			else if(type==VECTOR_BUCKET){
+				for (i=0;i<this->m;i++){
+					_printLine_("row "<<this->idxm[i]<<", value " << this->values[i]);
+				}
+			}
+			else _error_("unknown type of bucket!");
+		}
+		/*}}}*/
+		int     Id(){ /*{{{*/
+			return -1;
+		} /*}}}*/
+		int     ObjectEnum(){ /*{{{*/
+			return -1;
+		} /*}}}*/
+		Object *copy()        {/*{{{*/
+			_error_("Not implemented yet (similar to Elements)"); };
+		/*}}}*/
+
+		/*specific routines of Bucket: */
+		void SpawnBucketsPerCpu(DataSet* bucketsofcpu_i,int rank_i,int* rowranks){ /*{{{*/
+
+			int i,j;
+
+			/*go through our idxm index of rows this bucket owns, and spawn buckets  
+			 *if these rows belong to cpu rank_i. Use rowranks to determine this.*/
+			for(i=0;i<m;i++){
+				if (rowranks[idxm[i]]==rank_i){
+					/*This row belongs to cpu rank_i, so spawn a bucket with this row, and add it to the bucketsofcpu_i dataset: */
+					if(type==MATRIX_BUCKET){
+						bucketsofcpu_i->AddObject(new Bucket(1,idxm+i,n,idxn,values+n*i,mode));
+					}
+					else{
+						bucketsofcpu_i->AddObject(new Bucket(1,idxm+i,values+i,mode));
+					}
+				}
+			}
+
+		};
+		/*}}}*/
+		int BucketType(void){ /*{{{*/
+
+			return type;
+		};
+		/*}}}*/
+		void Marshall(int** prow_indices_forcpu,int** pcol_indices_forcpu,doubletype** pvalues_forcpu,int** pmodes_forcpu){ /*{{{*/
+
+			/*intermediary: */
+			int         i;
+			int         j;
+
+			/*buffers: */
+			int        *row_indices_forcpu = NULL;
+			int        *col_indices_forcpu = NULL;
+			doubletype *values_forcpu      = NULL;
+			int        *modes_forcpu       = NULL;
+
+			/*initialize buffers: */
+			row_indices_forcpu=*prow_indices_forcpu;
+			col_indices_forcpu=*pcol_indices_forcpu;
+			values_forcpu=*pvalues_forcpu;
+			modes_forcpu=*pmodes_forcpu;
+
+			/*fill buffers with out values and indices and modes: */
+			for(i=0;i<m;i++){
+				for(j=0;j<n;j++){
+					row_indices_forcpu[i*n+j]=idxm[i];
+					col_indices_forcpu[i*n+j]=idxn[j];
+					values_forcpu[i*n+j]=values[i*n+j];
+					modes_forcpu[i*n+j]=mode;
+				}
+			}
+
+			/*increment buffer for next Bucket who will marshall his data: */
+			row_indices_forcpu+=(m*n);
+			col_indices_forcpu+=(m*n);
+			values_forcpu+=(m*n);
+			modes_forcpu+=(m*n);
+
+			/*output modified buffers: */
+			*prow_indices_forcpu=row_indices_forcpu;
+			*pcol_indices_forcpu=col_indices_forcpu;
+			*pvalues_forcpu=values_forcpu;
+			*pmodes_forcpu=modes_forcpu;
+		};
+		/*}}}*/
+		void Marshall(int** prow_indices_forcpu,doubletype** pvalues_forcpu,int** pmodes_forcpu){ /*{{{*/
+
+			/*intermediary: */
+			int         i;
+
+			/*buffers: */
+			int        *row_indices_forcpu = NULL;
+			doubletype *values_forcpu      = NULL;
+			int        *modes_forcpu       = NULL;
+
+			/*initialize buffers: */
+			row_indices_forcpu=*prow_indices_forcpu;
+			values_forcpu=*pvalues_forcpu;
+			modes_forcpu=*pmodes_forcpu;
+
+			/*fill buffers with out values and indices and modes: */
+			for(i=0;i<m;i++){
+				row_indices_forcpu[i]=idxm[i];
+				values_forcpu[i]=values[i];
+				modes_forcpu[i]=mode;
+			}
+
+			/*increment buffer for next Bucket who will marshall his data: */
+			row_indices_forcpu+=m;
+			values_forcpu+=m;
+			modes_forcpu+=m;
+
+			/*output modified buffers: */
+			*prow_indices_forcpu=row_indices_forcpu;
+			*pvalues_forcpu=values_forcpu;
+			*pmodes_forcpu=modes_forcpu;
+		};
+		/*}}}*/
+		int MarshallSize(void){ /*{{{*/
+
+			if(type==MATRIX_BUCKET){
+				return m*n;
+			}
+			else{
+				return m;
+			}
+		};
+		/*}}}*/
+};
+
+#endif  /* _BUCKET_H */
Index: /issm/trunk-jpl/src/c/classes/Constraints/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,10 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Constraints)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Constraints/SpcDynamic.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/Constraints/SpcStatic.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Constraints/SpcTransient.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Constraints/Constraint.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/Constraint.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/Constraint.h	(revision 15012)
@@ -0,0 +1,26 @@
+/*!\file:  Constraint.h
+ * \brief abstract class for Constraint object
+ * This class is a place holder for constraints
+ * It is derived from Object, so DataSets can contain them.
+ */ 
+
+#ifndef _CONSTRAINT_H_
+#define _CONSTRAINT_H_
+
+/*Headers:*/
+/*{{{*/
+class Nodes;
+#include "../Object.h"
+#include "../../toolkits/toolkits.h"
+/*}}}*/
+
+class Constraint: public Object{
+
+	public: 
+
+		virtual      ~Constraint(){};
+		virtual void ConstrainNode(Nodes* nodes,Parameters* parameters)=0;
+		virtual bool InAnalysis(int analysis_type)=0;
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Constraints/Constraints.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/Constraints.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/Constraints.cpp	(revision 15012)
@@ -0,0 +1,40 @@
+/*
+ * \file Constraints.cpp
+ * \brief: Implementation of Constraints class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Constraints.h"
+#include "../../shared/shared.h"
+#include "../../toolkits/toolkits.h"
+
+using namespace std;
+/*}}}*/
+
+/*Numerics: */
+/*FUNCTION Constraints::NumberOfConstraints{{{*/
+int Constraints::NumberOfConstraints(void){
+
+	int localconstraints;
+	int numberofconstraints;
+
+	/*Get number of local constraints*/
+	localconstraints=this->Size();
+
+	/*figure out total number of constraints combining all the cpus (no clones here)*/
+	#ifdef _HAVE_MPI_
+		MPI_Reduce(&localconstraints,&numberofconstraints,1,MPI_INT,MPI_SUM,0,IssmComm::GetComm() );
+		MPI_Bcast(&numberofconstraints,1,MPI_INT,0,IssmComm::GetComm());
+	#else
+		numberofconstraints=localconstraints;
+	#endif
+
+	return numberofconstraints;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Constraints/Constraints.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/Constraints.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/Constraints.h	(revision 15012)
@@ -0,0 +1,36 @@
+#ifndef _CONTAINER_CONSTRAINTS_H_
+#define  _CONTAINER_CONSTRAINTS_H_
+
+/*forward declarations */
+#include "../DataSet.h"
+#include "../../shared/shared.h"
+
+/*! \brief Declaration of Constraints class. 
+ *
+ * Declaration of Constraints class for handling Single Point Constraints (SPCs).
+ * Constraints are vector lists (Containers) of Constraint objects.
+ */ 
+class Constraints: public DataSet{
+
+	public:
+
+		/*Object constructors and destructor*/
+		/*FUNCTION Constraints::Constraints(){{{*/
+		Constraints(){
+			enum_type=ConstraintsEnum;
+			return;
+		}
+		/*}}}*/
+		/*FUNCTION Constraints::~Constraints(){{{*/
+		~Constraints(){
+			return;
+		}
+		/*}}}*/
+
+
+		/*numerics*/
+		int   NumberOfConstraints(void);
+
+};
+
+#endif //ifndef _CONSTRAINTS_H_
Index: /issm/trunk-jpl/src/c/classes/Constraints/SpcDynamic.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/SpcDynamic.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/SpcDynamic.cpp	(revision 15012)
@@ -0,0 +1,131 @@
+/*!\file SpcDynamic.c
+ * \brief: implementation of the SpcDynamic object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "./Constraint.h"
+#include "../../shared/shared.h"
+
+/*SpcDynamic constructors and destructor*/
+/*FUNCTION SpcDynamic::SpcDynamic(){{{*/
+SpcDynamic::SpcDynamic(){
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::SpcDynamic(int spc_sid,int spc_nodeid,...){{{*/
+SpcDynamic::SpcDynamic(int spc_sid,int spc_nodeid, int spc_dof,int spc_analysis_type){
+
+	sid=spc_sid;
+	nodeid=spc_nodeid;
+	dof=spc_dof;
+	value=0;
+	analysis_type=spc_analysis_type;
+	isset=false;
+
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::~SpcDynamic{{{*/
+SpcDynamic::~SpcDynamic(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION SpcDynamic::Echo {{{*/
+void SpcDynamic::Echo(void){
+
+	_printLine_("SpcDynamic:");
+	_printLine_("   sid: " << sid);
+	_printLine_("   nodeid: " << nodeid);
+	_printLine_("   dof: " << dof);
+	_printLine_("   value: " << value);
+	_printLine_("   isset: " <<(isset?"true":"false"));
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::DeepEcho {{{*/
+void SpcDynamic::DeepEcho(void){
+
+	this->Echo();
+	return;
+}		
+/*}}}*/
+/*FUNCTION SpcDynamic::Id {{{*/
+int    SpcDynamic::Id(void){ return sid; }
+/*}}}*/
+/*FUNCTION SpcDynamic::ObjectEnum{{{*/
+int SpcDynamic::ObjectEnum(void){
+
+	return SpcDynamicEnum;
+
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::copy {{{*/
+Object* SpcDynamic::copy() {
+	return new SpcDynamic(*this); 
+}
+/*}}}*/
+
+/*Constraint virtual functions definitions: */
+/*FUNCTION SpcDynamic::InAnalysis{{{*/
+bool SpcDynamic::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::ConstrainNode{{{*/
+void SpcDynamic::ConstrainNode(Nodes* nodes,Parameters* parameters){
+
+	Node* node=NULL;
+
+	/*Chase through nodes and find the node to which this SpcDynamic applys: */
+	node=(Node*)nodes->GetObjectById(NULL,nodeid);
+
+	/*Apply constraint: */
+	if(node){ //in case the spc is dealing with a node on another cpu
+
+		/*We should first check that the value has been set... (test306)*/
+		node->ApplyConstraint(dof,value);
+	}
+}
+/*}}}*/
+
+/*SpcDynamic functions*/
+/*FUNCTION SpcDynamic::GetDof {{{*/
+int SpcDynamic::GetDof(){
+	return dof;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::GetNodeId {{{*/
+int   SpcDynamic::GetNodeId(){
+
+	return nodeid;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::GetValue {{{*/
+IssmDouble SpcDynamic::GetValue(){
+	_assert_(this->isset);
+	_assert_(!xIsNan<IssmDouble>(value));
+	return value;
+}
+/*}}}*/
+/*FUNCTION SpcDynamic::SetDynamicConstraint {{{*/
+void SpcDynamic::SetDynamicConstraint(Nodes* nodes,IssmDouble* yg_serial){
+
+	int pos;
+
+	Node* node=(Node*)nodes->GetObjectById(NULL,nodeid);
+	pos=node->GetDof(dof-1,GsetEnum);
+
+	this->value=yg_serial[pos];
+	this->isset=true;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Constraints/SpcDynamic.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/SpcDynamic.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/SpcDynamic.h	(revision 15012)
@@ -0,0 +1,51 @@
+/*!\file SpcDynamic.h
+ * \brief: header file for spc object
+ */
+
+#ifndef _SPCDynamic_H_
+#define _SPCDynamic_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Object.h"
+class DataSet;
+/*}}}*/
+
+class SpcDynamic: public Constraint{
+
+	private: 
+		int	sid; /*! id, to track it*/
+		int	nodeid; /*!node id*/
+		int dof; /*!component*/
+		IssmDouble value; /*value*/
+		bool isset;
+		int analysis_type;
+
+	public:
+
+		/*SpcDynamic constructors, destructors:{{{*/
+		SpcDynamic();
+		SpcDynamic(int sid,int nodeid, int dof,int analysis_type);
+		~SpcDynamic();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Constraint virtual functions definitions: {{{*/
+		void   ConstrainNode(Nodes* nodes,Parameters* parameters);
+		bool   InAnalysis(int analysis_type);
+		/*}}}*/
+		/*SpcDynamic management:{{{ */
+		int    GetNodeId();
+		int    GetDof();
+		IssmDouble GetValue();
+		void   SetDynamicConstraint(Nodes* nodes,IssmDouble *yg_serial);
+		/*}}}*/
+
+};
+
+#endif  /* _SPCStatic_H_*/
Index: /issm/trunk-jpl/src/c/classes/Constraints/SpcStatic.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/SpcStatic.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/SpcStatic.cpp	(revision 15012)
@@ -0,0 +1,119 @@
+/*!\file SpcStatic.c
+ * \brief: implementation of the SpcStatic object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "./Constraint.h"
+#include "../../shared/shared.h"
+
+/*SpcStatic constructors and destructor*/
+/*FUNCTION SpcStatic::SpcStatic(){{{*/
+SpcStatic::SpcStatic(){
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcStatic::SpcStatic(int spc_sid,int spc_nodeid,...){{{*/
+SpcStatic::SpcStatic(int spc_sid,int spc_nodeid, int spc_dof,IssmDouble spc_value,int spc_analysis_type){
+
+	sid=spc_sid;
+	nodeid=spc_nodeid;
+	dof=spc_dof;
+	value=spc_value;
+	analysis_type=spc_analysis_type;
+
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcStatic::~SpcStatic{{{*/
+SpcStatic::~SpcStatic(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION SpcStatic::Echo {{{*/
+void SpcStatic::Echo(void){
+
+	_printLine_("SpcStatic:");
+	_printLine_("   sid: " << sid);
+	_printLine_("   nodeid: " << nodeid);
+	_printLine_("   dof: " << dof);
+	_printLine_("   value: " << value);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcStatic::DeepEcho {{{*/
+void SpcStatic::DeepEcho(void){
+
+	_printLine_("SpcStatic:");
+	_printLine_("   sid: " << sid);
+	_printLine_("   nodeid: " << nodeid);
+	_printLine_("   dof: " << dof);
+	_printLine_("   value: " << value);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	return;
+}		
+/*}}}*/
+/*FUNCTION SpcStatic::Id {{{*/
+int    SpcStatic::Id(void){ return sid; }
+/*}}}*/
+/*FUNCTION SpcStatic::ObjectEnum{{{*/
+int SpcStatic::ObjectEnum(void){
+
+	return SpcStaticEnum;
+
+}
+/*}}}*/
+/*FUNCTION SpcStatic::copy {{{*/
+Object* SpcStatic::copy() {
+	return new SpcStatic(*this); 
+}
+/*}}}*/
+
+/*Constraint virtual functions definitions: */
+/*FUNCTION SpcStatic::InAnalysis{{{*/
+bool SpcStatic::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION SpcStatic::ConstrainNode{{{*/
+void SpcStatic::ConstrainNode(Nodes* nodes,Parameters* parameters){
+
+	Node* node=NULL;
+
+	/*Chase through nodes and find the node to which this SpcStatic applys: */
+	node=(Node*)nodes->GetObjectById(NULL,nodeid);
+
+	/*Apply constraint: */
+	if(node){ //in case the spc is dealing with a node on another cpu
+		node->ApplyConstraint(dof,value);
+	}
+}
+/*}}}*/
+
+/*SpcStatic functions*/
+/*FUNCTION SpcStatic::GetDof {{{*/
+int SpcStatic::GetDof(){
+	return dof;
+}
+/*}}}*/
+/*FUNCTION SpcStatic::GetNodeId {{{*/
+int   SpcStatic::GetNodeId(){
+
+	return nodeid;
+}
+/*}}}*/
+/*FUNCTION SpcStatic::GetValue {{{*/
+IssmDouble SpcStatic::GetValue(){
+	_assert_(!xIsNan<IssmDouble>(value));
+	return value;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Constraints/SpcStatic.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/SpcStatic.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/SpcStatic.h	(revision 15012)
@@ -0,0 +1,49 @@
+/*!\file SpcStatic.h
+ * \brief: header file for spc object
+ */
+
+#ifndef _SPCStatic_H_
+#define _SPCStatic_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Object.h"
+class DataSet;
+/*}}}*/
+
+class SpcStatic: public Constraint{
+
+	private: 
+		int	sid; /*! id, to track it*/
+		int	nodeid; /*!node id*/
+		int dof; /*!component*/
+		IssmDouble value; /*value*/
+		int analysis_type;
+
+	public:
+
+		/*SpcStatic constructors, destructors:{{{*/
+		SpcStatic();
+		SpcStatic(int sid,int nodeid, int dof,IssmDouble value,int analysis_type);
+		~SpcStatic();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Constraint virtual functions definitions: {{{*/
+		void   ConstrainNode(Nodes* nodes,Parameters* parameters);
+		bool   InAnalysis(int analysis_type);
+		/*}}}*/
+		/*SpcStatic management:{{{ */
+		int    GetNodeId();
+		int    GetDof();
+		IssmDouble GetValue();
+		/*}}}*/
+
+};
+
+#endif  /* _SPCStatic_H_*/
Index: /issm/trunk-jpl/src/c/classes/Constraints/SpcTransient.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/SpcTransient.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/SpcTransient.cpp	(revision 15012)
@@ -0,0 +1,165 @@
+/*!\file SpcTransient.c
+ * \brief: implementation of the SpcTransient object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "./Constraint.h"
+#include "shared/shared.h"
+
+/*SpcTransient constructors and destructor*/
+/*FUNCTION SpcTransient::SpcTransient(){{{*/
+SpcTransient::SpcTransient(){
+	sid=-1;
+	nodeid=-1;
+	dof=-1;
+	values=NULL;
+	times=NULL;
+	nsteps=-1;
+	analysis_type=-1;
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcTransient::SpcTransient(int spc_sid,int spc_nodeid,...){{{*/
+SpcTransient::SpcTransient(int spc_sid,int spc_nodeid, int spc_dof,int spc_nsteps, IssmDouble* spc_times, IssmDouble* spc_values,int spc_analysis_type){
+
+	sid=spc_sid;
+	nodeid=spc_nodeid;
+	dof=spc_dof;
+	nsteps=spc_nsteps;
+	if(spc_nsteps){
+		values=xNew<IssmDouble>(spc_nsteps);
+		times=xNew<IssmDouble>(spc_nsteps);
+		xMemCpy<IssmDouble>(values,spc_values,nsteps);
+		xMemCpy<IssmDouble>(times,spc_times,nsteps);
+	}
+	analysis_type=spc_analysis_type;
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcTransient::~SpcTransient{{{*/
+SpcTransient::~SpcTransient(){
+	xDelete<IssmDouble>(times);
+	xDelete<IssmDouble>(values);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION SpcTransient::Echo {{{*/
+void SpcTransient::Echo(void){
+
+	int i;
+	_printLine_("SpcTransient:");
+	_printLine_("   sid: " << sid);
+	_printLine_("   nodeid: " << nodeid);
+	_printLine_("   dof: " << dof);
+	_printLine_("   nsteps: " << nsteps);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	_printLine_("   steps|times|values");
+	for(i=0;i<nsteps;i++){
+		_printLine_(i << "-" << times[i] << ":" << values[i]);
+	}
+	return;
+}
+/*}}}*/
+/*FUNCTION SpcTransient::DeepEcho {{{*/
+void SpcTransient::DeepEcho(void){
+	this->Echo();
+}		
+/*}}}*/
+/*FUNCTION SpcTransient::Id {{{*/
+int    SpcTransient::Id(void){ return sid; }
+/*}}}*/
+/*FUNCTION SpcTransient::ObjectEnum{{{*/
+int SpcTransient::ObjectEnum(void){
+
+	return SpcTransientEnum;
+
+}
+/*}}}*/
+/*FUNCTION SpcTransient::copy {{{*/
+Object* SpcTransient::copy() {
+	return new SpcTransient(sid,nodeid,dof,nsteps,times,values,analysis_type);
+}
+/*}}}*/
+
+/*Constraint virtual functions definitions:*/
+/*FUNCTION SpcTransient::InAnalysis{{{*/
+bool SpcTransient::InAnalysis(int in_analysis_type){
+
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION SpcTransient::ConstrainNode{{{*/
+void SpcTransient::ConstrainNode(Nodes* nodes,Parameters* parameters){
+
+	Node* node=NULL;
+	IssmDouble time=0;
+	int    i;
+	IssmDouble alpha=-1;
+	IssmDouble value;
+	bool   found=false;
+
+	/*Chase through nodes and find the node to which this SpcTransient applys: */
+	node=(Node*)nodes->GetObjectById(NULL,nodeid);
+
+	if(node){ //in case the spc is dealing with a node on another cpu
+
+		/*Retrieve time in parameters: */
+		parameters->FindParam(&time,TimeEnum);
+
+		/*Now, go fetch value for this time: */
+		if (time<=times[0]){
+			value=values[0];
+			found=true;
+		}
+		else if (time>=times[nsteps-1]){
+			value=values[nsteps-1];
+			found=true;
+		}
+		else{
+			for(i=0;i<nsteps-1;i++){
+				if (times[i]<=time && time<times[i+1]){
+					alpha=(time-times[i])/(times[i+1]-times[i]);
+					value=(1-alpha)*values[i]+alpha*values[i+1];
+					found=true;
+					break;
+				}
+			}
+		}
+
+		if(!found)_error_("could not find time segment for constraint");
+
+		/*Apply or relax constraint: */
+		if(xIsNan<IssmDouble>(value)){
+			node->RelaxConstraint(dof);
+		}
+		else node->ApplyConstraint(dof,value);
+	}
+}
+/*}}}*/
+
+/*SpcTransient functions*/
+/*FUNCTION SpcTransient::GetDof {{{*/
+int SpcTransient::GetDof(){
+	return dof;
+}
+/*}}}*/
+/*FUNCTION SpcTransient::GetNodeId {{{*/
+int   SpcTransient::GetNodeId(){
+
+	return nodeid;
+}
+/*}}}*/
+/*FUNCTION SpcTransient::GetValue {{{*/
+IssmDouble SpcTransient::GetValue(){
+	return values[0];
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Constraints/SpcTransient.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Constraints/SpcTransient.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Constraints/SpcTransient.h	(revision 15012)
@@ -0,0 +1,51 @@
+/*!\file SpcTransient.h
+ * \brief: header file for spc object
+ */
+
+#ifndef _SPCTRANSIENT_H_
+#define _SPCTRANSIENT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Object.h"
+class DataSet;
+/*}}}*/
+
+class SpcTransient: public Constraint{
+
+	private: 
+		int	sid; /*! id, to track it*/
+		int	nodeid; /*!node id*/
+		int dof; /*!component*/
+		IssmDouble* values; /*different values in time*/
+		IssmDouble* times; /*different time steps*/
+		int nsteps; /*number of time steps*/
+		int analysis_type;
+
+	public:
+
+		/*SpcTransient constructors, destructors:{{{*/
+		SpcTransient();
+		SpcTransient(int sid,int nodeid, int dof,int nsteps, IssmDouble* times, IssmDouble* values,int analysis_type);
+		~SpcTransient();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Constraint virtual functions definitions: {{{*/
+		void   ConstrainNode(Nodes* nodes,Parameters* parameters);
+		bool   InAnalysis(int analysis_type);
+		/*}}}*/
+		/*SpcTransient management:{{{ */
+		int    GetNodeId();
+		int    GetDof();
+		IssmDouble GetValue();
+		/*}}}*/
+
+};
+
+#endif  /* _SPCTRANSIENT_H_ */
Index: /issm/trunk-jpl/src/c/classes/Contour.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Contour.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Contour.h	(revision 15012)
@@ -0,0 +1,95 @@
+/*!\file Contour.h
+ * \brief: header file for Contour object
+ */
+
+#ifndef _CONTOUR_H_
+#define _CONTOUR_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../shared/Exceptions/exceptions.h"
+#include "../shared/MemOps/MemOps.h"
+#include "../shared/io/io.h"
+#include "../shared/Enum/Enum.h"
+#include "./Object.h"
+/*}}}*/
+
+template <class doubletype>
+class Contour: public Object{
+
+	public: 
+
+		int         id;
+		int         nods;     //number of vertices in the contour
+		doubletype *x;
+		doubletype *y;
+		bool        closed;   //is this contour closed?
+
+		/*Contour constructors, destructors :*/
+		/*FUNCTION Contour() {{{*/
+		Contour(){
+			this->id     = 0;
+			this->nods   = 0;
+			this->x      = NULL;
+			this->y      = NULL;
+			this->closed = false;
+		}
+		/*}}}*/
+		/*FUNCTION Contour(int pid, int nods, doubletype* x, doubletype* y,bool closed) {{{*/
+		Contour(int pid,int pnods, doubletype* px, doubletype* py,bool pclosed){
+
+			this->id     = pid;
+			this->nods   = pnods;
+			this->closed = pclosed;
+			if(nods){
+				this->x=xNew<doubletype>(nods);
+				xMemCpy<doubletype>(this->x,px,nods);
+				this->y=xNew<doubletype>(nods);
+				xMemCpy<doubletype>(this->y,py,nods);
+			}
+		}
+		/*}}}*/
+		/*FUNCTION ~Contour() {{{*/
+		~Contour(){
+			xDelete<doubletype>(this->x);
+			xDelete<doubletype>(this->y);
+		}
+		/*}}}*/
+
+		/*Object virtual function resolutoin: */
+		/*FUNCTION Echo(){{{*/
+		void Echo(void){
+			_printLine_(" Contour: " << id);
+			_printLine_("    nods: " << nods);
+			_printLine_("  closed: " << (closed?"true":"false"));
+			if(nods){
+				_printLine_("   x , y:");
+				for(int i=0;i<nods;i++){
+					_printLine_(i << ": " << x[i] << " | " << y[i]);
+				}
+			}
+		}
+		/*}}}*/
+		/*FUNCTION DeepEcho(){{{*/
+		void DeepEcho(void){
+			this->Echo();
+		}
+		/*}}}*/
+		/*FUNCTION Id(){{{*/
+		int Id(void){
+			return id;
+		}
+		/*}}}*/
+		/*FUNCTION ObjectEnum{{{*/
+		int ObjectEnum(void){
+			return ContourEnum;
+		}
+		/*}}}*/
+		/*FUNCTION copy {{{*/
+		Object* copy() {
+			return new Contour(*this); 
+		}
+		/*}}}*/
+};
+
+#endif  /* _CONTOUR_H_ */
Index: /issm/trunk-jpl/src/c/classes/DataSet.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/DataSet.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/DataSet.cpp	(revision 15012)
@@ -0,0 +1,284 @@
+/*
+ * \file DataSet.cpp
+ * \brief: Implementation of DataSet class
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <cstring>
+#include <vector>
+#include <functional>
+#include <algorithm>
+#include <iostream>
+
+#include "./DataSet.h"
+#include "../shared/shared.h"
+
+using namespace std;
+/*}}}*/
+
+/*Constructors/Destructors*/
+/*FUNCTION DataSet::DataSet(){{{*/
+DataSet::DataSet(){
+
+	sorted=0;
+	sorted_ids=NULL;
+	id_offsets=NULL;
+
+}
+/*}}}*/
+/*FUNCTION DataSet::DataSet(int dataset_enum){{{*/
+DataSet::DataSet(int dataset_enum){
+	enum_type=dataset_enum;
+
+	sorted=0;
+	sorted_ids=NULL;
+	id_offsets=NULL;
+
+}
+/*}}}*/
+/*FUNCTION DataSet::Copy{{{*/
+DataSet*   DataSet::Copy(void){
+
+	vector<Object*>::iterator object;
+	Object* object_copy=NULL;
+
+	DataSet* copy=new DataSet(enum_type);
+
+	copy->sorted=sorted;
+	copy->presorted=presorted;
+	if(sorted_ids){
+		copy->sorted_ids=xNew<int>(objects.size());
+		xMemCpy<int>(copy->sorted_ids,sorted_ids,objects.size());
+	}
+	if(id_offsets){
+		copy->id_offsets=xNew<int>(objects.size());
+		xMemCpy<int>(copy->id_offsets,id_offsets,objects.size());
+	}
+
+	/*Now we need to deep copy the objects: */
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		/*Call echo on object: */
+		object_copy = (*object)->copy();
+		copy->AddObject(object_copy);
+	}
+	return copy;
+}
+/*}}}*/
+/*FUNCTION DataSet::~DataSet{{{*/
+DataSet::~DataSet(){
+	clear();
+	xDelete<int>(sorted_ids);
+	xDelete<int>(id_offsets);
+}
+/*}}}*/
+
+/*Specific methods*/
+/*FUNCTION DataSet::AddObject{{{*/
+int  DataSet::AddObject(Object* object){
+
+	_assert_(this);
+	objects.push_back(object);
+
+	return 1;
+}
+/*}}}*/
+/*FUNCTION DataSet::clear{{{*/
+void  DataSet::clear(){
+
+/*  use reverse_iterator for efficiency in matlab memory manager
+	(keeping old code in case it needs to revert back)  */
+
+//	vector<Object*>::iterator object;
+	vector<Object*>::reverse_iterator object;
+
+//	for ( object=objects.begin() ; object < objects.end(); object++ ){
+//		delete (*object);
+//	}
+	for ( object=objects.rbegin() ; object < objects.rend(); object++ ){
+		delete (*object);
+	}
+	objects.clear();
+}
+/*}}}*/
+/*FUNCTION DataSet::DeleteObject{{{*/
+int  DataSet::DeleteObject(Object* object){
+
+	vector<Object*>::iterator iterator;
+
+	if(object){
+		iterator = find(objects.begin(), objects.end(),object);
+		delete *iterator;
+		objects.erase(iterator);
+	}
+
+	return 1;
+
+}
+/*}}}*/
+/*FUNCTION DataSet::DeepEcho{{{*/
+void DataSet::DeepEcho(){
+
+	vector<Object*>::iterator object;
+
+	if(this==NULL)_error_("trying to echo a NULL dataset");
+
+	_pprintLine_("DataSet echo: " << objects.size() << " objects");
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		/*Call deep echo on object: */
+		(*object)->DeepEcho();
+
+	}
+}
+/*}}}*/
+/*FUNCTION DataSet::Echo{{{*/
+void DataSet::Echo(){
+
+	vector<Object*>::iterator object;
+
+	if(this==NULL)_error_("trying to echo a NULL dataset");
+
+	_pprintLine_("DataSet echo: " << objects.size() << " objects");
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		/*Call echo on object: */
+		(*object)->Echo();
+
+	}
+	return;
+}
+/*}}}*/
+/*FUNCTION DataSet::GetEnum(){{{*/
+int  DataSet::GetEnum(){
+	return enum_type;
+}
+/*}}}*/
+/*FUNCTION DataSet::GetEnum(int offset){{{*/
+int   DataSet::GetEnum(int offset){
+
+	return objects[offset]->ObjectEnum();
+
+}
+/*}}}*/
+/*FUNCTION DataSet::GetObjectByOffset{{{*/
+Object* DataSet::GetObjectByOffset(int offset){
+
+	/*Check index in debugging mode*/
+	_assert_(this!=NULL);
+	_assert_(offset>=0);
+	_assert_(offset<this->Size());
+
+	return objects[offset];
+
+}
+/*}}}*/
+/*FUNCTION DataSet::GetObjectById{{{*/
+Object* DataSet::GetObjectById(int* poffset,int eid){
+
+	int id_offset;
+	int offset;
+
+	_assert_(this);
+	if(!sorted)_error_("trying to binary search on a non-sorted dataset!");
+
+	/*Carry out a binary search on the sorted_ids: */
+	if(!binary_search(&id_offset,eid,sorted_ids,objects.size())){
+		_error_("could not find object with id " << eid << " in DataSet " << EnumToStringx(enum_type));
+	}
+
+	/*Convert  the id offset into sorted offset: */
+	offset=id_offsets[id_offset];
+
+	/*Assign output pointers if requested:*/
+	if(poffset)*poffset=offset;
+
+	/*Return object at offset position in objects :*/
+	return objects[offset];
+}
+/*}}}*/
+/*FUNCTION DataSet::Presort{{{*/
+void DataSet::Presort(){
+
+	/*vector of objects is already sorted, just allocate the sorted ids and their
+	 * offsets:*/
+	if(objects.size()){
+
+		/*Delete existing ids*/
+		xDelete<int>(sorted_ids);
+		xDelete<int>(id_offsets);
+
+		/*Allocate new ids*/
+		sorted_ids=xNew<int>(objects.size());
+		id_offsets=xNew<int>(objects.size());
+
+		/*Build id_offsets and sorted_ids*/
+		for(int i=0;i<objects.size();i++){
+			id_offsets[i]=i;
+			sorted_ids[i]=objects[i]->Id();
+		}
+	}
+
+	/*set sorted flag: */
+	sorted=1;
+}
+/*}}}*/
+/*FUNCTION DataSet::Size{{{*/
+int  DataSet::Size(void){
+	_assert_(this!=NULL);
+
+	return objects.size();
+}
+/*}}}*/
+/*FUNCTION DataSet::Sort{{{*/
+void DataSet::Sort(){
+
+	/*Only sort if we are not already sorted: */
+	if(!sorted){
+		_error_("not implemented yet!");
+	}
+}
+/*}}}*/
+
+/*Routines that relate to datasets, but which are not methods: */
+int ExpWrite(DataSet* contours,char* domainname){/*{{{*/
+
+	/*I/O: */
+	FILE* fid=NULL;
+	Contour<double>* contour = NULL;
+
+	/*open domain outline file for writing: */
+	if((fid=fopen(domainname,"w"))==NULL) _error_("could not open domain file " << domainname); 
+
+	for(int counter=0;counter<contours->Size();counter++){
+		contour=(Contour<double>*)contours->GetObjectByOffset(counter);
+
+		/*Write header: */
+		fprintf(fid,"## Name:%s\n",domainname);
+		fprintf(fid,"## Icon:0\n");
+		fprintf(fid,"# Points Count	Value\n");
+		fprintf(fid,"%u %s\n",contour->nods  ,"1.");
+		fprintf(fid,"# X pos	Y pos\n");
+
+		/*Write vertices: */
+		for(int i=0;i<contour->nods;i++){
+			fprintf(fid,"%lf\t%lf\n",contour->x[i],contour->y[i]);
+		}
+
+		/*Write blank line: */
+		if(counter<contours->Size()-1) fprintf(fid,"\n");
+	}
+
+	/*close Exp file: */
+	fclose(fid);
+
+	return 1;
+}/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/DataSet.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/DataSet.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/DataSet.h	(revision 15012)
@@ -0,0 +1,87 @@
+#ifndef _CONTAINER_DATASET_H_
+#define _CONTAINER_DATASET_H_
+
+#include <vector>
+#include <cstring>
+#include "./Contour.h"
+#include "../shared/Exp/exp.h"
+
+/*forward declarations */
+class Object;
+class Results;
+
+/*! \brief Declaration of DataSet class
+ *
+ * Declaration of DataSet class.  A DataSet is a Container of Objects.
+ */
+class DataSet{
+
+	public: 
+
+		/*internals: */
+		std::vector<Object*> objects;
+
+		/*type of dataset: */
+		int             enum_type;
+
+		/*sorting: */
+		int             sorted;
+		int             presorted;
+		int*            sorted_ids;
+		int*            id_offsets;
+
+		/*constructors, destructors*/
+		DataSet();
+		DataSet(int enum_type);
+		~DataSet();
+
+		/*management*/
+		int      GetEnum();
+		int      GetEnum(int offset);
+		void     Echo();
+		void     DeepEcho();
+		int      AddObject(Object *object);
+		int      DeleteObject(int id);
+		int      Size();
+		void     clear();
+		Object  *GetObjectByOffset(int  offset);
+		Object  *GetObjectById(int *poffset,int eid);
+		void     Presort();
+		void     Sort();
+		DataSet *Copy(void);
+		int      DeleteObject(Object *object);
+		Results *SpawnTriaResults(int *indices);
+
+};
+
+/*Methods that relate to datasets: */
+int ExpWrite(DataSet* contours,char* domainname);
+template <class doubletype> DataSet* ExpRead(char* domainname){ /*{{{*/
+
+	/*intermediary: */
+	int                  nprof;
+	int                 *profnvertices = NULL;
+	doubletype         **pprofx        = NULL;
+	doubletype         **pprofy        = NULL;
+
+	/*output: */
+	DataSet *domain = NULL;
+
+	/*If domainname is an empty string, return empty dataset*/
+	if (strcmp(domainname,"")==0){
+		nprof=0;
+	}
+	else{
+		ExpRead(&nprof,&profnvertices,&pprofx, &pprofy, NULL,domainname);
+	}
+
+	/*now create dataset of contours: */
+	domain=new DataSet(0);
+
+	for(int i=0;i<nprof;i++){
+		domain->AddObject(new Contour<doubletype>(i,profnvertices[i],pprofx[i],pprofy[i],1));
+	}
+	return domain;
+} /*}}}*/
+
+#endif
Index: /issm/trunk-jpl/src/c/classes/DependentObject.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/DependentObject.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/DependentObject.cpp	(revision 15012)
@@ -0,0 +1,99 @@
+/*!\file DependentObject.c
+ * \brief: implementation of the DependentObject object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./classes.h"
+#include "shared/shared.h"
+
+/*DependentObject constructors and destructor*/
+/*FUNCTION DependentObject::DependentObject(){{{*/
+DependentObject::DependentObject(){
+	this->name=NoneEnum;
+	this->type=0;
+	this->index=-1;
+}
+/*}}}*/
+/*FUNCTION DependentObject::DependentObject(int in_name, int in_type, int in_index){{{*/
+DependentObject::DependentObject(int in_name, int in_type,int in_index){
+
+	this->name=in_name;
+	this->type=in_type;
+	this->index=in_index;
+	if(in_type!=0 && in_type!=1)_error_("cannot create an DependentObject of type " << in_type);
+	if(in_type==1)_error_("not implemented yet!");
+
+}
+/*}}}*/
+/*FUNCTION DependentObject::~DependentObject() {{{*/
+DependentObject::~DependentObject(){ //destructor
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DependentObject::Echo{{{*/
+void DependentObject::Echo(void){
+
+	_printLine_("DependentObject:");
+	_printLine_("   name: " << EnumToStringx(this->name));
+	if(this->type==0)
+		_printLine_("   type: scalar");
+	else if(this->type==1)
+		_printLine_("   type: vertex");
+	else
+		_error_(" unknown type: " << this->type);
+	if(this->index>=0) _printLine_("   index: " << this->index);
+}
+/*}}}*/
+/*FUNCTION DependentObject::DeepEcho{{{*/
+void DependentObject::DeepEcho(void){
+	this->Echo();
+}
+/*}}}*/
+/*FUNCTION DependentObject::Id{{{*/
+int    DependentObject::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DependentObject::ObjectEnum{{{*/
+int DependentObject::ObjectEnum(void){
+
+	return DependentObjectEnum;
+
+}
+/*}}}*/
+/*FUNCTION DependentObject::copy{{{*/
+Object* DependentObject::copy(void) { 
+	return new DependentObject(name,type,index);
+} /*}}}*/
+
+/*DependentObject methods: */
+/*FUNCTION DependentObject::NumDependents{{{*/
+int  DependentObject::NumDependents(void){
+
+	/*Branch according to the type of variable: */
+	if(type==0){ /*scalar:*/
+		return 1;
+	}
+	else if(type==1){ /* vector:*/
+		_error_("not implemented yet!");
+	}
+	else _error_("should not have a type of " << type);
+}
+/*}}}*/
+/*FUNCTION DependentObject::Responsex{{{*/
+void  DependentObject::Responsex(IssmDouble* poutput_value,FemModel* femmodel){
+
+	if(this->name==MassFluxEnum){
+
+		/*to identify the mass flux that will be computed, we need the index of the profile: */
+		femmodel->parameters->SetParam(this->index,IndexEnum);
+	}
+
+	femmodel->Responsex(poutput_value,this->name,false,0);
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/DependentObject.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/DependentObject.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/DependentObject.h	(revision 15012)
@@ -0,0 +1,41 @@
+/*!\file: DependentObject.h
+ * \brief prototype for DependentObject.h
+ */ 
+
+#ifndef _DEPENDENTOBJECT_H_
+#define  _DEPENDENTOBJECT_H_
+
+/*{{{*/
+#include "./Object.h"
+#include "../shared/shared.h"
+/*}}}*/
+
+class FemModel;
+
+class DependentObject: public Object{
+
+	public:
+
+		int name;
+		int type;  /*0: scalar, 1: vertex*/
+		int index;  /*0: scalar, 1: vertex*/
+
+		/*DependentObject constructors, destructors {{{*/
+		DependentObject();
+		DependentObject(int name, int type,int index);
+		~DependentObject();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy(void);
+		/*}}}*/
+
+		/*DependentObject methods: */
+		int  NumDependents(void);
+		void Responsex(IssmDouble* poutput_value,FemModel* femmodel);
+
+};
+#endif //ifndef _DEPENDENTOBJECT_H_
Index: /issm/trunk-jpl/src/c/classes/ElementResults/BoolElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/BoolElementResult.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/BoolElementResult.cpp	(revision 15012)
@@ -0,0 +1,124 @@
+/*!\file BoolElementResult.c
+ * \brief: implementation of the BoolElementResult object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*BoolElementResult constructors and destructor*/
+/*FUNCTION BoolElementResult::BoolElementResult(){{{*/
+BoolElementResult::BoolElementResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::BoolElementResult(int in_enum_type,IssmDouble in_value,int in_step, IssmDouble in_time){{{*/
+BoolElementResult::BoolElementResult(int in_enum_type,bool in_value,int in_step, IssmDouble in_time){
+
+	enum_type=in_enum_type;
+	value=in_value;
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::~BoolElementResult(){{{*/
+BoolElementResult::~BoolElementResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION BoolElementResult::Echo {{{*/
+void BoolElementResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::DeepEcho{{{*/
+void BoolElementResult::DeepEcho(void){
+
+	_printLine_("BoolElementResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: "<<(this->value?"true":"false"));
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::Id{{{*/
+int    BoolElementResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION BoolElementResult::ObjectEnum{{{*/
+int BoolElementResult::ObjectEnum(void){
+
+	return BoolElementResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::copy{{{*/
+Object* BoolElementResult::copy() {
+
+	return new BoolElementResult(this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*ElementResult management*/
+/*FUNCTION BoolElementResult::InstanceEnum{{{*/
+int BoolElementResult::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::SpawnTriaElementResult{{{*/
+ElementResult* BoolElementResult::SpawnTriaElementResult(int* indices){
+
+	/*output*/
+	BoolElementResult* outresult=new BoolElementResult();
+
+	/*copy fields: */
+	outresult->enum_type=this->enum_type;
+	outresult->value=this->value;
+	outresult->time=this->time;
+	outresult->step=this->step;
+
+	/*Assign output*/
+	return outresult;
+
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::ProcessUnits{{{*/
+void BoolElementResult::ProcessUnits(Parameters* parameters){
+// no op
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::NumberOfNodalValues{{{*/
+int BoolElementResult::NumberOfNodalValues(void){
+	return 1;
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::PatchFill{{{*/
+void BoolElementResult::PatchFill(int row, Patch* patch){
+
+	 /*Here, we fill the result information into the patch object. First, let's remember what is in a row 
+	  * of the patch object: enum_type step time element_id interpolation vertices_ids nodal_values
+	  * Here, we will supply the enum_type, step, time, interpolation and nodal_values: */
+	IssmDouble IssmDoublevalue=this->value?1:0;
+	patch->fillresultinfo(row,this->enum_type,this->step,this->time,P0Enum,&IssmDoublevalue,1);
+
+}
+/*}}}*/
+/*FUNCTION BoolElementResult::GetVectorFromResults{{{*/
+void BoolElementResult::GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	_error_("cannot return vector on vertices");
+} /*}}}*/
+/*FUNCTION BoolElementResult::GetElementVectorFromResults{{{*/
+void BoolElementResult::GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof){
+
+	vector->SetValue(dof,value,INS_VAL);
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/ElementResults/BoolElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/BoolElementResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/BoolElementResult.h	(revision 15012)
@@ -0,0 +1,49 @@
+/*! \file BoolElementResult.h 
+ *  \brief: header file for bool result object
+ *  A boll result object is just derived from a BoolInput object, with additional time and step information.
+ */
+
+#ifndef _BOOLELEMENTRESULT_H_
+#define _BOOLELEMENTRESULT_H_
+
+/*Headers:*/
+#include "../Inputs/Input.h"
+class Parameters;
+
+class BoolElementResult: public ElementResult{
+
+	private: 
+		int    enum_type;
+		bool   value;
+		int    step;
+		IssmDouble time;
+
+	public:
+
+		/*BoolElementResult constructors, destructors: {{{*/
+		BoolElementResult();
+		BoolElementResult(int enum_type,bool value,int step,IssmDouble time);
+		~BoolElementResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ElementResult virtual functions definitions: {{{*/
+		ElementResult* SpawnTriaElementResult(int* indices);
+		IssmDouble  GetTime(void){return time;};
+		int     GetStep(void){return step;};
+		void    ProcessUnits(Parameters* parameters);
+		int     NumberOfNodalValues(void);
+		void    PatchFill(int row, Patch* patch);
+		/*}}}*/
+		/*BoolElementResult management: {{{*/
+		int   InstanceEnum();
+		void GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof);
+		/*}}}*/
+};
+#endif  /* _BOOLELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/ElementResults/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,13 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/ElementResults)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/ElementResults/BoolElementResult.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/ElementResults/DoubleElementResult.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/ElementResults/TriaP1ElementResult.cpp PARENT_SCOPE)
+# }}}
+# THREED_SOURCES {{{
+set(THREED_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/ElementResults/PentaP1ElementResult.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/ElementResults/DoubleElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/DoubleElementResult.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/DoubleElementResult.cpp	(revision 15012)
@@ -0,0 +1,125 @@
+/*!\file DoubleElementResult.c
+ * \brief: implementation of the DoubleElementResult object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*DoubleElementResult constructors and destructor*/
+/*FUNCTION DoubleElementResult::DoubleElementResult(){{{*/
+DoubleElementResult::DoubleElementResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::DoubleElementResult(int in_enum_type,IssmDouble in_value,int in_step, IssmDouble in_time){{{*/
+DoubleElementResult::DoubleElementResult(int in_enum_type,IssmDouble in_value,int in_step, IssmDouble in_time){
+
+	enum_type=in_enum_type;
+	value=in_value;
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::~DoubleElementResult(){{{*/
+DoubleElementResult::~DoubleElementResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleElementResult::Echo {{{*/
+void DoubleElementResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::DeepEcho{{{*/
+void DoubleElementResult::DeepEcho(void){
+
+	_printLine_("DoubleElementResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::Id{{{*/
+int    DoubleElementResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleElementResult::ObjectEnum{{{*/
+int DoubleElementResult::ObjectEnum(void){
+
+	return DoubleElementResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::copy{{{*/
+Object* DoubleElementResult::copy() {
+
+	return new DoubleElementResult(this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*ElementResult management*/
+/*FUNCTION DoubleElementResult::InstanceEnum{{{*/
+int DoubleElementResult::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::SpawnTriaElementResult{{{*/
+ElementResult* DoubleElementResult::SpawnTriaElementResult(int* indices){
+
+	/*output*/
+	DoubleElementResult* outresult=new DoubleElementResult();
+
+	/*copy fields: */
+	outresult->enum_type=this->enum_type;
+	outresult->value=this->value;
+	outresult->time=this->time;
+	outresult->step=this->step;
+
+	/*Assign output*/
+	return outresult;
+
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::ProcessUnits{{{*/
+void DoubleElementResult::ProcessUnits(Parameters* parameters){
+
+	this->value=UnitConversion(this->value,IuToExtEnum,this->enum_type);
+
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::NumberOfNodalValues{{{*/
+int DoubleElementResult::NumberOfNodalValues(void){
+	return 1;
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::PatchFill{{{*/
+void DoubleElementResult::PatchFill(int row, Patch* patch){
+
+	 /*Here, we fill the result information into the patch object. First, let's remember what is in a row 
+	  * of the patch object: enum_type step time element_id interpolation vertices_ids nodal_values
+	  * Here, we will supply the enum_type, step, time, interpolation and nodal_values: */
+	patch->fillresultinfo(row,this->enum_type,this->step,this->time,P0Enum,&this->value,1);
+
+}
+/*}}}*/
+/*FUNCTION DoubleElementResult::GetVectorFromResults{{{1*/
+void DoubleElementResult::GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	_error_("cannot return vector on vertices");
+} /*}}}*/
+/*FUNCTION DoubleElementResult::GetElementVectorFromResults{{{1*/
+void DoubleElementResult::GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof){
+
+	vector->SetValue(dof,value,INS_VAL);
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/ElementResults/DoubleElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/DoubleElementResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/DoubleElementResult.h	(revision 15012)
@@ -0,0 +1,49 @@
+/*! \file DoubleElementResult.h 
+ *  \brief: header file for IssmDouble result object
+ *  A IssmDouble result object is just derived from a DoubleInput object, with additional time and step information.
+ */
+
+#ifndef _DOUBLEELEMENTRESULT_H_
+#define _DOUBLEELEMENTRESULT_H_
+
+/*Headers:*/
+#include "../Inputs/Input.h"
+class Parameters;
+
+class DoubleElementResult: public ElementResult{
+
+	private: 
+		int    enum_type;
+		IssmDouble value;
+		int    step;
+		IssmDouble time;
+
+	public:
+
+		/*DoubleElementResult constructors, destructors: {{{*/
+		DoubleElementResult();
+		DoubleElementResult(int enum_type,IssmDouble value,int step,IssmDouble time);
+		~DoubleElementResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ElementResult virtual functions definitions: {{{*/
+		ElementResult* SpawnTriaElementResult(int* indices);
+		IssmDouble  GetTime(void){return time;};
+		int     GetStep(void){return step;};
+		void    ProcessUnits(Parameters* parameters);
+		int     NumberOfNodalValues(void);
+		void    PatchFill(int row, Patch* patch);
+		/*}}}*/
+		/*DoubleElementResult management: {{{*/
+		int   InstanceEnum();
+		void GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof);
+		/*}}}*/
+};
+#endif  /* _DOUBLEELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/ElementResults/ElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/ElementResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/ElementResult.h	(revision 15012)
@@ -0,0 +1,30 @@
+/*!\file:  ElementResult.h
+ * \brief abstract class for ElementResult object
+ */ 
+
+#ifndef _ELEMENTRESULT_H_
+#define _ELEMENTRESULT_H_
+
+/*Headers:*/
+#include "../Object.h"
+class Patch;
+class Parameters;
+
+class ElementResult:public Object{
+
+	public: 
+
+		virtual        ~ElementResult(){};
+		virtual         ElementResult* SpawnTriaElementResult(int* indices)=0;
+		virtual IssmDouble  GetTime(void)=0;
+		virtual int     GetStep(void)=0;
+		virtual void    ProcessUnits(Parameters* parameters)=0;
+		virtual int     NumberOfNodalValues(void)=0;
+		virtual void    PatchFill(int row, Patch* patch)=0;
+		virtual int     InstanceEnum()=0;
+		virtual void    GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdof)=0;
+		virtual void    GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof)=0;
+
+};
+
+#endif
Index: /issm/trunk-jpl/src/c/classes/ElementResults/PentaP1ElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/PentaP1ElementResult.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/PentaP1ElementResult.cpp	(revision 15012)
@@ -0,0 +1,141 @@
+/*!\file PentaP1ElementResult.c
+ * \brief: implementation of the PentaP1ElementResult object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*PentaP1ElementResult constructors and destructor*/
+/*FUNCTION PentaP1ElementResult::PentaP1ElementResult(){{{*/
+PentaP1ElementResult::PentaP1ElementResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::PentaP1ElementResult(int in_enum_type,IssmDouble* in_values,int in_step, IssmDouble in_time){{{*/
+PentaP1ElementResult::PentaP1ElementResult(int in_enum_type,IssmDouble* in_values,int in_step, IssmDouble in_time){
+
+	int i;
+
+	enum_type=in_enum_type;
+	for(i=0;i<6;i++)values[i]=in_values[i];
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::~PentaP1ElementResult(){{{*/
+PentaP1ElementResult::~PentaP1ElementResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION PentaP1ElementResult::Echo {{{*/
+void PentaP1ElementResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::DeepEcho{{{*/
+void PentaP1ElementResult::DeepEcho(void){
+
+	_printLine_("PentaP1ElementResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   values: [" << this->values[0] << " " << this->values[1] << " " << this->values[2] << " " << this->values[3] << " " << this->values[4] << " " << this->values[5] << "]");
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::Id{{{*/
+int    PentaP1ElementResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::ObjectEnum{{{*/
+int PentaP1ElementResult::ObjectEnum(void){
+
+	return PentaP1ElementResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::copy{{{*/
+Object* PentaP1ElementResult::copy() {
+
+	return new PentaP1ElementResult(this->enum_type,this->values,this->step,this->time);
+
+}
+/*}}}*/
+
+/*ElementResult management*/
+/*FUNCTION PentaP1ElementResult::InstanceEnum{{{*/
+int PentaP1ElementResult::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::SpawnTriaElementResult{{{*/
+ElementResult* PentaP1ElementResult::SpawnTriaElementResult(int* indices){
+
+	/*output*/
+	TriaP1ElementResult* outresult=NULL;
+	IssmDouble newvalues[3];
+
+	/*Loop over the new indices*/
+	for(int i=0;i<3;i++){
+
+		/*Check index value*/
+		_assert_(indices[i]>=0 && indices[i]<6);
+
+		/*Assign value to new result*/
+		newvalues[i]=this->values[indices[i]];
+	}
+
+	/*Create new Tria result*/
+	outresult=new TriaP1ElementResult(this->enum_type,&newvalues[0],this->step,this->time);
+
+	/*Assign output*/
+	return outresult;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::ProcessUnits{{{*/
+void PentaP1ElementResult::ProcessUnits(Parameters* parameters){
+
+	UnitConversion(this->values,6,IuToExtEnum,this->enum_type);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::NumberOfNodalValues{{{*/
+int PentaP1ElementResult::NumberOfNodalValues(void){
+	return 6;
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::PatchFill{{{*/
+void PentaP1ElementResult::PatchFill(int row, Patch* patch){
+
+	 /*Here, we fill the result information into the patch object. First, let's remember what is in a row 
+	  * of the patch object: enum_type step time element_id interpolation vertices_ids nodal_values
+	  * Here, we will supply the enum_type, step, time, interpolation and nodal_values: */
+	patch->fillresultinfo(row,this->enum_type,this->step,this->time,P1Enum,this->values,6);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1ElementResult::GetVectorFromResults{{{*/
+void PentaP1ElementResult::GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	IssmDouble data[6];
+
+	if(numdofs!=6)_error_("Result " << EnumToStringx(this->enum_type) << " is a PentaP1ElementResult and cannot write vector of " << numdofs << " dofs");
+	for(int i=0;i<6;i++) data[i]=this->values[i]/(IssmDouble)connectivitylist[i];
+	vector->SetValues(numdofs,doflist,&data[0],ADD_VAL);
+
+} /*}}}*/
+/*FUNCTION PentaP1ElementResult::GetElementVectorFromResults{{{*/
+void PentaP1ElementResult::GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof){
+
+	_error_("Result " << EnumToStringx(enum_type) << " is a PentaP1ElementResult and should not write vector of size numberofelemenrs");
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/ElementResults/PentaP1ElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/PentaP1ElementResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/PentaP1ElementResult.h	(revision 15012)
@@ -0,0 +1,49 @@
+/*! \file PentaP1ElementResult.h 
+ *  \brief: header file for PentaP1ElementResult object
+ *  this object is just a PentaP1Input with additional time and step info.
+ */
+
+#ifndef _PENTAP1ELEMENTRESULT_H_
+#define _PENTAP1ELEMENTRESULT_H_
+
+/*Headers:*/
+#include "../Inputs/Input.h"
+
+class PentaP1ElementResult: public ElementResult{
+
+	private: 
+		int    enum_type;
+		IssmDouble values[6];
+		int    step;
+		IssmDouble time;
+
+	public:
+
+		/*PentaP1ElementResult constructors, destructors: {{{*/
+		PentaP1ElementResult();
+		PentaP1ElementResult(int enum_type,IssmDouble* values,int step, IssmDouble time);
+		~PentaP1ElementResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ElementResult virtual functions definitions: {{{*/
+		ElementResult* SpawnTriaElementResult(int* indices);
+		IssmDouble  GetTime(void){return time;};
+		int     GetStep(void){return step;};
+		void    ProcessUnits(Parameters* parameters);
+		int     NumberOfNodalValues(void);
+		void    PatchFill(int row, Patch* patch);
+		/*}}}*/
+		/*PentaP1ElementResult management: {{{*/
+		int   InstanceEnum();
+		void GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof);
+		/*}}}*/
+
+};
+#endif  /* _PENTAP1ELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/ElementResults/TriaP1ElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/TriaP1ElementResult.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/TriaP1ElementResult.cpp	(revision 15012)
@@ -0,0 +1,128 @@
+/*!\file TriaP1ElementResult.c
+ * \brief: implementation of the TriaP1ElementResult object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*TriaP1ElementResult constructors and destructor*/
+/*FUNCTION TriaP1ElementResult::TriaP1ElementResult(){{{*/
+TriaP1ElementResult::TriaP1ElementResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::TriaP1ElementResult(int in_enum_type,IssmDouble* in_values,int in_step, IssmDouble in_time){{{*/
+TriaP1ElementResult::TriaP1ElementResult(int in_enum_type,IssmDouble* in_values,int in_step, IssmDouble in_time){
+
+	enum_type=in_enum_type;
+	values[0]=in_values[0];
+	values[1]=in_values[1];
+	values[2]=in_values[2];
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::~TriaP1ElementResult(){{{*/
+TriaP1ElementResult::~TriaP1ElementResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION TriaP1ElementResult::Echo {{{*/
+void TriaP1ElementResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::DeepEcho{{{*/
+void TriaP1ElementResult::DeepEcho(void){
+
+	_printLine_("TriaP1ElementResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   values: [" << this->values[0] << " " << this->values[1] << " " << this->values[2] << "]");
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::Id{{{*/
+int    TriaP1ElementResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::ObjectEnum{{{*/
+int TriaP1ElementResult::ObjectEnum(void){
+
+	return TriaP1ElementResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::copy{{{*/
+Object* TriaP1ElementResult::copy() {
+
+	return new TriaP1ElementResult(this->enum_type,this->values,this->step,this->time);
+
+}
+/*}}}*/
+
+/*ElementResult management*/
+/*FUNCTION TriaP1ElementResult::InstanceEnum{{{*/
+int TriaP1ElementResult::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::SpawnTriaElementResult{{{*/
+ElementResult* TriaP1ElementResult::SpawnTriaElementResult(int* indices){
+
+	/*output*/
+	TriaP1ElementResult* outresult=NULL;
+
+	/*Create new Tria result (copy of current result)*/
+	outresult=new TriaP1ElementResult(this->enum_type,&this->values[0],this->step,this->time);
+
+	/*Assign output*/
+	return outresult;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::ProcessUnits{{{*/
+void TriaP1ElementResult::ProcessUnits(Parameters* parameters){
+
+	UnitConversion(this->values,3,IuToExtEnum,this->enum_type);
+
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::NumberOfNodalValues{{{*/
+int TriaP1ElementResult::NumberOfNodalValues(void){
+	return 3;
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::PatchFill{{{*/
+void TriaP1ElementResult::PatchFill(int row, Patch* patch){
+
+	 /*Here, we fill the result information into the patch object. First, let's remember what is in a row 
+	  * of the patch object: enum_type step time element_id interpolation vertices_ids nodal_values
+	  * Here, we will supply the enum_type, step, time, interpolation and nodal_values: */
+	patch->fillresultinfo(row,this->enum_type,this->step,this->time,P1Enum,this->values,3);
+
+}
+/*}}}*/
+/*FUNCTION TriaP1ElementResult::GetVectorFromResults{{{*/
+void TriaP1ElementResult::GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	IssmDouble data[3];
+
+	if(numdofs!=3)_error_("Result " << EnumToStringx(this->enum_type) << " is a TriaP1ElementResult and cannot write vector of " << numdofs << " dofs");
+	for(int i=0;i<3;i++) data[i]=this->values[i]/(IssmDouble)connectivitylist[i];
+	vector->SetValues(numdofs,doflist,&data[0],ADD_VAL);
+
+} /*}}}*/
+/*FUNCTION TriaP1ElementResult::GetElementVectorFromResults{{{*/
+void TriaP1ElementResult::GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof){
+	_error_("Result " << EnumToStringx(enum_type) << " is a TriaP1ElementResult and should not write vector of size numberofelemenrs");
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/ElementResults/TriaP1ElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ElementResults/TriaP1ElementResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ElementResults/TriaP1ElementResult.h	(revision 15012)
@@ -0,0 +1,48 @@
+/*! \file TriaP1ElementResult.h 
+ *  \brief: header file for TriaP1ElementResult object
+ */
+
+#ifndef _TRIAP1ELEMENTRESULT_H_
+#define _TRIAP1ELEMENTRESULT_H_
+
+/*Headers:*/
+#include "../Inputs/Input.h"
+
+class TriaP1ElementResult: public ElementResult{
+
+	private: 
+		int    enum_type;
+		IssmDouble values[3];
+		int    step;
+		IssmDouble time;
+
+	public:
+
+		/*TriaP1ElementResult constructors, destructors: {{{*/
+		TriaP1ElementResult();
+		TriaP1ElementResult(int enum_type,IssmDouble* values,int step,IssmDouble time);
+		~TriaP1ElementResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ElementResult virtual functions definitions: {{{*/
+		ElementResult* SpawnTriaElementResult(int* indices);
+		IssmDouble  GetTime(void){return time;};
+		int     GetStep(void){return step;};
+		void    ProcessUnits(Parameters* parameters);
+		int     NumberOfNodalValues(void);
+		void    PatchFill(int row, Patch* patch);
+		/*}}}*/
+		/*TriaP1ElementResult management: {{{*/
+		int   InstanceEnum();
+		void GetVectorFromResults(Vector<IssmDouble>* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector<IssmDouble>* vector,int dof);
+		/*}}}*/
+
+};
+#endif  /* _TRIAP1ELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/Elements/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,15 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Elements)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Elements/Tria.cpp
+             $ENV{ISSM_DIR}/src/c/classes/objects/Elements/TriaHook.cpp
+              $ENV{ISSM_DIR}/src/c/classes/objects/Elements/TriaRef.cpp PARENT_SCOPE)
+# }}}
+# THREED_SOURCES {{{
+set(THREED_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Elements/Penta.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Elements/PentaHook.cpp
+                $ENV{ISSM_DIR}/src/c/classes/objects/Elements/PentaRef.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Elements/Element.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Element.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Element.h	(revision 15012)
@@ -0,0 +1,140 @@
+/*!\file:  Element.h
+ * \brief abstract class for Element object
+ * This class is a place holder for the Tria and the Penta elements. 
+ * It is derived from Element, so DataSets can contain them.
+ */ 
+
+#ifndef _ELEMENT_H_
+#define _ELEMENT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Object.h"
+#include "../Update.h"
+
+class DataSet;
+class Parameters;
+class Patch;
+class Elements;
+class Loads;
+class Node;
+class Nodes;
+class Vertices;
+class Materials;
+template <class doublematrix> class Matrix;
+template <class doubletype> class Vector;
+
+#include "../../toolkits/toolkits.h"
+/*}}}*/
+
+class Element: public Object,public Update{
+
+	public: 
+
+		virtual        ~Element(){};
+
+		virtual void   Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters)=0;
+		virtual void   SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Materials* materials,Parameters* parameters)=0;
+		virtual void   SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum)=0;
+		virtual void   CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>*  Kfs)=0;
+		virtual void   CreateDVector(Vector<IssmDouble>* df)=0;
+		virtual void   CreatePVector(Vector<IssmDouble>* pf)=0;
+		virtual void   CreateJacobianMatrix(Matrix<IssmDouble>* Jff)=0;
+		virtual void   GetSolutionFromInputs(Vector<IssmDouble>* solution)=0;
+		virtual int    GetNodeIndex(Node* node)=0;
+		virtual int    GetNumberOfNodes(void)=0;
+		virtual void   GetNodesSidList(int* sidlist)=0;
+
+		virtual int    Sid()=0;
+		virtual bool   IsFloating()=0; 
+		virtual bool   IsNodeOnShelf()=0; 
+		virtual bool   IsNodeOnShelfFromFlags(IssmDouble* flags)=0; 
+		virtual bool   IsOnBed()=0;
+		virtual void   GetInputListOnVertices(IssmDouble* pvalue,int enumtype)=0;
+		virtual void   GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue)=0;
+		virtual void   GetInputValue(IssmDouble* pvalue,Node* node,int enumtype)=0;
+
+		virtual IssmDouble SurfaceArea(void)=0;
+		virtual void   InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum)=0;
+		virtual void   ComputeBasalStress(Vector<IssmDouble>* sigma_b)=0;
+		virtual void   ComputeStrainRate(Vector<IssmDouble>* eps)=0;
+		virtual void   PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes)=0;
+		virtual void   PatchFill(int* pcount, Patch* patch)=0;
+		virtual void   ListResultsInfo(int** results_enums,int** results_size,IssmDouble** results_times,int** results_steps,int* num_results)=0;
+		virtual void   DeleteResults(void)=0;
+		virtual void   Update(int index, IoModel* iomodel,int analysis_counter,int analysis_type)=0;
+		virtual void   InputToResult(int enum_type,int step,IssmDouble time)=0;
+		virtual void   InputDuplicate(int original_enum,int new_enum)=0;
+		virtual void   InputCreate(IssmDouble scalar,int name,int code)=0;
+		virtual void   InputCreate(IssmDouble* vector, int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code)=0;
+		virtual void   ProcessResultsUnits(void)=0;
+		virtual void   RequestedOutput(int output_enum,int step,IssmDouble time)=0;
+
+		virtual int    NodalValue(IssmDouble* pvalue, int index, int natureofdataenum,bool process_units)=0;
+		virtual void   InputScale(int enum_type,IssmDouble scale_factor)=0;
+		virtual void   GetVectorFromInputs(Vector<IssmDouble>* vector, int name_enum)=0;
+		virtual void   GetVectorFromResults(Vector<IssmDouble>* vector,int id,int enum_in,int interp)=0;
+		virtual void   InputArtificialNoise(int enum_type,IssmDouble min,IssmDouble max)=0;
+		virtual bool   InputConvergence(IssmDouble* eps, int* enums,int num_enums,int* criterionenums,IssmDouble* criterionvalues,int num_criterionenums)=0;
+		virtual void   AverageOntoPartition(Vector<IssmDouble>* partition_contributions,Vector<IssmDouble>* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part)=0;
+		virtual int*   GetHorizontalNeighboorSids(void)=0;
+		virtual IssmDouble TimeAdapt()=0;
+		virtual void   MigrateGroundingLine(IssmDouble* old_floating_ice,IssmDouble* sheet_ungrounding)=0;
+		virtual void   PotentialUngrounding(Vector<IssmDouble>* potential_sheet_ungrounding)=0;
+		virtual void   PositiveDegreeDay(IssmDouble* pdds,IssmDouble* pds,IssmDouble signorm)=0;
+		virtual void   Delta18oParameterization(void)=0;
+		virtual void   SmbGradients()=0;
+		virtual int    UpdatePotentialUngrounding(IssmDouble* potential_sheet_ungrounding,Vector<IssmDouble>* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf)=0;
+		virtual void   ResetCoordinateSystem()=0;
+		virtual void   SmearFunction(Vector<IssmDouble>* smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius)=0;
+
+		#ifdef _HAVE_RESPONSES_
+		virtual void   MinVel(IssmDouble* pminvel, bool process_units)=0;
+		virtual void   MaxVel(IssmDouble* pmaxvel, bool process_units)=0;
+		virtual void   MinVx(IssmDouble* pminvx, bool process_units)=0;
+		virtual void   MaxVx(IssmDouble* pmaxvx, bool process_units)=0;
+		virtual void   MaxAbsVx(IssmDouble* pmaxabsvx, bool process_units)=0;
+		virtual void   MinVy(IssmDouble* pminvy, bool process_units)=0;
+		virtual void   MaxVy(IssmDouble* pmaxvy, bool process_units)=0;
+		virtual void   MaxAbsVy(IssmDouble* pmaxabsvy, bool process_units)=0;
+		virtual void   MinVz(IssmDouble* pminvz, bool process_units)=0;
+		virtual void   MaxVz(IssmDouble* pmaxvz, bool process_units)=0;
+		virtual void   MaxAbsVz(IssmDouble* pmaxabsvz, bool process_units)=0;
+		virtual IssmDouble MassFlux(IssmDouble* segment,bool process_units)=0;
+		virtual void   ElementResponse(IssmDouble* presponse,int response_enum,bool process_units)=0;
+		virtual IssmDouble IceVolume(void)=0;
+		virtual IssmDouble TotalSmb(void)=0;
+		#endif
+
+		#ifdef _HAVE_GIA_
+		virtual void   GiaDeflection(Vector<IssmDouble>* wg,Vector<IssmDouble>* dwgdt,IssmDouble* x,IssmDouble* y)=0;
+		#endif
+
+		#ifdef _HAVE_CONTROL_
+		virtual void   Gradj(Vector<IssmDouble>* gradient,int control_type,int control_index)=0;
+		virtual IssmDouble ThicknessAbsMisfit(bool process_units  ,int weight_index)=0;
+		virtual IssmDouble SurfaceAbsVelMisfit(bool process_units ,int weight_index)=0;
+		virtual IssmDouble SurfaceRelVelMisfit(bool process_units ,int weight_index)=0;
+		virtual IssmDouble SurfaceLogVelMisfit(bool process_units ,int weight_index)=0;
+		virtual IssmDouble SurfaceLogVxVyMisfit(bool process_units,int weight_index)=0;
+		virtual IssmDouble SurfaceAverageVelMisfit(bool process_units,int weight_index)=0;
+		virtual IssmDouble ThicknessAbsGradient(bool process_units,int weight_index)=0;
+		virtual IssmDouble ThicknessAlongGradient(bool process_units,int weight_index)=0;
+		virtual IssmDouble ThicknessAcrossGradient(bool process_units,int weight_index)=0;
+		virtual IssmDouble BalancethicknessMisfit(bool process_units,int weight_index)=0;
+		virtual IssmDouble RheologyBbarAbsGradient(bool process_units,int weight_index)=0;
+		virtual IssmDouble DragCoefficientAbsGradient(bool process_units,int weight_index)=0;
+		virtual void   ControlInputGetGradient(Vector<IssmDouble>* gradient,int enum_type,int control_index)=0;
+		virtual void   ControlInputSetGradient(IssmDouble* gradient,int enum_type,int control_index)=0;
+		virtual void   ControlInputScaleGradient(int enum_type, IssmDouble scale)=0;
+		virtual void   GetVectorFromControlInputs(Vector<IssmDouble>* gradient,int control_enum,int control_index,const char* data)=0;
+		virtual void   SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index)=0;
+		virtual void   InputControlUpdate(IssmDouble scalar,bool save_parameter)=0;
+		#endif
+
+		#ifdef _HAVE_HYDROLOGY_
+		virtual void GetHydrologyDCInefficientHmax(IssmDouble* ph_max, Node* innode)=0;
+		virtual void BasisIntegral(Vector<IssmDouble>* basisg)=0; 
+		#endif
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Elements/Elements.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Elements.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Elements.cpp	(revision 15012)
@@ -0,0 +1,343 @@
+/*
+ * \file Elements.cpp
+ * \brief: Implementation of Elements class, derived from DataSet class
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Element.h"
+#include "./Elements.h"
+#include "../Params/Parameters.h"
+#include "../ExternalResults/Results.h"
+#include "../ExternalResults/GenericExternalResult.h"
+#include "../Patch.h"
+#include "../toolkits/toolkitobjects.h"
+#include "../../shared/shared.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Elements::Elements(){{{*/
+Elements::Elements(){
+	enum_type=MeshElementsEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Elements::~Elements(){{{*/
+Elements::~Elements(){
+	return;
+}
+/*}}}*/
+
+/*Object management*/
+/*FUNCTION Elements::Configure{{{*/
+void Elements::Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Element* element=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		element=dynamic_cast<Element*>((*object));
+		element->Configure(elements,loads,nodes,vertices,materials,parameters);
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION Elements::ProcessResultsUnits{{{*/
+void Elements::ProcessResultsUnits(void){
+
+	//Process results to be output in the correct units
+	for(int i=0;i<this->Size();i++){
+		Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
+		element->ProcessResultsUnits();
+	}
+}
+/*}}}*/
+/*FUNCTION Elements::DeleteResults{{{*/
+void Elements::DeleteResults(void){
+
+	for (int i=0;i<this->Size();i++){
+		Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
+		element->DeleteResults();
+	}
+}
+/*}}}*/
+/*FUNCTION Elements::ResultsToPatch{{{*/
+Patch* Elements::ResultsToPatch(void){ 
+
+	/*output: */
+	Patch* patch=NULL;
+
+	/*intermediary: */
+	int i;
+	int count;
+	int numrows;
+	int numvertices;
+	int numnodes;
+	int max_numvertices;
+	int max_numnodes;
+	int element_numvertices;
+	int element_numrows;
+	int element_numnodes;
+
+	/*We are going to extract from the results within the elements, the desired results , and create a table 
+	 * of patch information, that will hold, for each element that computed the result that 
+	 * we desire, the enum_type of the result, the step and time, the id of the element, the interpolation type, the vertices ids, and the values 
+	 * at the nodes (could be different from the vertices). This will be used for visualization purposes. 
+	 * For example, we could build the following patch table, for velocities: 
+	 * 
+	 1. on a Beam element, Vx, at step 1, time .5, element id 1, interpolation type P0 (constant), vertices ids 1 and 2, one constant value 4.5
+	 VxEnum 1  .5  1 P0  1 2       4.5 NaN  NaN
+	 2. on a Tria element, Vz, at step 2, time .8, element id 2, interpolation type P1 (linear), vertices ids 1 3 and 4, with values at 3 nodes 4.5, 3.2, 2.5
+	 VzEnum 2  .8  2 P1  1 3 4     4.5 3.2  2.5
+	 * ... etc ...
+	 *
+	 * So what do we need to build the table: the maximum number of vertices included in the table, 
+	 * and the maximum number of nodal values, as well as the number of rows. Once we have that, 
+	 * we ask the elements to fill their own row in the table, by looping on the elememnts. 
+	 *
+	 * We will use the Patch object, which will store all of the information needed, and will be able 
+	 * to output itself to disk on its own. See object/Patch.h for format of this object.*/
+
+	/*First, determine maximum number of vertices, nodes, and number of results: */
+	numrows=0;
+	numvertices=0;
+	numnodes=0;
+
+	for(i=0;i<this->Size();i++){
+
+		Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
+		element->PatchSize(&element_numrows,&element_numvertices,&element_numnodes);
+
+		numrows+=element_numrows;
+		if(element_numvertices>numvertices)numvertices=element_numvertices;
+		if(element_numnodes>numnodes)numnodes=element_numnodes;
+	}
+
+	/*Synchronize across cluster, so as to not end up with different sizes for each patch on each cpu: */
+	#ifdef _HAVE_MPI_
+	MPI_Reduce (&numvertices,&max_numvertices,1,MPI_INT,MPI_MAX,0,IssmComm::GetComm() );
+	MPI_Bcast(&max_numvertices,1,MPI_INT,0,IssmComm::GetComm());
+	numvertices=max_numvertices;
+
+	MPI_Reduce (&numnodes,&max_numnodes,1,MPI_INT,MPI_MAX,0,IssmComm::GetComm() );
+	MPI_Bcast(&max_numnodes,1,MPI_INT,0,IssmComm::GetComm());
+	numnodes=max_numnodes;
+	#endif
+
+	/*Ok, initialize Patch object: */
+	patch=new Patch(numrows,numvertices,numnodes);
+
+	/*Now, go through elements, and fill the Patch object: */
+	count=0;
+	for(i=0;i<this->Size();i++){
+		Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
+		element->PatchFill(&count,patch);
+	}
+
+	return patch;
+}
+/*}}}*/
+/*FUNCTION Elements::SetCurrentConfiguration{{{*/
+void Elements::SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Element* element=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		element=dynamic_cast<Element*>((*object));
+		element->SetCurrentConfiguration(elements,loads,nodes,materials,parameters);
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION Elements::ToResults{{{*/
+void Elements::ToResults(Results* results,Parameters* parameters){
+
+	int my_rank;
+	int num_procs;
+
+	Patch               *patch              = NULL;
+	int                 *resultsenums       = NULL;
+	int                 *resultssizes       = NULL;
+	int                 *resultssteps       = NULL;
+	IssmDouble          *resultstimes       = NULL;
+	IssmDouble          *vector_serial      = NULL;
+	Vector<IssmDouble> *vector = NULL;
+	bool                io_gather;
+	bool                results_as_patches;
+	int                 numberofvertices     ,numberofelements;
+	int                 numberofresults      ,vectorsize;
+	int                 rank;
+	int                 minrank;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+	num_procs=IssmComm::GetSize();
+
+	/*Recover parameters: */
+	parameters->FindParam(&io_gather,SettingsIoGatherEnum);
+	parameters->FindParam(&results_as_patches,SettingsResultsAsPatchesEnum);
+	parameters->FindParam(&numberofvertices,MeshNumberofverticesEnum);
+	parameters->FindParam(&numberofelements,MeshNumberofelementsEnum);
+
+	if(!results_as_patches){
+		/*No patch here, we prepare vectors*/
+
+		/*Get rank of first cpu that has results*/
+		#ifdef _HAVE_MPI_
+		if(this->Size()) rank=my_rank;
+		else rank=num_procs;
+		MPI_Allreduce (&rank,&minrank,1,MPI_INT,MPI_MIN,IssmComm::GetComm());
+		#else
+		minrank=my_rank;
+		#endif
+
+		/*see what the first element of this partition has in stock (this is common to all partitions)*/
+		if(my_rank==minrank){
+			if(this->Size()==0) _error_("Cannot write results because there is no element??");
+			Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(0));
+			element->ListResultsInfo(&resultsenums,&resultssizes,&resultstimes,&resultssteps,&numberofresults);
+		}
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(&numberofresults,1,MPI_DOUBLE,minrank,IssmComm::GetComm());
+		#endif
+
+		/*Get out if there is no results. Otherwise broadcast info*/
+		if(!numberofresults) return;
+		#ifdef _HAVE_MPI_
+		if(my_rank!=minrank){
+			resultsenums=xNew<int>(numberofresults);
+			resultssizes=xNew<int>(numberofresults);
+			resultstimes=xNew<IssmDouble>(numberofresults);
+			resultssteps=xNew<int>(numberofresults);
+		}
+		MPI_Bcast(resultsenums,numberofresults,MPI_INT,minrank,IssmComm::GetComm());
+		MPI_Bcast(resultssizes,numberofresults,MPI_INT,minrank,IssmComm::GetComm());
+		MPI_Bcast(resultstimes,numberofresults,MPI_DOUBLE,minrank,IssmComm::GetComm());
+		MPI_Bcast(resultssteps,numberofresults,MPI_INT,minrank,IssmComm::GetComm());
+		#endif
+
+		/*Loop over all results and get nodal vector*/
+		for(int i=0;i<numberofresults;i++){
+
+			/*Get vector for result number i*/
+			if(resultssizes[i]==P1Enum)      vectorsize=numberofvertices;
+			else if(resultssizes[i]==P0Enum) vectorsize=numberofelements;
+			else _error_("Unkown result size: " << EnumToStringx(resultssizes[i]));
+			vector=new Vector<IssmDouble>(vectorsize);
+
+			for(int j=0;j<this->Size();j++){
+				Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(j));
+				element->GetVectorFromResults(vector,i,resultsenums[i],resultssizes[i]);
+			}
+			vector->Assemble();
+
+			/*Serialize and add to results*/
+			vector_serial=vector->ToMPISerial();
+			if(my_rank==0){
+				/*No need to add this vector for all cpus*/
+				#ifdef _HAVE_ADOLC_
+				IssmPDouble* vector_serial_passive=xNew<IssmPDouble>(vectorsize);
+				for(int k=0;k<vectorsize;k++)vector_serial_passive[k]=reCast<IssmPDouble>(vector_serial[k]);
+				results->AddObject(new GenericExternalResult<double*>(results->Size()+1,resultsenums[i],vector_serial_passive,vectorsize,1,resultssteps[i],resultstimes[i]));
+				xDelete<IssmPDouble>(vector_serial_passive);
+				#else
+				results->AddObject(new GenericExternalResult<double*>(results->Size()+1,resultsenums[i],vector_serial,vectorsize,1,resultssteps[i],resultstimes[i]));
+				#endif
+			}
+
+			/*clean up*/
+			delete vector;
+			xDelete<IssmDouble>(vector_serial);
+		}
+	}
+	else{
+		/*create patch object out of all results in this dataset: */
+		patch=this->ResultsToPatch();
+
+		/*Gather onto master cpu 0, if needed: */
+		if(io_gather)patch->Gather();
+
+		/*create result object and add to results dataset:*/
+		if (patch->maxvertices && patch->maxnodes){
+			results->AddObject(new GenericExternalResult<int>(results->Size()+1,PatchVerticesEnum,patch->maxvertices,1,0));
+			results->AddObject(new GenericExternalResult<int>(results->Size()+1,PatchNodesEnum,   patch->maxnodes,1,0));
+			#ifdef _HAVE_ADOLC_
+			IssmPDouble* values_passive=xNew<IssmPDouble>(patch->numrows*patch->numcols);
+			for(int k=0;k<(patch->numrows*patch->numcols);k++)values_passive[k]=reCast<IssmPDouble>(patch->values[k]);
+			results->AddObject(new GenericExternalResult<double*>(results->Size()+1,PatchEnum,  values_passive,patch->numrows,patch->numcols,1,0));
+			xDelete<IssmPDouble>(values_passive);
+			#else
+			results->AddObject(new GenericExternalResult<double*>(results->Size()+1,PatchEnum,  patch->values,patch->numrows,patch->numcols,1,0));
+			#endif
+		}
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(resultsenums);
+	xDelete<int>(resultssizes);
+	xDelete<int>(resultssteps);
+	xDelete<IssmDouble>(resultstimes);
+	delete patch;
+}
+/*}}}*/
+/*FUNCTION Elements::MaxNumNodes{{{*/
+int Elements::MaxNumNodes(void){
+
+	int max=0;
+	int allmax;
+	int numnodes=0;
+
+	/*Now go through all elements, and get how many nodes they own, unless they are clone nodes: */
+	for(int i=0;i<this->Size();i++){
+
+		Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
+		numnodes=element->GetNumberOfNodes();
+		if(numnodes>max)max=numnodes;
+	}
+
+	/*Grab max of all cpus: */
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)&max,(void*)&allmax,1,MPI_INT,MPI_MAX,IssmComm::GetComm());
+	max=allmax;
+	#endif
+
+	return max;
+}
+/*}}}*/
+/*FUNCTION Elements::NumberOfElements{{{*/
+int Elements::NumberOfElements(void){
+
+	int local_nelem;
+	int numberofelements;
+
+	local_nelem=this->Size();
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce ( (void*)&local_nelem,(void*)&numberofelements,1,MPI_INT,MPI_SUM,IssmComm::GetComm());
+	#else
+	numberofelements=local_nelem;
+	#endif
+
+	return numberofelements;
+}
+/*}}}*/
+/*FUNCTION Elements::InputCopy{{{*/
+void Elements::InputDuplicate(int input_enum,int output_enum){
+
+	for(int i=0;i<this->Size();i++){
+		Element* element=dynamic_cast<Element*>(this->GetObjectByOffset(i));
+		element->InputDuplicate(input_enum,output_enum);
+	}
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Elements/Elements.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Elements.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Elements.h	(revision 15012)
@@ -0,0 +1,38 @@
+#ifndef _CONTAINER_ELEMENTS_H_
+#define  _CONTAINER_ELEMENTS_H_
+
+/*forward declarations */
+#include "../DataSet.h"
+class Materials;
+class Parameters;
+class Vertices;
+class Loads;
+class Nodes;
+class Patch;
+
+/*! \brief Declaration of Elements class 
+ *
+ * Declaration of Elements class.  Elements are vector lists (Containers) of Element objects.
+ */ 
+class Elements: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Elements();
+		~Elements();
+
+		/*numerics*/
+		void   Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+		void   DeleteResults(void);
+		int    MaxNumNodes(void);
+		void   ProcessResultsUnits(void);
+		void   SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+		void   ToResults(Results* results,Parameters* parameters);
+		Patch* ResultsToPatch(void);
+		int    NumberOfElements(void);
+		void   InputDuplicate(int input_enum,int output_enum);
+
+};
+
+#endif //ifndef _ELEMENTS_H_
Index: /issm/trunk-jpl/src/c/classes/Elements/Penta.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Penta.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Penta.cpp	(revision 15012)
@@ -0,0 +1,9352 @@
+/*!\file Penta.cpp
+ * \brief: implementation of the Penta object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES   6
+#define NUMVERTICES2D 3
+
+/*Constructors/destructor/copy*/
+/*FUNCTION Penta::Penta(){{{*/
+Penta::Penta(){
+
+	this->nodes             = NULL;
+	this->vertices          = NULL;
+	this->material          = NULL;
+	this->matpar            = NULL;
+	this->verticalneighbors = NULL;
+	this->inputs            = NULL;
+	this->parameters        = NULL;
+	this->results           = NULL;
+	for(int i=0;i<3;i++)this->horizontalneighborsids[i]=UNDEF;
+}
+/*}}}*/
+/*FUNCTION Penta::~Penta(){{{*/
+Penta::~Penta(){
+	delete inputs;
+	delete results;
+	this->parameters=NULL;
+}
+/*}}}*/
+/*FUNCTION Penta::Penta(int id, int index, IoModel* iomodel,int nummodels) {{{*/
+Penta::Penta(int penta_id, int penta_sid, int index, IoModel* iomodel,int nummodels)
+	:PentaRef(nummodels)
+	,PentaHook(nummodels,index+1,iomodel) //index+1: material id, iomodel->numberofelements+1: matpar id
+                                                                      { //i is the element index
+
+	int i;
+	int penta_elements_ids[2];
+
+	/*Checks in debugging mode*/
+	/*{{{*/
+	_assert_(iomodel->Data(MeshUpperelementsEnum));
+	_assert_(iomodel->Data(MeshLowerelementsEnum));
+	/*}}}*/
+
+	/*id: */
+	this->id=penta_id;
+	this->sid=penta_sid;
+
+	/*Build neighbors list*/
+	if (xIsNan<IssmDouble>(iomodel->Data(MeshUpperelementsEnum)[index]) || iomodel->Data(MeshUpperelementsEnum)[index]==-1.) penta_elements_ids[1]=this->id; //upper penta is the same penta
+	else                                    penta_elements_ids[1]=reCast<int,IssmDouble>((iomodel->Data(MeshUpperelementsEnum)[index]));
+	if (xIsNan<IssmDouble>(iomodel->Data(MeshLowerelementsEnum)[index]) || iomodel->Data(MeshLowerelementsEnum)[index]==-1.) penta_elements_ids[0]=this->id; //lower penta is the same penta
+	else                                    penta_elements_ids[0]=reCast<int,IssmDouble>((iomodel->Data(MeshLowerelementsEnum)[index]));
+	this->InitHookNeighbors(penta_elements_ids);
+
+	/*Build horizontalneighborsids list: */
+	_assert_(iomodel->Data(MeshElementconnectivityEnum));
+	for(i=0;i<3;i++) this->horizontalneighborsids[i]=reCast<int,IssmDouble>(iomodel->Data(MeshElementconnectivityEnum)[3*index+i])-1;
+
+	//this->parameters: we still can't point to it, it may not even exist. Configure will handle this.
+	this->parameters=NULL;
+
+	/*intialize inputs and results: */
+	this->inputs=new Inputs();
+	this->results=new Results();
+
+	/*initialize pointers:*/
+	this->nodes             = NULL;
+	this->vertices          = NULL;
+	this->material          = NULL;
+	this->matpar            = NULL;
+	this->verticalneighbors = NULL;
+}
+/*}}}*/
+/*FUNCTION Penta::copy {{{*/
+Object* Penta::copy() {
+
+	int i;
+
+	Penta* penta=NULL;
+
+	penta=new Penta();
+
+	//deal with PentaRef mother class
+	penta->element_type_list=xNew<int>(this->numanalyses);
+	for(i=0;i<this->numanalyses;i++) penta->element_type_list[i]=this->element_type_list[i];
+
+	//deal with PentaHook mother class
+	penta->numanalyses=this->numanalyses;
+	penta->hnodes=new Hook*[penta->numanalyses];
+	for(i=0;i<penta->numanalyses;i++)penta->hnodes[i]=(Hook*)this->hnodes[i]->copy();
+	penta->hvertices=(Hook*)this->hvertices->copy();
+	penta->hmaterial=(Hook*)this->hmaterial->copy();
+	penta->hmatpar=(Hook*)this->hmatpar->copy();
+	penta->hneighbors=(Hook*)this->hneighbors->copy();
+
+	/*deal with Penta  copy fields: */
+	penta->id=this->id;
+	penta->sid=this->sid;
+	if(this->inputs){
+		penta->inputs=(Inputs*)this->inputs->Copy();
+	}
+	else{
+		penta->inputs=new Inputs();
+	}
+	if(this->results){
+		penta->results=(Results*)this->results->Copy();
+	}
+	else{
+		penta->results=new Results();
+	}
+	/*point parameters: */
+	penta->parameters=this->parameters;
+
+	/*recover objects: */
+	penta->nodes=xNew<Node*>(6); //we cannot rely on an analysis_counter to tell us which analysis_type we are running, so we just copy the nodes.
+	for(i=0;i<6;i++)penta->nodes[i]=this->nodes[i];
+	penta->vertices=(Vertex**)penta->hvertices->deliverp();
+	penta->material=(Material*)penta->hmaterial->delivers();
+	penta->matpar=(Matpar*)penta->hmatpar->delivers();
+	penta->verticalneighbors=(Penta**)penta->hneighbors->deliverp();
+
+	/*neighbors: */
+	for(i=0;i<3;i++)penta->horizontalneighborsids[i]=this->horizontalneighborsids[i];
+
+	return penta;
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION Penta::AverageOntoPartition {{{*/
+void  Penta::AverageOntoPartition(Vector<IssmDouble>* partition_contributions,Vector<IssmDouble>* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part){
+	_error_("Not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::BedNormal {{{*/
+void Penta::BedNormal(IssmDouble* bed_normal, IssmDouble xyz_list[3][3]){
+
+	int i;
+	IssmDouble v13[3],v23[3];
+	IssmDouble normal[3];
+	IssmDouble 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::BasalFrictionCreateInput {{{*/
+void Penta::BasalFrictionCreateInput(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int    count;
+	IssmDouble basalfriction[NUMVERTICES]={0,0,0,0,0,0};
+	IssmDouble alpha2,vx,vy;
+	Friction*  friction=NULL;
+	GaussPenta* gauss=NULL;
+
+	/* Basal friction can only be found at the base of an ice sheet: */
+	if (!IsOnBed() || IsFloating()){
+		//empty friction: 
+		this->inputs->AddInput(new PentaP1Input(BasalFrictionEnum,&basalfriction[0]));
+		return;
+	}
+
+	/*Retrieve all inputs and parameters*/
+	Input* vx_input=inputs->GetInput(VxEnum);                         _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                         _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                         _assert_(vz_input);
+
+	/*Build friction element, needed later: */
+	friction=new Friction("3d",inputs,matpar,DiagnosticHorizAnalysisEnum);
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	count=0;
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		basalfriction[count]=alpha2*(pow(vx,2.0)+pow(vy,2.0));
+		count++;
+	}
+
+	/*Create PentaVertex input, which will hold the basal friction:*/
+	this->inputs->AddInput(new PentaP1Input(BasalFrictionEnum,&basalfriction[0]));
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+}
+/*}}}*/
+/*FUNCTION Penta::ComputeBasalStress {{{*/
+void  Penta::ComputeBasalStress(Vector<IssmDouble>* sigma_b){
+
+	int         i,j;
+	int         dofv[3]={0,1,2};
+	int         dofp[1]={3};
+	int         analysis_type,approximation;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  xyz_list_tria[3][3];
+	IssmDouble  rho_ice,gravity,stokesreconditioning;
+	IssmDouble  pressure,viscosity,Jdet2d;
+	IssmDouble  bed_normal[3];
+	IssmDouble  basalforce[3];
+	IssmDouble  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble  stresstensor[6]={0.0};
+	IssmDouble  sigma_xx,sigma_yy,sigma_zz;
+	IssmDouble  sigma_xy,sigma_xz,sigma_yz;
+	IssmDouble  surface=0,value=0;
+	GaussPenta* gauss;
+
+	/*retrive parameters: */
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	/*Check analysis_types*/
+	if (analysis_type!=DiagnosticHorizAnalysisEnum) _error_("Not supported yet!");
+	if (approximation!=StokesApproximationEnum) _error_("Not supported yet!");
+
+	/*retrieve some parameters: */
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+
+	if(!IsOnBed()){
+		//put zero
+		sigma_b->SetValue(id-1,0.0,INS_VAL);
+		return;
+	}
+
+	/*recovre material parameters: */
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<3;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+
+	/*Retrieve all inputs we will be needing: */
+	Input* pressure_input=inputs->GetInput(PressureEnum); _assert_(pressure_input);
+	Input* vx_input=inputs->GetInput(VxEnum);             _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);             _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);             _assert_(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/*Compute strain rate viscosity and pressure: */
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		pressure_input->GetInputValue(&pressure,gauss);
+
+		/*Compute Stress*/
+		sigma_xx=2*viscosity*epsilon[0]-pressure*stokesreconditioning; // sigma = nu eps - pressure
+		sigma_yy=2*viscosity*epsilon[1]-pressure*stokesreconditioning;
+		sigma_zz=2*viscosity*epsilon[2]-pressure*stokesreconditioning;
+		sigma_xy=2*viscosity*epsilon[3];
+		sigma_xz=2*viscosity*epsilon[4];
+		sigma_yz=2*viscosity*epsilon[5];
+
+		/*Get normal vector to the bed */
+		BedNormal(&bed_normal[0],xyz_list_tria);
+
+		/*basalforce*/
+		basalforce[0] += sigma_xx*bed_normal[0] + sigma_xy*bed_normal[1] + sigma_xz*bed_normal[2];
+		basalforce[1] += sigma_xy*bed_normal[0] + sigma_yy*bed_normal[1] + sigma_yz*bed_normal[2];
+		basalforce[2] += sigma_xz*bed_normal[0] + sigma_yz*bed_normal[1] + sigma_zz*bed_normal[2];
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		value+=sigma_zz*Jdet2d*gauss->weight;
+		surface+=Jdet2d*gauss->weight;
+	}
+	value=value/surface;
+
+	/*Add value to output*/
+	sigma_b->SetValue(id-1,value,INS_VAL);
+}
+/*}}}*/
+/*FUNCTION Penta::ComputeStrainRate {{{*/
+void  Penta::ComputeStrainRate(Vector<IssmDouble>* eps){
+
+	_error_("Not implemented yet");
+
+}
+/*}}}*/
+/*FUNCTION Penta::ComputeStressTensor {{{*/
+void  Penta::ComputeStressTensor(){
+
+	IssmDouble      xyz_list[NUMVERTICES][3];
+	IssmDouble      pressure,viscosity;
+	IssmDouble      epsilon[6]; /* epsilon=[exx,eyy,exy];*/
+	IssmDouble      sigma_xx[NUMVERTICES];
+	IssmDouble		sigma_yy[NUMVERTICES];
+	IssmDouble		sigma_zz[NUMVERTICES];
+	IssmDouble      sigma_xy[NUMVERTICES];
+	IssmDouble		sigma_xz[NUMVERTICES];
+	IssmDouble		sigma_yz[NUMVERTICES];
+	GaussPenta* gauss=NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* pressure_input=inputs->GetInput(PressureEnum); _assert_(pressure_input);
+	Input* vx_input=inputs->GetInput(VxEnum);             _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);             _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);             _assert_(vz_input);
+
+	/* Start looping on the number of vertices: */
+	gauss=new GaussPenta();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+
+		/*Compute strain rate viscosity and pressure: */
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3d(&viscosity,&epsilon[0]);
+		pressure_input->GetInputValue(&pressure,gauss);
+
+		/*Compute Stress*/
+		sigma_xx[iv]=2*viscosity*epsilon[0]-pressure; // sigma = nu eps - pressure
+		sigma_yy[iv]=2*viscosity*epsilon[1]-pressure;
+		sigma_zz[iv]=2*viscosity*epsilon[2]-pressure;
+		sigma_xy[iv]=2*viscosity*epsilon[3];
+		sigma_xz[iv]=2*viscosity*epsilon[4];
+		sigma_yz[iv]=2*viscosity*epsilon[5];
+	}
+
+	/*Add Stress tensor components into inputs*/
+	this->inputs->AddInput(new PentaP1Input(StressTensorxxEnum,&sigma_xx[0]));
+	this->inputs->AddInput(new PentaP1Input(StressTensorxyEnum,&sigma_xy[0]));
+	this->inputs->AddInput(new PentaP1Input(StressTensorxzEnum,&sigma_xz[0]));
+	this->inputs->AddInput(new PentaP1Input(StressTensoryyEnum,&sigma_yy[0]));
+	this->inputs->AddInput(new PentaP1Input(StressTensoryzEnum,&sigma_yz[0]));
+	this->inputs->AddInput(new PentaP1Input(StressTensorzzEnum,&sigma_zz[0]));
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+		/*FUNCTION Penta::Configure {{{*/
+void  Penta::Configure(Elements* elementsin, Loads* loadsin, Nodes* nodesin,Vertices* verticesin, 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];
+
+	/*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->hvertices->configure(verticesin);
+	this->hmaterial->configure(materialsin);
+	this->hmatpar->configure(materialsin);
+	this->hneighbors->configure(elementsin);
+
+	/*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->vertices          = (Vertex**)this->hvertices->deliverp();
+	this->material          = (Material*)this->hmaterial->delivers();
+	this->matpar            = (Matpar*)this->hmatpar->delivers();
+	this->verticalneighbors = (Penta**)this->hneighbors->deliverp();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+
+	/*get inputs configured too: */
+	this->inputs->Configure(parameters);
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrix {{{*/
+void  Penta::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->material && this->matpar && this->verticalneighbors && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Skip if water element*/
+	if(IsOnWater()) return;
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticHoriz();
+			break;
+		case AdjointHorizAnalysisEnum:
+			Ke=CreateKMatrixAdjointHoriz();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticHutter();
+			break;
+		case DiagnosticVertAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticVert();
+			break;
+		#endif
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			Ke=CreateBasalMassMatrix();
+			break;
+		case PrognosticAnalysisEnum:
+			Ke=CreateKMatrixPrognostic();
+			break;
+		#ifdef _HAVE_BALANCED_
+		case BalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixBalancethickness();
+			break;
+		#endif
+		#ifdef _HAVE_THERMAL_
+		case ThermalAnalysisEnum:
+			Ke=CreateKMatrixThermal();
+			break;
+		case EnthalpyAnalysisEnum:
+			Ke=CreateKMatrixEnthalpy();
+			break;
+		case MeltingAnalysisEnum:
+			Ke=CreateKMatrixMelting();
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixPrognostic {{{*/
+ElementMatrix* Penta::CreateKMatrixPrognostic(void){
+
+	if (!IsOnBed()) return NULL;
+
+	/*Depth Averaging Vx and Vy*/
+	this->InputDepthAverageAtBase(VxEnum,VxAverageEnum);
+	this->InputDepthAverageAtBase(VyEnum,VyAverageEnum);
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixPrognostic();
+	delete tria->material; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateBasalMassMatrix{{{*/
+ElementMatrix* Penta::CreateBasalMassMatrix(void){
+
+	if (!IsOnBed()) return NULL;
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateMassMatrix();
+	delete tria->material; delete tria;
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateDVector {{{*/
+void  Penta::CreateDVector(Vector<IssmDouble>* df){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	ElementVector* De=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->material && this->matpar && this->verticalneighbors && this->parameters && this->inputs);
+	/*}}}*/
+
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			De=CreateDVectorDiagnosticHoriz();
+			break;
+		#endif
+	}
+
+	/*Add to global Vector*/
+	if(De){
+		De->InsertIntoGlobal(df);
+		delete De;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVector {{{*/
+void  Penta::CreatePVector(Vector<IssmDouble>* pf){
+
+	/*retrive parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*if debugging mode, check that all pointers exist {{{*/
+	_assert_(this->nodes && this->material && this->matpar && this->verticalneighbors && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Skip if water element*/
+	if(IsOnWater()) return;
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			pe=CreatePVectorDiagnosticHoriz();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			pe=CreatePVectorDiagnosticHutter();
+			break;
+		case DiagnosticVertAnalysisEnum:
+			pe=CreatePVectorDiagnosticVert();
+			break;
+		#endif
+	 	#ifdef _HAVE_CONTROL_
+		case AdjointHorizAnalysisEnum:
+			pe=CreatePVectorAdjointHoriz();
+			break;
+		#endif
+		#ifdef _HAVE_THERMAL_
+		case ThermalAnalysisEnum:
+			pe=CreatePVectorThermal();
+			break;
+		case EnthalpyAnalysisEnum:
+			pe=CreatePVectorEnthalpy();
+			break;
+		case MeltingAnalysisEnum:
+			pe=CreatePVectorMelting();
+			break;
+		#endif
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			pe=CreatePVectorSlope();
+			break;
+		case PrognosticAnalysisEnum:
+			pe=CreatePVectorPrognostic();
+			break;
+		#ifdef _HAVE_BALANCED_
+		case BalancethicknessAnalysisEnum:
+			pe=CreatePVectorBalancethickness();
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorPrognostic {{{*/
+ElementVector* Penta::CreatePVectorPrognostic(void){
+
+	if (!IsOnBed()) 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); //nodes 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorPrognostic();
+	delete tria->material; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorSlope {{{*/
+ElementVector* Penta::CreatePVectorSlope(void){
+
+	if (!IsOnBed()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorSlope();
+	delete tria->material; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianMatrix{{{*/
+void  Penta::CreateJacobianMatrix(Matrix<IssmDouble>* Jff){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->material && this->matpar && this->verticalneighbors && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Skip if water element*/
+	if(IsOnWater()) return;
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			Ke=CreateJacobianDiagnosticHoriz();
+			break;
+#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Jff);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::DeepEcho{{{*/
+void Penta::DeepEcho(void){
+
+	_printLine_("Penta:");
+	_printLine_("   id: " << id);
+	nodes[0]->DeepEcho();
+	nodes[1]->DeepEcho();
+	nodes[2]->DeepEcho();
+	nodes[3]->DeepEcho();
+	nodes[4]->DeepEcho();
+	nodes[5]->DeepEcho();
+	material->DeepEcho();
+	matpar->DeepEcho();
+	_printLine_("   neighbor ids: " << verticalneighbors[0]->Id() << "-" << verticalneighbors[1]->Id());
+	_printLine_("   parameters");
+	parameters->DeepEcho();
+	_printLine_("   inputs");
+	inputs->DeepEcho();
+	_printLine_("   results");
+	results->DeepEcho();
+	_printLine_("neighboor sids: ");
+	_printLine_(" " << horizontalneighborsids[0] << " " << horizontalneighborsids[1] << " " << horizontalneighborsids[2]);
+}
+/*}}}*/
+/*FUNCTION Penta::DeleteResults {{{*/
+void  Penta::DeleteResults(void){
+
+	/*Delete and reinitialize results*/
+	delete this->results;
+	this->results=new Results();
+
+}
+/*}}}*/
+/*FUNCTION Penta::Delta18oParameterization{{{*/
+void  Penta::Delta18oParameterization(void){
+        /*Are we on the base? If not, return*/
+        if(!IsOnBed()) return;
+
+	int        i;
+	IssmDouble monthlytemperatures[NUMVERTICES][12],monthlyprec[NUMVERTICES][12];
+	IssmDouble TemperaturesPresentday[NUMVERTICES][12],TemperaturesLgm[NUMVERTICES][12];
+	IssmDouble PrecipitationsPresentday[NUMVERTICES][12];
+	IssmDouble tmp[NUMVERTICES];
+	IssmDouble Delta18oPresent,Delta18oLgm,Delta18oTime;
+	IssmDouble Delta18oSurfacePresent,Delta18oSurfaceLgm,Delta18oSurfaceTime;
+	IssmDouble time,yts,finaltime;
+	this->parameters->FindParam(&time,TimeEnum);
+	this->parameters->FindParam(&yts,ConstantsYtsEnum);
+	this->parameters->FindParam(&finaltime,TimesteppingFinalTimeEnum);
+
+	/*Recover present day temperature and precipitation*/
+	Input*     input=inputs->GetInput(SurfaceforcingsTemperaturesPresentdayEnum);    _assert_(input);
+	Input*     input2=inputs->GetInput(SurfaceforcingsTemperaturesLgmEnum);          _assert_(input2);
+	Input*     input3=inputs->GetInput(SurfaceforcingsPrecipitationsPresentdayEnum); _assert_(input3);
+	GaussPenta* gauss=new GaussPenta();
+	for(int month=0;month<12;month++) {
+		for(int iv=0;iv<NUMVERTICES;iv++) {
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&TemperaturesPresentday[iv][month],gauss,month/12.*yts);
+			input2->GetInputValue(&TemperaturesLgm[iv][month],gauss,month/12.*yts);
+			input3->GetInputValue(&PrecipitationsPresentday[iv][month],gauss,month/12.*yts);
+			PrecipitationsPresentday[iv][month]=PrecipitationsPresentday[iv][month]/yts; // converion in m/sec
+		}
+	}
+
+	/*Recover delta18o and Delta18oSurface at present day, lgm and at time t*/
+	this->parameters->FindParam(&Delta18oPresent,SurfaceforcingsDelta18oEnum,finaltime);
+	this->parameters->FindParam(&Delta18oLgm,SurfaceforcingsDelta18oEnum,finaltime-(21000*yts));
+	this->parameters->FindParam(&Delta18oTime,SurfaceforcingsDelta18oEnum,time);
+	this->parameters->FindParam(&Delta18oSurfacePresent,SurfaceforcingsDelta18oSurfaceEnum,finaltime);
+	this->parameters->FindParam(&Delta18oSurfaceLgm,SurfaceforcingsDelta18oSurfaceEnum,finaltime-(21000*yts));
+	this->parameters->FindParam(&Delta18oSurfaceTime,SurfaceforcingsDelta18oSurfaceEnum,time);
+
+	/*Compute the temperature and precipitation*/
+	for(int iv=0;iv<NUMVERTICES;iv++){
+		ComputeDelta18oTemperaturePrecipitation(Delta18oSurfacePresent, Delta18oSurfaceLgm, Delta18oSurfaceTime, 
+					Delta18oPresent, Delta18oLgm, Delta18oTime,
+					&PrecipitationsPresentday[iv][0], 
+					&TemperaturesLgm[iv][0], &TemperaturesPresentday[iv][0], 
+					&monthlytemperatures[iv][0], &monthlyprec[iv][0]);
+	}
+
+	/*Update inputs*/ 
+	TransientInput* NewTemperatureInput = new TransientInput(SurfaceforcingsMonthlytemperaturesEnum);
+	TransientInput* NewPrecipitationInput = new TransientInput(SurfaceforcingsPrecipitationEnum);
+	for (int imonth=0;imonth<12;imonth++) {
+		for(i=0;i<NUMVERTICES;i++) tmp[i]=monthlytemperatures[i][imonth];
+		PentaP1Input* newmonthinput1 = new PentaP1Input(SurfaceforcingsMonthlytemperaturesEnum,&tmp[0]);
+		NewTemperatureInput->AddTimeInput(newmonthinput1,time+imonth/12.*yts);
+
+		for(i=0;i<NUMVERTICES;i++) tmp[i]=monthlyprec[i][imonth];
+		PentaP1Input* newmonthinput2 = new PentaP1Input(SurfaceforcingsPrecipitationEnum,&tmp[0]);
+		NewPrecipitationInput->AddTimeInput(newmonthinput2,time+imonth/12.*yts);
+	}
+
+	this->inputs->AddInput(NewTemperatureInput);
+	this->inputs->AddInput(NewPrecipitationInput);
+
+	this->InputExtrude(SurfaceforcingsMonthlytemperaturesEnum,ElementEnum);
+	this->InputExtrude(SurfaceforcingsPrecipitationEnum,ElementEnum);
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::Echo{{{*/
+
+void Penta::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION Penta::ObjectEnum{{{*/
+int Penta::ObjectEnum(void){
+
+	return PentaEnum;
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetBasalElement{{{*/
+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();
+		_assert_(penta->Id()!=this->id);
+	}
+
+	/*return output*/
+	return penta;
+}
+/*}}}*/
+/*FUNCTION Penta::GetDofList {{{*/
+void  Penta::GetDofList(int** pdoflist,int approximation_enum,int setenum){
+
+	int  i,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=xNew<int>(numberofdofs);
+
+	/*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::GetGroundedPortion{{{*/
+IssmDouble Penta::GetGroundedPortion(IssmDouble* xyz_list){
+	/*Computeportion of the element that is grounded*/ 
+
+	bool               mainlyfloating = true;
+	const IssmPDouble  epsilon= 1.e-15;
+	IssmDouble         phi,s1,s2,area_init,area_grounded;
+	IssmDouble         gl[3];
+	IssmDouble         xyz_bis[3][3];
+
+	/*Recover parameters and values*/
+	GetInputListOnVertices(&gl[0],GLlevelsetEnum);
+
+	/*Be sure that values are not zero*/
+	if(gl[0]==0) gl[0]=gl[0]+epsilon;
+	if(gl[1]==0) gl[1]=gl[1]+epsilon;
+	if(gl[2]==0) gl[2]=gl[2]+epsilon;
+
+	/*Check that not all nodes are grounded or floating*/
+	if(gl[0]>0 && gl[1]>0 && gl[2]>0){ // All grounded
+		phi=1;
+	}
+	else if(gl[0]<0 && gl[1]<0 && gl[2]<0){ //All floating
+		phi=0;
+	}
+	else{
+		/*Figure out if two nodes are floating or grounded*/
+		if(gl[0]*gl[1]*gl[2]>0) mainlyfloating=false;
+
+		if(gl[0]*gl[1]>0){ //Nodes 0 and 1 are similar, so points must be found on segment 0-2 and 1-2
+			/*Coordinates of point 2: same as initial point 2*/
+			xyz_bis[2][0]=*(xyz_list+3*2+0);
+			xyz_bis[2][1]=*(xyz_list+3*2+1);
+			xyz_bis[2][2]=*(xyz_list+3*2+2);
+
+			/*Portion of the segments*/
+			s1=gl[2]/(gl[2]-gl[1]);
+			s2=gl[2]/(gl[2]-gl[0]);
+
+			/*New point 1*/
+			xyz_bis[1][0]=*(xyz_list+3*2+0)+s1*(*(xyz_list+3*1+0)-*(xyz_list+3*2+0));
+			xyz_bis[1][1]=*(xyz_list+3*2+1)+s1*(*(xyz_list+3*1+1)-*(xyz_list+3*2+1));
+			xyz_bis[1][2]=*(xyz_list+3*2+2)+s1*(*(xyz_list+3*1+2)-*(xyz_list+3*2+2));
+
+			/*New point 0*/
+			xyz_bis[0][0]=*(xyz_list+3*2+0)+s2*(*(xyz_list+3*0+0)-*(xyz_list+3*2+0));
+			xyz_bis[0][1]=*(xyz_list+3*2+1)+s2*(*(xyz_list+3*0+1)-*(xyz_list+3*2+1));
+			xyz_bis[0][2]=*(xyz_list+3*2+2)+s2*(*(xyz_list+3*0+2)-*(xyz_list+3*2+2));
+		}
+		else if(gl[1]*gl[2]>0){ //Nodes 1 and 2 are similar, so points must be found on segment 0-1 and 0-2
+			/*Coordinates of point 0: same as initial point 2*/
+			xyz_bis[0][0]=*(xyz_list+3*0+0);
+			xyz_bis[0][1]=*(xyz_list+3*0+1);
+			xyz_bis[0][2]=*(xyz_list+3*0+2);
+
+			/*Portion of the segments*/
+			s1=gl[0]/(gl[0]-gl[1]);
+			s2=gl[0]/(gl[0]-gl[2]);
+
+			/*New point 1*/
+			xyz_bis[1][0]=*(xyz_list+3*0+0)+s1*(*(xyz_list+3*1+0)-*(xyz_list+3*0+0));
+			xyz_bis[1][1]=*(xyz_list+3*0+1)+s1*(*(xyz_list+3*1+1)-*(xyz_list+3*0+1));
+			xyz_bis[1][2]=*(xyz_list+3*0+2)+s1*(*(xyz_list+3*1+2)-*(xyz_list+3*0+2));
+
+			/*New point 2*/
+			xyz_bis[2][0]=*(xyz_list+3*0+0)+s2*(*(xyz_list+3*2+0)-*(xyz_list+3*0+0));
+			xyz_bis[2][1]=*(xyz_list+3*0+1)+s2*(*(xyz_list+3*2+1)-*(xyz_list+3*0+1));
+			xyz_bis[2][2]=*(xyz_list+3*0+2)+s2*(*(xyz_list+3*2+2)-*(xyz_list+3*0+2));
+		}
+		else if(gl[0]*gl[2]>0){ //Nodes 0 and 2 are similar, so points must be found on segment 1-0 and 1-2
+			/*Coordinates of point 1: same as initial point 2*/
+			xyz_bis[1][0]=*(xyz_list+3*1+0);
+			xyz_bis[1][1]=*(xyz_list+3*1+1);
+			xyz_bis[1][2]=*(xyz_list+3*1+2);
+
+			/*Portion of the segments*/
+			s1=gl[1]/(gl[1]-gl[0]);
+			s2=gl[1]/(gl[1]-gl[2]);
+
+			/*New point 0*/
+			xyz_bis[0][0]=*(xyz_list+3*1+0)+s1*(*(xyz_list+3*0+0)-*(xyz_list+3*1+0));
+			xyz_bis[0][1]=*(xyz_list+3*1+1)+s1*(*(xyz_list+3*0+1)-*(xyz_list+3*1+1));
+			xyz_bis[0][2]=*(xyz_list+3*1+2)+s1*(*(xyz_list+3*0+2)-*(xyz_list+3*1+2));
+
+			/*New point 2*/
+			xyz_bis[2][0]=*(xyz_list+3*1+0)+s2*(*(xyz_list+3*2+0)-*(xyz_list+3*1+0));
+			xyz_bis[2][1]=*(xyz_list+3*1+1)+s2*(*(xyz_list+3*2+1)-*(xyz_list+3*1+1));
+			xyz_bis[2][2]=*(xyz_list+3*1+2)+s2*(*(xyz_list+3*2+2)-*(xyz_list+3*1+2));
+		}
+
+		/*Compute fraction of grounded element*/
+		GetJacobianDeterminant(&area_init, xyz_list,NULL);
+		GetJacobianDeterminant(&area_grounded, &xyz_bis[0][0],NULL);
+		if(mainlyfloating==true) area_grounded=area_init-area_grounded;
+		phi=area_grounded/area_init;
+	}
+
+	if(phi>1 || phi<0) _error_("Error. Problem with portion of grounded element: value should be between 0 and 1");
+
+	return phi;
+}
+/*}}}*/
+/*FUNCTION Penta::GetVertexPidList {{{*/
+void  Penta::GetVertexPidList(int* doflist){
+
+	int i;
+	for(i=0;i<6;i++) doflist[i]=nodes[i]->GetVertexPid();
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetVertexSidList{{{*/
+void  Penta::GetVertexSidList(int* sidlist){
+
+	int i;
+	for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetVertexSid();
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetConnectivityList {{{*/
+void  Penta::GetConnectivityList(int* connectivity){
+	for(int i=0;i<NUMVERTICES;i++) connectivity[i]=nodes[i]->GetConnectivity();
+}
+/*}}}*/
+/*FUNCTION Penta::GetElementType {{{*/
+int Penta::GetElementType(){
+
+	/*return PentaRef field*/
+	return this->element_type;
+}
+/*}}}*/
+/*FUNCTION Penta::GetElementSizes{{{*/
+void Penta::GetElementSizes(IssmDouble* hx,IssmDouble* hy,IssmDouble* hz){
+
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xmin,ymin,zmin;
+	IssmDouble xmax,ymax,zmax;
+
+	/*Get xyz list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	xmin=xyz_list[0][0]; xmax=xyz_list[0][0];
+	ymin=xyz_list[0][1]; ymax=xyz_list[0][1];
+	zmin=xyz_list[0][2]; zmax=xyz_list[0][2];
+
+	for(int i=1;i<NUMVERTICES;i++){
+		if(xyz_list[i][0]<xmin) xmin=xyz_list[i][0];
+		if(xyz_list[i][0]>xmax) xmax=xyz_list[i][0];
+		if(xyz_list[i][1]<ymin) ymin=xyz_list[i][1];
+		if(xyz_list[i][1]>ymax) ymax=xyz_list[i][1];
+		if(xyz_list[i][2]<zmin) zmin=xyz_list[i][2];
+		if(xyz_list[i][2]>zmax) zmax=xyz_list[i][2];
+	}
+
+	*hx=xmax-xmin;
+	*hy=ymax-ymin;
+	*hz=zmax-zmin;
+}
+/*}}}*/
+/*FUNCTION Penta::GetHorizontalNeighboorSids {{{*/
+int* Penta::GetHorizontalNeighboorSids(){
+
+	/*return PentaRef field*/
+	return &this->horizontalneighborsids[0];
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetLowerElement{{{*/
+Penta* Penta::GetLowerElement(void){
+
+	Penta* upper_penta=NULL;
+
+	upper_penta=(Penta*)verticalneighbors[0]; //first one (0) under, second one (1) above
+
+	return upper_penta;
+}
+/*}}}*/
+/*FUNCTION Penta::GetNodeIndex {{{*/
+int Penta::GetNodeIndex(Node* node){
+
+	_assert_(nodes);
+	for(int i=0;i<NUMVERTICES;i++){
+		if(node==nodes[i])
+		 return i;
+	}
+	_error_("Node provided not found among element nodes");
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetNodesSidList{{{*/
+void Penta::GetNodesSidList(int* sidlist){
+
+	_assert_(sidlist);
+	_assert_(nodes);
+
+	for(int i=0;i<NUMVERTICES;i++){
+		sidlist[i]=nodes[i]->Sid();
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::GetNumberOfNodes{{{*/
+int Penta::GetNumberOfNodes(void){
+
+	if(this->nodes==NULL) return 0;
+
+	switch(this->element_type){
+		case P1Enum:
+			return 6;
+		case P1DGEnum:
+			return 6;
+		default:
+			_error_("Element type "<<EnumToStringx(this->element_type)<<" not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::GetInputListOnVertices(IssmDouble* pvalue,int enumtype) {{{*/
+void Penta::GetInputListOnVertices(IssmDouble* pvalue,int enumtype){
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+	if (!input) _error_("Input " << EnumToStringx(enumtype) << " not found in element");
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	GaussPenta *gauss=new GaussPenta();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+		input->GetInputValue(&pvalue[iv],gauss);
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue) {{{*/
+void Penta::GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue){
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		GaussPenta *gauss=new GaussPenta();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&pvalue[iv],gauss);
+		}
+		delete gauss;
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::GetInputValue(IssmDouble* pvalue,Node* node,int enumtype) {{{*/
+void Penta::GetInputValue(IssmDouble* pvalue,Node* node,int enumtype){
+
+	Input* input=inputs->GetInput(enumtype);
+	if(!input) _error_("No input of type " << EnumToStringx(enumtype) << " found in tria");
+
+	GaussPenta* gauss=new GaussPenta();
+	gauss->GaussVertex(this->GetNodeIndex(node));
+
+	input->GetInputValue(pvalue,gauss);
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GetPhi {{{*/
+void Penta::GetPhi(IssmDouble* phi, IssmDouble*  epsilon, IssmDouble viscosity){
+	/*Compute deformational heating from epsilon and viscosity */
+
+	IssmDouble epsilon_matrix[3][3];
+	IssmDouble epsilon_eff;
+	IssmDouble 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 * mu * eps_eff ^2*/
+	*phi=4*pow(epsilon_eff,2.0)*viscosity;
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputs{{{*/
+void  Penta::GetSolutionFromInputs(Vector<IssmDouble>* solution){
+
+	int analysis_type;
+
+	/*retrive parameters: */
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Just branch to the correct InputUpdateFromSolution generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+	#ifdef _HAVE_DIAGNOSTIC_
+	case DiagnosticHorizAnalysisEnum:
+		int approximation;
+		inputs->GetInputValue(&approximation,ApproximationEnum);
+		if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
+			GetSolutionFromInputsDiagnosticStokes(solution);
+		}
+		else if (approximation==MacAyealApproximationEnum || approximation==PattynApproximationEnum || approximation==HutterApproximationEnum){
+			GetSolutionFromInputsDiagnosticHoriz(solution);
+		}
+		else if (approximation==MacAyealPattynApproximationEnum || approximation==PattynStokesApproximationEnum || approximation==MacAyealStokesApproximationEnum){
+			return; //the elements around will create the solution
+		}
+		break;
+	case DiagnosticHutterAnalysisEnum:
+		GetSolutionFromInputsDiagnosticHutter(solution);
+		break;
+	case DiagnosticVertAnalysisEnum:
+		GetSolutionFromInputsDiagnosticVert(solution);
+		break;
+	#endif
+	#ifdef _HAVE_THERMAL_
+	case ThermalAnalysisEnum:
+		GetSolutionFromInputsThermal(solution);
+		break;
+	case EnthalpyAnalysisEnum:
+		GetSolutionFromInputsEnthalpy(solution);
+		break;
+	#endif
+	default:
+		_error_("analysis: " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::GetStabilizationParameter {{{*/
+IssmDouble Penta::GetStabilizationParameter(IssmDouble u, IssmDouble v, IssmDouble w, IssmDouble diameter, IssmDouble kappa){
+	/*Compute stabilization parameter*/
+	/*kappa=thermalconductivity/(rho_ice*hearcapacity) for thermal model*/
+	/*kappa=enthalpydiffusionparameter for enthalpy model*/
+
+	IssmDouble normu;
+	IssmDouble tau_parameter;
+
+	normu=pow(pow(u,2)+pow(v,2)+pow(w,2),0.5);
+	if(normu*diameter/(3*2*kappa)<1){ 
+		tau_parameter=pow(diameter,2)/(3*2*2*kappa);
+	}
+	else tau_parameter=diameter/(2*normu);
+
+	return tau_parameter;
+}
+/*}}}*/
+/*FUNCTION Penta::GetStrainRate3dPattyn{{{*/
+void Penta::GetStrainRate3dPattyn(IssmDouble* epsilon,IssmDouble* 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;
+	IssmDouble epsilonvx[5];
+	IssmDouble epsilonvy[5];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input){
+		_error_("Input missing. Here are the input pointers we have for vx: " << vx_input << ", vy: " << vy_input << "\n");
+	}
+
+	/*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{{{*/
+void Penta::GetStrainRate3d(IssmDouble* epsilon,IssmDouble* 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;
+	IssmDouble epsilonvx[6];
+	IssmDouble epsilonvy[6];
+	IssmDouble epsilonvz[6];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input || !vz_input){
+		_error_("Input missing. Here are the input pointers we have for vx: " << vx_input << ", vy: " << vy_input << ", vz: " << vz_input << "\n");
+	}
+
+	/*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{{{*/
+Penta* Penta::GetUpperElement(void){
+
+	Penta* upper_penta=NULL;
+
+	upper_penta=(Penta*)verticalneighbors[1]; //first one under, second one above
+
+	return upper_penta;
+}
+/*}}}*/
+/*FUNCTION Penta::GetVectorFromInputs{{{*/
+void  Penta::GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum){
+
+	int vertexpidlist[NUMVERTICES];
+
+	/*Get out if this is not an element input*/
+	if (!IsInput(input_enum)) return;
+
+	/*Prepare index list*/
+	this->GetVertexPidList(&vertexpidlist[0]);
+
+	/*Get input (either in element or material)*/
+	Input* input=inputs->GetInput(input_enum);
+	if(!input) _error_("Input " << EnumToStringx(input_enum) << " not found in element");
+
+	/*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
+	input->GetVectorFromInputs(vector,&vertexpidlist[0]);
+}
+/*}}}*/
+/*FUNCTION Penta::GetVectorFromResults{{{*/
+void  Penta::GetVectorFromResults(Vector<IssmDouble>* vector,int offset,int enum_in,int interp){
+
+	/*Get result*/
+	ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(offset);
+	if(elementresult->InstanceEnum()!=enum_in){
+		_error_("Results of offset "<<offset<<" is "<<EnumToStringx(elementresult->InstanceEnum())<<" when "<<EnumToStringx(enum_in)<<" was expected");
+	}  
+	if(interp==P1Enum){
+		int vertexpidlist[NUMVERTICES];
+		int connectivity[NUMVERTICES];
+		this->GetVertexSidList(&vertexpidlist[0]);
+		this->GetConnectivityList(&connectivity[0]);
+		elementresult->GetVectorFromResults(vector,&vertexpidlist[0],&connectivity[0],NUMVERTICES);
+	}
+	else if(interp==P0Enum){
+		elementresult->GetElementVectorFromResults(vector,sid);
+	}
+	else{
+		_printLine_("Interpolation " << EnumToStringx(interp) << " not supported");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::GetZcoord {{{*/
+IssmDouble Penta::GetZcoord(GaussPenta* gauss){
+
+	int    i;
+	IssmDouble z;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble z_list[NUMVERTICES];
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES;i++) z_list[i]=xyz_list[i][2];
+	PentaRef::GetInputValue(&z,z_list,gauss);
+
+	return z;
+}
+/*}}}*/
+/*FUNCTION Penta::Sid {{{*/
+int    Penta::Sid(){
+
+	return sid;
+
+}
+/*}}}*/
+/*FUNCTION Penta::Id {{{*/
+int    Penta::Id(void){
+	return id; 
+}
+/*}}}*/
+/*FUNCTION Penta::InputArtificialNoise{{{*/
+void  Penta::InputArtificialNoise(int enum_type,IssmDouble min,IssmDouble max){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)_error_("could not find old input with enum: " << EnumToStringx(enum_type));
+
+	/*ArtificialNoise: */
+	input->ArtificialNoise(min,max);
+}
+/*}}}*/
+/*FUNCTION Penta::InputConvergence{{{*/
+bool Penta::InputConvergence(IssmDouble* eps, int* enums,int num_enums,int* criterionenums,IssmDouble* criterionvalues,int num_criterionenums){
+
+	int i;
+	bool    converged=true;
+	Input** new_inputs=NULL;
+	Input** old_inputs=NULL;
+
+	new_inputs=xNew<Input*>(num_enums/2); //half the enums are for the new inputs
+	old_inputs=xNew<Input*>(num_enums/2); //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])_error_("could not find input with enum " << EnumToStringx(enums[2*i+0]));
+		if(!old_inputs[i])_error_("could not find input with enum " << EnumToStringx(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*/
+	xDelete<Input*>(new_inputs);
+	xDelete<Input*>(old_inputs);
+
+	/*Return output*/
+	return converged;
+}
+/*}}}*/
+/*FUNCTION Penta::InputCreate(IssmDouble scalar,int enum,int code);{{{*/
+void Penta::InputCreate(IssmDouble scalar,int name,int code){
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	if ((code==5) || (code==1)){ //boolean
+		this->inputs->AddInput(new BoolInput(name,reCast<bool,IssmDouble>(scalar)));
+	}
+	else if ((code==6) || (code==2)){ //integer
+		this->inputs->AddInput(new IntInput(name,reCast<int,IssmDouble>(scalar)));
+	}
+	else if ((code==7) || (code==3)){ //IssmDouble
+		this->inputs->AddInput(new DoubleInput(name,scalar));
+	}
+	else _error_("could not recognize nature of vector from code " << code);
+
+}
+/*}}}*/
+/*FUNCTION Penta::InputCreate(IssmDouble* vector,int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code){{{*/
+void Penta::InputCreate(IssmDouble* vector, int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code){//index into elements
+
+	/*Intermediaries*/
+	int    i,t;
+	int    penta_vertex_ids[6];
+	int    row;
+	IssmDouble nodeinputs[6];
+	IssmDouble time;
+	TransientInput* transientinput=NULL;
+
+	int    numberofvertices;
+	int    numberofelements;
+	IssmDouble yts;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&numberofvertices,MeshNumberofverticesEnum);
+	iomodel->Constant(&numberofelements,MeshNumberofelementsEnum);
+	iomodel->Constant(&yts,ConstantsYtsEnum);
+
+	/*Branch on type of vector: nodal or elementary: */
+	if(vector_type==1){ //nodal vector
+
+		/*Recover vertices ids needed to initialize inputs*/
+		for(i=0;i<6;i++){ 
+			_assert_(iomodel->Data(MeshElementsEnum));
+			penta_vertex_ids[i]=reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[6*index+i]); //ids for vertices are in the elements array from Matlab
+		}
+
+		/*Are we in transient or static? */
+		if(M==numberofvertices){
+
+			/*create input values: */
+			for(i=0;i<6;i++)nodeinputs[i]=(IssmDouble)vector[penta_vertex_ids[i]-1];
+
+			/*process units: */
+			UnitConversion(&nodeinputs[0], 6 ,ExtToIuEnum, vector_enum);
+
+			/*create static input: */
+			this->inputs->AddInput(new PentaP1Input(vector_enum,nodeinputs));
+		}
+		else if(M==numberofvertices+1){
+			/*create transient input: */
+			for(t=0;t<N;t++){ //N is the number of times
+
+				/*create input values: */
+				for(i=0;i<6;i++){
+					row=penta_vertex_ids[i]-1;
+					nodeinputs[i]=(IssmDouble)vector[N*row+t];
+				}
+
+				/*process units: */
+				UnitConversion(&nodeinputs[0], 6 ,ExtToIuEnum, vector_enum);
+
+				/*time? :*/
+				time=(IssmDouble)vector[(M-1)*N+t]*yts;
+
+				if(t==0)transientinput=new TransientInput(vector_enum);
+				transientinput->AddTimeInput(new PentaP1Input(vector_enum,nodeinputs),time);
+			}
+			this->inputs->AddInput(transientinput);
+		}
+		else _error_("nodal vector is either numberofnodes (" << numberofvertices << "), or numberofnodes+1 long. Field provided is " << M << " long. Enum " << EnumToStringx(vector_enum));
+	}
+	else if(vector_type==2){ //element vector
+		/*Are we in transient or static? */
+		if(M==numberofelements){
+
+			/*static mode: create an input out of the element value: */
+
+			if (code==5){ //boolean
+				this->inputs->AddInput(new BoolInput(vector_enum,reCast<bool,IssmDouble>(vector[index])));
+			}
+			else if (code==6){ //integer
+				this->inputs->AddInput(new IntInput(vector_enum,reCast<int,IssmDouble>(vector[index])));
+			}
+			else if (code==7){ //IssmDouble
+				this->inputs->AddInput(new DoubleInput(vector_enum,vector[index]));
+			}
+			else _error_("could not recognize nature of vector from code " << code);
+		}
+		else {
+			_error_("transient elementary inputs not supported yet!");
+		}
+	}
+	else{
+		_error_("Cannot add input for vector type " << vector_type << " (not supported)");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::InputDepthAverageAtBase{{{*/
+void  Penta::InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum){
+
+	int  step,i;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  Helem_list[NUMVERTICES];
+	IssmDouble  zeros_list[NUMVERTICES]={0.0};
+	Penta* penta=NULL;
+	Input* original_input=NULL;
+	Input* element_integrated_input=NULL;
+	Input* total_integrated_input=NULL;
+	Input* element_thickness_input=NULL;
+	Input* total_thickness_input=NULL;
+	Input* depth_averaged_input=NULL;
+
+	/*recover parameters: */
+
+	/*Are we on the base? If not, return*/
+	if(!IsOnBed()) return;
+
+	/*OK, we are on bed. Initialize global inputs as 0*/
+	total_thickness_input =new PentaP1Input(ThicknessEnum,zeros_list);
+
+	/*Now follow all the upper element from the base to the surface to integrate the input*/
+	penta=this;
+	step =0;
+	for(;;){
+
+		/*Step1: Get original input (to be depth avegaged): */
+		if (object_enum==MeshElementsEnum)
+		 original_input=(Input*)penta->inputs->GetInput(enum_type);
+		else if (object_enum==MaterialsEnum)
+		 original_input=(Input*)penta->material->inputs->GetInput(enum_type);
+		else
+		 _error_("object " << EnumToStringx(object_enum) << " not supported yet");
+		if(!original_input) _error_("could not find input with enum " << EnumToStringx(enum_type));
+
+		/*If first time, initialize total_integrated_input*/
+		if (step==0){
+			if (original_input->ObjectEnum()==PentaP1InputEnum)
+			 total_integrated_input=new PentaP1Input(average_enum_type,zeros_list);
+			else if (original_input->ObjectEnum()==ControlInputEnum)
+			 total_integrated_input=new PentaP1Input(average_enum_type,zeros_list);
+			else if (original_input->ObjectEnum()==DoubleInputEnum)
+			 total_integrated_input=new DoubleInput(average_enum_type,0.0);
+			else
+			 _error_("object " << EnumToStringx(original_input->ObjectEnum()) << " not supported yet");
+		}
+
+		/*Step2: Create element thickness input*/
+		GetVerticesCoordinates(&xyz_list[0][0],penta->vertices,NUMVERTICES);
+		for(i=0;i<3;i++){
+			Helem_list[i]=xyz_list[i+3][2]-xyz_list[i][2];
+			Helem_list[i+3]=Helem_list[i];
+		}
+		element_thickness_input=new PentaP1Input(ThicknessEnum,Helem_list);
+
+		/*Step3: Vertically integrate A COPY of the original*/
+		element_integrated_input=(Input*)original_input->copy();
+		element_integrated_input->VerticallyIntegrate(element_thickness_input);
+
+		/*Add contributions to global inputs*/
+		total_integrated_input->AXPY(element_integrated_input,1.0);
+		total_thickness_input ->AXPY(element_thickness_input,1.0);
+
+		/*Clean up*/
+		delete element_thickness_input;
+		delete element_integrated_input;
+
+		/*Stop if we have reached the surface, else, take upper penta*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement();
+		_assert_(penta->Id()!=this->id);
+
+		/*increase couter*/
+		step++;
+	}
+
+	/*OK, now we only need to divide the depth integrated input by the total thickness!*/
+	depth_averaged_input=total_integrated_input->PointwiseDivide(total_thickness_input);
+	depth_averaged_input->ChangeEnum(average_enum_type);
+
+	/*Clean up*/
+	delete total_thickness_input;
+	delete total_integrated_input;
+
+	/*Finally, add to inputs*/
+	if (object_enum==MeshElementsEnum)
+	 this->inputs->AddInput((Input*)depth_averaged_input);
+	else if (object_enum==MaterialsEnum)
+	 this->material->inputs->AddInput((Input*)depth_averaged_input);
+	else
+	 _error_("object " << EnumToStringx(object_enum) << " not supported yet");
+}
+/*}}}*/
+/*FUNCTION Penta::InputDuplicate{{{*/
+void  Penta::InputDuplicate(int original_enum,int new_enum){
+
+	/*Call inputs method*/
+	if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
+
+}
+/*}}}*/
+/*FUNCTION Penta::InputExtrude {{{*/
+void  Penta::InputExtrude(int enum_type,int object_type){
+
+	int     i,num_inputs;
+	Penta  *penta       = NULL;
+	Input  *copy        = NULL;
+	Input **base_inputs = NULL;
+
+	/*Are we on the base, not on the surface?:*/
+	if(!IsOnBed()) return;
+
+	/*Step1: Get and Extrude original input: */
+	if (object_type==ElementEnum){
+		num_inputs=1;
+		base_inputs=xNew<Input*>(num_inputs);
+		base_inputs[0]=(Input*)this->inputs->GetInput(enum_type);
+	}
+	else if (object_type==MaterialsEnum){
+		num_inputs=1;
+		base_inputs=xNew<Input*>(num_inputs);
+		base_inputs[0]=(Input*)material->inputs->GetInput(enum_type);
+	}
+	else if (object_type==NodeEnum){
+		num_inputs=3; //only the three upper nodes
+		base_inputs=xNew<Input*>(num_inputs);
+		for(i=0;i<num_inputs;i++){
+			base_inputs[i]=(Input*)this->nodes[i]->inputs->GetInput(enum_type);
+		}
+	}
+	else{
+		_error_("object of type " << EnumToStringx(object_type) << " not supported yet");
+	}
+	for(i=0;i<num_inputs;i++){
+		if(!base_inputs[i]) _error_("could not find input with enum " << EnumToStringx(enum_type) << " in object " << EnumToStringx(object_type));
+		base_inputs[i]->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();
+		_assert_(penta->Id()!=this->id);
+
+		/*Add input of the basal element to penta->inputs*/
+		for(i=0;i<num_inputs;i++){
+			copy=(Input*)base_inputs[i]->copy();
+			if (object_type==ElementEnum){
+				penta->inputs->AddInput((Input*)copy);
+			}
+			else if(object_type==MaterialsEnum){
+				penta->material->inputs->AddInput((Input*)copy);
+			}
+			else if(object_type==NodeEnum){
+				penta->nodes[i+3]->inputs->AddInput((Input*)copy); //change only the three upper nodes
+			}
+			else{
+				_error_("object of type " << EnumToStringx(object_type) << " not supported yet");
+			}
+		}
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+	}
+
+	/*clean-up and return*/
+	xDelete<Input*>(base_inputs);
+}
+/*}}}*/
+/*FUNCTION Penta::InputScale{{{*/
+void  Penta::InputScale(int enum_type,IssmDouble scale_factor){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)_error_("could not find old input with enum: " << EnumToStringx(enum_type));
+
+	/*Scale: */
+	input->Scale(scale_factor);
+}
+/*}}}*/
+/*FUNCTION Penta::InputToResult{{{*/
+void  Penta::InputToResult(int enum_type,int step,IssmDouble time){
+
+	bool   found = false;
+	Input *input = NULL;
+
+	/*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
+	if (enum_type==MaterialsRheologyBbarEnum) input=this->material->inputs->GetInput(MaterialsRheologyBEnum);
+	else if (enum_type==MaterialsRheologyZbarEnum) input=this->material->inputs->GetInput(MaterialsRheologyZEnum);
+	else input=this->inputs->GetInput(enum_type);
+	//if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found in penta->inputs"); why error out? if the requested input does not exist, we should still 
+	//try and output whatever we can instead of just failing.
+	if(!input)return;
+
+	/*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));
+	#ifdef _HAVE_CONTROL_
+	if(input->ObjectEnum()==ControlInputEnum){
+		if(((ControlInput*)input)->gradient!=NULL) this->results->AddObject((Object*)((ControlInput*)input)->SpawnGradient(step,time));
+	}
+	#endif
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromConstant(bool value, int name);{{{*/
+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(IssmDouble value, int name);{{{*/
+void  Penta::InputUpdateFromConstant(IssmDouble 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);{{{*/
+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 {{{*/
+void Penta::InputUpdateFromIoModel(int index,IoModel* iomodel){ 
+
+	/*Intermediaries*/
+	IssmInt i,j;
+	int     penta_vertex_ids[6];
+	IssmDouble  nodeinputs[6];
+	IssmDouble  cmmininputs[6];
+	IssmDouble  cmmaxinputs[6];
+
+	IssmDouble  yts;
+	bool    control_analysis;
+	int     num_control_type;
+	int     num_cm_responses;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&yts,ConstantsYtsEnum);
+	iomodel->Constant(&control_analysis,InversionIscontrolEnum);
+	if(control_analysis) iomodel->Constant(&num_control_type,InversionNumControlParametersEnum);
+	if(control_analysis) iomodel->Constant(&num_cm_responses,InversionNumCostFunctionsEnum);
+
+	/*Checks if debuging*/
+	/*{{{*/
+	_assert_(iomodel->Data(MeshElementsEnum));
+	/*}}}*/
+
+	/*Recover vertices ids needed to initialize inputs*/
+	for(i=0;i<6;i++){ 
+		penta_vertex_ids[i]=reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[6*index+i]); //ids for vertices are in the elements array from Matlab
+	}
+
+	/*Control Inputs*/
+	#ifdef _HAVE_CONTROL_
+	if (control_analysis && iomodel->Data(InversionControlParametersEnum)){
+		for(i=0;i<num_control_type;i++){
+			switch(reCast<int,IssmDouble>(iomodel->Data(InversionControlParametersEnum)[i])){
+				case BalancethicknessThickeningRateEnum:
+					if (iomodel->Data(BalancethicknessThickeningRateEnum)){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->Data(BalancethicknessThickeningRateEnum)[penta_vertex_ids[j]-1]/yts;
+						for(j=0;j<6;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i]/yts;
+						for(j=0;j<6;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i]/yts;
+						this->inputs->AddInput(new ControlInput(BalancethicknessThickeningRateEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case VxEnum:
+					if (iomodel->Data(VxEnum)){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->Data(VxEnum)[penta_vertex_ids[j]-1]/yts;
+						for(j=0;j<6;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i]/yts;
+						for(j=0;j<6;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i]/yts;
+						this->inputs->AddInput(new ControlInput(VxEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case VyEnum:
+					if (iomodel->Data(VyEnum)){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->Data(VyEnum)[penta_vertex_ids[j]-1]/yts;
+						for(j=0;j<6;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i]/yts;
+						for(j=0;j<6;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i]/yts;
+						this->inputs->AddInput(new ControlInput(VyEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case FrictionCoefficientEnum:
+					if (iomodel->Data(FrictionCoefficientEnum)){
+						for(j=0;j<6;j++)nodeinputs[j]=iomodel->Data(FrictionCoefficientEnum)[penta_vertex_ids[j]-1];
+						for(j=0;j<6;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i];
+						for(j=0;j<6;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(penta_vertex_ids[j]-1)*num_control_type+i];
+						this->inputs->AddInput(new ControlInput(FrictionCoefficientEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case MaterialsRheologyBbarEnum:
+				case MaterialsRheologyZbarEnum:
+					/*Material will take care of it*/ break;
+				default:
+					_error_("Control " << EnumToStringx(reCast<int,IssmDouble>(iomodel->Data(InversionControlParametersEnum)[i])) << " not implemented yet");
+			}
+		}
+	}
+	#endif
+
+	//Need to know the type of approximation for this element
+	if(iomodel->Data(FlowequationElementEquationEnum)){
+		if (iomodel->Data(FlowequationElementEquationEnum)[index]==MacAyealApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==PattynApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,PattynApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==MacAyealPattynApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealPattynApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==HutterApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,HutterApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==L1L2ApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,L1L2ApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==StokesApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,StokesApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==MacAyealStokesApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,MacAyealStokesApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==PattynStokesApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,PattynStokesApproximationEnum));
+		}
+		else if (iomodel->Data(FlowequationElementEquationEnum)[index]==NoneApproximationEnum){
+			this->inputs->AddInput(new IntInput(ApproximationEnum,NoneApproximationEnum));
+		}
+		else{
+			_error_("Approximation type " << EnumToStringx(reCast<int,IssmDouble>(iomodel->Data(FlowequationElementEquationEnum)[index])) << " not supported yet");
+		}
+	}
+
+	/*DatasetInputs*/
+	if (control_analysis && iomodel->Data(InversionCostFunctionsCoefficientsEnum)) {
+
+		/*Create inputs and add to DataSetInput*/
+		DatasetInput* datasetinput=new DatasetInput(InversionCostFunctionsCoefficientsEnum);
+		for(i=0;i<num_cm_responses;i++){
+			for(j=0;j<6;j++)nodeinputs[j]=iomodel->Data(InversionCostFunctionsCoefficientsEnum)[(penta_vertex_ids[j]-1)*num_cm_responses+i];
+			datasetinput->inputs->AddObject(new PentaP1Input(InversionCostFunctionsCoefficientsEnum,nodeinputs));
+		}
+
+		/*Add datasetinput to element inputs*/
+		this->inputs->AddInput(datasetinput);
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolution {{{*/
+void  Penta::InputUpdateFromSolution(IssmDouble* 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: */
+	switch(analysis_type){
+	#ifdef _HAVE_DIAGNOSTIC_
+	case DiagnosticHorizAnalysisEnum:
+		InputUpdateFromSolutionDiagnosticHoriz( solution);
+		break;
+	case DiagnosticHutterAnalysisEnum:
+		InputUpdateFromSolutionDiagnosticHutter( solution);
+		break;
+	case DiagnosticVertAnalysisEnum:
+		InputUpdateFromSolutionDiagnosticVert( solution);
+		break;
+	#endif
+	#ifdef _HAVE_CONTROL_
+	case AdjointHorizAnalysisEnum:
+		int approximation;
+		inputs->GetInputValue(&approximation,ApproximationEnum);
+		if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
+			InputUpdateFromSolutionAdjointStokes( solution);
+		}
+		else{
+			InputUpdateFromSolutionAdjointHoriz( solution);
+		}
+		break;
+	#endif
+	#ifdef _HAVE_THERMAL_
+	case ThermalAnalysisEnum:
+		InputUpdateFromSolutionThermal( solution);
+		break;
+	case EnthalpyAnalysisEnum:
+		InputUpdateFromSolutionEnthalpy( solution);
+		break;
+	case MeltingAnalysisEnum:
+		InputUpdateFromSolutionOneDof(solution,BasalforcingsMeltingRateEnum);
+		break;
+	#endif
+	case BedSlopeXAnalysisEnum:
+		InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeXEnum);
+		break;
+	case BedSlopeYAnalysisEnum:
+		InputUpdateFromSolutionOneDofCollapsed(solution,BedSlopeYEnum);
+		break;
+	case SurfaceSlopeXAnalysisEnum:
+		InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeXEnum);
+		break;
+	case SurfaceSlopeYAnalysisEnum:
+		InputUpdateFromSolutionOneDofCollapsed(solution,SurfaceSlopeYEnum);
+		break;
+	case PrognosticAnalysisEnum:
+		InputUpdateFromSolutionPrognostic(solution);
+		break;
+	#ifdef _HAVE_BALANCED_
+	case BalancethicknessAnalysisEnum:
+		InputUpdateFromSolutionOneDofCollapsed(solution,ThicknessEnum);
+		break;
+	#endif
+	default: 
+		_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionPrognostic{{{*/
+void  Penta::InputUpdateFromSolutionPrognostic(IssmDouble* solution){
+
+	const int  numdof   = NDOF1*NUMVERTICES;
+	const int  numdof2d = NDOF1*NUMVERTICES2D;
+
+	int    i,hydroadjustment;
+	int*   doflist = NULL;
+	IssmDouble rho_ice,rho_water,minthickness;
+	IssmDouble newthickness[numdof];
+	IssmDouble newbed[numdof];
+	IssmDouble newsurface[numdof];
+	IssmDouble oldbed[NUMVERTICES];
+	IssmDouble oldsurface[NUMVERTICES];
+	IssmDouble oldthickness[NUMVERTICES];
+	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 */
+	this->parameters->FindParam(&minthickness,PrognosticMinThicknessEnum);
+	for(i=0;i<numdof2d;i++){
+		newthickness[i]=solution[doflist[i]];
+		if(xIsNan<IssmDouble>(newthickness[i])) _error_("NaN found in solution vector");
+		/*Constrain thickness to be at least 1m*/
+		if(newthickness[i]<minthickness) newthickness[i]=minthickness;
+		newthickness[i+numdof2d]=newthickness[i];
+	}
+
+	/*Get previous bed, thickness and surface*/
+	GetInputListOnVertices(&oldbed[0],BedEnum);
+	GetInputListOnVertices(&oldsurface[0],SurfaceEnum);
+	GetInputListOnVertices(&oldthickness[0],ThicknessEnum);
+
+	/*Fing PrognosticHydrostaticAdjustment to figure out how to update the geometry:*/
+	this->parameters->FindParam(&hydroadjustment,PrognosticHydrostaticAdjustmentEnum);
+
+	/*recover material parameters: */
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+
+	for(i=0;i<numdof;i++) {
+		/*If shelf: hydrostatic equilibrium*/
+		if (this->nodes[i]->IsGrounded()){
+			newsurface[i]=oldbed[i]+newthickness[i]; //surface = oldbed + newthickness
+			newbed[i]=oldbed[i];               //same bed: do nothing
+		}
+		else{ //so it is an ice shelf
+			if(hydroadjustment==AbsoluteEnum){
+				newsurface[i]=newthickness[i]*(1-rho_ice/rho_water);
+				newbed[i]=newthickness[i]*(-rho_ice/rho_water);
+			}
+			else if(hydroadjustment==IncrementalEnum){
+				newsurface[i]=oldsurface[i]+(1.0-rho_ice/rho_water)*(newthickness[i]-oldthickness[i]); //surface = oldsurface + (1-di) * dH 
+				newbed[i]=oldbed[i]-rho_ice/rho_water*(newthickness[i]-oldthickness[i]); //bed = oldbed + di * dH
+			}
+			else _error_("Hydrostatic adjustment " << hydroadjustment << " (" << EnumToStringx(hydroadjustment) << ") not supported yet");
+		}
+	}
+
+	/*Start looping over all elements above current element and update all inputs*/
+	penta=this;
+	for(;;){
+		/*Add input to the element: */
+		penta->inputs->AddInput(new PentaP1Input(ThicknessEnum,newthickness));
+		penta->inputs->AddInput(new PentaP1Input(SurfaceEnum,newsurface));
+		penta->inputs->AddInput(new PentaP1Input(BedEnum,newbed));
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement(); _assert_(penta->Id()!=this->id);
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionOneDof{{{*/
+void  Penta::InputUpdateFromSolutionOneDof(IssmDouble* solution,int enum_type){
+
+	const int numdof = NDOF1*NUMVERTICES;
+
+	IssmDouble 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]];
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new PentaP1Input(enum_type,values));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionOneDofCollpased{{{*/
+void  Penta::InputUpdateFromSolutionOneDofCollapsed(IssmDouble* solution,int enum_type){
+
+	const int  numdof   = NDOF1*NUMVERTICES;
+	const int  numdof2d = NDOF1*NUMVERTICES2D;
+
+	IssmDouble  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];
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Start looping over all elements above current element and update all inputs*/
+	penta=this;
+	for(;;){
+		/*Add input to the element: */
+		penta->inputs->AddInput(new PentaP1Input(enum_type,values));
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement(); _assert_(penta->Id()!=this->id);
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(IssmDouble* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVector(IssmDouble* 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*/
+				IssmDouble values[6];
+
+				/*Get values on the 6 vertices*/
+				for (int i=0;i<6;i++){
+					values[i]=vector[this->nodes[i]->GetVertexPid()];
+				}
+
+				/*update input*/
+				if (name==MaterialsRheologyZEnum || name==MaterialsRheologyZbarEnum){
+					material->inputs->AddInput(new PentaP1Input(name,values));
+				}
+				else{
+					this->inputs->AddInput(new PentaP1Input(name,values));
+				}
+				return;
+				break;
+			}
+
+		default:
+
+			_error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(int* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVector(int* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(bool* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVector(bool* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnBed{{{*/
+bool Penta::IsOnBed(void){
+
+	bool onbed;
+	inputs->GetInputValue(&onbed,MeshElementonbedEnum);
+	return onbed;
+}
+/*}}}*/
+/*FUNCTION Penta::IsInput{{{*/
+bool Penta::IsInput(int name){
+	if (
+				name==ThicknessEnum ||
+				name==SurfaceEnum ||
+				name==BedEnum ||
+				name==SurfaceSlopeXEnum ||
+				name==SurfaceSlopeYEnum ||
+				name==SurfaceforcingsMassBalanceEnum ||
+				name==BasalforcingsMeltingRateEnum ||
+				name==BasalforcingsGeothermalfluxEnum ||
+				name==SurfaceAreaEnum||
+				name==PressureEnum ||
+				name==VxEnum ||
+				name==VyEnum ||
+				name==VzEnum ||
+				name==VxMeshEnum ||
+				name==VyMeshEnum ||
+				name==VzMeshEnum ||
+				name==InversionVxObsEnum ||
+				name==InversionVyObsEnum ||
+				name==InversionVzObsEnum ||
+				name==TemperatureEnum ||
+				name==EnthalpyEnum ||
+				name==EnthalpyPicardEnum ||
+				name==WaterfractionEnum||
+				name==FrictionCoefficientEnum ||
+				name==GLlevelsetEnum ||
+				name==GradientEnum ||
+				name==OldGradientEnum  ||
+				name==ConvergedEnum || 
+				name==QmuVxEnum ||
+				name==QmuVyEnum ||
+				name==QmuVzEnum ||
+				name==QmuPressureEnum ||
+				name==QmuBedEnum ||
+				name==QmuThicknessEnum ||
+				name==QmuSurfaceEnum ||
+				name==QmuTemperatureEnum ||
+				name==QmuMeltingEnum ||
+				name==GiaWEnum || 
+				name==GiadWdtEnum
+
+				) {
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Penta::IsFloating{{{*/
+bool   Penta::IsFloating(){
+
+	bool onshelf;
+	inputs->GetInputValue(&onshelf,MaskElementonfloatingiceEnum);
+	return onshelf;
+}
+/*}}}*/
+/*FUNCTION Penta::IsNodeOnShelf {{{*/
+bool   Penta::IsNodeOnShelf(){
+
+	int  i;
+	bool shelf=false;
+
+	for(i=0;i<6;i++){
+		if (nodes[i]->IsFloating()){
+			shelf=true;
+			break;
+		}
+	}
+	return shelf;
+}
+/*}}}*/
+/*FUNCTION Penta::IsNodeOnShelfFromFlags {{{*/
+bool   Penta::IsNodeOnShelfFromFlags(IssmDouble* flags){
+
+	int  i;
+	bool shelf=false;
+
+	for(i=0;i<NUMVERTICES;i++){
+		if (reCast<bool,IssmDouble>(flags[nodes[i]->Sid()])){
+			shelf=true;
+			break;
+		}
+	}
+	return shelf;
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnSurface{{{*/
+bool Penta::IsOnSurface(void){
+
+	bool onsurface;
+	inputs->GetInputValue(&onsurface,MeshElementonsurfaceEnum);
+	return onsurface;
+}
+/*}}}*/
+/*FUNCTION Penta::IsOnWater {{{*/
+bool   Penta::IsOnWater(){
+
+	bool onwater;
+	inputs->GetInputValue(&onwater,MaskElementonwaterEnum);
+	return onwater;
+}
+/*}}}*/
+/*FUNCTION Penta::ListResultsInfo{{{*/
+void Penta::ListResultsInfo(int** in_resultsenums,int** in_resultssizes,IssmDouble** in_resultstimes,int** in_resultssteps,int* in_num_results){
+
+	/*Intermediaries*/
+	int     i;
+	int     numberofresults = 0;
+	int     *resultsenums   = NULL;
+	int     *resultssizes   = NULL;
+	IssmDouble  *resultstimes   = NULL;
+	int     *resultssteps   = NULL;
+
+	/*Checks*/
+	_assert_(in_num_results);
+
+	/*Count number of results*/
+	for(i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+		numberofresults++;
+	}
+
+	if(numberofresults){
+
+		/*Allocate output*/
+		resultsenums=xNew<int>(numberofresults);
+		resultssizes=xNew<int>(numberofresults);
+		resultstimes=xNew<IssmDouble>(numberofresults);
+		resultssteps=xNew<int>(numberofresults);
+
+		/*populate enums*/
+		for(i=0;i<this->results->Size();i++){
+			ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+			resultsenums[i]=elementresult->InstanceEnum();
+			resultstimes[i]=elementresult->GetTime();
+			resultssteps[i]=elementresult->GetStep();
+			if(elementresult->ObjectEnum()==PentaP1ElementResultEnum){
+				resultssizes[i]=P1Enum;
+			}
+			else{
+				resultssizes[i]=P0Enum;
+			}
+		}
+	}
+
+	/*Assign output pointers:*/
+	*in_num_results=numberofresults;
+	*in_resultsenums=resultsenums;
+	*in_resultssizes=resultssizes;
+	*in_resultstimes=resultstimes;
+	*in_resultssteps=resultssteps;
+
+}/*}}}*/
+/*FUNCTION Penta::MigrateGroundingLine{{{*/
+void  Penta::MigrateGroundingLine(IssmDouble* old_floating_ice,IssmDouble* sheet_ungrounding){
+
+	int     i,migration_style;
+	bool    floatingelement = false;
+	bool    groundedelement = false;
+	IssmDouble  bed_hydro,yts,gl_melting_rate;
+	IssmDouble  rho_water,rho_ice,density;
+	IssmDouble  melting[NUMVERTICES],phi[NUMVERTICES];
+	IssmDouble  h[NUMVERTICES],s[NUMVERTICES],b[NUMVERTICES],ba[NUMVERTICES];
+
+	if(!IsOnBed()) return;
+
+	/*Recover info at the vertices: */
+	parameters->FindParam(&migration_style,GroundinglineMigrationEnum);
+	parameters->FindParam(&gl_melting_rate,GroundinglineMeltingRateEnum);
+	parameters->FindParam(&yts,ConstantsYtsEnum);
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&s[0],SurfaceEnum);
+	GetInputListOnVertices(&b[0],BedEnum);
+	GetInputListOnVertices(&ba[0],BathymetryEnum);
+	if(migration_style==SubelementMigrationEnum) GetInputListOnVertices(&phi[0],GLlevelsetEnum);
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	density=rho_ice/rho_water;
+
+	/*go through vertices, and update inputs, considering them to be PentaVertex type: */
+	for(i=0;i<NUMVERTICES;i++){
+		/*Ice shelf: if bed below bathymetry, impose it at the bathymetry and update surface, elso do nothing */
+		if(reCast<bool,IssmDouble>(old_floating_ice[nodes[i]->Sid()])){
+			if(b[i]<=ba[i]){ 
+				b[i]=ba[i];
+				s[i]=b[i]+h[i];
+				nodes[i]->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,false));
+				nodes[i]->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,true));
+			}
+		}
+		/*Ice sheet: if hydrostatic bed above bathymetry, ice sheet starts to unground, elso do nothing */
+		/*Change only if AgressiveMigration or if the ice sheet is in contact with the ocean*/
+		else{
+			bed_hydro=-density*h[i];
+			if (bed_hydro>ba[i]){
+				/*Unground only if the element is connected to the ice shelf*/
+				if(migration_style==AgressiveMigrationEnum || migration_style==SubelementMigrationEnum){
+					s[i]=(1-density)*h[i];
+					b[i]=-density*h[i];
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,true));
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,false));
+				}
+				else if(migration_style==SoftMigrationEnum && reCast<int,IssmDouble>(sheet_ungrounding[nodes[i]->Sid()])){
+					s[i]=(1-density)*h[i];
+					b[i]=-density*h[i];
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,true));
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,false));
+				}
+				else{
+					if(migration_style!=SoftMigrationEnum) _error_("Error: migration should be Aggressive, Soft or Subelement");
+				}
+			}
+		}
+	}
+
+	/*SubelementMigrationEnum: if one grounded, all grounded*/
+	if(migration_style==SubelementMigrationEnum){
+		for(i=0;i<NUMVERTICES;i++){
+			if(nodes[i]->IsGrounded()){
+				groundedelement=true;
+				break;
+			}
+		}
+		floatingelement=!groundedelement;
+	}
+	else{
+		for(i=0;i<NUMVERTICES;i++){
+			if(nodes[i]->IsFloating()){
+				floatingelement=true;
+				break;
+			}
+		}
+	}
+
+   /*Add basal melting rate if element just ungrounded*/
+	if(!this->IsFloating() && floatingelement==true){
+		for(i=0;i<NUMVERTICES;i++)melting[i]=gl_melting_rate/yts;
+		this->inputs->AddInput(new PentaP1Input(BasalforcingsMeltingRateEnum,&melting[0]));
+	} 
+
+	/*Update inputs*/
+	this->inputs->AddInput(new PentaP1Input(SurfaceEnum,&s[0]));
+	this->inputs->AddInput(new PentaP1Input(BedEnum,&b[0]));
+   this->inputs->AddInput(new BoolInput(MaskElementonfloatingiceEnum,floatingelement));
+
+	/*Recalculate phi*/
+	if(migration_style==SubelementMigrationEnum){
+		for(i=0;i<NUMVERTICES;i++) phi[i]=h[i]+ba[i]/density;
+		this->inputs->AddInput(new PentaP1Input(GLlevelsetEnum,&phi[0]));
+		this->InputExtrude(GLlevelsetEnum,ElementEnum);
+	}
+
+	/*Extrude inputs*/
+	this->InputExtrude(SurfaceEnum,ElementEnum);
+	this->InputExtrude(BedEnum,ElementEnum);
+	this->InputExtrude(MaskElementonfloatingiceEnum,ElementEnum);
+	this->InputExtrude(MaskVertexonfloatingiceEnum,NodeEnum);
+	this->InputExtrude(MaskVertexongroundediceEnum,NodeEnum);
+}
+/*}}}*/
+/*FUNCTION Penta::MinEdgeLength{{{*/
+IssmDouble Penta::MinEdgeLength(IssmDouble 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
+	IssmDouble length;
+	IssmDouble 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::NodalValue {{{*/
+int    Penta::NodalValue(IssmDouble* pvalue, int index, int natureofdataenum,bool process_units){
+
+	int i;
+	int found=0;
+	IssmDouble value;
+	Input* data=NULL;
+	GaussPenta* gauss=NULL;
+
+	/*First, serarch the input: */
+	data=inputs->GetInput(natureofdataenum); 
+
+	/*figure out if we have the vertex id: */
+	found=0;
+	for(i=0;i<NUMVERTICES;i++){
+		if(index==nodes[i]->GetVertexId()){
+			/*Do we have natureofdataenum in our inputs? :*/
+			if(data){
+				/*ok, we are good. retrieve value of input at vertex :*/
+				gauss=new GaussPenta(); gauss->GaussVertex(i);
+				data->GetInputValue(&value,gauss);
+				found=1;
+				break;
+			}
+		}
+	}
+
+	delete gauss;
+	if(found)*pvalue=value;
+	return found;
+}
+/*}}}*/
+/*FUNCTION Penta::PatchFill{{{*/
+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->sid+1,vertices_ids,6);
+		elementresult->PatchFill(count,patch);
+
+		/*increment counter: */
+		count++;
+	}
+
+	/*Assign output pointers:*/
+	*pcount=count;
+}/*}}}*/
+/*FUNCTION Penta::PatchSize{{{*/
+void  Penta::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
+
+	int     i;
+	int     numrows       = 0;
+	int     numnodes      = 0;
+	int     temp_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? :*/
+		temp_numnodes=elementresult->NumberOfNodalValues(); //ask result object.
+		if(temp_numnodes>numnodes)numnodes=temp_numnodes;
+	}
+
+	/*Assign output pointers:*/
+	*pnumrows=numrows;
+	*pnumvertices=NUMVERTICES;
+	*pnumnodes=numnodes;
+}
+/*}}}*/
+/*FUNCTION Penta::PositiveDegreeDay{{{*/
+void  Penta::PositiveDegreeDay(IssmDouble* pdds,IssmDouble* pds,IssmDouble signorm){
+
+   IssmDouble agd[NUMVERTICES];             // surface mass balance
+   IssmDouble monthlytemperatures[NUMVERTICES][12],monthlyprec[NUMVERTICES][12];
+   IssmDouble h[NUMVERTICES],s[NUMVERTICES]; // ,b
+   IssmDouble rho_water,rho_ice,desfac,s0p;
+
+   /*Recover monthly temperatures and precipitation*/
+   Input*     input=inputs->GetInput(SurfaceforcingsMonthlytemperaturesEnum); _assert_(input);
+   Input*     input2=inputs->GetInput(SurfaceforcingsPrecipitationEnum); _assert_(input2);
+   GaussPenta* gauss=new GaussPenta();
+   IssmDouble time,yts;
+   this->parameters->FindParam(&time,TimeEnum);
+   this->parameters->FindParam(&yts,ConstantsYtsEnum);
+   for(int month=0;month<12;month++) {
+     for(int iv=0;iv<NUMVERTICES;iv++) {
+       gauss->GaussVertex(iv);
+       input->GetInputValue(&monthlytemperatures[iv][month],gauss,time+month/12.*yts);
+       monthlytemperatures[iv][month]=monthlytemperatures[iv][month]-273.15; // conversion from Kelvin to celcius
+       input2->GetInputValue(&monthlyprec[iv][month],gauss,time+month/12.*yts);
+       monthlyprec[iv][month]=monthlyprec[iv][month]*yts; // convertion to m/yr
+     }
+   } 
+
+  /*Recover info at the vertices: */
+  GetInputListOnVertices(&h[0],ThicknessEnum);
+  GetInputListOnVertices(&s[0],SurfaceEnum);
+
+  /*Get material parameters :*/
+  rho_ice=matpar->GetRhoIce();
+  rho_water=matpar->GetRhoFreshwater();
+
+  /*Get desertification effect parameters*/
+  desfac=matpar->GetDesFac();
+  s0p=matpar->GetS0p();
+
+   /*measure the surface mass balance*/
+   for (int iv = 0; iv < NUMVERTICES; iv++){
+     agd[iv]=PddSurfaceMassBlance(&monthlytemperatures[iv][0], &monthlyprec[iv][0], pdds, pds, 
+				  signorm, yts, h[iv], s[iv], rho_ice, rho_water, desfac, s0p);
+     //printf("mass balance %f \n",agd[iv]);
+   }
+
+   /*Update inputs*/    
+   this->inputs->AddInput(new PentaP1Input(SurfaceforcingsMassBalanceEnum,&agd[0]));
+   //this->inputs->AddInput(new PentaVertexInput(ThermalSpcTemperatureEnum,&Tsurf[0]));
+   this->InputExtrude(SurfaceforcingsMassBalanceEnum,ElementEnum);
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::PotentialUngrounding{{{*/
+void  Penta::PotentialUngrounding(Vector<IssmDouble>* potential_ungrounding){
+
+	int     i;
+	IssmDouble  h[NUMVERTICES],ba[NUMVERTICES];
+	IssmDouble  bed_hydro;
+	IssmDouble  rho_water,rho_ice,density;
+
+	/*material parameters: */
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	density=rho_ice/rho_water;
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&ba[0],BathymetryEnum);
+
+	/*go through vertices, and figure out which ones are on the ice sheet, and want to unground: */
+	for(i=0;i<NUMVERTICES;i++){
+		/*Find if grounded vertices want to start floating*/
+		if (!nodes[i]->IsFloating()){
+			bed_hydro=-density*h[i];
+			if (bed_hydro>ba[i]){
+				/*Vertex that could potentially unground, flag it*/
+				potential_ungrounding->SetValue(nodes[i]->Sid(),1,INS_VAL);
+			}
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::ProcessResultsUnits{{{*/
+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 {{{*/
+void Penta::ReduceMatrixStokes(IssmDouble* Ke_reduced, IssmDouble* Ke_temp){
+
+	int    i,j;
+	IssmDouble Kii[24][24];
+	IssmDouble Kib[24][3];
+	IssmDouble Kbb[3][3];
+	IssmDouble Kbi[3][24];
+	IssmDouble Kbbinv[3][3];
+	IssmDouble 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 {{{*/
+void Penta::ReduceVectorStokes(IssmDouble* Pe_reduced, IssmDouble* Ke_temp, IssmDouble* Pe_temp){
+
+	int    i,j;
+	IssmDouble Pi[24];
+	IssmDouble Pb[3];
+	IssmDouble Kbb[3][3];
+	IssmDouble Kib[24][3];
+	IssmDouble Kbbinv[3][3];
+	IssmDouble 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::RequestedOutput{{{*/
+void Penta::RequestedOutput(int output_enum,int step,IssmDouble time){
+	if(IsInput(output_enum)){
+		/*just transfer this input to results, and we are done: */
+		InputToResult(output_enum,step,time);
+	}
+	else{
+		/*this input does not exist, compute it, and then transfer to results: */
+		switch(output_enum){
+			case BasalFrictionEnum:
+
+				/*create input: */
+				BasalFrictionCreateInput();
+
+				/*transfer to results :*/
+				InputToResult(output_enum,step,time);
+
+				/*erase input: */
+				inputs->DeleteInput(output_enum);
+				break;
+			case ViscousHeatingEnum:
+
+				/*create input: */
+				ViscousHeatingCreateInput();
+
+				/*transfer to results :*/
+				InputToResult(output_enum,step,time);
+
+				/*erase input: */
+				inputs->DeleteInput(output_enum);
+				break;
+
+			case StressTensorEnum: 
+				this->ComputeStressTensor();
+				InputToResult(StressTensorxxEnum,step,time);
+				InputToResult(StressTensorxyEnum,step,time);
+				InputToResult(StressTensorxzEnum,step,time);
+				InputToResult(StressTensoryyEnum,step,time);
+				InputToResult(StressTensoryzEnum,step,time);
+				InputToResult(StressTensorzzEnum,step,time);
+				break;
+
+			default:
+				/*do nothing, no need to derail the computation because one of the outputs requested cannot be found: */
+				break;
+		}
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::ResetCoordinateSystem{{{*/
+void  Penta::ResetCoordinateSystem(void){
+
+	int    approximation;
+	IssmDouble slopex[NUMVERTICES];
+	IssmDouble slopey[NUMVERTICES];
+	IssmDouble xz_plane[6];
+
+	/*For Stokes only: we want the CS to be tangential to the bedrock*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(IsFloating() || !IsOnBed() || (approximation!=StokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum &&  approximation!=PattynStokesApproximationEnum)) return;
+
+	/*Get slope on each node*/
+	GetInputListOnVertices(&slopex[0],BedSlopeXEnum);
+	GetInputListOnVertices(&slopey[0],BedSlopeYEnum);
+
+	/*Loop over basal nodes (first 3) and update their CS*/
+	for(int i=0;i<NUMVERTICES2D;i++){
+
+		/*New X axis             New Z axis*/
+		xz_plane[0]=1.;          xz_plane[3]=-slopex[i];  
+		xz_plane[1]=0.;          xz_plane[4]=-slopey[i];  
+		xz_plane[2]=slopex[i];   xz_plane[5]=1.;          
+
+		XZvectorsToCoordinateSystem(&this->nodes[i]->coord_system[0][0],&xz_plane[0]);
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SetClone {{{*/
+void  Penta::SetClone(int* minranks){
+
+	_error_("not implemented yet");
+}
+/*}}}*/
+/*FUNCTION Penta::SetCurrentConfiguration {{{*/
+void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, Nodes* 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::SetwiseNodeConnectivity{{{*/
+void Penta::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	/*Loop over all nodes*/
+	for(int i=0;i<6;i++){
+
+		if(!flags[this->nodes[i]->Sid()]){
+
+			/*flag current node so that no other element processes it*/
+			flags[this->nodes[i]->Sid()]=true;
+
+			/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+			switch(set2_enum){
+				case FsetEnum:
+					if(nodes[i]->indexing.fsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case GsetEnum:
+					if(nodes[i]->indexing.gsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case SsetEnum:
+					if(nodes[i]->indexing.ssize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				default: _error_("not supported");
+			}
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+/*FUNCTION Penta::SpawnTria {{{*/
+Tria*  Penta::SpawnTria(int g0, int g1, int g2){
+
+	int   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 material*/
+	tria->material=NULL;
+	tria->material=(Material*)this->material->copy();
+	delete tria->material->inputs;
+	tria->material->inputs=(Inputs*)this->material->inputs->SpawnTriaInputs(indices);
+
+	/*recover nodes, material and matpar: */
+	tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
+	tria->vertices=(Vertex**)tria->hvertices->deliverp();
+	tria->matpar=(Matpar*)tria->hmatpar->delivers();
+
+	return tria;
+}
+/*}}}*/
+/*FUNCTION Penta::SmbGradients{{{*/
+void Penta::SmbGradients(void){
+
+	int i;
+
+	// input
+   IssmDouble h[NUMVERTICES];					// ice thickness (m)		
+	IssmDouble s[NUMVERTICES];					// surface elevation (m)
+	IssmDouble b_pos[NUMVERTICES];				// Hs-SMB relation parameter
+	IssmDouble b_neg[NUMVERTICES];				// Hs-SMB relation paremeter
+	IssmDouble Href[NUMVERTICES];					// reference elevation from which deviations are used to calculate the SMB adjustment
+	IssmDouble Smbref[NUMVERTICES];				// reference SMB to which deviations are added
+   IssmDouble rho_water;                   // density of fresh water
+	IssmDouble rho_ice;                     // density of ice
+
+	// output
+	IssmDouble smb[NUMVERTICES];					// surface mass balance (m/yr ice)
+
+	/*Recover SmbGradients*/
+	GetInputListOnVertices(&Href[0],SurfaceforcingsHrefEnum);
+	GetInputListOnVertices(&Smbref[0],SurfaceforcingsSmbrefEnum);
+	GetInputListOnVertices(&b_pos[0],SurfaceforcingsBPosEnum);
+	GetInputListOnVertices(&b_neg[0],SurfaceforcingsBNegEnum);
+
+   /*Recover surface elevatio at vertices: */
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&s[0],SurfaceEnum);
+
+   /*Get material parameters :*/
+   rho_ice=matpar->GetRhoIce();
+   rho_water=matpar->GetRhoFreshwater();
+
+   // loop over all vertices
+ for(i=0;i<NUMVERTICES;i++){
+     if(Smbref[i]>0){
+		  smb[i]=Smbref[i]+b_pos[i]*(s[i]-Href[i]);
+	  }
+	  else{
+		  smb[i]=Smbref[i]+b_neg[i]*(s[i]-Href[i]);
+	  }
+	  smb[i]=smb[i]/rho_ice;      // SMB in m/y ice		
+	}  //end of the loop over the vertices
+	  /*Update inputs*/
+	  this->inputs->AddInput(new PentaP1Input(SurfaceforcingsMassBalanceEnum,&smb[0]));
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceArea {{{*/
+IssmDouble Penta::SurfaceArea(void){
+
+	int    approximation;
+	IssmDouble S;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&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); //nodes 0, 1 and 2 make the new tria (lower face).
+		S=tria->SurfaceArea();
+		delete tria->material; delete tria;
+		return S;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+		S=tria->SurfaceArea();
+		delete tria->material; delete tria;
+		return S;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceNormal {{{*/
+void Penta::SurfaceNormal(IssmDouble* surface_normal, IssmDouble xyz_list[3][3]){
+
+	int    i;
+	IssmDouble v13[3],v23[3];
+	IssmDouble normal[3];
+	IssmDouble 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::TimeAdapt{{{*/
+IssmDouble  Penta::TimeAdapt(void){
+
+	int    i;
+	IssmDouble C,dx,dy,dz,dt;
+	IssmDouble maxabsvx,maxabsvy,maxabsvz;
+	IssmDouble maxx,minx,maxy,miny,maxz,minz;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	/*get CFL coefficient:*/
+	this->parameters->FindParam(&C,TimesteppingCflCoefficientEnum);
+
+	/*Get for Vx and Vy, the max of abs value: */
+	this->MaxAbsVx(&maxabsvx,false);
+	this->MaxAbsVy(&maxabsvy,false);
+	this->MaxAbsVz(&maxabsvz,false);
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	minx=xyz_list[0][0];
+	maxx=xyz_list[0][0];
+	miny=xyz_list[0][1];
+	maxy=xyz_list[0][1];
+	minz=xyz_list[0][2];
+	maxz=xyz_list[0][2];
+
+	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];
+		if (xyz_list[i][2]<minz)minz=xyz_list[i][2];
+		if (xyz_list[i][2]>maxz)maxz=xyz_list[i][2];
+	}
+	dx=maxx-minx;
+	dy=maxy-miny;
+	dz=maxz-minz;
+
+	/*CFL criterion: */
+	dt=C/(maxabsvy/dx+maxabsvy/dy+maxabsvz/dz);
+
+	return dt;
+}/*}}}*/
+/*FUNCTION Penta::Update(int index,IoModel* iomodel,int analysis_counter,int analysis_type) {{{*/
+void Penta::Update(int index,IoModel* iomodel,int analysis_counter,int analysis_type){ 
+
+	/*Intermediaries*/
+	int        i;
+	int        penta_type;
+	int        penta_node_ids[6];
+	int        penta_vertex_ids[6];
+	IssmDouble nodeinputs[6];
+	IssmDouble yts;
+	int        stabilization;
+	bool       dakota_analysis;
+	bool       isstokes;
+	IssmDouble beta,heatcapacity,referencetemperature,meltingpoint,latentheat;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&yts,ConstantsYtsEnum);
+	iomodel->Constant(&stabilization,PrognosticStabilizationEnum);
+	iomodel->Constant(&dakota_analysis,QmuIsdakotaEnum);
+	iomodel->Constant(&isstokes,FlowequationIsstokesEnum);
+	iomodel->Constant(&beta,MaterialsBetaEnum);
+	iomodel->Constant(&heatcapacity,MaterialsHeatcapacityEnum);
+	iomodel->Constant(&referencetemperature,ConstantsReferencetemperatureEnum);
+	iomodel->Constant(&meltingpoint,MaterialsMeltingpointEnum);
+	iomodel->Constant(&latentheat,MaterialsLatentheatEnum);
+
+	/*Checks if debuging*/
+	/*{{{*/
+	_assert_(iomodel->Data(MeshElementsEnum));
+	/*}}}*/
+
+	/*Recover element type*/
+	if ((analysis_type==PrognosticAnalysisEnum || analysis_type==BalancethicknessAnalysisEnum) && stabilization==3){
+		/*P1 Discontinuous Galerkin*/
+		penta_type=P1DGEnum;
+	}
+	else{
+		/*P1 Continuous Galerkin*/
+		penta_type=P1Enum;
+	}
+	this->SetElementType(penta_type,analysis_counter);
+
+	/*Recover vertices ids needed to initialize inputs*/
+	for(i=0;i<6;i++) penta_vertex_ids[i]=reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[6*index+i]); //ids for vertices are in the elements array from Matlab
+
+	/*Recover nodes ids needed to initialize the node hook.*/
+	for(i=0;i<6;i++){ 
+		//go recover node ids, needed to initialize the node hook.
+		//WARNING: We assume P1 elements here!!!!!
+		penta_node_ids[i]=iomodel->nodecounter+reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[6*index+i]); //ids for vertices are in the elements array from Matlab
+	}
+
+	/*hooks: */
+	this->SetHookNodes(penta_node_ids,analysis_counter); this->nodes=NULL; //set hook to nodes, for this analysis type
+
+	/*Fill with IoModel*/
+	this->InputUpdateFromIoModel(index,iomodel);
+
+	/*Defaults if not provided in iomodel*/
+	switch(analysis_type){
+
+		case DiagnosticHorizAnalysisEnum:
+
+			/*default vx,vy and vz: either observation or 0 */
+			if(!iomodel->Data(VxEnum)){
+				for(i=0;i<6;i++)nodeinputs[i]=0;
+				this->inputs->AddInput(new PentaP1Input(VxEnum,nodeinputs));
+				if(dakota_analysis) this->inputs->AddInput(new PentaP1Input(QmuVxEnum,nodeinputs));
+			}
+			if(!iomodel->Data(VyEnum)){
+				for(i=0;i<6;i++)nodeinputs[i]=0;
+				this->inputs->AddInput(new PentaP1Input(VyEnum,nodeinputs));
+				if(dakota_analysis) this->inputs->AddInput(new PentaP1Input(QmuVyEnum,nodeinputs));
+			}
+			if(!iomodel->Data(VzEnum)){
+				for(i=0;i<6;i++)nodeinputs[i]=0;
+				this->inputs->AddInput(new PentaP1Input(VzEnum,nodeinputs));
+				if(dakota_analysis) this->inputs->AddInput(new PentaP1Input(QmuVzEnum,nodeinputs));
+			}
+			if(!iomodel->Data(PressureEnum)){
+				for(i=0;i<6;i++)nodeinputs[i]=0;
+				if(dakota_analysis){
+					this->inputs->AddInput(new PentaP1Input(PressureEnum,nodeinputs));
+					this->inputs->AddInput(new PentaP1Input(QmuPressureEnum,nodeinputs));
+				}
+				if(isstokes){
+					this->inputs->AddInput(new PentaP1Input(PressureEnum,nodeinputs));
+					this->inputs->AddInput(new PentaP1Input(PressurePicardEnum,nodeinputs));
+				}
+			}
+			if(*(iomodel->Data(FlowequationElementEquationEnum)+index)==PattynStokesApproximationEnum){
+				/*Create VzPattyn and VzStokes Enums*/
+				if(iomodel->Data(VzEnum) && iomodel->Data(FlowequationBorderstokesEnum)){
+					for(i=0;i<6;i++) nodeinputs[i]=iomodel->Data(VzEnum)[penta_vertex_ids[i]-1]/yts*iomodel->Data(FlowequationBorderstokesEnum)[penta_vertex_ids[i]-1];
+					this->inputs->AddInput(new PentaP1Input(VzStokesEnum,nodeinputs));
+					for(i=0;i<6;i++) nodeinputs[i]=iomodel->Data(VzEnum)[penta_vertex_ids[i]-1]/yts*(1-iomodel->Data(FlowequationBorderstokesEnum)[penta_vertex_ids[i]-1]);
+					this->inputs->AddInput(new PentaP1Input(VzPattynEnum,nodeinputs));
+				}
+				else{
+					for(i=0;i<6;i++)nodeinputs[i]=0;
+					this->inputs->AddInput(new PentaP1Input(VzStokesEnum,nodeinputs));
+					this->inputs->AddInput(new PentaP1Input(VzPattynEnum,nodeinputs));
+				}
+			}
+			if(*(iomodel->Data(FlowequationElementEquationEnum)+index)==MacAyealStokesApproximationEnum){
+				/*Create VzMacAyeal and VzStokes Enums*/
+				if(iomodel->Data(VzEnum) && iomodel->Data(FlowequationBorderstokesEnum)){
+					for(i=0;i<6;i++) nodeinputs[i]=iomodel->Data(VzEnum)[penta_vertex_ids[i]-1]/yts*iomodel->Data(FlowequationBorderstokesEnum)[penta_vertex_ids[i]-1];
+					this->inputs->AddInput(new PentaP1Input(VzStokesEnum,nodeinputs));
+					for(i=0;i<6;i++) nodeinputs[i]=iomodel->Data(VzEnum)[penta_vertex_ids[i]-1]/yts*(1-iomodel->Data(FlowequationBorderstokesEnum)[penta_vertex_ids[i]-1]);
+					this->inputs->AddInput(new PentaP1Input(VzMacAyealEnum,nodeinputs));
+				}
+				else{
+					for(i=0;i<6;i++)nodeinputs[i]=0;
+					this->inputs->AddInput(new PentaP1Input(VzStokesEnum,nodeinputs));
+					this->inputs->AddInput(new PentaP1Input(VzMacAyealEnum,nodeinputs));
+				}
+			}
+			break;
+
+		case ThermalAnalysisEnum:
+			/*Initialize mesh velocity*/
+			for(i=0;i<6;i++)nodeinputs[i]=0;
+			this->inputs->AddInput(new PentaP1Input(VxMeshEnum,nodeinputs));
+			this->inputs->AddInput(new PentaP1Input(VyMeshEnum,nodeinputs));
+			this->inputs->AddInput(new PentaP1Input(VzMeshEnum,nodeinputs));
+			break;
+
+		case EnthalpyAnalysisEnum:
+			/*Initialize mesh velocity*/
+			for(i=0;i<6;i++)nodeinputs[i]=0;
+			this->inputs->AddInput(new PentaP1Input(VxMeshEnum,nodeinputs));
+			this->inputs->AddInput(new PentaP1Input(VyMeshEnum,nodeinputs));
+			this->inputs->AddInput(new PentaP1Input(VzMeshEnum,nodeinputs));
+			if (iomodel->Data(TemperatureEnum) && iomodel->Data(WaterfractionEnum) && iomodel->Data(PressureEnum)) {
+				for(i=0;i<6;i++){
+					if(iomodel->Data(TemperatureEnum)[penta_vertex_ids[i]-1] < meltingpoint-beta*iomodel->Data(PressureEnum)[penta_vertex_ids[i]-1]){
+						nodeinputs[i]=heatcapacity*(iomodel->Data(TemperatureEnum)[penta_vertex_ids[i]-1]-referencetemperature);
+					}
+					else nodeinputs[i]=heatcapacity*
+					 (meltingpoint-beta*iomodel->Data(PressureEnum)[penta_vertex_ids[i]-1]-referencetemperature)
+						+latentheat*iomodel->Data(WaterfractionEnum)[penta_vertex_ids[i]-1];
+				}
+				this->inputs->AddInput(new PentaP1Input(EnthalpyEnum,nodeinputs));
+			}
+			else _error_("temperature and waterfraction required for the enthalpy solution");
+			break;
+
+		default:
+			/*No update for other solution types*/
+			break;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::UpdatePotentialUngrounding{{{*/
+int Penta::UpdatePotentialUngrounding(IssmDouble* vertices_potentially_ungrounding,Vector<IssmDouble>* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf){
+
+	int i;
+	int nflipped=0;
+
+	/*Go through nodes, and whoever is on the potential_ungrounding, ends up in nodes_on_iceshelf: */
+	for(i=0;i<NUMVERTICES;i++){
+		if (reCast<bool,IssmDouble>(vertices_potentially_ungrounding[nodes[i]->Sid()])){
+			vec_nodes_on_iceshelf->SetValue(nodes[i]->Sid(),1,INS_VAL);
+
+			/*If node was not on ice shelf, we flipped*/
+			if(nodes_on_iceshelf[nodes[i]->Sid()]==0){
+				nflipped++;
+			}
+		}
+	}
+	return nflipped;
+}
+/*}}}*/
+/*FUNCTION Penta::ViscousHeatingCreateInput {{{*/
+void Penta::ViscousHeatingCreateInput(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries*/
+	IssmDouble phi;
+	IssmDouble viscosity;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble epsilon[6];
+	IssmDouble viscousheating[NUMVERTICES]={0,0,0,0,0,0};
+	IssmDouble thickness;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); _assert_(vz_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+
+	/*loop over vertices: */
+	gauss=new GaussPenta();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+
+		thickness_input->GetInputValue(&thickness,gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		GetPhi(&phi, &epsilon[0], viscosity);
+
+		viscousheating[iv]=phi*thickness;
+	}
+
+	/*Create PentaVertex input, which will hold the basal friction:*/
+	this->inputs->AddInput(new PentaP1Input(ViscousHeatingEnum,&viscousheating[0]));
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::SmearFunction {{{*/
+void  Penta::SmearFunction(Vector<IssmDouble>* smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius){
+	_error_("not implemented yet");
+}
+/*}}}*/
+
+#ifdef _HAVE_RESPONSES_
+/*FUNCTION Penta::IceVolume {{{*/
+IssmDouble Penta::IceVolume(void){
+
+	/*The volume of a troncated prism is base * 1/3 sum(length of edges)*/
+	IssmDouble base,height;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	if(IsOnWater())return 0;
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*First calculate the area of the base (cross section triangle)
+	 * http://en.wikipedia.org/wiki/Pentangle
+	 * base = 1/2 abs((xA-xC)(yB-yA)-(xA-xB)(yC-yA))*/
+	base = 1./2.*fabs((xyz_list[0][0]-xyz_list[2][0])*(xyz_list[1][1]-xyz_list[0][1]) - (xyz_list[0][0]-xyz_list[1][0])*(xyz_list[2][1]-xyz_list[0][1]));
+
+	/*Now get the average height*/
+	height = 1./3.*((xyz_list[3][2]-xyz_list[0][2])+(xyz_list[4][2]-xyz_list[1][2])+(xyz_list[5][2]-xyz_list[2][2]));
+
+	/*Return: */
+	return base*height;
+}
+/*}}}*/
+/*FUNCTION Penta::MinVel{{{*/
+void  Penta::MinVel(IssmDouble* pminvel, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvel=this->inputs->Min(VelEnum);
+
+	/*process units if requested: */
+	if(process_units) minvel=UnitConversion(minvel,IuToExtEnum,VelEnum);
+
+	/*Assign output pointers:*/
+	*pminvel=minvel;
+}
+/*}}}*/
+/*FUNCTION Penta::MinVx{{{*/
+void  Penta::MinVx(IssmDouble* pminvx, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvx=this->inputs->Min(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) minvx=UnitConversion(minvx,IuToExtEnum,VxEnum);
+
+	/*Assign output pointers:*/
+	*pminvx=minvx;
+}
+/*}}}*/
+/*FUNCTION Penta::MinVy{{{*/
+void  Penta::MinVy(IssmDouble* pminvy, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvy=this->inputs->Min(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) minvy=UnitConversion(minvy,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pminvy=minvy;
+}
+/*}}}*/
+/*FUNCTION Penta::MinVz{{{*/
+void  Penta::MinVz(IssmDouble* pminvz, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvz=this->inputs->Min(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) minvz=UnitConversion(minvz,IuToExtEnum,VzEnum);
+
+	/*Assign output pointers:*/
+	*pminvz=minvz;
+}
+/*}}}*/
+/*FUNCTION Penta::MassFlux {{{*/
+IssmDouble Penta::MassFlux( IssmDouble* segment,bool process_units){
+
+	IssmDouble mass_flux=0;
+
+	if(!IsOnBed()) return mass_flux;
+
+	/*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); //nodes 0, 1 and 2 make the new tria.
+	mass_flux=tria->MassFlux(segment,process_units);
+	delete tria->material; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return mass_flux;
+}
+/*}}}*/
+/*FUNCTION Penta::MaxAbsVx{{{*/
+void  Penta::MaxAbsVx(IssmDouble* pmaxabsvx, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxabsvx=this->inputs->MaxAbs(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvx=UnitConversion(maxabsvx,IuToExtEnum,VxEnum);
+
+	/*Assign output pointers:*/
+	*pmaxabsvx=maxabsvx;
+}
+/*}}}*/
+/*FUNCTION Penta::MaxAbsVy{{{*/
+void  Penta::MaxAbsVy(IssmDouble* pmaxabsvy, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxabsvy=this->inputs->MaxAbs(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvy=UnitConversion(maxabsvy,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pmaxabsvy=maxabsvy;
+}
+/*}}}*/
+/*FUNCTION Penta::MaxAbsVz{{{*/
+void  Penta::MaxAbsVz(IssmDouble* pmaxabsvz, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxabsvz=this->inputs->MaxAbs(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvz=UnitConversion(maxabsvz,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pmaxabsvz=maxabsvz;
+}
+/*}}}*/
+/*FUNCTION Penta::MaxVel{{{*/
+void  Penta::MaxVel(IssmDouble* pmaxvel, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvel=this->inputs->Max(VelEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvel=UnitConversion(maxvel,IuToExtEnum,VelEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvel=maxvel;
+
+}
+/*}}}*/
+/*FUNCTION Penta::MaxVx{{{*/
+void  Penta::MaxVx(IssmDouble* pmaxvx, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvx=this->inputs->Max(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvx=UnitConversion(maxvx,IuToExtEnum,VxEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvx=maxvx;
+}
+/*}}}*/
+/*FUNCTION Penta::MaxVy{{{*/
+void  Penta::MaxVy(IssmDouble* pmaxvy, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvy=this->inputs->Max(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvy=UnitConversion(maxvy,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvy=maxvy;
+}
+/*}}}*/
+/*FUNCTION Penta::MaxVz{{{*/
+void  Penta::MaxVz(IssmDouble* pmaxvz, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvz=this->inputs->Max(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvz=UnitConversion(maxvz,IuToExtEnum,VzEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvz=maxvz;
+}
+/*}}}*/
+/*FUNCTION Penta::ElementResponse{{{*/
+void Penta::ElementResponse(IssmDouble* presponse,int response_enum,bool process_units){
+
+	switch(response_enum){
+		case MaterialsRheologyBbarEnum:
+			*presponse=this->material->GetBbar();
+			break;
+		case MaterialsRheologyZbarEnum:
+			*presponse=this->material->GetZbar();
+			break;
+		case VelEnum:
+			{
+
+				/*Get input:*/
+				IssmDouble vel;
+				Input* vel_input;
+
+				vel_input=this->inputs->GetInput(VelEnum); _assert_(vel_input);
+				vel_input->GetInputAverage(&vel);
+
+				/*process units if requested: */
+				if(process_units) vel=UnitConversion(vel,IuToExtEnum,VelEnum);
+
+				/*Assign output pointers:*/
+				*presponse=vel;
+			}
+			break;
+		default:  
+			_error_("Response type " << EnumToStringx(response_enum) << " not supported yet!");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::TotalSmb {{{*/
+IssmDouble Penta::TotalSmb(void){
+
+	/*The smb[Gt yr-1] of one element is area[m2] * smb [ m ice yr^-1] * rho_ice [kg m-3] / 1e+10^12 */
+	IssmDouble base,smb,rho_ice;
+	IssmDouble Total_Smb=0;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	/*Get material parameters :*/
+	rho_ice=matpar->GetRhoIce();
+
+	if(IsOnWater() || !IsOnSurface()) return 0.;
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*First calculate the area of the base (cross section triangle)
+	 * http://en.wikipedia.org/wiki/Triangle
+	 * base = 1/2 abs((xA-xC)(yB-yA)-(xA-xB)(yC-yA))*/
+	base = 1./2. * fabs((xyz_list[0][0]-xyz_list[2][0])*(xyz_list[1][1]-xyz_list[0][1]) - (xyz_list[0][0]-xyz_list[1][0])*(xyz_list[2][1]-xyz_list[0][1]));
+
+	/*Now get the average SMB over the element*/
+	Input* smb_input = inputs->GetInput(SurfaceforcingsMassBalanceEnum); _assert_(smb_input);
+
+	smb_input->GetInputAverage(&smb);
+	Total_Smb=rho_ice*base*smb;// smb on element in kg s-1
+
+	/*Process units: */
+	Total_Smb=UnitConversion(Total_Smb,IuToExtEnum,TotalSmbEnum);// smb on element in GigaTon yr-1
+
+	/*Return: */
+	return Total_Smb;
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_GIA_
+/*FUNCTION Penta::GiaDeflection {{{*/
+void Penta::GiaDeflection(Vector<IssmDouble>* wg,Vector<IssmDouble>* dwgdt,IssmDouble* x,IssmDouble* y){
+	_error_("GIA deflection not implemented yet!");
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_THERMAL_
+/*FUNCTION Penta::CreateKMatrixEnthalpy {{{*/
+ElementMatrix* Penta::CreateKMatrixEnthalpy(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixEnthalpyVolume();
+	ElementMatrix* Ke2=CreateKMatrixEnthalpyShelf();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixEnthalpyVolume {{{*/
+ElementMatrix* Penta::CreateKMatrixEnthalpyVolume(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        stabilization;
+	int        i,j,found=0;
+	IssmDouble Jdet,u,v,w,um,vm,wm;
+	IssmDouble h,hx,hy,hz,vx,vy,vz,vel;
+	IssmDouble gravity,rho_ice,rho_water;
+	IssmDouble epsvel=2.220446049250313e-16;
+	IssmDouble heatcapacity,thermalconductivity,dt;
+	IssmDouble pressure,enthalpy;
+	IssmDouble latentheat,kappa;
+	IssmDouble tau_parameter,diameter;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble B_conduct[3][numdof];
+	IssmDouble B_advec[3][numdof];
+	IssmDouble Bprime_advec[3][numdof];
+	IssmDouble L[numdof];
+	IssmDouble dbasis[3][6];
+	IssmDouble D_scalar_conduct,D_scalar_advec;
+	IssmDouble D_scalar_trans,D_scalar_stab;
+	IssmDouble D[3][3];
+	IssmDouble K[3][3]={0.0};
+	Tria*      tria=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	heatcapacity=matpar->GetHeatCapacity();
+	latentheat=matpar->GetLatentHeat();
+	thermalconductivity=matpar->GetThermalConductivity();
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&stabilization,ThermalStabilizationEnum);
+	Input* pressure_input=inputs->GetInput(PressureEnum);      _assert_(pressure_input);
+	Input* enthalpy_input=inputs->GetInput(EnthalpyPicardEnum);_assert_(enthalpy_input); //for this iteration of the step
+	Input* vx_input=inputs->GetInput(VxEnum);                  _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                  _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                  _assert_(vz_input);
+	Input* vxm_input=inputs->GetInput(VxMeshEnum);             _assert_(vxm_input);
+	Input* vym_input=inputs->GetInput(VyMeshEnum);             _assert_(vym_input);
+	Input* vzm_input=inputs->GetInput(VzMeshEnum);             _assert_(vzm_input);
+	if (stabilization==2) diameter=MinEdgeLength(xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Conduction: */  
+		/*Need to change that depending on enthalpy value -> cold or temperate ice: */  
+		GetBConduct(&B_conduct[0][0],&xyz_list[0][0],gauss); 
+
+		enthalpy_input->GetInputValue(&enthalpy, gauss);
+		pressure_input->GetInputValue(&pressure, gauss);
+		kappa=matpar->GetEnthalpyDiffusionParameter(enthalpy,pressure);
+		D_scalar_conduct=gauss->weight*Jdet*kappa;
+		if(reCast<bool,IssmDouble>(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->values[0],1);
+
+		/*Advection: */
+		GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss); 
+
+		vx_input->GetInputValue(&u, gauss); vxm_input->GetInputValue(&um,gauss); vx=u-um; 
+		vy_input->GetInputValue(&v, gauss); vym_input->GetInputValue(&vm,gauss); vy=v-vm; 
+		vz_input->GetInputValue(&w, gauss); vzm_input->GetInputValue(&wm,gauss); vz=w-wm;
+
+		D_scalar_advec=gauss->weight*Jdet;
+		if(reCast<bool,IssmDouble>(dt)) D_scalar_advec=D_scalar_advec*dt;
+
+		D[0][0]=D_scalar_advec*vx;D[0][1]=0;                D[0][2]=0;
+		D[1][0]=0;                D[1][1]=D_scalar_advec*vy;D[1][2]=0;
+		D[2][0]=0;                D[2][1]=0;                D[2][2]=D_scalar_advec*vz;
+
+		TripleMultiply(&B_advec[0][0],3,numdof,1,
+					&D[0][0],3,3,0,
+					&Bprime_advec[0][0],3,numdof,0,
+					&Ke->values[0],1);
+
+		/*Transient: */
+		if(reCast<bool,IssmDouble>(dt)){
+			GetNodalFunctionsP1(&L[0], gauss);
+			D_scalar_trans=gauss->weight*Jdet;
+
+			TripleMultiply(&L[0],numdof,1,0,
+						&D_scalar_trans,1,1,0,
+						&L[0],1,numdof,0,
+						&Ke->values[0],1);
+		}
+
+		/*Artifficial diffusivity*/
+		if(stabilization==1){
+			/*Build K: */
+			GetElementSizes(&hx,&hy,&hz);
+			vel=sqrt(pow(vx,2.)+pow(vy,2.)+pow(vz,2.))+1.e-14;
+			h=sqrt( pow(hx*vx/vel,2.) + pow(hy*vy/vel,2.) + pow(hz*vz/vel,2.));
+			K[0][0]=h/(2*vel)*vx*vx;  K[0][1]=h/(2*vel)*vx*vy; K[0][2]=h/(2*vel)*vx*vz;
+			K[1][0]=h/(2*vel)*vy*vx;  K[1][1]=h/(2*vel)*vy*vy; K[1][2]=h/(2*vel)*vy*vz;
+			K[2][0]=h/(2*vel)*vz*vx;  K[2][1]=h/(2*vel)*vz*vy; K[2][2]=h/(2*vel)*vz*vz;
+			D_scalar_stab=gauss->weight*Jdet;
+			if(reCast<bool,IssmDouble>(dt)) D_scalar_stab=D_scalar_stab*dt;
+			for(i=0;i<3;i++) for(j=0;j<3;j++) K[i][j] = D_scalar_stab*K[i][j];
+
+			GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss); 
+
+			TripleMultiply(&Bprime_advec[0][0],3,numdof,1,
+						&K[0][0],3,3,0,
+						&Bprime_advec[0][0],3,numdof,0,
+						&Ke->values[0],1);
+		}
+		else if(stabilization==2){
+			GetNodalFunctionsP1Derivatives(&dbasis[0][0],&xyz_list[0][0], gauss);
+			tau_parameter=GetStabilizationParameter(u-um,v-vm,w-wm,diameter,kappa);
+
+			for(i=0;i<numdof;i++){
+				for(j=0;j<numdof;j++){
+					Ke->values[i*numdof+j]+=tau_parameter*D_scalar_advec*
+					  ((u-um)*dbasis[0][i]+(v-vm)*dbasis[1][i]+(w-wm)*dbasis[2][i])*((u-um)*dbasis[0][j]+(v-vm)*dbasis[1][j]+(w-wm)*dbasis[2][j]);
+				}
+			}
+			if(reCast<bool,IssmDouble>(dt)){
+				for(i=0;i<numdof;i++){
+					for(j=0;j<numdof;j++){
+						Ke->values[i*numdof+j]+=tau_parameter*D_scalar_trans*L[j]*((u-um)*dbasis[0][i]+(v-vm)*dbasis[1][i]+(w-wm)*dbasis[2][i]);
+					}
+				}
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixEnthalpyShelf {{{*/
+ElementMatrix* Penta::CreateKMatrixEnthalpyShelf(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble mixed_layer_capacity,thermal_exchange_velocity;
+	IssmDouble rho_ice,rho_water,heatcapacity;
+	IssmDouble Jdet2d,dt;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble basis[NUMVERTICES];
+	IssmDouble D_scalar;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if (!IsOnBed() || !IsFloating()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
+	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	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 (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		D_scalar=gauss->weight*Jdet2d*rho_water*mixed_layer_capacity*thermal_exchange_velocity/(rho_ice*heatcapacity);
+		if(reCast<bool,IssmDouble>(dt)) D_scalar=dt*D_scalar;
+
+		TripleMultiply(&basis[0],numdof,1,0,
+					&D_scalar,1,1,0,
+					&basis[0],1,numdof,0,
+					&Ke->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixMelting {{{*/
+ElementMatrix* Penta::CreateKMatrixMelting(void){
+
+	if (!IsOnBed()) return NULL;
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixMelting();
+
+	delete tria->material; delete tria;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixThermal {{{*/
+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 {{{*/
+ElementMatrix* Penta::CreateKMatrixThermalVolume(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        stabilization;
+	int        i,j,found=0;
+	IssmDouble Jdet,u,v,w,um,vm,wm,vel;
+	IssmDouble h,hx,hy,hz,vx,vy,vz;
+	IssmDouble gravity,rho_ice,rho_water,kappa;
+	IssmDouble heatcapacity,thermalconductivity,dt;
+	IssmDouble tau_parameter,diameter;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble B_conduct[3][numdof];
+	IssmDouble B_advec[3][numdof];
+	IssmDouble Bprime_advec[3][numdof];
+	IssmDouble L[numdof];
+	IssmDouble dbasis[3][6];
+	IssmDouble D_scalar_conduct,D_scalar_advec;
+	IssmDouble D_scalar_trans,D_scalar_stab;
+	IssmDouble D[3][3];
+	IssmDouble K[3][3]={0.0};
+	Tria*      tria=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	heatcapacity=matpar->GetHeatCapacity();
+	thermalconductivity=matpar->GetThermalConductivity();
+	kappa=thermalconductivity/(rho_ice*heatcapacity);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&stabilization,ThermalStabilizationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);      _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);      _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);      _assert_(vz_input);
+	Input* vxm_input=inputs->GetInput(VxMeshEnum); _assert_(vxm_input);
+	Input* vym_input=inputs->GetInput(VyMeshEnum); _assert_(vym_input);
+	Input* vzm_input=inputs->GetInput(VzMeshEnum); _assert_(vzm_input);
+	if (stabilization==2) diameter=MinEdgeLength(xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for(int 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*kappa;
+		if(reCast<bool,IssmDouble>(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->values[0],1);
+
+		/*Advection: */
+
+		GetBAdvec(&B_advec[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss); 
+
+		vx_input->GetInputValue(&u, gauss); vxm_input->GetInputValue(&um,gauss); vx=u-um;
+		vy_input->GetInputValue(&v, gauss); vym_input->GetInputValue(&vm,gauss); vy=v-vm;
+		vz_input->GetInputValue(&w, gauss); vzm_input->GetInputValue(&wm,gauss); vz=w-wm;
+
+		D_scalar_advec=gauss->weight*Jdet;
+		if(reCast<bool,IssmDouble>(dt)) D_scalar_advec=D_scalar_advec*dt;
+
+		D[0][0]=D_scalar_advec*vx;    D[0][1]=0;                    D[0][2]=0;
+		D[1][0]=0;                    D[1][1]=D_scalar_advec*vy;    D[1][2]=0;
+		D[2][0]=0;                    D[2][1]=0;                    D[2][2]=D_scalar_advec*vz;
+
+		TripleMultiply(&B_advec[0][0],3,numdof,1,
+					&D[0][0],3,3,0,
+					&Bprime_advec[0][0],3,numdof,0,
+					&Ke->values[0],1);
+
+		/*Transient: */
+		if(reCast<bool,IssmDouble>(dt)){
+			GetNodalFunctionsP1(&L[0], gauss);
+			D_scalar_trans=gauss->weight*Jdet;
+
+			TripleMultiply(&L[0],numdof,1,0,
+						&D_scalar_trans,1,1,0,
+						&L[0],1,numdof,0,
+						&Ke->values[0],1);
+		}
+
+		/*Artifficial diffusivity*/
+		if(stabilization==1){
+			/*Build K: */
+			GetElementSizes(&hx,&hy,&hz);
+			vel=sqrt(pow(vx,2.)+pow(vy,2.)+pow(vz,2.))+1.e-14;
+			h=sqrt( pow(hx*vx/vel,2.) + pow(hy*vy/vel,2.) + pow(hz*vz/vel,2.));
+
+			K[0][0]=h/(2*vel)*fabs(vx*vx);  K[0][1]=h/(2*vel)*fabs(vx*vy); K[0][2]=h/(2*vel)*fabs(vx*vz);
+			K[1][0]=h/(2*vel)*fabs(vy*vx);  K[1][1]=h/(2*vel)*fabs(vy*vy); K[1][2]=h/(2*vel)*fabs(vy*vz);
+			K[2][0]=h/(2*vel)*fabs(vz*vx);  K[2][1]=h/(2*vel)*fabs(vz*vy); K[2][2]=h/(2*vel)*fabs(vz*vz);
+
+			D_scalar_stab=gauss->weight*Jdet;
+			if(reCast<bool,IssmDouble>(dt)) D_scalar_stab=D_scalar_stab*dt;
+			for(i=0;i<3;i++) for(j=0;j<3;j++) K[i][j] = D_scalar_stab*K[i][j];
+
+			GetBprimeAdvec(&Bprime_advec[0][0],&xyz_list[0][0],gauss); 
+
+			TripleMultiply(&Bprime_advec[0][0],3,numdof,1,
+						&K[0][0],3,3,0,
+						&Bprime_advec[0][0],3,numdof,0,
+						&Ke->values[0],1);
+		}
+		else if(stabilization==2){
+			GetNodalFunctionsP1Derivatives(&dbasis[0][0],&xyz_list[0][0], gauss);
+			tau_parameter=GetStabilizationParameter(u-um,v-vm,w-wm,diameter,kappa);
+
+			for(i=0;i<numdof;i++){
+				for(j=0;j<numdof;j++){
+					Ke->values[i*numdof+j]+=tau_parameter*D_scalar_advec*
+					  ((u-um)*dbasis[0][i]+(v-vm)*dbasis[1][i]+(w-wm)*dbasis[2][i])*((u-um)*dbasis[0][j]+(v-vm)*dbasis[1][j]+(w-wm)*dbasis[2][j]);
+				}
+			}
+			if(reCast<bool,IssmDouble>(dt)){
+				for(i=0;i<numdof;i++){
+					for(j=0;j<numdof;j++){
+						Ke->values[i*numdof+j]+=tau_parameter*D_scalar_trans*L[j]*((u-um)*dbasis[0][i]+(v-vm)*dbasis[1][i]+(w-wm)*dbasis[2][i]);
+					}
+				}
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixThermalShelf {{{*/
+ElementMatrix* Penta::CreateKMatrixThermalShelf(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int       i,j;
+	IssmDouble mixed_layer_capacity,thermal_exchange_velocity;
+	IssmDouble rho_ice,rho_water,heatcapacity;
+	IssmDouble Jdet2d,dt;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble basis[NUMVERTICES];
+	IssmDouble D_scalar;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if (!IsOnBed() || !IsFloating()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
+	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	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 (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		D_scalar=gauss->weight*Jdet2d*rho_water*mixed_layer_capacity*thermal_exchange_velocity/(heatcapacity*rho_ice);
+		if(reCast<bool,IssmDouble>(dt)) D_scalar=dt*D_scalar;
+
+		TripleMultiply(&basis[0],numdof,1,0,
+					&D_scalar,1,1,0,
+					&basis[0],1,numdof,0,
+					&Ke->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorEnthalpy {{{*/
+ElementVector* Penta::CreatePVectorEnthalpy(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorEnthalpyVolume();
+	ElementVector* pe2=CreatePVectorEnthalpySheet();
+	ElementVector* pe3=CreatePVectorEnthalpyShelf();
+	ElementVector* pe =new ElementVector(pe1,pe2,pe3);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	delete pe3;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorEnthalpyVolume {{{*/
+ElementVector* Penta::CreatePVectorEnthalpyVolume(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries*/
+	int    i,j,found=0;
+	int    friction_type,stabilization;
+	IssmDouble Jdet,phi,dt;
+	IssmDouble rho_ice,heatcapacity;
+	IssmDouble thermalconductivity,kappa;
+	IssmDouble viscosity,pressure;
+	IssmDouble enthalpy,enthalpypicard;
+	IssmDouble tau_parameter,diameter;
+	IssmDouble u,v,w;
+	IssmDouble scalar_def,scalar_transient;
+	IssmDouble temperature_list[NUMVERTICES];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[numdof];
+	IssmDouble dbasis[3][6];
+	IssmDouble epsilon[6];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	thermalconductivity=matpar->GetThermalConductivity();
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&stabilization,ThermalStabilizationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);                                  _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                                  _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                                  _assert_(vz_input);
+	Input* pressure_input=inputs->GetInput(PressureEnum);                      _assert_(pressure_input);
+	Input* enthalpy_input=NULL; 
+	Input* enthalpypicard_input=NULL; 
+	if(reCast<bool,IssmDouble>(dt)){
+		enthalpy_input=inputs->GetInput(EnthalpyEnum); _assert_(enthalpy_input);
+	}
+	if (stabilization==2){
+		diameter=MinEdgeLength(xyz_list);
+		enthalpypicard_input=inputs->GetInput(EnthalpyPicardEnum); _assert_(enthalpypicard_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,3);
+	for(int 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);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		GetPhi(&phi, &epsilon[0], viscosity);
+
+		scalar_def=phi/rho_ice*Jdet*gauss->weight;
+		if(reCast<bool,IssmDouble>(dt)) scalar_def=scalar_def*dt;
+
+		for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
+
+		/* Build transient now */
+		if(reCast<bool,IssmDouble>(dt)){
+			enthalpy_input->GetInputValue(&enthalpy, gauss);
+			scalar_transient=enthalpy*Jdet*gauss->weight;
+			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_transient*L[i];
+		}
+
+		if(stabilization==2){
+			GetNodalFunctionsP1Derivatives(&dbasis[0][0],&xyz_list[0][0], gauss);
+
+			vx_input->GetInputValue(&u, gauss);
+			vy_input->GetInputValue(&v, gauss);
+			vz_input->GetInputValue(&w, gauss);
+			pressure_input->GetInputValue(&pressure, gauss);
+			enthalpypicard_input->GetInputValue(&enthalpypicard, gauss);
+			kappa=matpar->GetEnthalpyDiffusionParameter(enthalpy,pressure);
+			tau_parameter=GetStabilizationParameter(u,v,w,diameter,kappa);
+
+			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_def*(u*dbasis[0][i]+v*dbasis[1][i]+w*dbasis[2][i]);
+			if(reCast<bool,IssmDouble>(dt)){
+				for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_transient*(u*dbasis[0][i]+v*dbasis[1][i]+w*dbasis[2][i]);
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorEnthalpyShelf {{{*/
+ElementVector* Penta::CreatePVectorEnthalpyShelf(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble Jdet2d;
+	IssmDouble heatcapacity,h_pmp;
+	IssmDouble mixed_layer_capacity,thermal_exchange_velocity;
+	IssmDouble rho_ice,rho_water,pressure,dt,scalar_ocean;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble basis[NUMVERTICES];
+	GaussPenta* gauss=NULL;
+
+	/* Ice/ocean heat exchange flux on ice shelf base */
+	if (!IsOnBed() || !IsFloating()) return NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
+	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* pressure_input=inputs->GetInput(PressureEnum); _assert_(pressure_input);
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		pressure_input->GetInputValue(&pressure,gauss);
+		h_pmp=matpar->PureIceEnthalpy(pressure);
+
+		scalar_ocean=gauss->weight*Jdet2d*rho_water*mixed_layer_capacity*thermal_exchange_velocity*(h_pmp)/(rho_ice*heatcapacity);
+		if(reCast<bool,IssmDouble>(dt)) scalar_ocean=dt*scalar_ocean;
+
+		for(i=0;i<numdof;i++) pe->values[i]+=scalar_ocean*basis[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorEnthalpySheet {{{*/
+ElementVector* Penta::CreatePVectorEnthalpySheet(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,j;
+	int        analysis_type;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble Jdet2d,dt;
+	IssmDouble rho_ice,heatcapacity,geothermalflux_value;
+	IssmDouble basalfriction,alpha2,vx,vy;
+	IssmDouble scalar,enthalpy,enthalpyup;
+	IssmDouble pressure,pressureup;
+	IssmDouble basis[NUMVERTICES];
+	Friction*  friction=NULL;
+	GaussPenta* gauss=NULL;
+	GaussPenta* gaussup=NULL;
+
+	/* Geothermal flux on ice sheet base and basal friction */
+	if (!IsOnBed() || IsFloating()) return NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);                         _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                         _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                         _assert_(vz_input);
+	Input* enthalpy_input=inputs->GetInput(EnthalpyEnum);             _assert_(enthalpy_input);
+	Input* pressure_input=inputs->GetInput(PressureEnum);             _assert_(pressure_input);
+	Input* geothermalflux_input=inputs->GetInput(BasalforcingsGeothermalfluxEnum); _assert_(geothermalflux_input);
+
+	/*Build frictoin element, needed later: */
+	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);
+	gaussup=new GaussPenta(3,4,5,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		gaussup->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		enthalpy_input->GetInputValue(&enthalpy,gauss);
+		pressure_input->GetInputValue(&pressure,gauss);
+//		if(enthalpy>matpar->PureIceEnthalpy(pressure)){
+//			enthalpy_input->GetInputValue(&enthalpyup,gaussup);
+//			pressure_input->GetInputValue(&pressureup,gaussup);
+//			if(enthalpyup>matpar->PureIceEnthalpy(pressureup)){
+//				//do nothing, don't add heatflux
+//			}
+//			else{
+//				//need to change spcenthalpy according to Aschwanden 
+//				//NEED TO UPDATE
+//			}
+//		}
+//		else{
+			geothermalflux_input->GetInputValue(&geothermalflux_value,gauss);
+			friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
+			vx_input->GetInputValue(&vx,gauss);
+			vy_input->GetInputValue(&vy,gauss);
+			basalfriction=alpha2*(pow(vx,2.0)+pow(vy,2.0));
+
+			scalar=gauss->weight*Jdet2d*(basalfriction+geothermalflux_value)/(rho_ice);
+			if(reCast<bool,IssmDouble>(dt)) scalar=dt*scalar;
+
+			for(i=0;i<numdof;i++) pe->values[i]+=scalar*basis[i];
+//		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	delete gaussup;
+	delete friction;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorMelting {{{*/
+ElementVector* Penta::CreatePVectorMelting(void){
+	return NULL;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermal {{{*/
+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 {{{*/
+ElementVector* Penta::CreatePVectorThermalVolume(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries*/
+	int    i,j,found=0;
+	int    friction_type,stabilization;
+	IssmDouble Jdet,phi,dt;
+	IssmDouble rho_ice,heatcapacity;
+	IssmDouble thermalconductivity,kappa;
+	IssmDouble viscosity,temperature;
+	IssmDouble tau_parameter,diameter;
+	IssmDouble u,v,w;
+	IssmDouble scalar_def,scalar_transient;
+	IssmDouble temperature_list[NUMVERTICES];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[numdof];
+	IssmDouble dbasis[3][6];
+	IssmDouble epsilon[6];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	thermalconductivity=matpar->GetThermalConductivity();
+	kappa=thermalconductivity/(rho_ice*heatcapacity);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&stabilization,ThermalStabilizationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); _assert_(vz_input);
+	Input* temperature_input=NULL;
+	if (reCast<bool,IssmDouble>(dt)) temperature_input=inputs->GetInput(TemperatureEnum); _assert_(inputs);
+	if (stabilization==2) diameter=MinEdgeLength(xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,3);
+	for(int 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);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		GetPhi(&phi, &epsilon[0], viscosity);
+
+		scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss->weight;
+		if(reCast<bool,IssmDouble>(dt)) scalar_def=scalar_def*dt;
+
+		for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
+
+		/* Build transient now */
+		if(reCast<bool,IssmDouble>(dt)){
+			temperature_input->GetInputValue(&temperature, gauss);
+			scalar_transient=temperature*Jdet*gauss->weight;
+			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_transient*L[i];
+		}
+
+		if(stabilization==2){
+			GetNodalFunctionsP1Derivatives(&dbasis[0][0],&xyz_list[0][0], gauss);
+
+			vx_input->GetInputValue(&u, gauss);
+			vy_input->GetInputValue(&v, gauss);
+			vz_input->GetInputValue(&w, gauss);
+
+			tau_parameter=GetStabilizationParameter(u,v,w,diameter,kappa);
+
+			for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_def*(u*dbasis[0][i]+v*dbasis[1][i]+w*dbasis[2][i]);
+			if(reCast<bool,IssmDouble>(dt)){
+				for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=tau_parameter*scalar_transient*(u*dbasis[0][i]+v*dbasis[1][i]+w*dbasis[2][i]);
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermalShelf {{{*/
+ElementVector* Penta::CreatePVectorThermalShelf(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble Jdet2d;
+	IssmDouble mixed_layer_capacity,thermal_exchange_velocity;
+	IssmDouble rho_ice,rho_water,pressure,dt,scalar_ocean;
+	IssmDouble heatcapacity,t_pmp;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble basis[NUMVERTICES];
+	GaussPenta* gauss=NULL;
+
+	/* Ice/ocean heat exchange flux on ice shelf base */
+	if (!IsOnBed() || !IsFloating()) return NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	mixed_layer_capacity=matpar->GetMixedLayerCapacity();
+	thermal_exchange_velocity=matpar->GetThermalExchangeVelocity();
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* pressure_input=inputs->GetInput(PressureEnum); _assert_(pressure_input);
+
+	/* Start looping on the number of gauss 2d (nodes on the bedrock) */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		pressure_input->GetInputValue(&pressure,gauss);
+		t_pmp=matpar->TMeltingPoint(pressure);
+
+		scalar_ocean=gauss->weight*Jdet2d*rho_water*mixed_layer_capacity*thermal_exchange_velocity*(t_pmp)/(heatcapacity*rho_ice);
+		if(reCast<bool,IssmDouble>(dt)) scalar_ocean=dt*scalar_ocean;
+
+		for(i=0;i<numdof;i++) pe->values[i]+=scalar_ocean*basis[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorThermalSheet {{{*/
+ElementVector* Penta::CreatePVectorThermalSheet(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	int        i,j;
+	int        analysis_type;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble Jdet2d,dt;
+	IssmDouble rho_ice,heatcapacity,geothermalflux_value;
+	IssmDouble basalfriction,alpha2,vx,vy;
+	IssmDouble basis[NUMVERTICES];
+	IssmDouble scalar;
+	Friction*  friction=NULL;
+	GaussPenta* gauss=NULL;
+
+	/* Geothermal flux on ice sheet base and basal friction */
+	if (!IsOnBed() || IsFloating()) return NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	rho_ice=matpar->GetRhoIce();
+	heatcapacity=matpar->GetHeatCapacity();
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);                         _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                         _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                         _assert_(vz_input);
+	Input* geothermalflux_input=inputs->GetInput(BasalforcingsGeothermalfluxEnum); _assert_(geothermalflux_input);
+
+	/*Build frictoin element, needed later: */
+	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(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+			geothermalflux_input->GetInputValue(&geothermalflux_value,gauss);
+			friction->GetAlpha2(&alpha2,gauss,VxEnum,VyEnum,VzEnum);
+			vx_input->GetInputValue(&vx,gauss);
+			vy_input->GetInputValue(&vy,gauss);
+			basalfriction=alpha2*(pow(vx,2.0)+pow(vy,2.0));
+
+			scalar=gauss->weight*Jdet2d*(basalfriction+geothermalflux_value)/(heatcapacity*rho_ice);
+			if(reCast<bool,IssmDouble>(dt)) scalar=dt*scalar;
+
+			for(i=0;i<numdof;i++) pe->values[i]+=scalar*basis[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsThermal{{{*/
+void  Penta::GetSolutionFromInputsThermal(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	int         i;
+	int        *doflist = NULL;
+	IssmDouble  values[numdof];
+	IssmDouble  temp;
+	GaussPenta *gauss = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* t_input=inputs->GetInput(TemperatureEnum); _assert_(t_input);
+
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+		/*Recover temperature*/
+		gauss->GaussVertex(i);
+		t_input->GetInputValue(&temp,gauss);
+		values[i]=temp;
+	}
+
+	/*Add value to global vector*/
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsEnthalpy{{{*/
+void  Penta::GetSolutionFromInputsEnthalpy(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	IssmDouble       values[numdof];
+	IssmDouble       enthalpy;
+	GaussPenta   *gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* h_input=inputs->GetInput(EnthalpyEnum); _assert_(h_input);
+
+	gauss=new GaussPenta();
+	for(i=0;i<NUMVERTICES;i++){
+		/*Recover temperature*/
+		gauss->GaussVertex(i);
+		h_input->GetInputValue(&enthalpy,gauss);
+		values[i]=enthalpy;
+	}
+
+	/*Add value to global vector*/
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionThermal {{{*/
+void  Penta::InputUpdateFromSolutionThermal(IssmDouble* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	bool   converged;
+	int    i,rheology_law;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble values[numdof];
+	IssmDouble B[numdof];
+	IssmDouble B_average,s_average;
+	int*   doflist=NULL;
+	//IssmDouble pressure[numdof];
+
+	/*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]];
+		//GetInputListOnVertices(&pressure[0],PressureEnum);
+		//if(values[i]>matpar->TMeltingPoint(pressure[i])) values[i]=matpar->TMeltingPoint(pressure[i]);
+		//if(values[i]<matpar->TMeltingPoint(pressure[i])-50) values[i]=matpar->TMeltingPoint(pressure[i])-50;
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+		//if(values[i]<0)      _printLine_("temperature < 0°K found in solution vector");
+		//if(values[i]>275)    _printLine_("temperature > 275°K found in solution vector (Paterson's rheology associated is negative)");
+	}
+
+	/*Get all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); _assert_(surface_input);
+
+	this->inputs->GetInputValue(&converged,ConvergedEnum);
+	if(converged){
+		this->inputs->AddInput(new PentaP1Input(TemperatureEnum,values));
+
+		/*Update Rheology only if converged (we must make sure that the temperature is below melting point
+		 * otherwise the rheology could be negative*/
+		this->parameters->FindParam(&rheology_law,MaterialsRheologyLawEnum);
+		switch(rheology_law){
+			case NoneEnum:
+				/*Do nothing: B is not temperature dependent*/
+				break;
+			case PatersonEnum:
+				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->material->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,B));
+				break;
+			case ArrheniusEnum:
+				surface_input->GetInputAverage(&s_average);
+				B_average=Arrhenius((values[0]+values[1]+values[2]+values[3]+values[4]+values[5])/6.0,
+							s_average-((xyz_list[0][2]+xyz_list[1][2]+xyz_list[2][2]+xyz_list[3][2]+xyz_list[4][2]+xyz_list[5][2])/6.0),
+							material->GetN());
+				for(i=0;i<numdof;i++) B[i]=B_average;
+				this->material->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,B));
+				break;
+			default:
+				_error_("Rheology law " << EnumToStringx(rheology_law) << " not supported yet");
+
+		}
+	}
+	else{
+		this->inputs->AddInput(new PentaP1Input(TemperaturePicardEnum,values));
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionEnthalpy {{{*/
+void  Penta::InputUpdateFromSolutionEnthalpy(IssmDouble* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	bool   converged=false;
+	int    i,rheology_law;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble values[numdof];
+	IssmDouble pressure[NUMVERTICES];
+	IssmDouble temperatures[numdof];
+	IssmDouble waterfraction[numdof];
+	IssmDouble B[numdof];
+	IssmDouble B_average,s_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]];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Get all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GetInputListOnVertices(&pressure[0],PressureEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); _assert_(surface_input);
+
+	this->inputs->GetInputValue(&converged,ConvergedEnum);
+	if(converged){
+		/*Convert enthalpy into temperature and water fraction*/
+		for(i=0;i<numdof;i++){
+			matpar->EnthalpyToThermal(&temperatures[i],&waterfraction[i],values[i],pressure[i]);
+			if(waterfraction[i]<0) _error_("Negative water fraction found in solution vector");
+			//if(waterfraction[i]>1) _error_("Water fraction >1 found in solution vector");
+		}
+
+		this->inputs->AddInput(new PentaP1Input(EnthalpyEnum,values));
+		this->inputs->AddInput(new PentaP1Input(WaterfractionEnum,waterfraction));
+		this->inputs->AddInput(new PentaP1Input(TemperatureEnum,temperatures));
+
+		/*Update Rheology only if converged (we must make sure that the temperature is below melting point
+		 * otherwise the rheology could be negative*/
+		this->parameters->FindParam(&rheology_law,MaterialsRheologyLawEnum);
+		switch(rheology_law){
+			case NoneEnum:
+				/*Do nothing: B is not temperature dependent*/
+				break;
+			case PatersonEnum:
+				B_average=Paterson((temperatures[0]+temperatures[1]+temperatures[2]+temperatures[3]+temperatures[4]+temperatures[5])/6.0);
+				for(i=0;i<numdof;i++) B[i]=B_average;
+				this->material->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,B));
+				break;
+			case ArrheniusEnum:
+				surface_input->GetInputAverage(&s_average);
+				B_average=Arrhenius((temperatures[0]+temperatures[1]+temperatures[2]+temperatures[3]+temperatures[4]+temperatures[5])/6.0,
+							s_average-((xyz_list[0][2]+xyz_list[1][2]+xyz_list[2][2]+xyz_list[3][2]+xyz_list[4][2]+xyz_list[5][2])/6.0),
+							material->GetN());
+				for(i=0;i<numdof;i++) B[i]=B_average;
+				this->material->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,B));
+				break;
+			default:
+				_error_("Rheology law " << EnumToStringx(rheology_law) << " not supported yet");
+
+		}
+	}
+	else{
+		this->inputs->AddInput(new PentaP1Input(EnthalpyPicardEnum,values));
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_CONTROL_
+/*FUNCTION Penta::ControlInputGetGradient{{{*/
+void Penta::ControlInputGetGradient(Vector<IssmDouble>* gradient,int enum_type,int control_index){
+
+	int vertexpidlist[NUMVERTICES];
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		if(!IsOnBed()) return;
+		input=(Input*)material->inputs->GetInput(MaterialsRheologyBEnum);
+	}
+	else if(enum_type==MaterialsRheologyZbarEnum){
+		if(!IsOnBed()) return;
+		input=(Input*)material->inputs->GetInput(MaterialsRheologyZEnum);
+	}
+
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&vertexpidlist[0],control_index);
+	((ControlInput*)input)->GetGradient(gradient,&vertexpidlist[0]);
+
+}/*}}}*/
+/*FUNCTION Penta::ControlInputScaleGradient{{{*/
+void Penta::ControlInputScaleGradient(int enum_type,IssmDouble scale){
+
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)material->inputs->GetInput(MaterialsRheologyBEnum);
+	}
+	else if(enum_type==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(MaterialsRheologyZEnum);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	((ControlInput*)input)->ScaleGradient(scale);
+}/*}}}*/
+/*FUNCTION Penta::ControlInputSetGradient{{{*/
+void Penta::ControlInputSetGradient(IssmDouble* gradient,int enum_type,int control_index){
+
+	int    vertexpidlist[NUMVERTICES];
+	IssmDouble grad_list[NUMVERTICES];
+	Input* grad_input=NULL;
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)material->inputs->GetInput(MaterialsRheologyBEnum);
+	}
+	else if(enum_type==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(MaterialsRheologyZEnum);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&vertexpidlist[0],control_index);
+	for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[vertexpidlist[i]];
+	grad_input=new PentaP1Input(GradientEnum,grad_list);
+	((ControlInput*)input)->SetGradient(grad_input);
+
+}/*}}}*/
+/*FUNCTION Penta::CreateKMatrixAdjointHoriz{{{*/
+ElementMatrix* Penta::CreateKMatrixAdjointHoriz(void){
+
+	int approximation;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreateKMatrixAdjointMacAyeal2d();
+		case PattynApproximationEnum:
+			return CreateKMatrixAdjointPattyn();
+		case StokesApproximationEnum:
+			return CreateKMatrixAdjointStokes();
+		case NoneApproximationEnum:
+			return NULL;
+		default:
+			_error_("Approximation " << EnumToStringx(approximation) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixAdjointMacAyeal2d{{{*/
+ElementMatrix* Penta::CreateKMatrixAdjointMacAyeal2d(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 nodes, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed()) return NULL;
+
+	/*Depth average some fields*/
+	switch(this->material->ObjectEnum()){
+		case MaticeEnum:
+			this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+			break;
+		case MatdamageiceEnum:
+			this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+			this->InputDepthAverageAtBase(MaterialsRheologyZEnum,MaterialsRheologyZbarEnum,MaterialsEnum);
+			break;
+		default:
+			_error_("material "<<EnumToStringx(this->material->ObjectEnum())<<" not supported");
+	}
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixAdjointMacAyeal();
+	delete tria->material; delete tria;
+
+	/*Delete averaged fields*/
+	this->material->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+	this->material->inputs->DeleteInput(MaterialsRheologyZbarEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixAdjointPattyn{{{*/
+ElementMatrix* Penta::CreateKMatrixAdjointPattyn(void){
+
+	/*Intermediaries */
+	int        i,j;
+	bool       incomplete_adjoint;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet;
+	IssmDouble eps1dotdphii,eps1dotdphij;
+	IssmDouble eps2dotdphii,eps2dotdphij;
+	IssmDouble mu_prime;
+	IssmDouble epsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble eps1[3],eps2[3];
+	IssmDouble phi[NUMVERTICES];
+	IssmDouble dphi[3][NUMVERTICES];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Jacobian with regular Pattyn (first part of the Gateau derivative)*/
+	parameters->FindParam(&incomplete_adjoint,InversionIncompleteAdjointEnum);
+	ElementMatrix* Ke=CreateKMatrixDiagnosticPattyn();
+	if(incomplete_adjoint) return Ke;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1Derivatives(&dphi[0][0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosityDerivativeEpsSquare(&mu_prime,&epsilon[0]);
+		eps1[0]=2*epsilon[0]+epsilon[1];   eps2[0]=epsilon[2];
+		eps1[1]=epsilon[2];                eps2[1]=epsilon[0]+2*epsilon[1];
+		eps1[2]=epsilon[3];                eps2[2]=epsilon[4];
+
+		for(i=0;i<6;i++){
+			for(j=0;j<6;j++){
+				eps1dotdphii=eps1[0]*dphi[0][i]+eps1[1]*dphi[1][i]+eps1[2]*dphi[2][i];
+				eps1dotdphij=eps1[0]*dphi[0][j]+eps1[1]*dphi[1][j]+eps1[2]*dphi[2][j];
+				eps2dotdphii=eps2[0]*dphi[0][i]+eps2[1]*dphi[1][i]+eps2[2]*dphi[2][i];
+				eps2dotdphij=eps2[0]*dphi[0][j]+eps2[1]*dphi[1][j]+eps2[2]*dphi[2][j];
+
+				Ke->values[12*(2*i+0)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps1dotdphii;
+				Ke->values[12*(2*i+0)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps1dotdphii;
+				Ke->values[12*(2*i+1)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps2dotdphii;
+				Ke->values[12*(2*i+1)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps2dotdphii;
+			}
+		}
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixAdjointStokes{{{*/
+ElementMatrix* Penta::CreateKMatrixAdjointStokes(void){
+
+	/*Constants*/
+	const int    numdof=NDOF4*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	bool       incomplete_adjoint;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet;
+	IssmDouble eps1dotdphii,eps1dotdphij;
+	IssmDouble eps2dotdphii,eps2dotdphij;
+	IssmDouble eps3dotdphii,eps3dotdphij;
+	IssmDouble mu_prime;
+	IssmDouble epsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble eps1[3],eps2[3],eps3[3];
+	IssmDouble dphi[3][NUMVERTICES];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Jacobian with regular Stokes (first part of the Gateau derivative)*/
+	parameters->FindParam(&incomplete_adjoint,InversionIncompleteAdjointEnum);
+	ElementMatrix* Ke=CreateKMatrixDiagnosticStokes();
+	if(incomplete_adjoint) return Ke;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);       _assert_(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1Derivatives(&dphi[0][0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosityDerivativeEpsSquare(&mu_prime,&epsilon[0]);
+		eps1[0]=epsilon[0];   eps2[0]=epsilon[2];   eps3[0]=epsilon[3];
+		eps1[1]=epsilon[2];   eps2[1]=epsilon[1];   eps3[1]=epsilon[4];
+		eps1[2]=epsilon[3];   eps2[2]=epsilon[4];   eps3[2]= -epsilon[0] -epsilon[1];
+
+		for(i=0;i<6;i++){
+			for(j=0;j<6;j++){
+				eps1dotdphii=eps1[0]*dphi[0][i]+eps1[1]*dphi[1][i]+eps1[2]*dphi[2][i];
+				eps1dotdphij=eps1[0]*dphi[0][j]+eps1[1]*dphi[1][j]+eps1[2]*dphi[2][j];
+				eps2dotdphii=eps2[0]*dphi[0][i]+eps2[1]*dphi[1][i]+eps2[2]*dphi[2][i];
+				eps2dotdphij=eps2[0]*dphi[0][j]+eps2[1]*dphi[1][j]+eps2[2]*dphi[2][j];
+				eps3dotdphii=eps3[0]*dphi[0][i]+eps3[1]*dphi[1][i]+eps3[2]*dphi[2][i];
+				eps3dotdphij=eps3[0]*dphi[0][j]+eps3[1]*dphi[1][j]+eps3[2]*dphi[2][j];
+
+				Ke->values[numdof*(4*i+0)+4*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps1dotdphii;
+				Ke->values[numdof*(4*i+0)+4*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps1dotdphii;
+				Ke->values[numdof*(4*i+0)+4*j+2]+=gauss->weight*Jdet*2*mu_prime*eps3dotdphij*eps1dotdphii;
+
+				Ke->values[numdof*(4*i+1)+4*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps2dotdphii;
+				Ke->values[numdof*(4*i+1)+4*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps2dotdphii;
+				Ke->values[numdof*(4*i+1)+4*j+2]+=gauss->weight*Jdet*2*mu_prime*eps3dotdphij*eps2dotdphii;
+
+				Ke->values[numdof*(4*i+2)+4*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps3dotdphii;
+				Ke->values[numdof*(4*i+2)+4*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps3dotdphii;
+				Ke->values[numdof*(4*i+2)+4*j+2]+=gauss->weight*Jdet*2*mu_prime*eps3dotdphij*eps3dotdphii;
+			}
+		}
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointHoriz{{{*/
+ElementVector* Penta::CreatePVectorAdjointHoriz(void){
+
+	int approximation;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreatePVectorAdjointMacAyeal();
+		case PattynApproximationEnum:
+			return CreatePVectorAdjointPattyn();
+		case NoneApproximationEnum:
+			return NULL;
+		case StokesApproximationEnum:
+			return CreatePVectorAdjointStokes();
+		default:
+			_error_("Approximation " << EnumToStringx(approximation) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointMacAyeal{{{*/
+ElementVector* Penta::CreatePVectorAdjointMacAyeal(){
+
+	if (!IsOnBed()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorAdjointHoriz();
+	delete tria->material; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointPattyn{{{*/
+ElementVector* Penta::CreatePVectorAdjointPattyn(void){
+
+	if (!IsOnSurface()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+	ElementVector* pe=tria->CreatePVectorAdjointHoriz();
+	delete tria->material; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorAdjointStokes{{{*/
+ElementVector* Penta::CreatePVectorAdjointStokes(void){
+
+	if (!IsOnSurface()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+	ElementVector* pe=tria->CreatePVectorAdjointStokes();
+	delete tria->material; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::GradientIndexing{{{*/
+void Penta::GradientIndexing(int* indexing,int control_index){
+
+	/*Get some parameters*/
+	int num_controls;
+	parameters->FindParam(&num_controls,InversionNumControlParametersEnum);
+
+	/*get gradient indices*/
+	for(int i=0;i<NUMVERTICES;i++){
+		indexing[i]=num_controls*this->nodes[i]->GetVertexPid() + control_index;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::Gradj {{{*/
+void  Penta::Gradj(Vector<IssmDouble>* gradient,int control_type,int control_index){
+	/*dJ/dalpha = ∂L/∂alpha = ∂J/∂alpha + ∂/∂alpha(KU-F)*/
+
+	int              i,approximation;
+	Tria*            tria=NULL;
+
+	/*If on water, skip grad (=0): */
+	if(IsOnWater())return;
+
+	/*First deal with ∂/∂alpha(KU-F)*/
+	switch(control_type){
+
+		case FrictionCoefficientEnum:
+			inputs->GetInputValue(&approximation,ApproximationEnum);
+			switch(approximation){
+				case MacAyealApproximationEnum:
+					GradjDragMacAyeal(gradient,control_index);
+					break;
+				case PattynApproximationEnum:
+					GradjDragPattyn(gradient,control_index);
+					break;
+				case StokesApproximationEnum:
+					GradjDragStokes(gradient,control_index);
+					break;
+				case NoneApproximationEnum:
+					/*Gradient is 0*/
+					break;
+				default:
+					_error_("approximation " << EnumToStringx(approximation) << " not supported yet");
+			}
+			break;
+
+		case MaterialsRheologyBbarEnum:
+			inputs->GetInputValue(&approximation,ApproximationEnum);
+			switch(approximation){
+				case MacAyealApproximationEnum:
+					GradjBbarMacAyeal(gradient,control_index);
+					break;
+				case PattynApproximationEnum:
+					GradjBbarPattyn(gradient,control_index);
+					break;
+				case StokesApproximationEnum:
+					GradjBbarStokes(gradient,control_index);
+					break;
+				case NoneApproximationEnum:
+					/*Gradient is 0*/
+					break;
+				default:
+					_error_("approximation " << EnumToStringx(approximation) << " not supported yet");
+			}
+			break;
+
+		default:
+			_error_("control type " << EnumToStringx(control_type) << " not supported yet: ");
+	}
+
+	/*Now deal with ∂J/∂alpha*/
+	int        *responses = NULL;
+	int         num_responses,resp;
+	this->parameters->FindParam(&num_responses,InversionNumCostFunctionsEnum);
+	this->parameters->FindParam(&responses,NULL,NULL,StepResponsesEnum);
+
+	for(resp=0;resp<num_responses;resp++) switch(responses[resp]){
+
+		case ThicknessAbsMisfitEnum:
+		case SurfaceAbsVelMisfitEnum:
+		case SurfaceRelVelMisfitEnum:
+		case SurfaceLogVelMisfitEnum:
+		case SurfaceLogVxVyMisfitEnum:
+		case SurfaceAverageVelMisfitEnum:
+			/*Nothing, J does not depends on the parameter being inverted for*/
+			break;
+		case DragCoefficientAbsGradientEnum:
+			if (!IsOnBed()) return;
+			tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+			tria->GradjDragGradient(gradient,resp,control_index);
+			delete tria->material; delete tria;
+			break;
+		case RheologyBbarAbsGradientEnum:
+			if (!IsOnBed()) return;
+			tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+			tria->GradjBGradient(gradient,resp,control_index);
+			delete tria->material; delete tria;
+			break;
+		default:
+			_error_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+	}
+	xDelete<int>(responses);
+}
+/*}}}*/
+/*FUNCTION Penta::GradjDragMacAyeal {{{*/
+void  Penta::GradjDragMacAyeal(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Gradient is 0 if on shelf or not on bed*/
+	if(IsFloating() || !IsOnBed()) return;
+
+	/*Spawn tria*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	tria->GradjDragMacAyeal(gradient,control_index);
+	delete tria->material; delete tria;
+
+} /*}}}*/
+/*FUNCTION Penta::GradjDragPattyn {{{*/
+void  Penta::GradjDragPattyn(Vector<IssmDouble>* gradient,int control_index){
+
+	int        i,j;
+	int        analysis_type;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble vx,vy,lambda,mu,alpha_complement,Jdet;
+	IssmDouble bed,thickness,Neff,drag;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble dk[NDOF3]; 
+	IssmDouble grade_g[NUMVERTICES]={0.0};
+	IssmDouble grade_g_gaussian[NUMVERTICES];
+	IssmDouble basis[6];
+	Friction*  friction=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Gradient is 0 if on shelf or not on bed*/
+	if(IsFloating() || !IsOnBed()) return;
+
+	/*Retrieve all inputs and parameters*/
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	GradientIndexing(&vertexpidlist[0],control_index);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);               _assert_(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);               _assert_(adjointy_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                           _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                           _assert_(vy_input);
+	Input* dragcoefficient_input=inputs->GetInput(FrictionCoefficientEnum); _assert_(dragcoefficient_input);
+
+	/*Build frictoin element, needed later: */
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet, &xyz_list_tria[0][0],gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		/*Build alpha_complement_list: */
+		friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum,VzEnum);
+
+		dragcoefficient_input->GetInputValue(&drag, gauss);
+		adjointx_input->GetInputValue(&lambda, gauss);
+		adjointy_input->GetInputValue(&mu, gauss);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		dragcoefficient_input->GetInputDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++){
+			grade_g_gaussian[i]=-2*drag*alpha_complement*((lambda*vx+mu*vy))*Jdet*gauss->weight*basis[i]; /*basis are 0 for the 3 upper nodes*/
+		}
+
+		/*Add gradje_g_gaussian vector to gradje_g: */
+		for(i=0;i<NUMVERTICES;i++){
+			_assert_(!xIsNan<IssmDouble>(grade_g[i]));
+			grade_g[i]+=grade_g_gaussian[i];
+		}
+	}
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+}
+/*}}}*/
+/*FUNCTION Penta::GradjDragStokes {{{*/
+void  Penta::GradjDragStokes(Vector<IssmDouble>* gradient,int control_index){
+
+	int        i,j;
+	int        analysis_type;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble bed,thickness,Neff;
+	IssmDouble lambda,mu,xi,Jdet,vx,vy,vz;
+	IssmDouble alpha_complement,drag;
+	IssmDouble surface_normal[3],bed_normal[3];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble dk[NDOF3]; 
+	IssmDouble basis[6];
+	IssmDouble grade_g[NUMVERTICES]={0.0};
+	IssmDouble grade_g_gaussian[NUMVERTICES];
+	Friction*  friction=NULL;
+	GaussPenta* gauss=NULL;
+
+	/*Gradient is 0 if on shelf or not on bed*/
+	if(IsFloating() || !IsOnBed()) return;
+
+	/*Retrieve all inputs and parameters*/
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	GradientIndexing(&vertexpidlist[0],control_index);
+	Input* drag_input    =inputs->GetInput(FrictionCoefficientEnum); _assert_(drag_input);
+	Input* vx_input      =inputs->GetInput(VxEnum);                  _assert_(vx_input);
+	Input* vy_input      =inputs->GetInput(VyEnum);                  _assert_(vy_input);
+	Input* vz_input      =inputs->GetInput(VzEnum);                  _assert_(vz_input);
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);            _assert_(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);            _assert_(adjointy_input);
+	Input* adjointz_input=inputs->GetInput(AdjointzEnum);            _assert_(adjointz_input);
+
+	/*Build frictoin element, needed later: */
+	friction=new Friction("3d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/*Recover alpha_complement and drag: */
+		friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum,VzEnum);
+		drag_input->GetInputValue(&drag,gauss);
+
+		/*recover lambda mu and xi: */
+		adjointx_input->GetInputValue(&lambda,gauss);
+		adjointy_input->GetInputValue(&mu    ,gauss);
+		adjointz_input->GetInputValue(&xi    ,gauss);
+
+		/*recover vx vy and vz: */
+		vx_input->GetInputValue(&vx, gauss);
+		vy_input->GetInputValue(&vy, gauss);
+		vz_input->GetInputValue(&vz, gauss);
+
+		/*Get normal vector to the bed */
+		SurfaceNormal(&surface_normal[0],xyz_list_tria);
+
+		bed_normal[0]=-surface_normal[0]; //Function is for upper 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: */
+		GetTriaJacobianDeterminant(&Jdet,&xyz_list_tria[0][0],gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		/*Get k derivative: dk/dx */
+		drag_input->GetInputDerivativeValue(&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*basis[i]; 
+		}
+
+		/*Add gradje_g_gaussian vector to gradje_g: */
+		for( i=0; i<NUMVERTICES; i++)grade_g[i]+=grade_g_gaussian[i];
+	}
+
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	delete friction;
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GradjBbarMacAyeal {{{*/
+void  Penta::GradjBbarMacAyeal(Vector<IssmDouble>* gradient,int control_index){
+
+	/*This element should be collapsed into a tria element at its base*/
+	if (!IsOnBed()) return; 
+
+	/*Depth Average B*/
+	this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+
+	/*Collapse element to the base*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria (lower face).
+	tria->GradjBMacAyeal(gradient,control_index);
+	delete tria->material; delete tria;
+
+	/*delete Average B*/
+	this->material->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+
+} /*}}}*/
+/*FUNCTION Penta::GradjBbarPattyn {{{*/
+void  Penta::GradjBbarPattyn(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Gradient is computed on bed only (Bbar)*/
+	if (!IsOnBed()) return;
+
+	/*Depth Average B*/
+	this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+
+	/*Collapse element to the base*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2);
+	tria->GradjBMacAyeal(gradient,control_index);    //We use MacAyeal as an estimate for now
+	delete tria->material; delete tria;
+
+	/*delete Average B*/
+	this->material->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+} /*}}}*/
+/*FUNCTION Penta::GradjBbarStokes {{{*/
+void  Penta::GradjBbarStokes(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Gradient is computed on bed only (Bbar)*/
+	if (!IsOnBed()) return;
+
+	/*Depth Average B*/
+	this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+
+	/*Collapse element to the base*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2);
+	tria->GradjBMacAyeal(gradient,control_index);    //We use MacAyeal as an estimate for now
+	delete tria->material; delete tria;
+
+	/*delete Average B*/
+	this->material->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+} /*}}}*/
+/*FUNCTION Penta::InputControlUpdate{{{*/
+void  Penta::InputControlUpdate(IssmDouble scalar,bool save_parameter){
+
+	/*Intermediary*/
+	int    num_controls;
+	int*   control_type=NULL;
+	Input* input=NULL;
+
+	/*retrieve some parameters: */
+	this->parameters->FindParam(&num_controls,InversionNumControlParametersEnum);
+	this->parameters->FindParam(&control_type,NULL,InversionControlParametersEnum);
+
+	for(int i=0;i<num_controls;i++){
+
+		if(control_type[i]==MaterialsRheologyBbarEnum){
+			if (!IsOnBed()) goto cleanup_and_return;
+			input=(Input*)material->inputs->GetInput(MaterialsRheologyBEnum); _assert_(input);
+		}
+		else if(control_type[i]==MaterialsRheologyZbarEnum){
+			if (!IsOnBed()) goto cleanup_and_return;
+			input=(Input*)material->inputs->GetInput(MaterialsRheologyZEnum); _assert_(input);
+		}
+		else{
+			input=(Input*)this->inputs->GetInput(control_type[i]); _assert_(input);
+		}
+
+		if (input->ObjectEnum()!=ControlInputEnum) _error_("input " << EnumToStringx(control_type[i]) << " is not a ControlInput");
+
+		((ControlInput*)input)->UpdateValue(scalar);
+		((ControlInput*)input)->Constrain();
+		if (save_parameter) ((ControlInput*)input)->SaveValue();
+
+		if(control_type[i]==MaterialsRheologyBbarEnum){
+			this->InputExtrude(MaterialsRheologyBEnum,MaterialsEnum);
+		}
+		else if(control_type[i]==MaterialsRheologyZbarEnum){
+			this->InputExtrude(MaterialsRheologyZEnum,MaterialsEnum);
+		}
+	}
+
+	/*Clean up and return*/
+cleanup_and_return:
+	xDelete<int>(control_type);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionAdjointStokes {{{*/
+void  Penta::InputUpdateFromSolutionAdjointStokes(IssmDouble* solution){
+
+	const int    numdof=NDOF4*NUMVERTICES;
+
+	int    i;
+	IssmDouble values[numdof];
+	IssmDouble lambdax[NUMVERTICES];
+	IssmDouble lambday[NUMVERTICES];
+	IssmDouble lambdaz[NUMVERTICES];
+	IssmDouble 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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(lambdax[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambday[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambdaz[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambdap[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(AdjointxEnum,lambdax));
+	this->inputs->AddInput(new PentaP1Input(AdjointyEnum,lambday));
+	this->inputs->AddInput(new PentaP1Input(AdjointzEnum,lambdaz));
+	this->inputs->AddInput(new PentaP1Input(AdjointpEnum,lambdap));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionAdjointHoriz {{{*/
+void  Penta::InputUpdateFromSolutionAdjointHoriz(IssmDouble* solution){
+
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int    i;
+	IssmDouble values[numdof];
+	IssmDouble lambdax[NUMVERTICES];
+	IssmDouble 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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(lambdax[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambday[i]))       _error_("NaN found in solution vector");
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(AdjointxEnum,lambdax));
+	this->inputs->AddInput(new PentaP1Input(AdjointyEnum,lambday));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceAverageVelMisfit {{{*/
+IssmDouble Penta::SurfaceAverageVelMisfit(bool process_units,int weight_index){
+
+	int    approximation;
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&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); //nodes 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceAverageVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceAverageVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceAbsVelMisfit {{{*/
+IssmDouble Penta::SurfaceAbsVelMisfit(bool process_units,int weight_index){
+
+	int    approximation;
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&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); //nodes 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceAbsVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceAbsVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceLogVelMisfit {{{*/
+IssmDouble Penta::SurfaceLogVelMisfit(bool process_units,int weight_index){
+
+	int    approximation;
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&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); //nodes 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceLogVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceLogVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceLogVxVyMisfit {{{*/
+IssmDouble Penta::SurfaceLogVxVyMisfit(bool process_units,int weight_index){
+
+	IssmDouble J;
+	Tria* tria=NULL;
+
+	/*inputs: */
+	int  approximation;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&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); //nodes 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceLogVxVyMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceLogVxVyMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::SurfaceRelVelMisfit {{{*/
+IssmDouble Penta::SurfaceRelVelMisfit(bool process_units,int weight_index){
+
+	int    approximation;
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&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); //nodes 0, 1 and 2 make the new tria (lower face).
+		J=tria->SurfaceRelVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+	else{
+
+		tria=(Tria*)SpawnTria(3,4,5); //nodes 3, 4 and 5 make the new tria (upper face).
+		J=tria->SurfaceRelVelMisfit(process_units,weight_index);
+		delete tria->material; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::ThicknessAbsGradient{{{*/
+IssmDouble Penta::ThicknessAbsGradient(bool process_units,int weight_index){
+
+	_error_("Not implemented yet");
+}
+/*}}}*/
+/*FUNCTION Penta::ThicknessAbsMisfit {{{*/
+IssmDouble Penta::ThicknessAbsMisfit(bool process_units,int weight_index){
+
+	int    approximation;
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*retrieve inputs :*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+	_error_("Not implemented yet");
+
+	tria=(Tria*)SpawnTria(0,1,2);
+	J=tria->ThicknessAbsMisfit(process_units,weight_index);
+	delete tria->material; delete tria;
+	return J;
+}
+/*}}}*/
+/*FUNCTION Penta::DragCoefficientAbsGradient{{{*/
+IssmDouble Penta::DragCoefficientAbsGradient(bool process_units,int weight_index){
+
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*If on water, on shelf or not on bed, skip: */
+	if(IsOnWater()|| IsFloating() || !IsOnBed()) return 0;
+
+	tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria
+	J=tria->DragCoefficientAbsGradient(process_units,weight_index);
+	delete tria->material; delete tria;
+	return J;
+}
+/*}}}*/
+/*FUNCTION Penta::RheologyBbarAbsGradient{{{*/
+IssmDouble Penta::RheologyBbarAbsGradient(bool process_units,int weight_index){
+
+	IssmDouble J;
+	Tria*  tria=NULL;
+
+	/*If on water, on shelf or not on bed, skip: */
+	if(IsOnWater() || !IsOnBed()) return 0;
+
+	tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria
+	J=tria->RheologyBbarAbsGradient(process_units,weight_index);
+	delete tria->material; delete tria;
+	return J;
+}
+/*}}}*/
+/*FUNCTION Penta::GetVectorFromControlInputs{{{*/
+void  Penta::GetVectorFromControlInputs(Vector<IssmDouble>* vector,int control_enum,int control_index,const char* data){
+
+	int vertexpidlist[NUMVERTICES];
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(control_enum)) return;
+
+	/*Prepare index list*/
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Get input (either in element or material)*/
+	Input* input=inputs->GetInput(control_enum);
+	if(!input) _error_("Input " << EnumToStringx(control_enum) << " not found in element");
+
+	/*Check that it is a ControlInput*/
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error_("input " << EnumToStringx(control_enum) << " is not a ControlInput");
+	}
+
+	((ControlInput*)input)->GetVectorFromInputs(vector,&vertexpidlist[0],data);
+}
+/*}}}*/
+/*FUNCTION Penta::SetControlInputsFromVector{{{*/
+void  Penta::SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index){
+
+	IssmDouble  values[NUMVERTICES];
+	int     vertexpidlist[NUMVERTICES];
+	Input  *input     = NULL;
+	Input  *new_input = NULL;
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(control_enum)) return;
+
+	/*Prepare index list*/
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Get values on vertices*/
+	for (int i=0;i<NUMVERTICES;i++){
+		values[i]=vector[vertexpidlist[i]];
+	}
+	new_input = new PentaP1Input(control_enum,values);
+
+	if(control_enum==MaterialsRheologyBbarEnum){
+		input=(Input*)material->inputs->GetInput(control_enum); _assert_(input);
+	}
+	else{
+		input=(Input*)this->inputs->GetInput(control_enum);   _assert_(input);
+	}
+
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error_("input " << EnumToStringx(control_enum) << " is not a ControlInput");
+	}
+
+	((ControlInput*)input)->SetInput(new_input);
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_DAKOTA_
+/*FUNCTION Penta::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+
+	int i,j;
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			/*New PentaP1Input*/
+			IssmDouble values[6];
+
+			/*Get values on the 6 vertices*/
+			for (i=0;i<6;i++){
+				values[i]=vector[this->nodes[i]->GetVertexSid()]; //careful, vector of values here is not parallel distributed, but serial distributed (from a serial Dakota core!)
+			}
+
+			/*Branch on the specified type of update: */
+			switch(name){
+				case ThicknessEnum:
+					/*Update thickness + surface: assume bed is constant. On ice shelves, takes hydrostatic equilibrium {{{*/
+					IssmDouble  thickness[6];
+					IssmDouble  thickness_init[6];
+					IssmDouble  hydrostatic_ratio[6];
+					IssmDouble  surface[6];
+					IssmDouble  bed[6];
+
+					/*retrieve inputs: */
+					GetInputListOnVertices(&thickness_init[0],ThicknessEnum);
+					GetInputListOnVertices(&hydrostatic_ratio[0],GeometryHydrostaticRatioEnum);
+					GetInputListOnVertices(&bed[0],BedEnum);
+					GetInputListOnVertices(&surface[0],SurfaceEnum);
+
+					/*build new thickness: */
+//					for(j=0;j<6;j++)thickness[j]=values[j];
+
+					/*build new bed and surface: */
+					if (this->IsFloating()){
+						/*hydrostatic equilibrium: */
+						IssmDouble rho_ice,rho_water,di;
+						rho_ice=this->matpar->GetRhoIce();
+						rho_water=this->matpar->GetRhoWater();
+
+						di=rho_ice/rho_water;
+
+						/*build new thickness: */
+						for (j=0; j<6; j++) {
+						/*  for observed/interpolated/hydrostatic thickness, remove scaling from any hydrostatic thickness  */
+							if     (hydrostatic_ratio[j] >= 0.)
+								thickness[j]=values[j]-(values[j]/thickness_init[j]-1.)*hydrostatic_ratio[j]*surface[j]/(1.-di);
+						/*  for minimum thickness, don't scale  */
+							else
+								thickness[j]=thickness_init[j];
+
+						/*  check the computed thickness and update bed  */
+							if (thickness[j] < 0.)
+								thickness[j]=1./(1.-di);
+							bed[j]=surface[j]-thickness[j];
+						}
+
+//						for(j=0;j<6;j++){
+//							surface[j]=(1-di)*thickness[j];
+//							bed[j]=-di*thickness[j];
+//						}
+					}
+					else{
+						/*build new thickness: */
+						for (j=0; j<6; j++) {
+						/*  for observed thickness, use scaled value  */
+							if(hydrostatic_ratio[j] >= 0.)
+								thickness[j]=values[j];
+						/*  for minimum thickness, don't scale  */
+							else
+								thickness[j]=thickness_init[j];
+						}
+
+						/*update bed on grounded ice: */
+//						for(j=0;j<6;j++)surface[j]=bed[j]+thickness[j];
+						for(j=0;j<6;j++)bed[j]=surface[j]-thickness[j];
+					}
+
+					/*Add new inputs: */
+					this->inputs->AddInput(new PentaP1Input(ThicknessEnum,thickness));
+					this->inputs->AddInput(new PentaP1Input(BedEnum,bed));
+					this->inputs->AddInput(new PentaP1Input(SurfaceEnum,surface));
+
+					/*}}}*/
+					break;
+				default:
+					this->inputs->AddInput(new PentaP1Input(name,values));
+			}
+			break;
+
+		default:
+			_error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVectorDakota(int* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type);{{{*/
+void  Penta::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){
+
+	int i,j,t;
+	TransientInput* transientinput=NULL;
+	IssmDouble values[6];
+	IssmDouble time;
+	int row;
+	IssmDouble yts;
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			/*Create transient input: */
+
+			parameters->FindParam(&yts,ConstantsYtsEnum);
+
+			for(t=0;t<ncols;t++){ //ncols is the number of times
+
+				/*create input values: */
+				for(i=0;i<6;i++){
+					row=this->nodes[i]->GetVertexSid();
+					values[i]=(IssmDouble)matrix[ncols*row+t];
+				}
+
+				/*time? :*/
+				time=(IssmDouble)matrix[(nrows-1)*ncols+t]*yts;
+
+				if(t==0) transientinput=new TransientInput(name);
+				transientinput->AddTimeInput(new PentaP1Input(name,values),time);
+				transientinput->Configure(parameters);
+			}
+			this->inputs->AddInput(transientinput);
+			break;
+
+		default:
+			_error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_DIAGNOSTIC_
+/*FUNCTION Penta::CreateDVectorDiagnosticHoriz {{{*/
+ElementVector* Penta::CreateDVectorDiagnosticHoriz(void){
+
+	int approximation;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case StokesApproximationEnum:
+			return CreateDVectorDiagnosticStokes();
+		default:
+			return NULL; //no need for doftypes outside of stokes approximation
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateDVectorDiagnosticStokes{{{*/
+ElementVector* Penta::CreateDVectorDiagnosticStokes(void){
+
+	/*output: */
+	ElementVector* De=NULL;
+	/*intermediary: */
+	int approximation;
+	int i;
+
+	/*Initialize Element vector and return if necessary*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation!=StokesApproximationEnum) return NULL;
+
+	De=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	for (i=0;i<NUMVERTICES;i++){
+		De->values[i*4+0]=VelocityEnum;
+		De->values[i*4+1]=VelocityEnum;
+		De->values[i*4+2]=VelocityEnum;
+		De->values[i*4+3]=PressureEnum;
+	}
+
+	return De;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattyn{{{*/
+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{{{*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynViscous(void){
+
+	/*Constants*/
+	const int numnodes    = 2 *NUMVERTICES;
+	const int numdofm     = NDOF2 *NUMVERTICES2D;
+	const int numdofp     = NDOF2 *NUMVERTICES;
+	const int numdoftotal = 2 *NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int         i,j;
+	IssmDouble  Jdet;
+	IssmDouble  viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
+	IssmDouble  epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  B[3][numdofp];
+	IssmDouble  Bprime[3][numdofm];
+	IssmDouble  D[3][3]={0.0};            // material matrix, simple scalar matrix.
+	IssmDouble  D_scalar;
+	IssmDouble  Ke_gg[numdofp][numdofm]={0.0}; //local element stiffness matrix 
+	IssmDouble  Ke_gg_gaussian[numdofp][numdofm]; //stiffness matrix evaluated at the gaussian point.
+	GaussPenta *gauss=NULL;
+	GaussTria  *gauss_tria=NULL;
+	Node       *node_list[numnodes];
+	int         cs_list[numnodes];
+
+	/*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); //nodes 0, 1 and 2 make the new tria.
+
+	/*Prepare node list*/
+	for(i=0;i<NUMVERTICES;i++){
+		node_list[i+0*NUMVERTICES] = pentabase->nodes[i];
+		node_list[i+1*NUMVERTICES] = this->nodes[i];
+		cs_list[i+0*NUMVERTICES] = XYEnum;
+		cs_list[i+1*NUMVERTICES] = XYEnum;
+	}
+
+	/*Initialize Element matrix*/
+	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],vertices,NUMVERTICES);
+	this->parameters->FindParam(&viscosity_overshoot,DiagnosticViscosityOvershootEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vxold_input=inputs->GetInput(VxPicardEnum); _assert_(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyPicardEnum); _assert_(vyold_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	gauss_tria=new GaussTria();
+	for(int 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);
+		material->GetViscosity3d(&viscosity, &epsilon[0]);
+		material->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];
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,node_list,numnodes,cs_list);
+
+	/*Clean-up and return*/
+	delete tria->material; delete tria;
+	delete gauss;
+	delete gauss_tria;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealPattynFriction{{{*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealPattynFriction(void){
+
+	/*Constants*/
+	const int numnodes    = 2 *NUMVERTICES;
+	const int numdof      = NDOF2 *NUMVERTICES;
+	const int numdoftotal = NDOF4 *NUMVERTICES;
+
+	/*Intermediaries */
+	int       i,j,analysis_type;
+	IssmDouble Jdet2d,slope_magnitude,alpha2;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble slope[3]={0.0,0.0,0.0};
+	IssmDouble MAXSLOPE=.06; // 6 %
+	IssmDouble MOUNTAINKEXPONENT=10;
+	IssmDouble L[2][numdof];
+	IssmDouble DL[2][2]                  ={{ 0,0 },{0,0}}; //for basal drag
+	IssmDouble DL_scalar;
+	IssmDouble Ke_gg[numdof][numdof]     ={0.0};
+	IssmDouble Ke_gg_gaussian[numdof][numdof]; //stiffness matrix contribution from drag
+	Friction  *friction = NULL;
+	GaussPenta *gauss=NULL;
+	Node       *node_list[numnodes];
+	int         cs_list[numnodes];
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsFloating() || !IsOnBed()) 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;
+
+	/*Prepare node list*/
+	for(i=0;i<NUMVERTICES;i++){
+		node_list[i+0*NUMVERTICES] = this->nodes[i];
+		node_list[i+1*NUMVERTICES] = this->nodes[i];
+		cs_list[i+0*NUMVERTICES] = XYEnum;
+		cs_list[i+1*NUMVERTICES] = XYEnum;
+	}
+
+	/*retrieve inputs :*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); _assert_(surface_input);
+	Input* vx_input=inputs->GetInput(VxEnum);           _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);           _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);           _assert_(vz_input);
+
+	/*build friction object, used later on: */
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int 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->GetInputDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
+
+		if (slope_magnitude>MAXSLOPE){
+			alpha2=pow((IssmDouble)10,MOUNTAINKEXPONENT);
+		}
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		GetL(&L[0][0], gauss,NDOF2);
+
+		DL_scalar=alpha2*gauss->weight*Jdet2d;
+		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];
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,node_list,numnodes,cs_list);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealStokes{{{*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealStokes(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixCouplingMacAyealStokesViscous();
+	ElementMatrix* Ke2=CreateKMatrixCouplingMacAyealStokesFriction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealStokesViscous{{{*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealStokesViscous(void){
+
+	/*Constants*/
+	const int numnodes    = 2 *NUMVERTICES;
+	const int numdofm     = NDOF2 *NUMVERTICES2D;
+	const int numdofs     = NDOF4 *NUMVERTICES;
+	const int numdoftotal = 2 *numdofm+numdofs;
+
+	/*Intermediaries */
+	int         i,j;
+	IssmDouble Jdet;
+	IssmDouble viscosity,stokesreconditioning; //viscosity
+	IssmDouble epsilon[6]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble B[4][numdofs+3];
+	IssmDouble Bprime[4][numdofm];
+	IssmDouble B2[3][numdofm];
+	IssmDouble Bprime2[3][numdofs+3];
+	IssmDouble D[4][4]={0.0};            // material matrix, simple scalar matrix.
+	IssmDouble D2[3][3]={0.0};            // material matrix, simple scalar matrix.
+	IssmDouble D_scalar;
+	IssmDouble Ke_gg[numdofs][numdofm]={0.0}; //local element stiffness matrix 
+	IssmDouble Ke_gg2[numdofm][numdofs]={0.0}; //local element stiffness matrix 
+	IssmDouble Ke_gg_gaussian[numdofs+3][numdofm]; //stiffness matrix evaluated at the gaussian point.
+	IssmDouble Ke_gg_gaussian2[numdofm][numdofs+3]; //stiffness matrix evaluated at the gaussian point.
+	GaussPenta *gauss=NULL;
+	GaussTria  *gauss_tria=NULL;
+	Node       *node_list[numnodes];
+	int         cs_list[numnodes];
+
+	/*Find penta on bed as stokes must be coupled to the dofs on the bed: */
+	Penta* pentabase=GetBasalElement();
+	Tria* tria=pentabase->SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+
+	/*Prepare node list*/
+	for(i=0;i<NUMVERTICES;i++){
+		node_list[i+0*NUMVERTICES] = pentabase->nodes[i];
+		node_list[i+1*NUMVERTICES] = this->nodes[i];
+		cs_list[i+0*NUMVERTICES] = XYEnum;
+		cs_list[i+1*NUMVERTICES] = XYZPEnum;
+	}
+
+	/*Initialize Element matrix and return if necessary*/
+	ElementMatrix* Ke1=new ElementMatrix(pentabase->nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+	ElementMatrix* Ke2=new ElementMatrix(this->nodes     ,NUMVERTICES,this->parameters,StokesApproximationEnum);
+	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
+	delete Ke1; delete Ke2;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);       _assert_(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	gauss_tria=new GaussTria();
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		gauss->SynchronizeGaussTria(gauss_tria);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBMacAyealStokes(&B[0][0], &xyz_list[0][0], gauss);
+		tria->GetBprimeMacAyealStokes(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
+		tria->GetBMacAyealStokes(&B2[0][0], &xyz_list[0][0], gauss_tria);
+		GetBprimeMacAyealStokes(&Bprime2[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity, &epsilon[0]);
+
+		D_scalar=2*viscosity*gauss->weight*Jdet;
+		for (i=0;i<3;i++) D[i][i]=D_scalar;
+		D[3][3]=-gauss->weight*Jdet*stokesreconditioning;
+		for (i=0;i<3;i++) D2[i][i]=D_scalar;
+
+		TripleMultiply( &B[0][0],4,numdofs+3,1,
+					&D[0][0],4,4,0,
+					&Bprime[0][0],4,numdofm,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		TripleMultiply( &B2[0][0],3,numdofm,1,
+					&D2[0][0],3,3,0,
+					&Bprime2[0][0],3,numdofs+3,0,
+					&Ke_gg_gaussian2[0][0],0);
+
+		for( i=0; i<numdofs; i++) for(j=0;j<numdofm; j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
+		for( i=0; i<numdofm; i++) for(j=0;j<numdofs; j++) Ke_gg2[i][j]+=Ke_gg_gaussian2[i][j];
+	} 
+	for(i=0;i<numdofs;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<numdofs;j++) Ke->values[i*numdoftotal+(j+2*numdofm)]+=Ke_gg2[i][j];
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,node_list,numnodes,cs_list);
+
+	/*Clean-up and return*/
+	delete tria->material; delete tria;
+	delete gauss;
+	delete gauss_tria;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingMacAyealStokesFriction {{{*/
+ElementMatrix* Penta::CreateKMatrixCouplingMacAyealStokesFriction(void){
+
+	/*Constants*/
+	const int numnodes  = 2 *NUMVERTICES;
+	const int numdof    = NUMVERTICES *NDOF4;
+	const int numdofm   = NUMVERTICES *NDOF2;
+	const int numdof2d  = NUMVERTICES2D *NDOF4;
+	const int numdof2dm = NUMVERTICES2D *NDOF2;
+	const int numdoftot = numdof+numdofm;
+
+	/*Intermediaries */
+	int        i,j;
+	int        analysis_type,approximation;
+	IssmDouble stokesreconditioning;
+	IssmDouble viscosity,alpha2_gauss,Jdet2d;
+	IssmDouble bed_normal[3];
+	IssmDouble epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble LMacAyealStokes[8][numdof2dm];
+	IssmDouble LprimeMacAyealStokes[8][numdof2d];
+	IssmDouble DLMacAyealStokes[8][8]={0.0};
+	IssmDouble LStokesMacAyeal[4][numdof2d];
+	IssmDouble LprimeStokesMacAyeal[4][numdof2dm];
+	IssmDouble DLStokesMacAyeal[4][4]={0.0};
+	IssmDouble Ke_drag_gaussian[numdof2dm][numdof2d];
+	IssmDouble Ke_drag_gaussian2[numdof2d][numdof2dm];
+	Friction*  friction=NULL;
+	GaussPenta *gauss=NULL;
+	Node       *node_list[numnodes];
+	int         cs_list[numnodes];
+
+	/*If on water or not Stokes, skip stiffness: */
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(IsFloating() || !IsOnBed()) return NULL;
+	ElementMatrix* Ke1=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+	ElementMatrix* Ke2=new ElementMatrix(this->nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+	ElementMatrix* Ke=new ElementMatrix(Ke1,Ke2);
+	delete Ke1; delete Ke2;
+
+	/*Prepare node list*/
+	for(i=0;i<NUMVERTICES;i++){
+		node_list[i+0*NUMVERTICES] = this->nodes[i];
+		node_list[i+1*NUMVERTICES] = this->nodes[i];
+		cs_list[i+0*NUMVERTICES] = XYEnum;
+		cs_list[i+1*NUMVERTICES] = XYZPEnum;
+	}
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); _assert_(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(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		GetLMacAyealStokes(&LMacAyealStokes[0][0], gauss);
+		GetLprimeMacAyealStokes(&LprimeMacAyealStokes[0][0], &xyz_list[0][0], gauss);
+		GetLStokesMacAyeal(&LStokesMacAyeal[0][0], gauss);
+		GetLprimeStokesMacAyeal(&LprimeStokesMacAyeal[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		BedNormal(&bed_normal[0],xyz_list_tria);
+		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
+
+		DLMacAyealStokes[0][0]=alpha2_gauss*gauss->weight*Jdet2d;
+		DLMacAyealStokes[1][1]=alpha2_gauss*gauss->weight*Jdet2d;
+		DLMacAyealStokes[2][2]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
+		DLMacAyealStokes[3][3]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
+		DLMacAyealStokes[4][4]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[0];
+		DLMacAyealStokes[5][5]=-2*viscosity*gauss->weight*Jdet2d*bed_normal[1];
+		DLMacAyealStokes[6][6]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[0];
+		DLMacAyealStokes[7][7]=stokesreconditioning*gauss->weight*Jdet2d*bed_normal[1];
+
+		DLStokesMacAyeal[0][0]=alpha2_gauss*gauss->weight*Jdet2d;
+		DLStokesMacAyeal[1][1]=alpha2_gauss*gauss->weight*Jdet2d;
+		DLStokesMacAyeal[2][2]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[0]*bed_normal[2];
+		DLStokesMacAyeal[3][3]=-alpha2_gauss*gauss->weight*Jdet2d*bed_normal[1]*bed_normal[2];
+
+		TripleMultiply( &LMacAyealStokes[0][0],8,numdof2dm,1,
+					&DLMacAyealStokes[0][0],8,8,0,
+					&LprimeMacAyealStokes[0][0],8,numdof2d,0,
+					&Ke_drag_gaussian[0][0],0);
+
+		TripleMultiply( &LStokesMacAyeal[0][0],4,numdof2d,1,
+					&DLStokesMacAyeal[0][0],4,4,0,
+					&LprimeStokesMacAyeal[0][0],4,numdof2dm,0,
+					&Ke_drag_gaussian2[0][0],0);
+
+		for(i=0;i<numdof2dm;i++) for(j=0;j<numdof2d;j++) Ke->values[i*numdoftot+j+numdofm]+=Ke_drag_gaussian[i][j];
+		for(i=0;i<numdof2d;i++) for(j=0;j<numdof2dm;j++) Ke->values[(i+numdofm)*numdoftot+j]+=Ke_drag_gaussian2[i][j];
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,node_list,numnodes,cs_list);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixCouplingPattynStokes{{{*/
+ElementMatrix* Penta::CreateKMatrixCouplingPattynStokes(void){
+
+	/*Constants*/
+	const int numnodes  = 2 *NUMVERTICES;
+	const int numdofp     = NDOF2 *NUMVERTICES;
+	const int numdofs     = NDOF4 *NUMVERTICES;
+	const int numdoftotal = (NDOF2+NDOF4) *NUMVERTICES;
+
+	/*Intermediaries*/
+	Node     *node_list[numnodes];
+	int       cs_list[numnodes];
+	int       i,j;
+
+	/*Prepare node list*/
+	for(i=0;i<NUMVERTICES;i++){
+		node_list[i+0*NUMVERTICES] = this->nodes[i];
+		node_list[i+1*NUMVERTICES] = this->nodes[i];
+		cs_list[i+0*NUMVERTICES] = XYEnum;
+		cs_list[i+1*NUMVERTICES] = XYZPEnum;
+	}
+
+	/*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(); TransformInvStiffnessMatrixCoord(Ke1,this->nodes,NUMVERTICES,XYEnum);
+	Ke2=CreateKMatrixDiagnosticStokes(); TransformInvStiffnessMatrixCoord(Ke2,this->nodes,NUMVERTICES,XYZPEnum);
+
+	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];
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,node_list,numnodes,cs_list);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticHoriz {{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticHoriz(void){
+
+	int approximation;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreateKMatrixDiagnosticMacAyeal2d();
+		case L1L2ApproximationEnum:
+			return CreateKMatrixDiagnosticL1L2();
+		case PattynApproximationEnum:
+			return CreateKMatrixDiagnosticPattyn();
+		case StokesApproximationEnum:
+			return CreateKMatrixDiagnosticStokes();
+		case HutterApproximationEnum:
+			return NULL;
+		case NoneApproximationEnum:
+			return NULL;
+		case MacAyealPattynApproximationEnum:
+			return CreateKMatrixDiagnosticMacAyealPattyn();
+		case MacAyealStokesApproximationEnum:
+			return CreateKMatrixDiagnosticMacAyealStokes();
+		case PattynStokesApproximationEnum:
+			return CreateKMatrixDiagnosticPattynStokes();
+		default:
+			_error_("Approximation " << EnumToStringx(approximation) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticHutter{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticHutter(void){
+
+	/*Constants*/
+	const int numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int         connectivity[2];
+	int         i,i0,i1,j0,j1;
+	IssmDouble  one0,one1;
+
+	/*Initialize Element matrix*/
+	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/(IssmDouble)connectivity[0];
+		one1=1/(IssmDouble)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{{{*/
+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 nodes, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed()) return NULL;
+
+	/*Depth average some fields*/
+	switch(this->material->ObjectEnum()){
+		case MaticeEnum:
+			this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+			break;
+		case MatdamageiceEnum:
+			this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+			this->InputDepthAverageAtBase(MaterialsRheologyZEnum,MaterialsRheologyZbarEnum,MaterialsEnum);
+			break;
+		default:
+			_error_("material "<<EnumToStringx(this->material->ObjectEnum())<<" not supported");
+	}
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyeal();
+	delete tria->material; delete tria;
+
+	/*Delete averaged fields*/
+	this->material->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+	this->material->inputs->DeleteInput(MaterialsRheologyZbarEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3d{{{*/
+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{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dViscous(void){
+
+	/*Constants*/
+	const int    numdof2d=2*NUMVERTICES2D;
+
+	/*Intermediaries */
+	int         i,j,approximation;
+	IssmDouble  Jdet;
+	IssmDouble  viscosity , oldviscosity, newviscosity, viscosity_overshoot;
+	IssmDouble  epsilon[5],oldepsilon[5];       /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble  epsilons[6];                    //6 for stokes
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  B[3][numdof2d];
+	IssmDouble  Bprime[3][numdof2d];
+	IssmDouble  D[3][3]= {0.0};                 // material matrix, simple scalar matrix.
+	IssmDouble  D_scalar;
+	IssmDouble  Ke_gg_gaussian[numdof2d][numdof2d];
+	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); //nodes 0, 1 and 2 make the new tria.
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(tria->nodes,NUMVERTICES2D,this->parameters,MacAyealApproximationEnum);
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&viscosity_overshoot,DiagnosticViscosityOvershootEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vxold_input=inputs->GetInput(VxPicardEnum); _assert_(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyPicardEnum); _assert_(vyold_input);
+	Input* vz_input=inputs->GetInput(VzEnum);       _assert_(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	gauss_tria=new GaussTria();
+	for(int 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);
+
+		if(approximation==MacAyealPattynApproximationEnum){
+			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);
+			material->GetViscosity3d(&viscosity, &epsilon[0]);
+			material->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
+
+			newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+		}
+		else if (approximation==MacAyealStokesApproximationEnum){
+			this->GetStrainRate3d(&epsilons[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+			material->GetViscosity3dStokes(&newviscosity,&epsilons[0]);
+		}
+		else _error_("approximation " << approximation << " (" << EnumToStringx(approximation) << ") not supported yet");
+
+		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];
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,tria->nodes,NUMVERTICES2D,XYEnum);
+
+	/*Clean up and return*/
+	delete tria->material;
+	delete tria;
+	delete gauss_tria;
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyeal3dFriction{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyeal3dFriction(void){
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsFloating() || !IsOnBed()) return NULL;
+
+	/*Build a tria element using the 3 nodes of the base of the penta. Then use 
+	 * the tria functionality to build a friction stiffness matrix on these 3
+	 * nodes: */
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyealFriction();
+	delete tria->material; delete tria;
+
+	/*clean-up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticMacAyealPattyn{{{*/
+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::CreateKMatrixDiagnosticMacAyealStokes{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticMacAyealStokes(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticMacAyeal3d();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticStokes();
+	ElementMatrix* Ke3=CreateKMatrixCouplingMacAyealStokes();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2,Ke3);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	delete Ke3;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticL1L2{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticL1L2(void){
+
+	/*compute all stiffness matrices for this element*/
+	ElementMatrix* Ke1=CreateKMatrixDiagnosticL1L2Viscous();
+	ElementMatrix* Ke2=CreateKMatrixDiagnosticL1L2Friction();
+	ElementMatrix* Ke =new ElementMatrix(Ke1,Ke2);
+
+	/*clean-up and return*/
+	delete Ke1;
+	delete Ke2;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticL1L2Viscous{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticL1L2Viscous(void){
+
+	/*Constants*/
+	const int    numdof2d=2*NUMVERTICES2D;
+
+	/*Intermediaries */
+	int         i,j;
+	IssmDouble  Jdet,viscosity;
+	IssmDouble  epsilon[5];       /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  B[3][numdof2d];
+	IssmDouble  Bprime[3][numdof2d];
+	IssmDouble  Ke_gg_gaussian[numdof2d][numdof2d];
+	IssmDouble  D[3][3]= {0.0};                 // material matrix, simple scalar matrix.
+	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); //nodes 0, 1 and 2 make the new tria.
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(tria->nodes,NUMVERTICES2D,this->parameters,L1L2ApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* surf_input=inputs->GetInput(SurfaceEnum); _assert_(surf_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	gauss_tria=new GaussTria();
+	for(int 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);
+
+		/*Get viscosity for L1L2 model*/
+		GetL1L2Viscosity(&viscosity,&xyz_list[0][0],gauss,vx_input,vy_input,surf_input);
+
+		for(i=0;i<3;i++) D[i][i]=2*viscosity*gauss->weight*Jdet;
+
+		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];
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,tria->nodes,NUMVERTICES2D,XYEnum);
+
+	/*Clean up and return*/
+	delete tria->material;
+	delete tria;
+	delete gauss_tria;
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticL1L2Friction{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticL1L2Friction(void){
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsFloating() || !IsOnBed()) return NULL;
+
+	/*Build a tria element using the 3 nodes of the base of the penta. Then use 
+	 * the tria functionality to build a friction stiffness matrix on these 3
+	 * nodes: */
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixDiagnosticMacAyealFriction();
+	delete tria->material; delete tria;
+
+	/*clean-up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattyn{{{*/
+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{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticPattynViscous(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	int        approximation;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet;
+	IssmDouble viscosity,oldviscosity,newviscosity,viscosity_overshoot; //viscosity
+	IssmDouble epsilon[5],oldepsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble D_scalar;
+	IssmDouble D[5][5]={0.0};            // material matrix, simple scalar matrix.
+	IssmDouble B[5][numdof];
+	IssmDouble Bprime[5][numdof];
+	Tria*      tria=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&viscosity_overshoot,DiagnosticViscosityOvershootEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vxold_input=inputs->GetInput(VxPicardEnum); _assert_(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyPicardEnum); _assert_(vyold_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int 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);
+		material->GetViscosity3d(&viscosity, &epsilon[0]);
+		material->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->values[0],1);
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattynFriction{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticPattynFriction(void){
+
+	/*Constants*/
+	const int numdof   = NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int       i,j;
+	int       analysis_type,migration_style;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble slope_magnitude,alpha2,Jdet;
+	IssmDouble phi=1.0;
+	IssmDouble slope[3]={0.0,0.0,0.0};
+	IssmDouble MAXSLOPE=.06; // 6 %
+	IssmDouble MOUNTAINKEXPONENT=10;
+	IssmDouble L[2][numdof];
+	IssmDouble DL[2][2]={{ 0,0 },{0,0}}; //for basal drag
+	IssmDouble DL_scalar;
+	Friction  *friction = NULL;
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsFloating() || !IsOnBed()) return NULL;
+
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	parameters->FindParam(&migration_style,GroundinglineMigrationEnum);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum); _assert_(surface_input);
+	Input* vx_input=inputs->GetInput(VxEnum);           _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);           _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);           _assert_(vz_input);
+
+	/*build friction object, used later on: */
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/*Recover portion of element that is grounded*/
+	if(migration_style==SubelementMigrationEnum) phi=this->GetGroundedPortion(&xyz_list[0][0]);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet, &xyz_list_tria[0][0],gauss);
+		GetL(&L[0][0], gauss,NDOF2);
+
+		surface_input->GetInputDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum); 
+		slope_magnitude=sqrt(pow(slope[0],2)+pow(slope[1],2));
+		if(migration_style==SubelementMigrationEnum) alpha2=phi*alpha2;
+
+		// 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((IssmDouble)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->values[0],1);
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticPattynStokes{{{*/
+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{{{*/
+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 {{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticStokesViscous(void){
+
+	/*Intermediaries */
+	int        i,approximation;
+	IssmDouble Jdet,viscosity,stokesreconditioning;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble B[8][27];
+	IssmDouble B_prime[8][27];
+	IssmDouble D_scalar;
+	IssmDouble D[8][8]={0.0};
+	IssmDouble Ke_temp[27][27]={0.0}; //for the six nodes and the bubble 
+	GaussPenta *gauss=NULL;
+
+	/*If on water or not Stokes, skip stiffness: */
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation!=StokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); _assert_(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int 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);
+		material->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_temp[0][0],1);
+	}
+
+	/*Condensation*/
+	ReduceMatrixStokes(Ke->values, &Ke_temp[0][0]);
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticStokesFriction{{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticStokesFriction(void){
+
+	/*Constants*/
+	const int numdof=NUMVERTICES*NDOF4;
+	const int numdof2d=NUMVERTICES2D*NDOF4;
+
+	/*Intermediaries */
+	int        i,j;
+	int        analysis_type,approximation;
+	IssmDouble alpha2,Jdet2d;
+	IssmDouble stokesreconditioning,viscosity;
+	IssmDouble epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble LStokes[2][numdof2d];
+	IssmDouble DLStokes[2][2]={0.0};
+	IssmDouble Ke_drag_gaussian[numdof2d][numdof2d];
+	Friction*  friction=NULL;
+	GaussPenta *gauss=NULL;
+
+	/*If on water or not Stokes, skip stiffness: */
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(IsFloating() || !IsOnBed() || (approximation!=StokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum &&  approximation!=PattynStokesApproximationEnum)) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum); _assert_(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(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		GetLStokes(&LStokes[0][0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
+
+		DLStokes[0][0] = +alpha2*gauss->weight*Jdet2d; //taub_x = -alpha2 vx
+		DLStokes[1][1] = +alpha2*gauss->weight*Jdet2d; //taub_y = -alpha2 vy
+
+		TripleMultiply( &LStokes[0][0],2,numdof2d,1,
+					&DLStokes[0][0],2,2,0,
+					&LStokes[0][0],2,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];
+	}
+
+	/*DO NOT Transform Coordinate System: this stiffness matrix is already expressed in tangential coordinates*/
+	//TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticVert {{{*/
+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 {{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticVertVolume(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble  Jdet;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  B[NDOF1][NUMVERTICES];
+	IssmDouble  Bprime[NDOF1][NUMVERTICES];
+	IssmDouble  DL_scalar;
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for(int 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->values[0],1);
+	} 
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixDiagnosticVertSurface {{{*/
+ElementMatrix* Penta::CreateKMatrixDiagnosticVertSurface(void){
+
+	if (!IsOnSurface()) return NULL;
+
+	/*Constants*/
+	const int numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int       i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble surface_normal[3];
+	IssmDouble Jdet2d,DL_scalar;
+	IssmDouble basis[NUMVERTICES];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i+3][j];
+	SurfaceNormal(&surface_normal[0],xyz_list_tria);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(3,4,5,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		DL_scalar= - gauss->weight*Jdet2d*surface_normal[2]; 
+
+		TripleMultiply( basis,1,numdof,1,
+					&DL_scalar,1,1,0,
+					basis,1,numdof,0,
+					&Ke->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingMacAyealStokes {{{*/
+ElementVector* Penta::CreatePVectorCouplingMacAyealStokes(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorCouplingMacAyealStokesViscous();
+	ElementVector* pe2=CreatePVectorCouplingMacAyealStokesFriction();
+	ElementVector* pe =new ElementVector(pe1,pe2);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingMacAyealStokesViscous {{{*/
+ElementVector* Penta::CreatePVectorCouplingMacAyealStokesViscous(void){
+
+	/*Constants*/
+	const int   numdof=NUMVERTICES*NDOF4;
+
+	/*Intermediaries */
+	int         i,j;
+	int         approximation;
+	IssmDouble  viscosity,Jdet;
+	IssmDouble  stokesreconditioning;
+	IssmDouble  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble  dw[3];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[6]; //for the six nodes of the penta
+	IssmDouble  dbasis[3][6]; //for the six nodes of the penta
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation!=MacAyealStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);               _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);               _assert_(vz_input);
+	Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);   _assert_(vzmacayeal_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+		GetNodalFunctionsP1Derivatives(&dbasis[0][0],&xyz_list[0][0], gauss);
+
+		vzmacayeal_input->GetInputDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		for(i=0;i<NUMVERTICES;i++){
+			pe->values[i*NDOF4+0]+=-Jdet*gauss->weight*viscosity*dw[0]*dbasis[2][i];
+			pe->values[i*NDOF4+1]+=-Jdet*gauss->weight*viscosity*dw[1]*dbasis[2][i];
+			pe->values[i*NDOF4+2]+=-Jdet*gauss->weight*viscosity*(dw[0]*dbasis[0][i]+dw[1]*dbasis[1][i]+2*dw[2]*dbasis[2][i]);
+			pe->values[i*NDOF4+3]+=Jdet*gauss->weight*stokesreconditioning*dw[2]*basis[i];
+		}
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingMacAyealStokesFriction{{{*/
+ElementVector* Penta::CreatePVectorCouplingMacAyealStokesFriction(void){
+
+	/*Constants*/
+	const int numdof=NUMVERTICES*NDOF4;
+
+	/*Intermediaries*/
+	int         i,j;
+	int         approximation,analysis_type;
+	IssmDouble  Jdet,Jdet2d;
+	IssmDouble  stokesreconditioning;
+	IssmDouble	bed_normal[3];
+	IssmDouble  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble  viscosity, w, alpha2_gauss;
+	IssmDouble  dw[3];
+	IssmDouble	xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[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(!IsOnBed() || IsFloating()) return NULL;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation!=MacAyealStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);               _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);               _assert_(vz_input);
+	Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);   _assert_(vzmacayeal_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(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		vzmacayeal_input->GetInputValue(&w, gauss);
+		vzmacayeal_input->GetInputDerivativeValue(&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);
+		material->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])*basis[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])*basis[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])*basis[i];
+		}
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingPattynStokes {{{*/
+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 {{{*/
+ElementVector* Penta::CreatePVectorCouplingPattynStokesViscous(void){
+
+	/*Constants*/
+	const int   numdof=NUMVERTICES*NDOF4;
+
+	/*Intermediaries */
+	int         i;
+	int         approximation;
+	IssmDouble  viscosity,Jdet;
+	IssmDouble  stokesreconditioning;
+	IssmDouble  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble  dw[3];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[6]; //for the six nodes of the penta
+	IssmDouble  dbasis[3][6]; //for the six nodes of the penta
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	inputs->GetInputValue(&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],vertices,NUMVERTICES);
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);               _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);               _assert_(vz_input);
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   _assert_(vzpattyn_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+		GetNodalFunctionsP1Derivatives(&dbasis[0][0],&xyz_list[0][0], gauss);
+
+		vzpattyn_input->GetInputDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		for(i=0;i<NUMVERTICES;i++){
+			pe->values[i*NDOF4+0]+=-Jdet*gauss->weight*viscosity*dw[0]*dbasis[2][i];
+			pe->values[i*NDOF4+1]+=-Jdet*gauss->weight*viscosity*dw[1]*dbasis[2][i];
+			pe->values[i*NDOF4+2]+=-Jdet*gauss->weight*viscosity*(dw[0]*dbasis[0][i]+dw[1]*dbasis[1][i]+2*dw[2]*dbasis[2][i]);
+			pe->values[i*NDOF4+3]+=Jdet*gauss->weight*stokesreconditioning*dw[2]*basis[i];
+		}
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorCouplingPattynStokesFriction{{{*/
+ElementVector* Penta::CreatePVectorCouplingPattynStokesFriction(void){
+
+	/*Constants*/
+	const int numdof=NUMVERTICES*NDOF4;
+
+	/*Intermediaries*/
+	int         i,j;
+	int         approximation,analysis_type;
+	IssmDouble  Jdet,Jdet2d;
+	IssmDouble  stokesreconditioning;
+	IssmDouble	bed_normal[3];
+	IssmDouble  epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble  viscosity, w, alpha2_gauss;
+	IssmDouble  dw[3];
+	IssmDouble	xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[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(!IsOnBed() || IsFloating()) return NULL;
+	inputs->GetInputValue(&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],vertices,NUMVERTICES);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);               _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);               _assert_(vz_input);
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);   _assert_(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(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		vzpattyn_input->GetInputValue(&w, gauss);
+		vzpattyn_input->GetInputDerivativeValue(&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);
+		material->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])*basis[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])*basis[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])*basis[i];
+		}
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticHoriz{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticHoriz(void){
+
+	int approximation;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreatePVectorDiagnosticMacAyeal();
+		case PattynApproximationEnum:
+			return CreatePVectorDiagnosticPattyn();
+		case L1L2ApproximationEnum:
+			return CreatePVectorDiagnosticL1L2();
+		case HutterApproximationEnum:
+			return NULL;
+		case NoneApproximationEnum:
+			return NULL;
+		case StokesApproximationEnum:
+			return CreatePVectorDiagnosticStokes();
+		case MacAyealPattynApproximationEnum:
+			return CreatePVectorDiagnosticMacAyealPattyn();
+		case MacAyealStokesApproximationEnum:
+			return CreatePVectorDiagnosticMacAyealStokes();
+		case PattynStokesApproximationEnum:
+			return CreatePVectorDiagnosticPattynStokes();
+		default:
+			_error_("Approximation " << EnumToStringx(approximation) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticMacAyealPattyn{{{*/
+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::CreatePVectorDiagnosticMacAyealStokes{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticMacAyealStokes(void){
+
+	/*compute all load vectors for this element*/
+	ElementVector* pe1=CreatePVectorDiagnosticMacAyeal();
+	ElementVector* pe2=CreatePVectorDiagnosticStokes();
+	ElementVector* pe3=CreatePVectorCouplingMacAyealStokes();
+	ElementVector* pe =new ElementVector(pe1,pe2,pe3);
+
+	/*clean-up and return*/
+	delete pe1;
+	delete pe2;
+	delete pe3;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticPattynStokes{{{*/
+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{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticHutter(void){
+
+	/*Intermediaries*/
+	int          i,j;
+	int          node0,node1;
+	int          connectivity[2];
+	IssmDouble   Jdet;
+	IssmDouble   xyz_list[NUMVERTICES][3];
+	IssmDouble   xyz_list_segment[2][3];
+	IssmDouble   z_list[NUMVERTICES];
+	IssmDouble   slope[2];
+	IssmDouble   slope2,constant_part;
+	IssmDouble   rho_ice,gravity,n,B;
+	IssmDouble   ub,vb,z_g,surface,thickness;
+	GaussPenta*  gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	n=material->GetN();
+	B=material->GetB();
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);  _assert_(thickness_input);
+	Input* surface_input=inputs->GetInput(SurfaceEnum);      _assert_(surface_input);
+	Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); _assert_(slopex_input);
+	Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); _assert_(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(int ig=gauss->begin();ig<gauss->end();ig++){
+			gauss->GaussPoint(ig);
+
+			slopex_input->GetInputValue(&slope[0],gauss);
+			slopey_input->GetInputValue(&slope[1],gauss);
+			surface_input->GetInputValue(&surface,gauss);
+			thickness_input->GetInputValue(&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::GetInputValue(&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/(IssmDouble)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/(IssmDouble)connectivity[1];
+			}
+		}
+		delete gauss;
+
+		//Deal with lower surface
+		if (IsOnBed()){
+			constant_part=-1.58*pow((IssmDouble)10.0,-(IssmDouble)10.0)*rho_ice*gravity*thickness;
+			ub=constant_part*slope[0];
+			vb=constant_part*slope[1];
+
+			pe->values[2*node0]+=ub/(IssmDouble)connectivity[0];
+			pe->values[2*node0+1]+=vb/(IssmDouble)connectivity[0];
+		}
+	}
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticMacAyeal{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticMacAyeal(void){
+
+	if (!IsOnBed()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorDiagnosticMacAyeal();
+	delete tria->material; delete tria;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticL1L2{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticL1L2(void){
+
+	if (!IsOnBed()) return NULL;
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorDiagnosticMacAyeal();
+	delete tria->material; delete tria;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticPattyn{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticPattyn(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int         i,j;
+	IssmDouble  Jdet;
+	IssmDouble  slope[3]; //do not put 2! this goes into GetInputDerivativeValue, which addresses slope[3] also!
+	IssmDouble  driving_stress_baseline,thickness;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[6];
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+	Input* surface_input=inputs->GetInput(SurfaceEnum);     _assert_(surface_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,3);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		thickness_input->GetInputValue(&thickness, gauss);
+		surface_input->GetInputDerivativeValue(&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*basis[i];
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticStokes {{{*/
+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 {{{*/
+ElementVector* Penta::CreatePVectorDiagnosticStokesViscous(void){
+
+	/*Constants*/
+	const int numdofbubble=NDOF4*NUMVERTICES+NDOF3*1;
+
+	/*Intermediaries*/
+	int        i,j;
+	int        approximation;
+	IssmDouble Jdet,viscosity;
+	IssmDouble gravity,rho_ice,stokesreconditioning;
+	IssmDouble forcex,forcey,forcez;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble l1l7[7]; //for the six nodes and the bubble 
+	IssmDouble B[8][numdofbubble];
+	IssmDouble B_prime[8][numdofbubble];
+	IssmDouble B_prime_bubble[8][3];
+	IssmDouble D[8][8]={0.0};
+	IssmDouble D_scalar;
+	IssmDouble Pe_gaussian[numdofbubble]={0.0}; //for the six nodes and the bubble 
+	IssmDouble Ke_temp[numdofbubble][3]={0.0}; //for the six nodes and the bubble 
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation!=StokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum && approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);   _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);   _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);   _assert_(vz_input);
+	Input* loadingforcex_input=inputs->GetInput(LoadingforceXEnum);  _assert_(loadingforcex_input);
+	Input* loadingforcey_input=inputs->GetInput(LoadingforceYEnum);  _assert_(loadingforcey_input);
+	Input* loadingforcez_input=inputs->GetInput(LoadingforceZEnum);  _assert_(loadingforcez_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int 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);
+		material->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		loadingforcex_input->GetInputValue(&forcex, gauss);
+		loadingforcey_input->GetInputValue(&forcey, gauss);
+		loadingforcez_input->GetInputValue(&forcez, gauss);
+
+		for(i=0;i<NUMVERTICES+1;i++){
+			Pe_gaussian[i*NDOF4+2]+=-rho_ice*gravity*Jdet*gauss->weight*l1l7[i];
+			Pe_gaussian[i*NDOF4+0]+=forcex*Jdet*gauss->weight*l1l7[i];
+			Pe_gaussian[i*NDOF4+1]+=forcey*Jdet*gauss->weight*l1l7[i];
+			Pe_gaussian[i*NDOF4+2]+=forcez*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_temp[0][0],1);
+	}
+
+	/*Condensation*/
+	ReduceVectorStokes(pe->values, &Ke_temp[0][0], &Pe_gaussian[0]);
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticStokesShelf{{{*/
+ElementVector* Penta::CreatePVectorDiagnosticStokesShelf(void){
+
+	/*Intermediaries*/
+	int         i,j;
+	int         approximation,shelf_dampening;
+	IssmDouble  gravity,rho_water,bed,water_pressure;
+	IssmDouble  damper,normal_vel,vx,vy,vz,dt;
+	IssmDouble	xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble	bed_normal[3];
+	IssmDouble  dz[3];
+	IssmDouble  basis[6]; //for the six nodes of the penta
+	IssmDouble  Jdet2d;
+	GaussPenta  *gauss=NULL;
+
+	/*Initialize Element vector and return if necessary*/
+	if(!IsOnBed() || !IsFloating()) return NULL;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	this->parameters->FindParam(&shelf_dampening,DiagnosticShelfDampeningEnum);
+	if(approximation!=StokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum && 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],vertices,NUMVERTICES);
+	Input* bed_input=inputs->GetInput(BedEnum); _assert_(bed_input);
+	Input* vx_input=inputs->GetInput(VxEnum);   _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);   _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);   _assert_(vz_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(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0], gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		BedNormal(&bed_normal[0],xyz_list_tria);
+		bed_input->GetInputValue(&bed, gauss);
+		if(shelf_dampening){ //add dampening to avoid too high vertical velocities when not in hydrostatic equilibrium
+			bed_input->GetInputDerivativeValue(&dz[0],&xyz_list[0][0],gauss);
+			vx_input->GetInputValue(&vx, gauss);
+			vy_input->GetInputValue(&vy, gauss);
+			vz_input->GetInputValue(&vz, gauss);
+			dt=0;
+			normal_vel=bed_normal[0]*vx+bed_normal[1]*vy+bed_normal[2]*vz;
+			damper=gravity*rho_water*pow(1+pow(dz[0],2)+pow(dz[1],2),0.5)*normal_vel*dt;
+		}
+		else damper=0;
+		water_pressure=gravity*rho_water*bed;
+
+		for(i=0;i<NUMVERTICES;i++) for(j=0;j<3;j++) pe->values[i*NDOF4+j]+=(water_pressure+damper)*gauss->weight*Jdet2d*basis[i]*bed_normal[j];
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticVert {{{*/
+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 {{{*/
+ElementVector* Penta::CreatePVectorDiagnosticVertVolume(void){
+
+	/*Constants*/
+	const int  numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        approximation;
+	IssmDouble     Jdet;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     dudx,dvdy,dwdz;
+	IssmDouble     du[3],dv[3],dw[3];
+	IssmDouble     basis[6];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	Input* vzstokes_input=NULL;
+	if(approximation==PattynStokesApproximationEnum || approximation==MacAyealStokesApproximationEnum){
+		vzstokes_input=inputs->GetInput(VzStokesEnum); _assert_(vzstokes_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(basis, gauss);
+
+		vx_input->GetInputDerivativeValue(&du[0],&xyz_list[0][0],gauss);
+		vy_input->GetInputDerivativeValue(&dv[0],&xyz_list[0][0],gauss);
+		if(approximation==PattynStokesApproximationEnum || approximation==MacAyealStokesApproximationEnum){
+			vzstokes_input->GetInputDerivativeValue(&dw[0],&xyz_list[0][0],gauss);
+			dwdz=dw[2];
+		}
+		else dwdz=0;
+		dudx=du[0];
+		dvdy=dv[1];
+
+		for(int i=0;i<numdof;i++) pe->values[i] += (dudx+dvdy+dwdz)*Jdet*gauss->weight*basis[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorDiagnosticVertBase {{{*/
+ElementVector* Penta::CreatePVectorDiagnosticVertBase(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	int        approximation;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble xyz_list_tria[NUMVERTICES2D][3];
+	IssmDouble Jdet2d;
+	IssmDouble vx,vy,vz,dbdx,dbdy,basalmeltingvalue;
+	IssmDouble slope[3];
+	IssmDouble basis[NUMVERTICES];
+	GaussPenta* gauss=NULL;
+
+	if (!IsOnBed()) return NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<3;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	Input* bed_input=inputs->GetInput(BedEnum);                                _assert_(bed_input);
+	Input* basal_melting_input=inputs->GetInput(BasalforcingsMeltingRateEnum); _assert_(basal_melting_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                                  _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                                  _assert_(vy_input);
+	Input* vzstokes_input=NULL;
+	if(approximation==PattynStokesApproximationEnum || approximation==MacAyealStokesApproximationEnum){
+		vzstokes_input=inputs->GetInput(VzStokesEnum);       _assert_(vzstokes_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(0,1,2,2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		basal_melting_input->GetInputValue(&basalmeltingvalue, gauss);
+		bed_input->GetInputDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		vx_input->GetInputValue(&vx, gauss);
+		vy_input->GetInputValue(&vy, gauss);
+		if(approximation==PattynStokesApproximationEnum || approximation==MacAyealStokesApproximationEnum){
+			vzstokes_input->GetInputValue(&vz, gauss);
+		}
+		else vz=0;
+
+		dbdx=slope[0];
+		dbdy=slope[1];
+
+		GetTriaJacobianDeterminant(&Jdet2d, &xyz_list_tria[0][0],gauss);
+		GetNodalFunctionsP1(&basis[0], gauss);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=-Jdet2d*gauss->weight*(vx*dbdx+vy*dbdy-vz-basalmeltingvalue)*basis[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianDiagnosticHoriz{{{*/
+ElementMatrix* Penta::CreateJacobianDiagnosticHoriz(void){
+
+	int approximation;
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	switch(approximation){
+		case MacAyealApproximationEnum:
+			return CreateJacobianDiagnosticMacayeal2d();
+		case PattynApproximationEnum:
+			return CreateJacobianDiagnosticPattyn();
+		case StokesApproximationEnum:
+			return CreateJacobianDiagnosticStokes();
+		case NoneApproximationEnum:
+			return NULL;
+		default:
+			_error_("Approximation " << EnumToStringx(approximation) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianDiagnosticMacayeal2d{{{*/
+ElementMatrix* Penta::CreateJacobianDiagnosticMacayeal2d(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 nodes, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed()) return NULL;
+
+	/*Depth average some fields*/
+	switch(this->material->ObjectEnum()){
+		case MaticeEnum:
+			this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+			break;
+		case MatdamageiceEnum:
+			this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+			this->InputDepthAverageAtBase(MaterialsRheologyZEnum,MaterialsRheologyZbarEnum,MaterialsEnum);
+			break;
+		default:
+			_error_("material "<<EnumToStringx(this->material->ObjectEnum())<<" not supported");
+	}
+
+	/*Call Tria function*/
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateJacobianDiagnosticMacayeal();
+	delete tria->material; delete tria;
+
+	/*Delete averaged inputs*/
+	this->material->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+	this->material->inputs->DeleteInput(MaterialsRheologyZbarEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianDiagnosticPattyn{{{*/
+ElementMatrix* Penta::CreateJacobianDiagnosticPattyn(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet;
+	IssmDouble eps1dotdphii,eps1dotdphij;
+	IssmDouble eps2dotdphii,eps2dotdphij;
+	IssmDouble mu_prime;
+	IssmDouble epsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble eps1[3],eps2[3];
+	IssmDouble dphi[3][NUMVERTICES];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Jacobian with regular Pattyn (first part of the Gateau derivative)*/
+	ElementMatrix* Ke=CreateKMatrixDiagnosticPattyn();
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1Derivatives(&dphi[0][0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosityDerivativeEpsSquare(&mu_prime,&epsilon[0]);
+		eps1[0]=2*epsilon[0]+epsilon[1];   eps2[0]=epsilon[2];
+		eps1[1]=epsilon[2];                eps2[1]=epsilon[0]+2*epsilon[1];
+		eps1[2]=epsilon[3];                eps2[2]=epsilon[4];
+
+		for(i=0;i<6;i++){
+			for(j=0;j<6;j++){
+				eps1dotdphii=eps1[0]*dphi[0][i]+eps1[1]*dphi[1][i]+eps1[2]*dphi[2][i];
+				eps1dotdphij=eps1[0]*dphi[0][j]+eps1[1]*dphi[1][j]+eps1[2]*dphi[2][j];
+				eps2dotdphii=eps2[0]*dphi[0][i]+eps2[1]*dphi[1][i]+eps2[2]*dphi[2][i];
+				eps2dotdphij=eps2[0]*dphi[0][j]+eps2[1]*dphi[1][j]+eps2[2]*dphi[2][j];
+
+				Ke->values[12*(2*i+0)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps1dotdphii;
+				Ke->values[12*(2*i+0)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps1dotdphii;
+				Ke->values[12*(2*i+1)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps2dotdphii;
+				Ke->values[12*(2*i+1)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps2dotdphii;
+			}
+		}
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianDiagnosticStokes{{{*/
+ElementMatrix* Penta::CreateJacobianDiagnosticStokes(void){
+
+	/*Constants*/
+	const int    numdof=NDOF4*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet;
+	IssmDouble eps1dotdphii,eps1dotdphij;
+	IssmDouble eps2dotdphii,eps2dotdphij;
+	IssmDouble eps3dotdphii,eps3dotdphij;
+	IssmDouble mu_prime;
+	IssmDouble epsilon[5]; /* epsilon=[exx,eyy,exy,exz,eyz];*/
+	IssmDouble eps1[3],eps2[3],eps3[3];
+	IssmDouble dphi[3][NUMVERTICES];
+	GaussPenta *gauss=NULL;
+
+	/*Initialize Jacobian with regular Stokes (first part of the Gateau derivative)*/
+	ElementMatrix* Ke=CreateKMatrixDiagnosticStokes();
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);       _assert_(vz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(5,5);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1Derivatives(&dphi[0][0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosityDerivativeEpsSquare(&mu_prime,&epsilon[0]);
+		eps1[0]=epsilon[0];   eps2[0]=epsilon[2];   eps3[0]=epsilon[3];
+		eps1[1]=epsilon[2];   eps2[1]=epsilon[1];   eps3[1]=epsilon[4];
+		eps1[2]=epsilon[3];   eps2[2]=epsilon[4];   eps3[2]= -epsilon[0] -epsilon[1];
+
+		for(i=0;i<6;i++){
+			for(j=0;j<6;j++){
+				eps1dotdphii=eps1[0]*dphi[0][i]+eps1[1]*dphi[1][i]+eps1[2]*dphi[2][i];
+				eps1dotdphij=eps1[0]*dphi[0][j]+eps1[1]*dphi[1][j]+eps1[2]*dphi[2][j];
+				eps2dotdphii=eps2[0]*dphi[0][i]+eps2[1]*dphi[1][i]+eps2[2]*dphi[2][i];
+				eps2dotdphij=eps2[0]*dphi[0][j]+eps2[1]*dphi[1][j]+eps2[2]*dphi[2][j];
+				eps3dotdphii=eps3[0]*dphi[0][i]+eps3[1]*dphi[1][i]+eps3[2]*dphi[2][i];
+				eps3dotdphij=eps3[0]*dphi[0][j]+eps3[1]*dphi[1][j]+eps3[2]*dphi[2][j];
+
+				Ke->values[numdof*(4*i+0)+4*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps1dotdphii;
+				Ke->values[numdof*(4*i+0)+4*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps1dotdphii;
+				Ke->values[numdof*(4*i+0)+4*j+2]+=gauss->weight*Jdet*2*mu_prime*eps3dotdphij*eps1dotdphii;
+
+				Ke->values[numdof*(4*i+1)+4*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps2dotdphii;
+				Ke->values[numdof*(4*i+1)+4*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps2dotdphii;
+				Ke->values[numdof*(4*i+1)+4*j+2]+=gauss->weight*Jdet*2*mu_prime*eps3dotdphij*eps2dotdphii;
+
+				Ke->values[numdof*(4*i+2)+4*j+0]+=gauss->weight*Jdet*2*mu_prime*eps1dotdphij*eps3dotdphii;
+				Ke->values[numdof*(4*i+2)+4*j+1]+=gauss->weight*Jdet*2*mu_prime*eps2dotdphij*eps3dotdphii;
+				Ke->values[numdof*(4*i+2)+4*j+2]+=gauss->weight*Jdet*2*mu_prime*eps3dotdphij*eps3dotdphii;
+			}
+		}
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHoriz{{{*/
+void  Penta::GetSolutionFromInputsDiagnosticHoriz(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int         i;
+	int         approximation;
+	int        *doflist        = NULL;
+	IssmDouble  vx,vy;
+	IssmDouble  values[numdof];
+	GaussPenta *gauss;
+
+	/*Get approximation enum and dof list: */
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+
+	/*If the element is a coupling, do nothing: every node 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->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	/*Add value to global vector*/
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticHutter{{{*/
+void  Penta::GetSolutionFromInputsDiagnosticHutter(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	IssmDouble       vx,vy;
+	IssmDouble       values[numdof];
+	GaussPenta*  gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(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->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	/*Add value to global vector*/
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticVert{{{*/
+void  Penta::GetSolutionFromInputsDiagnosticVert(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	IssmDouble       vz;
+	IssmDouble       values[numdof];
+	GaussPenta*  gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	Input* vz_input=inputs->GetInput(VzEnum); _assert_(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->GetInputValue(&vz,gauss);
+		values[i]=vz;
+	}
+
+	/*Add value to global vector*/
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputsDiagnosticStokes{{{*/
+void  Penta::GetSolutionFromInputsDiagnosticStokes(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF4*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	IssmDouble       vx,vy,vz,p;
+	IssmDouble       stokesreconditioning;
+	IssmDouble       values[numdof];
+	GaussPenta   *gauss;
+
+	/*Get dof list: */
+	GetDofList(&doflist,StokesApproximationEnum,GsetEnum);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);       _assert_(vz_input);
+	Input* p_input =inputs->GetInput(PressureEnum); _assert_(p_input);
+
+	/*Recondition pressure: */
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+
+	/*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->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vz_input->GetInputValue(&vz,gauss);
+		p_input ->GetInputValue(&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*/
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::GetL1L2Viscosity{{{*/
+void Penta::GetL1L2Viscosity(IssmDouble* pviscosity,IssmDouble* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input,Input* surface_input){
+	/*Compute the L1L2 viscosity
+	 *
+	 *      1
+	 * mu = - A^-1 (sigma'_e)^(1-n)
+	 *      2
+	 *
+	 * sigma'_e^2 = |sigma'_//|^2 + |sigma'_perp|^2 (see Perego 2012 eq. 17,18)
+	 *
+	 * L1L2 assumptions:
+	 *
+	 * (1) |eps_b|_// = A (|sigma'_//|^2 + |sigma'_perp|^2)^((n-1)/2) |sigma'_//|
+	 * (2) |sigma'_perp|^2 = |rho g (s-z) grad(s)|^2
+	 *
+	 * Assuming that n = 3, we have a polynom of degree 3 to solve (the only unkown is X=|sigma'_//|)
+	 *
+	 * A X^3 + A |rho g (s-z) grad(s)|^2 X - |eps_b|_// = 0     */
+
+	int        i;
+	IssmDouble z,s,viscosity,p,q,delta;
+	IssmDouble tau_perp,tau_par,eps_b,A;
+	IssmDouble epsilonvx[5]; /*exx eyy exy exz eyz*/
+	IssmDouble epsilonvy[5]; /*exx eyy exy exz eyz*/
+	IssmDouble epsilon[5];   /*exx eyy exy exz eyz*/
+	IssmDouble z_list[NUMVERTICES];
+	IssmDouble slope[3];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input || !surface_input) _error_("Input missing");
+
+	/*Get tau_perp*/
+	for(i=0;i<NUMVERTICES;i++) z_list[i]=xyz_list[3*i+2];
+	surface_input->GetInputValue(&s,gauss);
+	surface_input->GetInputDerivativeValue(&slope[0],xyz_list,gauss);
+	PentaRef::GetInputValue(&z,&z_list[0],gauss);
+	tau_perp = matpar->GetRhoIce() * matpar->GetG() * fabs(s-z)*sqrt(slope[0]*slope[0]+slope[1]*slope[1]);
+
+	/* Get eps_b*/
+	vx_input->GetVxStrainRate3dPattyn(epsilonvx,xyz_list,gauss);
+	vy_input->GetVyStrainRate3dPattyn(epsilonvy,xyz_list,gauss);
+	for(i=0;i<5;i++) epsilon[i]=epsilonvx[i]+epsilonvy[i];
+	eps_b = sqrt(epsilon[0]*epsilon[0] + epsilon[1]*epsilon[1] + epsilon[0]*epsilon[1] + epsilon[2]*epsilon[2]);
+	if(eps_b==0.){
+		*pviscosity = 2.5e+17;
+		return;
+	}
+
+	/*Get A*/
+	_assert_(material->GetN()==3.0);
+	A=material->GetA();
+
+	/*Solve for tau_perp (http://fr.wikipedia.org/wiki/Méthode_de_Cardan)*/
+	p     = tau_perp *tau_perp;
+	q     = - eps_b/A;
+	delta = q *q + p*p*p*4./27.;
+	_assert_(delta>0);
+	tau_par = pow(0.5*(-q+sqrt(delta)),1./3.) - pow(0.5*(q+sqrt(delta)),1./3.);
+
+	/*Viscosity*/
+	viscosity = 1./(2.*A*(tau_par*tau_par + tau_perp*tau_perp));
+	_assert_(!isnan(viscosity));
+	_assert_(viscosity > 0.);
+
+	/*Assign output pointer*/
+	*pviscosity = viscosity;
+	return; 
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHoriz {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticHoriz(IssmDouble* solution){
+
+	int  approximation;
+
+	/*Recover inputs*/
+	inputs->GetInputValue(&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;
+		}
+	}
+	if (approximation==L1L2ApproximationEnum){
+		if (!IsOnBed()) return;
+		InputUpdateFromSolutionDiagnosticL1L2(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 {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticMacAyeal(IssmDouble* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int     i;
+	IssmDouble  rho_ice,g;
+	IssmDouble  values[numdof];
+	IssmDouble  vx[NUMVERTICES];
+	IssmDouble  vy[NUMVERTICES];
+	IssmDouble  vz[NUMVERTICES];
+	IssmDouble  vel[NUMVERTICES];
+	IssmDouble  pressure[NUMVERTICES];
+	IssmDouble  surface[NUMVERTICES];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	int    *doflist = 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]];
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&values[0],nodes,NUMVERTICES2D,XYEnum); /*2D: only the first 3 nodes are taken*/
+
+	/*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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*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->vertices,NUMVERTICES);
+
+		/*Now Compute vel*/
+		GetInputListOnVertices(&vz[0],VzEnum,0.0); //default is 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*/
+		GetInputListOnVertices(&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,VxPicardEnum);
+		penta->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+		penta->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+		/*Add vx and vy as inputs to the tria element: */
+		penta->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+		penta->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+		penta->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+		penta->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement(); _assert_(penta->Id()!=this->id);
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticMacAyealPattyn(IssmDouble* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+	const int    numdof2d=NDOF2*NUMVERTICES2D;
+
+	int     i;
+	IssmDouble  rho_ice,g;
+	IssmDouble  macayeal_values[numdof];
+	IssmDouble  pattyn_values[numdof];
+	IssmDouble  vx[NUMVERTICES];
+	IssmDouble  vy[NUMVERTICES];
+	IssmDouble  vz[NUMVERTICES];
+	IssmDouble  vel[NUMVERTICES];
+	IssmDouble  pressure[NUMVERTICES];
+	IssmDouble  surface[NUMVERTICES];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	int*    doflistp = NULL;
+	int*    doflistm = 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],vertices,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];
+	}
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&macayeal_values[0],penta->nodes,NUMVERTICES,XYEnum);
+	TransformSolutionCoord(&pattyn_values[0],   this->nodes,NUMVERTICES,XYEnum);
+
+	/*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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Now Compute vel*/
+	GetInputListOnVertices(&vz[0],VzEnum,0.0); //default is 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 3D, 
+	 *so the pressure is just the pressure at the z elevation: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetInputListOnVertices(&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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflistp);
+	xDelete<int>(doflistm);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticMacAyealStokes(IssmDouble* solution){
+
+	const int    numdofm=NDOF2*NUMVERTICES;
+	const int    numdofs=NDOF4*NUMVERTICES;
+	const int    numdof2d=NDOF2*NUMVERTICES2D;
+
+	int     i;
+	IssmDouble  stokesreconditioning;
+	IssmDouble  macayeal_values[numdofm];
+	IssmDouble  stokes_values[numdofs];
+	IssmDouble  vx[NUMVERTICES];
+	IssmDouble  vy[NUMVERTICES];
+	IssmDouble  vz[NUMVERTICES];
+	IssmDouble  vzmacayeal[NUMVERTICES];
+	IssmDouble  vzstokes[NUMVERTICES];
+	IssmDouble  vel[NUMVERTICES];
+	IssmDouble  pressure[NUMVERTICES];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	int*    doflistm        = NULL;
+	int*    doflists        = 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,DiagnosticStokesreconditioningEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,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]];
+	}
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&macayeal_values[0],this->nodes,NUMVERTICES,XYEnum);
+	TransformSolutionCoord(&stokes_values[0],this->nodes,NUMVERTICES,XYZPEnum);
+
+	/*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;
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vzstokes[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(pressure[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Get Vz*/
+	Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);
+	if (vzmacayeal_input){
+		if (vzmacayeal_input->ObjectEnum()!=PentaP1InputEnum){
+			_error_("Cannot compute Vel as VzMacAyeal is of type " << EnumToStringx(vzmacayeal_input->ObjectEnum()));
+		}
+		GetInputListOnVertices(&vzmacayeal[0],VzMacAyealEnum);
+	}
+	else{
+		_error_("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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(VzEnum,VzPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new PentaP1Input(VzEnum,vz));
+	this->inputs->AddInput(new PentaP1Input(VzStokesEnum,vzstokes));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflistm);
+	xDelete<int>(doflists);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticL1L2 {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticL1L2(IssmDouble* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int     i;
+	IssmDouble  rho_ice,g;
+	IssmDouble  values[numdof];
+	IssmDouble  vx[NUMVERTICES];
+	IssmDouble  vy[NUMVERTICES];
+	IssmDouble  vz[NUMVERTICES];
+	IssmDouble  vel[NUMVERTICES];
+	IssmDouble  pressure[NUMVERTICES];
+	IssmDouble  surface[NUMVERTICES];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	int    *doflist = NULL;
+	Penta  *penta   = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,L1L2ApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&values[0],nodes,NUMVERTICES2D,XYEnum); /*2D: only the first 3 nodes are taken*/
+
+	/*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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*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->vertices,NUMVERTICES);
+
+		/*Now Compute vel*/
+		GetInputListOnVertices(&vz[0],VzEnum,0.0); //default is 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*/
+		GetInputListOnVertices(&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,VxPicardEnum);
+		penta->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+		penta->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+		/*Add vx and vy as inputs to the tria element: */
+		penta->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+		penta->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+		penta->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+		penta->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+		/*Stop if we have reached the surface*/
+		if (penta->IsOnSurface()) break;
+
+		/* get upper Penta*/
+		penta=penta->GetUpperElement(); _assert_(penta->Id()!=this->id);
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattyn {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticPattyn(IssmDouble* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int    i;
+	IssmDouble rho_ice,g;
+	IssmDouble values[numdof];
+	IssmDouble vx[NUMVERTICES];
+	IssmDouble vy[NUMVERTICES];
+	IssmDouble vz[NUMVERTICES];
+	IssmDouble vel[NUMVERTICES];
+	IssmDouble pressure[NUMVERTICES];
+	IssmDouble surface[NUMVERTICES];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	int*   doflist = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,PattynApproximationEnum,GsetEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&values[0],nodes,NUMVERTICES,XYEnum);
+
+	/*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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Get Vz*/
+	Input* vz_input=inputs->GetInput(VzEnum);
+	if (vz_input){
+		GetInputListOnVertices(&vz[0],VzEnum);
+	}
+	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();
+	GetInputListOnVertices(&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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticPattynStokes {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticPattynStokes(IssmDouble* solution){
+
+	const int    numdofp=NDOF2*NUMVERTICES;
+	const int    numdofs=NDOF4*NUMVERTICES;
+
+	int    i;
+	IssmDouble pattyn_values[numdofp];
+	IssmDouble stokes_values[numdofs];
+	IssmDouble vx[NUMVERTICES];
+	IssmDouble vy[NUMVERTICES];
+	IssmDouble vz[NUMVERTICES];
+	IssmDouble vzpattyn[NUMVERTICES];
+	IssmDouble vzstokes[NUMVERTICES];
+	IssmDouble vel[NUMVERTICES];
+	IssmDouble pressure[NUMVERTICES];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble stokesreconditioning;
+	int*   doflistp      = NULL;
+	int*   doflists      = 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,DiagnosticStokesreconditioningEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,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]];
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&pattyn_values[0],this->nodes,NUMVERTICES,XYEnum);
+	TransformSolutionCoord(&stokes_values[0],this->nodes,NUMVERTICES,XYZPEnum);
+
+	/*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;
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vzstokes[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(pressure[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Get Vz*/
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);
+	if (vzpattyn_input){
+		if (vzpattyn_input->ObjectEnum()!=PentaP1InputEnum){
+			_error_("Cannot compute Vel as VzPattyn is of type " << EnumToStringx(vzpattyn_input->ObjectEnum()));
+		}
+		GetInputListOnVertices(&vzpattyn[0],VzPattynEnum);
+	}
+	else{
+		_error_("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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(VzEnum,VzPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new PentaP1Input(VzEnum,vz));
+	this->inputs->AddInput(new PentaP1Input(VzStokesEnum,vzstokes));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflistp);
+	xDelete<int>(doflists);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticHutter {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticHutter(IssmDouble* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int     i;
+	IssmDouble  rho_ice,g;
+	IssmDouble  values[numdof];
+	IssmDouble  vx[NUMVERTICES];
+	IssmDouble  vy[NUMVERTICES];
+	IssmDouble  vz[NUMVERTICES];
+	IssmDouble  vel[NUMVERTICES];
+	IssmDouble  pressure[NUMVERTICES];
+	IssmDouble  surface[NUMVERTICES];
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	int*    doflist = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get node data: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Now Compute vel*/
+	GetInputListOnVertices(&vz[0],VzEnum,0.0); //default is 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 3D, 
+	 *so the pressure is just the pressure at the z elevation: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	GetInputListOnVertices(&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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticVert {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticVert(IssmDouble* solution){
+
+	const int numdof=NDOF1*NUMVERTICES;
+
+	int      i;
+	int      approximation;
+	IssmDouble   rho_ice,g;
+	IssmDouble   values[numdof];
+	IssmDouble   vx[NUMVERTICES];
+	IssmDouble   vy[NUMVERTICES];
+	IssmDouble   vz[NUMVERTICES];
+	IssmDouble   vzmacayeal[NUMVERTICES];
+	IssmDouble   vzpattyn[NUMVERTICES];
+	IssmDouble   vzstokes[NUMVERTICES];
+	IssmDouble   vel[NUMVERTICES];
+	IssmDouble   pressure[NUMVERTICES];
+	IssmDouble   surface[NUMVERTICES];
+	IssmDouble   xyz_list[NUMVERTICES][3];
+	int*     doflist      = NULL;
+
+	/*Get the approximation and do nothing if the element in Stokes or None*/
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation==StokesApproximationEnum || approximation==NoneApproximationEnum){
+		return;
+	}
+
+	/*Get dof list and vertices coordinates: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vz[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Get Vx and Vy*/
+	GetInputListOnVertices(&vx[0],VxEnum,0.0); //default is 0
+	GetInputListOnVertices(&vy[0],VyEnum,0.0); //default is 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->ObjectEnum()!=PentaP1InputEnum) _error_("Cannot compute Vel as VzStokes is of type " << EnumToStringx(vzstokes_input->ObjectEnum()));
+			GetInputListOnVertices(&vzstokes[0],VzStokesEnum);
+		}
+		else _error_("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->ObjectEnum()!=PentaP1InputEnum) _error_("Cannot compute Vel as VzStokes is of type " << EnumToStringx(vzstokes_input->ObjectEnum()));
+			GetInputListOnVertices(&vzstokes[0],VzStokesEnum);
+		}
+		else _error_("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();
+		GetInputListOnVertices(&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,VzPicardEnum);
+
+	if(approximation!=PattynStokesApproximationEnum && approximation!=MacAyealStokesApproximationEnum){
+		this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+		this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+	}
+	else if(approximation==PattynStokesApproximationEnum){
+		this->inputs->AddInput(new PentaP1Input(VzPattynEnum,vzpattyn));
+	}
+	else if(approximation==MacAyealStokesApproximationEnum){
+		this->inputs->AddInput(new PentaP1Input(VzMacAyealEnum,vzmacayeal));
+	}
+	this->inputs->AddInput(new PentaP1Input(VzEnum,vz));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromSolutionDiagnosticStokes {{{*/
+void  Penta::InputUpdateFromSolutionDiagnosticStokes(IssmDouble* solution){
+
+	const int numdof=NDOF4*NUMVERTICES;
+
+	int     i;
+	IssmDouble  values[numdof];
+	IssmDouble  vx[NUMVERTICES];
+	IssmDouble  vy[NUMVERTICES];
+	IssmDouble  vz[NUMVERTICES];
+	IssmDouble  vel[NUMVERTICES];
+	IssmDouble  pressure[NUMVERTICES];
+	IssmDouble  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]];
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&values[0],nodes,NUMVERTICES,XYZPEnum);
+
+	/*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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vz[i]))       _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(pressure[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Recondition pressure and compute vel: */
+	this->parameters->FindParam(&stokesreconditioning,DiagnosticStokesreconditioningEnum);
+	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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(VzEnum,VzPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new PentaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new PentaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new PentaP1Input(VzEnum,vz));
+	this->inputs->AddInput(new PentaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new PentaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_BALANCED_
+/*FUNCTION Penta::CreateKMatrixBalancethickness {{{*/
+ElementMatrix* Penta::CreateKMatrixBalancethickness(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 nodes, and use it to build 
+	  the stiffness matrix. */
+	if (!IsOnBed()) 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); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixBalancethickness();
+	delete tria->material; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorBalancethickness {{{*/
+ElementVector* Penta::CreatePVectorBalancethickness(void){
+
+	if (!IsOnBed()) 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); //nodes 0, 1 and 2 make the new tria.
+	ElementVector* pe=tria->CreatePVectorBalancethickness();
+	delete tria->material; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+#endif
+#ifdef _HAVE_HYDROLOGY_
+/*FUNCTION Penta::GetHydrologyDCInefficientHmax{{{*/
+void  Penta::GetHydrologyDCInefficientHmax(IssmDouble* ph_max, Node* innode){
+	_error_("Hydrological stuff not suported in Penta");
+}
+/*}}}*/
+/*FUNCTION Tria::BasisIntegral {{{*/
+void Penta::BasisIntegral(Vector<IssmDouble>* basisg){
+	_error_("Hydrological stuff not suported in Penta");
+}
+/*}}}*/
+
+#endif
Index: /issm/trunk-jpl/src/c/classes/Elements/Penta.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Penta.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Penta.h	(revision 15012)
@@ -0,0 +1,337 @@
+/*! \file Penta.h 
+ *  \brief: header file for penta object
+ */
+
+#ifndef _PENTA_H_
+#define _PENTA_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Element.h"
+#include "./PentaHook.h"
+#include "./PentaRef.h"
+class  Object;
+class Parameters;
+class Inputs;
+class Input;
+class IoModel;
+class Node;
+class Material;
+class Matpar;
+class Tria;
+class ElementMatrix;
+class ElementVector;
+
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+/*}}}*/
+
+class Penta: public Element,public PentaHook,public PentaRef{
+
+	public:
+
+		int          id;
+		int          sid;
+
+		Node       **nodes;                       // set of nodes
+		Vertex     **vertices;                    // 6 vertices
+		Material    *material;                    // 1 material ice
+		Matpar      *matpar;                      // 1 material parameter
+		Penta      **verticalneighbors;           // 2 neighbors: first one under, second one above
+		int          horizontalneighborsids[3];
+
+		Parameters  *parameters;                  //pointer to solution parameters
+		Inputs      *inputs;
+		Results     *results;
+
+		/*Penta constructors and destructor: {{{*/
+		Penta();
+		Penta(int penta_id,int penta_sid,int i, IoModel* iomodel,int nummodels);
+		~Penta();
+		/*}}}*/
+		/*Object virtual functions definitions: {{{*/
+		Object *copy();
+		void    DeepEcho();
+		void    Echo();
+		int     ObjectEnum();
+		int     Id();
+		/*}}}*/
+		/*Update virtual functions definitions: {{{*/
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solutiong);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		#ifdef _HAVE_DAKOTA_
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix, int nows, int ncols, int name, int type);
+		#endif
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel);
+		/*}}}*/
+		/*Element virtual functions definitions: {{{*/
+		void   AverageOntoPartition(Vector<IssmDouble>* partition_contributions,Vector<IssmDouble>* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part);
+		void   BasalFrictionCreateInput(void);
+		void   ComputeBasalStress(Vector<IssmDouble>* sigma_b);
+		void   ComputeStrainRate(Vector<IssmDouble>* eps);
+		void   ComputeStressTensor();
+		void   Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void   SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Materials* materials,Parameters* parameters);
+		void   SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		void   CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void   CreateDVector(Vector<IssmDouble>* df);
+		void   CreatePVector(Vector<IssmDouble>* pf);
+		void   CreateJacobianMatrix(Matrix<IssmDouble>* Jff);
+		void   Delta18oParameterization(void);
+		void   DeleteResults(void);
+		int    GetNodeIndex(Node* node);
+		void   GetNodesSidList(int* sidlist);
+		int    GetNumberOfNodes(void);
+		void   GetSolutionFromInputs(Vector<IssmDouble>* solution);
+		IssmDouble GetZcoord(GaussPenta* gauss);
+		void   GetVectorFromInputs(Vector<IssmDouble>* vector,int name_enum);
+		void   GetVectorFromResults(Vector<IssmDouble>* vector,int offset,int name_enum,int interp);
+
+		int    Sid();
+		void   InputArtificialNoise(int enum_type,IssmDouble min, IssmDouble max);
+		bool   InputConvergence(IssmDouble* eps, int* enums,int num_enums,int* criterionenums,IssmDouble* criterionvalues,int num_criterionenums);
+		void   InputCreate(IssmDouble scalar,int name,int code);
+		void   InputCreate(IssmDouble* vector, int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code);
+		void   InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum=MeshElementsEnum);
+		void   InputDuplicate(int original_enum,int new_enum);
+		void   InputScale(int enum_type,IssmDouble scale_factor);
+
+		void   InputToResult(int enum_type,int step,IssmDouble time);
+		void   MigrateGroundingLine(IssmDouble* old_floating_ice,IssmDouble* sheet_ungrounding);
+		void   PotentialUngrounding(Vector<IssmDouble>* potential_sheet_ungrounding);
+		void   RequestedOutput(int output_enum,int step,IssmDouble time);
+		void   ListResultsInfo(int** results_enums,int** results_size,IssmDouble** results_times,int** results_steps,int* num_results);
+		void   PatchFill(int* pcount, Patch* patch);
+		void   PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes);
+		void   PositiveDegreeDay(IssmDouble* pdds,IssmDouble* pds,IssmDouble signorm);
+		void   ProcessResultsUnits(void);
+		void   ResetCoordinateSystem(void);
+		void   SmbGradients();
+		IssmDouble SurfaceArea(void);
+		void   Update(int index, IoModel* iomodel,int analysis_counter,int analysis_type);
+		int    UpdatePotentialUngrounding(IssmDouble* potential_sheet_ungrounding,Vector<IssmDouble>* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf);
+		int    NodalValue(IssmDouble* pvalue, int index, int natureofdataenum,bool process_units);
+		IssmDouble TimeAdapt();
+		int*   GetHorizontalNeighboorSids(void);
+		void   ViscousHeatingCreateInput(void);
+		void   SmearFunction(Vector<IssmDouble>* smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius);
+
+		 #ifdef _HAVE_RESPONSES_
+		IssmDouble IceVolume(void);
+		IssmDouble TotalSmb(void);
+		void   MinVel(IssmDouble* pminvel, bool process_units);
+		void   MinVx(IssmDouble* pminvx, bool process_units);
+		void   MinVy(IssmDouble* pminvy, bool process_units);
+		void   MinVz(IssmDouble* pminvz, bool process_units);
+		IssmDouble MassFlux(IssmDouble* segment,bool process_units);
+		void   MaxAbsVx(IssmDouble* pmaxabsvx, bool process_units);
+		void   MaxAbsVy(IssmDouble* pmaxabsvy, bool process_units);
+		void   MaxAbsVz(IssmDouble* pmaxabsvz, bool process_units);
+		void   MaxVel(IssmDouble* pmaxvel, bool process_units);
+		void   ElementResponse(IssmDouble* presponse,int response_enum,bool process_units);
+		void   MaxVx(IssmDouble* pmaxvx, bool process_units);
+		void   MaxVy(IssmDouble* pmaxvy, bool process_units);
+		void   MaxVz(IssmDouble* pmaxvz, bool process_units);
+		#endif
+
+		#ifdef _HAVE_GIA_
+		void   GiaDeflection(Vector<IssmDouble>* wg,Vector<IssmDouble>* dwgdt,IssmDouble* x,IssmDouble* y);
+		#endif
+
+		#ifdef _HAVE_CONTROL_
+		IssmDouble DragCoefficientAbsGradient(bool process_units,int weight_index);
+		void   GradientIndexing(int* indexing,int control_index);
+		void   Gradj(Vector<IssmDouble>* gradient,int control_type,int control_index);
+		void   GradjDragMacAyeal(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjDragPattyn(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjDragStokes(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjBbarMacAyeal(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjBbarPattyn(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjBbarStokes(Vector<IssmDouble>* gradient,int control_index);
+		void   GetVectorFromControlInputs(Vector<IssmDouble>* gradient,int control_enum,int control_index,const char* data);
+		void   SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index);
+		void   ControlInputGetGradient(Vector<IssmDouble>* gradient,int enum_type,int control_index);
+		void   ControlInputScaleGradient(int enum_type,IssmDouble scale);
+		void   ControlInputSetGradient(IssmDouble* gradient,int enum_type,int control_index);
+		IssmDouble RheologyBbarAbsGradient(bool process_units,int weight_index);
+		IssmDouble ThicknessAbsMisfit(     bool process_units,int weight_index);
+		IssmDouble SurfaceAbsVelMisfit(    bool process_units,int weight_index);
+		IssmDouble SurfaceRelVelMisfit(    bool process_units,int weight_index);
+		IssmDouble SurfaceLogVelMisfit(    bool process_units,int weight_index);
+		IssmDouble SurfaceLogVxVyMisfit(   bool process_units,int weight_index);
+		IssmDouble SurfaceAverageVelMisfit(bool process_units,int weight_index);
+		IssmDouble ThicknessAbsGradient(bool process_units,int weight_index);
+		IssmDouble ThicknessAlongGradient( bool process_units,int weight_index){_error_("not supported");};
+		IssmDouble ThicknessAcrossGradient(bool process_units,int weight_index){_error_("not supported");};
+		IssmDouble BalancethicknessMisfit(bool process_units,int weight_index){_error_("not supported");};
+		void   InputControlUpdate(IssmDouble scalar,bool save_parameter);
+		#endif
+		/*}}}*/
+		/*Penta specific routines:{{{*/
+		void	  BedNormal(IssmDouble* bed_normal, IssmDouble xyz_list[3][3]);
+		ElementMatrix* CreateBasalMassMatrix(void);
+		ElementMatrix* CreateKMatrixPrognostic(void);
+		ElementVector* CreatePVectorPrognostic(void);
+		ElementVector* CreatePVectorSlope(void);
+		void	         GetDofList(int** pdoflist,int approximation_enum,int setenum);
+		void	         GetVertexPidList(int* doflist);
+		void           GetVertexSidList(int* sidlist);
+		void           GetConnectivityList(int* connectivity);
+		IssmDouble     GetGroundedPortion(IssmDouble* xyz_list);
+		int            GetElementType(void);
+		void           GetElementSizes(IssmDouble* hx,IssmDouble* hy,IssmDouble* hz);
+		void           GetInputListOnVertices(IssmDouble* pvalue,int enumtype);
+		void           GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue);
+		void           GetInputValue(IssmDouble* pvalue,Node* node,int enumtype);
+		void	         GetPhi(IssmDouble* phi, IssmDouble*  epsilon, IssmDouble viscosity);
+		void	         GetSolutionFromInputsEnthalpy(Vector<IssmDouble>* solutiong);
+		IssmDouble     GetStabilizationParameter(IssmDouble u, IssmDouble v, IssmDouble w, IssmDouble diameter, IssmDouble kappa);
+		void    GetStrainRate3dPattyn(IssmDouble* epsilon,IssmDouble* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input);
+		void    GetStrainRate3d(IssmDouble* epsilon,IssmDouble* xyz_list, GaussPenta* gauss, Input* vx_input, Input* vy_input, Input* vz_input);
+		Penta*  GetUpperElement(void);
+		Penta*  GetLowerElement(void);
+		Penta*  GetBasalElement(void);
+		void	  InputExtrude(int enum_type,int object_type);
+		void    InputUpdateFromSolutionPrognostic(IssmDouble* solutiong);
+		void    InputUpdateFromSolutionOneDof(IssmDouble* solutiong,int enum_type);
+		void    InputUpdateFromSolutionOneDofCollapsed(IssmDouble* solutiong,int enum_type);
+		bool	  IsInput(int name);
+		bool	  IsOnSurface(void);
+		bool	  IsOnBed(void);
+		bool    IsFloating(void); 
+		bool    IsNodeOnShelf(); 
+		bool    IsNodeOnShelfFromFlags(IssmDouble* flags);
+		bool    IsOnWater(void); 
+		IssmDouble  MinEdgeLength(IssmDouble xyz_list[6][3]);
+		void	  ReduceMatrixStokes(IssmDouble* Ke_reduced, IssmDouble* Ke_temp);
+		void	  ReduceVectorStokes(IssmDouble* Pe_reduced, IssmDouble* Ke_temp, IssmDouble* Pe_temp);
+		void	  SetClone(int* minranks);
+		Tria*	  SpawnTria(int g0, int g1, int g2);
+		void	  SurfaceNormal(IssmDouble* surface_normal, IssmDouble xyz_list[3][3]);
+
+		#ifdef _HAVE_DIAGNOSTIC_
+		ElementMatrix* CreateKMatrixCouplingMacAyealPattyn(void);
+		ElementMatrix* CreateKMatrixCouplingMacAyealPattynViscous(void);
+		ElementMatrix* CreateKMatrixCouplingMacAyealPattynFriction(void);
+		ElementMatrix* CreateKMatrixCouplingMacAyealStokes(void);
+		ElementMatrix* CreateKMatrixCouplingMacAyealStokesViscous(void);
+		ElementMatrix* CreateKMatrixCouplingMacAyealStokesFriction(void);
+		ElementMatrix* CreateKMatrixCouplingPattynStokes(void);
+		ElementMatrix* CreateKMatrixDiagnosticHoriz(void);
+		ElementMatrix* CreateKMatrixAdjointHoriz(void);
+		ElementVector* CreateDVectorDiagnosticHoriz(void);
+		ElementVector* CreateDVectorDiagnosticStokes(void);
+		ElementMatrix* CreateKMatrixDiagnosticHutter(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyeal2d(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyeal3d(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyeal3dViscous(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyeal3dFriction(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyealPattyn(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyealStokes(void);
+		ElementMatrix* CreateKMatrixDiagnosticL1L2(void);
+		ElementMatrix* CreateKMatrixDiagnosticL1L2Viscous(void);
+		ElementMatrix* CreateKMatrixDiagnosticL1L2Friction(void);
+		ElementMatrix* CreateKMatrixDiagnosticPattyn(void);
+		ElementMatrix* CreateKMatrixDiagnosticPattynViscous(void);
+		ElementMatrix* CreateKMatrixDiagnosticPattynFriction(void);
+		ElementMatrix* CreateKMatrixDiagnosticPattynStokes(void);
+		ElementMatrix* CreateKMatrixDiagnosticStokes(void);
+		ElementMatrix* CreateKMatrixDiagnosticStokesViscous(void);
+		ElementMatrix* CreateKMatrixDiagnosticStokesFriction(void);
+		ElementMatrix* CreateKMatrixDiagnosticVert(void);
+		ElementMatrix* CreateKMatrixDiagnosticVertVolume(void);
+		ElementMatrix* CreateKMatrixDiagnosticVertSurface(void);
+		ElementMatrix* CreateJacobianDiagnosticHoriz(void);
+		ElementMatrix* CreateJacobianDiagnosticMacayeal2d(void);
+		ElementMatrix* CreateJacobianDiagnosticPattyn(void);
+		ElementMatrix* CreateJacobianDiagnosticStokes(void);
+		void           InputUpdateFromSolutionDiagnosticHoriz( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticMacAyeal( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticMacAyealPattyn( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticMacAyealStokes( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticL1L2( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticPattyn( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticPattynStokes( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticHutter( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticVert( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticStokes( IssmDouble* solutiong);
+		void	         GetSolutionFromInputsDiagnosticHoriz(Vector<IssmDouble>* solutiong);
+		void	         GetSolutionFromInputsDiagnosticHutter(Vector<IssmDouble>* solutiong);
+		void	         GetSolutionFromInputsDiagnosticStokes(Vector<IssmDouble>* solutiong);
+		void	         GetSolutionFromInputsDiagnosticVert(Vector<IssmDouble>* solutiong);
+		ElementVector* CreatePVectorCouplingMacAyealStokes(void);
+		ElementVector* CreatePVectorCouplingMacAyealStokesViscous(void);
+		ElementVector* CreatePVectorCouplingMacAyealStokesFriction(void);
+		ElementVector* CreatePVectorCouplingPattynStokes(void);
+		ElementVector* CreatePVectorCouplingPattynStokesViscous(void);
+		ElementVector* CreatePVectorCouplingPattynStokesFriction(void);
+		ElementVector* CreatePVectorDiagnosticHoriz(void);
+		ElementVector* CreatePVectorDiagnosticHutter(void);
+		ElementVector* CreatePVectorDiagnosticMacAyeal(void);
+		ElementVector* CreatePVectorDiagnosticMacAyealPattyn(void);
+		ElementVector* CreatePVectorDiagnosticMacAyealStokes(void);
+		ElementVector* CreatePVectorDiagnosticL1L2(void);
+		ElementVector* CreatePVectorDiagnosticPattyn(void);
+		ElementVector* CreatePVectorDiagnosticPattynStokes(void);
+		ElementVector* CreatePVectorDiagnosticStokes(void);
+		ElementVector* CreatePVectorDiagnosticStokesViscous(void);
+		ElementVector* CreatePVectorDiagnosticStokesShelf(void);
+		ElementVector* CreatePVectorDiagnosticVert(void);
+		ElementVector* CreatePVectorDiagnosticVertVolume(void);
+		ElementVector* CreatePVectorDiagnosticVertBase(void);
+		void GetL1L2Viscosity(IssmDouble*, IssmDouble*, GaussPenta*, Input*, Input*, Input*);
+		#endif
+
+		#ifdef _HAVE_CONTROL_
+		ElementVector* CreatePVectorAdjointHoriz(void);
+		ElementMatrix* CreateKMatrixAdjointMacAyeal2d(void);
+		ElementMatrix* CreateKMatrixAdjointPattyn(void);
+		ElementMatrix* CreateKMatrixAdjointStokes(void);
+		ElementVector* CreatePVectorAdjointMacAyeal(void);
+		ElementVector* CreatePVectorAdjointPattyn(void);
+		ElementVector* CreatePVectorAdjointStokes(void);
+		void    InputUpdateFromSolutionAdjointHoriz( IssmDouble* solutiong);
+		void    InputUpdateFromSolutionAdjointStokes( IssmDouble* solutiong);
+		#endif
+
+		#ifdef _HAVE_HYDROLOGY_
+		void    CreateHydrologyWaterVelocityInput(void);
+		void    GetHydrologyDCInefficientHmax(IssmDouble* ph_max, Node* innode);
+		void    BasisIntegral(Vector<IssmDouble>* gbasis);
+		#endif
+		#ifdef _HAVE_THERMAL_
+		ElementMatrix* CreateKMatrixEnthalpy(void);
+		ElementMatrix* CreateKMatrixEnthalpyVolume(void);
+		ElementMatrix* CreateKMatrixEnthalpyShelf(void);
+		ElementMatrix* CreateKMatrixThermal(void);
+		ElementMatrix* CreateKMatrixMelting(void);
+		ElementMatrix* CreateKMatrixThermalVolume(void);
+		ElementMatrix* CreateKMatrixThermalShelf(void);
+		ElementVector* CreatePVectorEnthalpy(void);
+		ElementVector* CreatePVectorEnthalpyVolume(void);
+		ElementVector* CreatePVectorEnthalpyShelf(void);
+		ElementVector* CreatePVectorEnthalpySheet(void);
+		ElementVector* CreatePVectorMelting(void);
+		ElementVector* CreatePVectorThermal(void);
+		ElementVector* CreatePVectorThermalVolume(void);
+		ElementVector* CreatePVectorThermalShelf(void);
+		ElementVector* CreatePVectorThermalSheet(void);
+		void	       GetSolutionFromInputsThermal(Vector<IssmDouble>* solutiong);
+		void           InputUpdateFromSolutionThermal( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionEnthalpy( IssmDouble* solutiong);
+		#endif
+		#ifdef _HAVE_BALANCED_
+		ElementMatrix* CreateKMatrixBalancethickness(void);
+		ElementVector* CreatePVectorBalancethickness(void);
+		#endif
+		/*}}}*/
+};
+#endif  /* _PENTA_H */
Index: /issm/trunk-jpl/src/c/classes/Elements/PentaHook.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/PentaHook.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/PentaHook.cpp	(revision 15012)
@@ -0,0 +1,112 @@
+/*!\file PentaHook.c
+ * \brief: implementation of the PentaHook object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION PentaHook::PentaHook(){{{*/
+PentaHook::PentaHook(){
+	numanalyses=UNDEF;
+	this->hnodes     = NULL;
+	this->hvertices  = NULL;
+	this->hmaterial  = NULL;
+	this->hmatpar    = NULL;
+	this->hneighbors = NULL;
+}
+/*}}}*/
+/*FUNCTION PentaHook::~PentaHook(){{{*/
+PentaHook::~PentaHook(){
+
+	int i;
+
+	for(i=0;i<this->numanalyses;i++){
+		if (this->hnodes[i]) delete this->hnodes[i];
+	}
+	delete [] this->hnodes;
+	delete hvertices;
+	delete hmaterial;
+	delete hmatpar;
+	delete hneighbors;
+}
+/*}}}*/
+/*FUNCTION PentaHook::PentaHook(int in_numanalyses,int element_id, int matpar_id){{{*/
+PentaHook::PentaHook(int in_numanalyses,int element_id, IoModel* iomodel){
+
+	/*intermediary: */
+	int matpar_id;
+	int material_id;
+	int penta_vertex_ids[6];
+
+	/*retrieve material_id: */
+	iomodel->Constant(&matpar_id,MeshNumberofelementsEnum); matpar_id++;
+
+	/*retrive material_id*/
+	material_id = element_id;
+
+	/*retrieve vertices ids*/
+	for(int i=0;i<6;i++){ 
+		penta_vertex_ids[i]=reCast<int>(iomodel->Data(MeshElementsEnum)[6*(element_id-1)+i]);
+	}
+
+	this->numanalyses = in_numanalyses;
+	this->hnodes      = new Hook*[in_numanalyses];
+	this->hvertices   = new Hook(&penta_vertex_ids[0],6);
+	this->hmaterial   = new Hook(&material_id,1);
+	this->hmatpar     = new Hook(&matpar_id,1);
+	this->hneighbors  = NULL;
+
+	//Initialize hnodes as NULL
+	for(int i=0;i<this->numanalyses;i++){
+		this->hnodes[i]=NULL;
+	}
+
+}
+/*}}}*/
+
+/*FUNCTION PentaHook::SetHookNodes{{{*/
+void PentaHook::SetHookNodes(int* node_ids,int analysis_counter){
+	this->hnodes[analysis_counter]= new Hook(node_ids,6);
+}
+/*}}}*/
+/*FUNCTION PentaHook::InitHookNeighbors{{{*/
+void PentaHook::InitHookNeighbors(int* element_ids){
+	this->hneighbors=new Hook(element_ids,2);
+
+}
+/*}}}*/
+/*FUNCTION PentaHook::SpawnTriaHook{{{*/
+void PentaHook::SpawnTriaHook(TriaHook* triahook,int* indices){
+
+	int i;
+	int zero=0;
+
+	triahook->numanalyses=this->numanalyses;
+	triahook->hnodes=new Hook*[this->numanalyses];
+
+	for(i=0;i<this->numanalyses;i++){
+		/*Do not do anything if Hook is empty*/
+		if (!this->hnodes[i] || this->hnodes[i]->GetNum()==0){
+			triahook->hnodes[i]=NULL;
+		}
+		else{
+			/*Else, spawn Hook*/
+			triahook->hnodes[i]=this->hnodes[i]->Spawn(indices,3);
+		}
+	}
+	// do not spawn hmaterial. material will be taken care of by Penta
+	triahook->hmaterial=NULL;
+	triahook->hvertices=(Hook*)this->hvertices->Spawn(indices,3);
+	triahook->hmatpar=(Hook*)this->hmatpar->copy();
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Elements/PentaHook.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/PentaHook.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/PentaHook.h	(revision 15012)
@@ -0,0 +1,32 @@
+/*!\file: PentaHook.h
+ * \brief prototypes for PentaHook.h
+ */ 
+
+#ifndef _PENTAHOOK_H_
+#define  _PENTAHOOK_H_
+
+class Hook;
+class TriaHook;
+class IoModel;
+
+class PentaHook{
+
+	public: 
+		int    numanalyses;   //number of analysis types
+		Hook **hnodes;        // set of nodes for each analysis type
+		Hook  *hvertices;     // 6 vertices for each analysis type
+		Hook  *hmaterial;     // 1 ice material
+		Hook  *hmatpar;       // 1 material parameter
+		Hook  *hneighbors;    // 2 elements, first down, second up
+
+		/*constructors, destructors*/
+		PentaHook();
+		PentaHook(int in_numanalyses,int material_id, IoModel* iomodel);
+		~PentaHook();
+
+		void SetHookNodes(int* node_ids,int analysis_counter);
+		void SpawnTriaHook(TriaHook* triahook,int* indices);
+		void InitHookNeighbors(int* element_ids);
+};
+
+#endif //ifndef _PENTAHOOK_H_
Index: /issm/trunk-jpl/src/c/classes/Elements/PentaRef.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/PentaRef.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/PentaRef.cpp	(revision 15012)
@@ -0,0 +1,1258 @@
+/*!\file PentaRef.c
+ * \brief: implementation of the PentaRef object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMNODESP1    6
+#define NUMNODESP1_2d 3
+#define NUMNODESMINI  7
+
+/*Object constructors and destructor*/
+/*FUNCTION PentaRef::PentaRef(){{{*/
+PentaRef::PentaRef(){
+	this->element_type_list=NULL;
+}
+/*}}}*/
+/*FUNCTION PentaRef::PentaRef(int* types,int nummodels){{{*/
+PentaRef::PentaRef(const int nummodels){
+
+	/*Only allocate pointer*/
+	element_type_list=xNew<int>(nummodels);
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::~PentaRef(){{{*/
+PentaRef::~PentaRef(){
+	xDelete<int>(element_type_list);
+}
+/*}}}*/
+
+/*Management*/
+/*FUNCTION PentaRef::SetElementType{{{*/
+void PentaRef::SetElementType(int type,int type_counter){
+
+	_assert_(type==P1Enum || type==P1DGEnum);
+
+	/*initialize element type*/
+	this->element_type_list[type_counter]=type;
+}
+/*}}}*/
+
+/*Reference Element numerics*/
+/*FUNCTION PentaRef::GetBMacAyealPattyn {{{*/
+void PentaRef::GetBMacAyealPattyn(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ dh/dx          0      ]
+	 *          [   0           dh/dy   ]
+	 *          [ 1/2*dh/dy  1/2*dh/dx  ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 5x(NDOF2*NUMNODESP1)
+	 */
+
+	IssmDouble dbasis[3][NUMNODESP1];
+
+	/*Get dbasis in actual coordinate system: */
+	GetNodalFunctionsP1Derivatives(&dbasis[0][0],xyz_list, gauss);
+
+	/*Build B: */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i)=dbasis[0][i]; 
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i+1)=0.0;
+
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i)=0.0;
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i+1)=dbasis[1][i];
+
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i)=(float).5*dbasis[1][i]; 
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i+1)=(float).5*dbasis[0][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBMacAyealStokes{{{*/
+void PentaRef::GetBMacAyealStokes(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ dh/dx          0       0   0 ]
+	 *          [   0           dh/dy    0   0 ]
+	 *          [ 1/2*dh/dy  1/2*dh/dx   0   0 ]
+	 *          [   0            0       0   h ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 5x(NDOF2*NUMNODESP1)
+	 */
+
+	int    i;
+	IssmDouble dh1dh7[3][NUMNODESMINI];
+	IssmDouble l1l6[NUMNODESP1];
+
+	/*Get dh1dh6 in actual coordinate system: */
+	GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss);
+	GetNodalFunctionsP1(l1l6, gauss);
+
+	/*Build B: */
+	for (i=0;i<NUMNODESMINI;i++){
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i)=dh1dh7[0][i]; //B[0][NDOF4*i]=dh1dh6[0][i];
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+1)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+1)=dh1dh7[1][i];
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i)=0.5*dh1dh7[1][i];
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+1)=0.5*dh1dh7[0][i];
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+1)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+2)=0;
+	}
+
+	for (i=0;i<NUMNODESP1;i++){ //last column not for the bubble function
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+3)=l1l6[i];
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBPattyn {{{*/
+void PentaRef::GetBPattyn(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ dh/dx          0      ]
+	 *          [   0           dh/dy   ]
+	 *          [ 1/2*dh/dy  1/2*dh/dx  ]
+	 *          [ 1/2*dh/dz      0      ]
+	 *          [  0         1/2*dh/dz  ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 5x(NDOF2*NUMNODESP1)
+	 */
+
+	IssmDouble dbasis[3][NUMNODESP1];
+
+	/*Get dbasis in actual coordinate system: */
+	GetNodalFunctionsP1Derivatives(&dbasis[0][0],xyz_list, gauss);
+
+	/*Build B: */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i)=dbasis[0][i]; 
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i+1)=0.0;
+
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i)=0.0;
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i+1)=dbasis[1][i];
+
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i)=(float).5*dbasis[1][i]; 
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i+1)=(float).5*dbasis[0][i]; 
+
+		*(B+NDOF2*NUMNODESP1*3+NDOF2*i)=(float).5*dbasis[2][i]; 
+		*(B+NDOF2*NUMNODESP1*3+NDOF2*i+1)=0.0;
+
+		*(B+NDOF2*NUMNODESP1*4+NDOF2*i)=0.0;
+		*(B+NDOF2*NUMNODESP1*4+NDOF2*i+1)=(float).5*dbasis[2][i]; 
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBprimePattyn {{{*/
+void PentaRef::GetBprimePattyn(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss_coord){
+	/*Compute B  prime matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ 2*dh/dx     dh/dy   ]
+	 *                [   dh/dx    2*dh/dy  ]
+	 *                [ dh/dy      dh/dx    ]
+	 *                [ dh/dz         0     ]
+	 *                [  0         dh/dz    ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 5x(NDOF2*NUMNODESP1)
+	 */
+	IssmDouble dbasis[3][NUMNODESP1];
+
+	/*Get dbasis in actual coordinate system: */
+	GetNodalFunctionsP1Derivatives(&dbasis[0][0],xyz_list, gauss_coord);
+
+	/*Build BPrime: */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i)=2.0*dbasis[0][i]; 
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i+1)=dbasis[1][i];
+
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i)=dbasis[0][i];
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i+1)=2.0*dbasis[1][i];
+
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i)=dbasis[1][i]; 
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i+1)=dbasis[0][i]; 
+
+		*(B+NDOF2*NUMNODESP1*3+NDOF2*i)=dbasis[2][i]; 
+		*(B+NDOF2*NUMNODESP1*3+NDOF2*i+1)=0.0;
+
+		*(B+NDOF2*NUMNODESP1*4+NDOF2*i)=0.0;
+		*(B+NDOF2*NUMNODESP1*4+NDOF2*i+1)=dbasis[2][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBprimeMacAyealStokes{{{*/
+void PentaRef::GetBprimeMacAyealStokes(IssmDouble* Bprime, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute Bprime  matrix. Bprime=[Bprime1 Bprime2 Bprime3 Bprime4 Bprime5 Bprime6] where Bprimei is of size 5*NDOF2. 
+	 * For node i, Bprimei can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bprimei=[ 2*dh/dx    dh/dy   0   0 ]
+	 *               [  dh/dx    2*dh/dy  0   0 ]
+	 *               [  dh/dy     dh/dx   0   0 ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume Bprime has been allocated already, of size: 5x(NDOF2*NUMNODESP1)
+	 */
+
+	int    i;
+	IssmDouble dh1dh7[3][NUMNODESMINI];
+
+	/*Get dh1dh6 in actual coordinate system: */
+	GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss);
+
+	/*Build Bprime: */
+	for (i=0;i<NUMNODESMINI;i++){
+		*(Bprime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i)=2*dh1dh7[0][i]; //Bprime[0][NDOF4*i]=dh1dh6[0][i];
+		*(Bprime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+1)=dh1dh7[1][i];
+		*(Bprime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+2)=0;
+		*(Bprime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i)=dh1dh7[0][i];
+		*(Bprime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+1)=2*dh1dh7[1][i];
+		*(Bprime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+2)=0;
+		*(Bprime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i)=dh1dh7[1][i];
+		*(Bprime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+1)=dh1dh7[0][i];
+		*(Bprime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+2)=0;
+	}
+
+	for (i=0;i<NUMNODESP1;i++){ //last column not for the bubble function
+		*(Bprime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+3)=0;
+		*(Bprime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+3)=0;
+		*(Bprime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+3)=0;
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBStokes {{{*/
+void PentaRef::GetBStokes(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 3*NDOF4. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 		Bi=[ dh/dx          0              0       0  ]
+	 *					[   0           dh/dy           0       0  ]
+	 *					[   0             0           dh/dy     0  ]
+	 *					[ 1/2*dh/dy    1/2*dh/dx        0       0  ]
+	 *					[ 1/2*dh/dz       0         1/2*dh/dx   0  ]
+	 *					[   0          1/2*dh/dz    1/2*dh/dy   0  ]
+	 *					[   0             0             0       h  ]
+	 *					[ dh/dx         dh/dy         dh/dz     0  ]
+	 *	where h is the interpolation function for node i.
+	 *	Same thing for Bb except the last column that does not exist.
+	 */
+
+	int i;
+
+	IssmDouble dh1dh7[3][NUMNODESMINI];
+	IssmDouble l1l6[NUMNODESP1];
+
+	/*Get dh1dh7 in actual coordinate system: */
+	GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss);
+	GetNodalFunctionsP1(l1l6, gauss);
+
+	/*Build B: */
+	for (i=0;i<NUMNODESMINI;i++){
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i)=dh1dh7[0][i]; //B[0][NDOF4*i]=dh1dh6[0][i];
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+1)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+1)=dh1dh7[1][i];
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+1)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+2)=dh1dh7[2][i];
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i)=(float).5*dh1dh7[1][i]; 
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+1)=(float).5*dh1dh7[0][i]; 
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*4+NDOF4*i)=(float).5*dh1dh7[2][i];
+		*(B+(NDOF4*NUMNODESP1+3)*4+NDOF4*i+1)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*4+NDOF4*i+2)=(float).5*dh1dh7[0][i];
+		*(B+(NDOF4*NUMNODESP1+3)*5+NDOF4*i)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*5+NDOF4*i+1)=(float).5*dh1dh7[2][i];
+		*(B+(NDOF4*NUMNODESP1+3)*5+NDOF4*i+2)=(float).5*dh1dh7[1][i];
+		*(B+(NDOF4*NUMNODESP1+3)*6+NDOF4*i)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*6+NDOF4*i+1)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*6+NDOF4*i+2)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*7+NDOF4*i)=dh1dh7[0][i];
+		*(B+(NDOF4*NUMNODESP1+3)*7+NDOF4*i+1)=dh1dh7[1][i];
+		*(B+(NDOF4*NUMNODESP1+3)*7+NDOF4*i+2)=dh1dh7[2][i];
+	}
+
+	for (i=0;i<NUMNODESP1;i++){ //last column not for the bubble function
+		*(B+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*4+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*5+NDOF4*i+3)=0;
+		*(B+(NDOF4*NUMNODESP1+3)*6+NDOF4*i+3)=l1l6[i];
+		*(B+(NDOF4*NUMNODESP1+3)*7+NDOF4*i+3)=0;
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBprimeStokes {{{*/
+void PentaRef::GetBprimeStokes(IssmDouble* B_prime, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*	Compute B'  matrix. B'=[B1' B2' B3' B4' B5' B6' Bb'] where Bi' is of size 3*NDOF2. 
+	 *	For node i, Bi' can be expressed in the actual coordinate system
+	 *	by: 
+	 *				Bi'=[  dh/dx   0          0       0]
+	 *					 [   0      dh/dy      0       0]
+	 *					 [   0      0         dh/dz    0]
+	 *					 [  dh/dy   dh/dx      0       0]
+	 *					 [  dh/dz   0        dh/dx     0]
+	 *					 [   0      dh/dz    dh/dy     0]
+	 *					 [  dh/dx   dh/dy    dh/dz     0]
+	 *					 [   0      0          0       h]
+	 *	where h is the interpolation function for node i.
+	 *
+	 * 	Same thing for the bubble fonction except that there is no fourth column
+	 */
+
+	int i;
+	IssmDouble dh1dh7[3][NUMNODESMINI];
+	IssmDouble l1l6[NUMNODESP1];
+
+	/*Get dh1dh7 in actual coordinate system: */
+	GetNodalFunctionsMINIDerivatives(&dh1dh7[0][0],xyz_list, gauss);
+	GetNodalFunctionsP1(l1l6, gauss);
+
+	/*B_primeuild B_prime: */
+	for (i=0;i<NUMNODESMINI;i++){
+		*(B_prime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i)=dh1dh7[0][i]; //B_prime[0][NDOF4*i]=dh1dh6[0][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+1)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+2)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+1)=dh1dh7[1][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+2)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+1)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+2)=dh1dh7[2][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*3+NDOF4*i)=dh1dh7[1][i]; 
+		*(B_prime+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+1)=dh1dh7[0][i]; 
+		*(B_prime+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+2)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*4+NDOF4*i)=dh1dh7[2][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*4+NDOF4*i+1)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*4+NDOF4*i+2)=dh1dh7[0][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*5+NDOF4*i)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*5+NDOF4*i+1)=dh1dh7[2][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*5+NDOF4*i+2)=dh1dh7[1][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*6+NDOF4*i)=dh1dh7[0][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*6+NDOF4*i+1)=dh1dh7[1][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*6+NDOF4*i+2)=dh1dh7[2][i];
+		*(B_prime+(NDOF4*NUMNODESP1+3)*7+NDOF4*i)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*7+NDOF4*i+1)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*7+NDOF4*i+2)=0;
+	}
+
+	for (i=0;i<NUMNODESP1;i++){ //last column not for the bubble function
+		*(B_prime+(NDOF4*NUMNODESP1+3)*0+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*1+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*2+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*3+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*4+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*5+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*6+NDOF4*i+3)=0;
+		*(B_prime+(NDOF4*NUMNODESP1+3)*7+NDOF4*i+3)=l1l6[i];
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBAdvec{{{*/
+void PentaRef::GetBAdvec(IssmDouble* B_advec, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF1. 
+	 * For node i, Bi' can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi_advec =[ h ]
+	 *                 [ h ]
+	 *                 [ h ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 3x(NDOF1*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble l1l6[6];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsP1(l1l6, gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B_advec+NDOF1*NUMNODESP1*0+NDOF1*i)=l1l6[i]; 
+		*(B_advec+NDOF1*NUMNODESP1*1+NDOF1*i)=l1l6[i]; 
+		*(B_advec+NDOF1*NUMNODESP1*2+NDOF1*i)=l1l6[i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBConduct{{{*/
+void PentaRef::GetBConduct(IssmDouble* B_conduct, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF1. 
+	 * For node i, Bi' can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi_conduct=[ dh/dx ]
+	 *                  [ dh/dy ]
+	 *                  [ dh/dz ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 3x(NDOF1*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B_conduct+NDOF1*NUMNODESP1*0+NDOF1*i)=dh1dh6[0][i]; 
+		*(B_conduct+NDOF1*NUMNODESP1*1+NDOF1*i)=dh1dh6[1][i]; 
+		*(B_conduct+NDOF1*NUMNODESP1*2+NDOF1*i)=dh1dh6[2][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBVert{{{*/
+void PentaRef::GetBVert(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*	Compute B  matrix. B=[dh1/dz dh2/dz dh3/dz dh4/dz dh5/dz dh6/dz];
+		where hi is the interpolation function for node i.*/
+
+	int i;
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get dh1dh6 in actual coordinate system: */
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list, gauss);
+
+	/*Build B: */
+	for (i=0;i<NUMNODESP1;i++){
+		B[i]=dh1dh6[2][i];  
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBprimeAdvec{{{*/
+void PentaRef::GetBprimeAdvec(IssmDouble* Bprime_advec, IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3 B4 B5 B6] where Bi is of size 5*NDOF1. 
+	 * For node i, Bi' can be expressed in the actual coordinate system
+	 * by: 
+	 *       Biprime_advec=[ dh/dx ]
+	 *                     [ dh/dy ]
+	 *                     [ dh/dz ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 3x(NDOF1*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(Bprime_advec+NDOF1*NUMNODESP1*0+NDOF1*i)=dh1dh6[0][i]; 
+		*(Bprime_advec+NDOF1*NUMNODESP1*1+NDOF1*i)=dh1dh6[1][i]; 
+		*(Bprime_advec+NDOF1*NUMNODESP1*2+NDOF1*i)=dh1dh6[2][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetBprimeVert{{{*/
+void PentaRef::GetBprimeVert(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss){
+	/* Compute Bprime  matrix. Bprime=[L1 L2 L3 L4 L5 L6] where Li is the nodal function for node i*/
+
+	GetNodalFunctionsP1(B, gauss);
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetL{{{*/
+void PentaRef::GetL(IssmDouble* L, GaussPenta* gauss, int numdof){
+	/*Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof. 
+	 ** For node i, Li can be expressed in the actual coordinate system
+	 ** by: 
+	 **       numdof=1: 
+	 **                 Li=h;
+	 **       numdof=2:
+	 **                 Li=[ h   0 ]
+	 **                    [ 0   h ]
+	 ** where h is the interpolation function for node i.
+	 **
+	 ** We assume L has been allocated already, of size: NUMNODESP1 (numdof=1), or numdofx(numdof*NUMNODESP1) (numdof=2)
+	 **/
+
+	int i;
+	IssmDouble l1l6[6];
+
+	/*Get l1l6 in actual coordinate system: */
+	GetNodalFunctionsP1(l1l6,gauss);
+
+	/*Build L: */
+	if(numdof==1){
+		for (i=0;i<NUMNODESP1;i++){
+			L[i]=l1l6[i]; 
+		}
+	}
+	else{
+		for (i=0;i<NUMNODESP1;i++){
+			*(L+numdof*NUMNODESP1*0+numdof*i)=l1l6[i]; 
+			*(L+numdof*NUMNODESP1*0+numdof*i+1)=0;
+			*(L+numdof*NUMNODESP1*1+numdof*i)=0;
+			*(L+numdof*NUMNODESP1*1+numdof*i+1)=l1l6[i];
+		}
+	}
+} 
+/*}}}*/
+/*FUNCTION PentaRef::GetLStokes{{{*/
+void PentaRef::GetLStokes(IssmDouble* LStokes, GaussPenta* gauss){
+	/*
+	 * Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof. 
+	 * For node i, Li can be expressed in the actual coordinate system
+	 * by: 
+	 *       Li=[ h 0 ]
+	 *	 	      [ 0 h ]
+	 *		      [ 0 0 ]
+	 *		      [ 0 0 ]
+	 * where h is the interpolation function for node i.
+	 */
+
+	const int num_dof=4;
+	IssmDouble l1l2l3[NUMNODESP1_2d];
+
+	/*Get l1l2l3 in actual coordinate system: */
+	l1l2l3[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l2l3[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l2l3[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+
+	/*Build LStokes: */
+	for (int i=0;i<3;i++){
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+0)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+1)=0.;
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+2)=0.;
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+3)=0.;
+
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+0)=0.;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+2)=0.;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+3)=0.;
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetLprimeStokes {{{*/
+void PentaRef::GetLprimeStokes(IssmDouble* LprimeStokes, IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*
+	 * Compute Lprime  matrix. Lprime=[Lp1 Lp2 Lp3] where Lpi is square and of size numdof. 
+	 * For node i, Lpi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Lpi=[ h    0    0   0]1
+	 *		       [ 0    h    0   0]2
+	 *		       [ h    0    0   0]3
+	 *		       [ 0    h    0   0]4
+	 *		       [ 0    0    h   0]5
+	 *		       [ 0    0    h   0]6
+	 *		       [ 0    0  dh/dz 0]7
+	 *		       [ 0    0  dh/dz 0]8
+	 *		       [ 0    0  dh/dz 0]9
+	 *		       [dh/dz 0  dh/dx 0]0
+	 *		       [ 0 dh/dz dh/dy 0]1
+	 *           [ 0    0    0   h]2
+	 *           [ 0    0    0   h]3
+	 *           [ 0    0    0   h]4
+	 *
+	 *       Li=[ h    0    0   0]1
+	 *	 	      [ 0    h    0   0]2
+	 *		      [ 0    0    h   0]3
+	 *		      [ 0    0    h   0]4
+	 *	 	      [ h    0    0   0]5
+	 *	 	      [ 0    h    0   0]6
+	 *	 	      [ h    0    0   0]7
+	 *	 	      [ 0    h    0   0]8
+	 *		      [ 0    0    h   0]9
+	 *		      [ 0    0    h   0]0
+	 *		      [ 0    0    h   0]1
+	 *	 	      [ h    0    0   0]2
+	 *	 	      [ 0    h    0   0]3
+	 *		      [ 0    0    h   0]4
+	 * where h is the interpolation function for node i.
+	 */
+	int i;
+	int num_dof=4;
+
+	IssmDouble l1l2l3[NUMNODESP1_2d];
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get l1l2l3 in actual coordinate system: */
+	l1l2l3[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l2l3[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l2l3[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
+
+	/*Build LprimeStokes: */
+	for (i=0;i<3;i++){
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i)=l1l2l3[i]; //LprimeStokes[0][NDOF2*i]=dh1dh3[0][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+1)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+2)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+2)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+2)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+2)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*8+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*8+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*8+num_dof*i+2)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*8+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*9+num_dof*i)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*9+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*9+num_dof*i+2)=dh1dh6[0][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*9+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*10+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*10+num_dof*i+1)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*10+num_dof*i+2)=dh1dh6[1][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*10+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*11+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*11+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*11+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*11+num_dof*i+3)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*12+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*12+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*12+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*12+num_dof*i+3)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*13+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*13+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*13+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*13+num_dof*i+3)=l1l2l3[i];
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetLMacAyealStokes {{{*/
+void PentaRef::GetLMacAyealStokes(IssmDouble* LStokes, GaussPenta* gauss){
+	/*
+	 * Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof. 
+	 * For node i, Li can be expressed in the actual coordinate system
+	 * by: 
+	 *       Li=[ h    0 ]
+	 *	 	      [ 0    h ]
+	 *	 	      [ h    0 ]
+	 *	 	      [ 0    h ]
+	 *	 	      [ h    0 ]
+	 *	 	      [ 0    h ]
+	 *	 	      [ h    0 ]
+	 *	 	      [ 0    h ]
+	 * where h is the interpolation function for node i.
+	 */
+
+	int i;
+	int num_dof=2;
+
+	IssmDouble l1l2l3[NUMNODESP1_2d];
+
+	/*Get l1l2l3 in actual coordinate system: */
+	l1l2l3[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l2l3[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l2l3[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+
+	/*Build LStokes: */
+	for (i=0;i<3;i++){
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i)=l1l2l3[i]; //LStokes[0][NDOF2*i]=dh1dh3[0][i];
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*2+num_dof*i)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*3+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*4+num_dof*i)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*5+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*6+num_dof*i)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*7+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+1)=l1l2l3[i];
+
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetLprimeMacAyealStokes {{{*/
+void PentaRef::GetLprimeMacAyealStokes(IssmDouble* LprimeStokes, IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*
+	 * Compute Lprime  matrix. Lprime=[Lp1 Lp2 Lp3] where Lpi is square and of size numdof. 
+	 * For node i, Lpi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Lpi=[ h    0    0   0]
+	 *		       [ 0    h    0   0]
+	 *		       [ 0    0    h   0]
+	 *		       [ 0    0    h   0]
+	 *		       [ 0    0  dh/dz 0]
+	 *		       [ 0    0  dh/dz 0]
+	 *           [ 0    0    0   h]
+	 *           [ 0    0    0   h]
+	 * where h is the interpolation function for node i.
+	 */
+	int i;
+	int num_dof=4;
+
+	IssmDouble l1l2l3[NUMNODESP1_2d];
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get l1l2l3 in actual coordinate system: */
+	l1l2l3[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l2l3[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l2l3[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
+
+	/*Build LprimeStokes: */
+	for (i=0;i<3;i++){
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i)=l1l2l3[i]; //LprimeStokes[0][NDOF2*i]=dh1dh3[0][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+2)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+2)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+2)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*4+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+2)=dh1dh6[2][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*5+num_dof*i+3)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*6+num_dof*i+3)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+2)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*7+num_dof*i+3)=l1l2l3[i];
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetLStokesMacAyeal {{{*/
+void PentaRef::GetLStokesMacAyeal(IssmDouble* LStokes, GaussPenta* gauss){
+	/*
+	 * Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof. 
+	 * For node i, Li can be expressed in the actual coordinate system
+	 * by: 
+	 *       Li=[ h    0    0   0]
+	 *	 	      [ 0    h    0   0]
+	 *		      [ 0    0    h   0]
+	 *		      [ 0    0    h   0]
+	 * where h is the interpolation function for node i.
+	 */
+
+	int i;
+	int num_dof=4;
+
+	IssmDouble l1l2l3[NUMNODESP1_2d];
+
+	/*Get l1l2l3 in actual coordinate system: */
+	l1l2l3[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l2l3[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l2l3[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+
+	/*Build LStokes: */
+	for (i=0;i<3;i++){
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i)=l1l2l3[i]; //LStokes[0][NDOF2*i]=dh1dh3[0][i];
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+2)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+3)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+2)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+3)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*2+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+3)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*3+num_dof*i)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+1)=0;
+		*(LStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+2)=l1l2l3[i];
+		*(LStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+3)=0;
+
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetLprimeStokesMacAyeal {{{*/
+void PentaRef::GetLprimeStokesMacAyeal(IssmDouble* LprimeStokes, IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*
+	 * Compute Lprime  matrix. Lprime=[Lp1 Lp2 Lp3] where Lpi is square and of size numdof. 
+	 * For node i, Lpi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Lpi=[ h    0 ]
+	 *		       [ 0    h ]
+	 *		       [ h    0 ]
+	 *		       [ 0    h ]
+	 * where h is the interpolation function for node i.
+	 */
+	int i;
+	int num_dof=2;
+
+	IssmDouble l1l2l3[NUMNODESP1_2d];
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get l1l2l3 in actual coordinate system: */
+	l1l2l3[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l2l3[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l2l3[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list,gauss);
+
+	/*Build LprimeStokes: */
+	for (i=0;i<3;i++){
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i)=l1l2l3[i]; //LprimeStokes[0][NDOF2*i]=dh1dh3[0][i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*0+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*1+num_dof*i+1)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i)=l1l2l3[i];
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*2+num_dof*i+1)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i)=0;
+		*(LprimeStokes+num_dof*NUMNODESP1_2d*3+num_dof*i+1)=l1l2l3[i];
+	}
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetJacobian {{{*/
+void PentaRef::GetJacobian(IssmDouble* J, IssmDouble* xyz_list,GaussPenta* gauss){
+
+	/*The Jacobian is constant over the element, discard the gaussian points. 
+	 * J is assumed to have been allocated of size NDOF2xNDOF2.*/
+
+	IssmDouble A1,A2,A3; //area coordinates
+	IssmDouble xi,eta,zi; //parametric coordinates
+
+	IssmDouble x1,x2,x3,x4,x5,x6;
+	IssmDouble y1,y2,y3,y4,y5,y6;
+	IssmDouble z1,z2,z3,z4,z5,z6;
+
+	/*Figure out xi,eta and zi (parametric coordinates), for this gaussian point: */
+	A1=gauss->coord1;
+	A2=gauss->coord2;
+	A3=gauss->coord3;
+
+	xi  = A2-A1;
+	eta = SQRT3*A3;
+	zi  = gauss->coord4;
+
+	x1=*(xyz_list+3*0+0);
+	x2=*(xyz_list+3*1+0);
+	x3=*(xyz_list+3*2+0);
+	x4=*(xyz_list+3*3+0);
+	x5=*(xyz_list+3*4+0);
+	x6=*(xyz_list+3*5+0);
+
+	y1=*(xyz_list+3*0+1);
+	y2=*(xyz_list+3*1+1);
+	y3=*(xyz_list+3*2+1);
+	y4=*(xyz_list+3*3+1);
+	y5=*(xyz_list+3*4+1);
+	y6=*(xyz_list+3*5+1);
+
+	z1=*(xyz_list+3*0+2);
+	z2=*(xyz_list+3*1+2);
+	z3=*(xyz_list+3*2+2);
+	z4=*(xyz_list+3*3+2);
+	z5=*(xyz_list+3*4+2);
+	z6=*(xyz_list+3*5+2);
+
+	*(J+NDOF3*0+0)=0.25*(x1-x2-x4+x5)*zi+0.25*(-x1+x2-x4+x5);
+	*(J+NDOF3*1+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*zi+SQRT3/12.0*(-x1-x2+2*x3-x4-x5+2*x6);
+	*(J+NDOF3*2+0)=SQRT3/12.0*(x1+x2-2*x3-x4-x5+2*x6)*eta+1/4*(x1-x2-x4+x5)*xi +0.25*(-x1+x5-x2+x4);
+
+	*(J+NDOF3*0+1)=0.25*(y1-y2-y4+y5)*zi+0.25*(-y1+y2-y4+y5);
+	*(J+NDOF3*1+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*zi+SQRT3/12.0*(-y1-y2+2*y3-y4-y5+2*y6);
+	*(J+NDOF3*2+1)=SQRT3/12.0*(y1+y2-2*y3-y4-y5+2*y6)*eta+0.25*(y1-y2-y4+y5)*xi+0.25*(y4-y1+y5-y2);
+
+	*(J+NDOF3*0+2)=0.25*(z1-z2-z4+z5)*zi+0.25*(-z1+z2-z4+z5);
+	*(J+NDOF3*1+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*zi+SQRT3/12.0*(-z1-z2+2*z3-z4-z5+2*z6);
+	*(J+NDOF3*2+2)=SQRT3/12.0*(z1+z2-2*z3-z4-z5+2*z6)*eta+0.25*(z1-z2-z4+z5)*xi+0.25*(-z1+z5-z2+z4);
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetJacobianDeterminant {{{*/
+void PentaRef::GetJacobianDeterminant(IssmDouble*  Jdet, IssmDouble* xyz_list,GaussPenta* gauss){
+	/*On a penta, Jacobian varies according to coordinates. We need to get the Jacobian, and take 
+	 * the determinant of it: */
+	IssmDouble J[3][3];
+
+	/*Get Jacobian*/
+	GetJacobian(&J[0][0],xyz_list,gauss);
+
+	/*Get Determinant*/
+	Matrix3x3Determinant(Jdet,&J[0][0]);
+	if(*Jdet<0) _error_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetTriaJacobianDeterminant{{{*/
+void PentaRef::GetTriaJacobianDeterminant(IssmDouble*  Jdet, IssmDouble* xyz_list,GaussPenta* gauss){
+	/*The Jacobian determinant is constant over the element, discard the gaussian points. 
+	 * J is assumed to have been allocated of size NDOF2xNDOF2.*/
+
+	IssmDouble x1,x2,x3,y1,y2,y3,z1,z2,z3;
+
+	x1=*(xyz_list+3*0+0);
+	y1=*(xyz_list+3*0+1);
+	z1=*(xyz_list+3*0+2);
+	x2=*(xyz_list+3*1+0);
+	y2=*(xyz_list+3*1+1);
+	z2=*(xyz_list+3*1+2);
+	x3=*(xyz_list+3*2+0);
+	y3=*(xyz_list+3*2+1);
+	z3=*(xyz_list+3*2+2);
+
+	/*Jdet = norm( AB ^ AC ) / (2 * area of the reference triangle), with areaRef=sqrt(3) */
+	*Jdet=SQRT3/6.0*pow(pow(((y2-y1)*(z3-z1)-(z2-z1)*(y3-y1)),2.0)+pow(((z2-z1)*(x3-x1)-(x2-x1)*(z3-z1)),2.0)+pow(((x2-x1)*(y3-y1)-(y2-y1)*(x3-x1)),2.0),0.5);
+	if(*Jdet<0) _error_("negative jacobian determinant!");
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetSegmentJacobianDeterminant{{{*/
+void PentaRef::GetSegmentJacobianDeterminant(IssmDouble*  Jdet, IssmDouble* xyz_list,GaussPenta* gauss){
+	/*The Jacobian determinant is constant over the element, discard the gaussian points. 
+	 * J is assumed to have been allocated of size NDOF2xNDOF2.*/
+
+	IssmDouble x1,x2,y1,y2,z1,z2;
+
+	x1=*(xyz_list+3*0+0);
+	y1=*(xyz_list+3*0+1);
+	z1=*(xyz_list+3*0+2);
+	x2=*(xyz_list+3*1+0);
+	y2=*(xyz_list+3*1+1);
+	z2=*(xyz_list+3*1+2);
+
+	*Jdet=1.0/2.0*sqrt(pow(x2-x1,2.) + pow(y2-y1,2.) + pow(z2-z1,2.));
+	if(*Jdet<0) _error_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetJacobianInvert {{{*/
+void PentaRef::GetJacobianInvert(IssmDouble* Jinv, IssmDouble* xyz_list,GaussPenta* gauss){
+
+	/*Jacobian*/
+	IssmDouble J[3][3];
+
+	/*Call Jacobian routine to get the jacobian:*/
+	GetJacobian(&J[0][0], xyz_list, gauss);
+
+	/*Invert Jacobian matrix: */
+	Matrix3x3Invert(Jinv,&J[0][0]);
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetNodalFunctionsMINI{{{*/
+void PentaRef::GetNodalFunctionsMINI(IssmDouble* l1l7, GaussPenta* gauss){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	l1l7[0]=gauss->coord1*(1.0-gauss->coord4)/2.0;
+	l1l7[1]=gauss->coord2*(1.0-gauss->coord4)/2.0;
+	l1l7[2]=gauss->coord3*(1.0-gauss->coord4)/2.0;
+	l1l7[3]=gauss->coord1*(1.0+gauss->coord4)/2.0;
+	l1l7[4]=gauss->coord2*(1.0+gauss->coord4)/2.0;
+	l1l7[5]=gauss->coord3*(1.0+gauss->coord4)/2.0;
+	l1l7[6]=27*gauss->coord1*gauss->coord2*gauss->coord3*(1.0+gauss->coord4)*(1.0-gauss->coord4);
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetNodalFunctionsMINIDerivatives{{{*/
+void PentaRef::GetNodalFunctionsMINIDerivatives(IssmDouble* dh1dh7,IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * actual coordinate system): */
+
+	int       i;
+	IssmDouble    dh1dh7_ref[3][NUMNODESMINI];
+	IssmDouble    Jinv[3][3];
+
+	/*Get derivative values with respect to parametric coordinate system: */
+	GetNodalFunctionsMINIDerivativesReference(&dh1dh7_ref[0][0], gauss); 
+
+	/*Get Jacobian invert: */
+	GetJacobianInvert(&Jinv[0][0], xyz_list, gauss);
+
+	/*Build dh1dh6: 
+	 *
+	 * [dhi/dx]= Jinv'*[dhi/dr]
+	 * [dhi/dy]        [dhi/ds]
+	 * [dhi/dz]        [dhi/dzeta]
+	 */
+
+	for (i=0;i<NUMNODESMINI;i++){
+		*(dh1dh7+NUMNODESMINI*0+i)=Jinv[0][0]*dh1dh7_ref[0][i]+Jinv[0][1]*dh1dh7_ref[1][i]+Jinv[0][2]*dh1dh7_ref[2][i];
+		*(dh1dh7+NUMNODESMINI*1+i)=Jinv[1][0]*dh1dh7_ref[0][i]+Jinv[1][1]*dh1dh7_ref[1][i]+Jinv[1][2]*dh1dh7_ref[2][i];
+		*(dh1dh7+NUMNODESMINI*2+i)=Jinv[2][0]*dh1dh7_ref[0][i]+Jinv[2][1]*dh1dh7_ref[1][i]+Jinv[2][2]*dh1dh7_ref[2][i];
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetNodalFunctionsMINIDerivativesReference{{{*/
+void PentaRef::GetNodalFunctionsMINIDerivativesReference(IssmDouble* dl1dl7,GaussPenta* gauss){
+
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * natural coordinate system) at the gaussian point. */
+	IssmDouble r=gauss->coord2-gauss->coord1;
+	IssmDouble s=-3.0/SQRT3*(gauss->coord1+gauss->coord2-2.0/3.0);
+	IssmDouble zeta=gauss->coord4;
+
+	/*First nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+0)=-0.5*(1.0-zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*1+0)=-SQRT3/6.0*(1.0-zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*2+0)=-0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
+
+	/*Second nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+1)=0.5*(1.0-zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*1+1)=-SQRT3/6.0*(1.0-zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*2+1)=-0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
+
+	/*Third nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+2)=0;
+	*(dl1dl7+NUMNODESMINI*1+2)=SQRT3/3.0*(1.0-zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*2+2)=-0.5*(SQRT3/3.0*s+ONETHIRD);
+
+	/*Fourth nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+3)=-0.5*(1.0+zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*1+3)=-SQRT3/6.0*(1.0+zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*2+3)=0.5*(-0.5*r-SQRT3/6.0*s+ONETHIRD);
+
+	/*Fith nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+4)=0.5*(1.0+zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*1+4)=-SQRT3/6.0*(1.0+zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*2+4)=0.5*(0.5*r-SQRT3/6.0*s+ONETHIRD);
+
+	/*Sixth nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+5)=0;
+	*(dl1dl7+NUMNODESMINI*1+5)=SQRT3/3.0*(1.0+zeta)/2.0;
+	*(dl1dl7+NUMNODESMINI*2+5)=0.5*(SQRT3/3.0*s+ONETHIRD);
+
+	/*Seventh nodal function: */
+	*(dl1dl7+NUMNODESMINI*0+6)=9.0/2.0*r*(1.0+zeta)*(zeta-1.0)*(SQRT3*s+1.0);
+	*(dl1dl7+NUMNODESMINI*1+6)=9.0/4.0*(1+zeta)*(1-zeta)*(SQRT3*pow(s,2.0)-2.0*s-SQRT3*pow(r,2.0));
+	*(dl1dl7+NUMNODESMINI*2+6)=27*gauss->coord1*gauss->coord2*gauss->coord3*(-2.0*zeta);
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetNodalFunctionsP1 {{{*/
+void PentaRef::GetNodalFunctionsP1(IssmDouble* l1l6, GaussPenta* gauss){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	l1l6[0]=gauss->coord1*(1-gauss->coord4)/2.0;
+	l1l6[1]=gauss->coord2*(1-gauss->coord4)/2.0;
+	l1l6[2]=gauss->coord3*(1-gauss->coord4)/2.0;
+	l1l6[3]=gauss->coord1*(1+gauss->coord4)/2.0;
+	l1l6[4]=gauss->coord2*(1+gauss->coord4)/2.0;
+	l1l6[5]=gauss->coord3*(1+gauss->coord4)/2.0;
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetNodalFunctionsP1Derivatives {{{*/
+void PentaRef::GetNodalFunctionsP1Derivatives(IssmDouble* dh1dh6,IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * actual coordinate system): */
+	IssmDouble    dh1dh6_ref[NDOF3][NUMNODESP1];
+	IssmDouble    Jinv[NDOF3][NDOF3];
+
+	/*Get derivative values with respect to parametric coordinate system: */
+	GetNodalFunctionsP1DerivativesReference(&dh1dh6_ref[0][0], gauss); 
+
+	/*Get Jacobian invert: */
+	GetJacobianInvert(&Jinv[0][0], xyz_list, gauss);
+
+	/*Build dh1dh3: 
+	 *
+	 * [dhi/dx]= Jinv*[dhi/dr]
+	 * [dhi/dy]       [dhi/ds]
+	 * [dhi/dz]       [dhi/dn]
+	 */
+
+	for (int i=0;i<NUMNODESP1;i++){
+		*(dh1dh6+NUMNODESP1*0+i)=Jinv[0][0]*dh1dh6_ref[0][i]+Jinv[0][1]*dh1dh6_ref[1][i]+Jinv[0][2]*dh1dh6_ref[2][i];
+		*(dh1dh6+NUMNODESP1*1+i)=Jinv[1][0]*dh1dh6_ref[0][i]+Jinv[1][1]*dh1dh6_ref[1][i]+Jinv[1][2]*dh1dh6_ref[2][i];
+		*(dh1dh6+NUMNODESP1*2+i)=Jinv[2][0]*dh1dh6_ref[0][i]+Jinv[2][1]*dh1dh6_ref[1][i]+Jinv[2][2]*dh1dh6_ref[2][i];
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetNodalFunctionsP1DerivativesReference {{{*/
+void PentaRef::GetNodalFunctionsP1DerivativesReference(IssmDouble* dl1dl6,GaussPenta* gauss){
+
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * natural coordinate system) at the gaussian point. Those values vary along xi,eta,z */
+
+	IssmDouble A1,A2,A3,z;
+
+	A1=gauss->coord1; _assert_(A1>=0 && A1<=1);//first area coordinate value. In term of xi and eta: A1=(1-xi)/2-eta/(2*SQRT3);
+	A2=gauss->coord2; _assert_(A2>=0 && A2<=1);//second area coordinate value In term of xi and eta: A2=(1+xi)/2-eta/(2*SQRT3);
+	A3=gauss->coord3; _assert_(A3>=0 && A3<=1);//third area coordinate value  In term of xi and eta: A3=y/SQRT3;
+	z =gauss->coord4; _assert_(z>=-1 &&  z<=1);//fourth vertical coordinate value. Corresponding nodal function: (1-z)/2 and (1+z)/2
+
+	/*First nodal function derivatives. The corresponding nodal function is N=A1*(1-z)/2. Its derivatives follow*/
+	*(dl1dl6+NUMNODESP1*0+0)=-0.5*(1.0-z)/2.0;
+	*(dl1dl6+NUMNODESP1*1+0)=-0.5/SQRT3*(1.0-z)/2.0;
+	*(dl1dl6+NUMNODESP1*2+0)=-0.5*A1;
+
+	/*Second nodal function: The corresponding nodal function is N=A2*(1-z)/2. Its derivatives follow*/
+	*(dl1dl6+NUMNODESP1*0+1)=0.5*(1.0-z)/2.0;
+	*(dl1dl6+NUMNODESP1*1+1)=-0.5/SQRT3*(1.0-z)/2.0;
+	*(dl1dl6+NUMNODESP1*2+1)=-0.5*A2;
+
+	/*Third nodal function: The corresponding nodal function is N=A3*(1-z)/2. Its derivatives follow*/
+	*(dl1dl6+NUMNODESP1*0+2)=0.0;
+	*(dl1dl6+NUMNODESP1*1+2)=1.0/SQRT3*(1.0-z)/2.0;
+	*(dl1dl6+NUMNODESP1*2+2)=-0.5*A3;
+
+	/*Fourth nodal function: The corresponding nodal function is N=A1*(1+z)/2. Its derivatives follow*/
+	*(dl1dl6+NUMNODESP1*0+3)=-0.5*(1.0+z)/2.0;
+	*(dl1dl6+NUMNODESP1*1+3)=-0.5/SQRT3*(1.0+z)/2.0;
+	*(dl1dl6+NUMNODESP1*2+3)=0.5*A1;
+
+	/*Fifth nodal function: The corresponding nodal function is N=A2*(1+z)/2. Its derivatives follow*/
+	*(dl1dl6+NUMNODESP1*0+4)=0.5*(1.0+z)/2.0;
+	*(dl1dl6+NUMNODESP1*1+4)=-0.5/SQRT3*(1.0+z)/2.0;
+	*(dl1dl6+NUMNODESP1*2+4)=0.5*A2;
+
+	/*Sixth nodal function: The corresponding nodal function is N=A3*(1+z)/2. Its derivatives follow*/
+	*(dl1dl6+NUMNODESP1*0+5)=0.0;
+	*(dl1dl6+NUMNODESP1*1+5)=1.0/SQRT3*(1.0+z)/2.0;
+	*(dl1dl6+NUMNODESP1*2+5)=0.5*A3;
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetQuadNodalFunctions {{{*/
+void PentaRef::GetQuadNodalFunctions(IssmDouble* l1l4,GaussPenta* gauss,int index1,int index2,int index3,int index4){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	IssmDouble BasisFunctions[6];
+
+	GetNodalFunctionsP1(&BasisFunctions[0],gauss);
+
+	_assert_(index1>=0 && index1<6);
+	_assert_(index2>=0 && index2<6);
+	_assert_(index3>=0 && index3<6);
+	_assert_(index4>=0 && index4<6);
+
+	l1l4[0]=BasisFunctions[index1];
+	l1l4[1]=BasisFunctions[index2];
+	l1l4[2]=BasisFunctions[index3];
+	l1l4[3]=BasisFunctions[index4];
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetQuadJacobianDeterminant{{{*/
+void PentaRef::GetQuadJacobianDeterminant(IssmDouble* Jdet,IssmDouble xyz_list[4][3],GaussPenta* gauss){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	IssmDouble x1,x2,x3,x4,y1,y2,y3,y4,z1,z2,z3,z4;
+
+	x1=xyz_list[0][0];
+	y1=xyz_list[0][1];
+	z1=xyz_list[0][2];
+	x2=xyz_list[1][0];
+	y2=xyz_list[1][1];
+	z2=xyz_list[1][2];
+	x3=xyz_list[2][0];
+	y3=xyz_list[2][1];
+	z3=xyz_list[2][2];
+	x4=xyz_list[3][0];
+	y4=xyz_list[3][1];
+	z4=xyz_list[3][2];
+
+	/*Jdet = (Area of the trapezoid)/(Area trapezoid ref) with AreaRef = 4*/
+	/*Area of a trabezoid = altitude * (base1 + base2)/2 */
+	*Jdet= pow(pow(x2-x1,2.) + pow(y2-y1,2.),0.5) * (z4-z1 + z3-z2)/8;
+	if(*Jdet<0) _error_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetInputValue{{{*/
+void PentaRef::GetInputValue(IssmDouble* pvalue,IssmDouble* plist,GaussPenta* gauss){
+	/*P1 interpolation on Gauss point*/
+
+	/*intermediary*/
+	IssmDouble l1l6[6];
+
+	/*nodal functions: */
+	GetNodalFunctionsP1(&l1l6[0],gauss);
+
+	/*Assign output pointers:*/
+	*pvalue=l1l6[0]*plist[0]+l1l6[1]*plist[1]+l1l6[2]*plist[2]+l1l6[3]*plist[3]+l1l6[4]*plist[4]+l1l6[5]*plist[5];
+
+}
+/*}}}*/
+/*FUNCTION PentaRef::GetInputDerivativeValue{{{*/
+void PentaRef::GetInputDerivativeValue(IssmDouble* p, IssmDouble* plist,IssmDouble* xyz_list, GaussPenta* gauss){
+	/*From node values of parameter p (p_list[0], p_list[1], p_list[2], p_list[3], p_list[4] and p_list[4]), return parameter derivative value at gaussian point specified by gauss_coord:
+	 *   dp/dx=p_list[0]*dh1/dx+p_list[1]*dh2/dx+p_list[2]*dh3/dx+p_list[3]*dh4/dx+p_list[4]*dh5/dx+p_list[5]*dh6/dx;
+	 *   dp/dy=p_list[0]*dh1/dy+p_list[1]*dh2/dy+p_list[2]*dh3/dy+p_list[3]*dh4/dy+p_list[4]*dh5/dy+p_list[5]*dh6/dy;
+	 *   dp/dz=p_list[0]*dh1/dz+p_list[1]*dh2/dz+p_list[2]*dh3/dz+p_list[3]*dh4/dz+p_list[4]*dh5/dz+p_list[5]*dh6/dz;
+	 *
+	 *   p is a vector of size 3x1 already allocated.
+	 */
+	IssmDouble dh1dh6[3][NUMNODESP1];
+
+	/*Get nodal funnctions derivatives in actual coordinate system: */
+	GetNodalFunctionsP1Derivatives(&dh1dh6[0][0],xyz_list, gauss);
+
+	/*Assign output*/
+	p[0]=plist[0]*dh1dh6[0][0]+plist[1]*dh1dh6[0][1]+plist[2]*dh1dh6[0][2]+plist[3]*dh1dh6[0][3]+plist[4]*dh1dh6[0][4]+plist[5]*dh1dh6[0][5];
+	p[1]=plist[0]*dh1dh6[1][0]+plist[1]*dh1dh6[1][1]+plist[2]*dh1dh6[1][2]+plist[3]*dh1dh6[1][3]+plist[4]*dh1dh6[1][4]+plist[5]*dh1dh6[1][5];
+	p[2]=plist[0]*dh1dh6[2][0]+plist[1]*dh1dh6[2][1]+plist[2]*dh1dh6[2][2]+plist[3]*dh1dh6[2][3]+plist[4]*dh1dh6[2][4]+plist[5]*dh1dh6[2][5];
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Elements/PentaRef.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/PentaRef.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/PentaRef.h	(revision 15012)
@@ -0,0 +1,62 @@
+/*!\file:  PentaRef.h
+ * \brief abstract class for handling Penta oriented routines, like nodal functions, 
+ * strain rate generation, etc ...
+ */ 
+
+#ifndef _PENTAREF_H_
+#define _PENTAREF_H_
+
+class GaussPenta;
+class PentaRef{
+
+	public: 
+		int* element_type_list; //P1CG, P1DG, MINI, P2...
+		int  element_type;
+
+		PentaRef();
+		PentaRef(const int nummodels);
+		~PentaRef();
+
+		/*Management*/
+		void SetElementType(int type,int type_counter);
+
+		/*Numerics*/
+		void GetNodalFunctionsP1(IssmDouble* l1l6, GaussPenta* gauss);
+		void GetNodalFunctionsMINI(IssmDouble* l1l7, GaussPenta* gauss);
+		void GetNodalFunctionsP1Derivatives(IssmDouble* dh1dh6,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetNodalFunctionsMINIDerivatives(IssmDouble* dh1dh7,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetNodalFunctionsP1DerivativesReference(IssmDouble* dl1dl6,GaussPenta* gauss);
+		void GetNodalFunctionsMINIDerivativesReference(IssmDouble* dl1dl7,GaussPenta* gauss);
+		void GetQuadNodalFunctions(IssmDouble* l1l4,GaussPenta* gauss,int index1,int index2,int index3,int index4);
+		void GetQuadJacobianDeterminant(IssmDouble*  Jdet, IssmDouble xyz_list[4][3],GaussPenta* gauss);
+		void GetJacobian(IssmDouble* J, IssmDouble* xyz_list,GaussPenta* gauss);
+		void GetJacobianDeterminant(IssmDouble*  Jdet, IssmDouble* xyz_list,GaussPenta* gauss);
+		void GetTriaJacobianDeterminant(IssmDouble*  Jdet, IssmDouble* xyz_list,GaussPenta* gauss);
+		void GetSegmentJacobianDeterminant(IssmDouble*  Jdet, IssmDouble* xyz_list,GaussPenta* gauss);
+		void GetJacobianInvert(IssmDouble*  Jinv, IssmDouble* xyz_list,GaussPenta* gauss);
+		void GetBMacAyealPattyn(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBMacAyealStokes(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBPattyn(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBStokes(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBprimeMacAyealStokes(IssmDouble* Bprime, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBprimePattyn(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBprimeStokes(IssmDouble* B_prime, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBprimeVert(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBAdvec(IssmDouble* B_advec, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBConduct(IssmDouble* B_conduct, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBVert(IssmDouble* B, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetBprimeAdvec(IssmDouble* Bprime_advec, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetL(IssmDouble* L, GaussPenta* gauss,int numdof);
+		void GetLStokes(IssmDouble* LStokes, GaussPenta* gauss);
+		void GetLprimeStokes(IssmDouble* LprimeStokes, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetLMacAyealStokes(IssmDouble* LMacAyealStokes, GaussPenta* gauss);
+		void GetLprimeMacAyealStokes(IssmDouble* LprimeMacAyealStokes, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetLStokesMacAyeal(IssmDouble* LStokesMacAyeal, GaussPenta* gauss);
+		void GetLprimeStokesMacAyeal(IssmDouble* LprimeStokesMacAyeal, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,IssmDouble* plist, GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,IssmDouble* plist,GaussTria* gauss){_error_("only PentaGauss are supported");};
+		void GetInputDerivativeValue(IssmDouble* pvalues, IssmDouble* plist,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputDerivativeValue(IssmDouble* pvalues, IssmDouble* plist,IssmDouble* xyz_list, GaussTria* gauss){_error_("only PentaGauss are supported");};
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Elements/Tria.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Tria.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Tria.cpp	(revision 15012)
@@ -0,0 +1,6896 @@
+/*!\file Tria.cpp
+ * \brief: implementation of the Tria object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "../classes.h"
+#include "../../shared/shared.h"
+#ifdef _HAVE_GIA_
+#include "../../modules/GiaDeflectionCorex/GiaDeflectionCorex.h"
+#endif
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES 3
+
+/*Constructors/destructor/copy*/
+/*FUNCTION Tria::Tria(){{{*/
+Tria::Tria(){
+
+	int i;
+
+	this->nodes    = NULL;
+	this->vertices = NULL;
+	this->material = NULL;
+	this->matpar   = NULL;
+	for(i=0;i<3;i++)this->horizontalneighborsids[i]=UNDEF;
+	this->inputs     = NULL;
+	this->parameters = NULL;
+	this->results    = NULL;
+
+}
+/*}}}*/
+/*FUNCTION Tria::Tria(int id, int sid,int index, IoModel* iomodel,int nummodels){{{*/
+Tria::Tria(int tria_id, int tria_sid, int index, IoModel* iomodel,int nummodels)
+	:TriaRef(nummodels)
+	,TriaHook(nummodels,index+1,iomodel){
+
+		/*id: */
+		this->id=tria_id;
+		this->sid=tria_sid;
+
+		//this->parameters: we still can't point to it, it may not even exist. Configure will handle this.
+		this->parameters=NULL;
+
+		/*Build horizontalneighborsids list: */
+		_assert_(iomodel->Data(MeshElementconnectivityEnum));
+		//for (i=0;i<3;i++) this->horizontalneighborsids[i]=(int)iomodel->elementconnectivity[3*index+i]-1;
+
+		/*intialize inputs and results: */
+		this->inputs=new Inputs();
+		this->results=new Results();
+
+		/*initialize pointers:*/
+		this->nodes    = NULL;
+		this->vertices = NULL;
+		this->material = NULL;
+		this->matpar   = NULL;
+
+}
+/*}}}*/
+/*FUNCTION Tria::~Tria(){{{*/
+Tria::~Tria(){
+	delete inputs;
+	delete results;
+	this->parameters=NULL;
+}
+/*}}}*/
+/*FUNCTION Tria::copy {{{*/
+Object* Tria::copy() {
+
+	int i;
+	Tria* tria=NULL;
+
+	tria=new Tria();
+
+	//deal with TriaRef mother class
+	tria->element_type_list=xNew<int>(this->numanalyses);
+	for(i=0;i<this->numanalyses;i++) tria->element_type_list[i]=this->element_type_list[i];
+
+	//deal with TriaHook mother class
+	tria->numanalyses=this->numanalyses;
+	tria->hnodes=new Hook*[tria->numanalyses];
+	for(i=0;i<tria->numanalyses;i++)tria->hnodes[i]=(Hook*)this->hnodes[i]->copy();
+	tria->hvertices=(Hook*)this->hvertices->copy();
+	tria->hmaterial=(Hook*)this->hmaterial->copy();
+	tria->hmatpar=(Hook*)this->hmatpar->copy();
+
+	/*deal with Tria fields: */
+	tria->id=this->id;
+	tria->sid=this->sid;
+	if(this->inputs){
+		tria->inputs=(Inputs*)this->inputs->Copy();
+	}
+	else{
+		tria->inputs=new Inputs();
+	}
+	if(this->results){
+		tria->results=(Results*)this->results->Copy();
+	}
+	else{
+		tria->results=new Results();
+	}
+	/*point parameters: */
+	tria->parameters=this->parameters;
+
+	/*recover objects: */
+	tria->nodes=xNew<Node*>(3); //we cannot rely on an analysis_counter to tell us which analysis_type we are running, so we just copy the nodes.
+	for(i=0;i<3;i++)tria->nodes[i]=this->nodes[i];
+	tria->vertices=(Vertex**)tria->hvertices->deliverp();
+	tria->material=(Material*)tria->hmaterial->delivers();
+	tria->matpar=(Matpar*)tria->hmatpar->delivers();
+
+	/*neighbors: */
+	for(i=0;i<3;i++)tria->horizontalneighborsids[i]=this->horizontalneighborsids[i];
+
+	return tria;
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION Tria::AverageOntoPartition {{{*/
+void  Tria::AverageOntoPartition(Vector<IssmDouble>* partition_contributions,Vector<IssmDouble>* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part){
+
+	bool       already = false;
+	int        i,j;
+	int        partition[NUMVERTICES];
+	int        offsetsid[NUMVERTICES];
+	int        offsetdof[NUMVERTICES];
+	IssmDouble area;
+	IssmDouble mean;
+
+	/*First, get the area: */
+	area=this->GetArea();
+
+	/*Figure out the average for this element: */
+	this->GetVertexSidList(&offsetsid[0]);
+	this->GetVertexPidList(&offsetdof[0]);
+	mean=0;
+	for(i=0;i<NUMVERTICES;i++){
+		partition[i]=reCast<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){
+			partition_contributions->SetValue(partition[i],mean*area,ADD_VAL);
+			partition_areas->SetValue(partition[i],area,ADD_VAL);
+		};
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::SetwiseNodeConnectivity{{{*/
+void Tria::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	/*Loop over all nodes*/
+	for(int i=0;i<3;i++){
+
+		if(!flags[this->nodes[i]->Sid()]){
+
+			/*flag current node so that no other element processes it*/
+			flags[this->nodes[i]->Sid()]=true;
+
+			/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+			switch(set2_enum){
+				case FsetEnum:
+					if(nodes[i]->indexing.fsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case GsetEnum:
+					if(nodes[i]->indexing.gsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case SsetEnum:
+					if(nodes[i]->indexing.ssize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				default: _error_("not supported");
+			}
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrix {{{*/
+void  Tria::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+
+	/*retreive parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging mode{{{*/
+	_assert_(this->nodes && this->material && this->matpar && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Skip if water element*/
+	if(IsOnWater()) return;
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticMacAyeal();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticHutter();
+			break;
+		 #endif
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			Ke=CreateMassMatrix();
+			break;
+		case PrognosticAnalysisEnum:
+			Ke=CreateKMatrixPrognostic();
+			break;
+		#ifdef _HAVE_HYDROLOGY_
+		case HydrologyShreveAnalysisEnum:
+			Ke=CreateKMatrixHydrologyShreve();
+			break;
+		case HydrologyDCInefficientAnalysisEnum:
+			Ke=CreateKMatrixHydrologyDCInefficient();
+			break;
+		case HydrologyDCEfficientAnalysisEnum:
+			Ke=CreateKMatrixHydrologyDCEfficient();
+			break;
+		#endif
+		#ifdef _HAVE_BALANCED_
+		case BalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixBalancethickness();
+			break;
+		#endif
+		#ifdef _HAVE_CONTROL_
+		case AdjointBalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixAdjointBalancethickness();
+			break;
+		case AdjointHorizAnalysisEnum:
+			Ke=CreateKMatrixAdjointMacAyeal();
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixMelting {{{*/
+ElementMatrix* Tria::CreateKMatrixMelting(void){
+
+	/*Constants*/
+	const int  numdof=NUMVERTICES*NDOF1;
+
+	/*Intermediaries */
+	IssmDouble heatcapacity,latentheat;
+	IssmDouble Jdet,D_scalar;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[3];
+	GaussTria *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	latentheat=matpar->GetLatentHeat();
+	heatcapacity=matpar->GetHeatCapacity();
+
+	/* Start looping on the number of gauss  (nodes on the bedrock) */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+		GetJacobianDeterminant(&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->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixPrognostic {{{*/
+ElementMatrix* Tria::CreateKMatrixPrognostic(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreateKMatrixPrognostic_CG();
+		case P1DGEnum:
+			return CreateKMatrixPrognostic_DG();
+		default:
+			_error_("Element type " << EnumToStringx(GetElementType()) << " not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixPrognostic_CG {{{*/
+ElementMatrix* Tria::CreateKMatrixPrognostic_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        stabilization;
+	int        dim;
+	IssmDouble Jdettria,DL_scalar,dt,h;
+	IssmDouble vel,vx,vy,dvxdx,dvydy;
+	IssmDouble dvx[2],dvy[2];
+	IssmDouble v_gauss[2]={0.0};
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[NUMVERTICES];
+	IssmDouble B[2][NUMVERTICES];
+	IssmDouble Bprime[2][NUMVERTICES];
+	IssmDouble K[2][2]                        ={0.0};
+	IssmDouble KDL[2][2]                      ={0.0};
+	IssmDouble DL[2][2]                        ={0.0};
+	IssmDouble DLprime[2][2]                   ={0.0};
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&dim,MeshDimensionEnum);
+	this->parameters->FindParam(&stabilization,PrognosticStabilizationEnum);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); _assert_(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); _assert_(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); _assert_(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); _assert_(vyaverage_input);
+	}
+	h=sqrt(2*this->GetArea());
+
+	/* Start  looping on the number of gaussian points: */
+	GaussTria *gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		vxaverage_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vyaverage_input->GetInputDerivativeValue(&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->values[0],1);
+
+		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->values[0],1);
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DLprime[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke->values[0],1);
+
+		if(stabilization==2){
+			/*Streamline upwinding*/
+			vel=sqrt(vx*vx+vy*vy)+1.e-8;
+			K[0][0]=h/(2*vel)*vx*vx;
+			K[1][0]=h/(2*vel)*vy*vx;
+			K[0][1]=h/(2*vel)*vx*vy;
+			K[1][1]=h/(2*vel)*vy*vy;
+		}
+		else if(stabilization==1){
+			/*MacAyeal*/
+			vxaverage_input->GetInputAverage(&vx);
+			vyaverage_input->GetInputAverage(&vy);
+			K[0][0]=h/2.0*fabs(vx);
+			K[0][1]=0.;
+			K[1][0]=0.;
+			K[1][1]=h/2.0*fabs(vy);
+		}
+		if(stabilization==1 || stabilization==2){
+			KDL[0][0]=DL_scalar*K[0][0];
+			KDL[1][0]=DL_scalar*K[1][0];
+			KDL[0][1]=DL_scalar*K[0][1];
+			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->values[0],1);
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixPrognostic_DG {{{*/
+ElementMatrix* Tria::CreateKMatrixPrognostic_DG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        dim;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdettria,dt,vx,vy;
+	IssmDouble L[NUMVERTICES];
+	IssmDouble B[2][NUMVERTICES];
+	IssmDouble Bprime[2][NUMVERTICES];
+	IssmDouble DL[2][2]={0.0};
+	IssmDouble DLprime[2][2]={0.0};
+	IssmDouble DL_scalar;
+	GaussTria  *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&dim,MeshDimensionEnum);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); _assert_(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); _assert_(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); _assert_(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); _assert_(vyaverage_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+
+		GetJacobianDeterminant(&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->values[0],1);
+
+		/*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->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateMassMatrix {{{*/
+ElementMatrix* Tria::CreateMassMatrix(void){
+
+	/*constants: */
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/* Intermediaries */
+	IssmDouble  D,Jdet;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  L[1][numdof];
+	GaussTria  *gauss = NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		D=gauss->weight*Jdet;
+
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF1);
+
+		TripleMultiply(&L[0][0],1,3,1,
+					&D,1,1,0,
+					&L[0][0],1,3,0,
+					&Ke->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateDVector {{{*/
+void  Tria::CreateDVector(Vector<IssmDouble>* df){
+
+	/*Nothing done yet*/
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVector {{{*/
+void  Tria::CreatePVector(Vector<IssmDouble>* pf){
+
+	/*retrive parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*asserts: {{{*/
+	/*if debugging mode, check that all pointers exist*/
+	_assert_(this->nodes && this->material && this->matpar && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Skip if water element*/
+	if(IsOnWater()) return;
+
+	/*Just branch to the correct load generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			pe=CreatePVectorDiagnosticMacAyeal();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			pe=CreatePVectorDiagnosticHutter();
+			break;
+		#endif
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			pe=CreatePVectorSlope();
+			break;
+		case PrognosticAnalysisEnum:
+			pe=CreatePVectorPrognostic();
+			break;
+		#ifdef _HAVE_HYDROLOGY_
+		case HydrologyShreveAnalysisEnum:
+			pe=CreatePVectorHydrologyShreve();
+			break;
+		case HydrologyDCInefficientAnalysisEnum:
+			pe=CreatePVectorHydrologyDCInefficient();
+			break;
+		case HydrologyDCEfficientAnalysisEnum:
+			pe=CreatePVectorHydrologyDCEfficient();
+			break;
+		#endif
+		#ifdef _HAVE_BALANCED_
+		case BalancethicknessAnalysisEnum:
+			pe=CreatePVectorBalancethickness();
+			break;
+		#endif
+		#ifdef _HAVE_CONTROL_
+		case AdjointBalancethicknessAnalysisEnum:
+			pe=CreatePVectorAdjointBalancethickness();
+			break;
+		case AdjointHorizAnalysisEnum:
+			pe=CreatePVectorAdjointHoriz();
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic{{{*/
+ElementVector* Tria::CreatePVectorPrognostic(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreatePVectorPrognostic_CG();
+		case P1DGEnum:
+			return CreatePVectorPrognostic_DG();
+		default:
+			_error_("Element type " << EnumToStringx(GetElementType()) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic_CG {{{*/
+ElementVector* Tria::CreatePVectorPrognostic_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble Jdettria,dt;
+	IssmDouble surface_mass_balance_g,basal_melting_g,basal_melting_correction_g,thickness_g;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* surface_mass_balance_input=inputs->GetInput(SurfaceforcingsMassBalanceEnum); _assert_(surface_mass_balance_input);
+	Input* basal_melting_input=inputs->GetInput(BasalforcingsMeltingRateEnum);          _assert_(basal_melting_input);
+	Input* basal_melting_correction_input=inputs->GetInput(BasalforcingsMeltingRateCorrectionEnum);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);                             _assert_(thickness_input);
+
+	/*Initialize basal_melting_correction_g to 0, do not forget!:*/
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		surface_mass_balance_input->GetInputValue(&surface_mass_balance_g,gauss);
+		basal_melting_input->GetInputValue(&basal_melting_g,gauss);
+		thickness_input->GetInputValue(&thickness_g,gauss);
+		if(basal_melting_correction_input)
+		 basal_melting_correction_input->GetInputValue(&basal_melting_correction_g,gauss);
+		else
+		 basal_melting_correction_g=0.;
+
+		for(int i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(surface_mass_balance_g-basal_melting_g-basal_melting_correction_g))*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic_DG {{{*/
+ElementVector* Tria::CreatePVectorPrognostic_DG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble Jdettria,dt;
+	IssmDouble surface_mass_balance_g,basal_melting_g,thickness_g;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* surface_mass_balance_input=inputs->GetInput(SurfaceforcingsMassBalanceEnum); _assert_(surface_mass_balance_input);
+	Input* basal_melting_input=inputs->GetInput(BasalforcingsMeltingRateEnum);          _assert_(basal_melting_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);                             _assert_(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		surface_mass_balance_input->GetInputValue(&surface_mass_balance_g,gauss);
+		basal_melting_input->GetInputValue(&basal_melting_g,gauss);
+		thickness_input->GetInputValue(&thickness_g,gauss);
+
+		for(int i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(thickness_g+dt*(surface_mass_balance_g-basal_melting_g))*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorSlope {{{*/
+ElementVector* Tria::CreatePVectorSlope(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i;
+	int        analysis_type;
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble slope[2];
+	IssmDouble basis[3];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* slope_input=NULL;
+	if ( (analysis_type==SurfaceSlopeXAnalysisEnum) || (analysis_type==SurfaceSlopeYAnalysisEnum)){
+		slope_input=inputs->GetInput(SurfaceEnum); _assert_(slope_input);
+	}
+	if ( (analysis_type==BedSlopeXAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
+		slope_input=inputs->GetInput(BedEnum);     _assert_(slope_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		slope_input->GetInputDerivativeValue(&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]*basis[i];
+		}
+		if ( (analysis_type==SurfaceSlopeYAnalysisEnum) || (analysis_type==BedSlopeYAnalysisEnum)){
+			for(i=0;i<numdof;i++) pe->values[i]+=Jdet*gauss->weight*slope[1]*basis[i];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateJacobianMatrix{{{*/
+void  Tria::CreateJacobianMatrix(Matrix<IssmDouble>* Jff){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->material && this->matpar && this->parameters && this->inputs);
+	/*}}}*/
+
+	/*Skip if water element*/
+	if(IsOnWater()) return;
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			Ke=CreateJacobianDiagnosticMacayeal();
+			break;
+#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Jff);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeBasalStress {{{*/
+void  Tria::ComputeBasalStress(Vector<IssmDouble>* eps){
+	_error_("Not Implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeStrainRate {{{*/
+void  Tria::ComputeStrainRate(Vector<IssmDouble>* eps){
+	_error_("Not Implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeStressTensor {{{*/
+void  Tria::ComputeStressTensor(){
+
+	IssmDouble      xyz_list[NUMVERTICES][3];
+	IssmDouble      pressure,viscosity;
+	IssmDouble      epsilon[3]; /* epsilon=[exx,eyy,exy];*/
+	IssmDouble      sigma_xx[NUMVERTICES];
+	IssmDouble		sigma_yy[NUMVERTICES];
+	IssmDouble		sigma_zz[NUMVERTICES]={0,0,0};
+	IssmDouble      sigma_xy[NUMVERTICES];
+	IssmDouble		sigma_xz[NUMVERTICES]={0,0,0};
+	IssmDouble		sigma_yz[NUMVERTICES]={0,0,0};
+	GaussTria* gauss=NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* pressure_input=inputs->GetInput(PressureEnum); _assert_(pressure_input);
+	Input* vx_input=inputs->GetInput(VxEnum);             _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);             _assert_(vy_input);
+
+	/* Start looping on the number of vertices: */
+	gauss=new GaussTria();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+
+		/*Compute strain rate viscosity and pressure: */
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosity2d(&viscosity,&epsilon[0]);
+		pressure_input->GetInputValue(&pressure,gauss);
+
+		/*Compute Stress*/
+		sigma_xx[iv]=2*viscosity*epsilon[0]-pressure; // sigma = nu eps - pressure
+		sigma_yy[iv]=2*viscosity*epsilon[1]-pressure;
+		sigma_xy[iv]=2*viscosity*epsilon[2];
+	}
+
+	/*Add Stress tensor components into inputs*/
+	this->inputs->AddInput(new TriaP1Input(StressTensorxxEnum,&sigma_xx[0]));
+	this->inputs->AddInput(new TriaP1Input(StressTensorxyEnum,&sigma_xy[0]));
+	this->inputs->AddInput(new TriaP1Input(StressTensorxzEnum,&sigma_xz[0]));
+	this->inputs->AddInput(new TriaP1Input(StressTensoryyEnum,&sigma_yy[0]));
+	this->inputs->AddInput(new TriaP1Input(StressTensoryzEnum,&sigma_yz[0]));
+	this->inputs->AddInput(new TriaP1Input(StressTensorzzEnum,&sigma_zz[0]));
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::Configure {{{*/
+void  Tria::Configure(Elements* elementsin, Loads* loadsin,Nodes* nodesin,Vertices *verticesin,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->hvertices->configure(verticesin);
+	this->hmaterial->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->vertices = (Vertex**)this->hvertices->deliverp();
+	this->material = (Material*)this->hmaterial->delivers();
+	this->matpar   = (Matpar*)this->hmatpar->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+
+	/*get inputs configured too: */
+	this->inputs->Configure(parameters);
+
+}
+/*}}}*/
+/*FUNCTION Tria::DeepEcho{{{*/
+void Tria::DeepEcho(void){
+
+	_printLine_("Tria:");
+	_printLine_("   id: " << id);
+	if(nodes){
+		nodes[0]->DeepEcho();
+		nodes[1]->DeepEcho();
+		nodes[2]->DeepEcho();
+	}
+	else _printLine_("nodes = NULL");
+
+	if (material) material->DeepEcho();
+	else _printLine_("material = NULL");
+
+	if (matpar) matpar->DeepEcho();
+	else _printLine_("matpar = NULL");
+
+	_printLine_("   parameters");
+	if (parameters) parameters->DeepEcho();
+	else _printLine_("parameters = NULL");
+
+	_printLine_("   inputs");
+	if (inputs) inputs->DeepEcho();
+	else _printLine_("inputs=NULL");
+
+	if (results) results->DeepEcho();
+	else _printLine_("results=NULL");
+
+	_printLine_("neighboor sids: ");
+	_printLine_(" " << horizontalneighborsids[0] << " " << horizontalneighborsids[1] << " " << horizontalneighborsids[2]);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Tria::DeleteResults {{{*/
+void  Tria::DeleteResults(void){
+
+	/*Delete and reinitialize results*/
+	delete this->results;
+	this->results=new Results();
+
+}
+/*}}}*/
+/*FUNCTION Tria::Delta18oParameterization{{{*/
+void  Tria::Delta18oParameterization(void){
+
+	int        i;
+	IssmDouble monthlytemperatures[NUMVERTICES][12],monthlyprec[NUMVERTICES][12];
+	IssmDouble TemperaturesPresentday[NUMVERTICES][12],TemperaturesLgm[NUMVERTICES][12];
+	IssmDouble PrecipitationsPresentday[NUMVERTICES][12];
+	IssmDouble tmp[NUMVERTICES];
+	IssmDouble Delta18oPresent,Delta18oLgm,Delta18oTime;
+	IssmDouble Delta18oSurfacePresent,Delta18oSurfaceLgm,Delta18oSurfaceTime;
+	IssmDouble time,yts,finaltime;
+
+	/*Recover parameters*/
+	this->parameters->FindParam(&time,TimeEnum);
+	this->parameters->FindParam(&yts,ConstantsYtsEnum);
+	this->parameters->FindParam(&finaltime,TimesteppingFinalTimeEnum);
+
+	/*Recover present day temperature and precipitation*/
+	Input* input=inputs->GetInput(SurfaceforcingsTemperaturesPresentdayEnum);    _assert_(input);
+	Input* input2=inputs->GetInput(SurfaceforcingsTemperaturesLgmEnum);          _assert_(input2);
+	Input* input3=inputs->GetInput(SurfaceforcingsPrecipitationsPresentdayEnum); _assert_(input3);
+	GaussTria* gauss=new GaussTria();
+	for(int month=0;month<12;month++){
+		for(int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&TemperaturesPresentday[iv][month],gauss,month/12.*yts);
+			input2->GetInputValue(&TemperaturesLgm[iv][month],gauss,month/12.*yts);
+			input3->GetInputValue(&PrecipitationsPresentday[iv][month],gauss,month/12.*yts);
+			PrecipitationsPresentday[iv][month]=PrecipitationsPresentday[iv][month]/yts; // converion in m/sec
+		}
+	}
+
+	/*Recover delta18o and Delta18oSurface at present day, lgm and at time t*/
+	this->parameters->FindParam(&Delta18oPresent,SurfaceforcingsDelta18oEnum,finaltime);
+	this->parameters->FindParam(&Delta18oLgm,SurfaceforcingsDelta18oEnum,(finaltime-(21000*yts)));
+	this->parameters->FindParam(&Delta18oTime,SurfaceforcingsDelta18oEnum,time);
+	this->parameters->FindParam(&Delta18oSurfacePresent,SurfaceforcingsDelta18oSurfaceEnum,finaltime);
+	this->parameters->FindParam(&Delta18oSurfaceLgm,SurfaceforcingsDelta18oSurfaceEnum,(finaltime-(21000*yts)));
+	this->parameters->FindParam(&Delta18oSurfaceTime,SurfaceforcingsDelta18oSurfaceEnum,time);
+
+	/*Compute the temperature and precipitation*/
+	for(int iv=0;iv<NUMVERTICES;iv++){
+		ComputeDelta18oTemperaturePrecipitation(Delta18oSurfacePresent, Delta18oSurfaceLgm, Delta18oSurfaceTime, 
+					Delta18oPresent, Delta18oLgm, Delta18oTime,
+					&PrecipitationsPresentday[iv][0], 
+					&TemperaturesLgm[iv][0], &TemperaturesPresentday[iv][0], 
+					&monthlytemperatures[iv][0], &monthlyprec[iv][0]);
+	}
+
+	/*Update inputs*/ 
+	TransientInput* NewTemperatureInput = new TransientInput(SurfaceforcingsMonthlytemperaturesEnum);
+	TransientInput* NewPrecipitationInput = new TransientInput(SurfaceforcingsPrecipitationEnum);
+	for (int imonth=0;imonth<12;imonth++) {
+		for(i=0;i<NUMVERTICES;i++) tmp[i]=monthlytemperatures[i][imonth];
+		TriaP1Input* newmonthinput1 = new TriaP1Input(SurfaceforcingsMonthlytemperaturesEnum,&tmp[0]);
+		NewTemperatureInput->AddTimeInput(newmonthinput1,time+imonth/12.*yts);
+
+		for(i=0;i<NUMVERTICES;i++) tmp[i]=monthlyprec[i][imonth];
+		TriaP1Input* newmonthinput2 = new TriaP1Input(SurfaceforcingsPrecipitationEnum,&tmp[0]);
+		NewPrecipitationInput->AddTimeInput(newmonthinput2,time+imonth/12.*yts);
+	}
+
+	this->inputs->AddInput(NewTemperatureInput);
+	this->inputs->AddInput(NewPrecipitationInput);
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::Echo{{{*/
+void Tria::Echo(void){
+	_printLine_("Tria:");
+	_printLine_("   id: " << id);
+	if(nodes){
+		nodes[0]->Echo();
+		nodes[1]->Echo();
+		nodes[2]->Echo();
+	}
+	else _printLine_("nodes = NULL");
+
+	if (material) material->Echo();
+	else _printLine_("material = NULL");
+
+	if (matpar) matpar->Echo();
+	else _printLine_("matpar = NULL");
+
+	_printLine_("   parameters");
+	if (parameters) parameters->Echo();
+	else _printLine_("parameters = NULL");
+
+	_printLine_("   inputs");
+	if (inputs) inputs->Echo();
+	else _printLine_("inputs=NULL");
+
+	if (results) results->Echo();
+	else _printLine_("results=NULL");
+
+	_printLine_("neighboor sids: ");
+	_printLine_(" " << horizontalneighborsids[0] << " " << horizontalneighborsids[1] << " " << horizontalneighborsids[2]);
+}
+/*}}}*/
+/*FUNCTION Tria::ObjectEnum{{{*/
+int Tria::ObjectEnum(void){
+
+	return TriaEnum;
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetArea {{{*/
+IssmDouble Tria::GetArea(void){
+
+	IssmDouble area=0;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble x1,y1,x2,y2,x3,y3;
+
+	/*Get xyz list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,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];
+
+	_assert_(x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1>0);
+	return (x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
+}
+/*}}}*/
+/*FUNCTION Tria::GetDofList {{{*/
+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=xNew<int>(numberofdofs);
+
+	/*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::GetElementType {{{*/
+int Tria::GetElementType(){
+
+	/*return TriaRef field*/
+	return this->element_type;
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetHorizontalNeighboorSids {{{*/
+int* Tria::GetHorizontalNeighboorSids(){
+
+	/*return TriaRef field*/
+	return &this->horizontalneighborsids[0];
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetGroundedPortion{{{*/
+IssmDouble Tria::GetGroundedPortion(IssmDouble* xyz_list){
+	/*Computeportion of the element that is grounded*/ 
+
+	bool               mainlyfloating = true;
+	const IssmPDouble  epsilon= 1.e-15;
+	IssmDouble         phi,s1,s2,area_init,area_grounded;
+	IssmDouble         gl[3];
+	IssmDouble         xyz_bis[3][3];
+
+	/*Recover parameters and values*/
+	GetInputListOnVertices(&gl[0],GLlevelsetEnum);
+
+	/*Be sure that values are not zero*/
+	if(gl[0]==0) gl[0]=gl[0]+epsilon;
+	if(gl[1]==0) gl[1]=gl[1]+epsilon;
+	if(gl[2]==0) gl[2]=gl[2]+epsilon;
+
+	/*Check that not all nodes are grounded or floating*/
+	if(gl[0]>0 && gl[1]>0 && gl[2]>0){ // All grounded
+		phi=1;
+	}
+	else if(gl[0]<0 && gl[1]<0 && gl[2]<0){ //All floating
+		phi=0;
+	}
+	else{
+		/*Figure out if two nodes are floating or grounded*/
+		if(gl[0]*gl[1]*gl[2]>0) mainlyfloating=false;
+
+		if(gl[0]*gl[1]>0){ //Nodes 0 and 1 are similar, so points must be found on segment 0-2 and 1-2
+			/*Coordinates of point 2: same as initial point 2*/
+			xyz_bis[2][0]=*(xyz_list+3*2+0);
+			xyz_bis[2][1]=*(xyz_list+3*2+1);
+			xyz_bis[2][2]=*(xyz_list+3*2+2);
+
+			/*Portion of the segments*/
+			s1=gl[2]/(gl[2]-gl[1]);
+			s2=gl[2]/(gl[2]-gl[0]);
+
+			/*New point 1*/
+			xyz_bis[1][0]=*(xyz_list+3*2+0)+s1*(*(xyz_list+3*1+0)-*(xyz_list+3*2+0));
+			xyz_bis[1][1]=*(xyz_list+3*2+1)+s1*(*(xyz_list+3*1+1)-*(xyz_list+3*2+1));
+			xyz_bis[1][2]=*(xyz_list+3*2+2)+s1*(*(xyz_list+3*1+2)-*(xyz_list+3*2+2));
+
+			/*New point 0*/
+			xyz_bis[0][0]=*(xyz_list+3*2+0)+s2*(*(xyz_list+3*0+0)-*(xyz_list+3*2+0));
+			xyz_bis[0][1]=*(xyz_list+3*2+1)+s2*(*(xyz_list+3*0+1)-*(xyz_list+3*2+1));
+			xyz_bis[0][2]=*(xyz_list+3*2+2)+s2*(*(xyz_list+3*0+2)-*(xyz_list+3*2+2));
+		}
+		else if(gl[1]*gl[2]>0){ //Nodes 1 and 2 are similar, so points must be found on segment 0-1 and 0-2
+			/*Coordinates of point 0: same as initial point 2*/
+			xyz_bis[0][0]=*(xyz_list+3*0+0);
+			xyz_bis[0][1]=*(xyz_list+3*0+1);
+			xyz_bis[0][2]=*(xyz_list+3*0+2);
+
+			/*Portion of the segments*/
+			s1=gl[0]/(gl[0]-gl[1]);
+			s2=gl[0]/(gl[0]-gl[2]);
+
+			/*New point 1*/
+			xyz_bis[1][0]=*(xyz_list+3*0+0)+s1*(*(xyz_list+3*1+0)-*(xyz_list+3*0+0));
+			xyz_bis[1][1]=*(xyz_list+3*0+1)+s1*(*(xyz_list+3*1+1)-*(xyz_list+3*0+1));
+			xyz_bis[1][2]=*(xyz_list+3*0+2)+s1*(*(xyz_list+3*1+2)-*(xyz_list+3*0+2));
+
+			/*New point 2*/
+			xyz_bis[2][0]=*(xyz_list+3*0+0)+s2*(*(xyz_list+3*2+0)-*(xyz_list+3*0+0));
+			xyz_bis[2][1]=*(xyz_list+3*0+1)+s2*(*(xyz_list+3*2+1)-*(xyz_list+3*0+1));
+			xyz_bis[2][2]=*(xyz_list+3*0+2)+s2*(*(xyz_list+3*2+2)-*(xyz_list+3*0+2));
+		}
+		else if(gl[0]*gl[2]>0){ //Nodes 0 and 2 are similar, so points must be found on segment 1-0 and 1-2
+			/*Coordinates of point 1: same as initial point 2*/
+			xyz_bis[1][0]=*(xyz_list+3*1+0);
+			xyz_bis[1][1]=*(xyz_list+3*1+1);
+			xyz_bis[1][2]=*(xyz_list+3*1+2);
+
+			/*Portion of the segments*/
+			s1=gl[1]/(gl[1]-gl[0]);
+			s2=gl[1]/(gl[1]-gl[2]);
+
+			/*New point 0*/
+			xyz_bis[0][0]=*(xyz_list+3*1+0)+s1*(*(xyz_list+3*0+0)-*(xyz_list+3*1+0));
+			xyz_bis[0][1]=*(xyz_list+3*1+1)+s1*(*(xyz_list+3*0+1)-*(xyz_list+3*1+1));
+			xyz_bis[0][2]=*(xyz_list+3*1+2)+s1*(*(xyz_list+3*0+2)-*(xyz_list+3*1+2));
+
+			/*New point 2*/
+			xyz_bis[2][0]=*(xyz_list+3*1+0)+s2*(*(xyz_list+3*2+0)-*(xyz_list+3*1+0));
+			xyz_bis[2][1]=*(xyz_list+3*1+1)+s2*(*(xyz_list+3*2+1)-*(xyz_list+3*1+1));
+			xyz_bis[2][2]=*(xyz_list+3*1+2)+s2*(*(xyz_list+3*2+2)-*(xyz_list+3*1+2));
+		}
+
+		/*Compute fraction of grounded element*/
+		GetJacobianDeterminant(&area_init, xyz_list,NULL);
+		GetJacobianDeterminant(&area_grounded, &xyz_bis[0][0],NULL);
+		if(mainlyfloating==true) area_grounded=area_init-area_grounded;
+		phi=area_grounded/area_init;
+	}
+
+	if(phi>1 || phi<0) _error_("Error. Problem with portion of grounded element: value should be between 0 and 1");
+
+	return phi;
+}
+/*}}}*/
+/*FUNCTION Tria::GetNodeIndex {{{*/
+int Tria::GetNodeIndex(Node* node){
+
+	_assert_(nodes);
+	for(int i=0;i<NUMVERTICES;i++){
+		if(node==nodes[i])
+		 return i;
+	}
+	_error_("Node provided not found among element nodes");
+}
+/*}}}*/
+/*FUNCTION Tria::GetNodesSidList{{{*/
+void Tria::GetNodesSidList(int* sidlist){
+
+	_assert_(sidlist);
+	_assert_(nodes);
+
+	for(int i=0;i<NUMVERTICES;i++){
+		sidlist[i]=nodes[i]->Sid();
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::GetNumberOfNodes{{{*/
+int Tria::GetNumberOfNodes(void){
+
+	if(this->nodes==NULL) return 0;
+
+	switch(this->element_type){
+		case P1Enum:
+			return 3;
+		case P1DGEnum:
+			return 3;
+		default:
+			_error_("Element type "<<EnumToStringx(this->element_type)<<" not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype) {{{*/
+void Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype){
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+	if (!input) _error_("Input " << EnumToStringx(enumtype) << " not found in element");
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	GaussTria* gauss=new GaussTria();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+		input->GetInputValue(&pvalue[iv],gauss);
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue) {{{*/
+void Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue){
+
+	Input     *input = inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		GaussTria* gauss=new GaussTria();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&pvalue[iv],gauss);
+		}
+		delete gauss;
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue,int index) TO BE REMOVED{{{*/
+void Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue,int index){
+
+	Input     *input = inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		GaussTria* gauss=new GaussTria();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&pvalue[iv],gauss,index);
+		}
+		delete gauss;
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::GetInputValue(IssmDouble* pvalue,Node* node,int enumtype) {{{*/
+void Tria::GetInputValue(IssmDouble* pvalue,Node* node,int enumtype){
+
+	Input* input=inputs->GetInput(enumtype);
+	if(!input) _error_("No input of type " << EnumToStringx(enumtype) << " found in tria");
+
+	GaussTria* gauss=new GaussTria();
+	gauss->GaussVertex(this->GetNodeIndex(node));
+
+	input->GetInputValue(pvalue,gauss);
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GetVertexPidList {{{*/
+void  Tria::GetVertexPidList(int* doflist){
+
+	int i;
+	for(i=0;i<3;i++) doflist[i]=nodes[i]->GetVertexPid();
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetVertexSidList {{{*/
+void  Tria::GetVertexSidList(int* sidlist){
+	for(int i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetVertexSid();
+}
+/*}}}*/
+/*FUNCTION Tria::GetConnectivityList {{{*/
+void  Tria::GetConnectivityList(int* connectivity){
+	for(int i=0;i<NUMVERTICES;i++) connectivity[i]=nodes[i]->GetConnectivity();
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputs{{{*/
+void  Tria::GetSolutionFromInputs(Vector<IssmDouble>* 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: */
+	switch(analysis_type){
+	#ifdef _HAVE_DIAGNOSTIC_
+	case DiagnosticHorizAnalysisEnum:
+		GetSolutionFromInputsDiagnosticHoriz(solution);
+		break;
+	case DiagnosticHutterAnalysisEnum:
+		GetSolutionFromInputsDiagnosticHutter(solution);
+		break;
+	#endif
+	#ifdef _HAVE_HYDROLOGY_
+	case HydrologyShreveAnalysisEnum:
+		GetSolutionFromInputsHydrologyShreve(solution);
+		break;
+	#endif
+	default:
+		_error_("analysis: " << EnumToStringx(analysis_type) << " not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::GetStrainRate2d(IssmDouble* epsilon,IssmDouble* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){{{*/
+void Tria::GetStrainRate2d(IssmDouble* epsilon,IssmDouble* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input){
+	/*Compute the 2d Strain Rate (3 components):
+	 * epsilon=[exx eyy exy] */
+
+	int i;
+	IssmDouble epsilonvx[3];
+	IssmDouble epsilonvy[3];
+
+	/*Check that both inputs have been found*/
+	if (!vx_input || !vy_input){
+		_error_("Input missing. Here are the input pointers we have for vx: " << vx_input << ", vy: " << vy_input << "\n");
+	}
+
+	/*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{{{*/
+void  Tria::GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum){
+
+	int vertexpidlist[NUMVERTICES];
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(input_enum)) return;
+
+	/*Prepare index list*/
+	this->GetVertexPidList(&vertexpidlist[0]);
+
+	/*Get input (either in element or material)*/
+	Input* input=inputs->GetInput(input_enum);
+	if(!input) _error_("Input " << EnumToStringx(input_enum) << " not found in element");
+
+	/*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
+	input->GetVectorFromInputs(vector,&vertexpidlist[0]);
+}
+/*}}}*/
+/*FUNCTION Tria::GetVectorFromResults{{{*/
+void  Tria::GetVectorFromResults(Vector<IssmDouble>* vector,int offset,int enum_in,int interp){
+
+	/*Get result*/
+	ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(offset);
+	if(elementresult->InstanceEnum()!=enum_in){
+		_error_("Results of offset "<<offset<<" is "<<EnumToStringx(elementresult->InstanceEnum())<<" when "<<EnumToStringx(enum_in)<<" was expected");
+	}
+	if(interp==P1Enum){
+		int vertexpidlist[NUMVERTICES];
+		int connectivity[NUMVERTICES];
+		this->GetVertexSidList(&vertexpidlist[0]);
+		this->GetConnectivityList(&connectivity[0]);
+		elementresult->GetVectorFromResults(vector,&vertexpidlist[0],&connectivity[0],NUMVERTICES);
+	}
+	else if(interp==P0Enum){
+		elementresult->GetElementVectorFromResults(vector,sid);
+	}
+	else{
+		_printLine_("Interpolation " << EnumToStringx(interp) << " not supported");
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::Id {{{*/
+int    Tria::Id(){
+
+	return id;
+
+}
+/*}}}*/
+/*FUNCTION Tria::Sid {{{*/
+int    Tria::Sid(){
+
+	return sid;
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputArtificialNoise{{{*/
+void  Tria::InputArtificialNoise(int enum_type,IssmDouble min,IssmDouble max){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)_error_("could not find old input with enum: " << EnumToStringx(enum_type));
+
+	/*ArtificialNoise: */
+	input->ArtificialNoise(min,max);
+}
+/*}}}*/
+/*FUNCTION Tria::InputConvergence{{{*/
+bool Tria::InputConvergence(IssmDouble* eps, int* enums,int num_enums,int* criterionenums,IssmDouble* criterionvalues,int num_criterionenums){
+
+	bool    converged=true;
+	int     i;
+	Input** new_inputs=NULL;
+	Input** old_inputs=NULL;
+
+	new_inputs=xNew<Input*>(num_enums/2); //half the enums are for the new inputs
+	old_inputs=xNew<Input*>(num_enums/2); //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])_error_("could not find input with enum " << EnumToStringx(enums[2*i+0]));
+		if(!old_inputs[i])_error_("could not find input with enum " << EnumToStringx(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*/
+	xDelete<Input*>(new_inputs);
+	xDelete<Input*>(old_inputs);
+	return converged;
+}
+/*}}}*/
+/*FUNCTION Tria::InputDepthAverageAtBase {{{*/
+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==MeshElementsEnum)
+	 oldinput=(Input*)this->inputs->GetInput(enum_type);
+	else if (object_enum==MaterialsEnum)
+	 oldinput=(Input*)this->material->inputs->GetInput(enum_type);
+	else
+	 _error_("object " << EnumToStringx(object_enum) << " not supported yet");
+	if(!oldinput)_error_("could not find old input with enum: " << EnumToStringx(enum_type));
+	newinput=(Input*)oldinput->copy();
+
+	/*Assign new name (average)*/
+	newinput->ChangeEnum(average_enum_type);
+
+	/*Add new input to current element*/
+	if (object_enum==MeshElementsEnum)
+	 this->inputs->AddInput((Input*)newinput);
+	else if (object_enum==MaterialsEnum)
+	 this->material->inputs->AddInput((Input*)newinput);
+	else
+	 _error_("object " << EnumToStringx(object_enum) << " not supported yet");
+}
+/*}}}*/
+/*FUNCTION Tria::InputDuplicate{{{*/
+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{{{*/
+void  Tria::InputScale(int enum_type,IssmDouble scale_factor){
+
+	Input* input=NULL;
+
+	/*Make a copy of the original input: */
+	input=(Input*)this->inputs->GetInput(enum_type);
+	if(!input)_error_("could not find old input with enum: " << EnumToStringx(enum_type));
+
+	/*Scale: */
+	input->Scale(scale_factor);
+}
+/*}}}*/
+/*FUNCTION Tria::InputToResult{{{*/
+void  Tria::InputToResult(int enum_type,int step,IssmDouble time){
+
+	Input *input = NULL;	
+
+	/*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
+	if (enum_type==MaterialsRheologyBbarEnum || enum_type==MaterialsRheologyZbarEnum)
+	 input=this->material->inputs->GetInput(enum_type);
+	else
+	 input=this->inputs->GetInput(enum_type);
+	//if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found in tria->inputs");
+	if(!input)return;
+
+	/*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));
+
+	#ifdef _HAVE_CONTROL_
+	if(input->ObjectEnum()==ControlInputEnum){
+		if(((ControlInput*)input)->gradient!=NULL) this->results->AddObject((Object*)((ControlInput*)input)->SpawnGradient(step,time));
+	}
+	#endif
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromConstant(int value, int name);{{{*/
+void  Tria::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 Tria::InputUpdateFromConstant(IssmDouble value, int name);{{{*/
+void  Tria::InputUpdateFromConstant(IssmDouble constant, int name){
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	this->inputs->AddInput(new DoubleInput(name,constant));
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromConstant(bool value, int name);{{{*/
+void  Tria::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 Tria::InputUpdateFromIoModel{{{*/
+void Tria::InputUpdateFromIoModel(int index, IoModel* iomodel){ //i is the element index
+
+	/*Intermediaries*/
+	int        i,j;
+	int        tria_vertex_ids[3];
+	IssmDouble nodeinputs[3];
+	IssmDouble cmmininputs[3];
+	IssmDouble cmmaxinputs[3];
+	bool       control_analysis   = false;
+	int        num_control_type;
+	IssmDouble yts;
+	int        num_cm_responses;
+
+	/*Get parameters: */
+	iomodel->Constant(&yts,ConstantsYtsEnum); 
+	iomodel->Constant(&control_analysis,InversionIscontrolEnum);
+	if(control_analysis) iomodel->Constant(&num_control_type,InversionNumControlParametersEnum);
+	if(control_analysis) iomodel->Constant(&num_cm_responses,InversionNumCostFunctionsEnum);
+
+	/*Recover vertices ids needed to initialize inputs*/
+	for(i=0;i<3;i++){ 
+		tria_vertex_ids[i]=reCast<int>(iomodel->Data(MeshElementsEnum)[3*index+i]); //ids for vertices are in the elements array from Matlab
+	}
+
+	/*Control Inputs*/
+	#ifdef _HAVE_CONTROL_
+	if (control_analysis && iomodel->Data(InversionControlParametersEnum)){
+		for(i=0;i<num_control_type;i++){
+			switch(reCast<int>(iomodel->Data(InversionControlParametersEnum)[i])){
+				case BalancethicknessThickeningRateEnum:
+					if (iomodel->Data(BalancethicknessThickeningRateEnum)){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->Data(BalancethicknessThickeningRateEnum)[tria_vertex_ids[j]-1]/yts;
+						for(j=0;j<3;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i]/yts;
+						for(j=0;j<3;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i]/yts;
+						this->inputs->AddInput(new ControlInput(BalancethicknessThickeningRateEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case VxEnum:
+					if (iomodel->Data(VxEnum)){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->Data(VxEnum)[tria_vertex_ids[j]-1]/yts;
+						for(j=0;j<3;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i]/yts;
+						for(j=0;j<3;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i]/yts;
+						this->inputs->AddInput(new ControlInput(VxEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case VyEnum:
+					if (iomodel->Data(VyEnum)){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->Data(VyEnum)[tria_vertex_ids[j]-1]/yts;
+						for(j=0;j<3;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i]/yts;
+						for(j=0;j<3;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i]/yts;
+						this->inputs->AddInput(new ControlInput(VyEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case ThicknessEnum:
+					if (iomodel->Data(ThicknessEnum)){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->Data(ThicknessEnum)[tria_vertex_ids[j]-1];
+						for(j=0;j<3;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i];
+						for(j=0;j<3;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i];
+						this->inputs->AddInput(new ControlInput(ThicknessEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case FrictionCoefficientEnum:
+					if (iomodel->Data(FrictionCoefficientEnum)){
+						for(j=0;j<3;j++)nodeinputs[j]=iomodel->Data(FrictionCoefficientEnum)[tria_vertex_ids[j]-1];
+						for(j=0;j<3;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i];
+						for(j=0;j<3;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[(tria_vertex_ids[j]-1)*num_control_type+i];
+						this->inputs->AddInput(new ControlInput(FrictionCoefficientEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+					}
+					break;
+				case MaterialsRheologyBbarEnum:
+				case MaterialsRheologyZbarEnum:
+					/*Material will take care of it*/ break;
+				default:
+					_error_("Control " << EnumToStringx(reCast<int,IssmDouble>(iomodel->Data(InversionControlParametersEnum)[i])) << " not implemented yet");
+			}
+		}
+	}
+	#endif
+
+	/*DatasetInputs*/
+	if (control_analysis && iomodel->Data(InversionCostFunctionsCoefficientsEnum)){
+
+		/*Create inputs and add to DataSetInput*/
+		DatasetInput* datasetinput=new DatasetInput(InversionCostFunctionsCoefficientsEnum);
+		for(i=0;i<num_cm_responses;i++){
+			for(j=0;j<3;j++)nodeinputs[j]=iomodel->Data(InversionCostFunctionsCoefficientsEnum)[(tria_vertex_ids[j]-1)*num_cm_responses+i];
+			datasetinput->inputs->AddObject(new TriaP1Input(InversionCostFunctionsCoefficientsEnum,nodeinputs));
+		}
+
+		/*Add datasetinput to element inputs*/
+		this->inputs->AddInput(datasetinput);
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolution {{{*/
+void  Tria::InputUpdateFromSolution(IssmDouble* 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: */
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			InputUpdateFromSolutionDiagnosticHoriz(solution);
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			InputUpdateFromSolutionDiagnosticHoriz(solution);
+			break;
+		#endif
+		#ifdef _HAVE_CONTROL_
+		case AdjointHorizAnalysisEnum:
+			InputUpdateFromSolutionAdjointHoriz(solution);
+			break;
+		case AdjointBalancethicknessAnalysisEnum:
+			InputUpdateFromSolutionAdjointBalancethickness(solution);
+			break;
+		#endif
+		#ifdef _HAVE_HYDROLOGY_ 
+		case HydrologyShreveAnalysisEnum:
+			InputUpdateFromSolutionHydrologyShreve(solution);
+			break;
+		case HydrologyDCInefficientAnalysisEnum:
+			InputUpdateFromSolutionHydrologyDCInefficient(solution);
+			break;
+		case HydrologyDCEfficientAnalysisEnum:
+			InputUpdateFromSolutionHydrologyDCEfficient(solution);
+			break;
+		#endif
+	 	#ifdef _HAVE_BALANCED_
+		case BalancethicknessAnalysisEnum:
+			InputUpdateFromSolutionOneDof(solution,ThicknessEnum);
+			break;
+		#endif
+		case BedSlopeXAnalysisEnum:
+			InputUpdateFromSolutionOneDof(solution,BedSlopeXEnum);
+			break;
+		case BedSlopeYAnalysisEnum:
+			InputUpdateFromSolutionOneDof(solution,BedSlopeYEnum);
+			break;
+		case SurfaceSlopeXAnalysisEnum:
+			InputUpdateFromSolutionOneDof(solution,SurfaceSlopeXEnum);
+			break;
+		case SurfaceSlopeYAnalysisEnum:
+			InputUpdateFromSolutionOneDof(solution,SurfaceSlopeYEnum);
+			break;
+		case PrognosticAnalysisEnum:
+			InputUpdateFromSolutionPrognostic(solution);
+			break;
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionOneDof{{{*/
+void  Tria::InputUpdateFromSolutionOneDof(IssmDouble* solution,int enum_type){
+
+	const int numdof          = NDOF1*NUMVERTICES;
+
+	int*      doflist=NULL;
+	IssmDouble    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]];
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new TriaP1Input(enum_type,values));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionPrognostic{{{*/
+void  Tria::InputUpdateFromSolutionPrognostic(IssmDouble* solution){
+
+	/*Intermediaries*/
+	const int numdof = NDOF1*NUMVERTICES;
+
+	int       i,hydroadjustment;
+	int*      doflist=NULL;
+	IssmDouble    rho_ice,rho_water,minthickness;
+	IssmDouble    newthickness[numdof];
+	IssmDouble    newbed[numdof];
+	IssmDouble    newsurface[numdof];
+	IssmDouble    oldbed[NUMVERTICES];
+	IssmDouble    oldsurface[NUMVERTICES];
+	IssmDouble    oldthickness[NUMVERTICES];
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Use the dof list to index into the solution vector: */
+	this->parameters->FindParam(&minthickness,PrognosticMinThicknessEnum);
+	for(i=0;i<numdof;i++){
+		newthickness[i]=solution[doflist[i]];
+		if(xIsNan<IssmDouble>(newthickness[i])) _error_("NaN found in solution vector");
+		/*Constrain thickness to be at least 1m*/
+		if(newthickness[i]<minthickness) newthickness[i]=minthickness;
+	}
+
+	/*Get previous bed, thickness and surface*/
+	GetInputListOnVertices(&oldbed[0],BedEnum);
+	GetInputListOnVertices(&oldsurface[0],SurfaceEnum);
+	GetInputListOnVertices(&oldthickness[0],ThicknessEnum);
+
+	/*Fing PrognosticHydrostaticAdjustment to figure out how to update the geometry:*/
+	this->parameters->FindParam(&hydroadjustment,PrognosticHydrostaticAdjustmentEnum);
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+
+	for(i=0;i<numdof;i++) {
+		/*If shelf: hydrostatic equilibrium*/
+		if (this->nodes[i]->IsGrounded()){
+			newsurface[i]=oldbed[i]+newthickness[i]; //surface = oldbed + newthickness
+			newbed[i]=oldbed[i];               //same bed: do nothing
+		}
+		else{ //this is an ice shelf
+
+			if(hydroadjustment==AbsoluteEnum){
+				newsurface[i]=newthickness[i]*(1-rho_ice/rho_water);
+				newbed[i]=newthickness[i]*(-rho_ice/rho_water);
+			}
+			else if(hydroadjustment==IncrementalEnum){
+				newsurface[i]=oldsurface[i]+(1.0-rho_ice/rho_water)*(newthickness[i]-oldthickness[i]); //surface = oldsurface + (1-di) * dH 
+				newbed[i]=oldbed[i]-rho_ice/rho_water*(newthickness[i]-oldthickness[i]); //bed = oldbed + di * dH
+			}
+			else _error_("Hydrostatic adjustment " << hydroadjustment << " (" << EnumToStringx(hydroadjustment) << ") not supported yet");
+		}
+	}
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new TriaP1Input(ThicknessEnum,newthickness));
+	this->inputs->AddInput(new TriaP1Input(SurfaceEnum,newsurface));
+	this->inputs->AddInput(new TriaP1Input(BedEnum,newbed));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVector(IssmDouble* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+
+	const int   numdof         = NDOF1 *NUMVERTICES;
+	int        *doflist        = NULL;
+	IssmDouble  values[numdof];
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+	case VertexPIdEnum: 
+		/*Get values on the 3 vertices*/
+		for (int i=0;i<3;i++){
+			values[i]=vector[this->nodes[i]->GetVertexPid()];
+		}
+		/*update input*/
+		if (name==MaterialsRheologyBbarEnum || name==MaterialsRheologyBEnum || name==MaterialsRheologyZEnum || name==MaterialsRheologyZbarEnum){
+			material->inputs->AddInput(new TriaP1Input(name,values));
+		}
+		else{
+			this->inputs->AddInput(new TriaP1Input(name,values));
+		}
+		return; 
+
+	case VertexSIdEnum: 
+		/*Get values on the 3 vertices*/
+		for (int i=0;i<3;i++){
+			values[i]=vector[this->nodes[i]->GetVertexSid()];
+		}
+		/*update input*/
+		if (name==MaterialsRheologyBbarEnum || name==MaterialsRheologyBEnum || name==MaterialsRheologyZEnum || name==MaterialsRheologyZbarEnum){
+			material->inputs->AddInput(new TriaP1Input(name,values));
+		}
+		else{
+			this->inputs->AddInput(new TriaP1Input(name,values));
+		}
+		return; 
+
+	case NodesEnum:
+		/*Get dof list: */
+		GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+		
+		/*Use the dof list to index into the vector: */
+		for(int i=0;i<numdof;i++){
+			values[i]=vector[doflist[i]];
+			if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+		}
+		/*Add input to the element: */
+		this->inputs->AddInput(new TriaP1Input(name,values));
+		
+		/*Free ressources:*/
+		xDelete<int>(doflist);
+		return;
+
+	default:
+		_error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVector(int* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVector(int* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVector(bool* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVector(bool* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Tria::InputCreate(IssmDouble scalar,int enum,int code);{{{*/
+void Tria::InputCreate(IssmDouble scalar,int name,int code){
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	if ((code==5) || (code==1)){ //boolean
+		this->inputs->AddInput(new BoolInput(name,reCast<bool>(scalar)));
+	}
+	else if ((code==6) || (code==2)){ //integer
+		this->inputs->AddInput(new IntInput(name,reCast<int>(scalar)));
+	}
+	else if ((code==7) || (code==3)){ //IssmDouble
+		this->inputs->AddInput(new DoubleInput(name,reCast<int>(scalar)));
+	}
+	else _error_("could not recognize nature of vector from code " << code);
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputCreate(IssmDouble* vector,int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code){{{*/
+void Tria::InputCreate(IssmDouble* vector, int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code){//index into elements
+
+	/*Intermediaries*/
+	int    i,j,t;
+	int    tria_vertex_ids[3];
+	int    row;
+	IssmDouble nodeinputs[3];
+	IssmDouble time;
+	TransientInput* transientinput=NULL;
+	int    numberofvertices;
+	int    numberofelements;
+	IssmDouble yts;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&numberofvertices,MeshNumberofverticesEnum);
+	iomodel->Constant(&numberofelements,MeshNumberofelementsEnum);
+	iomodel->Constant(&yts,ConstantsYtsEnum);
+
+	/*Branch on type of vector: nodal or elementary: */
+	if(vector_type==1){ //nodal vector
+
+		/*Recover vertices ids needed to initialize inputs*/
+		for(i=0;i<3;i++){ 
+			_assert_(iomodel->Data(MeshElementsEnum));
+			tria_vertex_ids[i]=reCast<int>(iomodel->Data(MeshElementsEnum)[3*index+i]); //ids for vertices are in the elements array from Matlab
+		}
+
+		/*Are we in transient or static? */
+		if(M==numberofvertices){
+
+			/*create input values: */
+			for(i=0;i<3;i++)nodeinputs[i]=(IssmDouble)vector[tria_vertex_ids[i]-1];
+
+			/*process units: */
+			UnitConversion(&nodeinputs[0], 3 ,ExtToIuEnum, vector_enum);
+
+			/*create static input: */
+			this->inputs->AddInput(new TriaP1Input(vector_enum,nodeinputs));
+		}
+		else if(M==numberofvertices+1){
+			/*create transient input: */
+			for(t=0;t<N;t++){ //N is the number of times
+
+				/*create input values: */
+				for(i=0;i<3;i++){
+					row=tria_vertex_ids[i]-1;
+					nodeinputs[i]=(IssmDouble)vector[N*row+t];
+				}
+
+				/*process units: */
+				UnitConversion(&nodeinputs[0], 3 ,ExtToIuEnum, vector_enum);
+
+				/*time? :*/
+				time=(IssmDouble)vector[(M-1)*N+t]*yts;
+
+				if(t==0) transientinput=new TransientInput(vector_enum);
+				transientinput->AddTimeInput(new TriaP1Input(vector_enum,nodeinputs),time);
+			}
+			this->inputs->AddInput(transientinput);
+		}
+		else _error_("nodal vector is either numberofnodes or numberofnodes+1 long. Field provided (" << EnumToStringx(vector_enum) << ") is " << M << " long");
+	}
+	else if(vector_type==2){ //element vector
+		/*Are we in transient or static? */
+		if(M==numberofelements){
+
+			/*static mode: create an input out of the element value: */
+
+			if (code==5){ //boolean
+				this->inputs->AddInput(new BoolInput(vector_enum,reCast<bool>(vector[index])));
+			}
+			else if (code==6){ //integer
+				this->inputs->AddInput(new IntInput(vector_enum,reCast<int>(vector[index])));
+			}
+			else if (code==7){ //IssmDouble
+				this->inputs->AddInput(new DoubleInput(vector_enum,vector[index]));
+			}
+			else _error_("could not recognize nature of vector from code " << code);
+		}
+		else {
+			_error_("transient element inputs not supported yet!");
+		}
+	}
+	else{
+		_error_("Cannot add input for vector type " << vector_type << " (not supported)");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::IsInput{{{*/
+bool Tria::IsInput(int name){
+	if (
+				name==ThicknessEnum ||
+				name==SurfaceEnum ||
+				name==BathymetryEnum ||
+				name==BedEnum ||
+				name==GLlevelsetEnum ||
+				name==SurfaceSlopeXEnum ||
+				name==SurfaceSlopeYEnum ||
+				name==BasalforcingsMeltingRateEnum ||
+				name==WatercolumnEnum || 
+				name==SurfaceforcingsMassBalanceEnum ||
+				name==SurfaceAreaEnum||
+				name==VxEnum ||
+				name==VyEnum ||
+				name==InversionVxObsEnum ||
+				name==InversionVyObsEnum ||
+				name==FrictionCoefficientEnum ||
+				name==MaterialsRheologyBbarEnum ||
+				name==MaterialsRheologyZbarEnum ||
+				name==GradientEnum ||
+				name==OldGradientEnum ||
+				name==ConvergedEnum ||
+				name==SedimentHeadOldEnum ||
+				name==SedimentHeadEnum ||
+				name==BasisIntegralEnum ||
+				name==QmuVxEnum ||
+				name==QmuVyEnum ||
+				name==QmuPressureEnum ||
+				name==QmuBedEnum ||
+				name==QmuThicknessEnum ||
+				name==QmuSurfaceEnum ||
+				name==QmuTemperatureEnum ||
+				name==QmuMeltingEnum || 
+				name==GiaWEnum || 
+				name==GiadWdtEnum
+		){
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Tria::IsOnBed {{{*/
+bool Tria::IsOnBed(){
+
+	bool onbed;
+	inputs->GetInputValue(&onbed,MeshElementonbedEnum);
+	return onbed;
+}
+/*}}}*/
+/*FUNCTION Tria::IsFloating {{{*/
+bool   Tria::IsFloating(){
+
+	bool shelf;
+	inputs->GetInputValue(&shelf,MaskElementonfloatingiceEnum);
+	return shelf;
+}
+/*}}}*/
+/*FUNCTION Tria::IsNodeOnShelf {{{*/
+bool   Tria::IsNodeOnShelf(){
+
+	int  i;
+	bool shelf=false;
+
+	for(i=0;i<3;i++){
+		if (nodes[i]->IsFloating()){
+			shelf=true;
+			break;
+		}
+	}
+	return shelf;
+}
+/*}}}*/
+/*FUNCTION Tria::IsNodeOnShelfFromFlags {{{*/
+bool   Tria::IsNodeOnShelfFromFlags(IssmDouble* flags){
+
+	int  i;
+	bool shelf=false;
+
+	for(i=0;i<NUMVERTICES;i++){
+		if (reCast<bool>(flags[nodes[i]->Sid()])){
+			shelf=true;
+			break;
+		}
+	}
+	return shelf;
+}
+/*}}}*/
+/*FUNCTION Tria::IsOnWater {{{*/
+bool   Tria::IsOnWater(){
+
+	bool water;
+	inputs->GetInputValue(&water,MaskElementonwaterEnum);
+	return water;
+}
+/*}}}*/
+/*FUNCTION Tria::ListResultsInfo{{{*/
+void Tria::ListResultsInfo(int** in_resultsenums,int** in_resultssizes,IssmDouble** in_resultstimes,int** in_resultssteps,int* in_num_results){
+
+	/*Intermediaries*/
+	int     i;
+	int     numberofresults = 0;
+	int     *resultsenums   = NULL;
+	int     *resultssizes   = NULL;
+	IssmDouble  *resultstimes   = NULL;
+	int     *resultssteps   = NULL;
+
+	/*Checks*/
+	_assert_(in_num_results);
+
+	/*Count number of results*/
+	for(i=0;i<this->results->Size();i++){
+		ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+		numberofresults++;
+	}
+
+	if(numberofresults){
+
+		/*Allocate output*/
+		resultsenums=xNew<int>(numberofresults);
+		resultssizes=xNew<int>(numberofresults);
+		resultstimes=xNew<IssmDouble>(numberofresults);
+		resultssteps=xNew<int>(numberofresults);
+
+		/*populate enums*/
+		for(i=0;i<this->results->Size();i++){
+			ElementResult* elementresult=(ElementResult*)this->results->GetObjectByOffset(i);
+			resultsenums[i]=elementresult->InstanceEnum();
+			resultstimes[i]=elementresult->GetTime();
+			resultssteps[i]=elementresult->GetStep();
+			if(elementresult->ObjectEnum()==TriaP1ElementResultEnum){
+				resultssizes[i]=P1Enum;
+			}
+			else{
+				resultssizes[i]=P0Enum;
+			}
+		}
+	}
+
+	/*Assign output pointers:*/
+	*in_num_results=numberofresults;
+	*in_resultsenums=resultsenums;
+	*in_resultssizes=resultssizes;
+	*in_resultstimes=resultstimes;
+	*in_resultssteps=resultssteps;
+
+}/*}}}*/
+/*FUNCTION Tria::MigrateGroundingLine{{{*/
+void  Tria::MigrateGroundingLine(IssmDouble* old_floating_ice,IssmDouble* sheet_ungrounding){
+
+	int     i,migration_style;
+	bool    floatingelement = false;
+	bool    groundedelement = false;
+	IssmDouble  bed_hydro,yts,gl_melting_rate;
+	IssmDouble  rho_water,rho_ice,density;
+	IssmDouble  melting[NUMVERTICES],phi[NUMVERTICES];;
+	IssmDouble  h[NUMVERTICES],s[NUMVERTICES],b[NUMVERTICES],ba[NUMVERTICES];
+
+	/*Recover info at the vertices: */
+	parameters->FindParam(&migration_style,GroundinglineMigrationEnum);
+	parameters->FindParam(&gl_melting_rate,GroundinglineMeltingRateEnum);
+	parameters->FindParam(&yts,ConstantsYtsEnum);
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&s[0],SurfaceEnum);
+	GetInputListOnVertices(&b[0],BedEnum);
+	GetInputListOnVertices(&ba[0],BathymetryEnum);
+	if(migration_style==SubelementMigrationEnum || migration_style==SubelementMigration2Enum) GetInputListOnVertices(&phi[0],GLlevelsetEnum);
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	density=rho_ice/rho_water;
+
+	/*go through vertices, and update inputs, considering them to be TriaVertex type: */
+	for(i=0;i<NUMVERTICES;i++){
+		/*Ice shelf: if bed below bathymetry, impose it at the bathymetry and update surface, elso do nothing */
+		if(reCast<bool>(old_floating_ice[nodes[i]->Sid()])){
+			if(b[i]<=ba[i]){ 
+				b[i]=ba[i];
+				s[i]=b[i]+h[i];
+				nodes[i]->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,false));
+				nodes[i]->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,true));
+			}
+		}
+		/*Ice sheet: if hydrostatic bed above bathymetry, ice sheet starts to unground, elso do nothing */
+		/*Change only if AgressiveMigration or if the ice sheet is in contact with the ocean*/
+		else{
+			bed_hydro=-density*h[i];
+			if (bed_hydro>ba[i]){
+				/*Unground only if the element is connected to the ice shelf*/
+				if(migration_style==AgressiveMigrationEnum || migration_style==SubelementMigrationEnum || migration_style==SubelementMigration2Enum){
+					s[i]=(1-density)*h[i];
+					b[i]=-density*h[i];
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,true));
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,false));
+				}
+				else if(migration_style==SoftMigrationEnum && reCast<bool>(sheet_ungrounding[nodes[i]->Sid()])){
+					s[i]=(1-density)*h[i];
+					b[i]=-density*h[i];
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,true));
+					nodes[i]->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,false));
+				}
+				else{
+					if(migration_style!=SoftMigrationEnum) _error_("Error: migration should be Aggressive, Soft or Subelement");
+				}
+			}
+		}
+	}
+
+	/*SubelementMigrationEnum: if one grounded, all grounded*/
+	if(migration_style==SubelementMigrationEnum || migration_style==SubelementMigration2Enum){
+		for(i=0;i<NUMVERTICES;i++){
+			if(nodes[i]->IsGrounded()){
+				groundedelement=true;
+				break;
+			}
+		}
+		floatingelement=!groundedelement;
+	}
+	else{
+		/*Otherwise: if one floating, all floating*/
+		for(i=0;i<NUMVERTICES;i++){
+			if(nodes[i]->IsFloating()){
+				floatingelement=true;
+				break;
+			}
+		}
+	}
+
+   /*Add basal melting rate if element just ungrounded*/
+	if(!this->IsFloating() && floatingelement==true){
+		for(i=0;i<NUMVERTICES;i++)melting[i]=gl_melting_rate/yts;
+		this->inputs->AddInput(new TriaP1Input(BasalforcingsMeltingRateEnum,&melting[0]));
+	} 
+
+	/*Update inputs*/
+   this->inputs->AddInput(new BoolInput(MaskElementonfloatingiceEnum,floatingelement));
+	this->inputs->AddInput(new TriaP1Input(SurfaceEnum,&s[0]));
+	this->inputs->AddInput(new TriaP1Input(BedEnum,&b[0]));
+
+	/*Recalculate phi*/
+	if(migration_style==SubelementMigrationEnum || migration_style==SubelementMigration2Enum){
+		for(i=0;i<NUMVERTICES;i++) phi[i]=h[i]+ba[i]/density;
+		this->inputs->AddInput(new TriaP1Input(GLlevelsetEnum,&phi[0]));
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::NodalValue {{{*/
+int    Tria::NodalValue(IssmDouble* pvalue, int index, int natureofdataenum,bool process_units){
+
+	int         found = 0;
+	IssmDouble  value;
+	Input      *data  = NULL;
+	GaussTria  *gauss = NULL;
+
+	/*First, serarch the input: */
+	data=inputs->GetInput(natureofdataenum); 
+
+	/*figure out if we have the vertex id: */
+	found=0;
+	for(int i=0;i<NUMVERTICES;i++){
+		if(index==nodes[i]->GetVertexId()){
+			/*Do we have natureofdataenum in our inputs? :*/
+			if(data){
+				/*ok, we are good. retrieve value of input at vertex :*/
+				gauss=new GaussTria(); gauss->GaussVertex(i);
+				data->GetInputValue(&value,gauss);
+				found=1;
+				break;
+			}
+		}
+	}
+
+	/*clean-up*/
+	delete gauss;
+
+	if(found)*pvalue=value;
+	return found;
+}
+/*}}}*/
+/*FUNCTION Tria::PatchFill{{{*/
+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->sid+1,vertices_ids,3);
+		elementresult->PatchFill(row,patch);
+
+		/*increment rower: */
+		row++;
+	}
+
+	/*Assign output pointers:*/
+	*prow=row;
+}
+/*}}}*/
+/*FUNCTION Tria::PatchSize{{{*/
+void  Tria::PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes){
+
+	int     i;
+	int     numrows       = 0;
+	int     numnodes      = 0;
+	int     temp_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? :*/
+		temp_numnodes=elementresult->NumberOfNodalValues(); //ask result object.
+		if(temp_numnodes>numnodes)numnodes=temp_numnodes;
+	}
+
+	/*Assign output pointers:*/
+	*pnumrows=numrows;
+	*pnumvertices=NUMVERTICES;
+	*pnumnodes=numnodes;
+}
+/*}}}*/
+/*FUNCTION Tria::PotentialUngrounding{{{*/
+void  Tria::PotentialUngrounding(Vector<IssmDouble>* potential_ungrounding){
+
+	int     i;
+	IssmDouble  h[NUMVERTICES],ba[NUMVERTICES];
+	IssmDouble  bed_hydro;
+	IssmDouble  rho_water,rho_ice,density;
+
+	/*material parameters: */
+	rho_water=matpar->GetRhoWater();
+	rho_ice=matpar->GetRhoIce();
+	density=rho_ice/rho_water;
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&ba[0],BathymetryEnum);
+
+	/*go through vertices, and figure out which ones are grounded and want to unground: */
+	for(i=0;i<NUMVERTICES;i++){
+		/*Find if grounded vertices want to start floating*/
+		if (!nodes[i]->IsFloating()){
+			bed_hydro=-density*h[i];
+			if (bed_hydro>ba[i]){
+				/*Vertex that could potentially unground, flag it*/
+				potential_ungrounding->SetValue(nodes[i]->Sid(),1,INS_VAL);
+			}
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::PositiveDegreeDay{{{*/
+void  Tria::PositiveDegreeDay(IssmDouble* pdds,IssmDouble* pds,IssmDouble signorm){
+
+   IssmDouble agd[NUMVERTICES];             // surface mass balance
+   IssmDouble monthlytemperatures[NUMVERTICES][12],monthlyprec[NUMVERTICES][12];
+   IssmDouble h[NUMVERTICES],s[NUMVERTICES];
+   IssmDouble rho_water,rho_ice,desfac,s0p;
+
+   /*Recover monthly temperatures and precipitation*/
+   Input*     input=inputs->GetInput(SurfaceforcingsMonthlytemperaturesEnum); _assert_(input);
+   Input*     input2=inputs->GetInput(SurfaceforcingsPrecipitationEnum); _assert_(input2);
+   GaussTria* gauss=new GaussTria();
+   IssmDouble time,yts;
+   this->parameters->FindParam(&time,TimeEnum);
+   this->parameters->FindParam(&yts,ConstantsYtsEnum);
+   for(int month=0;month<12;month++) {
+     for(int iv=0;iv<NUMVERTICES;iv++) {
+       gauss->GaussVertex(iv);
+       input->GetInputValue(&monthlytemperatures[iv][month],gauss,time+month/12.*yts);
+       monthlytemperatures[iv][month]=monthlytemperatures[iv][month]-273.15; // conversion from Kelvin to celcius
+       input2->GetInputValue(&monthlyprec[iv][month],gauss,time+month/12.*yts);
+       monthlyprec[iv][month]=monthlyprec[iv][month]*yts; // convertion in m/y
+     }
+   }
+
+  /*Recover info at the vertices: */
+  GetInputListOnVertices(&h[0],ThicknessEnum);
+  GetInputListOnVertices(&s[0],SurfaceEnum);
+
+  /*Get material parameters :*/
+  rho_ice=matpar->GetRhoIce();
+  rho_water=matpar->GetRhoFreshwater();
+
+  /*Get desertification effect parameters*/
+  desfac=matpar->GetDesFac();
+  s0p=matpar->GetS0p();
+
+   /*measure the surface mass balance*/
+   for (int iv = 0; iv<NUMVERTICES; iv++){
+     agd[iv]=PddSurfaceMassBlance(&monthlytemperatures[iv][0], &monthlyprec[iv][0], pdds, pds, signorm, yts, h[iv], s[iv], rho_ice, rho_water, desfac, s0p);
+   }
+
+   /*Update inputs*/    
+   this->inputs->AddInput(new TriaP1Input(SurfaceforcingsMassBalanceEnum,&agd[0]));
+   // this->inputs->AddInput(new TriaVertexInput(ThermalSpcTemperatureEnum,&Tsurf[0]));
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::ProcessResultsUnits{{{*/
+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::RequestedOutput{{{*/
+void Tria::RequestedOutput(int output_enum,int step,IssmDouble time){
+
+	if(IsInput(output_enum)){
+		/*just transfer this input to results, and we are done: */
+		InputToResult(output_enum,step,time);
+	}
+	else{
+		/*this input does not exist, compute it, and then transfer to results: */
+		switch(output_enum){
+			case StressTensorEnum: 
+				this->ComputeStressTensor();
+				InputToResult(StressTensorxxEnum,step,time);
+				InputToResult(StressTensorxyEnum,step,time);
+				InputToResult(StressTensorxzEnum,step,time);
+				InputToResult(StressTensoryyEnum,step,time);
+				InputToResult(StressTensoryzEnum,step,time);
+				InputToResult(StressTensorzzEnum,step,time);
+				break;
+
+			default:
+				/*do nothing, no need to derail the computation because one of the outputs requested cannot be found: */
+				break;
+		}
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::SetClone {{{*/
+void  Tria::SetClone(int* minranks){
+
+	_error_("not implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::SmearFunction {{{*/
+void  Tria::SmearFunction(Vector<IssmDouble>*  smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius){
+	_error_("not implemented yet");
+
+}
+/*}}}*/
+/*FUNCTION Tria::SmbGradients{{{*/
+void Tria::SmbGradients(void){
+
+	int i;
+
+	// input
+   IssmDouble h[NUMVERTICES];					// ice thickness (m)		
+	IssmDouble s[NUMVERTICES];					// surface elevation (m)
+	IssmDouble b_pos[NUMVERTICES];				// Hs-SMB relation parameter
+	IssmDouble b_neg[NUMVERTICES];				// Hs-SMB relation paremeter
+	IssmDouble Href[NUMVERTICES];					// reference elevation from which deviations are used to calculate the SMB adjustment
+	IssmDouble Smbref[NUMVERTICES];				// reference SMB to which deviations are added
+   IssmDouble rho_water;                   // density of fresh water
+	IssmDouble rho_ice;                     // density of ice
+
+	// output
+	IssmDouble smb[NUMVERTICES];					// surface mass balance (m/yr ice)
+
+	/*Recover SmbGradients*/
+	GetInputListOnVertices(&Href[0],SurfaceforcingsHrefEnum);
+	GetInputListOnVertices(&Smbref[0],SurfaceforcingsSmbrefEnum);
+	GetInputListOnVertices(&b_pos[0],SurfaceforcingsBPosEnum);
+	GetInputListOnVertices(&b_neg[0],SurfaceforcingsBNegEnum);
+
+   /*Recover surface elevatio at vertices: */
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&s[0],SurfaceEnum);
+
+   /*Get material parameters :*/
+   rho_ice=matpar->GetRhoIce();
+   rho_water=matpar->GetRhoFreshwater();
+
+   // loop over all vertices
+   for(i=0;i<NUMVERTICES;i++){
+     if(Smbref[i]>0){
+		  smb[i]=Smbref[i]+b_pos[i]*(s[i]-Href[i]);
+	  }
+	  else{
+		  smb[i]=Smbref[i]+b_neg[i]*(s[i]-Href[i]);
+	  }
+	  smb[i]=smb[i]/rho_ice;      // SMB in m/y ice		
+		}  //end of the loop over the vertices
+	  /*Update inputs*/
+	  this->inputs->AddInput(new TriaP1Input(SurfaceforcingsMassBalanceEnum,&smb[0]));
+}
+/*}}}*/
+/*FUNCTION Tria::SetCurrentConfiguration {{{*/
+void  Tria::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, Nodes* 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];
+
+	/*Pick up nodes*/
+	if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
+	else this->nodes=NULL;
+
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceArea {{{*/
+IssmDouble Tria::SurfaceArea(void){
+
+	IssmDouble S;
+	IssmDouble normal[3];
+	IssmDouble v13[3],v23[3];
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	for(int 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(normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
+
+	/*Return: */
+	return S;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceNormal{{{*/
+void Tria::SurfaceNormal(IssmDouble* surface_normal, IssmDouble xyz_list[3][3]){
+
+	IssmDouble v13[3],v23[3];
+	IssmDouble normal[3];
+	IssmDouble normal_norm;
+
+	for(int 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( normal[0]*normal[0] + normal[1]*normal[1] + normal[2]*normal[2]);
+
+	*(surface_normal+0) = normal[0]/normal_norm;
+	*(surface_normal+1) = normal[1]/normal_norm;
+	*(surface_normal+2) = normal[2]/normal_norm;
+}
+/*}}}*/
+/*FUNCTION Tria::TimeAdapt{{{*/
+IssmDouble  Tria::TimeAdapt(void){
+
+	/*intermediary: */
+	int    i;
+	IssmDouble C,dt;
+	IssmDouble dx,dy;
+	IssmDouble maxx,minx;
+	IssmDouble maxy,miny;
+	IssmDouble maxabsvx,maxabsvy;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	/*get CFL coefficient:*/
+	this->parameters->FindParam(&C,TimesteppingCflCoefficientEnum);
+
+	/*Get for Vx and Vy, the max of abs value: */
+	#ifdef _HAVE_RESPONSES_
+	this->MaxAbsVx(&maxabsvx,false);
+	this->MaxAbsVy(&maxabsvy,false);
+	#else
+		_error_("ISSM was not compiled with responses compiled in, exiting!");
+	#endif
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,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::Update(int index, IoModel* iomodel,int analysis_counter,int analysis_type){{{*/
+void Tria::Update(int index, IoModel* iomodel,int analysis_counter,int analysis_type){ //i is the element index
+
+	/*Intermediaries*/
+	int    i,j;
+	int    tria_node_ids[3];
+	int    tria_vertex_ids[3];
+	int    tria_type;
+	IssmDouble nodeinputs[3];
+	IssmDouble yts;
+	int    progstabilization,balancestabilization;
+	bool   dakota_analysis;
+
+	/*Checks if debuging*/
+	/*{{{*/
+	_assert_(iomodel->Data(MeshElementsEnum));
+	/*}}}*/
+
+	/*Fetch parameters: */
+	iomodel->Constant(&yts,ConstantsYtsEnum);
+	iomodel->Constant(&progstabilization,PrognosticStabilizationEnum);
+	iomodel->Constant(&balancestabilization,BalancethicknessStabilizationEnum);
+	iomodel->Constant(&dakota_analysis,QmuIsdakotaEnum);
+
+	/*Recover element type*/
+	if ((analysis_type==PrognosticAnalysisEnum && progstabilization==3) || (analysis_type==BalancethicknessAnalysisEnum && balancestabilization==3)){
+		/*P1 Discontinuous Galerkin*/
+		tria_type=P1DGEnum;
+	}
+	else{
+		/*P1 Continuous Galerkin*/
+		tria_type=P1Enum;
+	}
+	this->SetElementType(tria_type,analysis_counter);
+
+	/*Recover vertices ids needed to initialize inputs*/
+	for(i=0;i<3;i++){ 
+		tria_vertex_ids[i]=reCast<int>(iomodel->Data(MeshElementsEnum)[3*index+i]); //ids for vertices are in the elements array from Matlab
+	}
+
+	/*Recover nodes ids needed to initialize the node hook.*/
+	if (tria_type==P1DGEnum){
+		/*Discontinuous Galerkin*/
+		tria_node_ids[0]=iomodel->nodecounter+3*index+1;
+		tria_node_ids[1]=iomodel->nodecounter+3*index+2;
+		tria_node_ids[2]=iomodel->nodecounter+3*index+3;
+	}
+	else{
+		/*Continuous Galerkin*/
+		for(i=0;i<3;i++){ 
+			tria_node_ids[i]=iomodel->nodecounter+reCast<int,IssmDouble>(*(iomodel->Data(MeshElementsEnum)+3*index+i)); //ids for vertices are in the elements array from Matlab
+		}
+	}
+
+	/*hooks: */
+	this->SetHookNodes(tria_node_ids,analysis_counter); this->nodes=NULL; //set hook to nodes, for this analysis type
+
+	/*Fill with IoModel*/
+	this->InputUpdateFromIoModel(index,iomodel);
+
+	/*Defaults if not provided in iomodel*/
+	switch(analysis_type){
+
+		case DiagnosticHorizAnalysisEnum:
+
+			/*default vx,vy and vz: either observation or 0 */
+			if(!iomodel->Data(VxEnum)){
+				for(i=0;i<3;i++)nodeinputs[i]=0;
+				this->inputs->AddInput(new TriaP1Input(VxEnum,nodeinputs));
+				if(dakota_analysis) this->inputs->AddInput(new TriaP1Input(QmuVxEnum,nodeinputs));
+			}
+			if(!iomodel->Data(VyEnum)){
+				for(i=0;i<3;i++)nodeinputs[i]=0;
+				this->inputs->AddInput(new TriaP1Input(VyEnum,nodeinputs));
+				if(dakota_analysis) this->inputs->AddInput(new TriaP1Input(QmuVyEnum,nodeinputs));
+			}
+			if(!iomodel->Data(VzEnum)){
+				for(i=0;i<3;i++)nodeinputs[i]=0;
+				this->inputs->AddInput(new TriaP1Input(VzEnum,nodeinputs));
+				if(dakota_analysis) this->inputs->AddInput(new TriaP1Input(QmuVzEnum,nodeinputs));
+			}
+			if(!iomodel->Data(PressureEnum)){
+				for(i=0;i<3;i++)nodeinputs[i]=0;
+				if(dakota_analysis){
+					this->inputs->AddInput(new TriaP1Input(PressureEnum,nodeinputs));
+					this->inputs->AddInput(new TriaP1Input(QmuPressureEnum,nodeinputs));
+				}
+			}
+			break;
+
+		default:
+			/*No update for other solution types*/
+			break;
+
+	}
+
+	//this->parameters: we still can't point to it, it may not even exist. Configure will handle this.
+	this->parameters=NULL;
+}
+/*}}}*/
+/*FUNCTION Tria::UpdatePotentialUngrounding{{{*/
+int Tria::UpdatePotentialUngrounding(IssmDouble* vertices_potentially_ungrounding,Vector<IssmDouble>* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf){
+
+	int i;
+	int nflipped=0;
+
+	/*Go through nodes, and whoever is on the potential_ungrounding, ends up in nodes_on_iceshelf: */
+	for(i=0;i<3;i++){
+		if (reCast<bool>(vertices_potentially_ungrounding[nodes[i]->Sid()])){
+			vec_nodes_on_iceshelf->SetValue(nodes[i]->Sid(),1,INS_VAL);
+
+			/*If node was not on ice shelf, we flipped*/
+			if(nodes_on_iceshelf[nodes[i]->Sid()]==0){
+				nflipped++;
+			}
+		}
+	}
+	return nflipped;
+}
+/*}}}*/
+
+#ifdef _HAVE_RESPONSES_
+/*FUNCTION Tria::IceVolume {{{*/
+IssmDouble Tria::IceVolume(void){
+
+	/*The volume of a troncated prism is base * 1/3 sum(length of edges)*/
+	IssmDouble base,surface,bed;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	if(IsOnWater())return 0;
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*First calculate the area of the base (cross section triangle)
+	 * http://en.wikipedia.org/wiki/Triangle
+	 * base = 1/2 abs((xA-xC)(yB-yA)-(xA-xB)(yC-yA))*/
+	base = 1./2. * fabs((xyz_list[0][0]-xyz_list[2][0])*(xyz_list[1][1]-xyz_list[0][1]) - (xyz_list[0][0]-xyz_list[1][0])*(xyz_list[2][1]-xyz_list[0][1]));
+
+	/*Now get the average height*/
+	Input* surface_input = inputs->GetInput(SurfaceEnum); _assert_(surface_input);
+	Input* bed_input     = inputs->GetInput(BedEnum);     _assert_(bed_input);
+	surface_input->GetInputAverage(&surface);
+	bed_input->GetInputAverage(&bed);
+
+	/*Return: */
+	return base*(surface-bed);
+}
+/*}}}*/
+/*FUNCTION Tria::MassFlux {{{*/
+IssmDouble Tria::MassFlux( IssmDouble* segment,bool process_units){
+
+	const int  numdofs=2;
+	int        dim;
+	IssmDouble mass_flux=0;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble normal[2];
+	IssmDouble length,rho_ice;
+	IssmDouble x1,y1,x2,y2,h1,h2;
+	IssmDouble 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 (reCast<int>(*(segment+4))!=this->id)_error_("error message: segment with id " << reCast<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],vertices,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)+pow(y2-y1,2));
+
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+	this->parameters->FindParam(&dim,MeshDimensionEnum);
+	Input* vx_input=NULL;
+	Input* vy_input=NULL;
+	if(dim==2){
+		vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+		vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+	}
+	else{
+		vx_input=inputs->GetInput(VxAverageEnum); _assert_(vx_input);
+		vy_input=inputs->GetInput(VyAverageEnum); _assert_(vy_input);
+	}
+
+	thickness_input->GetInputValue(&h1, gauss_1);
+	thickness_input->GetInputValue(&h2, gauss_2);
+	vx_input->GetInputValue(&vx1,gauss_1);
+	vx_input->GetInputValue(&vx2,gauss_2);
+	vy_input->GetInputValue(&vy1,gauss_1);
+	vy_input->GetInputValue(&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);
+
+	/*clean up and return:*/
+	delete gauss_1;
+	delete gauss_2;
+	return mass_flux;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxAbsVx{{{*/
+void  Tria::MaxAbsVx(IssmDouble* pmaxabsvx, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxabsvx=this->inputs->MaxAbs(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvx=UnitConversion(maxabsvx,IuToExtEnum,VxEnum);
+
+	/*Assign output pointers:*/
+	*pmaxabsvx=maxabsvx;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxAbsVy{{{*/
+void  Tria::MaxAbsVy(IssmDouble* pmaxabsvy, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxabsvy=this->inputs->MaxAbs(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvy=UnitConversion(maxabsvy,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pmaxabsvy=maxabsvy;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxAbsVz{{{*/
+void  Tria::MaxAbsVz(IssmDouble* pmaxabsvz, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxabsvz=this->inputs->MaxAbs(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) maxabsvz=UnitConversion(maxabsvz,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pmaxabsvz=maxabsvz;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVel{{{*/
+void  Tria::MaxVel(IssmDouble* pmaxvel, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvel=this->inputs->Max(VelEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvel=UnitConversion(maxvel,IuToExtEnum,VelEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvel=maxvel;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVx{{{*/
+void  Tria::MaxVx(IssmDouble* pmaxvx, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvx=this->inputs->Max(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvx=UnitConversion(maxvx,IuToExtEnum,VxEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvx=maxvx;
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVy{{{*/
+void  Tria::MaxVy(IssmDouble* pmaxvy, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvy=this->inputs->Max(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvy=UnitConversion(maxvy,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvy=maxvy;
+
+}
+/*}}}*/
+/*FUNCTION Tria::MaxVz{{{*/
+void  Tria::MaxVz(IssmDouble* pmaxvz, bool process_units){
+
+	/*Get maximum:*/
+	IssmDouble maxvz=this->inputs->Max(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) maxvz=UnitConversion(maxvz,IuToExtEnum,VzEnum);
+
+	/*Assign output pointers:*/
+	*pmaxvz=maxvz;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVel{{{*/
+void  Tria::MinVel(IssmDouble* pminvel, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvel=this->inputs->Min(VelEnum);
+
+	/*process units if requested: */
+	if(process_units) minvel=UnitConversion(minvel,IuToExtEnum,VelEnum);
+
+	/*Assign output pointers:*/
+	*pminvel=minvel;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVx{{{*/
+void  Tria::MinVx(IssmDouble* pminvx, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvx=this->inputs->Min(VxEnum);
+
+	/*process units if requested: */
+	if(process_units) minvx=UnitConversion(minvx,IuToExtEnum,VxEnum);
+
+	/*Assign output pointers:*/
+	*pminvx=minvx;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVy{{{*/
+void  Tria::MinVy(IssmDouble* pminvy, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvy=this->inputs->Min(VyEnum);
+
+	/*process units if requested: */
+	if(process_units) minvy=UnitConversion(minvy,IuToExtEnum,VyEnum);
+
+	/*Assign output pointers:*/
+	*pminvy=minvy;
+}
+/*}}}*/
+/*FUNCTION Tria::MinVz{{{*/
+void  Tria::MinVz(IssmDouble* pminvz, bool process_units){
+
+	/*Get minimum:*/
+	IssmDouble minvz=this->inputs->Min(VzEnum);
+
+	/*process units if requested: */
+	if(process_units) minvz=UnitConversion(minvz,IuToExtEnum,VzEnum);
+
+	/*Assign output pointers:*/
+	*pminvz=minvz;
+}
+/*}}}*/
+/*FUNCTION Tria::ElementResponse{{{*/
+void Tria::ElementResponse(IssmDouble* presponse,int response_enum,bool process_units){
+
+	switch(response_enum){
+		case MaterialsRheologyBbarEnum:
+			*presponse=this->material->GetBbar();
+			break;
+		case MaterialsRheologyZbarEnum:
+			*presponse=this->material->GetZbar();
+			break;
+		case VelEnum:{
+
+			/*Get input:*/
+			IssmDouble vel;
+			Input* vel_input;
+
+			vel_input=this->inputs->GetInput(VelEnum); _assert_(vel_input);
+			vel_input->GetInputAverage(&vel);
+
+			/*process units if requested: */
+			if(process_units) vel=UnitConversion(vel,IuToExtEnum,VelEnum);
+
+			/*Assign output pointers:*/
+			*presponse=vel;}
+			break;
+		default:  
+			_error_("Response type " << EnumToStringx(response_enum) << " not supported yet!");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::TotalSmb {{{*/
+IssmDouble Tria::TotalSmb(void){
+
+	/*The smb[kg yr-1] of one element is area[m2] * smb [kg m^-2 yr^-1]*/
+	IssmDouble base,smb,rho_ice;
+	IssmDouble Total_Smb=0;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	/*Get material parameters :*/
+	rho_ice=matpar->GetRhoIce();
+
+   if(IsOnWater())return 0;
+
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*First calculate the area of the base (cross section triangle)
+	 * http://en.wikipedia.org/wiki/Triangle
+	 * base = 1/2 abs((xA-xC)(yB-yA)-(xA-xB)(yC-yA))*/
+	base = 1./2. * fabs((xyz_list[0][0]-xyz_list[2][0])*(xyz_list[1][1]-xyz_list[0][1]) - (xyz_list[0][0]-xyz_list[1][0])*(xyz_list[2][1]-xyz_list[0][1]));	// area of element in m2
+
+	/*Now get the average SMB over the element*/
+	Input* smb_input = inputs->GetInput(SurfaceforcingsMassBalanceEnum); _assert_(smb_input);
+	smb_input->GetInputAverage(&smb);																								// average smb on element in m ice s-1
+   Total_Smb=rho_ice*base*smb;																											// smb on element in kg s-1
+
+	/*Process units: */
+	Total_Smb=UnitConversion(Total_Smb,IuToExtEnum,TotalSmbEnum);																// smb on element in GigaTon yr-1
+
+	/*Return: */
+	return Total_Smb;
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_GIA_
+/*FUNCTION Tria::GiaDeflection {{{*/
+void Tria::GiaDeflection(Vector<IssmDouble>* wg,Vector<IssmDouble>* dwgdt,IssmDouble* x, IssmDouble* y){
+
+	int i;
+	int gsize;
+	IssmDouble xi,yi,ri,re,area;
+	IssmDouble x0,y0;
+	IssmDouble xyz_list[NUMVERTICES][3];
+
+	/*thickness averages: */
+	IssmDouble* hes=NULL;
+	IssmDouble* times=NULL;
+	IssmDouble  currenttime;
+	int         numtimes;
+	Input* thickness_input=NULL;
+
+	/*gia solution parameters:*/
+	int output_rates=0;
+	int cross_section_shape=0;
+
+	/*gia material parameters: */
+	IssmDouble lithosphere_shear_modulus;
+	IssmDouble lithosphere_density;
+	IssmDouble mantle_shear_modulus;
+	IssmDouble mantle_density;
+	Input* mantle_viscosity_input=NULL;
+	IssmDouble mantle_viscosity;
+	Input* lithosphere_thickness_input=NULL;
+	IssmDouble lithosphere_thickness;
+
+	/*ice properties: */
+	IssmDouble rho_ice;
+
+	/*constants: */
+	IssmDouble yts;
+
+	/*output: */
+	IssmDouble  wi;
+	IssmDouble  dwidt;
+
+	/*arguments to GiaDeflectionCorex: */
+	GiaDeflectionCoreArgs arguments;
+
+	/*how many dofs are we working with here? */
+	this->parameters->FindParam(&gsize,MeshNumberofverticesEnum);
+	this->parameters->FindParam(&yts,ConstantsYtsEnum);
+
+	/*recover gia solution parameters: */
+	this->parameters->FindParam(&output_rates,GiaOutputRatesEnum);
+	this->parameters->FindParam(&cross_section_shape,GiaCrossSectionShapeEnum);
+
+	/*what time is it? :*/
+	this->parameters->FindParam(&currenttime,TimeEnum);
+
+	/*recover material parameters: */
+	lithosphere_shear_modulus=matpar->GetLithosphereShearModulus();
+	lithosphere_density=matpar->GetLithosphereDensity();
+	mantle_shear_modulus=matpar->GetMantleShearModulus();
+	mantle_density=matpar->GetMantleDensity();
+	rho_ice=matpar->GetRhoIce();
+
+	/*pull thickness averages: */
+	thickness_input=inputs->GetInput(ThicknessEnum); 
+	if (!thickness_input)_error_("thickness input needed to compute gia deflection!");
+	thickness_input->GetInputUpToCurrentTimeAverages(&hes,&times,&numtimes,currenttime);
+
+	/*recover mantle viscosity: */
+	mantle_viscosity_input=inputs->GetInput(GiaMantleViscosityEnum);
+	if (!mantle_viscosity_input)_error_("mantle viscosity input needed to compute gia deflection!");
+	mantle_viscosity_input->GetInputAverage(&mantle_viscosity);
+
+	/*recover lithosphere thickness: */
+	lithosphere_thickness_input=inputs->GetInput(GiaLithosphereThicknessEnum);
+	if (!lithosphere_thickness_input)_error_("lithosphere thickness input needed to compute gia deflection!");
+	lithosphere_thickness_input->GetInputAverage(&lithosphere_thickness);
+
+	/*pull area of this Tria: */
+	area=this->GetArea();
+
+	/*element radius: */
+	re=sqrt(area/PI);
+
+	/*figure out gravity center of our element: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	x0=(xyz_list[0][0]+xyz_list[1][0]+xyz_list[2][0])/3.0;
+	y0=(xyz_list[0][1]+xyz_list[1][1]+xyz_list[2][1])/3.0;
+
+	/*start loading GiaDeflectionCore arguments: */
+	arguments.re=re;
+	arguments.hes=hes;
+	arguments.times=times;
+	arguments.numtimes=numtimes;
+	arguments.currenttime=currenttime;
+	arguments.lithosphere_shear_modulus=lithosphere_shear_modulus;
+	arguments.lithosphere_density=lithosphere_density;
+	arguments.mantle_shear_modulus=mantle_shear_modulus;
+	arguments.mantle_viscosity=mantle_viscosity;
+	arguments.mantle_density=mantle_density;
+	arguments.lithosphere_thickness=lithosphere_thickness;
+	arguments.rho_ice=rho_ice;
+	arguments.idisk=this->id;
+	arguments.irate=output_rates;
+	arguments.iedge=cross_section_shape;
+	arguments.yts=yts;
+
+	for(i=0;i<gsize;i++){
+		/*compute distance from the center of the tria to the vertex i: */
+		xi=x[i]; yi=y[i];
+		ri=sqrt(pow(xi-x0,2)+pow(yi-y0,2));
+
+		/*load ri onto arguments for this vertex i: */
+		arguments.ri=ri;
+
+		/*for this Tria, compute contribution to rebound at vertex i: */
+		GiaDeflectionCorex(&wi,&dwidt,&arguments);
+
+		/*plug value into solution vector: */
+		wg->SetValue(i,wi,ADD_VAL);
+		dwgdt->SetValue(i,dwidt,ADD_VAL);
+
+	}
+
+	/*Free ressources: */
+	xDelete<IssmDouble>(hes);
+	xDelete<IssmDouble>(times);
+
+	return;
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_DIAGNOSTIC_
+/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyeal {{{*/
+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{{{*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealViscous(void){
+
+	/*Constants*/
+	const int  numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble viscosity,newviscosity,oldviscosity;
+	IssmDouble viscosity_overshoot,thickness,Jdet;
+	IssmDouble epsilon[3],oldepsilon[3];    /* epsilon=[exx,eyy,exy];    */
+	IssmDouble B[3][numdof];
+	IssmDouble Bprime[3][numdof];
+	IssmDouble D[3][3]   = {0.0};
+	IssmDouble D_scalar;
+	GaussTria *gauss = NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+	Input* vx_input=inputs->GetInput(VxEnum);               _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);               _assert_(vy_input);
+	Input* vxold_input=inputs->GetInput(VxPicardEnum);      _assert_(vxold_input);
+	Input* vyold_input=inputs->GetInput(VyPicardEnum);      _assert_(vyold_input);
+	this->parameters->FindParam(&viscosity_overshoot,DiagnosticViscosityOvershootEnum);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&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);
+		material->GetViscosity2d(&viscosity, &epsilon[0]);
+		material->GetViscosity2d(&oldviscosity, &oldepsilon[0]);
+		thickness_input->GetInputValue(&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->values[0],1);
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticMacAyealFriction {{{*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticMacAyealFriction(void){
+
+	/*Constants*/
+	const int  numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,j;
+	int        analysis_type,migration_style;
+	int        gausspoints=2;
+	IssmDouble MAXSLOPE  = .06; // 6 %
+	IssmDouble MOUNTAINKEXPONENT = 10;
+	IssmDouble slope_magnitude,alpha2;
+	IssmDouble Jdet;
+	IssmDouble phi=1.0;
+	IssmDouble L[2][numdof];
+	IssmDouble DL[2][2]  = {{ 0,0 },{0,0}};
+	IssmDouble DL_scalar;
+	IssmDouble slope[2]  = {0.0,0.0};
+	IssmDouble gllevelset;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	Friction  *friction = NULL;
+	GaussTria *gauss    = NULL;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(IsFloating()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&migration_style,GroundinglineMigrationEnum);
+	Input* surface_input=inputs->GetInput(SurfaceEnum);       _assert_(surface_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                 _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                 _assert_(vy_input);
+	Input* vz_input=inputs->GetInput(VzEnum);                 _assert_(vz_input);
+	Input* gllevelset_input=NULL;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*build friction object, used later on: */
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/*Recover portion of element that is grounded*/
+	if(migration_style==SubelementMigrationEnum) phi=this->GetGroundedPortion(&xyz_list[0][0]);
+	if(migration_style==SubelementMigration2Enum){
+		gllevelset_input=inputs->GetInput(GLlevelsetEnum); _assert_(gllevelset_input);
+		gausspoints=20;
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(gausspoints);
+	for(int 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->GetInputDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		slope_magnitude=sqrt(slope[0]*slope[0]+slope[1]*slope[1]);
+		if(slope_magnitude>MAXSLOPE) alpha2=pow((IssmDouble)10,MOUNTAINKEXPONENT);
+		else friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
+		if(migration_style==SubelementMigrationEnum) alpha2=phi*alpha2;
+		if(migration_style==SubelementMigration2Enum){
+			gllevelset_input->GetInputValue(&gllevelset, gauss);
+			if(gllevelset<0) alpha2=0;
+		}
+
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
+		GetJacobianDeterminant(&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->values[0],1);
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixDiagnosticHutter{{{*/
+ElementMatrix* Tria::CreateKMatrixDiagnosticHutter(void){
+
+	/*Intermediaries*/
+	const int numdof=NUMVERTICES*NDOF2;
+	int    i,connectivity;
+
+	/*Initialize Element matrix*/
+	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/(IssmDouble)connectivity;
+		Ke->values[(2*i+1)*numdof+(2*i+1)]=1/(IssmDouble)connectivity;
+	}
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorDiagnosticMacAyeal {{{*/
+ElementVector* Tria::CreatePVectorDiagnosticMacAyeal(){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int            i,j;
+	IssmDouble     driving_stress_baseline,thickness;
+	IssmDouble     Jdet;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     slope[2];
+	IssmDouble     basis[3];
+	IssmDouble     pe_g_gaussian[numdof];
+	GaussTria*     gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input); 
+	Input* surface_input=inputs->GetInput(SurfaceEnum);     _assert_(surface_input);
+	Input* drag_input=inputs->GetInput(FrictionCoefficientEnum);_assert_(drag_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		thickness_input->GetInputValue(&thickness,gauss);
+		surface_input->GetInputDerivativeValue(&slope[0],&xyz_list[0][0],gauss);
+		driving_stress_baseline=matpar->GetRhoIce()*matpar->GetG()*thickness;
+
+		/*Build pe_g_gaussian vector: */
+		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*basis[i];
+			}
+		}
+	}
+
+	/*Transform coordinate system*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorDiagnosticHutter{{{*/
+ElementVector* Tria::CreatePVectorDiagnosticHutter(void){
+
+	/*Intermediaries */
+	int        i,connectivity;
+	IssmDouble     constant_part,ub,vb;
+	IssmDouble     rho_ice,gravity,n,B;
+	IssmDouble     slope2,thickness;
+	IssmDouble     slope[2];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	n=material->GetN();
+	B=material->GetBbar();
+	Input* slopex_input=inputs->GetInput(SurfaceSlopeXEnum); _assert_(slopex_input);
+	Input* slopey_input=inputs->GetInput(SurfaceSlopeYEnum); _assert_(slopey_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);  _assert_(thickness_input);
+
+	/*Spawn 3 sing elements: */
+	gauss=new GaussTria();
+	for(i=0;i<NUMVERTICES;i++){
+
+		gauss->GaussVertex(i);
+
+		connectivity=nodes[i]->GetConnectivity();
+
+		thickness_input->GetInputValue(&thickness,gauss);
+		slopex_input->GetInputValue(&slope[0],gauss);
+		slopey_input->GetInputValue(&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((IssmDouble)10.0,(IssmDouble)-10.0)*rho_ice*gravity*thickness*slope[0];
+		vb=-1.58*pow((IssmDouble)10.0,(IssmDouble)-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])/(IssmDouble)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])/(IssmDouble)connectivity;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateJacobianDiagnosticMacayeal{{{*/
+ElementMatrix* Tria::CreateJacobianDiagnosticMacayeal(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet,thickness;
+	IssmDouble eps1dotdphii,eps1dotdphij;
+	IssmDouble eps2dotdphii,eps2dotdphij;
+	IssmDouble mu_prime;
+	IssmDouble epsilon[3];/* epsilon=[exx,eyy,exy];*/
+	IssmDouble eps1[2],eps2[2];
+	IssmDouble phi[NUMVERTICES];
+	IssmDouble dphi[2][NUMVERTICES];
+	GaussTria *gauss=NULL;
+
+	/*Initialize Jacobian with regular MacAyeal (first part of the Gateau derivative)*/
+	ElementMatrix* Ke=CreateKMatrixDiagnosticMacAyeal();
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsDerivatives(&dphi[0][0],&xyz_list[0][0],gauss);
+
+		thickness_input->GetInputValue(&thickness, gauss);
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosity2dDerivativeEpsSquare(&mu_prime,&epsilon[0]);
+		eps1[0]=2*epsilon[0]+epsilon[1];   eps2[0]=epsilon[2];
+		eps1[1]=epsilon[2];                eps2[1]=epsilon[0]+2*epsilon[1];
+
+		for(i=0;i<3;i++){
+			for(j=0;j<3;j++){
+				eps1dotdphii=eps1[0]*dphi[0][i]+eps1[1]*dphi[1][i];
+				eps1dotdphij=eps1[0]*dphi[0][j]+eps1[1]*dphi[1][j];
+				eps2dotdphii=eps2[0]*dphi[0][i]+eps2[1]*dphi[1][i];
+				eps2dotdphij=eps2[0]*dphi[0][j]+eps2[1]*dphi[1][j];
+
+				Ke->values[6*(2*i+0)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*thickness*eps1dotdphij*eps1dotdphii;
+				Ke->values[6*(2*i+0)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*thickness*eps2dotdphij*eps1dotdphii;
+				Ke->values[6*(2*i+1)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*thickness*eps1dotdphij*eps2dotdphii;
+				Ke->values[6*(2*i+1)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*thickness*eps2dotdphij*eps2dotdphii;
+			}
+		}
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHoriz{{{*/
+void  Tria::GetSolutionFromInputsDiagnosticHoriz(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int          i;
+	int*         doflist=NULL;
+	IssmDouble       vx,vy;
+	IssmDouble       values[numdof];
+	GaussTria*   gauss=NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get inputs*/
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(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->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputsDiagnosticHutter{{{*/
+void  Tria::GetSolutionFromInputsDiagnosticHutter(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int        i;
+	IssmDouble     vx,vy;
+	IssmDouble     values[numdof];
+	int       *doflist = NULL;
+	GaussTria *gauss   = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get inputs*/
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(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->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		values[i*NDOF2+0]=vx;
+		values[i*NDOF2+1]=vy;
+	}
+
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHoriz {{{*/
+void  Tria::InputUpdateFromSolutionDiagnosticHoriz(IssmDouble* solution){
+
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	IssmDouble    rho_ice,g;
+	IssmDouble    values[numdof];
+	IssmDouble    vx[NUMVERTICES];
+	IssmDouble    vy[NUMVERTICES];
+	IssmDouble    vz[NUMVERTICES];
+	IssmDouble    vel[NUMVERTICES];
+	IssmDouble    pressure[NUMVERTICES];
+	IssmDouble    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]];
+
+	/*Transform solution in Cartesian Space*/
+	TransformSolutionCoord(&values[0],nodes,NUMVERTICES,XYEnum);
+
+	/*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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Get Vz and compute vel*/
+	GetInputListOnVertices(&vz[0],VzEnum,0);
+	for(i=0;i<NUMVERTICES;i++) vel[i]=sqrt(vx[i]*vx[i] + vy[i]*vy[i] + vz[i]*vz[i]);
+
+	/*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();
+	GetInputListOnVertices(&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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new TriaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new TriaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new TriaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionDiagnosticHutter {{{*/
+void  Tria::InputUpdateFromSolutionDiagnosticHutter(IssmDouble* solution){
+
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	IssmDouble    rho_ice,g;
+	IssmDouble    values[numdof];
+	IssmDouble    vx[NUMVERTICES];
+	IssmDouble    vy[NUMVERTICES];
+	IssmDouble    vz[NUMVERTICES];
+	IssmDouble    vel[NUMVERTICES];
+	IssmDouble    pressure[NUMVERTICES];
+	IssmDouble    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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Now Compute vel*/
+	GetInputListOnVertices(&vz[0],VzEnum,0.0); //default is 0
+	for(i=0;i<NUMVERTICES;i++) vel[i]=sqrt(vx[i]*vx[i] + vy[i]*vy[i] + vz[i]*vz[i]);
+
+	/*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();
+	GetInputListOnVertices(&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,VxPicardEnum);
+	this->inputs->ChangeEnum(VyEnum,VyPicardEnum);
+	this->inputs->ChangeEnum(PressureEnum,PressurePicardEnum);
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaP1Input(VxEnum,vx));
+	this->inputs->AddInput(new TriaP1Input(VyEnum,vy));
+	this->inputs->AddInput(new TriaP1Input(VelEnum,vel));
+	this->inputs->AddInput(new TriaP1Input(PressureEnum,pressure));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_CONTROL_
+/*FUNCTION Tria::BalancethicknessMisfit{{{*/
+IssmDouble Tria::BalancethicknessMisfit(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	IssmDouble Jelem = 0;
+	IssmDouble weight;
+	IssmDouble Jdet,temp;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dH[2];
+	IssmDouble vx,vy,H;
+	IssmDouble dvx[2],dvy[2];
+	IssmDouble dhdt,basal_melting,surface_mass_balance;
+	GaussTria *gauss = NULL;
+
+	/*If on water, return 0: */
+	if(IsOnWater()) return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* weights_input              = inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* thickness_input            = inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+	Input* vx_input                   = inputs->GetInput(VxEnum);                                 _assert_(vx_input);
+	Input* vy_input                   = inputs->GetInput(VyEnum);                                 _assert_(vy_input);
+	Input* surface_mass_balance_input = inputs->GetInput(SurfaceforcingsMassBalanceEnum);         _assert_(surface_mass_balance_input);
+	Input* basal_melting_input        = inputs->GetInput(BasalforcingsMeltingRateEnum);           _assert_(basal_melting_input);
+	Input* dhdt_input                 = inputs->GetInput(BalancethicknessThickeningRateEnum);     _assert_(dhdt_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		thickness_input->GetInputValue(&H, gauss);
+		thickness_input->GetInputDerivativeValue(&dH[0],&xyz_list[0][0],gauss);
+		surface_mass_balance_input->GetInputValue(&surface_mass_balance,gauss);
+		basal_melting_input->GetInputValue(&basal_melting,gauss);
+		dhdt_input->GetInputValue(&dhdt,gauss);
+		vx_input->GetInputValue(&vx,gauss);
+		vx_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vy_input->GetInputDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+
+		/*Weak balance thickness J = 1/2 (div(Hv)-a)^2*/
+		temp  = vx*dH[0]+vy*dH[1]+H*(dvx[0]+dvy[1]) - (surface_mass_balance-basal_melting-dhdt);
+		Jelem+=weight*1/2*temp*temp*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::InputControlUpdate{{{*/
+void  Tria::InputControlUpdate(IssmDouble scalar,bool save_parameter){
+
+	/*Intermediary*/
+	int    num_controls;
+	int*   control_type=NULL;
+	Input* input=NULL;
+
+	/*retrieve some parameters: */
+	this->parameters->FindParam(&num_controls,InversionNumControlParametersEnum);
+	this->parameters->FindParam(&control_type,NULL,InversionControlParametersEnum);
+
+	for(int i=0;i<num_controls;i++){
+
+		if(control_type[i]==MaterialsRheologyBbarEnum || control_type[i]==MaterialsRheologyZbarEnum){
+			input=(Input*)material->inputs->GetInput(control_type[i]); _assert_(input);
+		}
+		else{
+			input=(Input*)this->inputs->GetInput(control_type[i]);   _assert_(input);
+		}
+
+		if (input->ObjectEnum()!=ControlInputEnum){
+			_error_("input " << EnumToStringx(control_type[i]) << " is not a ControlInput");
+		}
+
+		((ControlInput*)input)->UpdateValue(scalar);
+		((ControlInput*)input)->Constrain();
+		if (save_parameter) ((ControlInput*)input)->SaveValue();
+
+	}
+
+	/*Clean up and return*/
+	xDelete<int>(control_type);
+}
+/*}}}*/
+/*FUNCTION Tria::ControlInputGetGradient{{{*/
+void Tria::ControlInputGetGradient(Vector<IssmDouble>* gradient,int enum_type,int control_index){
+
+	int vertexpidlist[NUMVERTICES];
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum || enum_type==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&vertexpidlist[0],control_index);
+	((ControlInput*)input)->GetGradient(gradient,&vertexpidlist[0]);
+
+}/*}}}*/
+/*FUNCTION Tria::ControlInputScaleGradient{{{*/
+void Tria::ControlInputScaleGradient(int enum_type,IssmDouble scale){
+
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum || enum_type==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	((ControlInput*)input)->ScaleGradient(scale);
+}/*}}}*/
+/*FUNCTION Tria::ControlInputSetGradient{{{*/
+void Tria::ControlInputSetGradient(IssmDouble* gradient,int enum_type,int control_index){
+
+	int    vertexpidlist[NUMVERTICES];
+	IssmDouble grad_list[NUMVERTICES];
+	Input* grad_input=NULL;
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum || enum_type==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&vertexpidlist[0],control_index);
+	for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[vertexpidlist[i]];
+	grad_input=new TriaP1Input(GradientEnum,grad_list);
+
+	((ControlInput*)input)->SetGradient(grad_input);
+
+}/*}}}*/
+/*FUNCTION Tria::Gradj {{{*/
+void  Tria::Gradj(Vector<IssmDouble>* gradient,int control_type,int control_index){
+	/*dJ/dalpha = ∂L/∂alpha = ∂J/∂alpha + ∂/∂alpha(KU-F)*/
+
+	/*If on water, grad = 0: */
+	if(IsOnWater()) return;
+
+	/*First deal with ∂/∂alpha(KU-F)*/
+	switch(control_type){
+		case FrictionCoefficientEnum:
+			GradjDragMacAyeal(gradient,control_index);
+			break;
+		case MaterialsRheologyBbarEnum:
+			GradjBMacAyeal(gradient,control_index);
+			break;
+		case MaterialsRheologyZbarEnum:
+			GradjZMacAyeal(gradient,control_index);
+			break;
+		case BalancethicknessThickeningRateEnum:
+			GradjDhDtBalancedthickness(gradient,control_index);
+			break;
+		case VxEnum:
+			GradjVxBalancedthickness(gradient,control_index);
+			break;
+		case VyEnum:
+			GradjVyBalancedthickness(gradient,control_index);
+			break;
+		case ThicknessEnum:
+			GradjThicknessWeakBalancedthickness(gradient,control_index);
+			break;
+		default:
+			_error_("control type not supported yet: " << control_type);
+	}
+
+	/*Now deal with ∂J/∂alpha*/
+	int        *responses = NULL;
+	int         num_responses,resp;
+	this->parameters->FindParam(&num_responses,InversionNumCostFunctionsEnum);
+	this->parameters->FindParam(&responses,NULL,NULL,StepResponsesEnum);
+
+	for(resp=0;resp<num_responses;resp++) switch(responses[resp]){
+		//FIXME: the control type should be checked somewhere (with respect to what variable are we taking the gradient!)
+
+		case ThicknessAbsMisfitEnum:
+		case ThicknessAbsGradientEnum:
+		case ThicknessAlongGradientEnum:
+		case ThicknessAcrossGradientEnum:
+		case BalancethicknessMisfitEnum:
+		case SurfaceAbsVelMisfitEnum:
+		case SurfaceRelVelMisfitEnum:
+		case SurfaceLogVelMisfitEnum:
+		case SurfaceLogVxVyMisfitEnum:
+		case SurfaceAverageVelMisfitEnum:
+			/*Nothing, J does not depends on the parameter being inverted for*/
+			break;
+		case DragCoefficientAbsGradientEnum:
+			GradjDragGradient(gradient,resp,control_index);
+			break;
+		case RheologyBbarAbsGradientEnum:
+			GradjBGradient(gradient,resp,control_index);
+			break;
+		default:
+			_error_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+	}
+
+	xDelete<int>(responses);
+}
+/*}}}*/
+/*FUNCTION Tria::GradjBGradient{{{*/
+void  Tria::GradjBGradient(Vector<IssmDouble>* gradient,int weight_index,int control_index){
+
+	int        i;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble Jdet,weight;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dbasis[NDOF2][NUMVERTICES];
+	IssmDouble dk[NDOF2]; 
+	IssmDouble grade_g[NUMVERTICES]={0.0};
+	GaussTria  *gauss=NULL;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+	Input* rheologyb_input=material->inputs->GetInput(MaterialsRheologyBbarEnum); _assert_(rheologyb_input);
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);                _assert_(weights_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+
+		/*Build alpha_complement_list: */
+		rheologyb_input->GetInputDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++) grade_g[i]+=-weight*Jdet*gauss->weight*(dbasis[0][i]*dk[0]+dbasis[1][i]*dk[1]);
+	}
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjZGradient{{{*/
+void  Tria::GradjZGradient(Vector<IssmDouble>* gradient,int weight_index,int control_index){
+
+	int        i;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble Jdet,weight;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dbasis[NDOF2][NUMVERTICES];
+	IssmDouble dk[NDOF2]; 
+	IssmDouble grade_g[NUMVERTICES]={0.0};
+	GaussTria  *gauss=NULL;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+	Input* rheologyz_input=material->inputs->GetInput(MaterialsRheologyZbarEnum); _assert_(rheologyz_input);
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);                _assert_(weights_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+
+		/*Build alpha_complement_list: */
+		rheologyz_input->GetInputDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++) grade_g[i]+=-weight*Jdet*gauss->weight*(dbasis[0][i]*dk[0]+dbasis[1][i]*dk[1]);
+	}
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjBMacAyeal{{{*/
+void  Tria::GradjBMacAyeal(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i;
+	int        doflist[NUMVERTICES];
+	IssmDouble vx,vy,lambda,mu,thickness,Jdet;
+	IssmDouble viscosity_complement;
+	IssmDouble dvx[NDOF2],dvy[NDOF2],dadjx[NDOF2],dadjy[NDOF2],dB[NDOF2]; 
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble basis[3],epsilon[3];
+	IssmDouble grad[NUMVERTICES]={0.0};
+	GaussTria *gauss = NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&doflist[0],control_index);
+
+	/*Retrieve all inputs*/
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);                     _assert_(thickness_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                                   _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                                   _assert_(vy_input);
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);                       _assert_(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);                       _assert_(adjointy_input);
+	Input* rheologyb_input=material->inputs->GetInput(MaterialsRheologyBbarEnum); _assert_(rheologyb_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		thickness_input->GetInputValue(&thickness,gauss);
+		rheologyb_input->GetInputDerivativeValue(&dB[0],&xyz_list[0][0],gauss);
+		vx_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vy_input->GetInputDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+		adjointx_input->GetInputDerivativeValue(&dadjx[0],&xyz_list[0][0],gauss);
+		adjointy_input->GetInputDerivativeValue(&dadjy[0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosityComplement(&viscosity_complement,&epsilon[0]);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis,gauss);
+
+		/*standard gradient dJ/dki*/
+		for (i=0;i<NUMVERTICES;i++) grad[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];
+	}
+
+	gradient->SetValues(NUMVERTICES,doflist,grad,ADD_VAL);
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjZMacAyeal{{{*/
+void  Tria::GradjZMacAyeal(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i;
+	int        doflist[NUMVERTICES];
+	IssmDouble vx,vy,lambda,mu,thickness,Jdet;
+	IssmDouble viscosity_complement;
+	IssmDouble dvx[NDOF2],dvy[NDOF2],dadjx[NDOF2],dadjy[NDOF2],dZ[NDOF2]; 
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble basis[3],epsilon[3];
+	IssmDouble grad[NUMVERTICES]={0.0};
+	GaussTria *gauss = NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&doflist[0],control_index);
+
+	/*Retrieve all inputs*/
+	Input* thickness_input=inputs->GetInput(ThicknessEnum);                     _assert_(thickness_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                                   _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                                   _assert_(vy_input);
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);                       _assert_(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);                       _assert_(adjointy_input);
+	Input* rheologyz_input=material->inputs->GetInput(MaterialsRheologyZbarEnum); _assert_(rheologyz_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		thickness_input->GetInputValue(&thickness,gauss);
+		rheologyz_input->GetInputDerivativeValue(&dZ[0],&xyz_list[0][0],gauss);
+		vx_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vy_input->GetInputDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+		adjointx_input->GetInputDerivativeValue(&dadjx[0],&xyz_list[0][0],gauss);
+		adjointy_input->GetInputDerivativeValue(&dadjy[0],&xyz_list[0][0],gauss);
+
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosityZComplement(&viscosity_complement,&epsilon[0]);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis,gauss);
+
+		/*standard gradient dJ/dki*/
+		for (i=0;i<NUMVERTICES;i++) grad[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];
+	}
+
+	gradient->SetValues(NUMVERTICES,doflist,grad,ADD_VAL);
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDragMacAyeal {{{*/
+void  Tria::GradjDragMacAyeal(Vector<IssmDouble>* gradient,int control_index){
+
+	int        i;
+	int        analysis_type;
+	int        vertexpidlist[NUMVERTICES];
+	int        connectivity[NUMVERTICES];
+	IssmDouble vx,vy,lambda,mu,alpha_complement,Jdet;
+	IssmDouble bed,thickness,Neff,drag;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dk[NDOF2]; 
+	IssmDouble grade_g[NUMVERTICES]={0.0};
+	IssmDouble grade_g_gaussian[NUMVERTICES];
+	IssmDouble basis[3];
+	IssmDouble epsilon[3]; /* epsilon=[exx,eyy,exy];*/
+	Friction*  friction=NULL;
+	GaussTria  *gauss=NULL;
+
+	if(IsFloating())return;
+
+	/*retrive parameters: */
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+	this->GetConnectivityList(&connectivity[0]);
+
+	/*Build frictoin element, needed later: */
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* adjointx_input=inputs->GetInput(AdjointxEnum);                   _assert_(adjointx_input);
+	Input* adjointy_input=inputs->GetInput(AdjointyEnum);                   _assert_(adjointy_input);
+	Input* vx_input=inputs->GetInput(VxEnum);                               _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);                               _assert_(vy_input);
+	Input* dragcoefficient_input=inputs->GetInput(FrictionCoefficientEnum); _assert_(dragcoefficient_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		/*Build alpha_complement_list: */
+		friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum,VzEnum);
+
+		dragcoefficient_input->GetInputValue(&drag, gauss);
+		adjointx_input->GetInputValue(&lambda, gauss);
+		adjointy_input->GetInputValue(&mu, gauss);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		dragcoefficient_input->GetInputDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++){
+			grade_g_gaussian[i]=-2*drag*alpha_complement*((lambda*vx+mu*vy))*Jdet*gauss->weight*basis[i];
+		}
+
+		/*Add gradje_g_gaussian vector to gradje_g: */
+		for(i=0;i<NUMVERTICES;i++){
+			_assert_(!xIsNan<IssmDouble>(grade_g[i]));
+			grade_g[i]+=grade_g_gaussian[i];
+		}
+	}
+	/*Analytical gradient*/
+	//delete gauss;
+	//gauss=new GaussTria();
+	//for (int iv=0;iv<NUMVERTICES;iv++){
+	//	gauss->GaussVertex(iv);
+	//	friction->GetAlphaComplement(&alpha_complement, gauss,VxEnum,VyEnum,VzEnum);
+	//	dragcoefficient_input->GetInputValue(&drag, gauss);
+	//	adjointx_input->GetInputValue(&lambda, gauss);
+	//	adjointy_input->GetInputValue(&mu, gauss);
+	//	vx_input->GetInputValue(&vx,gauss);
+	//	vy_input->GetInputValue(&vy,gauss);
+	//	grade_g[iv] = -2*1.e+7*drag*alpha_complement*(lambda*vx+mu*vy)/((IssmDouble)connectivity[iv]);
+	//}
+	/*End Analytical gradient*/
+
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDragGradient{{{*/
+void  Tria::GradjDragGradient(Vector<IssmDouble>* gradient, int weight_index,int control_index){
+
+	int        i;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble Jdet,weight;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dbasis[NDOF2][NUMVERTICES];
+	IssmDouble dk[NDOF2]; 
+	IssmDouble grade_g[NUMVERTICES]={0.0};
+	GaussTria  *gauss=NULL;
+
+	/*Retrieve all inputs we will be needing: */
+	if(IsFloating())return;
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+	Input* dragcoefficient_input=inputs->GetInput(FrictionCoefficientEnum); _assert_(dragcoefficient_input);
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);                 _assert_(weights_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+
+		/*Build alpha_complement_list: */
+		dragcoefficient_input->GetInputDerivativeValue(&dk[0],&xyz_list[0][0],gauss);
+
+		/*Build gradje_g_gaussian vector (actually -dJ/ddrag): */
+		for (i=0;i<NUMVERTICES;i++){
+			grade_g[i]+=-weight*Jdet*gauss->weight*(dbasis[0][i]*dk[0]+dbasis[1][i]*dk[1]);
+			_assert_(!xIsNan<IssmDouble>(grade_g[i]));
+		}
+	}
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDhDtBalancedthickness{{{*/
+void  Tria::GradjDhDtBalancedthickness(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Intermediaries*/
+	int    vertexpidlist[NUMVERTICES];
+	IssmDouble lambda[NUMVERTICES];
+	IssmDouble gradient_g[NUMVERTICES];
+
+	/*Compute Gradient*/
+	GradientIndexing(&vertexpidlist[0],control_index);
+	GetInputListOnVertices(&lambda[0],AdjointEnum);
+	for(int i=0;i<NUMVERTICES;i++) gradient_g[i]=-lambda[i];
+
+	gradient->SetValues(NUMVERTICES,vertexpidlist,gradient_g,INS_VAL);
+}
+/*}}}*/
+/*FUNCTION Tria::GradjVxBalancedthickness{{{*/
+void  Tria::GradjVxBalancedthickness(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble thickness,Jdet;
+	IssmDouble basis[3];
+	IssmDouble Dlambda[2],dp[2];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble grade_g[NUMVERTICES] = {0.0};
+	GaussTria *gauss                = NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* adjoint_input=inputs->GetInput(AdjointEnum);     _assert_(adjoint_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		adjoint_input->GetInputDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
+		thickness_input->GetInputValue(&thickness, gauss);
+		thickness_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[0]*Jdet*gauss->weight*basis[i];
+	}
+
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjVyBalancedthickness{{{*/
+void  Tria::GradjVyBalancedthickness(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i;
+	int        vertexpidlist[NUMVERTICES];
+	IssmDouble thickness,Jdet;
+	IssmDouble basis[3];
+	IssmDouble Dlambda[2],dp[2];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble grade_g[NUMVERTICES] = {0.0};
+	GaussTria *gauss                = NULL;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* adjoint_input=inputs->GetInput(AdjointEnum);     _assert_(adjoint_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		adjoint_input->GetInputDerivativeValue(&Dlambda[0],&xyz_list[0][0],gauss);
+		thickness_input->GetInputValue(&thickness, gauss);
+		thickness_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		for(i=0;i<NUMVERTICES;i++) grade_g[i]+=thickness*Dlambda[1]*Jdet*gauss->weight*basis[i];
+	}
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjThicknessWeakBalancedthickness{{{*/
+void  Tria::GradjThicknessWeakBalancedthickness(Vector<IssmDouble>* gradient,int control_index){
+
+	/*Intermediaries */
+	int         i,resp;
+	int         vertexpidlist[NUMVERTICES];
+	IssmDouble  Jdet;
+	IssmDouble  thickness,thicknessobs,weight;
+	int         num_responses;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[3];
+	IssmDouble  dbasis[NDOF2][NUMVERTICES];
+	IssmDouble  dH[2];
+	IssmDouble  vx,vy,vel;
+	IssmDouble  dvx[2],dvy[2];
+	IssmDouble dhdt,basal_melting,surface_mass_balance;
+	GaussTria *gauss     = NULL;
+	int       *responses = NULL;
+	IssmDouble grade_g[NUMVERTICES] = {0.0};
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&num_responses,InversionNumCostFunctionsEnum);
+	this->parameters->FindParam(&responses,NULL,NULL,StepResponsesEnum);
+	Input* thickness_input            = inputs->GetInput(ThicknessEnum);                          _assert_(thickness_input);
+	Input* thicknessobs_input         = inputs->GetInput(InversionThicknessObsEnum);              _assert_(thicknessobs_input);
+	Input* weights_input              = inputs->GetInput(InversionCostFunctionsCoefficientsEnum); _assert_(weights_input);
+	Input* vx_input                   = inputs->GetInput(VxEnum);                                 _assert_(vx_input);
+	Input* vy_input                   = inputs->GetInput(VyEnum);                                 _assert_(vy_input);
+	Input* surface_mass_balance_input = inputs->GetInput(SurfaceforcingsMassBalanceEnum);         _assert_(surface_mass_balance_input);
+	Input* basal_melting_input        = inputs->GetInput(BasalforcingsMeltingRateEnum);           _assert_(basal_melting_input);
+	Input* dhdt_input                 = inputs->GetInput(BalancethicknessThickeningRateEnum);     _assert_(dhdt_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+
+		thickness_input->GetInputValue(&thickness, gauss);
+		thickness_input->GetInputDerivativeValue(&dH[0],&xyz_list[0][0],gauss);
+		thicknessobs_input->GetInputValue(&thicknessobs, gauss);
+
+		/*Loop over all requested responses*/
+		for(resp=0;resp<num_responses;resp++) switch(responses[resp]){
+
+			case ThicknessAbsMisfitEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				for(i=0;i<NUMVERTICES;i++) grade_g[i]+= (thicknessobs-thickness)*weight*Jdet*gauss->weight*basis[i];
+				break;
+			case ThicknessAbsGradientEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				for(i=0;i<NUMVERTICES;i++) grade_g[i]+= - weight*dH[0]*dbasis[0][i]*Jdet*gauss->weight;
+				for(i=0;i<NUMVERTICES;i++) grade_g[i]+= - weight*dH[1]*dbasis[1][i]*Jdet*gauss->weight;
+				break;
+			case ThicknessAlongGradientEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				vx_input->GetInputValue(&vx,gauss);
+				vy_input->GetInputValue(&vy,gauss);
+				vel = sqrt(vx*vx+vy*vy);
+				vx  = vx/(vel+1.e-9);
+				vy  = vy/(vel+1.e-9);
+				for(i=0;i<NUMVERTICES;i++) grade_g[i]+= - weight*(dH[0]*vx+dH[1]*vy)*(dbasis[0][i]*vx+dbasis[1][i]*vy)*Jdet*gauss->weight;
+				break;
+			case ThicknessAcrossGradientEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				vx_input->GetInputValue(&vx,gauss);
+				vy_input->GetInputValue(&vy,gauss);
+				vel = sqrt(vx*vx+vy*vy);
+				vx  = vx/(vel+1.e-9);
+				vy  = vy/(vel+1.e-9);
+				for(i=0;i<NUMVERTICES;i++) grade_g[i]+= - weight*(dH[0]*(-vy)+dH[1]*vx)*(dbasis[0][i]*(-vy)+dbasis[1][i]*vx)*Jdet*gauss->weight;
+				break;
+			case BalancethicknessMisfitEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				surface_mass_balance_input->GetInputValue(&surface_mass_balance,gauss);
+				basal_melting_input->GetInputValue(&basal_melting,gauss);
+				dhdt_input->GetInputValue(&dhdt,gauss);
+				vx_input->GetInputValue(&vx,gauss);
+				vx_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+				vy_input->GetInputValue(&vy,gauss);
+				vy_input->GetInputDerivativeValue(&dvy[0],&xyz_list[0][0],gauss);
+				for(i=0;i<NUMVERTICES;i++){
+					grade_g[i]+= - weight*Jdet*gauss->weight*(
+								(vx*dH[0]+vy*dH[1] + thickness*(dvx[0]+dvy[1]))*(vx*dbasis[0][i]+ vy*dbasis[1][i] + basis[i]*(dvx[0]+dvy[1]))
+								-(surface_mass_balance-basal_melting-dhdt)*(vx*dbasis[0][i]+ vy*dbasis[1][i] + basis[i]*(dvx[0]+dvy[1]))
+								);
+				}
+				break;
+			default:
+				_error_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+		}
+	}
+
+	gradient->SetValues(NUMVERTICES,vertexpidlist,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+	xDelete<int>(responses);
+}
+/*}}}*/
+/*FUNCTION Tria::GradientIndexing{{{*/
+void  Tria::GradientIndexing(int* indexing,int control_index){
+
+	/*Get some parameters*/
+	int num_controls;
+	parameters->FindParam(&num_controls,InversionNumControlParametersEnum);
+
+	/*get gradient indices*/
+	for(int i=0;i<NUMVERTICES;i++){
+		indexing[i]=num_controls*this->nodes[i]->GetVertexPid() + control_index;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::RheologyBbarAbsGradient{{{*/
+IssmDouble Tria::RheologyBbarAbsGradient(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	IssmDouble Jelem = 0;
+	IssmDouble weight;
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dp[NDOF2];
+	GaussTria *gauss = NULL;
+
+	/*retrieve parameters and inputs*/
+
+	/*If on water, return 0: */
+	if(IsOnWater()) return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* weights_input  =inputs->GetInput(InversionCostFunctionsCoefficientsEnum);              _assert_(weights_input);
+	Input* rheologyb_input=material->inputs->GetInput(MaterialsRheologyBbarEnum); _assert_(rheologyb_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		rheologyb_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		/*Tikhonov regularization: J = 1/2 ((dp/dx)^2 + (dp/dy)^2) */ 
+		Jelem+=weight*1/2*(pow(dp[0],2.)+pow(dp[1],2.))*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceAverageVelMisfit {{{*/
+IssmDouble Tria::SurfaceAverageVelMisfit(bool process_units,int weight_index){
+
+	IssmDouble Jelem=0,S,Jdet;
+	IssmDouble misfit;
+	IssmDouble vx,vy,vxobs,vyobs,weight;
+	IssmDouble 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],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	inputs->GetInputValue(&S,SurfaceAreaEnum);
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input     =inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input     =inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input  =inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input  =inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(3);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+
+		/*Compute SurfaceAverageVelMisfitEnum:
+		 *
+		 *      1                    2              2
+		 * J = ---  sqrt(  (u - u   )  +  (v - v   )  )
+		 *      S                obs            obs
+		 */
+		misfit=1/S*sqrt( pow(vx-vxobs,2) + pow(vy-vyobs,2));
+
+		if(process_units)UnitConversion(misfit,IuToExtEnum,SurfaceAverageVelMisfitEnum);
+
+		/*Add to cost function*/
+		Jelem+=misfit*weight*Jdet*gauss->weight;
+	}
+
+	/*clean-up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceLogVelMisfit {{{*/
+IssmDouble Tria::SurfaceLogVelMisfit(bool process_units,int weight_index){
+
+	IssmDouble Jelem=0;
+	IssmDouble misfit,Jdet;
+	IssmDouble epsvel=2.220446049250313e-16;
+	IssmDouble meanvel=3.170979198376458e-05; /*1000 m/yr*/
+	IssmDouble velocity_mag,obs_velocity_mag;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble vx,vy,vxobs,vyobs,weight;
+	GaussTria *gauss=NULL;
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input     =inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input     =inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input  =inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input  =inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+
+		/*Compute SurfaceLogVelMisfit:
+		 *                 [        vel + eps     ] 2
+		 * J = 4 \bar{v}^2 | log ( -----------  ) |  
+		 *                 [       vel   + eps    ]
+		 *                            obs
+		 */
+		velocity_mag    =sqrt(pow(vx,   2)+pow(vy,   2))+epsvel;
+		obs_velocity_mag=sqrt(pow(vxobs,2)+pow(vyobs,2))+epsvel;
+		misfit=4*pow(meanvel,2)*pow(log(velocity_mag/obs_velocity_mag),2);
+
+		if(process_units)UnitConversion(misfit,IuToExtEnum,SurfaceLogVelMisfitEnum);
+
+		/*Add to cost function*/
+		Jelem+=misfit*weight*Jdet*gauss->weight;
+	}
+
+	/*clean-up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceLogVxVyMisfit {{{*/
+IssmDouble Tria::SurfaceLogVxVyMisfit(bool process_units,int weight_index){
+
+	int        fit=-1;
+	IssmDouble Jelem=0, S=0;
+	IssmDouble epsvel=2.220446049250313e-16;
+	IssmDouble meanvel=3.170979198376458e-05; /*1000 m/yr*/
+	IssmDouble misfit, Jdet;
+	IssmDouble vx,vy,vxobs,vyobs,weight;
+	IssmDouble 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],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input     =inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input     =inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input  =inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input  =inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+
+		/*Compute SurfaceRelVelMisfit:
+		 *
+		 *      1            [        |u| + eps     2          |v| + eps     2  ]
+		 * J = --- \bar{v}^2 | log ( -----------  )   +  log ( -----------  )   |  
+		 *      2            [       |u    |+ eps              |v    |+ eps     ]
+		 *                              obs                       obs
+		 */
+		misfit=0.5*pow(meanvel,2)*(
+					pow(log((fabs(vx)+epsvel)/(fabs(vxobs)+epsvel)),2) +
+					pow(log((fabs(vy)+epsvel)/(fabs(vyobs)+epsvel)),2) );
+
+		if(process_units)UnitConversion(misfit,IuToExtEnum,SurfaceLogVxVyMisfitEnum);
+
+		/*Add to cost function*/
+		Jelem+=misfit*weight*Jdet*gauss->weight;
+	}
+
+	/*clean-up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceAbsVelMisfit {{{*/
+IssmDouble Tria::SurfaceAbsVelMisfit(bool process_units,int weight_index){
+
+	IssmDouble Jelem=0;
+	IssmDouble misfit,Jdet;
+	IssmDouble vx,vy,vxobs,vyobs,weight;
+	IssmDouble 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],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input     =inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input     =inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input  =inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input  =inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+
+		/*Compute SurfaceAbsVelMisfitEnum:
+		 *
+		 *      1  [           2              2 ]
+		 * J = --- | (u - u   )  +  (v - v   )  |
+		 *      2  [       obs            obs   ]
+		 *
+		 */
+		misfit=0.5*( pow(vx-vxobs,2) + pow(vy-vyobs,2) );
+
+		if(process_units)UnitConversion(misfit,IuToExtEnum,SurfaceAverageVelMisfitEnum);
+
+		/*Add to cost function*/
+		Jelem+=misfit*weight*Jdet*gauss->weight;
+	}
+
+	/*clean up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceRelVelMisfit {{{*/
+IssmDouble Tria::SurfaceRelVelMisfit(bool process_units,int weight_index){
+
+	IssmDouble  Jelem=0;
+	IssmDouble  scalex=1,scaley=1;
+	IssmDouble  misfit,Jdet;
+	IssmDouble  epsvel=2.220446049250313e-16;
+	IssmDouble  meanvel=3.170979198376458e-05; /*1000 m/yr*/
+	IssmDouble  vx,vy,vxobs,vyobs,weight;
+	IssmDouble  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],vertices,NUMVERTICES);
+
+	/*Retrieve all inputs we will be needing: */
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input     =inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input     =inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input  =inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input  =inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+
+		/*Compute SurfaceRelVelMisfit:
+		 *                        
+		 *      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                      
+		 */
+		scalex=pow(meanvel/(vxobs+epsvel),2); if(vxobs==0)scalex=0;
+		scaley=pow(meanvel/(vyobs+epsvel),2); if(vyobs==0)scaley=0;
+		misfit=0.5*(scalex*pow((vx-vxobs),2)+scaley*pow((vy-vyobs),2));
+		if(process_units)UnitConversion(misfit,IuToExtEnum,SurfaceRelVelMisfitEnum);
+
+		/*Add to cost function*/
+		Jelem+=misfit*weight*Jdet*gauss->weight;
+	}
+
+	/*clean up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::ThicknessAbsGradient{{{*/
+IssmDouble Tria::ThicknessAbsGradient(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	IssmDouble Jelem = 0;
+	IssmDouble weight;
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dp[NDOF2];
+	GaussTria *gauss = NULL;
+
+	/*retrieve parameters and inputs*/
+
+	/*If on water, return 0: */
+	if(IsOnWater()) return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* weights_input  =inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		thickness_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		/*Tikhonov regularization: J = 1/2 ((dp/dx)^2 + (dp/dy)^2) */ 
+		Jelem+=weight*1/2*(dp[0]*dp[0]+dp[1]*dp[1])*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::ThicknessAlongGradient{{{*/
+IssmDouble Tria::ThicknessAlongGradient(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	IssmDouble  Jelem = 0;
+	IssmDouble  weight;
+	IssmDouble  Jdet;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  dp[NDOF2];
+	IssmDouble  vx,vy,vel;
+	GaussTria  *gauss                    = NULL;
+
+	/*retrieve parameters and inputs*/
+
+	/*If on water, return 0: */
+	if(IsOnWater()) return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* weights_input  = inputs->GetInput(InversionCostFunctionsCoefficientsEnum); _assert_(weights_input);
+	Input* thickness_input= inputs->GetInput(ThicknessEnum);                          _assert_(thickness_input);
+	Input* vx_input       = inputs->GetInput(VxEnum);                                 _assert_(vx_input);
+	Input* vy_input       = inputs->GetInput(VyEnum);                                 _assert_(vy_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		thickness_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vel = sqrt(vx*vx+vy*vy);
+		vx  = vx/(vel+1.e-9);
+		vy  = vy/(vel+1.e-9);
+
+		/*J = 1/2 ( vx*dH/dx + vy*dH/dy )^2 */
+		Jelem+=weight*1/2*(vx*dp[0] + vy*dp[1])*(vx*dp[0] + vy*dp[1])*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::ThicknessAcrossGradient{{{*/
+IssmDouble Tria::ThicknessAcrossGradient(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	IssmDouble  Jelem = 0;
+	IssmDouble  weight;
+	IssmDouble  Jdet;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  dp[NDOF2];
+	IssmDouble  vx,vy,vel;
+	GaussTria  *gauss                    = NULL;
+
+	/*retrieve parameters and inputs*/
+
+	/*If on water, return 0: */
+	if(IsOnWater()) return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* weights_input  = inputs->GetInput(InversionCostFunctionsCoefficientsEnum); _assert_(weights_input);
+	Input* thickness_input= inputs->GetInput(ThicknessEnum);                          _assert_(thickness_input);
+	Input* vx_input       = inputs->GetInput(VxEnum);                                 _assert_(vx_input);
+	Input* vy_input       = inputs->GetInput(VyEnum);                                 _assert_(vy_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		thickness_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vel = sqrt(vx*vx+vy*vy);
+		vx  = vx/(vel+1.e-9);
+		vy  = vy/(vel+1.e-9);
+
+		/*J = 1/2 ( -vy*dH/dx + vx*dH/dy )^2 */
+		Jelem+=weight*1/2*(-vy*dp[0] + vx*dp[1])*(-vy*dp[0] + vx*dp[1])*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::ThicknessAbsMisfit {{{*/
+IssmDouble Tria::ThicknessAbsMisfit(bool process_units,int weight_index){
+
+	/*Intermediaries*/
+	IssmDouble thickness,thicknessobs,weight;
+	IssmDouble Jdet;
+	IssmDouble Jelem = 0;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	GaussTria *gauss = NULL;
+	IssmDouble dH[2];
+
+	/*If on water, return 0: */
+	if(IsOnWater())return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* thickness_input   =inputs->GetInput(ThicknessEnum);   _assert_(thickness_input);
+	Input* thicknessobs_input=inputs->GetInput(InversionThicknessObsEnum);_assert_(thicknessobs_input);
+	Input* weights_input     =inputs->GetInput(InversionCostFunctionsCoefficientsEnum);     _assert_(weights_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get parameters at gauss point*/
+		thickness_input->GetInputValue(&thickness,gauss);
+		thickness_input->GetInputDerivativeValue(&dH[0],&xyz_list[0][0],gauss);
+		thicknessobs_input->GetInputValue(&thicknessobs,gauss);
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+
+		/*compute ThicknessAbsMisfit*/
+		Jelem+=0.5*(thickness-thicknessobs)*(thickness-thicknessobs)*weight*Jdet*gauss->weight;
+	}
+
+	/* clean up and Return: */
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorAdjointBalancethickness{{{*/
+ElementVector* Tria::CreatePVectorAdjointBalancethickness(void){
+
+	/*Constants*/
+	const int    numdof=1*NUMVERTICES;
+
+	/*Intermediaries */
+	int         i,resp;
+	IssmDouble  Jdet;
+	IssmDouble  thickness,thicknessobs,weight;
+	int         num_responses;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  basis[3];
+	IssmDouble  dbasis[NDOF2][NUMVERTICES];
+	IssmDouble  dH[2];
+	IssmDouble  vx,vy,vel;
+	GaussTria *gauss     = NULL;
+	int       *responses = NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&num_responses,InversionNumCostFunctionsEnum);
+	this->parameters->FindParam(&responses,NULL,NULL,StepResponsesEnum);
+	Input* thickness_input    = inputs->GetInput(ThicknessEnum);                          _assert_(thickness_input);
+	Input* thicknessobs_input = inputs->GetInput(InversionThicknessObsEnum);              _assert_(thicknessobs_input);
+	Input* weights_input      = inputs->GetInput(InversionCostFunctionsCoefficientsEnum); _assert_(weights_input);
+	Input* vx_input           = inputs->GetInput(VxEnum);                                 _assert_(vx_input);
+	Input* vy_input           = inputs->GetInput(VyEnum);                                 _assert_(vy_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+		GetNodalFunctionsDerivatives(&dbasis[0][0],&xyz_list[0][0],gauss);
+
+		thickness_input->GetInputValue(&thickness, gauss);
+		thickness_input->GetInputDerivativeValue(&dH[0],&xyz_list[0][0],gauss);
+		thicknessobs_input->GetInputValue(&thicknessobs, gauss);
+
+		/*Loop over all requested responses*/
+		for(resp=0;resp<num_responses;resp++) switch(responses[resp]){
+
+			case ThicknessAbsMisfitEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				for(i=0;i<numdof;i++) pe->values[i]+=(thicknessobs-thickness)*weight*Jdet*gauss->weight*basis[i];
+				break;
+			case ThicknessAbsGradientEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				for(i=0;i<numdof;i++) pe->values[i]+= - weight*dH[0]*dbasis[0][i]*Jdet*gauss->weight;
+				for(i=0;i<numdof;i++) pe->values[i]+= - weight*dH[1]*dbasis[1][i]*Jdet*gauss->weight;
+				break;
+			case ThicknessAlongGradientEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				vx_input->GetInputValue(&vx,gauss);
+				vy_input->GetInputValue(&vy,gauss);
+				vel = sqrt(vx*vx+vy*vy);
+				vx  = vx/(vel+1.e-9);
+				vy  = vy/(vel+1.e-9);
+				for(i=0;i<numdof;i++) pe->values[i]+= - weight*(dH[0]*vx+dH[1]*vy)*(dbasis[0][i]*vx+dbasis[1][i]*vy)*Jdet*gauss->weight;
+				break;
+			case ThicknessAcrossGradientEnum:
+				weights_input->GetInputValue(&weight, gauss,resp);
+				vx_input->GetInputValue(&vx,gauss);
+				vy_input->GetInputValue(&vy,gauss);
+				vel = sqrt(vx*vx+vy*vy);
+				vx  = vx/(vel+1.e-9);
+				vy  = vy/(vel+1.e-9);
+				for(i=0;i<numdof;i++) pe->values[i]+= - weight*(dH[0]*(-vy)+dH[1]*vx)*(dbasis[0][i]*(-vy)+dbasis[1][i]*vx)*Jdet*gauss->weight;
+				break;
+			default:
+				_error_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	xDelete<int>(responses);
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorAdjointHoriz{{{*/
+ElementVector* Tria::CreatePVectorAdjointHoriz(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,resp;
+	int       *responses=NULL;
+	int        num_responses;
+	IssmDouble     Jdet;
+	IssmDouble     obs_velocity_mag,velocity_mag;
+	IssmDouble     dux,duy;
+	IssmDouble     epsvel=2.220446049250313e-16;
+	IssmDouble     meanvel=3.170979198376458e-05; /*1000 m/yr*/
+	IssmDouble     scalex=0,scaley=0,scale=0,S=0;
+	IssmDouble     vx,vy,vxobs,vyobs,weight;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     basis[3];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&num_responses,InversionNumCostFunctionsEnum);
+	this->parameters->FindParam(&responses,NULL,NULL,StepResponsesEnum);
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input     =inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input     =inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input  =inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input  =inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/*Get Surface if required by one response*/
+	for(resp=0;resp<num_responses;resp++){
+		if(responses[resp]==SurfaceAverageVelMisfitEnum){
+			inputs->GetInputValue(&S,SurfaceAreaEnum); break;
+		}
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+		GetNodalFunctions(basis, gauss);
+
+		/*Loop over all requested responses*/
+		for(resp=0;resp<num_responses;resp++){
+
+			weights_input->GetInputValue(&weight,gauss,resp);
+
+			switch(responses[resp]){
+				case SurfaceAbsVelMisfitEnum:
+					/*
+					 *      1  [           2              2 ]
+					 * J = --- | (u - u   )  +  (v - v   )  |
+					 *      2  [       obs            obs   ]
+					 *
+					 *        dJ
+					 * DU = - -- = (u   - u )
+					 *        du     obs
+					 */
+					for (i=0;i<NUMVERTICES;i++){
+						dux=vxobs-vx;
+						duy=vyobs-vy;
+						pe->values[i*NDOF2+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF2+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceRelVelMisfitEnum:
+					/*
+					 *      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/(vxobs+epsvel),2); if(vxobs==0)scalex=0;
+						scaley=pow(meanvel/(vyobs+epsvel),2); if(vyobs==0)scaley=0;
+						dux=scalex*(vxobs-vx);
+						duy=scaley*(vyobs-vy);
+						pe->values[i*NDOF2+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF2+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceLogVelMisfitEnum:
+					/*
+					 *                 [        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,   2)+pow(vy,   2))+epsvel;
+						obs_velocity_mag=sqrt(pow(vxobs,2)+pow(vyobs,2))+epsvel;
+						scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
+						dux=scale*vx;
+						duy=scale*vy;
+						pe->values[i*NDOF2+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF2+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceAverageVelMisfitEnum:
+					/*
+					 *      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./(S*2*sqrt(pow(vx-vxobs,2)+pow(vy-vyobs,2))+epsvel);
+						dux=scale*(vxobs-vx);
+						duy=scale*(vyobs-vy);
+						pe->values[i*NDOF2+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF2+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceLogVxVyMisfitEnum:
+					/*
+					 *      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 = - meanvel*meanvel * log((fabs(vx)+epsvel)/(fabs(vxobs)+epsvel)) / (vx+epsvel);
+						duy = - meanvel*meanvel * log((fabs(vy)+epsvel)/(fabs(vyobs)+epsvel)) / (vy+epsvel);
+						pe->values[i*NDOF2+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF2+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case DragCoefficientAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case ThicknessAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case ThicknessAlongGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case ThicknessAcrossGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case RheologyBbarAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				default:
+					_error_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	xDelete<int>(responses);
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorAdjointStokes{{{*/
+ElementVector* Tria::CreatePVectorAdjointStokes(void){
+
+	/*Intermediaries */
+	int        i,resp;
+	int       *responses=NULL;
+	int        num_responses;
+	IssmDouble     Jdet;
+	IssmDouble     obs_velocity_mag,velocity_mag;
+	IssmDouble     dux,duy;
+	IssmDouble     epsvel=2.220446049250313e-16;
+	IssmDouble     meanvel=3.170979198376458e-05; /*1000 m/yr*/
+	IssmDouble     scalex=0,scaley=0,scale=0,S=0;
+	IssmDouble     vx,vy,vxobs,vyobs,weight;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     basis[3];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&num_responses,InversionNumCostFunctionsEnum);
+	this->parameters->FindParam(&responses,NULL,NULL,StepResponsesEnum);
+	Input* weights_input = inputs->GetInput(InversionCostFunctionsCoefficientsEnum);   _assert_(weights_input);
+	Input* vx_input      = inputs->GetInput(VxEnum);        _assert_(vx_input);
+	Input* vy_input      = inputs->GetInput(VyEnum);        _assert_(vy_input);
+	Input* vxobs_input   = inputs->GetInput(InversionVxObsEnum);     _assert_(vxobs_input);
+	Input* vyobs_input   = inputs->GetInput(InversionVyObsEnum);     _assert_(vyobs_input);
+
+	/*Get Surface if required by one response*/
+	for(resp=0;resp<num_responses;resp++){
+		if(responses[resp]==SurfaceAverageVelMisfitEnum){
+			inputs->GetInputValue(&S,SurfaceAreaEnum); break;
+		}
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vxobs_input->GetInputValue(&vxobs,gauss);
+		vyobs_input->GetInputValue(&vyobs,gauss);
+		GetNodalFunctions(basis, gauss);
+
+		/*Loop over all requested responses*/
+		for(resp=0;resp<num_responses;resp++){
+
+			weights_input->GetInputValue(&weight,gauss,resp);
+
+			switch(responses[resp]){
+
+				case SurfaceAbsVelMisfitEnum:
+					/*
+					 *      1  [           2              2 ]
+					 * J = --- | (u - u   )  +  (v - v   )  |
+					 *      2  [       obs            obs   ]
+					 *
+					 *        dJ
+					 * DU = - -- = (u   - u )
+					 *        du     obs
+					 */
+					for (i=0;i<NUMVERTICES;i++){
+						dux=vxobs-vx;
+						duy=vyobs-vy;
+						pe->values[i*NDOF4+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF4+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceRelVelMisfitEnum:
+					/*
+					 *      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/(vxobs+epsvel),2); if(vxobs==0)scalex=0;
+						scaley=pow(meanvel/(vyobs+epsvel),2); if(vyobs==0)scaley=0;
+						dux=scalex*(vxobs-vx);
+						duy=scaley*(vyobs-vy);
+						pe->values[i*NDOF4+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF4+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceLogVelMisfitEnum:
+					/*
+					 *                 [        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,   2)+pow(vy,   2))+epsvel;
+						obs_velocity_mag=sqrt(pow(vxobs,2)+pow(vyobs,2))+epsvel;
+						scale=-8*pow(meanvel,2)/pow(velocity_mag,2)*log(velocity_mag/obs_velocity_mag);
+						dux=scale*vx;
+						duy=scale*vy;
+						pe->values[i*NDOF4+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF4+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceAverageVelMisfitEnum:
+					/*
+					 *      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./(S*2*sqrt(pow(vx-vxobs,2)+pow(vy-vyobs,2))+epsvel);
+						dux=scale*(vxobs-vx);
+						duy=scale*(vyobs-vy);
+						pe->values[i*NDOF4+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF4+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case SurfaceLogVxVyMisfitEnum:
+					/*
+					 *      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 = - meanvel*meanvel * log((fabs(vx)+epsvel)/(fabs(vxobs)+epsvel)) / (vx+epsvel);
+						duy = - meanvel*meanvel * log((fabs(vy)+epsvel)/(fabs(vyobs)+epsvel)) / (vy+epsvel);
+						pe->values[i*NDOF4+0]+=dux*weight*Jdet*gauss->weight*basis[i]; 
+						pe->values[i*NDOF4+1]+=duy*weight*Jdet*gauss->weight*basis[i]; 
+					}
+					break;
+				case DragCoefficientAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case ThicknessAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case ThicknessAcrossGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case ThicknessAlongGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				case RheologyBbarAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				default:
+					_error_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+			}
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	xDelete<int>(responses);
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::DragCoefficientAbsGradient{{{*/
+IssmDouble Tria::DragCoefficientAbsGradient(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	IssmDouble Jelem = 0;
+	IssmDouble weight;
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dp[NDOF2];
+	GaussTria *gauss = NULL;
+
+	/*retrieve parameters and inputs*/
+
+	/*If on water, return 0: */
+	if(IsOnWater()) return 0;
+
+	/*Retrieve all inputs we will be needing: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* weights_input=inputs->GetInput(InversionCostFunctionsCoefficientsEnum);         _assert_(weights_input);
+	Input* drag_input   =inputs->GetInput(FrictionCoefficientEnum); _assert_(drag_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get all parameters at gaussian point*/
+		weights_input->GetInputValue(&weight,gauss,weight_index);
+		drag_input->GetInputDerivativeValue(&dp[0],&xyz_list[0][0],gauss);
+
+		/*Tikhonov regularization: J = 1/2 ((dp/dx)^2 + (dp/dy)^2) */ 
+		Jelem+=weight*1/2*(dp[0]*dp[0]+dp[1]*dp[1])*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixAdjointBalancethickness {{{*/
+ElementMatrix* Tria::CreateKMatrixAdjointBalancethickness(void){
+
+	ElementMatrix* Ke=NULL;
+
+	/*Get Element Matrix of the forward model*/
+	switch(GetElementType()){
+		case P1Enum:
+			Ke=CreateKMatrixBalancethickness_CG();
+			break;
+		case P1DGEnum:
+			Ke=CreateKMatrixBalancethickness_DG();
+			break;
+		default:
+			_error_("Element type " << EnumToStringx(GetElementType()) << " not supported yet");
+	}
+
+	/*Transpose and return Ke*/
+	Ke->Transpose();
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixAdjointMacAyeal{{{*/
+ElementMatrix* Tria::CreateKMatrixAdjointMacAyeal(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	bool       incomplete_adjoint;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble Jdet,thickness;
+	IssmDouble eps1dotdphii,eps1dotdphij;
+	IssmDouble eps2dotdphii,eps2dotdphij;
+	IssmDouble mu_prime;
+	IssmDouble epsilon[3];/* epsilon=[exx,eyy,exy];*/
+	IssmDouble eps1[2],eps2[2];
+	IssmDouble dphi[2][NUMVERTICES];
+	GaussTria *gauss=NULL;
+
+	/*Initialize Jacobian with regular MacAyeal (first part of the Gateau derivative)*/
+	parameters->FindParam(&incomplete_adjoint,InversionIncompleteAdjointEnum);
+	ElementMatrix* Ke=CreateKMatrixDiagnosticMacAyeal();
+	if(incomplete_adjoint) return Ke;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vx_input=inputs->GetInput(VxEnum);       _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum);       _assert_(vy_input);
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsDerivatives(&dphi[0][0],&xyz_list[0][0],gauss);
+
+		thickness_input->GetInputValue(&thickness, gauss);
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		material->GetViscosity2dDerivativeEpsSquare(&mu_prime,&epsilon[0]);
+		eps1[0]=2*epsilon[0]+epsilon[1];   eps2[0]=epsilon[2];
+		eps1[1]=epsilon[2];                eps2[1]=epsilon[0]+2*epsilon[1];
+
+		for(i=0;i<3;i++){
+			for(j=0;j<3;j++){
+				eps1dotdphii=eps1[0]*dphi[0][i]+eps1[1]*dphi[1][i];
+				eps1dotdphij=eps1[0]*dphi[0][j]+eps1[1]*dphi[1][j];
+				eps2dotdphii=eps2[0]*dphi[0][i]+eps2[1]*dphi[1][i];
+				eps2dotdphij=eps2[0]*dphi[0][j]+eps2[1]*dphi[1][j];
+
+				Ke->values[6*(2*i+0)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*thickness*eps1dotdphij*eps1dotdphii;
+				Ke->values[6*(2*i+0)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*thickness*eps2dotdphij*eps1dotdphii;
+				Ke->values[6*(2*i+1)+2*j+0]+=gauss->weight*Jdet*2*mu_prime*thickness*eps1dotdphij*eps2dotdphii;
+				Ke->values[6*(2*i+1)+2*j+1]+=gauss->weight*Jdet*2*mu_prime*thickness*eps2dotdphij*eps2dotdphii;
+			}
+		}
+	}
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,nodes,NUMVERTICES,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	//Ke->Transpose();
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionAdjointHoriz {{{*/
+void  Tria::InputUpdateFromSolutionAdjointHoriz(IssmDouble* solution){
+
+	const int numdof=NDOF2*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	IssmDouble    values[numdof];
+	IssmDouble    lambdax[NUMVERTICES];
+	IssmDouble    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];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(lambdax[i])) _error_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambday[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaP1Input(AdjointxEnum,lambdax));
+	this->inputs->AddInput(new TriaP1Input(AdjointyEnum,lambday));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionAdjointBalancethickness {{{*/
+void  Tria::InputUpdateFromSolutionAdjointBalancethickness(IssmDouble* solution){
+
+	const int numdof=NDOF1*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	IssmDouble    values[numdof];
+	IssmDouble    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];
+		if(xIsNan<IssmDouble>(lambda[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Add vx and vy as inputs to the tria element: */
+	this->inputs->AddInput(new TriaP1Input(AdjointEnum,lambda));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::GetVectorFromControlInputs{{{*/
+void  Tria::GetVectorFromControlInputs(Vector<IssmDouble>* vector,int control_enum,int control_index,const char* data){
+
+	int vertexpidlist[NUMVERTICES];
+	Input *input=NULL;
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(control_enum)) return;
+
+	/*Prepare index list*/
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Get input (either in element or material)*/
+	if(control_enum==MaterialsRheologyBbarEnum || control_enum==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(control_enum); _assert_(input);
+	}
+	else{
+		input=(Input*)this->inputs->GetInput(control_enum);   _assert_(input);
+	}
+
+	/*Check that it is a ControlInput*/
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error_("input " << EnumToStringx(control_enum) << " is not a ControlInput");
+	}
+
+	((ControlInput*)input)->GetVectorFromInputs(vector,&vertexpidlist[0],data);
+}
+/*}}}*/
+/*FUNCTION Tria::SetControlInputsFromVector{{{*/
+void  Tria::SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index){
+
+	IssmDouble  values[NUMVERTICES];
+	int     vertexpidlist[NUMVERTICES];
+	Input  *input     = NULL;
+	Input  *new_input = NULL;
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(control_enum)) return;
+
+	/*Prepare index list*/
+	GradientIndexing(&vertexpidlist[0],control_index);
+
+	/*Get values on vertices*/
+	for (int i=0;i<NUMVERTICES;i++){
+		values[i]=vector[vertexpidlist[i]];
+	}
+	new_input = new TriaP1Input(control_enum,values);
+
+	if(control_enum==MaterialsRheologyBbarEnum || control_enum==MaterialsRheologyZbarEnum){
+		input=(Input*)material->inputs->GetInput(control_enum); _assert_(input);
+	}
+	else{
+		input=(Input*)this->inputs->GetInput(control_enum);   _assert_(input);
+	}
+
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error_("input " << EnumToStringx(control_enum) << " is not a ControlInput");
+	}
+
+	((ControlInput*)input)->SetInput(new_input);
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_HYDROLOGY_
+/*FUNCTION Tria::CreateHydrologyWaterVelocityInput {{{*/
+void Tria::CreateHydrologyWaterVelocityInput(void){
+
+	/*material parameters: */
+	IssmDouble mu_water;
+	IssmDouble VelocityFactor;  // This factor represents the number 12 in laminar flow velocity which can vary by differnt hydrology.CR
+	IssmDouble n_man,CR;
+	IssmDouble w;
+	IssmDouble rho_ice, rho_water, g;
+	IssmDouble dsdx,dsdy,dbdx,dbdy;
+	IssmDouble vx[NUMVERTICES];
+	IssmDouble vy[NUMVERTICES];
+	GaussTria *gauss = NULL;
+
+	/*Retrieve all inputs and parameters*/
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+	g=matpar->GetG();
+	CR=matpar->GetHydrologyCR(); // To have Lebrocq equavalent equation: CR=0.01,n_man=0.02
+	n_man=matpar->GetHydrologyN(); 
+	mu_water=matpar->GetMuWater();
+	Input* surfaceslopex_input=inputs->GetInput(SurfaceSlopeXEnum); _assert_(surfaceslopex_input);
+	Input* surfaceslopey_input=inputs->GetInput(SurfaceSlopeYEnum); _assert_(surfaceslopey_input);
+	Input* bedslopex_input=inputs->GetInput(BedSlopeXEnum);         _assert_(bedslopex_input);
+	Input* bedslopey_input=inputs->GetInput(BedSlopeYEnum);         _assert_(bedslopey_input);
+	Input* watercolumn_input=inputs->GetInput(WatercolumnEnum);     _assert_(watercolumn_input);
+
+	/* compute VelocityFactor */
+	VelocityFactor= n_man*CR*CR*rho_water*g/mu_water;
+
+	gauss=new GaussTria();
+	for (int iv=0;iv<NUMVERTICES;iv++){
+		gauss->GaussVertex(iv);
+		surfaceslopex_input->GetInputValue(&dsdx,gauss);
+		surfaceslopey_input->GetInputValue(&dsdy,gauss);
+		bedslopex_input->GetInputValue(&dbdx,gauss);
+		bedslopey_input->GetInputValue(&dbdy,gauss);
+		watercolumn_input->GetInputValue(&w,gauss);
+
+		/* Water velocity x and y components */
+	//	vx[iv]= - w*w/(12 * mu_water)*(rho_ice*g*dsdx+(rho_water-rho_ice)*g*dbdx);
+	//	vy[iv]= - w*w/(12 * mu_water)*(rho_ice*g*dsdy+(rho_water-rho_ice)*g*dbdy);
+		vx[iv]= - w*w/(VelocityFactor* mu_water)*(rho_ice*g*dsdx+(rho_water-rho_ice)*g*dbdx);
+		vy[iv]= - w*w/(VelocityFactor* mu_water)*(rho_ice*g*dsdy+(rho_water-rho_ice)*g*dbdy);
+	}
+
+	/*clean-up*/
+	delete gauss;
+
+	/*Add to inputs*/
+	this->inputs->AddInput(new TriaP1Input(HydrologyWaterVxEnum,vx));
+	this->inputs->AddInput(new TriaP1Input(HydrologyWaterVyEnum,vy));
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixHydrologyShreve{{{*/
+ElementMatrix* Tria::CreateKMatrixHydrologyShreve(void){
+
+	/*Constants*/
+	const int  numdof=NDOF1*NUMVERTICES;
+
+/*Intermediaries */
+	IssmDouble diffusivity;
+	IssmDouble Jdettria,DL_scalar,dt,h;
+	IssmDouble vx,vy,vel,dvxdx,dvydy;
+	IssmDouble dvx[2],dvy[2];
+	IssmDouble v_gauss[2]={0.0};
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[NUMVERTICES];
+	IssmDouble B[2][NUMVERTICES];
+	IssmDouble Bprime[2][NUMVERTICES];
+	IssmDouble K[2][2]                        ={0.0};
+	IssmDouble KDL[2][2]                      ={0.0};
+	IssmDouble DL[2][2]                        ={0.0};
+	IssmDouble DLprime[2][2]                   ={0.0};
+	GaussTria *gauss=NULL;
+
+/*Skip if water or ice shelf element*/
+	if(IsOnWater() | IsFloating()) return NULL;
+
+/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+/*Create water velocity vx and vy from current inputs*/
+	CreateHydrologyWaterVelocityInput();
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&diffusivity,HydrologyshreveStabilizationEnum);
+	Input* vx_input=inputs->GetInput(HydrologyWaterVxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(HydrologyWaterVyEnum); _assert_(vy_input);
+	h=sqrt(2*this->GetArea());
+
+/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		vx_input->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&vy,gauss);
+		vx_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vy_input->GetInputDerivativeValue(&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->values[0],1);
+
+		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->values[0],1);
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+										&DLprime[0][0],2,2,0,
+										&Bprime[0][0],2,numdof,0,
+										&Ke->values[0],1);
+
+		/*Artificial diffusivity*/
+		vel=sqrt(vx*vx+vy*vy);
+		K[0][0]=diffusivity*h/(2*vel)*vx*vx;
+		K[1][0]=diffusivity*h/(2*vel)*vy*vx;
+		K[0][1]=diffusivity*h/(2*vel)*vx*vy;
+		K[1][1]=diffusivity*h/(2*vel)*vy*vy;
+		KDL[0][0]=DL_scalar*K[0][0];
+		KDL[1][0]=DL_scalar*K[1][0];
+		KDL[0][1]=DL_scalar*K[0][1];
+		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->values[0],1);
+	}
+
+/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixHydrologyDCInefficient{{{*/
+ElementMatrix* Tria::CreateKMatrixHydrologyDCInefficient(void){
+
+	/*constants: */
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/* Intermediaries */
+	IssmDouble  D_scalar,Jdet;
+	IssmDouble 	sediment_transmitivity,dt;
+	IssmDouble  sediment_storing;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  B[2][numdof];
+	IssmDouble  L[NUMVERTICES];
+	IssmDouble  D[2][2];
+	GaussTria   *gauss = NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	sediment_storing       = matpar->GetSedimentStoring();
+	sediment_transmitivity = matpar->GetSedimentTransmitivity();
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Diffusivity*/
+		D_scalar=sediment_transmitivity*gauss->weight*Jdet;
+		if(reCast<bool,IssmDouble>(dt)) D_scalar=D_scalar*dt;
+		D[0][0]=D_scalar; D[0][1]=0.;
+		D[1][0]=0.;       D[1][1]=D_scalar;
+		GetBHydro(&B[0][0],&xyz_list[0][0],gauss); 
+		TripleMultiply(&B[0][0],2,numdof,1,
+									 &D[0][0],2,2,0,
+									 &B[0][0],2,numdof,0,
+									 &Ke->values[0],1);
+
+		/*Transient*/
+		if(reCast<bool,IssmDouble>(dt)){
+			GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+			D_scalar=sediment_storing*gauss->weight*Jdet;
+
+			TripleMultiply(&L[0],numdof,1,0,
+										 &D_scalar,1,1,0,
+										 &L[0],1,numdof,0,
+										 &Ke->values[0],1);
+		}
+	}
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixHydrologyDCEfficient{{{*/
+ElementMatrix* Tria::CreateKMatrixHydrologyDCEfficient(void){
+
+	/*constants: */
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/* Intermediaries */
+	IssmDouble  D_scalar,Jdet;
+	IssmDouble 	epl_transmitivity,dt;
+	IssmDouble  epl_storing;
+	IssmDouble  xyz_list[NUMVERTICES][3];
+	IssmDouble  B[2][numdof];
+	IssmDouble  L[NUMVERTICES];
+	IssmDouble  D[2][2];
+	GaussTria   *gauss = NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	epl_storing       = matpar->GetEplStoring();
+	epl_transmitivity = matpar->GetEplTransmitivity();
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Diffusivity*/
+		D_scalar=epl_transmitivity*gauss->weight*Jdet;
+		if(reCast<bool,IssmDouble>(dt)) D_scalar=D_scalar*dt;
+		D[0][0]=D_scalar; D[0][1]=0.;
+		D[1][0]=0.;       D[1][1]=D_scalar;
+		GetBHydro(&B[0][0],&xyz_list[0][0],gauss); 
+		TripleMultiply(&B[0][0],2,numdof,1,
+									 &D[0][0],2,2,0,
+									 &B[0][0],2,numdof,0,
+									 &Ke->values[0],1);
+
+		/*Transient*/
+		if(reCast<bool,IssmDouble>(dt)){
+			GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+			D_scalar=epl_storing*gauss->weight*Jdet;
+
+			TripleMultiply(&L[0],numdof,1,0,
+										 &D_scalar,1,1,0,
+										 &L[0],1,numdof,0,
+										 &Ke->values[0],1);
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorHydrologyShreve {{{*/
+ElementVector* Tria::CreatePVectorHydrologyShreve(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble Jdettria,dt;
+	IssmDouble basal_melting_g;
+	IssmDouble old_watercolumn_g;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble basis[numdof];
+	GaussTria* gauss=NULL;
+
+	/*Skip if water or ice shelf element*/
+	if(IsOnWater() | IsFloating()) return NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* basal_melting_input=inputs->GetInput(BasalforcingsMeltingRateEnum); _assert_(basal_melting_input);
+	Input* old_watercolumn_input=inputs->GetInput(WaterColumnOldEnum);         _assert_(old_watercolumn_input);
+
+	/*Initialize basal_melting_correction_g to 0, do not forget!:*/
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdettria, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		basal_melting_input->GetInputValue(&basal_melting_g,gauss);
+		old_watercolumn_input->GetInputValue(&old_watercolumn_g,gauss);
+
+		if(reCast<int,IssmDouble>(dt))for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(old_watercolumn_g+dt*basal_melting_g)*basis[i];
+		else  for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*basal_melting_g*basis[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorHydrologyDCInefficient {{{*/
+ElementVector* Tria::CreatePVectorHydrologyDCInefficient(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dt,scalar,water_head;
+	IssmDouble water_load;
+	IssmDouble sediment_storing;
+	IssmDouble basis[numdof];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	sediment_storing = matpar->GetSedimentStoring();
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* water_input=inputs->GetInput(BasalforcingsMeltingRateEnum);  _assert_(water_input);
+	Input* old_wh_input=NULL; 
+
+	if(reCast<bool,IssmDouble>(dt)){
+		old_wh_input=inputs->GetInput(SedimentHeadOldEnum); _assert_(old_wh_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		/*Loading term*/
+		water_input->GetInputValue(&water_load,gauss);
+		scalar = Jdet*gauss->weight*water_load;
+		if(reCast<bool,IssmDouble>(dt)) scalar = scalar*dt;
+		for(int i=0;i<numdof;i++) pe->values[i]+=scalar*basis[i];
+
+		/*Transient term*/
+		if(reCast<bool,IssmDouble>(dt)){
+			old_wh_input->GetInputValue(&water_head,gauss);
+			scalar = Jdet*gauss->weight*water_head*sediment_storing;
+			for(int i=0;i<numdof;i++) pe->values[i]+=scalar*basis[i];
+		}
+	}
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorHydrologyDCEfficient {{{*/
+ElementVector* Tria::CreatePVectorHydrologyDCEfficient(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dt,scalar,water_head;
+	IssmDouble residual_load;
+	IssmDouble epl_storing;
+	IssmDouble basis[numdof];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	epl_storing = matpar->GetEplStoring();
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* residual_input=inputs->GetInput(SedimentHeadResidualEnum);  _assert_(residual_input);
+	Input* old_wh_input=NULL; 
+
+	if(reCast<bool,IssmDouble>(dt)){
+		old_wh_input=inputs->GetInput(EplHeadEnum); _assert_(old_wh_input);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(basis, gauss);
+
+		/*Loading term*/
+		residual_input->GetInputValue(&residual_load,gauss);
+		scalar = Jdet*gauss->weight*residual_load;
+		if(reCast<bool,IssmDouble>(dt)) scalar = scalar*dt;
+		for(int i=0;i<numdof;i++) pe->values[i]+=scalar*basis[i];
+		
+		/*Transient term*/
+		if(reCast<bool,IssmDouble>(dt)){
+			old_wh_input->GetInputValue(&water_head,gauss);
+			scalar = Jdet*gauss->weight*water_head*epl_storing;
+			for(int i=0;i<numdof;i++) pe->values[i]+=scalar*basis[i];
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::GetSolutionFromInputsHydrologyShreve{{{*/
+void  Tria::GetSolutionFromInputsHydrologyShreve(Vector<IssmDouble>* solution){
+
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	int         i;
+	int        *doflist = NULL;
+	IssmDouble  watercolumn;
+	IssmDouble  values[numdof];
+	GaussTria  *gauss   = NULL;
+
+	/*Get dof list: */
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+
+	/*Get inputs*/
+	Input* watercolumn_input=inputs->GetInput(WatercolumnEnum); _assert_(watercolumn_input);
+
+	/*Ok, we have watercolumn values, fill in watercolumn array: */
+	/*P1 element only for now*/
+	gauss=new GaussTria();
+	for(i=0;i<NUMVERTICES;i++){
+
+		gauss->GaussVertex(i);
+
+		/*Recover watercolumn*/
+		watercolumn_input->GetInputValue(&watercolumn,gauss);
+		values[i]=watercolumn;
+	}
+
+	solution->SetValues(numdof,doflist,values,INS_VAL);
+
+	/*Free ressources:*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionHydrologyShreve{{{*/
+void  Tria::InputUpdateFromSolutionHydrologyShreve(IssmDouble* solution){
+
+	/*Intermediaries*/
+	const int   numdof         = NDOF1 *NUMVERTICES;
+	int        *doflist        = NULL;
+	IssmDouble  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]];
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+		if (values[i]<10e-10) values[i]=10e-10; //correcting the water column to positive values
+	}
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new TriaP1Input(WatercolumnEnum,values));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionHydrologyDCInefficient{{{*/
+void  Tria::InputUpdateFromSolutionHydrologyDCInefficient(IssmDouble* solution){
+
+	/*Intermediaries*/
+	const int   numdof         = NDOF1 *NUMVERTICES;
+	int        *doflist        = NULL;
+	bool        converged;
+	IssmDouble  values[numdof];
+	IssmDouble  residual[numdof];
+	IssmDouble  intbasis[numdof];	
+	IssmDouble  penalty_factor, dt;
+	IssmDouble  kmax, kappa, h_max;
+
+	/*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]];
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+	}
+
+	/*If converged keep the residual in mind*/
+	this->inputs->GetInputValue(&converged,ConvergedEnum);
+	GetInputListOnVertices(&intbasis[0],BasisIntegralEnum);
+
+	if(converged){
+		this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+		this->parameters->FindParam(&kmax,HydrologySedimentKmaxEnum);
+		this->parameters->FindParam(&penalty_factor,HydrologydcPenaltyFactorEnum);
+		kappa=kmax*pow(10.,penalty_factor);
+		
+		for(int i=0;i<NUMVERTICES;i++){
+			this->GetHydrologyDCInefficientHmax(&h_max,nodes[i]);
+			if(values[i]>h_max)
+				residual[i]=kappa*(values[i]-h_max)/(dt*intbasis[i]);
+			else
+				residual[i]=0.0;
+		}
+	}	
+
+	/*Add input to the element: */
+
+	this->inputs->AddInput(new TriaP1Input(SedimentHeadEnum,values));
+	this->inputs->AddInput(new TriaP1Input(SedimentHeadResidualEnum,residual));
+	if(converged)this->inputs->AddInput(new TriaP1Input(SedimentHeadOldEnum,values));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromSolutionHydrologyDCEfficient{{{*/
+void  Tria::InputUpdateFromSolutionHydrologyDCEfficient(IssmDouble* solution){
+
+	/*Intermediaries*/
+	const int   numdof         = NDOF1 *NUMVERTICES;
+	int        *doflist        = NULL;
+	IssmDouble  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]];
+		if(xIsNan<IssmDouble>(values[i])) _error_("NaN found in solution vector");
+	}
+
+	/*Add input to the element: */
+	this->inputs->AddInput(new TriaP1Input(EplHeadEnum,values));
+
+	/*Free ressources:*/
+	xDelete<int>(doflist);
+}
+/*}}}*/
+/*FUNCTION Tria::GetHydrologyDCInefficientHmax{{{*/
+void  Tria::GetHydrologyDCInefficientHmax(IssmDouble* ph_max, Node* innode){
+
+		int        hmax_flag;
+		IssmDouble h_max;
+		IssmDouble gravity,rho_ice,rho_water;
+		IssmDouble thickness,bed;
+
+		/*Get the flag to the limitation method*/
+		this->parameters->FindParam(&hmax_flag,HydrologydcSedimentlimitFlagEnum);
+
+		/*Switch between the different cases*/
+		switch(hmax_flag){
+			case 0:
+				h_max=1.0e+10;
+				break;
+			case 1:
+				parameters->FindParam(&h_max,HydrologydcSedimentlimitEnum);
+				break;
+			case 2:
+				gravity=matpar->GetG();
+				rho_ice=matpar->GetRhoIce();
+				rho_water=matpar->GetRhoFreshwater();
+				this->GetInputValue(&thickness,innode,ThicknessEnum);
+				this->GetInputValue(&bed,innode,BedEnum);
+				h_max=((rho_ice*gravity*thickness)/rho_water)+bed;
+				break;
+			case 3:
+				_error_("Using normal stress  not supported yet");
+				break;
+			default:
+				_error_("no case higher than 3 for SedimentlimitFlag");
+		}
+
+		/*Assign output pointer*/
+		*ph_max=h_max;
+
+}
+/*}}}*/
+/*FUNCTION Tria::BasisIntegral {{{*/
+void Tria::BasisIntegral(Vector<IssmDouble>* basisg){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble Jdet;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble basis[numdof];
+	IssmDouble basisint[numdof]={0.};
+	int       *doflist=NULL;
+	GaussTria* gauss=NULL;
+
+	GetDofList(&doflist,NoneApproximationEnum,GsetEnum);
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(&basis[0], gauss);
+
+		for(int i=0;i<numdof;i++) basisint[i]+=Jdet*gauss->weight*basis[i];
+	}
+
+	basisg->SetValues(numdof,doflist,&basisint[0],ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+	xDelete<int>(doflist);
+}
+/*}}}*/
+
+#endif
+
+#ifdef _HAVE_DAKOTA_
+/*FUNCTION Tria::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+
+	int i,j;
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			/*New TriaP1Input*/
+			IssmDouble values[3];
+
+			/*Get values on the 3 vertices*/
+			for (i=0;i<3;i++){
+				values[i]=vector[this->nodes[i]->GetVertexSid()]; //careful, vector of values here is not parallel distributed, but serial distributed (from a serial Dakota core!)
+			}
+
+			/*Branch on the specified type of update: */
+			switch(name){
+				case ThicknessEnum:
+					IssmDouble  thickness[3];
+					IssmDouble  thickness_init[3];
+					IssmDouble  hydrostatic_ratio[3];
+					IssmDouble  surface[3];
+					IssmDouble  bed[3];
+
+					/*retrieve inputs: */
+					GetInputListOnVertices(&thickness_init[0],ThicknessEnum);
+					GetInputListOnVertices(&hydrostatic_ratio[0],GeometryHydrostaticRatioEnum);
+					GetInputListOnVertices(&bed[0],BedEnum);
+					GetInputListOnVertices(&surface[0],SurfaceEnum);
+
+					/*build new bed and surface: */
+					if (this->IsFloating()){
+						/*hydrostatic equilibrium: */
+						IssmDouble rho_ice,rho_water,di;
+						rho_ice   = this->matpar->GetRhoIce();
+						rho_water = this->matpar->GetRhoWater();
+						di        = rho_ice/rho_water;
+
+						/*build new thickness: */
+						for (j=0; j<3; j++) {
+							/*  for observed/interpolated/hydrostatic thickness, remove scaling from any hydrostatic thickness  */
+							if (hydrostatic_ratio[j] >= 0.)
+								thickness[j]=values[j]-(values[j]/thickness_init[j]-1.)*hydrostatic_ratio[j]*surface[j]/(1.-di);
+							/*  for minimum thickness, don't scale  */
+							else
+								thickness[j]=thickness_init[j];
+
+							/*  check the computed thickness and update bed*/
+							if (thickness[j] < 0.) thickness[j]=1./(1.-di);
+							bed[j]=surface[j]-thickness[j];
+						}
+					}
+					else{
+						/*build new thickness: */
+						for (j=0; j<3; j++) {
+							/*  for observed thickness, use scaled value  */
+							if (hydrostatic_ratio[j] >= 0.)
+								thickness[j]=values[j];
+							/*  for minimum thickness, don't scale  */
+							else
+								thickness[j]=thickness_init[j];
+						}
+
+						/*update bed on grounded ice: */
+						for(j=0;j<3;j++)bed[j]=surface[j]-thickness[j];
+					}
+
+					/*Add new inputs: */
+					this->inputs->AddInput(new TriaP1Input(ThicknessEnum,thickness));
+					this->inputs->AddInput(new TriaP1Input(BedEnum,bed));
+					this->inputs->AddInput(new TriaP1Input(SurfaceEnum,surface));
+
+					break;
+				default:
+					this->inputs->AddInput(new TriaP1Input(name,values));
+			}
+			break;
+
+		default:
+			_error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVectorDakota(int* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	_error_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type);{{{*/
+void  Tria::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){
+
+	int i,j,t;
+	TransientInput* transientinput=NULL;
+	IssmDouble values[3];
+	IssmDouble time;
+	int row;
+	IssmDouble yts;
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			/*Create transient input: */
+
+			parameters->FindParam(&yts,ConstantsYtsEnum);
+			for(t=0;t<ncols;t++){ //ncols is the number of times
+
+				/*create input values: */
+				for(i=0;i<3;i++){
+					row=this->nodes[i]->GetVertexSid();
+					values[i]=(IssmDouble)matrix[ncols*row+t];
+				}
+
+				/*time? :*/
+				time=(IssmDouble)matrix[(nrows-1)*ncols+t]*yts;
+
+				if(t==0) transientinput=new TransientInput(name);
+				transientinput->AddTimeInput(new TriaP1Input(name,values),time);
+				transientinput->Configure(parameters);
+			}
+			this->inputs->AddInput(transientinput);
+			break;
+
+		default:
+			_error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_BALANCED_
+/*FUNCTION Tria::CreateKMatrixBalancethickness {{{*/
+ElementMatrix* Tria::CreateKMatrixBalancethickness(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreateKMatrixBalancethickness_CG();
+		case P1DGEnum:
+			return CreateKMatrixBalancethickness_DG();
+		default:
+			_error_("Element type " << EnumToStringx(GetElementType()) << " not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixBalancethickness_CG {{{*/
+ElementMatrix* Tria::CreateKMatrixBalancethickness_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        stabilization;
+	int        i,j,dim;
+	IssmDouble Jdettria,vx,vy,dvxdx,dvydy,vel,h;
+	IssmDouble dvx[2],dvy[2];
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble L[NUMVERTICES];
+	IssmDouble B[2][NUMVERTICES];
+	IssmDouble Bprime[2][NUMVERTICES];
+	IssmDouble K[2][2]                          = {0.0};
+	IssmDouble KDL[2][2]                        = {0.0};
+	IssmDouble DL[2][2]                         = {0.0};
+	IssmDouble DLprime[2][2]                    = {0.0};
+	IssmDouble DL_scalar;
+	GaussTria *gauss                            = NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all Inputs and parameters: */
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&stabilization,BalancethicknessStabilizationEnum);
+	this->parameters->FindParam(&dim,MeshDimensionEnum);
+	Input* vxaverage_input=NULL;
+	Input* vyaverage_input=NULL;
+	if(dim==2){
+		vxaverage_input=inputs->GetInput(VxEnum); _assert_(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyEnum); _assert_(vyaverage_input);
+	}
+	else{
+		vxaverage_input=inputs->GetInput(VxAverageEnum); _assert_(vxaverage_input);
+		vyaverage_input=inputs->GetInput(VyAverageEnum); _assert_(vyaverage_input);
+	}
+	h=sqrt(2*this->GetArea());
+
+	/*Start looping on the number of gaussian points:*/
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&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->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		vxaverage_input->GetInputDerivativeValue(&dvx[0],&xyz_list[0][0],gauss);
+		vyaverage_input->GetInputDerivativeValue(&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->values[0],1);
+
+		TripleMultiply( &B[0][0],2,numdof,1,
+					&DLprime[0][0],2,2,0,
+					&Bprime[0][0],2,numdof,0,
+					&Ke->values[0],1);
+
+		if(stabilization==1){
+			/*Streamline upwinding*/
+			vel=sqrt(vx*vx+vy*vy);
+			K[0][0]=h/(2*vel)*vx*vx;
+			K[1][0]=h/(2*vel)*vy*vx;
+			K[0][1]=h/(2*vel)*vx*vy;
+			K[1][1]=h/(2*vel)*vy*vy;
+		}
+		else if(stabilization==2){
+			/*MacAyeal*/
+			vxaverage_input->GetInputAverage(&vx);
+			vyaverage_input->GetInputAverage(&vy);
+			K[0][0]=h/2.0*fabs(vx);
+			K[0][1]=0.;
+			K[1][0]=0.;
+			K[1][1]=h/2.0*fabs(vy);
+		}
+		if(stabilization==1 || stabilization==2){
+			KDL[0][0]=DL_scalar*K[0][0];
+			KDL[1][0]=DL_scalar*K[1][0];
+			KDL[0][1]=DL_scalar*K[0][1];
+			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->values[0],1);
+		}
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreateKMatrixBalancethickness_DG {{{*/
+ElementMatrix* Tria::CreateKMatrixBalancethickness_DG(void){
+
+	/*Constants*/
+	const int  numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries*/
+	int        i,j,dim;
+	IssmDouble vx,vy,Jdettria;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble B[2][NUMVERTICES];
+	IssmDouble Bprime[2][NUMVERTICES];
+	IssmDouble DL[2][2]={0.0};
+	IssmDouble DL_scalar;
+	GaussTria  *gauss=NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	this->parameters->FindParam(&dim,MeshDimensionEnum);
+	Input* vx_input=inputs->GetInput(VxEnum); _assert_(vx_input);
+	Input* vy_input=inputs->GetInput(VyEnum); _assert_(vy_input);
+
+	/*Start looping on the number of gaussian points:*/
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&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->GetInputValue(&vx,gauss);
+		vy_input->GetInputValue(&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->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancethickness{{{*/
+ElementVector* Tria::CreatePVectorBalancethickness(void){
+
+	switch(GetElementType()){
+		case P1Enum:
+			return CreatePVectorBalancethickness_CG();
+			break;
+		case P1DGEnum:
+			return CreatePVectorBalancethickness_DG();
+		default:
+			_error_("Element type " << EnumToStringx(GetElementType()) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancethickness_CG{{{*/
+ElementVector* Tria::CreatePVectorBalancethickness_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble dhdt_g,basal_melting_g,surface_mass_balance_g,Jdettria;
+	IssmDouble L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* surface_mass_balance_input=inputs->GetInput(SurfaceforcingsMassBalanceEnum); _assert_(surface_mass_balance_input);
+	Input* basal_melting_input=inputs->GetInput(BasalforcingsMeltingRateEnum);          _assert_(basal_melting_input);
+	Input* dhdt_input=inputs->GetInput(BalancethicknessThickeningRateEnum);             _assert_(dhdt_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		surface_mass_balance_input->GetInputValue(&surface_mass_balance_g,gauss);
+		basal_melting_input->GetInputValue(&basal_melting_g,gauss);
+		dhdt_input->GetInputValue(&dhdt_g,gauss);
+
+		GetJacobianDeterminant(&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*(surface_mass_balance_g-basal_melting_g-dhdt_g)*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorBalancethickness_DG {{{*/
+ElementVector* Tria::CreatePVectorBalancethickness_DG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble basal_melting_g,surface_mass_balance_g,dhdt_g,Jdettria;
+	IssmDouble L[NUMVERTICES];
+	GaussTria* gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* surface_mass_balance_input=inputs->GetInput(SurfaceforcingsMassBalanceEnum); _assert_(surface_mass_balance_input);
+	Input* basal_melting_input=inputs->GetInput(BasalforcingsMeltingRateEnum);          _assert_(basal_melting_input);
+	Input* dhdt_input=inputs->GetInput(BalancethicknessThickeningRateEnum);                                       _assert_(dhdt_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(int ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		surface_mass_balance_input->GetInputValue(&surface_mass_balance_g,gauss);
+		basal_melting_input->GetInputValue(&basal_melting_g,gauss);
+		dhdt_input->GetInputValue(&dhdt_g,gauss);
+
+		GetJacobianDeterminant(&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*(surface_mass_balance_g-basal_melting_g-dhdt_g)*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+#endif
Index: /issm/trunk-jpl/src/c/classes/Elements/Tria.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/Tria.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/Tria.h	(revision 15012)
@@ -0,0 +1,263 @@
+/*! \file Tria.h 
+ *  \brief: header file for tria object
+ */
+
+#ifndef _TRIA_H_
+#define _TRIA_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Element.h"
+#include "./TriaHook.h"
+#include "./TriaRef.h"
+class Parameters;
+class Inputs;
+class IoModel;
+class Node;
+class Material;
+class Matpar;
+class ElementMatrix;
+class ElementVector;
+class Vertex;
+
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+/*}}}*/
+
+class Tria: public Element,public TriaHook,public TriaRef{
+
+	public:
+
+		int          id;
+		int          sid;
+
+		Node       **nodes;                       // nodes
+		Vertex     **vertices;                    // 3 vertices
+		Material    *material;                    // 1 material ice
+		Matpar      *matpar;                      // 1 material parameter
+		int          horizontalneighborsids[3];
+
+		Parameters  *parameters;                  //pointer to solution parameters
+		Inputs      *inputs;
+		Results     *results;
+
+		/*Tria constructors, destructors {{{*/
+		Tria();
+		Tria(int tria_id,int tria_sid,int i, IoModel* iomodel,int nummodels);
+		~Tria();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void  InputUpdateFromSolution(IssmDouble* solutiong);
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		#ifdef _HAVE_DAKOTA_
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix, int nows, int ncols, int name, int type);
+		#endif
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel);
+		/*}}}*/
+		/*Element virtual functions definitions: {{{*/
+		void   AverageOntoPartition(Vector<IssmDouble>* partition_contributions,Vector<IssmDouble>* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part);
+		void   ComputeBasalStress(Vector<IssmDouble>* sigma_b);
+		void   ComputeStrainRate(Vector<IssmDouble>* eps);
+		void   ComputeStressTensor();
+		void   Configure(Elements* elements,Loads* loads,Nodes* nodesin,Vertices* verticesin,Materials* materials,Parameters* parameters);
+		void   SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Materials* materials,Parameters* parameters);
+		void   SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		void   CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void   CreateDVector(Vector<IssmDouble>* df);
+		void   CreatePVector(Vector<IssmDouble>* pf);
+		void   CreateJacobianMatrix(Matrix<IssmDouble>* Jff);
+		void   Delta18oParameterization(void);
+		int    GetNodeIndex(Node* node);
+		int    GetNumberOfNodes(void);
+		void   GetNodesSidList(int* sidlist);
+		int    Sid();
+		bool   IsOnBed();
+		bool   IsFloating(); 
+		bool   IsNodeOnShelf(); 
+		bool   IsNodeOnShelfFromFlags(IssmDouble* flags);
+		bool   IsOnWater(); 
+		void   GetSolutionFromInputs(Vector<IssmDouble>* solution);
+		void   GetVectorFromInputs(Vector<IssmDouble>* vector, int name_enum);
+		void   GetVectorFromResults(Vector<IssmDouble>* vector,int offset,int enum_in,int interp);
+		void   InputArtificialNoise(int enum_type,IssmDouble min, IssmDouble max);
+		bool   InputConvergence(IssmDouble* eps, int* enums,int num_enums,int* criterionenums,IssmDouble* criterionvalues,int num_criterionenums);
+		void   InputCreate(IssmDouble scalar,int name,int code);
+		void   InputCreate(IssmDouble* vector, int index,IoModel* iomodel,int M,int N,int vector_type,int vector_enum,int code);
+		void   InputDepthAverageAtBase(int enum_type,int average_enum_type,int object_enum=MeshElementsEnum);
+		void   InputDuplicate(int original_enum,int new_enum);
+		void   InputScale(int enum_type,IssmDouble scale_factor);
+		void   InputToResult(int enum_type,int step,IssmDouble time);
+		void   DeleteResults(void);
+		void   MaterialUpdateFromTemperature(void){_error_("not implemented yet");};
+		void   MigrateGroundingLine(IssmDouble* oldfloating,IssmDouble* sheet_ungrounding);
+		int    NodalValue(IssmDouble* pvalue, int index, int natureofdataenum,bool process_units);
+		void   PotentialUngrounding(Vector<IssmDouble>* potential_sheet_ungrounding);
+		void   PositiveDegreeDay(IssmDouble* pdds,IssmDouble* pds,IssmDouble signorm);
+		void   RequestedOutput(int output_enum,int step,IssmDouble time);
+		void   ListResultsInfo(int** results_enums,int** results_size,IssmDouble** results_times,int** results_steps,int* num_results);
+		void   PatchFill(int* pcount, Patch* patch);
+		void   PatchSize(int* pnumrows, int* pnumvertices,int* pnumnodes);
+		void   ProcessResultsUnits(void);
+		void   ResetCoordinateSystem(void){_error_("not implemented yet");};
+		void	 SmbGradients();
+		IssmDouble SurfaceArea(void);
+		void   Update(int index, IoModel* iomodel,int analysis_counter,int analysis_type);
+		int    UpdatePotentialUngrounding(IssmDouble* vertices_potentially_ungrounding,Vector<IssmDouble>* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf);
+		IssmDouble TimeAdapt();
+		int*   GetHorizontalNeighboorSids(void);
+		void   SmearFunction(Vector<IssmDouble>* smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius);
+
+		#ifdef _HAVE_RESPONSES_
+		IssmDouble IceVolume(void);
+		IssmDouble TotalSmb(void);
+		void   MinVel(IssmDouble* pminvel, bool process_units);
+		void   MinVx(IssmDouble* pminvx, bool process_units);
+		void   MinVy(IssmDouble* pminvy, bool process_units);
+		void   MinVz(IssmDouble* pminvz, bool process_units);
+		IssmDouble MassFlux(IssmDouble* segment,bool process_units);
+		void   MaxAbsVx(IssmDouble* pmaxabsvx, bool process_units);
+		void   MaxAbsVy(IssmDouble* pmaxabsvy, bool process_units);
+		void   MaxAbsVz(IssmDouble* pmaxabsvz, bool process_units);
+		void   ElementResponse(IssmDouble* presponse,int response_enum,bool process_units);
+		void   MaxVel(IssmDouble* pmaxvel, bool process_units);
+		void   MaxVx(IssmDouble* pmaxvx, bool process_units);
+		void   MaxVy(IssmDouble* pmaxvy, bool process_units);
+		void   MaxVz(IssmDouble* pmaxvz, bool process_units);
+		#endif
+
+		#ifdef _HAVE_GIA_
+		void   GiaDeflection(Vector<IssmDouble>* wg,Vector<IssmDouble>* dwgdt,IssmDouble* x,IssmDouble* y);
+		#endif
+
+		#ifdef _HAVE_CONTROL_
+		IssmDouble DragCoefficientAbsGradient(bool process_units,int weight_index);
+		void   GradientIndexing(int* indexing,int control_index);
+		void   Gradj(Vector<IssmDouble>* gradient,int control_type,int control_index);
+		void   GradjBGradient(Vector<IssmDouble>* gradient,int weight_index,int control_index);
+		void   GradjZGradient(Vector<IssmDouble>* gradient,int weight_index,int control_index);
+		void   GradjBMacAyeal(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjZMacAyeal(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjDragMacAyeal(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjDragStokes(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjDragGradient(Vector<IssmDouble>* gradient,int weight_index,int control_index);
+		void   GradjDhDtBalancedthickness(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjVxBalancedthickness(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjVyBalancedthickness(Vector<IssmDouble>* gradient,int control_index);
+		void   GradjThicknessWeakBalancedthickness(Vector<IssmDouble>* gradient,int control_index);
+		void   GetVectorFromControlInputs(Vector<IssmDouble>* gradient,int control_enum,int control_index,const char* data);
+		void   SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index);
+		void   ControlInputGetGradient(Vector<IssmDouble>* gradient,int enum_type,int control_index);
+		void   ControlInputScaleGradient(int enum_type,IssmDouble scale);
+		void   ControlInputSetGradient(IssmDouble* gradient,int enum_type,int control_index);
+		IssmDouble RheologyBbarAbsGradient(bool process_units,int weight_index);
+		IssmDouble ThicknessAbsMisfit(     bool process_units,int weight_index);
+		IssmDouble SurfaceAbsVelMisfit(    bool process_units,int weight_index);
+		IssmDouble ThicknessAbsGradient(   bool process_units,int weight_index);
+		IssmDouble ThicknessAlongGradient( bool process_units,int weight_index);
+		IssmDouble ThicknessAcrossGradient(bool process_units,int weight_index);
+		IssmDouble BalancethicknessMisfit(     bool process_units,int weight_index);
+		IssmDouble SurfaceRelVelMisfit(    bool process_units,int weight_index);
+		IssmDouble SurfaceLogVelMisfit(    bool process_units,int weight_index);
+		IssmDouble SurfaceLogVxVyMisfit(   bool process_units,int weight_index);
+		IssmDouble SurfaceAverageVelMisfit(bool process_units,int weight_index);
+		void   InputControlUpdate(IssmDouble scalar,bool save_parameter);
+		#endif
+
+		/*}}}*/
+		/*Tria specific routines:{{{*/
+		ElementMatrix* CreateKMatrixBalancethickness(void);
+		ElementMatrix* CreateKMatrixBalancethickness_DG(void);
+		ElementMatrix* CreateKMatrixBalancethickness_CG(void);
+		ElementMatrix* CreateKMatrixMelting(void);
+		ElementMatrix* CreateKMatrixPrognostic(void);
+		ElementMatrix* CreateKMatrixPrognostic_CG(void);
+		ElementMatrix* CreateKMatrixPrognostic_DG(void);
+		ElementMatrix* CreateMassMatrix(void);
+		ElementVector* CreatePVectorBalancethickness(void);
+		ElementVector* CreatePVectorBalancethickness_DG(void);
+		ElementVector* CreatePVectorBalancethickness_CG(void);
+		ElementVector* CreatePVectorPrognostic(void);
+		ElementVector* CreatePVectorPrognostic_CG(void);
+		ElementVector* CreatePVectorPrognostic_DG(void);
+		ElementVector* CreatePVectorSlope(void);
+		IssmDouble     GetArea(void);
+		int            GetElementType(void);
+		void	         GetDofList(int** pdoflist,int approximation_enum,int setenum);
+		void	         GetVertexPidList(int* doflist);
+		void           GetVertexSidList(int* sidlist);
+		void           GetConnectivityList(int* connectivity);
+		IssmDouble     GetGroundedPortion(IssmDouble* xyz_list);
+		void           GetInputListOnVertices(IssmDouble* pvalue,int enumtype);
+		void           GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue);
+		void           GetInputListOnVertices(IssmDouble* pvalue,int enumtype,IssmDouble defaultvalue,int index); //TO BE REMOVED
+		void           GetInputValue(IssmDouble* pvalue,Node* node,int enumtype);
+		void           GetStrainRate2d(IssmDouble* epsilon,IssmDouble* xyz_list, GaussTria* gauss, Input* vx_input, Input* vy_input);
+		void	         InputUpdateFromSolutionOneDof(IssmDouble* solution,int enum_type);
+		void	         InputUpdateFromSolutionPrognostic(IssmDouble* solution);
+		bool	         IsInput(int name);
+		void	         SetClone(int* minranks);
+		void	         SurfaceNormal(IssmDouble* surface_normal, IssmDouble xyz_list[3][3]);
+
+		#ifdef _HAVE_DIAGNOSTIC_
+		ElementMatrix* CreateKMatrixDiagnosticMacAyeal(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyealViscous(void);
+		ElementMatrix* CreateKMatrixDiagnosticMacAyealFriction(void);
+		ElementMatrix* CreateKMatrixDiagnosticHutter(void);
+		ElementVector* CreatePVectorDiagnosticMacAyeal(void);
+		ElementVector* CreatePVectorDiagnosticHutter(void);
+		ElementMatrix* CreateJacobianDiagnosticMacayeal(void);
+		void	  GetSolutionFromInputsDiagnosticHoriz(Vector<IssmDouble>* solution);
+		void	  GetSolutionFromInputsDiagnosticHutter(Vector<IssmDouble>* solution);
+		void	  InputUpdateFromSolutionDiagnosticHoriz( IssmDouble* solution);
+		void	  InputUpdateFromSolutionDiagnosticHutter( IssmDouble* solution);
+		#endif
+
+		#ifdef _HAVE_CONTROL_
+		ElementMatrix* CreateKMatrixAdjointBalancethickness(void);
+		ElementMatrix* CreateKMatrixAdjointMacAyeal(void);
+		ElementVector* CreatePVectorAdjointHoriz(void);
+		ElementVector* CreatePVectorAdjointStokes(void);
+		ElementVector* CreatePVectorAdjointBalancethickness(void);
+		void	  InputUpdateFromSolutionAdjointBalancethickness( IssmDouble* solution);
+		void	  InputUpdateFromSolutionAdjointHoriz( IssmDouble* solution);
+		#endif
+
+		#ifdef _HAVE_HYDROLOGY_
+		ElementMatrix* CreateKMatrixHydrologyShreve(void);
+		ElementMatrix* CreateKMatrixHydrologyDCInefficient(void);
+		ElementMatrix* CreateKMatrixHydrologyDCEfficient(void);
+		ElementVector* CreatePVectorHydrologyShreve(void);
+		ElementVector* CreatePVectorHydrologyDCInefficient(void);
+		ElementVector* CreatePVectorHydrologyDCEfficient(void);
+		void	  GetSolutionFromInputsHydrologyShreve(Vector<IssmDouble>* solution);
+		void    CreateHydrologyWaterVelocityInput(void);
+		void	  InputUpdateFromSolutionHydrology(IssmDouble* solution);
+		void	  InputUpdateFromSolutionHydrologyShreve(IssmDouble* solution);
+		void    InputUpdateFromSolutionHydrologyDC(IssmDouble* solution);
+		void	  InputUpdateFromSolutionHydrologyDCInefficient(IssmDouble* solution);
+		void	  InputUpdateFromSolutionHydrologyDCEfficient(IssmDouble* solution);
+		void    GetHydrologyDCInefficientHmax(IssmDouble* ph_max, Node* innode);
+		void    BasisIntegral(Vector<IssmDouble>* gbasis);
+		#endif
+		#ifdef _HAVE_BALANCED_
+		#endif
+
+		/*}}}*/
+
+};
+#endif  /* _TRIA_H */
Index: /issm/trunk-jpl/src/c/classes/Elements/TriaHook.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/TriaHook.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/TriaHook.cpp	(revision 15012)
@@ -0,0 +1,80 @@
+/*!\file TriaHook.c
+ * \brief: implementation of the TriaHook object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION TriaHook::TriaHook(){{{*/
+TriaHook::TriaHook(){
+	numanalyses=UNDEF;
+	this->hnodes    = NULL;
+	this->hvertices = NULL;
+	this->hmaterial = NULL;
+	this->hmatpar   = NULL;
+}
+/*}}}*/
+/*FUNCTION TriaHook::~TriaHook(){{{*/
+TriaHook::~TriaHook(){
+	int i;
+
+	for(i=0;i<this->numanalyses;i++){
+		if (this->hnodes[i]) delete this->hnodes[i];
+	}
+	delete [] hnodes;
+	delete hvertices;
+	delete hmaterial;
+	delete hmatpar;
+
+}
+/*}}}*/
+/*FUNCTION TriaHook::TriaHook(int in_numanalyses,int element_id, int matpar_id){{{*/
+TriaHook::TriaHook(int in_numanalyses,int element_id, IoModel* iomodel){
+
+	/*intermediary: */
+	int matpar_id;
+	int material_id;
+	int tria_vertex_ids[3];
+
+	/*retrieve material_id: */
+	iomodel->Constant(&matpar_id,MeshNumberofelementsEnum); matpar_id++;
+
+	/*retrive material_id*/
+	material_id = element_id;
+
+	/*retrieve vertices ids*/
+	for(int i=0;i<3;i++){ 
+		tria_vertex_ids[i]=reCast<int>(iomodel->Data(MeshElementsEnum)[3*(element_id-1)+i]);
+	}
+
+	this->numanalyses = in_numanalyses;
+	this->hnodes      = new Hook*[in_numanalyses];
+	this->hvertices   = new Hook(&tria_vertex_ids[0],3);
+	this->hmaterial   = new Hook(&material_id,1);
+	this->hmatpar     = new Hook(&matpar_id,1);
+
+	//Initialize hnodes as NULL
+	for(int i=0;i<this->numanalyses;i++){
+		this->hnodes[i]=NULL;
+	}
+
+}
+/*}}}*/
+
+/*FUNCTION TriaHook::SetHookNodes{{{*/
+void TriaHook::SetHookNodes(int* node_ids,int analysis_counter){
+
+	/*initialize hook*/
+	this->hnodes[analysis_counter]=new Hook(node_ids,3);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Elements/TriaHook.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/TriaHook.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/TriaHook.h	(revision 15012)
@@ -0,0 +1,29 @@
+/*!\file: TriaHook.h
+ * \brief prototypes for TriaHook.h
+ */ 
+
+#ifndef _TRIAHOOK_H_
+#define  _TRIAHOOK_H_
+
+class Hook;
+class IoModel;
+
+class TriaHook{
+
+	public: 
+		int    numanalyses;   //number of analysis types
+		Hook **hnodes;        // nodes for each analysis type
+		Hook  *hvertices;     // 3 vertices
+		Hook  *hmaterial;     // 1 ice material
+		Hook  *hmatpar;       // 1 material parameter
+
+		/*FUNCTION constructors, destructors {{{*/
+		TriaHook();
+		TriaHook(int in_numanalyses,int material_id, IoModel* iomodel);
+		~TriaHook();
+		void SetHookNodes(int* node_ids,int analysis_counter);
+		/*}}}*/
+
+};
+
+#endif //ifndef _TRIAHOOK_H_
Index: /issm/trunk-jpl/src/c/classes/Elements/TriaRef.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/TriaRef.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/TriaRef.cpp	(revision 15012)
@@ -0,0 +1,551 @@
+/*!\file TriaRef.c
+ * \brief: implementation of the TriaRef object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMNODESP1 3
+#define NUMNODESP2 6
+
+/*Object constructors and destructor*/
+/*FUNCTION TriaRef::TriaRef(){{{*/
+TriaRef::TriaRef(){
+	this->element_type_list=NULL;
+}
+/*}}}*/
+/*FUNCTION TriaRef::TriaRef(int* types,int nummodels){{{*/
+
+TriaRef::TriaRef(const int nummodels){
+
+	/*Only allocate pointer*/
+	element_type_list=xNew<int>(nummodels);
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::~TriaRef(){{{*/
+TriaRef::~TriaRef(){
+	xDelete<int>(element_type_list);
+}
+/*}}}*/
+
+/*Management*/
+/*FUNCTION TriaRef::SetElementType{{{*/
+void TriaRef::SetElementType(int type,int type_counter){
+
+	_assert_(type==P1Enum || type==P1DGEnum);
+
+	/*initialize element type*/
+	this->element_type_list[type_counter]=type;
+}
+/*}}}*/
+
+/*Reference Element numerics*/
+/*FUNCTION TriaRef::GetBHydro {{{*/
+void TriaRef::GetBHydro(IssmDouble* B, IssmDouble* xyz_list, GaussTria* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3] where Bi is of size 3*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ dh/dx ]
+	 *          [ dh/dy ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 3x(NDOF2*NUMNODESP1)
+	 */
+
+	int i;
+	IssmDouble dbasis[NDOF2][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinate system: */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B: */
+	for (i=0;i<NUMNODESP1;i++){
+		B[NDOF1*NUMNODESP1*0+NDOF1*i]=dbasis[0][i]; 
+		B[NDOF1*NUMNODESP1*1+NDOF1*i]=dbasis[1][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetBMacAyeal {{{*/
+void TriaRef::GetBMacAyeal(IssmDouble* B, IssmDouble* xyz_list, GaussTria* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3] where Bi is of size 3*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ dh/dx           0    ]
+	 *          [   0           dh/dy  ]
+	 *          [ 1/2*dh/dy  1/2*dh/dx ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 3x(NDOF2*NUMNODESP1)
+	 */
+
+	int i;
+	IssmDouble dbasis[NDOF2][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinate system: */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B: */
+	for (i=0;i<NUMNODESP1;i++){
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i)=dbasis[0][i]; //B[0][NDOF2*i]=dbasis[0][i];
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i+1)=0;
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i)=0;
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i+1)=dbasis[1][i];
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i)=(float).5*dbasis[1][i]; 
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i+1)=(float).5*dbasis[0][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetBMacAyealStokes {{{*/
+void TriaRef::GetBMacAyealStokes(IssmDouble* B, IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*Compute B  matrix. B=[B1 B2 B3] where Bi is of size 3*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[   dh/dx         0     ]
+	 *          [       0       dh/dy   ]
+	 *          [  1/2*dh/dy  1/2*dh/dx ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B has been allocated already, of size: 3x(NDOF2*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i)=dbasis[0][i]; 
+		*(B+NDOF2*NUMNODESP1*0+NDOF2*i+1)=0; 
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i)=0; 
+		*(B+NDOF2*NUMNODESP1*1+NDOF2*i+1)=dbasis[1][i]; 
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i)=0.5*dbasis[1][i]; 
+		*(B+NDOF2*NUMNODESP1*2+NDOF2*i+1)=0.5*dbasis[0][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetSegmentBFlux{{{*/
+void TriaRef::GetSegmentBFlux(IssmDouble* B,GaussTria* gauss, int index1,int index2){
+	/*Compute B  matrix. B=[phi1 phi2 -phi3 -phi4]
+	 *
+	 * and phi1=phi3 phi2=phi4
+	 *
+	 * We assume B has been allocated already, of size: 1x4
+	 */
+
+	IssmDouble l1l3[NUMNODESP1];
+
+	GetNodalFunctions(&l1l3[0],gauss);
+
+	B[0] = +l1l3[index1];
+	B[1] = +l1l3[index2];
+	B[2] = -l1l3[index1];
+	B[3] = -l1l3[index2];
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetSegmentBprimeFlux{{{*/
+void TriaRef::GetSegmentBprimeFlux(IssmDouble* Bprime,GaussTria* gauss, int index1,int index2){
+	/*Compute Bprime  matrix. Bprime=[phi1 phi2 phi3 phi4]
+	 *
+	 * and phi1=phi3 phi2=phi4
+	 *
+	 * We assume Bprime has been allocated already, of size: 1x4
+	 */
+
+	IssmDouble l1l3[NUMNODESP1];
+
+	GetNodalFunctions(&l1l3[0],gauss);
+
+	Bprime[0] = l1l3[index1];
+	Bprime[1] = l1l3[index2];
+	Bprime[2] = l1l3[index1];
+	Bprime[3] = l1l3[index2];
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetBPrognostic{{{*/
+void TriaRef::GetBPrognostic(IssmDouble* B_prog, IssmDouble* xyz_list, GaussTria* gauss){
+	/*Compute B  matrix. B=[B1 B2 B3] where Bi is of size 3*NDOF2. 
+	 * For node i, Bi can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi=[ h ]
+	 *          [ h ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B_prog has been allocated already, of size: 2x(NDOF1*NUMNODESP1)
+	 */
+
+	IssmDouble basis[NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinate system: */
+	GetNodalFunctions(&basis[0],gauss);
+
+	/*Build B_prog: */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(B_prog+NDOF1*NUMNODESP1*0+NDOF1*i)=basis[i];
+		*(B_prog+NDOF1*NUMNODESP1*1+NDOF1*i)=basis[i];
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetBprimeMacAyeal {{{*/
+void TriaRef::GetBprimeMacAyeal(IssmDouble* Bprime, IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*Compute B'  matrix. B'=[B1' B2' B3'] where Bi' is of size 3*NDOF2. 
+	 * For node i, Bi' can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi_prime=[ 2*dh/dx    dh/dy ]
+	 *                [   dh/dx  2*dh/dy ]
+	 *                [   dh/dy    dh/dx ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B' has been allocated already, of size: 3x(NDOF2*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(Bprime+NDOF2*NUMNODESP1*0+NDOF2*i)=2*dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*0+NDOF2*i+1)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*1+NDOF2*i)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*1+NDOF2*i+1)=2*dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*2+NDOF2*i)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*2+NDOF2*i+1)=dbasis[0][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetBprimeMacAyealStokes {{{*/
+void TriaRef::GetBprimeMacAyealStokes(IssmDouble* Bprime, IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*Compute Bprime  matrix. Bprime=[Bprime1 Bprime2 Bprime3] where Bprimei is of size 3*NDOF2. 
+	 * For node i, Bprimei can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bprimei=[  dh/dx    0   ]
+	 *               [    0    dh/dy ]
+	 *               [  dh/dy  dh/dx ]
+	 *               [  dh/dx  dh/dy ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume Bprime has been allocated already, of size: 3x(NDOF2*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build Bprime: */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(Bprime+NDOF2*NUMNODESP1*0+NDOF2*i)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*0+NDOF2*i+1)=0; 
+		*(Bprime+NDOF2*NUMNODESP1*1+NDOF2*i)=0; 
+		*(Bprime+NDOF2*NUMNODESP1*1+NDOF2*i+1)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*2+NDOF2*i)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*2+NDOF2*i+1)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*3+NDOF2*i)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODESP1*3+NDOF2*i+1)=dbasis[1][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetBprimePrognostic{{{*/
+void TriaRef::GetBprimePrognostic(IssmDouble* Bprime_prog, IssmDouble* xyz_list, GaussTria* gauss){
+	/*Compute B'  matrix. B'=[B1' B2' B3'] where Bi' is of size 3*NDOF2. 
+	 * For node i, Bi' can be expressed in the actual coordinate system
+	 * by: 
+	 *       Bi_prime=[ dh/dx ]
+	 *                [ dh/dy ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume B' has been allocated already, of size: 3x(NDOF2*NUMNODESP1)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODESP1];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODESP1;i++){
+		*(Bprime_prog+NDOF1*NUMNODESP1*0+NDOF1*i)=dbasis[0][i]; 
+		*(Bprime_prog+NDOF1*NUMNODESP1*1+NDOF1*i)=dbasis[1][i]; 
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetL{{{*/
+void TriaRef::GetL(IssmDouble* L, IssmDouble* xyz_list,GaussTria* gauss,int numdof){
+	/*Compute L  matrix. L=[L1 L2 L3] where Li is square and of size numdof. 
+	 * For node i, Li can be expressed in the actual coordinate system
+	 * by: 
+	 *       numdof=1: 
+	 *                 Li=h;
+	 *       numdof=2:
+	 *                 Li=[ h   0 ]
+	 *                    [ 0   h ]
+	 * where h is the interpolation function for node i.
+	 *
+	 * We assume L has been allocated already, of size: NUMNODESP1 (numdof=1), or numdofx(numdof*NUMNODESP1) (numdof=2)
+	 */
+
+	int i;
+	IssmDouble basis[3];
+
+	/*Get basis in actual coordinate system: */
+	GetNodalFunctions(basis,gauss);
+
+	/*Build L: */
+	if(numdof==1){
+		for (i=0;i<NUMNODESP1;i++){
+			L[i]=basis[i]; 
+		}
+	}
+	else{
+		for (i=0;i<NUMNODESP1;i++){
+			*(L+numdof*NUMNODESP1*0+numdof*i)=basis[i]; //L[0][NDOF2*i]=dbasis[0][i];
+			*(L+numdof*NUMNODESP1*0+numdof*i+1)=0;
+			*(L+numdof*NUMNODESP1*1+numdof*i)=0;
+			*(L+numdof*NUMNODESP1*1+numdof*i+1)=basis[i];
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetJacobian{{{*/
+void TriaRef::GetJacobian(IssmDouble* J, IssmDouble* xyz_list,GaussTria* gauss){
+	/*The Jacobian is constant over the element, discard the gaussian points. 
+	 * J is assumed to have been allocated of size NDOF2xNDOF2.*/
+	IssmDouble x1,y1,x2,y2,x3,y3;
+
+	x1=*(xyz_list+NUMNODESP1*0+0);
+	y1=*(xyz_list+NUMNODESP1*0+1);
+	x2=*(xyz_list+NUMNODESP1*1+0);
+	y2=*(xyz_list+NUMNODESP1*1+1);
+	x3=*(xyz_list+NUMNODESP1*2+0);
+	y3=*(xyz_list+NUMNODESP1*2+1);
+
+	*(J+NDOF2*0+0)=0.5*(x2-x1);
+	*(J+NDOF2*1+0)=SQRT3/6.0*(2*x3-x1-x2);
+	*(J+NDOF2*0+1)=0.5*(y2-y1);
+	*(J+NDOF2*1+1)=SQRT3/6.0*(2*y3-y1-y2);
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetSegmentJacobianDeterminant{{{*/
+void TriaRef::GetSegmentJacobianDeterminant(IssmDouble* Jdet, IssmDouble* xyz_list,GaussTria* gauss){
+	/*The Jacobian determinant is constant over the element, discard the gaussian points. 
+	 * J is assumed to have been allocated*/
+	IssmDouble x1,y1,x2,y2;
+
+	x1=*(xyz_list+3*0+0);
+	y1=*(xyz_list+3*0+1);
+	x2=*(xyz_list+3*1+0);
+	y2=*(xyz_list+3*1+1);
+
+	*Jdet=1.0/2.0*sqrt(pow(x2-x1,2.) + pow(y2-y1,2.));
+	if(*Jdet<0) _error_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetJacobianDeterminant{{{*/
+void TriaRef::GetJacobianDeterminant(IssmDouble* Jdet, IssmDouble* xyz_list,GaussTria* gauss){
+	/*The Jacobian determinant is constant over the element, discard the gaussian points. 
+	 * J is assumed to have been allocated of size NDOF2xNDOF2.*/
+	IssmDouble J[2][2];
+
+	/*Get Jacobian*/
+	GetJacobian(&J[0][0],xyz_list,gauss);
+
+	/*Get Determinant*/
+	Matrix2x2Determinant(Jdet,&J[0][0]);
+	if(*Jdet<0) _error_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetJacobianInvert{{{*/
+void TriaRef::GetJacobianInvert(IssmDouble*  Jinv, IssmDouble* xyz_list,GaussTria* gauss){
+
+	/*Jacobian*/
+	IssmDouble J[2][2];
+
+	/*Call Jacobian routine to get the jacobian:*/
+	GetJacobian(&J[0][0], xyz_list, gauss);
+
+	/*Invert Jacobian matrix: */
+	Matrix2x2Invert(Jinv,&J[0][0]);
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetNodalFunctions{{{*/
+void TriaRef::GetNodalFunctions(IssmDouble* basis,GaussTria* gauss){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	basis[0]=gauss->coord1;
+	basis[1]=gauss->coord2;
+	basis[2]=gauss->coord3;
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetNodalFunctionsP2{{{*/
+void TriaRef::GetNodalFunctionsP2(IssmDouble** pbasis,GaussTria* gauss){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	/*Allocate*/
+	IssmDouble* basis =xNew<IssmDouble>(NUMNODESP2);
+
+	basis[0]=gauss->coord1*(2.*gauss->coord1-1.);
+	basis[1]=gauss->coord2*(2.*gauss->coord2-1.);
+	basis[2]=gauss->coord3*(2.*gauss->coord3-1.);
+	basis[3]=4.*gauss->coord3*gauss->coord2;
+	basis[4]=4.*gauss->coord3*gauss->coord1;
+	basis[5]=4.*gauss->coord1*gauss->coord2;
+
+	/*Assign output pointer*/
+	*pbasis = basis;
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetSegmentNodalFunctions{{{*/
+void TriaRef::GetSegmentNodalFunctions(IssmDouble* basis,GaussTria* gauss,int index1,int index2){
+	/*This routine returns the values of the nodal functions  at the gaussian point.*/
+
+	IssmDouble BasisFunctions[3];
+
+	GetNodalFunctions(&BasisFunctions[0],gauss);
+
+	_assert_(index1>=0 && index1<3);
+	_assert_(index2>=0 && index2<3);
+	basis[0]=BasisFunctions[index1];
+	basis[1]=BasisFunctions[index2];
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetNodalFunctionsDerivatives{{{*/
+void TriaRef::GetNodalFunctionsDerivatives(IssmDouble* dbasis,IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * actual coordinate system): */
+	int       i;
+	IssmDouble    dbasis_ref[NDOF2][NUMNODESP1];
+	IssmDouble    Jinv[NDOF2][NDOF2];
+
+	/*Get derivative values with respect to parametric coordinate system: */
+	GetNodalFunctionsDerivativesReference(&dbasis_ref[0][0], gauss); 
+
+	/*Get Jacobian invert: */
+	GetJacobianInvert(&Jinv[0][0], xyz_list, gauss);
+
+	/*Build dbasis: 
+	 *
+	 * [dhi/dx]= Jinv*[dhi/dr]
+	 * [dhi/dy]       [dhi/ds]
+	 */
+	for (i=0;i<NUMNODESP1;i++){
+		dbasis[NUMNODESP1*0+i]=Jinv[0][0]*dbasis_ref[0][i]+Jinv[0][1]*dbasis_ref[1][i];
+		dbasis[NUMNODESP1*1+i]=Jinv[1][0]*dbasis_ref[0][i]+Jinv[1][1]*dbasis_ref[1][i];
+	}
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetNodalFunctionsDerivativesReference{{{*/
+void TriaRef::GetNodalFunctionsDerivativesReference(IssmDouble* dl1dl3,GaussTria* gauss){
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * natural coordinate system) at the gaussian point. */
+
+	/*First nodal function: */
+	*(dl1dl3+NUMNODESP1*0+0)=-0.5; 
+	*(dl1dl3+NUMNODESP1*1+0)=-1.0/(2.0*SQRT3);
+
+	/*Second nodal function: */
+	*(dl1dl3+NUMNODESP1*0+1)=0.5;
+	*(dl1dl3+NUMNODESP1*1+1)=-1.0/(2.0*SQRT3);
+
+	/*Third nodal function: */
+	*(dl1dl3+NUMNODESP1*0+2)=0;
+	*(dl1dl3+NUMNODESP1*1+2)=1.0/SQRT3;
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetNodalFunctionsDerivativesP2Reference{{{*/
+void TriaRef::GetNodalFunctionsDerivativesP2Reference(IssmDouble** pdbasis,GaussTria* gauss){
+	/*This routine returns the values of the nodal functions derivatives  (with respect to the 
+	 * natural coordinate system) at the gaussian point. */
+
+	/*Allocate*/
+	IssmDouble* dbasis =xNew<IssmDouble>(NUMNODESP2*2);
+
+	/*Nodal function 1*/
+	dbasis[NUMNODESP2*0+0]=-2.*gauss->coord1 + 0.5;
+	dbasis[NUMNODESP2*0+1]=-2.*SQRT3/3.*gauss->coord1 + SQRT3/6.;
+	/*Nodal function 2*/
+	dbasis[NUMNODESP2*0+0]=+2.*gauss->coord2 + 0.5;
+	dbasis[NUMNODESP2*0+1]=-2.*SQRT3/3.*gauss->coord2 + SQRT3/6.;
+	/*Nodal function 3*/
+	dbasis[NUMNODESP2*0+0]=0.;
+	dbasis[NUMNODESP2*0+1]=+4.*SQRT3/3.*gauss->coord3 - SQRT3/3.;
+	/*Nodal function 4*/
+	dbasis[NUMNODESP2*0+0]=+2.*gauss->coord3;
+	dbasis[NUMNODESP2*0+1]=+4.*SQRT3/3.*gauss->coord2 - 2.*SQRT3/3.*gauss->coord3;
+	/*Nodal function 5*/
+	dbasis[NUMNODESP2*0+0]=-2.*gauss->coord3;
+	dbasis[NUMNODESP2*0+1]=+4.*SQRT3/3.*gauss->coord1 - 2.*SQRT3/3.*gauss->coord3;
+	/*Nodal function 6*/
+	dbasis[NUMNODESP2*0+0]=2.*(gauss->coord1-gauss->coord2);
+	dbasis[NUMNODESP2*0+1]=-2.*SQRT3/3.*(gauss->coord1+gauss->coord2);
+
+	/*Assign output pointer*/
+	*pdbasis = dbasis;
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetInputDerivativeValue{{{*/
+void TriaRef::GetInputDerivativeValue(IssmDouble* p, IssmDouble* plist,IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*From node values of parameter p (plist[0],plist[1],plist[2]), return parameter derivative value at gaussian 
+	 * point specified by gauss_basis:
+	 *   dp/dx=plist[0]*dh1/dx+plist[1]*dh2/dx+plist[2]*dh3/dx
+	 *   dp/dx=plist[0]*dh1/dx+plist[1]*dh2/dx+plist[2]*dh3/dx
+	 *
+	 * p is a vector of size 2x1 already allocated.
+	 */
+
+	/*Nodal Derivatives*/
+	IssmDouble dbasis[2][3]; //nodal derivative functions in actual coordinate system.
+
+	/*Get dh1dh2dh3 in actual coordinate system: */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list, gauss);
+
+	/*Assign values*/
+	*(p+0)=plist[0]*dbasis[0][0]+plist[1]*dbasis[0][1]+plist[2]*dbasis[0][2];
+	*(p+1)=plist[0]*dbasis[1][0]+plist[1]*dbasis[1][1]+plist[2]*dbasis[1][2];
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetInputValue{{{*/
+void TriaRef::GetInputValue(IssmDouble* p, IssmDouble* plist, GaussTria* gauss){
+
+	/*From node values of parameter p (plist[0],plist[1],plist[2]), return parameter value at gaussian 
+	 * point specifie by gauss: */
+
+	/*nodal functions annd output: */
+	IssmDouble basis[3];
+
+	/*Get nodal functions*/
+	GetNodalFunctions(basis, gauss);
+
+	/*Get parameter*/
+	*p=basis[0]*plist[0]+basis[1]*plist[1]+basis[2]*plist[2];
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Elements/TriaRef.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Elements/TriaRef.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Elements/TriaRef.h	(revision 15012)
@@ -0,0 +1,49 @@
+/*!\file:  TriaRef.h
+ * \brief abstract class for handling Tria oriented routines, like nodal functions, 
+ * strain rate generation, etc ...
+ */ 
+
+#ifndef _TRIAREF_H_
+#define _TRIAREF_H_
+
+class GaussTria;
+
+class TriaRef{
+
+	public: 
+		int* element_type_list; //P1CG, P1DG, MINI, P2...
+		int  element_type;
+
+		TriaRef();
+		TriaRef(const int nummodels);
+		~TriaRef();
+
+		/*Management*/
+		void SetElementType(int type,int type_counter);
+
+		/*Numerics*/
+		void GetBMacAyeal(IssmDouble* B, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetBMacAyealStokes(IssmDouble* B , IssmDouble* xyz_list, GaussTria* gauss);
+		void GetBprimeMacAyeal(IssmDouble* Bprime, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetBprimeMacAyealStokes(IssmDouble* Bprime, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetBprimePrognostic(IssmDouble* Bprime_prog, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetBPrognostic(IssmDouble* B_prog, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetBHydro(IssmDouble* B, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetL(IssmDouble* L, IssmDouble* xyz_list,GaussTria* gauss,int numdof);
+		void GetJacobian(IssmDouble* J, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetSegmentJacobianDeterminant(IssmDouble* Jdet, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetJacobianDeterminant(IssmDouble* Jdet, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetJacobianInvert(IssmDouble*  Jinv, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetNodalFunctions(IssmDouble* basis,GaussTria* gauss);
+		void GetNodalFunctionsP2(IssmDouble** pbasis,GaussTria* gauss);
+		void GetSegmentNodalFunctions(IssmDouble* basis,GaussTria* gauss, int index1,int index2);
+		void GetSegmentBFlux(IssmDouble* B,GaussTria* gauss, int index1,int index2);
+		void GetSegmentBprimeFlux(IssmDouble* Bprime,GaussTria* gauss, int index1,int index2);
+		void GetNodalFunctionsDerivatives(IssmDouble* basis,IssmDouble* xyz_list, GaussTria* gauss);
+		void GetNodalFunctionsDerivativesReference(IssmDouble* dl1dl3,GaussTria* gauss);
+		void GetNodalFunctionsDerivativesP2Reference(IssmDouble** pdbasis,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pp, IssmDouble* plist, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* pp, IssmDouble* plist,IssmDouble* xyz_list, GaussTria* gauss);
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/ExternalResults/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/ExternalResults/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ExternalResults/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,5 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/ExternalResults)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/ExternalResults/ExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ExternalResults/ExternalResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ExternalResults/ExternalResult.h	(revision 15012)
@@ -0,0 +1,33 @@
+/*!\file:  ExternalResult.h
+ * \brief abstract class for ExternalResult object
+ */ 
+
+#ifndef _EXTERNALRESULT_H_
+#define _EXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../Object.h"
+#include "../Node.h"
+/*}}}*/
+
+class ExternalResult: public Object{
+
+	public: 
+
+		virtual        ~ExternalResult(){};
+		/*Virtual functions:{{{*/
+		virtual int   InstanceEnum()=0;
+		virtual void  WriteData(FILE* fid,bool io_gather)=0;
+		virtual void  GetResultName(char**)=0;
+		virtual int   GetStep(void)=0;
+		/*}}}*/
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/ExternalResults/GenericExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ExternalResults/GenericExternalResult.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ExternalResults/GenericExternalResult.h	(revision 15012)
@@ -0,0 +1,323 @@
+/*! \file GenericExternalResult.h 
+ *  \brief: header file for generic external result object
+ */
+
+#ifndef _GENERIC_EXTERNAL_RESULT_
+#define _GENERIC_EXTERNAL_RESULT_
+
+/*Headers:{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <cstring>
+#include "./ExternalResult.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+template <class ResultType> 
+class GenericExternalResult: public ExternalResult {
+
+	private: 
+		int id;
+		int enum_type;
+		ResultType value;
+		int M;
+		int N;
+		int step;
+		IssmDouble time;
+
+	public:
+		/*Diverse: must be in front, as it is used in what follows*/
+		void GenericEcho(void){/*{{{*/
+			_printLine_("   id: " << this->id);
+			_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+			_printLine_("   step: " << this->step);
+			_printLine_("   time: " << this->time);
+		}
+		/*}}}*/
+		void GenericWriteData(FILE* fid){/*{{{*/ 
+
+			int     length;
+			IssmPDouble  passiveDouble;
+			char*   name = NULL;
+
+			/*First write enum: */
+			EnumToStringx(&name,this->enum_type);
+			length=(strlen(name)+1)*sizeof(char);
+			fwrite(&length,sizeof(int),1,fid);
+			fwrite(name,length,1,fid);
+			xDelete<char>(name);
+
+			/*Now write time and step: */
+			passiveDouble=reCast<IssmPDouble>(time);
+			fwrite(&passiveDouble,sizeof(IssmPDouble),1,fid);
+			fwrite(&step,sizeof(int),1,fid);
+		} /*}}}*/
+
+		/*GenericExternalResult constructors and  destructors*/
+		GenericExternalResult(){ /*{{{*/
+			id  = 0;
+			enum_type = NoneEnum;
+			M=0;
+			N=0;
+			step=0;
+			time=0;
+		} /*}}}*/
+		GenericExternalResult(int in_id, int in_enum_type,ResultType in_values, int in_M,int in_N,int in_step,IssmDouble in_time){/*{{{*/
+			_error_("template GenericExternalResult(int in_id, int in_enum_type,double* in_values, int in_M,int in_N,int in_step,IssmDouble in_time) not implemented for this ResultType\n");
+		}
+/*}}}*/
+		GenericExternalResult(int in_id, int in_enum_type,ResultType in_value,int in_step, IssmDouble in_time){ /*{{{*/
+			id=in_id;
+			enum_type=in_enum_type;
+			value=in_value;
+			step=in_step;
+			time=in_time;
+		}
+		/*}}}*/
+		~GenericExternalResult(){ /*{{{*/
+		} /*}}}*/
+
+		/*Object virtual functions definitions:*/
+		void Echo(void){ /*{{{*/
+			this->DeepEcho();
+		}
+		/*}}}*/
+		void DeepEcho(void){ /*{{{*/
+			_error_("template DeepEcho not implemented for this ResultType\n");
+		}
+		/*}}}*/
+		int Id(void){ /*{{{*/ 
+			return -1; 
+		} /*}}}*/
+		int ObjectEnum(void){ /*{{{*/
+			_error_("template ObjectEnum not implemented for this ResultType\n");
+		} /*}}}*/
+		Object* copy(void) { /*{{{*/
+			return new GenericExternalResult<ResultType>(this->id,this->enum_type,this->value,this->step,this->time);
+		} /*}}}*/
+
+		/*GenericExternalResult management: */
+void WriteData(FILE* fid,bool io_gather){ /*{{{*/
+
+	int     my_rank;
+	int     type;
+	int     size;
+	IssmPDouble  passiveDouble;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	/*return if now on cpu 0: */
+	if(my_rank)return;
+
+	/*use generic part, same for all ResultTypes: */
+	this->GenericWriteData(fid);
+
+	/*writing a IssmPDouble for Matlab or Python to post-process, type is 1, size is 1: */
+	type=1;
+	size=1;
+	fwrite(&type,sizeof(int),1,fid);
+	fwrite(&size,sizeof(int),1,fid);
+
+	/*cast to a IssmPDouble: */
+	passiveDouble=reCast<IssmPDouble>(value);
+	fwrite(&passiveDouble,size*sizeof(IssmPDouble),1,fid);
+
+} /*}}}*/
+void GetResultName(char** pname){ /*{{{*/
+	EnumToStringx(pname,this->enum_type);
+} /*}}}*/
+int GetStep(void){ /*{{{*/
+	return this->step;
+} /*}}}*/
+int InstanceEnum(void){ /*{{{*/
+	return this->enum_type;
+} /*}}}*/
+};
+
+/*Specific instantiations for bool: */
+template <> inline void GenericExternalResult<bool>::DeepEcho(void){ /*{{{*/
+
+	_printLine_("GenericExternalResult<bool>:");
+	this->GenericEcho();
+	_printLine_("   value: " <<(this->value?"true":"false"));
+
+} /*}}}*/
+template <> inline int GenericExternalResult<bool>::ObjectEnum(void){ /*{{{*/
+	return BoolExternalResultEnum;
+} /*}}}*/
+
+/*Specific instantiations for int: */
+template <> inline void GenericExternalResult<int>::DeepEcho(void){ /*{{{*/
+
+	_printLine_("GenericExternalResult<int>:");
+	this->GenericEcho();
+	_printLine_("   value: " << this->value);
+
+} /*}}}*/
+template <> inline int GenericExternalResult<int>::ObjectEnum(void){ /*{{{*/
+	return IntExternalResultEnum;
+} /*}}}*/
+
+/*Specific instantiations for double: */
+template <> inline void GenericExternalResult<double>::DeepEcho(void){ /*{{{*/
+
+	_printLine_("GenericExternalResult<double>:");
+	this->GenericEcho();
+	_printLine_("   value: " << this->value);
+
+} /*}}}*/
+template <> inline int GenericExternalResult<double>::ObjectEnum(void){ /*{{{*/
+	return DoubleExternalResultEnum;
+} /*}}}*/
+
+/*Specific instantiations for char*: */
+template <> inline GenericExternalResult<char*>::GenericExternalResult(int in_id, int in_enum_type,char* in_value,int in_step, IssmDouble in_time){ /*{{{*/
+
+	id=in_id;
+	enum_type=in_enum_type;
+	value=xNew<char>(strlen(in_value)+1);
+	xMemCpy<char>(value,in_value,(strlen(in_value)+1));
+	step=in_step;
+	time=in_time;
+
+} /*}}}*/
+template <> inline GenericExternalResult<char*>::~GenericExternalResult(){ /*{{{*/
+	xDelete<char>(value);
+} /*}}}*/
+template <> inline void GenericExternalResult<char*>::DeepEcho(void){ /*{{{*/
+
+	_printLine_("GenericExternalResult<char*>:");
+	this->GenericEcho();
+	_printLine_("   value: " << this->value);
+
+} /*}}}*/
+template <> inline void GenericExternalResult<char*>::WriteData(FILE* fid,bool io_gather){ /*{{{*/
+
+	int     my_rank;
+	int     type;
+	int     length;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	/*return if now on cpu 0: */
+	if(my_rank)return;
+
+	/*use generic part, same for all ResultTypes: */
+	this->GenericWriteData(fid);
+
+	/*writing a string, type is 2: */
+	type=2;
+	fwrite(&type,sizeof(int),1,fid);
+
+	length=(strlen(this->value)+1)*sizeof(char);
+	fwrite(&length,sizeof(int),1,fid);
+	fwrite(this->value,length,1,fid);
+}
+/*}}}*/
+template <> inline int GenericExternalResult<char*>::ObjectEnum(void){ /*{{{*/
+	return StringExternalResultEnum;
+} /*}}}*/
+
+/*Specific instantiations for IssmPDouble*: */
+template <> inline GenericExternalResult<IssmPDouble*>::GenericExternalResult(int in_id, int in_enum_type,IssmPDouble* in_values, int in_M,int in_N,int in_step,IssmDouble in_time){/*{{{*/
+
+	id=in_id;
+	enum_type=in_enum_type;
+	M=in_M;
+	N=in_N;
+
+	step=in_step;
+	time=in_time;
+
+	/*Copy result in values*/
+	if(M*N){
+		value=xNew<IssmPDouble>(M*N);
+		xMemCpy<IssmPDouble>(value,in_values,M*N);
+	}
+	else value=NULL;
+}
+/*}}}*/
+template <> inline GenericExternalResult<IssmPDouble*>::GenericExternalResult(int in_id, int in_enum_type,IssmPDouble* in_value,int in_step, IssmDouble in_time){ /*{{{*/
+	_error_("you cannot initialize a GenericExternalResult<IssmPDouble*> without providing the dimensions of the matrix! Please use a more appropriate constructor!");
+} /*}}}*/
+template <> inline GenericExternalResult<IssmPDouble*>::~GenericExternalResult(){ /*{{{*/
+	xDelete<IssmPDouble>(value);
+} /*}}}*/
+template <> inline void GenericExternalResult<IssmPDouble*>::Echo(void){ /*{{{*/
+
+	_printLine_("GenericExternalResult<IssmPDouble*>:");
+	this->GenericEcho();
+	_printLine_("   matrix size: " << this->M << "-" << this->N);
+
+} /*}}}*/
+template <> inline void GenericExternalResult<IssmPDouble*>::DeepEcho(void){ /*{{{*/
+
+	int i,j;
+
+	_printLine_("GenericExternalResult<IssmPDouble*>:");
+	this->GenericEcho();
+
+	_printLine_("   matrix size: " << this->M << "-" << this->N);
+	for (i=0;i<this->M;i++){  
+		_printString_("   [ ");
+		for (j=0;j<this->N;j++){
+			_printString_( " " << setw(11) << setprecision (5) << this->value[i*this->N+j]);
+		}  
+		_printLine_(" ]");
+	}  
+
+} /*}}}*/
+template <> inline Object* GenericExternalResult<IssmPDouble*>::copy(void){ /*{{{*/
+	return new GenericExternalResult<IssmPDouble*>(this->id,this->enum_type,this->value,this->M,this->N,this->step,this->time);
+} /*}}}*/
+template <> inline void GenericExternalResult<IssmPDouble*>::WriteData(FILE* fid,bool io_gather){ /*{{{*/
+
+	int     my_rank;
+	int     length;
+	int     type;
+	int     rows,cols;
+	char   *name    = NULL;
+	IssmPDouble passiveDouble;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	if(io_gather){
+		/*we are gathering the data on cpu 0, don't write on other cpus: */
+		if(my_rank) return;
+	}
+
+	/*First write enum: */
+	EnumToStringx(&name,this->enum_type);
+	length=(strlen(name)+1)*sizeof(char);
+	fwrite(&length,sizeof(int),1,fid);
+	fwrite(name,length,1,fid);
+	xDelete<char>(name);
+
+	/*Now write time and step: */
+	passiveDouble=reCast<IssmPDouble>(time);
+	fwrite(&passiveDouble,sizeof(IssmPDouble),1,fid);
+	fwrite(&step,sizeof(int),1,fid);
+
+	/*writing a IssmDouble array, type is 3:*/
+	type=3;
+	fwrite(&type,sizeof(int),1,fid);
+	rows=this->M;
+	fwrite(&rows,sizeof(int),1,fid);
+	cols=this->N;
+	fwrite(&cols,sizeof(int),1,fid);
+	fwrite(value,cols*rows*sizeof(IssmPDouble),1,fid);
+
+}
+/*}}}*/
+template <> inline int GenericExternalResult<IssmPDouble*>::ObjectEnum(void){ /*{{{*/
+	return DoubleMatExternalResultEnum;
+} /*}}}*/
+
+#endif  /* _EXTERNAL_RESULTOBJECT_H */
Index: /issm/trunk-jpl/src/c/classes/ExternalResults/Results.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/ExternalResults/Results.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ExternalResults/Results.cpp	(revision 15012)
@@ -0,0 +1,81 @@
+/*
+ * \file Results.cpp
+ * \brief: Implementation of the Results class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Results.h"
+#include "./ExternalResult.h"
+#include "../../shared/shared.h"
+#include "../Params/Parameters.h"
+#include "../ElementResults/ElementResult.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Results::Results(){{{*/
+Results::Results(){
+	enum_type=ResultsEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Results::~Results(){{{*/
+Results::~Results(){
+	return;
+}
+/*}}}*/
+
+/*Object management*/
+/*FUNCTION Results::SpawnTriaResults{{{*/
+Results* Results::SpawnTriaResults(int* indices){
+
+	/*Intermediary*/
+	vector<Object*>::iterator object;
+	ElementResult* resultin=NULL;
+	ElementResult* resultout=NULL;
+
+	/*Output*/
+	Results* newresults=new Results();
+
+	/*Go through results and call Spawn function*/
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		/*Create new result*/
+		resultin=(ElementResult*)(*object); 
+		resultout=resultin->SpawnTriaElementResult(indices);
+
+		/*Add result to new results*/
+		newresults->AddObject((Object*)resultout);
+	}
+
+	/*Assign output pointer*/
+	return newresults;
+}
+/*}}}*/
+/*FUNCTION Results::Write{{{*/
+void Results::Write(Parameters* parameters){
+
+	int         i;
+	FILE       *fid          = NULL;
+	bool        io_gather=true;
+
+	/*Recover file descriptor: */
+	parameters->FindParam(&fid,OutputFilePointerEnum);
+	parameters->FindParam(&io_gather,SettingsIoGatherEnum);
+
+	for(i=0;i<this->Size();i++){
+		ExternalResult* result=dynamic_cast<ExternalResult*>(this->GetObjectByOffset(i));
+
+		/*write result to disk: */
+		result->WriteData(fid,io_gather);
+	}
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/ExternalResults/Results.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/ExternalResults/Results.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/ExternalResults/Results.h	(revision 15012)
@@ -0,0 +1,25 @@
+#ifndef _CONTAINER_RESULTS_H_
+#define  _CONTAINER_RESULTS_H_
+
+#include "../DataSet.h"
+
+/*forward declarations */
+class Parameters;
+
+/*!\brief Declaration of Results class.
+ *
+ * Declaration of Results class.  Results are vector lists (Containers) of Result objects.
+ */ 
+class Results: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Results();
+		~Results();
+
+		/*numerics*/
+		Results* SpawnTriaResults(int* indices);
+		void     Write(Parameters* parameters);
+};
+#endif //ifndef _RESULTS_H_
Index: /issm/trunk-jpl/src/c/classes/FemModel.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/FemModel.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/FemModel.h	(revision 15012)
@@ -8,5 +8,5 @@
 /*Headers:*/
 /*{{{*/
-#include "./objects/Object.h"
+#include "./Object.h"
 #include "../toolkits/toolkits.h"
 class DataSet;
Index: /issm/trunk-jpl/src/c/classes/Hook.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Hook.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/Hook.h	(revision 15012)
@@ -11,5 +11,5 @@
 /*Headers:*/
 /*{{{*/
-#include "./objects/Object.h"
+#include "./Object.h"
 class DataSet;
 /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/IndependentObject.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/IndependentObject.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/IndependentObject.cpp	(revision 15012)
@@ -0,0 +1,211 @@
+/*!\file IndependentObject.c
+ * \brief: implementation of the IndependentObject object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./classes.h"
+#include "../shared/shared.h"
+#include "IoModel.h"
+
+/*IndependentObject constructors and destructor*/
+/*FUNCTION IndependentObject::IndependentObject(){{{*/
+IndependentObject::IndependentObject(){
+	this->name=NoneEnum;
+	this->type=0;
+	this->numberofvertices=0;
+}
+/*}}}*/
+/*FUNCTION IndependentObject::IndependentObject(int in_name, int in_type,int in_numberofvertices){{{*/
+IndependentObject::IndependentObject(int in_name, int in_type,int in_numberofvertices){
+
+	this->numberofvertices=0;
+	this->name=in_name;
+	this->type=in_type;
+	if(in_type!=0 && in_type!=1)_error_("cannot create an IndependentObject of type " << in_type);
+	if(this->type==1)this->numberofvertices=in_numberofvertices;
+
+}
+/*}}}*/
+/*FUNCTION IndependentObject::~IndependentObject() {{{*/
+IndependentObject::~IndependentObject(){ //destructor
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION IndependentObject::Echo{{{*/
+void IndependentObject::Echo(void){
+
+	_printLine_("IndependentObject:");
+	_printLine_("   name: " << EnumToStringx(this->name));
+	if(this->type==0)
+		_printLine_("   type: scalar");
+	else if(this->type==1)
+		_printLine_("   type: vertex");
+	else
+		_error_(" unknown type: " << this->type);
+	_printLine_("   numberofvertices: " << this->numberofvertices);
+}
+/*}}}*/
+/*FUNCTION IndependentObject::DeepEcho{{{*/
+void IndependentObject::DeepEcho(void){
+	this->Echo();
+}
+/*}}}*/
+/*FUNCTION IndependentObject::Id{{{*/
+int    IndependentObject::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION IndependentObject::ObjectEnum{{{*/
+int IndependentObject::ObjectEnum(void){
+
+	return IndependentObjectEnum;
+
+}
+/*}}}*/
+/*FUNCTION IndependentObject::copy{{{*/
+Object* IndependentObject::copy(void) { 
+	return new IndependentObject(name,type,numberofvertices);
+} /*}}}*/
+
+/*IndependentObject methods: */
+/*FUNCTION IndependentObject::FetchIndependent{{{*/
+void IndependentObject::FetchIndependent(IoModel* iomodel){
+
+	int my_rank;
+	FILE* fid=NULL;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	#ifdef _HAVE_ADOLC_ //cannot come here unless you are running AD mode, from DeclaredIndependents:
+
+	/*Branch according to the type of variable: */
+	if(type==0){ /*scalar: {{{*/
+
+		/*output: */
+		IssmPDouble  pscalar;
+		IssmDouble   scalar; //same as pscalar, except it's an ADOLC independent variable
+		IssmDouble*  scalar_slot=NULL;
+		int      code;
+
+		/*Set file pointer to beginning of the data: */
+		fid=iomodel->SetFilePointerToData(&code,NULL,name);
+
+		if(code!=3)_error_("expecting a IssmDouble for enum " << EnumToStringx(name));
+
+		/*We have to read a scalar from disk. First read the dimensions of the scalar, then the scalar: */
+		if(my_rank==0){
+			if(fread(&pscalar,sizeof(IssmPDouble),1,fid)!=1)_error_("could not read scalar ");
+		}
+
+		/*Now, before we even broadcast this to other nodes, declare the scalar  as an independent variable!: */
+		scalar<<=pscalar;
+
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(&scalar,1,MPI_DOUBLE,0,IssmComm::GetComm()); 
+		#endif
+
+		/*Ok, we are almost done. scalar is now an independent variable. We don't want this variable to be fetched again in the 
+		 *future, which would effectively write over the independency in the ADOLC tape! So we are going to keep track of this 
+		 independent variable inthe iomodel->data[name] data slot. Because this data slot holds double*, we allocate a sizeof(double)
+		 space for it: */
+		scalar_slot=xNew<IssmDouble>(1); *scalar_slot=scalar;
+
+		iomodel->data[name]=scalar_slot;
+		iomodel->independents[name]=true;
+
+	} /*}}}*/
+	else if(type==1){ /* vector: {{{*/
+
+		FILE* fid=NULL;
+		int M,N;
+		IssmPDouble* buffer=NULL; //a buffer to read the data from disk
+		IssmDouble* matrix=NULL; //our independent variable
+		int code=0;
+
+		/*Set file pointer to beginning of the data: */
+		fid=iomodel->SetFilePointerToData(&code,NULL,name);
+		if((code!=5) && (code!=6) && (code!=7))_error_("expecting a IssmDouble, integer or boolean matrix for enum " << EnumToStringx(name));
+
+		/*We have to read a matrix from disk. First read the dimensions of the matrix, then the whole matrix: */
+		/*numberofelements: */
+		if(my_rank==0){  
+			if(fread(&M,sizeof(int),1,fid)!=1) _error_("could not read number of rows for matrix ");
+		}
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(&M,1,MPI_INT,0,IssmComm::GetComm()); 
+		#endif
+
+		if(my_rank==0){  
+			if(fread(&N,sizeof(int),1,fid)!=1) _error_("could not read number of columns for matrix ");
+		}
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(&N,1,MPI_INT,0,IssmComm::GetComm()); 
+		#endif
+
+		/*Now allocate matrix: */
+		if(M*N){
+			buffer=xNew<IssmPDouble>(M*N);
+			matrix=xNew<IssmDouble>(M*N);
+
+			/*Read matrix on node 0, then broadcast: */
+			if(my_rank==0){  
+				if(fread(buffer,M*N*sizeof(IssmPDouble),1,fid)!=1) _error_("could not read matrix ");
+
+				/*Now, before we even broadcast this to other nodes, declare the whole matrix as a independent variable!: */
+				for (int i=0;i<M*N;++i) matrix[i]<<=buffer[i];  /*we use the <<= ADOLC overloaded operator to declare the independency*/
+			}
+			#ifdef _HAVE_MPI_
+			MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,IssmComm::GetComm()); 
+			#endif
+
+			xDelete<IssmPDouble>(buffer);
+		}
+		else _error_("cannot declare the independent variable " << EnumToStringx(name) <<  "if it's empty!");
+
+		/*Ok, we are almost done. Matrix is now a independent matrix. We don't want this matrix to be fetched again in the 
+		 *future, which would effectively write over the independency in the ADOLC tape! So we are going to keep track of this 
+		 independent matrix inthe iomodel->data[name] data slot: */
+		iomodel->data[name]=matrix;
+		iomodel->independents[name]=true;
+	}/*}}}*/
+	else _error_("should not have a type of " << type);
+
+	#endif
+}
+/*}}}*/
+/*FUNCTION IndependentObject::NumIndependents{{{*/
+int  IndependentObject::NumIndependents(void){
+
+	/*Branch according to the type of variable: */
+	if(type==0){ /*scalar:*/
+		return 1;
+	}
+	else if(type==1){ /* vector:*/
+		return this->numberofvertices;
+	}
+	else _error_("should not have a type of " << type);
+}
+/*}}}*/
+/*FUNCTION IndependentObject::FillIndependents{{{*/
+void IndependentObject::FillIndependents(IssmDouble** data, IssmDouble* xp){
+
+	int i;
+
+	/*Branch according to the type of variable: */
+	if(type==0){ /*scalar:*/
+		xp[0]=*(data[name]);
+	}
+	else if(type==1){ /* vector:*/
+		IssmDouble* values=data[name];
+		for(i=0;i<this->numberofvertices;i++){
+			xp[i]=values[i];
+		}
+	}
+	else _error_("should not have a type of " << type);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/IndependentObject.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/IndependentObject.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/IndependentObject.h	(revision 15012)
@@ -0,0 +1,41 @@
+/*!\file: IndependentObject.h
+ * \brief prototype for IndependentObject.h
+ */ 
+
+#ifndef _INDEPENDENTOBJECT_H_
+#define  _INDEPENDENTOBJECT_H_
+
+/*{{{*/
+#include "./Object.h"
+#include "../shared/shared.h"
+/*}}}*/
+class IoModel;
+
+class IndependentObject: public Object{
+
+	public:
+
+		int name;
+		int type;  /*0: scalar, 1: vertex*/
+		int numberofvertices;
+
+		/*IndependentObject constructors, destructors {{{*/
+		IndependentObject();
+		IndependentObject(int name, int type, int numberofvertices);
+		~IndependentObject();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy(void);
+		/*}}}*/
+		/*IndependentObject methods: {{{*/
+		void FetchIndependent(IoModel* iomodel);
+		int  NumIndependents(void);
+		void FillIndependents(IssmDouble** data, IssmDouble* xp);
+		/*}}}*/
+
+};
+#endif //ifndef _INDEPENDENTOBJECT_H_
Index: /issm/trunk-jpl/src/c/classes/Inputs/BoolInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/BoolInput.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/BoolInput.cpp	(revision 15012)
@@ -0,0 +1,182 @@
+/*!\file BoolInput.c
+ * \brief: implementation of the BoolInput object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*BoolInput constructors and destructor*/
+/*FUNCTION BoolInput::BoolInput(){{{*/
+BoolInput::BoolInput(){
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolInput::BoolInput(int in_enum_type,bool in_value){{{*/
+BoolInput::BoolInput(int in_enum_type,bool in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION BoolInput::~BoolInput(){{{*/
+BoolInput::~BoolInput(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION BoolInput::Echo {{{*/
+void BoolInput::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION BoolInput::DeepEcho{{{*/
+void BoolInput::DeepEcho(void){
+
+	_printLine_("BoolInput:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " <<(value?"true":"false"));
+}
+/*}}}*/
+/*FUNCTION BoolInput::Id{{{*/
+int    BoolInput::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION BoolInput::ObjectEnum{{{*/
+int BoolInput::ObjectEnum(void){
+
+	return BoolInputEnum;
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::copy{{{*/
+Object* BoolInput::copy() {
+
+	return new BoolInput(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*BoolInput management*/
+/*FUNCTION BoolInput::InstanceEnum{{{*/
+int BoolInput::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::SpawnTriaInput{{{*/
+Input* BoolInput::SpawnTriaInput(int* indices){
+
+		/*output*/
+		BoolInput* outinput=new BoolInput();
+
+		/*only copy current value*/
+		outinput->enum_type=this->enum_type;
+		outinput->value=this->value;
+
+		/*Assign output*/
+		return outinput;
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::SpawnResult{{{*/
+ElementResult* BoolInput::SpawnResult(int step, IssmDouble time){
+
+	return new BoolElementResult(this->enum_type,this->value,step,time);
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION BoolInput::GetInputValue(bool* pvalue) {{{*/
+void BoolInput::GetInputValue(bool* pvalue){
+	*pvalue=value;
+}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(int* pvalue){{{*/
+void BoolInput::GetInputValue(int* pvalue){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(IssmDouble* pvalue){{{*/
+void BoolInput::GetInputValue(IssmDouble* pvalue){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void BoolInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void BoolInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::ChangeEnum{{{*/
+void BoolInput::ChangeEnum(int newenumtype){
+	this->enum_type=newenumtype;
+}
+/*}}}*/
+/*FUNCTION BoolInput::SquareMin{{{*/
+void BoolInput::SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){
+	/*square of a bool is the bool itself: */
+	*psquaremin=value;
+}
+/*}}}*/
+/*FUNCTION BoolInput::Scale{{{*/
+void BoolInput::Scale(IssmDouble scale_factor){
+	/*a bool cannot be scaled: */
+}
+/*}}}*/
+/*FUNCTION BoolInput::AXPY{{{*/
+void BoolInput::AXPY(Input* xinput,IssmDouble scalar){
+
+	BoolInput*  xboolinput=NULL;
+
+	/*xinput is of the same type, so cast it: */
+	xboolinput=(BoolInput*)xinput;
+
+	/*Carry out the AXPY operation depending on type:*/
+	switch(xinput->ObjectEnum()){
+
+		case BoolInputEnum:
+			this->value=reCast<bool,IssmDouble>(this->value+scalar*xboolinput->value);
+			return;
+
+		default:
+			_error_("not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::Extrude{{{*/
+void BoolInput::Extrude(void){
+
+	/*do nothing*/
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolInput::GetVectorFromInputs{{{*/
+void BoolInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+
+	_error_("not supporte yet!");
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::GetValuesPtr{{{*/
+void BoolInput::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	_error_("not supported yet!");
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::Configure{{{*/
+void BoolInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/BoolInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/BoolInput.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/BoolInput.h	(revision 15012)
@@ -0,0 +1,85 @@
+/*! \file BoolInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _BOOLINPUT_H_
+#define _BOOLINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class BoolInput: public Input{
+
+	public:
+		/*just hold 3 values for 3 vertices: */
+		int  enum_type;
+		bool value;
+
+		/*BoolInput constructors, destructors: {{{*/
+		BoolInput();
+		BoolInput(int enum_type,bool value);
+		~BoolInput();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy();
+		/*}}}*/
+		/*BoolInput management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void Configure(Parameters* parameters);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue);
+		void GetInputValue(int* pvalue);
+		void GetInputValue(IssmDouble* pvalue);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputAverage(IssmDouble* pvalue){_error_("not implemented yet");};
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){_error_("not implemented yet");};
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){_error_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum){_error_("not implemented yet");};
+		IssmDouble InfinityNorm(void){_error_("InfinityNorm not implemented for booleans");};
+		IssmDouble Max(void){_error_("Max not implemented for booleans");};
+		IssmDouble MaxAbs(void){_error_("Max not implemented for booleans");};
+		IssmDouble Min(void){_error_("Min not implemented for booleans");};
+		IssmDouble MinAbs(void){_error_("Min not implemented for booleans");};
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max){_error_("Constrain not implemented for booleans");};
+		void Extrude(void);
+		void VerticallyIntegrate(Input* thickness_input){_error_("not supported yet");};
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _BOOLINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,16 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Inputs)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/BoolInput.cpp
+              $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/DatasetInput.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/DoubleInput.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/IntInput.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/TransientInput.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/TriaP1Input.cpp PARENT_SCOPE)
+# }}}
+# THREED_SOURCES {{{
+set(THREED_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Inputs/PentaP1Input.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Inputs/ControlInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/ControlInput.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/ControlInput.cpp	(revision 15012)
@@ -0,0 +1,271 @@
+/*!\file ControlInput.c
+ * \brief: implementation of the ControlInput object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*ControlInput constructors and destructor*/
+/*FUNCTION ControlInput::ControlInput(){{{*/
+ControlInput::ControlInput(){
+	control_id  = 0;
+	values      = NULL;
+	savedvalues = NULL;
+	minvalues   = NULL;
+	maxvalues   = NULL;
+	gradient    = NULL;
+}
+/*}}}*/
+/*FUNCTION ControlInput::ControlInput(int enum_type,int enum_input,IssmDouble* pvalues,IssmDouble* pmin,IssmDouble* pmax,int id){{{*/
+ControlInput::ControlInput(int in_enum_type,int enum_input,IssmDouble* pvalues,IssmDouble* pmin,IssmDouble* pmax,int id){
+
+	control_id=id;
+	enum_type=in_enum_type;
+
+	switch(enum_input){
+		case TriaP1InputEnum:
+			values     =new TriaP1Input(enum_type,pvalues);
+			savedvalues=new TriaP1Input(enum_type,pvalues);
+			minvalues  =new TriaP1Input(enum_type,pmin);
+			maxvalues  =new TriaP1Input(enum_type,pmax);
+			break;
+		case PentaP1InputEnum:
+			values     =new PentaP1Input(enum_type,pvalues);
+			savedvalues=new PentaP1Input(enum_type,pvalues);
+			minvalues  =new PentaP1Input(enum_type,pmin);
+			maxvalues  =new PentaP1Input(enum_type,pmax);
+			break;
+		default:
+			_error_("Input of Enum " << EnumToStringx(enum_input) << " not supported yet by ControlInput");
+	}
+	gradient   =NULL;
+}
+/*}}}*/
+/*FUNCTION ControlInput::~ControlInput(){{{*/
+ControlInput::~ControlInput(){
+	delete values;
+	delete savedvalues;
+	delete minvalues;
+	delete maxvalues;
+	delete gradient;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+		/*FUNCTION ControlInput::Echo {{{*/
+void ControlInput::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION ControlInput::DeepEcho{{{*/
+void ControlInput::DeepEcho(void){
+
+	_printLine_("ControlInput:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("---values: ");     if (values)      values->Echo();
+	_printLine_("---savedvalues: ");if (savedvalues) savedvalues->Echo();
+	_printLine_("---minvalues: ");  if (minvalues)   minvalues->Echo();
+	_printLine_("---maxvalues: ");  if (maxvalues)   maxvalues->Echo();
+	_printLine_("---gradient: ");   if (gradient)    gradient->Echo();
+}
+/*}}}*/
+/*FUNCTION ControlInput::Id{{{*/
+int    ControlInput::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION ControlInput::ObjectEnum{{{*/
+int ControlInput::ObjectEnum(void){
+
+	return ControlInputEnum;
+
+}
+/*}}}*/
+/*FUNCTION ControlInput::copy{{{*/
+Object* ControlInput::copy() {
+
+	ControlInput* output=NULL;
+
+	output = new ControlInput();
+	output->enum_type=this->enum_type;
+	output->control_id=this->control_id;
+
+	if(values)      output->values      = dynamic_cast<Input*>(this->values->copy());
+	if(savedvalues) output->savedvalues = dynamic_cast<Input*>(this->savedvalues->copy());
+	if(minvalues)   output->minvalues   = dynamic_cast<Input*>(this->minvalues->copy());
+	if(maxvalues)   output->maxvalues   = dynamic_cast<Input*>(this->maxvalues->copy());
+	if(gradient)    output->gradient    = dynamic_cast<Input*>(this->gradient->copy());
+
+	return output;
+}
+/*}}}*/
+
+/*ControlInput management*/
+/*FUNCTION ControlInput::InstanceEnum{{{*/
+int ControlInput::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION ControlInput::Constrain(){{{*/
+void ControlInput::Constrain(void){
+
+	Input* newvalues=NULL;
+
+	newvalues=this->values->PointwiseMin(maxvalues);
+	delete values; this->values=newvalues;
+	newvalues=this->values->PointwiseMax(minvalues);
+	delete values; this->values=newvalues;
+}/*}}}*/
+/*FUNCTION ControlInput::Constrain(IssmDouble min, IssmDouble max){{{*/
+void ControlInput::Constrain(IssmDouble min, IssmDouble max){
+	   values->Constrain(min,max);
+}/*}}}*/
+/*FUNCTION ControlInput::Extrude{{{*/
+void ControlInput::Extrude(void){
+	values->Extrude();
+	savedvalues->Extrude();
+	//gradient->Extrude();
+}/*}}}*/
+/*FUNCTION ControlInput::GetGradient{{{*/
+void ControlInput::GetGradient(Vector<IssmDouble>* gradient_vec,int* doflist){
+	if(gradient) gradient->GetVectorFromInputs(gradient_vec,doflist);
+}/*}}}*/
+/*FUNCTION ControlInput::ScaleGradient{{{*/
+void ControlInput::ScaleGradient(IssmDouble scaling_factor){
+	if(!gradient) _error_("Gradient of ControlInput " << EnumToStringx(enum_type) << " not found");
+	gradient->Scale(scaling_factor);
+}/*}}}*/
+/*FUNCTION ControlInput::SetGradient{{{*/
+void ControlInput::SetGradient(Input* gradient_in){
+
+	/*Get enum for current gradient*/
+	switch(this->control_id){
+		case 1:
+			gradient_in->ChangeEnum(Gradient1Enum);
+			break;
+		case 2:
+			gradient_in->ChangeEnum(Gradient2Enum);
+			break;
+		case 3:
+			gradient_in->ChangeEnum(Gradient3Enum);
+			break;
+		default:
+			_error_("more than 3 controls not implemented yet (Gradient " << this->control_id << " was requested). EnumDefinitions.h needs to be updated.");
+	}
+
+	/*Delete old gradient and assign new gradient*/
+	if(gradient) delete gradient;
+	gradient=gradient_in;
+
+}/*}}}*/
+/*FUNCTION ControlInput::SetInput{{{*/
+void ControlInput::SetInput(Input* in_input){
+
+	delete values; this->values=in_input;
+	this->SaveValue(); //because this is what SpawnResult saves FIXME
+
+}/*}}}*/
+/*FUNCTION ControlInput::SpawnResult{{{*/
+ElementResult* ControlInput::SpawnResult(int step, IssmDouble time){
+	return savedvalues->SpawnResult(step,time);
+}/*}}}*/
+/*FUNCTION ControlInput::SpawnTriaInput{{{*/
+Input* ControlInput::SpawnTriaInput(int* indices){
+	return values->SpawnTriaInput(indices);
+}/*}}}*/
+/*FUNCTION ControlInput::SpawnGradient{{{*/
+ElementResult* ControlInput::SpawnGradient(int step, IssmDouble time){
+	_assert_(gradient);
+	return gradient->SpawnResult(step,time);
+}/*}}}*/
+/*FUNCTION ControlInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){{{*/
+void ControlInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+	values->GetVectorFromInputs(vector,doflist);
+}/*}}}*/
+/*FUNCTION ControlInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist,const char* data){{{*/
+void ControlInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist,const char* data){
+	 if(strcmp(data,"value")==0){
+		 _assert_(values);
+		 values->GetVectorFromInputs(vector,doflist);
+	 }
+	 else if (strcmp(data,"lowerbound")==0){
+		 _assert_(minvalues);
+		 minvalues->GetVectorFromInputs(vector,doflist);
+	 }
+	 else if (strcmp(data,"upperbound")==0){
+		 _assert_(maxvalues);
+		 maxvalues->GetVectorFromInputs(vector,doflist);
+	 }
+	 else if (strcmp(data,"gradient")==0){
+		 _assert_(gradient);
+		 gradient->GetVectorFromInputs(vector,doflist);
+	 }
+	 else{
+		 _error_("Data " << data << " not supported yet");
+	 }
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputAverage(IssmDouble* pvalue){{{*/
+void ControlInput::GetInputAverage(IssmDouble* pvalue){
+	values->GetInputAverage(pvalue);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputValue(bool* pvalue){{{*/
+void ControlInput::GetInputValue(bool* pvalue){
+	values->GetInputValue(pvalue);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputValue(int* pvalue){{{*/
+void ControlInput::GetInputValue(int* pvalue){
+	values->GetInputValue(pvalue);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputValue(IssmDouble* pvalue){{{*/
+void ControlInput::GetInputValue(IssmDouble* pvalue){
+	values->GetInputValue(pvalue);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputValue(IssmDouble* pvalue){{{*/
+void ControlInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){
+	values->GetInputValue(pvalue,gauss);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputValue(IssmDouble* pvalue){{{*/
+void ControlInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){
+	values->GetInputValue(pvalue,gauss);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void ControlInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){
+	values->GetInputDerivativeValue(derivativevalues,xyz_list,gauss);
+}/*}}}*/
+/*FUNCTION ControlInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void ControlInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){
+	values->GetInputDerivativeValue(derivativevalues,xyz_list,gauss);
+}/*}}}*/
+/*FUNCTION ControlInput::SaveValue{{{*/
+void ControlInput::SaveValue(void){
+	if(!values) _error_("Values of " << EnumToStringx(this->enum_type) << " not found");
+
+	if(savedvalues) delete this->savedvalues;
+	this->savedvalues=dynamic_cast<Input*>(this->values->copy());
+}/*}}}*/
+/*FUNCTION ControlInput::UpdateValue{{{*/
+void ControlInput::UpdateValue(IssmDouble scalar){
+	if(!gradient)    _error_("Gradient of " << EnumToStringx(this->enum_type) << " not found");
+	if(!savedvalues) _error_("Values of " << EnumToStringx(this->enum_type) << " not found");
+
+	if(values) delete this->values;
+	this->values=dynamic_cast<Input*>(this->savedvalues->copy());
+	this->values->AXPY(gradient,scalar);
+}/*}}}*/
+/*FUNCTION ControlInput::VerticallyIntegrate{{{*/
+void ControlInput::VerticallyIntegrate(Input* thickness_input){
+	values->VerticallyIntegrate(thickness_input);
+}/*}}}*/
+/*FUNCTION ControlInput::Configure{{{*/
+void ControlInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/ControlInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/ControlInput.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/ControlInput.h	(revision 15012)
@@ -0,0 +1,98 @@
+/*! \file ControlInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _CONTROLINPUT_H_
+#define _CONTROLINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class ControlInput: public Input{
+
+	public:
+		int    enum_type;
+		int    control_id;
+		Input* values;
+		Input* savedvalues;
+		Input* minvalues;
+		Input* maxvalues;
+		Input* gradient;
+
+		/*ControlInput constructors, destructors: {{{*/
+		ControlInput();
+		ControlInput(int enum_type,int enum_input,IssmDouble* pvalues,IssmDouble* pmin,IssmDouble* pmax,int id);
+		~ControlInput();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ControlInput management: {{{*/
+		int    InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void SetInput(Input* in_input);
+		void GetInputValue(bool* pvalue);
+		void GetInputValue(int* pvalue);
+		void GetInputValue(IssmDouble* pvalue);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){_error_("not implemented yet");};
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){_error_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void ChangeEnum(int newenumtype){_error_("not implemented yet");};
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){_error_("not implemented yet");};
+		void ConstrainMin(IssmDouble minimum){_error_("not implemented yet");};
+		void Scale(IssmDouble scale_factor){_error_("not implemented yet");};
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar){_error_("not implemented yet");};
+		void Constrain(void);
+		void Constrain(IssmDouble min,IssmDouble max);
+		IssmDouble InfinityNorm(void){_error_("not implemented yet");};
+		IssmDouble Max(void){_error_("not implemented yet");};
+		IssmDouble MaxAbs(void){_error_("not implemented yet");};
+		IssmDouble Min(void){_error_("not implemented yet");};
+		IssmDouble MinAbs(void){_error_("not implemented yet");};
+		void Extrude(void);
+		void VerticallyIntegrate(Input* thickness_input);
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist,const char* data);
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values){_error_("not implemented yet");};
+		ElementResult* SpawnGradient(int step, IssmDouble time);
+		void GetGradient(Vector<IssmDouble>* gradient_vec,int* doflist);
+		void ScaleGradient(IssmDouble scale);
+		void SetGradient(Input* gradient_in);
+		void UpdateValue(IssmDouble scalar);
+		void SaveValue(void);
+		/*}}}*/
+
+};
+#endif  /* _CONTROLINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/DatasetInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/DatasetInput.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/DatasetInput.cpp	(revision 15012)
@@ -0,0 +1,111 @@
+/*!\file DatasetInput.c
+ * \brief: implementation of the datasetinput object
+ */
+/*Headers{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*DatasetInput constructors and destructor*/
+/*FUNCTION DatasetInput::DatasetInput(){{{*/
+DatasetInput::DatasetInput(){
+	enum_type=UNDEF;
+	inputs=NULL;
+}
+/*}}}*/
+/*FUNCTION DatasetInput::DatasetInput(int in_enum_type) {{{*/
+DatasetInput::DatasetInput(int in_enum_type){
+
+	enum_type  = in_enum_type;
+	inputs     = new Inputs();
+}
+/*}}}*/
+/*FUNCTION DatasetInput::~DatasetInput(){{{*/
+DatasetInput::~DatasetInput(){
+	delete inputs;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+		/*FUNCTION DatasetInput::Echo {{{*/
+void DatasetInput::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION DatasetInput::DeepEcho{{{*/
+void DatasetInput::DeepEcho(void){
+
+	_printLine_("DatasetInput:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("---inputs: "); inputs->Echo();
+}
+/*}}}*/
+/*FUNCTION DatasetInput::Id{{{*/
+int    DatasetInput::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DatasetInput::ObjectEnum{{{*/
+int DatasetInput::ObjectEnum(void){
+
+	return DatasetInputEnum;
+
+}
+/*}}}*/
+/*FUNCTION DatasetInput::copy{{{*/
+Object* DatasetInput::copy() {
+
+	DatasetInput* output=NULL;
+
+	output = new DatasetInput();
+	output->enum_type=this->enum_type;
+	output->inputs=(Inputs*)this->inputs->Copy();
+
+	return output;
+}
+/*}}}*/
+/*FUNCTION DatasetInput::SpawnTriaInput{{{*/
+Input* DatasetInput::SpawnTriaInput(int* indices){
+
+	/*output*/
+	DatasetInput* outinput=NULL;
+
+	/*Create new Datasetinput (copy of current input)*/
+	outinput=new DatasetInput();
+	outinput->enum_type=this->enum_type;
+	outinput->inputs=dynamic_cast<Inputs*>(this->inputs->SpawnTriaInputs(indices));
+
+	/*Assign output*/
+	return outinput;
+}
+/*}}}*/
+
+/*DatasetInput management*/
+/*FUNCTION DatasetInput::InstanceEnum{{{*/
+int DatasetInput::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION DatasetInput::Configure{{{*/
+void DatasetInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
+/*FUNCTION DatasetInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss,int index){{{*/
+void DatasetInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss,int index){
+
+	/*Get requested input within dataset*/
+	if(index<0 || index > inputs->Size()-1) _error_("index requested (" << index << ") exceeds dataset size (" << inputs->Size() << ")");
+	Input* input=dynamic_cast<Input*>(this->inputs->GetObjectByOffset(index));
+
+	input->GetInputValue(pvalue,gauss);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/DatasetInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/DatasetInput.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/DatasetInput.h	(revision 15012)
@@ -0,0 +1,91 @@
+/*! \file DatasetInput.h 
+ *  \brief: header file for datasetinput object
+ */
+
+#ifndef _DATASETINPUT_H_
+#define _DATASETINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class DatasetInput: public Input{
+
+	public:
+		int     enum_type;
+		Inputs *inputs;
+
+		/*DatasetInput constructors, destructors: {{{*/
+		DatasetInput();
+		DatasetInput(int enum_type);
+		~DatasetInput();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*DatasetInput management: {{{*/
+		int    InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time){_error_("not implemented yet");};
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error_("not implemented yet");};
+		void GetInputValue(int* pvalue){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetInputAverage(IssmDouble* pvalue){_error_("not implemented yet");};
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){_error_("not implemented yet");};
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){_error_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void ChangeEnum(int newenumtype){_error_("not implemented yet");};
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){_error_("not implemented yet");};
+		void ConstrainMin(IssmDouble minimum){_error_("not implemented yet");};
+		void Scale(IssmDouble scale_factor){_error_("not implemented yet");};
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar){_error_("not implemented yet");};
+		void Constrain(void){_error_("not implemented yet");};
+		void Constrain(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		IssmDouble InfinityNorm(void){_error_("not implemented yet");};
+		IssmDouble Max(void){_error_("not implemented yet");};
+		IssmDouble MaxAbs(void){_error_("not implemented yet");};
+		IssmDouble Min(void){_error_("not implemented yet");};
+		IssmDouble MinAbs(void){_error_("not implemented yet");};
+		void Extrude(void){_error_("not implemented yet");};
+		void VerticallyIntegrate(Input* thickness_input){_error_("not implemented yet");};
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){_error_("not implemented yet");};
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values){_error_("not implemented yet");};
+		ElementResult* SpawnGradient(int step, IssmDouble time){_error_("not implemented yet");};
+		void GetGradient(Vector<IssmDouble>* gradient_vec,int* doflist){_error_("not implemented yet");};
+		void ScaleGradient(IssmDouble scale){_error_("not implemented yet");};
+		void SetGradient(Input* gradient_in){_error_("not implemented yet");};
+		void UpdateValue(IssmDouble scalar){_error_("not implemented yet");};
+		void SaveValue(void){_error_("not implemented yet");};
+		/*}}}*/
+
+};
+#endif  /* _DATASETINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/DoubleInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/DoubleInput.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/DoubleInput.cpp	(revision 15012)
@@ -0,0 +1,348 @@
+/*!\file DoubleInput.c
+ * \brief: implementation of the DoubleInput object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*DoubleInput constructors and destructor*/
+/*FUNCTION DoubleInput::DoubleInput(){{{*/
+DoubleInput::DoubleInput(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::DoubleInput(IssmDouble value){{{*/
+DoubleInput::DoubleInput(int in_enum_type,IssmDouble in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::~DoubleInput(){{{*/
+DoubleInput::~DoubleInput(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+		/*FUNCTION DoubleInput::Echo {{{*/
+void DoubleInput::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION DoubleInput::DeepEcho{{{*/
+void DoubleInput::DeepEcho(void){
+
+	_printLine_("DoubleInput:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+}
+/*}}}*/
+/*FUNCTION DoubleInput::Id{{{*/
+int    DoubleInput::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleInput::ObjectEnum{{{*/
+int DoubleInput::ObjectEnum(void){
+
+	return DoubleInputEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::copy{{{*/
+Object* DoubleInput::copy() {
+
+	return new DoubleInput(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*DoubleInput management*/
+/*FUNCTION DoubleInput::InstanceEnum{{{*/
+int DoubleInput::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::SpawnTriaInput{{{*/
+Input* DoubleInput::SpawnTriaInput(int* indices){
+
+	/*output*/
+	DoubleInput* outinput=new DoubleInput();
+
+	/*only copy current value*/
+	outinput->enum_type=this->enum_type;
+	outinput->value=this->value;
+
+	/*Assign output*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::SpawnResult{{{*/
+ElementResult* DoubleInput::SpawnResult(int step, IssmDouble time){
+
+	return new DoubleElementResult(this->enum_type,this->value,step,time);
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION DoubleInput::GetInputValue(bool* pvalue) {{{*/
+void DoubleInput::GetInputValue(bool* pvalue){
+	_error_("Double input of enum " << EnumToStringx(enum_type) << " cannot return a boolean");
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputValue(int* pvalue){{{*/
+void DoubleInput::GetInputValue(int* pvalue){
+	_error_("Double input of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an integer");
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputValue(IssmDouble* pvalue){{{*/
+void DoubleInput::GetInputValue(IssmDouble* pvalue){
+
+	/*return value*/
+	*pvalue=value;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void DoubleInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){*pvalue=this->value;}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void DoubleInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){*pvalue=this->value;}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void DoubleInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void DoubleInput::GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){
+	/*Epsilon is zero as vx is constant over the element*/
+	for(int i=0;i<3;i++) epsilonvx[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void DoubleInput::GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){
+	/*Epsilon is zero as vy is constant over the element*/
+	for(int i=0;i<3;i++) epsilonvy[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Epsilon is zero as vx is constant over the element*/
+	for(int i=0;i<6;i++) epsilonvx[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Epsilon is zero as vy is constant over the element*/
+	for(int i=0;i<6;i++) epsilonvy[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Epsilon is zero as vz is constant over the element*/
+	for(int i=0;i<6;i++) epsilonvz[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Epsilon is zero as vx is constant over the element*/
+	for(int i=0;i<5;i++) epsilonvx[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){
+	/*Epsilon is zero as vy is constant over the element*/
+	for(int i=0;i<5;i++) epsilonvy[i]=0;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::ChangeEnum{{{*/
+void DoubleInput::ChangeEnum(int newenumtype){
+	this->enum_type=newenumtype;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::SquareMin{{{*/
+void DoubleInput::SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){
+
+	/*square min of a IssmDouble is the square of the IssmDouble itself: */
+	*psquaremin=pow(value,2);
+}
+/*}}}*/
+/*FUNCTION DoubleInput::Scale{{{*/
+void DoubleInput::Scale(IssmDouble scale_factor){
+	value=value*scale_factor;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::ConstrainMin{{{*/
+void DoubleInput::ConstrainMin(IssmDouble minimum){
+	if (value<minimum) value=minimum;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::AXPY{{{*/
+void DoubleInput::AXPY(Input* xinput,IssmDouble scalar){
+
+	DoubleInput*  xIssmDoubleinput=NULL;
+
+	/*xinput is of the same type, so cast it: */
+	xIssmDoubleinput=(DoubleInput*)xinput;
+
+	/*Carry out the AXPY operation depending on type:*/
+	switch(xinput->ObjectEnum()){
+
+		case DoubleInputEnum:
+			this->value=this->value+scalar*xIssmDoubleinput->value;
+			return;
+
+		default:
+			_error_("not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::Constrain{{{*/
+void DoubleInput::Constrain(IssmDouble cm_min, IssmDouble cm_max){
+
+	if(!xIsNan<IssmDouble>(cm_min)) if (this->value<cm_min)this->value=cm_min;
+	if(!xIsNan<IssmDouble>(cm_max)) if (this->value>cm_max)this->value=cm_max;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::Max{{{*/
+IssmDouble DoubleInput::Max(void){
+	return this->value;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::MaxAbs{{{*/
+IssmDouble DoubleInput::MaxAbs(void){
+	return fabs(this->value);
+}
+/*}}}*/
+/*FUNCTION DoubleInput::Min{{{*/
+IssmDouble DoubleInput::Min(void){
+	return this->value;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::MinAbs{{{*/
+IssmDouble DoubleInput::MinAbs(void){
+	return fabs(this->value);
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetVectorFromInputs{{{*/
+void DoubleInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+
+	_error_("not supporte yet!");
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetValuesPtr{{{*/
+void DoubleInput::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	_error_("not supported yet!");
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputAverage{{{*/
+void DoubleInput::GetInputAverage(IssmDouble* pvalue){
+	*pvalue=value;
+}
+/*}}}*/
+/*FUNCTION DoubleInput::VerticallyIntegrate{{{*/
+void DoubleInput::VerticallyIntegrate(Input* thickness_input){
+
+	/*Intermediaries*/
+	IssmDouble thickness_value;
+
+	/*Check that input provided is a thickness*/
+	if (thickness_input->InstanceEnum()!=ThicknessEnum) _error_("Input provided is not a Thickness (enum_type is " << EnumToStringx(thickness_input->InstanceEnum()) << ")");
+
+	/*vertically integrate depending on type:*/
+	switch(thickness_input->ObjectEnum()){
+
+		case PentaP1InputEnum:
+			thickness_input->GetInputAverage(&thickness_value);
+			this->value=this->value*thickness_value;
+			return;
+
+		default:
+			_error_("not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION DoubleInput::PointwiseDivide{{{*/
+Input* DoubleInput::PointwiseDivide(Input* inputB){
+
+	/*Ouput*/
+	DoubleInput* outinput=NULL;
+
+	/*Intermediaries*/
+	IssmDouble       Bvalue;
+
+	/*Check that inputB is of the same type*/
+	inputB->GetInputAverage(&Bvalue);
+
+	/*Create new DoubleInput*/
+	outinput=new DoubleInput(this->enum_type,this->value/Bvalue);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::PointwiseMin{{{*/
+Input* DoubleInput::PointwiseMin(Input* input){
+
+	/*Ouput*/
+	DoubleInput* outinput=NULL;
+
+	/*Intermediaries*/
+	IssmDouble       min;
+
+	/*Check that inputB is of the same type*/
+	if (input->Min() < this->Min()) min=input->Min();
+	else min=this->Min();
+
+	/*Create new DoubleInput*/
+	outinput=new DoubleInput(this->enum_type,min);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::PointwiseMax{{{*/
+Input* DoubleInput::PointwiseMax(Input* input){
+
+	/*Ouput*/
+	DoubleInput* outinput=NULL;
+
+	/*Intermediaries*/
+	IssmDouble       max;
+
+	/*Check that inputB is of the same type*/
+	if (input->Max() > this->Max()) max=input->Max();
+	else max=this->Max();
+
+	/*Create new DoubleInput*/
+	outinput=new DoubleInput(this->enum_type,max);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::Configure{{{*/
+void DoubleInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/DoubleInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/DoubleInput.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/DoubleInput.h	(revision 15012)
@@ -0,0 +1,84 @@
+/*! \file DoubleInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _DOUBLEINPUT_H_
+#define _DOUBLEINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class DoubleInput: public Input{
+
+	public:
+		int    enum_type;
+		IssmDouble value;
+
+		/*DoubleInput constructors, destructors: {{{*/
+		DoubleInput();
+		DoubleInput(int enum_type,IssmDouble value);
+		~DoubleInput();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*DoubleInput management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB);
+		Input* PointwiseMin(Input* inputB);
+		Input* PointwiseMax(Input* inputB);
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue);
+		void GetInputValue(int* pvalue);
+		void GetInputValue(IssmDouble* pvalue);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){_error_("not implemented yet");};
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){_error_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss);
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss);
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss);
+		void ChangeEnum(int newenumtype);
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum);
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max);
+		IssmDouble InfinityNorm(void){_error_("not implemented yet");};
+		IssmDouble Max(void);
+		IssmDouble MaxAbs(void);
+		IssmDouble Min(void);
+		IssmDouble MinAbs(void);
+		void Extrude(void){_error_("not supported yet");};
+		void VerticallyIntegrate(Input* thickness_input);
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _DOUBLEINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/Input.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/Input.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/Input.h	(revision 15012)
@@ -0,0 +1,74 @@
+/*!\file:  Input.h
+ * \brief abstract class for Input object
+ */ 
+
+#ifndef _INPUT_H_
+#define _INPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Object.h"
+class Node;
+class ElementResult;
+class GaussTria;
+class Parameters;
+class GaussPenta;
+template <class doubletype> class Vector;
+#include "../../shared/shared.h"
+/*}}}*/
+
+
+class Input: public Object{
+
+	public: 
+
+		virtual        ~Input(){};
+
+		virtual int  InstanceEnum()=0; 
+		virtual void GetInputValue(bool* pvalue)=0;
+		virtual void GetInputValue(int* pvalue)=0;
+		virtual void GetInputValue(IssmDouble* pvalue)=0;
+		virtual void GetInputValue(IssmDouble* pvalue,GaussTria* gauss)=0;
+		virtual void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss)=0;
+		virtual void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time)=0;
+		virtual void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time)=0;
+		virtual void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index)=0;
+		virtual void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,int index)=0;
+		virtual void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss)=0;
+		virtual void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss)=0;
+		virtual void GetInputAverage(IssmDouble* pvalue)=0;
+		virtual void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes)=0;
+		virtual void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime)=0;
+		virtual void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss)=0;
+		virtual void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss)=0;
+		virtual void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss)=0;
+		virtual void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss)=0;
+		virtual void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss)=0;
+		virtual void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss)=0;
+		virtual void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss)=0;
+		virtual void ChangeEnum(int newenumtype)=0;
+		virtual void Configure(Parameters* parameters)=0;
+
+		virtual void   SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters)=0;
+		virtual void   ConstrainMin(IssmDouble minimum)=0;
+		virtual IssmDouble InfinityNorm(void)=0;
+		virtual IssmDouble MaxAbs(void)=0;
+		virtual IssmDouble MinAbs(void)=0;
+		virtual IssmDouble Max(void)=0;
+		virtual IssmDouble Min(void)=0;
+		virtual void   Scale(IssmDouble scale_factor)=0;
+		virtual void   ArtificialNoise(IssmDouble min,IssmDouble max)=0;
+		virtual void   AXPY(Input* xinput,IssmDouble scalar)=0;
+		virtual void   Constrain(IssmDouble cm_min, IssmDouble cm_max)=0;
+		virtual void   VerticallyIntegrate(Input* thickness_input)=0;
+		virtual void   Extrude()=0;
+		virtual void   GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist)=0;
+		virtual void   GetValuesPtr(IssmDouble** pvalues,int* pnum_values)=0;
+
+		virtual Input* SpawnTriaInput(int* indices)=0;
+		virtual Input* PointwiseDivide(Input* inputB)=0;
+		virtual Input* PointwiseMax(Input* inputmax)=0;
+		virtual Input* PointwiseMin(Input* inputmin)=0;
+		virtual ElementResult* SpawnResult(int step, IssmDouble time)=0;
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Inputs/Inputs.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/Inputs.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/Inputs.cpp	(revision 15012)
@@ -0,0 +1,479 @@
+/*
+ * \file Inputs.c
+ * \brief: implementation of the Inputs class, derived from DataSet class
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Input.h"
+#include "./Inputs.h"
+#include "../../shared/shared.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Inputs::Inputs(){{{*/
+Inputs::Inputs(){
+	return;
+}
+/*}}}*/
+/*FUNCTION Inputs::~Inputs(){{{*/
+Inputs::~Inputs(){
+	return;
+}
+/*}}}*/
+
+/*Object management*/
+/*FUNCTION Inputs::GetInputValue(bool* pvalue,int enum-type){{{*/
+void Inputs::GetInputValue(bool* pvalue,int enum_type){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+	bool   found=false;
+
+	/*Go through inputs and check whether any input with the same name is already in: */
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+		if (input->InstanceEnum()==enum_type){
+			found=true;
+			break;
+		}
+	}
+
+	if (!found){
+		/*we could not find an input with the correct enum type. No defaults values were provided, 
+		 * error out: */
+		_error_("could not find input with enum type " << enum_type << " (" << EnumToStringx(enum_type) << ")");
+	}
+
+	/*Ok, we have an input if we made it here, request the input to return the value: */
+	input->GetInputValue(pvalue);
+
+}
+/*}}}*/
+/*FUNCTION Inputs::GetInputValue(int* pvalue,int enum-type){{{*/
+void Inputs::GetInputValue(int* pvalue,int enum_type){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+	bool   found=false;
+
+	/*Go through inputs and check whether any input with the same name is already in: */
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+		if (input->InstanceEnum()==enum_type){
+			found=true;
+			break;
+		}
+	}
+
+	if (!found){
+		/*we could not find an input with the correct enum type. No defaults values were provided, 
+		 * error out: */
+		_error_("could not find input with enum type " << enum_type << " (" << EnumToStringx(enum_type) << ")");
+	}
+
+	/*Ok, we have an input if we made it here, request the input to return the value: */
+	input->GetInputValue(pvalue);
+
+}
+/*}}}*/
+/*FUNCTION Inputs::GetInputValue(IssmDouble* pvalue,int enum-type){{{*/
+void Inputs::GetInputValue(IssmDouble* pvalue,int enum_type){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+	bool   found=false;
+
+	/*Go through inputs and check whether any input with the same name is already in: */
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object); 
+		if (input->InstanceEnum()==enum_type){
+			found=true;
+			break;
+		}
+	}
+
+	if (!found){
+		/*we could not find an input with the correct enum type. No defaults values were provided, 
+		 * error out: */
+		_error_("could not find input with enum type " << enum_type << " (" << EnumToStringx(enum_type) << ")");
+	}
+
+	/*Ok, we have an input if we made it here, request the input to return the value: */
+	input->GetInputValue(pvalue);
+
+}
+/*}}}*/
+/*FUNCTION Inputs::GetInputAverage{{{*/
+void Inputs::GetInputAverage(IssmDouble* pvalue,int enum_type){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+	bool   found=false;
+
+	/*Go through inputs and check whether any input with the same name is already in: */
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+		if (input->InstanceEnum()==enum_type){
+			found=true;
+			break;
+		}
+	}
+
+	if (!found){
+		/*we could not find an input with the correct enum type. No defaults values were provided, 
+		 * error out: */
+		_error_("could not find input with enum type " << enum_type << " (" << EnumToStringx(enum_type) << ")");
+	}
+
+	/*Ok, we have an input if we made it here, request the input to return the value: */
+	input->GetInputAverage(pvalue);
+
+}
+/*}}}*/
+/*FUNCTION Inputs::AddInput{{{*/
+int  Inputs::AddInput(Input* in_input){
+
+	/*First, go through dataset of inputs and check whether any input 
+	 * with the same name is already in. If so, erase the corresponding 
+	 * object before adding this new one: */
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+
+	/*In debugging mode, check that the input is not a NULL pointer*/
+	_assert_(in_input);
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+
+		if (input->InstanceEnum()==in_input->InstanceEnum()){
+			this->DeleteObject(input);
+			break;
+		}
+	}
+	this->AddObject(in_input);
+
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Inputs::ChangeEnum{{{*/
+void  Inputs::ChangeEnum(int oldenumtype,int newenumtype){
+
+	/*Go through dataset of inputs and look for input with 
+	 * same enum as input enum, once found, just change its name */
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+
+	/*Delete existing input of newenumtype if it exists*/
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+		input=dynamic_cast<Input*>(*object);
+
+		if (input->InstanceEnum()==newenumtype){
+			this->DeleteObject(input);
+			break;
+		}
+	}
+
+	/*Change enum_type of input of oldenumtype*/
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+
+		if (input->InstanceEnum()==oldenumtype){
+			input->ChangeEnum(newenumtype);
+			break;
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION Inputs::ConstrainMin{{{*/
+void  Inputs::ConstrainMin(int constrain_enum, IssmDouble minimum){
+
+	/*Find x and y inputs: */
+	Input* constrain_input=dynamic_cast<Input*>(this->GetInput(constrain_enum));
+
+	/*some checks: */
+	if(!constrain_input) _error_("input " << EnumToStringx(constrain_enum) << " could not be found!");
+
+	/*Apply ContrainMin: */
+	constrain_input->ConstrainMin(minimum);
+}
+/*}}}*/
+/*FUNCTION Inputs::InfinityNorm{{{*/
+IssmDouble Inputs::InfinityNorm(int enumtype){
+
+	/*Output*/
+	IssmDouble norm;
+
+	/*Get input*/
+	Input* input=dynamic_cast<Input*>(this->GetInput(enumtype));
+
+	/*Apply ContrainMin: */
+	if (input){
+		norm=input->InfinityNorm();
+	}
+	else{
+		norm=0;
+	}
+
+	/*Return output*/
+	return norm;
+}
+/*}}}*/
+/*FUNCTION Inputs::Max{{{*/
+IssmDouble Inputs::Max(int enumtype){
+
+	/*Output*/
+	IssmDouble max;
+
+	/*Get input*/
+	Input* input=dynamic_cast<Input*>(this->GetInput(enumtype));
+
+	/*Apply ContrainMin: */
+	if (input){
+		max=input->Max();
+	}
+	else{
+		_error_("Input " << EnumToStringx(enumtype) << " not found");
+	}
+
+	/*Return output*/
+	return max;
+}
+/*}}}*/
+/*FUNCTION Inputs::MaxAbs{{{*/
+IssmDouble Inputs::MaxAbs(int enumtype){
+
+	/*Output*/
+	IssmDouble max;
+
+	/*Get input*/
+	Input* input=dynamic_cast<Input*>(this->GetInput(enumtype));
+
+	/*Apply ContrainMin: */
+	if (input){
+		max=input->MaxAbs();
+	}
+	else{
+		_error_("Input " << EnumToStringx(enumtype) << " not found");
+	}
+
+	/*Return output*/
+	return max;
+}
+/*}}}*/
+/*FUNCTION Inputs::Min{{{*/
+IssmDouble Inputs::Min(int enumtype){
+
+	/*Output*/
+	IssmDouble min;
+
+	/*Get input*/
+	Input* input=dynamic_cast<Input*>(this->GetInput(enumtype));
+
+	/*Apply ContrainMin: */
+	if (input){
+		min=input->Min();
+	}
+	else{
+		_error_("Input " << EnumToStringx(enumtype) << " not found");
+	}
+
+	/*Return output*/
+	return min;
+}
+/*}}}*/
+/*FUNCTION Inputs::MinAbs{{{*/
+IssmDouble Inputs::MinAbs(int enumtype){
+
+	/*Output*/
+	IssmDouble min;
+
+	/*Get input*/
+	Input* input=dynamic_cast<Input*>(this->GetInput(enumtype));
+
+	/*Apply ContrainMin: */
+	if (input){
+		min=input->MinAbs();
+	}
+	else{
+		_error_("Input " << EnumToStringx(enumtype) << " not found");
+	}
+
+	/*Return output*/
+	return min;
+}
+/*}}}*/
+/*FUNCTION Inputs::GetInput{{{*/
+Input* Inputs::GetInput(int enum_name){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+
+		if (input->InstanceEnum()==enum_name){
+			return input;
+		}
+	}
+	return NULL;
+}
+/*}}}*/
+/*FUNCTION Inputs::DeleteInput{{{*/
+int  Inputs::DeleteInput(int enum_type){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+
+		if (input->InstanceEnum()==enum_type){
+			this->DeleteObject(input);
+			break;
+		}
+	}
+
+	return 1;
+
+}
+/*}}}*/
+/*FUNCTION Inputs::DuplicateInput{{{*/
+void  Inputs::DuplicateInput(int original_enum,int new_enum){
+
+	/*Make a copy of the original input: */
+	Input* original=dynamic_cast<Input*>(this->GetInput(original_enum));
+	if(!original)_error_("could not find input with enum: " << EnumToStringx(original_enum)); 
+	Input* copy=dynamic_cast<Input*>(original->copy());
+
+	/*Change copy enum to reinitialized_enum: */
+	copy->ChangeEnum(new_enum);
+
+	/*Add copy into inputs, it will wipe off the one already there: */
+	this->AddInput(dynamic_cast<Input*>(copy));
+}
+/*}}}*/
+/*FUNCTION Inputs::SpawnTriaInputs{{{*/
+Inputs* Inputs::SpawnTriaInputs(int* indices){
+
+	/*Intermediary*/
+	vector<Object*>::iterator object;
+	Input* inputin=NULL;
+	Input* inputout=NULL;
+
+	/*Output*/
+	Inputs* newinputs=new Inputs();
+
+	/*Go through inputs and call Spawn function*/
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		/*Create new input*/
+		inputin=dynamic_cast<Input*>(*object);
+		inputout=inputin->SpawnTriaInput(indices);
+
+		/*Add input to new inputs*/
+		newinputs->AddObject(inputout);
+	}
+
+	/*Assign output pointer*/
+	return newinputs;
+}
+/*}}}*/
+/*FUNCTION Inputs::AXPY{{{*/
+void  Inputs::AXPY(int MeshYEnum, IssmDouble scalar, int MeshXEnum){
+
+	/*Find x and y inputs: */
+	Input* xinput=dynamic_cast<Input*>(this->GetInput(MeshXEnum));
+	Input* yinput=dynamic_cast<Input*>(this->GetInput(MeshYEnum));
+
+	/*some checks: */
+	if(!xinput) _error_("input " << EnumToStringx(MeshXEnum) << " could not be found!");
+	if(!yinput) _error_("input " << EnumToStringx(MeshYEnum) << " could not be found!");
+
+	/*Apply AXPY: */
+	yinput->AXPY(xinput,scalar);
+}
+/*}}}*/
+/*FUNCTION Inputs::Configure{{{*/
+void Inputs::Configure(Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Input* input=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		input=dynamic_cast<Input*>(*object);
+		input->Configure(parameters);
+
+	}
+
+}
+/*}}}*/
+
+/*Methods relating to inputs: */
+void IsInputConverged(IssmDouble* peps, Input** new_inputs,Input** old_inputs,int num_inputs,int criterion_enum){ /*{{{*/
+ 
+	/*figure out convergence at the input level. 
+	  We are given a list of inputs, new and old, and a criterion, and using the
+	  inputs, we return the value of the criterion test, which will be used at the
+	  solution level to determine convergence.
+	  */ 
+
+	int i,j;
+
+	/*output: */
+	IssmDouble eps;
+
+	/*intermediary: */
+	IssmDouble *newvalues     = NULL;
+	IssmDouble *oldvalues     = NULL;
+	int     num_values;
+	IssmDouble  ndu        = 0;
+	IssmDouble  nu         = 0;
+
+	if(criterion_enum==RelativeEnum){
+
+		/*conpute ndu/du (where u could be velocity, pressure, temperature, etc ...): */
+		for(i=0;i<num_inputs;i++){
+
+			/*in debugging mode, check that the inputs are of the same type*/
+			_assert_(new_inputs[i]->ObjectEnum()==old_inputs[i]->ObjectEnum());
+
+			/*Get pointers*/
+			new_inputs[i]->GetValuesPtr(&newvalues,&num_values);
+			old_inputs[i]->GetValuesPtr(&oldvalues,&num_values);
+			for(j=0;j<num_values;j++){
+				ndu+=pow(newvalues[j]-oldvalues[j],2);
+				nu+=pow(oldvalues[j],2);
+			}
+		}
+
+		/*take square root: */
+		ndu=sqrt(ndu);
+		nu=sqrt(nu);
+
+		/*now, compute eps: */
+		if(reCast<bool>(nu))eps=ndu/nu;
+		else eps=0;
+	}
+	else _error_("convergence criterion " << EnumToStringx(criterion_enum) << " not supported yet!");
+
+	/*Assign output pointers:*/
+	*peps=eps;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/Inputs.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/Inputs.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/Inputs.h	(revision 15012)
@@ -0,0 +1,48 @@
+#ifndef _CONTAINER_INPUTS_H_
+#define _CONTAINER_INPUTS_H_
+
+/*forward declarations */
+class Parameters;
+class Input;
+
+#include "../DataSet.h"
+#include "../../shared/shared.h"
+
+/*! \brief Declaration of Inputs class.
+ *
+ * Declaration of Inputs class.  Inputs are vector lists (Containers) of Input objects.
+ */ 
+class Inputs: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Inputs();
+		~Inputs();
+
+		/*numerics*/
+		int        AddInput(Input* in_input);
+		void       ChangeEnum(int enumtype,int new_enumtype);
+		void       ConstrainMin(int constrain_enum, IssmDouble minimum);
+		int        DeleteInput(int enum_type);
+		void       DuplicateInput(int original_enum,int new_enum);
+		Input*     GetInput(int enum_name);
+		Inputs*    SpawnTriaInputs(int* indices);
+		void       AXPY(int MeshYEnum, IssmDouble scalar, int MeshXEnum);
+		IssmDouble  InfinityNorm(int enumtype);
+		IssmDouble  Max(int enumtype);
+		IssmDouble  MaxAbs(int enumtype);
+		IssmDouble  Min(int enumtype);
+		IssmDouble  MinAbs(int enumtype);
+		void GetInputAverage(IssmDouble* pvalue, int enum_type);
+		void GetInputValue(bool* pvalue,int enum_type);
+		void GetInputValue(int* pvalue,int enum_type);
+		void GetInputValue(IssmDouble* pvalue,int enum_type);
+		void Configure(Parameters* parameters);
+
+};
+
+/*Methods relating to inputs: */
+void IsInputConverged(IssmDouble* peps, Input** new_inputs,Input** old_inputs,int num_inputs,int criterion_enum);
+
+#endif //ifndef _INPUTS_H_
Index: /issm/trunk-jpl/src/c/classes/Inputs/IntInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/IntInput.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/IntInput.cpp	(revision 15012)
@@ -0,0 +1,188 @@
+/*!\file IntInput.c
+ * \brief: implementation of the IntInput object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*IntInput constructors and destructor*/
+/*FUNCTION IntInput::IntInput(){{{*/
+IntInput::IntInput(){
+	return;
+}
+/*}}}*/
+/*FUNCTION IntInput::IntInput(IssmDouble* values){{{*/
+IntInput::IntInput(int in_enum_type,IssmInt in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION IntInput::~IntInput(){{{*/
+IntInput::~IntInput(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION IntInput::DeepEcho{{{*/
+void IntInput::DeepEcho(void){
+
+	_printLine_("IntInput:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << (int)this->value);
+}
+/*}}}*/
+/*FUNCTION IntInput::Id{{{*/
+int    IntInput::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION IntInput::ObjectEnum{{{*/
+int IntInput::ObjectEnum(void){
+
+	return IntInputEnum;
+
+}
+/*}}}*/
+/*FUNCTION IntInput::copy{{{*/
+Object* IntInput::copy() {
+
+	return new IntInput(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*IntInput management*/
+/*FUNCTION IntInput::Echo {{{*/
+void IntInput::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION IntInput::InstanceEnum{{{*/
+int IntInput::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION IntInput::SpawnTriaInput{{{*/
+Input* IntInput::SpawnTriaInput(int* indices){
+
+	/*output*/
+	IntInput* outinput=new IntInput();
+
+	/*only copy current value*/
+	outinput->enum_type=this->enum_type;
+	outinput->value=this->value;
+
+	/*Assign output*/
+	return outinput;
+}
+/*}}}*/
+/*FUNCTION IntInput::SpawnResult{{{*/
+ElementResult* IntInput::SpawnResult(int step, IssmDouble time){
+
+	_error_("not supported yet!");
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION IntInput::GetInputValue(bool* pvalue) {{{*/
+void IntInput::GetInputValue(bool* pvalue){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputValue(int* pvalue){{{*/
+void IntInput::GetInputValue(int* pvalue){
+	*pvalue=value;
+}
+/*}}}*/
+/*FUNCTION IntInput::GetInputValue(IssmDouble* pvalue){{{*/
+void IntInput::GetInputValue(IssmDouble* pvalue){
+	_error_("IntInput cannot return a IssmDouble in parallel");
+}
+/*}}}*/
+/*FUNCTION IntInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void IntInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void IntInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::ChangeEnum{{{*/
+void IntInput::ChangeEnum(int newenumtype){
+	this->enum_type=newenumtype;
+}
+/*}}}*/
+/*FUNCTION IntInput::SquareMin{{{*/
+void IntInput::SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){
+
+	/*square min of an integer is the square of the integer itself: */
+	*psquaremin=pow((IssmDouble)value,2);
+}
+/*}}}*/
+/*FUNCTION IntInput::Scale{{{*/
+void IntInput::Scale(IssmDouble scale_factor){
+	IssmDouble dvalue=(IssmDouble)value*scale_factor;
+	value=reCast<int>(dvalue);
+}
+/*}}}*/
+/*FUNCTION IntInput::AXPY{{{*/
+void IntInput::AXPY(Input* xinput,IssmDouble scalar){
+
+	IssmDouble dvalue;
+	IntInput*  xintinput=NULL;
+
+	/*xinput is of the same type, so cast it: */
+	xintinput=(IntInput*)xinput;
+
+	/*Carry out the AXPY operation depending on type:*/
+	switch(xinput->ObjectEnum()){
+
+		case IntInputEnum:
+			dvalue=(IssmDouble)this->value+scalar*(IssmDouble)xintinput->value;
+			this->value=reCast<int>(dvalue);
+			return;
+
+		default:
+			_error_("not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION IntInput::Constrain{{{*/
+void IntInput::Constrain(IssmDouble cm_min, IssmDouble cm_max){
+
+	if(!xIsNan<IssmDouble>(cm_min)) if (this->value<cm_min)this->value=reCast<int>(cm_min);
+	if(!xIsNan<IssmDouble>(cm_max)) if (this->value>cm_max)this->value=reCast<int>(cm_max);
+
+}
+/*}}}*/
+/*FUNCTION IntInput::GetVectorFromInputs{{{*/
+void IntInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+
+	_error_("not supporte yet!");
+
+}
+/*}}}*/
+/*FUNCTION IntInput::GetValuesPtr{{{*/
+void IntInput::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	_error_("not supported yet!");
+
+}
+/*}}}*/
+/*FUNCTION IntInput::Configure{{{*/
+void IntInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/IntInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/IntInput.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/IntInput.h	(revision 15012)
@@ -0,0 +1,86 @@
+/*! \file IntInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _INTINPUT_H_
+#define _INTINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class IntInput: public Input{
+
+	public:
+		/*just hold 3 values for 3 vertices: */
+		int    enum_type;
+		IssmInt value;
+
+		/*IntInput constructors, destructors: {{{*/
+		IntInput();
+		IntInput(int enum_type,IssmInt value);
+		~IntInput();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*IntInput management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue);
+		void GetInputValue(int* pvalue);
+		void GetInputValue(IssmDouble* pvalue);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputAverage(IssmDouble* pvalue){_error_("not implemented yet");};
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){_error_("not implemented yet");};
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){_error_("not implemented yet");};
+
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum){_error_("not implemented yet");};
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max);
+		IssmDouble InfinityNorm(void){_error_("InfinityNorm not implemented for integers");};
+		IssmDouble Max(void){_error_("Max not implemented for integers");};
+		IssmDouble MaxAbs(void){_error_("Max not implemented for integers");};
+		IssmDouble Min(void){_error_("Min not implemented for integers");};
+		IssmDouble MinAbs(void){_error_("Min not implemented for integers");};
+		void Extrude(void){_error_("not supported yet");};
+		void VerticallyIntegrate(Input* thickness_input){_error_("not supported yet");};
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _INTINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/PentaP1Input.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/PentaP1Input.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/PentaP1Input.cpp	(revision 15012)
@@ -0,0 +1,614 @@
+/*!\file PentaP1Input.c
+ * \brief: implementation of the PentaP1Input object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*PentaP1Input constructors and destructor*/
+/*FUNCTION PentaP1Input::PentaP1Input(){{{*/
+PentaP1Input::PentaP1Input(){
+	return;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::PentaP1Input(int in_enum_type,IssmDouble* values){{{*/
+PentaP1Input::PentaP1Input(int in_enum_type,IssmDouble* in_values)
+		:PentaRef(1)
+{
+
+	/*Set PentaRef*/
+	this->SetElementType(P1Enum,0);
+	this->element_type=P1Enum;
+
+	enum_type=in_enum_type;
+	values[0]=in_values[0];
+	values[1]=in_values[1];
+	values[2]=in_values[2];
+	values[3]=in_values[3];
+	values[4]=in_values[4];
+	values[5]=in_values[5];
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::~PentaP1Input(){{{*/
+PentaP1Input::~PentaP1Input(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION PentaP1Input::Echo {{{*/
+void PentaP1Input::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::DeepEcho{{{*/
+void PentaP1Input::DeepEcho(void){
+
+	_printLine_("PentaP1Input:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   values: [" << this->values[0] << " " << this->values[1] << " " << this->values[2] << " " << this->values[3] << " " << this->values[4] << " " << this->values[5] << "]");
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Id{{{*/
+int    PentaP1Input::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION PentaP1Input::ObjectEnum{{{*/
+int PentaP1Input::ObjectEnum(void){
+
+	return PentaP1InputEnum;
+
+}
+/*}}}*/
+
+/*PentaP1Input management*/
+/*FUNCTION PentaP1Input::copy{{{*/
+Object* PentaP1Input::copy() {
+
+	return new PentaP1Input(this->enum_type,this->values);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::InstanceEnum{{{*/
+int PentaP1Input::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::SpawnTriaInput{{{*/
+Input* PentaP1Input::SpawnTriaInput(int* indices){
+
+	/*output*/
+	TriaP1Input* outinput=NULL;
+	IssmDouble newvalues[3];
+
+	/*Loop over the new indices*/
+	for(int i=0;i<3;i++){
+
+		/*Check index value*/
+		_assert_(indices[i]>=0 && indices[i]<6);
+
+		/*Assign value to new input*/
+		newvalues[i]=this->values[indices[i]];
+	}
+
+	/*Create new Tria input*/
+	outinput=new TriaP1Input(this->enum_type,&newvalues[0]);
+
+	/*Assign output*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::SpawnResult{{{*/
+ElementResult* PentaP1Input::SpawnResult(int step, IssmDouble time){
+
+	return new PentaP1ElementResult(this->enum_type,this->values,step,time);
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION PentaP1Input::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void PentaP1Input::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){
+
+	/*Call PentaRef function*/
+	PentaRef::GetInputValue(pvalue,&values[0],gauss);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetInputDerivativeValue(IssmDouble* p, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void PentaP1Input::GetInputDerivativeValue(IssmDouble* p, IssmDouble* xyz_list, GaussPenta* gauss){
+
+	/*Call PentaRef function*/
+	PentaRef::GetInputDerivativeValue(p,&values[0],xyz_list,gauss);
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetVxStrainRate3d{{{*/
+void PentaP1Input::GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){
+	int i,j;
+
+	const int numnodes=6;
+	const int DOFVELOCITY=3;
+	IssmDouble B[8][27];
+	IssmDouble B_reduced[6][DOFVELOCITY*numnodes];
+	IssmDouble velocity[numnodes][DOFVELOCITY];
+
+	/*Get B matrix: */
+	GetBStokes(&B[0][0], xyz_list, gauss);
+	/*Create a reduced matrix of B to get rid of pressure */
+	for (i=0;i<6;i++){
+		for (j=0;j<3;j++){
+			B_reduced[i][j]=B[i][j];
+		}
+		for (j=4;j<7;j++){
+			B_reduced[i][j-1]=B[i][j];
+		}
+		for (j=8;j<11;j++){
+			B_reduced[i][j-2]=B[i][j];
+		}
+		for (j=12;j<15;j++){
+			B_reduced[i][j-3]=B[i][j];
+		}
+		for (j=16;j<19;j++){
+			B_reduced[i][j-4]=B[i][j];
+		}
+		for (j=20;j<23;j++){
+			B_reduced[i][j-5]=B[i][j];
+		}
+	}
+
+	/*Here, we are computing the strain rate of (vx,0,0)*/
+	for(i=0;i<numnodes;i++){
+		velocity[i][0]=this->values[i];
+		velocity[i][1]=0.0;
+		velocity[i][2]=0.0;
+	}
+	/*Multiply B by velocity, to get strain rate: */
+	MatrixMultiply(&B_reduced[0][0],6,DOFVELOCITY*numnodes,0,&velocity[0][0],DOFVELOCITY*numnodes,1,0,epsilonvx,0);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetVyStrainRate3d{{{*/
+void PentaP1Input::GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){
+	int i,j;
+
+	const int numnodes=6;
+	const int DOFVELOCITY=3;
+	IssmDouble B[8][27];
+	IssmDouble B_reduced[6][DOFVELOCITY*numnodes];
+	IssmDouble velocity[numnodes][DOFVELOCITY];
+
+	/*Get B matrix: */
+	GetBStokes(&B[0][0], xyz_list, gauss);
+	/*Create a reduced matrix of B to get rid of pressure */
+	for (i=0;i<6;i++){
+		for (j=0;j<3;j++){
+			B_reduced[i][j]=B[i][j];
+		}
+		for (j=4;j<7;j++){
+			B_reduced[i][j-1]=B[i][j];
+		}
+		for (j=8;j<11;j++){
+			B_reduced[i][j-2]=B[i][j];
+		}
+		for (j=12;j<15;j++){
+			B_reduced[i][j-3]=B[i][j];
+		}
+		for (j=16;j<19;j++){
+			B_reduced[i][j-4]=B[i][j];
+		}
+		for (j=20;j<23;j++){
+			B_reduced[i][j-5]=B[i][j];
+		}
+	}
+
+	/*Here, we are computing the strain rate of (0,vy,0)*/
+	for(i=0;i<numnodes;i++){
+		velocity[i][0]=0.0;
+		velocity[i][1]=this->values[i];
+		velocity[i][2]=0.0;
+	}
+	/*Multiply B by velocity, to get strain rate: */
+	MatrixMultiply(&B_reduced[0][0],6,DOFVELOCITY*numnodes,0,&velocity[0][0],DOFVELOCITY*numnodes,1,0,epsilonvy,0);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetVzStrainRate3d{{{*/
+void PentaP1Input::GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){
+	int i,j;
+
+	const int numnodes=6;
+	const int DOFVELOCITY=3;
+	IssmDouble B[8][27];
+	IssmDouble B_reduced[6][DOFVELOCITY*numnodes];
+	IssmDouble velocity[numnodes][DOFVELOCITY];
+
+	/*Get B matrix: */
+	GetBStokes(&B[0][0], xyz_list, gauss);
+	/*Create a reduced matrix of B to get rid of pressure */
+	for (i=0;i<6;i++){
+		for (j=0;j<3;j++){
+			B_reduced[i][j]=B[i][j];
+		}
+		for (j=4;j<7;j++){
+			B_reduced[i][j-1]=B[i][j];
+		}
+		for (j=8;j<11;j++){
+			B_reduced[i][j-2]=B[i][j];
+		}
+		for (j=12;j<15;j++){
+			B_reduced[i][j-3]=B[i][j];
+		}
+		for (j=16;j<19;j++){
+			B_reduced[i][j-4]=B[i][j];
+		}
+		for (j=20;j<23;j++){
+			B_reduced[i][j-5]=B[i][j];
+		}
+	}
+
+	/*Here, we are computing the strain rate of (0,0,vz)*/
+	for(i=0;i<numnodes;i++){
+		velocity[i][0]=0.0;
+		velocity[i][1]=0.0;
+		velocity[i][2]=this->values[i];
+	}
+
+	/*Multiply B by velocity, to get strain rate: */
+	MatrixMultiply(&B_reduced[0][0],6,DOFVELOCITY*numnodes,0,&velocity[0][0],DOFVELOCITY*numnodes,1,0,epsilonvz,0);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetVxStrainRate3dPattyn{{{*/
+void PentaP1Input::GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){
+
+	int i;
+	const int numnodes=6;
+	IssmDouble B[5][NDOF2*numnodes];
+	IssmDouble velocity[numnodes][NDOF2];
+
+	/*Get B matrix: */
+	GetBPattyn(&B[0][0], xyz_list, gauss);
+
+	/*Here, we are computing the strain rate of (vx,0)*/
+	for(i=0;i<numnodes;i++){
+		velocity[i][0]=this->values[i];
+		velocity[i][1]=0.0;
+	}
+
+	/*Multiply B by velocity, to get strain rate: */
+	MatrixMultiply( &B[0][0],5,NDOF2*numnodes,0,
+				&velocity[0][0],NDOF2*numnodes,1,0,
+				epsilonvx,0);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetVyStrainRate3dPattyn{{{*/
+void PentaP1Input::GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){
+
+	int i;
+	const int numnodes=6;
+	IssmDouble B[5][NDOF2*numnodes];
+	IssmDouble velocity[numnodes][NDOF2];
+
+	/*Get B matrix: */
+	GetBPattyn(&B[0][0], xyz_list, gauss);
+
+	/*Here, we are computing the strain rate of (0,vy)*/
+	for(i=0;i<numnodes;i++){
+		velocity[i][0]=0.0;
+		velocity[i][1]=this->values[i];
+	}
+
+	/*Multiply B by velocity, to get strain rate: */
+	MatrixMultiply( &B[0][0],5,NDOF2*numnodes,0,
+				&velocity[0][0],NDOF2*numnodes,1,0,
+				epsilonvy,0);
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::ChangeEnum{{{*/
+void PentaP1Input::ChangeEnum(int newenumtype){
+	this->enum_type=newenumtype;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetInputAverage{{{*/
+void PentaP1Input::GetInputAverage(IssmDouble* pvalue){
+	*pvalue=1./6.*(values[0]+values[1]+values[2]+values[3]+values[4]+values[5]);
+}
+/*}}}*/
+
+/*Intermediary*/
+/*FUNCTION PentaP1Input::SquareMin{{{*/
+void PentaP1Input::SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){
+
+	int i;
+	const int numnodes=6;
+	IssmDouble valuescopy[numnodes];
+	IssmDouble squaremin;
+
+	/*First,  copy values, to process units if requested: */
+	for(i=0;i<numnodes;i++)valuescopy[i]=this->values[i];
+
+	/*Process units if requested: */
+	if(process_units)UnitConversion(&valuescopy[0],numnodes,IuToExtEnum,enum_type);
+
+	/*Now, figure out minimum of valuescopy: */
+	squaremin=pow(valuescopy[0],2);
+	for(i=1;i<numnodes;i++){
+		if(pow(valuescopy[i],2)<squaremin)squaremin=pow(valuescopy[i],2);
+	}
+	/*Assign output pointers:*/
+	*psquaremin=squaremin;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::ConstrainMin{{{*/
+void PentaP1Input::ConstrainMin(IssmDouble minimum){
+
+	int i;
+	const int numnodes=6;
+
+	for(i=0;i<numnodes;i++) if (values[i]<minimum) values[i]=minimum;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::InfinityNorm{{{*/
+IssmDouble PentaP1Input::InfinityNorm(void){
+
+	/*Output*/
+	const int numnodes=6;
+	IssmDouble norm=0;
+
+	for(int i=0;i<numnodes;i++) if(fabs(values[i])>norm) norm=fabs(values[i]);
+	return norm;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Max{{{*/
+IssmDouble PentaP1Input::Max(void){
+
+	const int numnodes=6;
+	IssmDouble    max=values[0];
+
+	for(int i=1;i<numnodes;i++){
+		if(values[i]>max) max=values[i];
+	}
+	return max;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::MaxAbs{{{*/
+IssmDouble PentaP1Input::MaxAbs(void){
+
+	const int numnodes=6;
+	IssmDouble    max=fabs(values[0]);
+
+	for(int i=1;i<numnodes;i++){
+		if(fabs(values[i])>max) max=fabs(values[i]);
+	}
+	return max;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Min{{{*/
+IssmDouble PentaP1Input::Min(void){
+
+	const int numnodes=6;
+	IssmDouble    min=values[0];
+
+	for(int i=1;i<numnodes;i++){
+		if(values[i]<min) min=values[i];
+	}
+	return min;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::MinAbs{{{*/
+IssmDouble PentaP1Input::MinAbs(void){
+
+	const int numnodes=6;
+	IssmDouble    min=fabs(values[0]);
+
+	for(int i=1;i<numnodes;i++){
+		if(fabs(values[i])<min) min=fabs(values[i]);
+	}
+	return min;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Scale{{{*/
+void PentaP1Input::Scale(IssmDouble scale_factor){
+
+	int i;
+	const int numnodes=6;
+
+	for(i=0;i<numnodes;i++)values[i]=values[i]*scale_factor;
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::AXPY{{{*/
+void PentaP1Input::AXPY(Input* xinput,IssmDouble scalar){
+
+	int i;
+	const int numnodes=6;
+
+	/*xinput is of the same type, so cast it: */
+
+	/*Carry out the AXPY operation depending on type:*/
+	switch(xinput->ObjectEnum()){
+
+		case PentaP1InputEnum:{
+			PentaP1Input* cast_input=(PentaP1Input*)xinput;
+			for(i=0;i<numnodes;i++)this->values[i]=this->values[i]+scalar*(cast_input->values[i]);}
+			return;
+		case ControlInputEnum:{
+			ControlInput* cont_input=(ControlInput*)xinput;
+			if(cont_input->values->ObjectEnum()!=PentaP1InputEnum) _error_("not supported yet");
+			PentaP1Input* cast_input=(PentaP1Input*)cont_input->values;
+			for(i=0;i<numnodes;i++)this->values[i]=this->values[i]+scalar*(cast_input->values[i]);}
+			return;
+		default:
+			_error_("not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Constrain{{{*/
+void PentaP1Input::Constrain(IssmDouble cm_min, IssmDouble cm_max){
+
+	int i;
+	const int numnodes=6;
+
+	if(!xIsNan<IssmDouble>(cm_min)) for(i=0;i<numnodes;i++)if (this->values[i]<cm_min)this->values[i]=cm_min;
+	if(!xIsNan<IssmDouble>(cm_max)) for(i=0;i<numnodes;i++)if (this->values[i]>cm_max)this->values[i]=cm_max;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Extrude{{{*/
+void PentaP1Input::Extrude(void){
+
+	int i;
+
+	/*First 3 values copied on 3 last values*/
+	for(i=0;i<3;i++) this->values[3+i]=this->values[i];
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::VerticallyIntegrate{{{*/
+void PentaP1Input::VerticallyIntegrate(Input* thickness_input){
+
+	/*Intermediaries*/
+	int i;
+	const int  numnodes = 6;
+	int        num_thickness_values;
+	IssmDouble    *thickness_values = NULL;
+
+	/*Check that input provided is a thickness*/
+	if (thickness_input->InstanceEnum()!=ThicknessEnum) _error_("Input provided is not a Thickness (enum_type is " << EnumToStringx(thickness_input->InstanceEnum()) << ")");
+
+	/*Get Thickness value pointer*/
+	thickness_input->GetValuesPtr(&thickness_values,&num_thickness_values);
+
+	/*vertically integrate depending on type:*/
+	switch(thickness_input->ObjectEnum()){
+
+		case PentaP1InputEnum:
+			for(i=0;i<3;i++){
+				this->values[i]=0.5*(this->values[i]+this->values[i+3]) * thickness_values[i];
+				this->values[i+3]=this->values[i];
+			}
+			return;
+
+		default:
+			_error_("not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::PointwiseDivide{{{*/
+Input* PentaP1Input::PointwiseDivide(Input* inputB){
+
+	/*Ouput*/
+	PentaP1Input* outinput=NULL;
+
+	/*Intermediaries*/
+	PentaP1Input *xinputB  = NULL;
+	const int     numnodes = 6;
+	IssmDouble    AdotBvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=PentaP1InputEnum) _error_("Operation not permitted because inputB is of type " << EnumToStringx(inputB->ObjectEnum()));
+	xinputB=(PentaP1Input*)inputB;
+
+	/*Create point wise sum*/
+	for(int i=0;i<numnodes;i++){
+		_assert_(xinputB->values[i]!=0);
+		AdotBvalues[i]=this->values[i]/xinputB->values[i];
+	}
+
+	/*Create new Penta vertex input (copy of current input)*/
+	outinput=new PentaP1Input(this->enum_type,&AdotBvalues[0]);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::PointwiseMin{{{*/
+Input* PentaP1Input::PointwiseMin(Input* inputB){
+
+	/*Ouput*/
+	PentaP1Input* outinput=NULL;
+
+	/*Intermediaries*/
+	int               i;
+	PentaP1Input *xinputB     = NULL;
+	const int         numnodes    = 6;
+	IssmDouble            minvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=PentaP1InputEnum) _error_("Operation not permitted because inputB is of type " << EnumToStringx(inputB->ObjectEnum()));
+	xinputB=(PentaP1Input*)inputB;
+
+	/*Create point wise min*/
+	for(i=0;i<numnodes;i++){
+		if(this->values[i] > xinputB->values[i]) minvalues[i]=xinputB->values[i];
+		else minvalues[i]=this->values[i];
+	}
+
+	/*Create new Penta vertex input (copy of current input)*/
+	outinput=new PentaP1Input(this->enum_type,&minvalues[0]);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::PointwiseMax{{{*/
+Input* PentaP1Input::PointwiseMax(Input* inputB){
+
+	/*Ouput*/
+	PentaP1Input* outinput=NULL;
+
+	/*Intermediaries*/
+	int               i;
+	PentaP1Input *xinputB     = NULL;
+	const int         numnodes    = 6;
+	IssmDouble            maxvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=PentaP1InputEnum) _error_("Operation not permitted because inputB is of type " << EnumToStringx(inputB->ObjectEnum()));
+	xinputB=(PentaP1Input*)inputB;
+
+	/*Create point wise max*/
+	for(i=0;i<numnodes;i++){
+		if(this->values[i] < xinputB->values[i]) maxvalues[i]=xinputB->values[i];
+		else maxvalues[i]=this->values[i];
+	}
+
+	/*Create new Penta vertex input (copy of current input)*/
+	outinput=new PentaP1Input(this->enum_type,&maxvalues[0]);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::GetVectorFromInputs{{{*/
+void PentaP1Input::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+
+	const int numvertices=6;
+	vector->SetValues(numvertices,doflist,this->values,INS_VAL);
+
+} /*}}}*/
+/*FUNCTION PentaP1Input::GetValuesPtr{{{*/
+void PentaP1Input::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	*pvalues=this->values;
+	*pnum_values=6;
+
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::Configure{{{*/
+void PentaP1Input::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/PentaP1Input.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/PentaP1Input.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/PentaP1Input.h	(revision 15012)
@@ -0,0 +1,88 @@
+/*! \file PentaP1Input.h 
+ *  \brief: header file for PentaP1Input object
+ */
+
+#ifndef _PENTAP1INPUT_H_
+#define _PENTAP1INPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../Elements/PentaRef.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class PentaP1Input: public Input, public PentaRef{
+
+	public:
+		/*just hold 6 values for 6 vertices: */
+		int        enum_type;
+		IssmDouble values[6];
+
+		/*PentaP1Input constructors, destructors: {{{*/
+		PentaP1Input();
+		PentaP1Input(int enum_type,IssmDouble* values);
+		~PentaP1Input();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy();
+		/*}}}*/
+		/*PentaP1Input management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB);
+		Input* PointwiseMin(Input* inputB);
+		Input* PointwiseMax(Input* inputB);
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error_("not implemented yet");};
+		void GetInputValue(int* pvalue){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){_error_("not implemented yet");};
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){_error_("not implemented yet");};
+
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss);
+		void ChangeEnum(int newenumtype);
+
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum);
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max);
+		IssmDouble InfinityNorm(void);
+		IssmDouble Max(void);
+		IssmDouble MaxAbs(void);
+		IssmDouble Min(void);
+		IssmDouble MinAbs(void);
+		void Extrude(void);
+		void VerticallyIntegrate(Input* thickness_input);
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _PENTAP1INPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/TransientInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/TransientInput.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/TransientInput.cpp	(revision 15012)
@@ -0,0 +1,536 @@
+/*!\file TransientInput.c
+ * \brief: implementation of the TransientInput object
+ */
+/*Headers{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*TransientInput constructors and destructor*/
+/*FUNCTION TransientInput::TransientInput(){{{*/
+TransientInput::TransientInput(){
+
+	enum_type=UNDEF;
+	inputs=NULL;
+	this->numtimesteps=0;
+	this->parameters=NULL;
+	this->timesteps=NULL;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::TransientInput(int in_enum_type){{{*/
+TransientInput::TransientInput(int in_enum_type)
+{
+	/*Set Enum*/
+	enum_type=in_enum_type;
+
+	/*Allocate values and timesteps, and copy: */
+	this->numtimesteps=0;
+	this->timesteps=NULL;
+	inputs = new Inputs();
+	this->parameters=NULL;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::~TransientInput{{{*/
+TransientInput::~TransientInput(){
+	xDelete(this->timesteps);
+	this->timesteps=NULL;
+	this->numtimesteps=0;
+	parameters=NULL;
+	delete this->inputs;
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION TransientInput::Echo {{{*/
+void TransientInput::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION TransientInput::DeepEcho{{{*/
+void TransientInput::DeepEcho(void){
+
+	int i;
+
+	_printLine_("TransientInput:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   numtimesteps: " << this->numtimesteps);
+	_printLine_("---inputs: "); 
+	for(i=0;i<this->numtimesteps;i++){
+		_printLine_("   time: " << this->timesteps[i] << "  ");
+		((Input*)this->inputs->GetObjectByOffset(i))->Echo();
+	}
+}
+/*}}}*/
+/*FUNCTION TransientInput::Id{{{*/
+int    TransientInput::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION TransientInput::ObjectEnum{{{*/
+int TransientInput::ObjectEnum(void){
+
+	return TransientInputEnum;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::copy{{{*/
+Object* TransientInput::copy() {
+
+	TransientInput* output=NULL;
+
+	output = new TransientInput();
+	output->enum_type=this->enum_type;
+	output->numtimesteps=this->numtimesteps;
+	output->timesteps=xNew<IssmDouble>(this->numtimesteps);
+        xMemCpy(output->timesteps,this->timesteps,this->numtimesteps);
+	output->inputs=(Inputs*)this->inputs->Copy();
+	output->parameters=this->parameters;
+
+	return output;
+
+}
+/*}}}*/
+
+/*TransientInput management*/
+/*FUNCTION TransientInput::InstanceEnum{{{*/
+int TransientInput::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::SpawnTriaInput{{{*/
+Input* TransientInput::SpawnTriaInput(int* indices){
+
+	/*output*/
+	TransientInput* outinput=NULL;
+
+	/*Create new Transientinput (copy of current input)*/
+	outinput=new TransientInput();
+	outinput->enum_type=this->enum_type;
+	outinput->numtimesteps=this->numtimesteps;
+	outinput->timesteps=xNew<IssmDouble>(this->numtimesteps);
+	xMemCpy(outinput->timesteps,this->timesteps,this->numtimesteps);
+	outinput->inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
+	outinput->parameters=this->parameters;
+
+	/*Assign output*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::SpawnResult{{{*/
+ElementResult* TransientInput::SpawnResult(int step, IssmDouble time){
+
+	ElementResult* elementresult=NULL;
+
+	/*Ok, we want to spawn an ElementResult. We have the time, just get 
+	 *the correct values: */
+	Input* input=GetTimeInput(time);
+
+	elementresult=input->SpawnResult(step,time);
+
+   delete input;
+
+	return elementresult;
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION TransientInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void TransientInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){
+	IssmDouble time;
+
+	/*First, recover current time from parameters: */
+	this->parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetInputValue(pvalue,gauss);
+
+	delete input;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void TransientInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){
+	IssmDouble time;
+
+	/*First, recover current time from parameters: */
+	this->parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetInputValue(pvalue,gauss);
+
+	delete input;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){{{*/
+void TransientInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetInputValue(pvalue,gauss);
+
+	delete input;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){{{*/
+void TransientInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetInputValue(pvalue,gauss);
+
+	delete input;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputDerivativeValue(IssmDouble* p, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void TransientInput::GetInputDerivativeValue(IssmDouble* p, IssmDouble* xyz_list, GaussTria* gauss){
+
+	IssmDouble time;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetInputDerivativeValue(p,xyz_list,gauss);
+
+	delete input;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::ChangeEnum{{{*/
+void TransientInput::ChangeEnum(int newenumtype){
+	this->enum_type=newenumtype;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputAverage{{{*/
+void TransientInput::GetInputAverage(IssmDouble* pvalue){
+
+	IssmDouble time;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetInputAverage(pvalue);
+
+	delete input;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputAllTimeAverages{{{*/
+void TransientInput::GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){
+
+	int i;
+	IssmDouble* times=NULL;
+	IssmDouble* values=NULL;
+
+	/*allocate: */
+	times=xNew<IssmDouble>(this->numtimesteps);
+	values=xNew<IssmDouble>(this->numtimesteps);
+
+	for(i=0;i<numtimesteps;i++){
+		Input* input=(Input*)this->inputs->GetObjectByOffset(i);
+		input->GetInputAverage(values+i);
+		times[i]=this->timesteps[i];
+	}
+
+	*pvalues=values;
+	*ptimes=times;
+	*pnumtimes=numtimesteps;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetInputUpToCurrentTimeAverages{{{*/
+void TransientInput::GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){
+
+	int i;
+	IssmDouble* times=NULL;
+	IssmDouble* values=NULL;
+	int numsteps;
+	int count;
+	bool iscurrenttime_included=false;
+
+	/*Figure out how many time steps we are going to return: */
+	numsteps=0;
+	for(i=0;i<numtimesteps;i++){
+		if(this->timesteps[i]==currenttime)iscurrenttime_included=true;
+		if (this->timesteps[i]>currenttime)break;
+		else numsteps++;
+	}
+	if(iscurrenttime_included==false)numsteps++;
+
+	/*allocate: */
+	times=xNew<IssmDouble>(numsteps);
+	values=xNew<IssmDouble>(numsteps);
+
+	for(i=0;i<numsteps;i++){
+
+		if((iscurrenttime_included==false) && (i==(numsteps-1))){
+
+			/*Retrieve interpolated values for current time step: */
+			Input* input=GetTimeInput(currenttime);
+			input->GetInputAverage(values+i);
+			times[i]=currenttime;
+		}
+		else{
+			Input* input=(Input*)this->inputs->GetObjectByOffset(i);
+			input->GetInputAverage(values+i);
+			times[i]=this->timesteps[i];
+		}
+	}
+
+	*pvalues=values;
+	*ptimes=times;
+	*pnumtimes=numtimesteps;
+}
+/*}}}*/
+
+/*Intermediary*/
+/*FUNCTION TransientInput::AddTimeInput{{{*/
+void TransientInput::AddTimeInput(Input* input,IssmDouble time){
+
+	/*insert values at time step: */
+	if (this->numtimesteps>0 && time<=this->timesteps[this->numtimesteps-1]) _assert_("timestep values must increase sequentially");
+
+	//copy timesteps, add the new time, delete previous timesteps, and add the new input: inputs->AddObject(input);
+	IssmDouble* old_timesteps=NULL;
+
+	if (this->numtimesteps > 0){
+		old_timesteps=xNew<IssmDouble>(this->numtimesteps);
+		xMemCpy(old_timesteps,this->timesteps,this->numtimesteps);
+		xDelete(this->timesteps);
+	}
+
+	this->numtimesteps=this->numtimesteps+1;
+	this->timesteps=xNew<IssmDouble>(this->numtimesteps);
+
+	if (this->numtimesteps > 1){
+		xMemCpy(this->timesteps,old_timesteps,this->numtimesteps-1);
+		xDelete(old_timesteps);
+	}
+
+	/*go ahead and plug: */
+	this->timesteps[this->numtimesteps-1]=time;
+	inputs->AddObject(input);
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::Extrude{{{*/
+void TransientInput::Extrude(void){
+
+	for(int i=0;i<this->numtimesteps;i++){
+		((Input*)this->inputs->GetObjectByOffset(i))->Extrude();
+	}
+}
+/*}}}*/
+/*FUNCTION TransientInput::SquareMin{{{*/
+void TransientInput::SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){
+
+	IssmDouble time;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+   /*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->SquareMin(psquaremin,process_units,parameters);
+
+	delete input;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::InfinityNorm{{{*/
+IssmDouble TransientInput::InfinityNorm(void){
+
+	IssmDouble time;
+	IssmDouble infnorm;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+   /*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	infnorm=input->InfinityNorm();
+
+	/*Clean-up and return*/
+	delete input;
+	return infnorm;
+}
+/*}}}*/
+/*FUNCTION TransientInput::Max{{{*/
+IssmDouble TransientInput::Max(void){
+
+	IssmDouble time;
+	IssmDouble max;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+   /*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	max=input->Max();
+
+	delete input;
+
+	return max;
+}
+/*}}}*/
+/*FUNCTION TransientInput::MaxAbs{{{*/
+IssmDouble TransientInput::MaxAbs(void){
+
+	IssmDouble time;
+	IssmDouble maxabs;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	maxabs=input->MaxAbs();
+
+	/*Clean-up and return*/
+	delete input;
+	return maxabs;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::Min{{{*/
+IssmDouble TransientInput::Min(void){
+
+	IssmDouble time;
+	IssmDouble min;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+   /*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	min=input->Min();
+
+	/*Clean-up and return*/
+	delete input;
+	return min;
+
+}
+/*}}}*/
+/*FUNCTION TransientInput::MinAbs{{{*/
+IssmDouble TransientInput::MinAbs(void){
+
+	IssmDouble time;
+	IssmDouble minabs;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	minabs=input->MinAbs();
+
+	/*Clean-up and return*/
+	delete input;
+	return minabs;
+}
+/*}}}*/
+/*FUNCTION TransientInput::GetVectorFromInputs{{{*/
+void TransientInput::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+
+	IssmDouble time;
+
+	/*First, recover current time from parameters: */
+	parameters->FindParam(&time,TimeEnum);
+
+	/*Retrieve interpolated values for this time step: */
+	Input* input=GetTimeInput(time);
+
+	/*Call input function*/
+	input->GetVectorFromInputs(vector,doflist);
+
+	delete input;
+
+} /*}}}*/
+/*FUNCTION TransientInput::GetTimeInput{{{*/
+Input* TransientInput::GetTimeInput(IssmDouble intime){
+
+	IssmDouble deltat;
+	IssmDouble alpha1,alpha2;
+	int        found;
+	int        offset;
+
+	Input *input  = NULL;
+	Input *input1 = NULL;
+	Input *input2 = NULL;
+
+	/*go through the timesteps, and figure out which interval we 
+	 *fall within. Then interpolate the values on this interval: */
+	found=binary_search(&offset,intime,this->timesteps,this->numtimesteps);
+	if(!found) _error_("Input not found (is TransientInput sorted ?)");
+
+	if (offset==-1){
+		/*get values for the first time: */
+		_assert_(intime<this->timesteps[0]);
+		input=(Input*)((Input*)this->inputs->GetObjectByOffset(0))->copy();
+	}
+	else if(offset==(this->numtimesteps-1)){
+		/*get values for the last time: */
+		_assert_(intime>=this->timesteps[offset]);
+		input=(Input*)((Input*)this->inputs->GetObjectByOffset(offset))->copy();
+	}
+	else{
+		/*get values between two times [offset:offset+1[, Interpolate linearly*/
+		_assert_(intime>=this->timesteps[offset] && intime<this->timesteps[offset+1]);
+		deltat=this->timesteps[offset+1]-this->timesteps[offset];
+		alpha2=(intime-this->timesteps[offset])/deltat;
+		alpha1=(1.0-alpha2);
+
+		input1=(Input*)this->inputs->GetObjectByOffset(offset); 
+		input2=(Input*)this->inputs->GetObjectByOffset(offset+1);
+
+		input=(Input*)input1->copy();
+		input->Scale(alpha1);
+		input->AXPY(input2,alpha2);
+	}
+
+	/*Assign output pointer*/
+	return input;
+}
+/*}}}*/
+/*FUNCTION TransientInput::Configure{{{*/
+void TransientInput::Configure(Parameters* parameters){
+	this->parameters=parameters;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/TransientInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/TransientInput.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/TransientInput.h	(revision 15012)
@@ -0,0 +1,91 @@
+/*! \file TransientInput.h 
+ *  \brief: header file for transientinput object
+ */
+
+#ifndef _TRANSIENTINPUT_H_
+#define _TRANSIENTINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class Parameters;
+class GaussPenta;
+/*}}}*/
+
+class TransientInput: public Input{
+
+	public:
+		int         enum_type;
+		int         numtimesteps;
+		Inputs     *inputs;
+		IssmDouble *timesteps;
+		Parameters *parameters;     //to find current time.
+
+		/*TransientInput constructors, destructors: {{{*/
+		TransientInput();
+		TransientInput(int enum_type);
+		~TransientInput();
+		void AddTimeInput(Input* input,IssmDouble time);
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		int   Id();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*TransientInput management: {{{*/
+		int    InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* forcingB){_error_("not implemented yet");};
+		Input* PointwiseMin(Input* forcingB){_error_("not implemented yet");};
+		Input* PointwiseMax(Input* forcingB){_error_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error_("not implemented yet");};
+		void GetInputValue(int* pvalue){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes);
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime);
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum){_error_("not implemented yet");};
+		void Scale(IssmDouble scale_factor){_error_("not implemented yet");};
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error_("not implemented yet");};
+		void AXPY(Input* xforcing,IssmDouble scalar){_error_("not implemented yet");};
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max){_error_("not implemented yet");};
+		IssmDouble InfinityNorm(void);
+		IssmDouble Max(void);
+		IssmDouble MaxAbs(void);
+		IssmDouble Min(void);
+		IssmDouble MinAbs(void);
+		void Extrude(void);
+		void VerticallyIntegrate(Input* thickness_forcing){_error_("not supported yet");};
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values){_error_("not supported yet");};
+		void GetTimeValues(IssmDouble* values,IssmDouble time){_error_("not implemented yet");};
+		Input* GetTimeInput(IssmDouble time);
+		/*}}}*/
+
+};
+#endif  /* _TRANSIENTINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/Inputs/TriaP1Input.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/TriaP1Input.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/TriaP1Input.cpp	(revision 15012)
@@ -0,0 +1,449 @@
+/*!\file TriaP1Input.c
+ * \brief: implementation of the TriaP1Input object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*TriaP1Input constructors and destructor*/
+/*FUNCTION TriaP1Input::TriaP1Input(){{{*/
+TriaP1Input::TriaP1Input(){
+	return;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::TriaP1Input(int in_enum_type,IssmDouble* values){{{*/
+TriaP1Input::TriaP1Input(int in_enum_type,IssmDouble* in_values)
+	:TriaRef(1)
+{
+
+	/*Set TriaRef*/
+	this->SetElementType(P1Enum,0);
+	this->element_type=P1Enum;
+
+	/*Set Enum*/
+	enum_type=in_enum_type;
+
+	/*Set values*/
+	values[0]=in_values[0];
+	values[1]=in_values[1];
+	values[2]=in_values[2];
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::~TriaP1Input(){{{*/
+TriaP1Input::~TriaP1Input(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION TriaP1Input::Echo {{{*/
+void TriaP1Input::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::DeepEcho{{{*/
+void TriaP1Input::DeepEcho(void){
+
+	_printLine_("TriaP1Input:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   values: [" << this->values[0] << " " << this->values[1] << " " << this->values[2] << "]");
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::Id{{{*/
+int    TriaP1Input::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION TriaP1Input::ObjectEnum{{{*/
+int TriaP1Input::ObjectEnum(void){
+
+	return TriaP1InputEnum;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::copy{{{*/
+Object* TriaP1Input::copy() {
+
+	return new TriaP1Input(this->enum_type,this->values);
+
+}
+/*}}}*/
+
+/*TriaP1Input management*/
+/*FUNCTION TriaP1Input::InstanceEnum{{{*/
+int TriaP1Input::InstanceEnum(void){
+
+	return this->enum_type;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::SpawnTriaInput{{{*/
+Input* TriaP1Input::SpawnTriaInput(int* indices){
+
+	/*output*/
+	TriaP1Input* outinput=NULL;
+
+	/*Create new Tria input (copy of current input)*/
+	outinput=new TriaP1Input(this->enum_type,&this->values[0]);
+
+	/*Assign output*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::SpawnResult{{{*/
+ElementResult* TriaP1Input::SpawnResult(int step, IssmDouble time){
+
+	return new TriaP1ElementResult(this->enum_type,this->values,step,time);
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION TriaP1Input::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void TriaP1Input::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){
+
+	/*Call TriaRef function*/
+	TriaRef::GetInputValue(pvalue,&values[0],gauss);
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetInputDerivativeValue(IssmDouble* p, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void TriaP1Input::GetInputDerivativeValue(IssmDouble* p, IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*Call TriaRef function*/
+	TriaRef::GetInputDerivativeValue(p,&values[0],xyz_list,gauss);
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetVxStrainRate2d{{{*/
+void TriaP1Input::GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*Intermediary*/
+	int       i;
+	const int numnodes=3;
+	IssmDouble B[3][NDOF2*numnodes];
+	IssmDouble velocity[3][NDOF2];
+
+	/*Get B matrix: */
+	GetBMacAyeal(&B[0][0], xyz_list, gauss);
+
+	/*Here, we are computing the strain rate of (vx,0)*/
+	for(i=0;i<3;i++){
+		velocity[i][0]=this->values[i];
+		velocity[i][1]=0.0;
+	}
+	/*Get epsilon(vx) = B*velocity*/
+	MatrixMultiply( &B[0][0],3,NDOF2*numnodes,0,
+				&velocity[0][0],NDOF2*numnodes,1,0,
+				epsilonvx,0);
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetVyStrainRate2d{{{*/
+void TriaP1Input::GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){
+
+	/*Intermediary*/
+	int       i;
+	const int numnodes=3;
+	IssmDouble B[3][NDOF2*numnodes];
+	IssmDouble velocity[3][NDOF2];
+
+	/*Get B matrix: */
+	GetBMacAyeal(&B[0][0], xyz_list, gauss);
+
+	/*Here, we are computing the strain rate of (0,vy)*/
+	for(i=0;i<3;i++){
+		velocity[i][0]=0.0;
+		velocity[i][1]=this->values[i];
+	}
+	/*Get epsilon(vy) = B*velocity*/
+	MatrixMultiply( &B[0][0],3,NDOF2*numnodes,0,
+				&velocity[0][0],NDOF2*numnodes,1,0,
+				epsilonvy,0);
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::ChangeEnum{{{*/
+void TriaP1Input::ChangeEnum(int newenumtype){
+	this->enum_type=newenumtype;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetInputAverage{{{*/
+void TriaP1Input::GetInputAverage(IssmDouble* pvalue){
+	*pvalue=1./3.*(values[0]+values[1]+values[2]);
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetInputAllTimeAverages{{{*/
+void TriaP1Input::GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes){
+
+	IssmDouble* outvalues=NULL;
+	IssmDouble* times=NULL;
+	int         numtimes;
+
+	/*this is not a transient forcing, so we only have 1 value, steady state: */
+	numtimes=1;
+	outvalues=xNew<IssmDouble>(1);
+	times=xNew<IssmDouble>(1);
+
+	outvalues[0]=1./3.*(values[0]+values[1]+values[2]);
+	times[0]=0; /*we don't have a time*/
+
+	*pvalues=outvalues;
+	*ptimes=times;
+	*pnumtimes=numtimes;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetInputUpToCurrentTimeAverages{{{*/
+void TriaP1Input::GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime){
+
+	IssmDouble* outvalues=NULL;
+	IssmDouble* times=NULL;
+	int         numtimes;
+
+	/*this is not a transient forcing, so we only have 1 value, steady state: */
+	numtimes=1;
+	outvalues=xNew<IssmDouble>(1);
+	times=xNew<IssmDouble>(1);
+
+	outvalues[0]=1./3.*(values[0]+values[1]+values[2]);
+	times[0]=currenttime; /*we don't have a time*/
+
+	*pvalues=outvalues;
+	*ptimes=times;
+	*pnumtimes=numtimes;
+}
+/*}}}*/
+
+/*Intermediary*/
+/*FUNCTION TriaP1Input::SquareMin{{{*/
+void TriaP1Input::SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){
+
+	int i;
+	const int numnodes=3;
+	IssmDouble valuescopy[numnodes];
+	IssmDouble squaremin;
+
+	/*First,  copy values, to process units if requested: */
+	for(i=0;i<numnodes;i++)valuescopy[i]=this->values[i];
+
+	/*Process units if requested: */
+	if(process_units)UnitConversion(&valuescopy[0],numnodes,IuToExtEnum,enum_type);
+
+	/*Now, figure out minimum of valuescopy: */
+	squaremin=pow(valuescopy[0],2);
+	for(i=1;i<numnodes;i++){
+		if(pow(valuescopy[i],2)<squaremin)squaremin=pow(valuescopy[i],2);
+	}
+	/*Assign output pointers:*/
+	*psquaremin=squaremin;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::ContrainMin{{{*/
+void TriaP1Input::ConstrainMin(IssmDouble minimum){
+
+	int i;
+	const int numnodes=3;
+
+	for(i=0;i<numnodes;i++) if (values[i]<minimum) values[i]=minimum;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::InfinityNorm{{{*/
+IssmDouble TriaP1Input::InfinityNorm(void){
+
+	/*Output*/
+	IssmDouble norm=0;
+	const int numnodes=3;
+
+	for(int i=0;i<numnodes;i++) if(fabs(values[i])>norm) norm=fabs(values[i]);
+	return norm;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::Max{{{*/
+IssmDouble TriaP1Input::Max(void){
+
+	const int numnodes=3;
+	IssmDouble    max=values[0];
+
+	for(int i=1;i<numnodes;i++){
+		if(values[i]>max) max=values[i];
+	}
+	return max;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::MaxAbs{{{*/
+IssmDouble TriaP1Input::MaxAbs(void){
+
+	const int numnodes=3;
+	IssmDouble    max=fabs(values[0]);
+
+	for(int i=1;i<numnodes;i++){
+		if(fabs(values[i])>max) max=fabs(values[i]);
+	}
+	return max;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::Min{{{*/
+IssmDouble TriaP1Input::Min(void){
+
+	const int numnodes=3;
+	IssmDouble    min=values[0];
+
+	for(int i=1;i<numnodes;i++){
+		if(values[i]<min) min=values[i];
+	}
+	return min;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::MinAbs{{{*/
+IssmDouble TriaP1Input::MinAbs(void){
+
+	const int numnodes=3;
+	IssmDouble    min=fabs(values[0]);
+
+	for(int i=1;i<numnodes;i++){
+		if(fabs(values[i])<min) min=fabs(values[i]);
+	}
+	return min;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::Scale{{{*/
+void TriaP1Input::Scale(IssmDouble scale_factor){
+
+	int i;
+	const int numnodes=3;
+
+	for(i=0;i<numnodes;i++)values[i]=values[i]*scale_factor;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::ArtificialNoise{{{*/
+void TriaP1Input::ArtificialNoise(IssmDouble min,IssmDouble max){
+
+	int i;
+	const int numnodes=3;
+	IssmDouble noise;
+
+	/*Compute random number between bounds:
+	 * rand() outputs an integer in [0 RAND_MAX]
+	 * (IssmDouble)rand()/RAND_MAX is in [0 1]
+	 */
+	 noise=min+(max-min)*(IssmDouble)rand()/RAND_MAX;
+
+	for(i=0;i<numnodes;i++)values[i]=values[i]+noise;
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::AXPY{{{*/
+void TriaP1Input::AXPY(Input* xinput,IssmDouble scalar){
+
+	int i;
+	const int numnodes=3;
+	TriaP1Input*  xtriavertexinput=NULL;
+
+	/*xinput is of the same type, so cast it: */
+	xtriavertexinput=(TriaP1Input*)xinput;
+
+	/*Carry out the AXPY operation depending on type:*/
+	switch(xinput->ObjectEnum()){
+
+		case TriaP1InputEnum :
+			for(i=0;i<numnodes;i++)this->values[i]=this->values[i]+scalar*xtriavertexinput->values[i];
+			return;
+
+		default :
+			_error_("not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::Constrain{{{*/
+void TriaP1Input::Constrain(IssmDouble cm_min, IssmDouble cm_max){
+
+	int i;
+	const int numnodes=3;
+
+	if(!xIsNan<IssmDouble>(cm_min)) for(i=0;i<numnodes;i++)if (this->values[i]<cm_min)this->values[i]=cm_min;
+	if(!xIsNan<IssmDouble>(cm_max)) for(i=0;i<numnodes;i++)if (this->values[i]>cm_max)this->values[i]=cm_max;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::GetVectorFromInputs{{{*/
+void TriaP1Input::GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist){
+
+	const int numvertices=3;
+	vector->SetValues(numvertices,doflist,this->values,INS_VAL);
+
+} /*}}}*/
+/*FUNCTION TriaP1Input::GetValuesPtr{{{*/
+void TriaP1Input::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	*pvalues=this->values;
+	if(pnum_values)*pnum_values=3;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::PointwiseMin{{{*/
+Input* TriaP1Input::PointwiseMin(Input* inputB){
+
+	/*Ouput*/
+	TriaP1Input* outinput=NULL;
+
+	/*Intermediaries*/
+	int          i;
+	TriaP1Input *xinputB  = NULL;
+	const int    numnodes = 3;
+	IssmDouble   minvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=TriaP1InputEnum) _error_("Operation not permitted because inputB is of type " << EnumToStringx(inputB->ObjectEnum()));
+	xinputB=(TriaP1Input*)inputB;
+
+	/*Create point wise min*/
+	for(i=0;i<numnodes;i++){
+		if(this->values[i] > xinputB->values[i]) minvalues[i]=xinputB->values[i];
+		else minvalues[i]=this->values[i];
+	}
+
+	/*Create new Tria vertex input (copy of current input)*/
+	outinput=new TriaP1Input(this->enum_type,&minvalues[0]);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::PointwiseMax{{{*/
+Input* TriaP1Input::PointwiseMax(Input* inputB){
+
+	/*Ouput*/
+	TriaP1Input* outinput=NULL;
+
+	/*Intermediaries*/
+	int               i;
+	TriaP1Input *xinputB     = NULL;
+	const int         numnodes    = 3;
+	IssmDouble            maxvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=TriaP1InputEnum) _error_("Operation not permitted because inputB is of type " << EnumToStringx(inputB->ObjectEnum()));
+	xinputB=(TriaP1Input*)inputB;
+
+	/*Create point wise max*/
+	for(i=0;i<numnodes;i++){
+		if(this->values[i] < xinputB->values[i]) maxvalues[i]=xinputB->values[i];
+		else maxvalues[i]=this->values[i];
+	}
+
+	/*Create new Tria vertex input (copy of current input)*/
+	outinput=new TriaP1Input(this->enum_type,&maxvalues[0]);
+
+	/*Return output pointer*/
+	return outinput;
+
+}
+/*}}}*/
+/*FUNCTION TriaP1Input::Configure{{{*/
+void TriaP1Input::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Inputs/TriaP1Input.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Inputs/TriaP1Input.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Inputs/TriaP1Input.h	(revision 15012)
@@ -0,0 +1,87 @@
+/*! \file TriaP1Input.h 
+ *  \brief: header file for TriaP1Input object
+ */
+
+#ifndef _TRIAP1INPUT_H_
+#define _TRIAP1INPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../Elements/TriaRef.h"
+class GaussTria;
+class GaussPenta;
+/*}}}*/
+
+class TriaP1Input: public Input,public TriaRef{
+
+	public:
+		/*just hold 3 values for 3 vertices: */
+		int        enum_type;
+		IssmDouble values[3];
+
+		/*TriaP1Input constructors, destructors: {{{*/
+		TriaP1Input();
+		TriaP1Input(int enum_type,IssmDouble* values);
+		~TriaP1Input();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy();
+		/*}}}*/
+		/*TriaP1Input management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB);
+		Input* PointwiseMax(Input* inputB);
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error_("not implemented yet");}
+		void GetInputValue(int* pvalue){_error_("not implemented yet");}
+		void GetInputValue(IssmDouble* pvalue){_error_("not implemented yet");}
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,int index){_error_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetInputAllTimeAverages(IssmDouble** pvalues,IssmDouble** ptimes, int* pnumtimes);
+		void GetInputUpToCurrentTimeAverages(IssmDouble** pvalues, IssmDouble** ptimes, int* pnumtimes, IssmDouble currenttime);
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss);
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss);
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum);
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max);
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max);
+		IssmDouble InfinityNorm(void);
+		IssmDouble Max(void);
+		IssmDouble MaxAbs(void);
+		IssmDouble Min(void);
+		IssmDouble MinAbs(void);
+		void Extrude(void){_error_("not supported yet");};
+		void VerticallyIntegrate(Input* thickness_input){_error_("not supported yet");};
+		void GetVectorFromInputs(Vector<IssmDouble>* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _TRIAP1INPUT_H */
Index: /issm/trunk-jpl/src/c/classes/KML/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,34 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/KML)
+# }}}
+# KML_SOURCES {{{
+set(KML_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Attribute.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_ColorStyle.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Comment.cpp
+                $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Container.cpp
+                 $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Document.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Feature.cpp
+                     $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_File.cpp
+                   $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Folder.cpp
+                 $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Geometry.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_GroundOverlay.cpp
+                     $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Icon.cpp
+                $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_LatLonBox.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_LinearRing.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_LineString.cpp
+                $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_LineStyle.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_MultiGeometry.cpp
+                   $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Object.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Overlay.cpp
+                $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Placemark.cpp
+                    $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Point.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Polygon.cpp
+                $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_PolyStyle.cpp
+                    $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Style.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_StyleSelector.cpp
+                 $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_SubStyle.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/KML/KML_Unknown.cpp
+             $ENV{ISSM_DIR}/src/c/classes/objects/KML/KMLFileReadUtils.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/KML/KMLFileReadUtils.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KMLFileReadUtils.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KMLFileReadUtils.cpp	(revision 15012)
@@ -0,0 +1,719 @@
+/*!\file KMLFileUtils.cpp
+ * \brief: utilities for kml file reading.
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*FUNCTION  KMLFileToken(FILE* fid,int* pncom=NULL,char*** ppcom=NULL) {{{*/
+char* KMLFileToken(FILE* fid,
+				   int* pncom=NULL,char*** ppcom=NULL){
+
+/*  get the next token (tag or field) in the file  */
+
+	bool    inew=1,itag=0,ifield=0;
+	int     c;
+	int     ibuf=0,buflen=1024,bufblk=1024;
+	char    *buffer=NULL,*bufferc=NULL,**pcom2=NULL;
+
+	buffer=xNew<char>(buflen);
+	buffer[0]='\0';
+
+/*  read kml file character-by-character  */
+
+//  note that fgets includes newline
+//	fgets(buffer,buflen,fid);
+
+	while ((c=getc(fid)) != EOF) {
+		/*  ignore leading blanks  */
+		if (inew && isspace(c))
+			continue;
+
+		/*  distinguish between tag or field  */
+		if (!itag && !ifield) {
+
+			/*  distinguish between tag or comment  */
+			if (c == '<') {
+				ungetc(c,fid);
+				if (!(bufferc=KMLFileTokenComment(fid))) {
+					c=getc(fid);
+					itag=1;
+				}
+				else {
+					if (pncom && ppcom) {
+						(*pncom)++;
+						pcom2=xNew<char*>(*pncom);
+						memcpy(pcom2,*ppcom,(*pncom-1)*sizeof(char*));
+						xDelete<char*>(*ppcom);
+						*ppcom=pcom2;
+						pcom2=NULL;
+//						*ppcom=(char **) xrealloc(*ppcom,*pncom*sizeof(char*));
+						(*ppcom)[*pncom-1]=bufferc;
+					}
+					else
+						xDelete<char>(bufferc);
+					inew=1;
+					continue;
+				}
+			}
+			else
+				ifield=1;
+			inew=0;
+			KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
+							   c,
+							   bufblk);
+		}
+
+		/*  accumulate tag, not including newlines  */
+		else if (itag) {
+			if (c != '\n') {
+				inew=0;
+				KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
+								   c,
+								   bufblk);
+				if (c == '>')
+					break;
+			}
+			else
+				inew=1;
+		}
+
+		/*  accumulate field, including newlines  */
+		else if (ifield) {
+			/*  distinguish between another tag or comment  */
+			if (c == '<') {
+				ungetc(c,fid);
+				if (!(bufferc=KMLFileTokenComment(fid)))
+					break;
+				else
+					if (pncom && ppcom) {
+						(*pncom)++;
+						pcom2=xNew<char*>(*pncom);
+						memcpy(pcom2,*ppcom,(*pncom-1)*sizeof(char*));
+						xDelete<char*>(*ppcom);
+						*ppcom=pcom2;
+						pcom2=NULL;
+//						*ppcom=(char **) xrealloc(*ppcom,*pncom*sizeof(char*));
+						(*ppcom)[*pncom-1]=bufferc;
+					}
+					else
+						xDelete<char>(bufferc);
+			}
+			else {
+				inew=0;
+				KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
+								   c,
+								   bufblk);
+				if (c == '\n')
+					inew=1;
+			}
+		}
+
+	}
+
+/*  remove trailing blanks or newline  */
+
+	while (ibuf > 0)
+		if (isspace(buffer[ibuf-1]))
+			ibuf--;
+		else {
+			buffer[ibuf]='\0';
+			break;
+		}
+
+//	if      (itag)
+//		_pprintLine_("tag buffer (length=" << ibuf << "):");
+//	else if (ifield)
+//		_pprintLine_("field buffer (length=" << ibuf << "):");
+//	_pprintLine_(buffer);
+
+	if (!ibuf)
+		xDelete<char>(buffer);
+
+	return(buffer);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenComment(FILE* fid) {{{*/
+char* KMLFileTokenComment(FILE* fid){
+
+/*  check for comment in the file and read it  */
+
+	bool    inew=1;
+	int     i;
+	int     c;
+	int     ibuf=0,buflen=1024,bufblk=1024;
+	char*   buffer=NULL;
+
+	buffer=xNew<char>(buflen);
+	buffer[0]='\0';
+
+/*  read kml file character-by-character  */
+
+	while ((c=getc(fid)) != EOF) {
+		/*  ignore leading blanks  */
+		if (inew && isspace(c))
+			continue;
+
+		inew=0;
+		KMLFileTokenBuffer(&buffer,&ibuf,&buflen,
+						   c,
+						   bufblk);
+
+		/*  check for comment  */
+		if (ibuf <= 4) {
+			if ((ibuf == 1 && buffer[0] != '<') ||
+				(ibuf == 2 && buffer[1] != '!') ||
+				(ibuf == 3 && buffer[2] != '-') ||
+				(ibuf == 4 && buffer[3] != '-')) {
+				for (i=ibuf-1; i>=0; i--)
+					ungetc(buffer[i],fid);
+				xDelete<char>(buffer);
+				return(buffer);
+			}
+		}
+
+		/*  accumulate comment, including newlines  */
+		else
+			if (buffer[ibuf-3]=='-' && buffer[ibuf-2]=='-' && buffer[ibuf-1]=='>')
+				break;
+	}
+
+/*  remove trailing blanks or newline  */
+
+	while (ibuf > 0)
+		if (isspace(buffer[ibuf-1]))
+			ibuf--;
+		else {
+			buffer[ibuf]='\0';
+			break;
+		}
+
+//	_pprintLine_("comment buffer (length=" << ibuf << "):");
+//	_pprintLine_(buffer);
+
+	if (!ibuf)
+		xDelete<char>(buffer);
+
+	return(buffer);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenBuffer {{{*/
+void KMLFileTokenBuffer(char** pbuffer,int* pibuf,int* pbuflen,
+						int c,
+						int bufblk){
+
+/*  add the specified character to the token buffer  */
+
+	char*   buffer2=NULL;
+
+/*  check buffer length and realloc if necessary  */
+
+	if (*pibuf+2 > *pbuflen) {
+		*pbuflen+=bufblk;
+		buffer2=xNew<char>(*pbuflen);
+		memcpy(buffer2,*pbuffer,(*pbuflen-bufblk)*sizeof(char));
+		xDelete<char>(*pbuffer);
+		*pbuffer=buffer2;
+		buffer2=NULL;
+//		*pbuffer=(char *) xrealloc(*pbuffer,*pbuflen*sizeof(char));
+	}
+
+/*  add character and terminator  */
+
+	(*pbuffer)[(*pibuf)++]=c;
+	(*pbuffer)[ *pibuf   ]='\0';
+
+	return;
+}
+/*}}}*/
+/*FUNCTION  KMLFileTagName {{{*/
+char* KMLFileTagName(char* pname,
+					 char* ktag){
+
+	return(KMLFileTagName(pname,NULL,0,
+						  ktag));
+}
+/*}}}*/
+/*FUNCTION  KMLFileTagName {{{*/
+char* KMLFileTagName(char* pname,int *m,int maxlen,
+					 char* ktag){
+
+/*  for the given tag buffer, read and store the name  */
+
+	char*   ktagi;
+	char*   ktokn;
+
+	if (strncmp(&ktag[0],"<"        ,1) || strncmp(&ktag[strlen(ktag)-1],">",1))
+		_error_("KMLFileTagName -- Missing tag delimiters in " << ktag << ".\n");
+
+/*  strtok modifies ktag, so work on copy  */
+
+	ktagi=xNew<char>(strlen(ktag)+1);
+	memcpy(ktagi,ktag,(strlen(ktag)+1)*sizeof(char));
+
+/*  skip opening delimeter and find subsequent blank or closing delimiter  */
+
+	ktokn=strtok(ktagi,"< >");
+//	_pprintLine_("KMLFileTagName -- initial token=\"" << ktokn << "\".");
+
+	if (!pname) {
+		if (maxlen)
+			pname=xNew<char>(maxlen       +1);
+		else
+			pname=xNew<char>(strlen(ktokn)+1);
+	}
+
+	if (maxlen && (maxlen < strlen(ktokn))) {
+		_pprintLine_("KMLFileTagName -- string field too short for " << ktag << ".");
+		_pprintLine_("KMLFileTagName -- \"" << ktokn << "\" truncated to " << maxlen << " characters.");
+		strncpy(pname,ktokn,maxlen);
+	}
+	else
+		memcpy(pname,ktokn,(strlen(ktokn)+1)*sizeof(char));
+
+	xDelete<char>(ktagi);
+
+	if (m)
+		*m=strlen(pname);
+
+	return(pname);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTagAttrib {{{*/
+int KMLFileTagAttrib(KML_Object* kobj,
+					 char* ktag){
+
+/*  for the given tag buffer, read and store the attributes  */
+
+	char*   ktagi;
+	char*   ktokn;
+	char*   ktokv;
+	char    quote[]={'\"','\0'};
+	int     isolo=0;
+
+/*  strtok modifies ktag, so work on copy  */
+
+	ktagi=xNew<char>(strlen(ktag)+1);
+	memcpy(ktagi,ktag,(strlen(ktag)+1)*sizeof(char));
+
+/*  loop through tag to find all attributes  */
+
+	/*  return first non blank and move past subsequent blank  */
+	ktokn=strtok(ktagi," ");
+//	_pprintLine_("KMLFileTagAttrib -- initial token=\"" << ktokn << "\".");
+
+	/*  return next non " =?/>" and move past subsequent " =?/>"  */
+	while (ktokn=strtok(NULL," =?/>")) {
+
+		/*  return next non quote and move past subsequent quote  */
+		ktokv=strtok(NULL,quote);
+//		_pprintLine_("KMLFileTagAttrib -- attribute " << ktokn << "=\"" << ktokv << "\".");
+
+/*  add the attribute to the dataset  */
+
+		if (kobj)
+			kobj->AddAttrib(ktokn,ktokv);
+	}
+
+	xDelete<char>(ktagi);
+
+/*  check for xml declaration, dtd declaration, or solo tag  */
+
+	if ((!strncmp(&ktag[0],"<?"       ,2) && !strncmp(&ktag[strlen(ktag)-2],"?>",2)) ||
+		(!strncmp(&ktag[0],"<!DOCTYPE",9) && !strncmp(&ktag[strlen(ktag)-1], ">",1)) ||
+		(!strncmp(&ktag[0],"<"        ,1) && !strncmp(&ktag[strlen(ktag)-2],"/>",2)))
+		isolo=1;
+//	_pprintLine_("KMLFileTagAttrib -- isolo=" << isolo << ".");
+
+	return(isolo);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(int* pival,
+					  char* ktag,
+					  FILE* fid){
+
+	char*   kstr;
+
+/*  get next token and convert to appropriate format  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error_("KMLFileTokenParse -- Missing integer field for " << ktag << ".\n");
+
+	sscanf(kstr,"%d",pival);
+	xDelete<char>(kstr);
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=" << *pival << ".");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(bool* pbval, char* ktag, FILE* fid){
+
+	int     ival;
+	char*   kstr;
+
+/*  get next token and convert to appropriate format  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+	  {_error_("KMLFileTokenParse -- Missing bool field for " << ktag << ".\n");}
+
+	sscanf(kstr,"%d",&ival);
+	*pbval=(bool)ival;
+	xDelete<char>(kstr);
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=" << (*pbval ? "true" : "false") << ".");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+char* KMLFileTokenParse(char* pstr,
+						char* ktag,
+						FILE* fid){
+
+	return(KMLFileTokenParse(pstr,NULL,0,
+							 ktag,
+							 fid));
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+char* KMLFileTokenParse(char* pstr,int *m,int maxlen,
+						char* ktag,
+						FILE* fid){
+
+	char*   kstr;
+
+/*  get next token and allocate if necessary  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error_("KMLFileTokenParse -- Missing string field for " << ktag << ".\n");
+
+	if (!pstr) {
+		if (maxlen)
+			pstr=xNew<char>(maxlen      +1);
+		else
+			pstr=xNew<char>(strlen(kstr)+1);
+	}
+
+	if (maxlen && (maxlen < strlen(kstr))) {
+		_pprintLine_("KMLFileTokenParse -- string field too short for " << ktag << ".");
+		_pprintLine_("KMLFileTokenParse -- \"" << kstr << "\" truncated to " << maxlen << " characters.");
+		strncpy(pstr,kstr,maxlen);
+	}
+	else
+		memcpy(pstr,kstr,(strlen(kstr)+1)*sizeof(char));
+
+	xDelete<char>(kstr);
+
+	if (m)
+		*m=strlen(pstr);
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=\"" << pstr << "\".");
+
+	return(pstr);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(float* pfval,
+					  char* ktag,
+					  FILE* fid){
+
+	char*   kstr;
+
+/*  get next token and convert to appropriate format  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+	  {_error_("KMLFileTokenParse -- Missing integer field for " << ktag << ".\n");}
+
+	sscanf(kstr,"%g",pfval);
+	xDelete<char>(kstr);
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=" << *pfval << ".");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(double* pdval,
+					  char* ktag,
+					  FILE* fid){
+
+	char*   kstr;
+
+/*  get next token and convert to appropriate format  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error_("KMLFileTokenParse -- Missing integer field for " << ktag << ".\n");
+
+	sscanf(kstr,"%lg",pdval);
+	xDelete<char>(kstr);
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=" << *pdval << ".");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(double **pdval,int* m,int maxlen,
+					  char* ktag,
+					  FILE* fid){
+
+	int     i=-1;
+	char*   kstr;
+	char*   ktok;
+	double* dval2=NULL;
+	char    delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
+
+/*  get next token and allocate if necessary  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error_("KMLFileTokenParse -- Missing double [m] field for " << ktag << ".\n");
+
+	if (!*pdval)
+		if (maxlen)
+			*pdval=xNew<IssmDouble>(maxlen            );
+		else
+			*pdval=xNew<IssmDouble>((strlen(kstr)+1)/2);
+
+/*  loop through string to get all values  */
+
+	ktok=strtok(kstr,delim);
+	while (ktok) {
+		i++;
+		if (maxlen && (maxlen < i+1))
+			_error_("KMLFileTokenParse -- Double [m] field too short for " << ktag << ".\n");
+		sscanf(ktok,"%lg",&((*pdval)[i]));
+		ktok=strtok(NULL,delim);
+	}
+	xDelete<char>(kstr);
+
+	if (!maxlen)
+		dval2=xNew<double>(i+1);
+		memcpy(dval2,*pdval,(i+1)*sizeof(double));
+		xDelete<double>(*pdval);
+		*pdval=dval2;
+		dval2=NULL;
+//		*pdval=(double *) xrealloc(*pdval,(i+1)*sizeof(double));
+
+	if (m)
+		*m=i+1;
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=...");
+//	for (j=0; j<=i; j++)
+//		_pprintLine_("   [" << j << "]: " << (*pdval)[j] << "g");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(double **pdval,int* m,int n,int maxlen,
+					  char* ktag,
+					  FILE* fid){
+
+	int     i=-1,j=-1;
+	char*   kstr;
+	char*   ktok;
+	double* dval2=NULL;
+	char    delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
+
+/*  get next token and allocate if necessary  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error_("KMLFileTokenParse -- Missing double [m x n] field for " << ktag << ".\n");
+
+	if (!*pdval)
+		if (maxlen)
+			*pdval=xNew<IssmDouble>(maxlen*n          );
+		else
+			*pdval=xNew<IssmDouble>((strlen(kstr)+1)/2);
+
+/*  loop through string to get all values  */
+
+	ktok=strtok(kstr,delim);
+	while (ktok) {
+		i++;
+		if (maxlen && (maxlen*n < i+1))
+			_error_("KMLFileTokenParse -- Double [m x n] field too short for " << ktag << ".\n");
+		j=(j+1) % n;
+		sscanf(ktok,"%lg",&((*pdval)[i]));
+		ktok=strtok(NULL,delim);
+	}
+	xDelete<char>(kstr);
+
+	if (!maxlen)
+		dval2=xNew<double>((i+1)*n);
+		memcpy(dval2,*pdval,((i+1)*n)*sizeof(double));
+		xDelete<double>(*pdval);
+		*pdval=dval2;
+		dval2=NULL;
+//		*pdval=(double *) xrealloc(*pdval,((i+1)*n)*sizeof(double));
+
+	if (m)
+		*m=((i+1)+(n-1))/n;
+
+	if ((i+1) % n)
+		_pprintLine_("KMLFileTokenParse -- Double [m x n] field for " << ktag << " does not have multiple of n values.");
+
+/*  get additional token and compare to closing tag  */
+
+	if (ktag)
+		if (!(kstr=KMLFileToken(fid,
+								NULL,NULL)) ||
+			(kstr[0] != '<') ||
+			(kstr[1] != '/') ||
+			(strncmp(&(kstr[2]),&(ktag[1]),strlen(ktag)-1)))
+		  {_error_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xDelete<char>(kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=...");
+//	for (j=0; j<=i; j++)
+//		_pprintLine_("   [" << j << "]: " << (*pdval)[j] << "g");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTagSkip {{{*/
+int KMLFileTagSkip(char* ktag,
+				   FILE* fid){
+
+	char*   kstr;
+
+/*  note that tags of the same type can be nested inside each other, so for each
+	opening tag, must find corresponding closing tag  */
+
+	_pprintLine_("KMLFileTagSkip -- input tag " << ktag << ".");
+
+/*  if next token is a closing tag, compare to input  */
+
+	while (kstr=KMLFileToken(fid,
+							 NULL,NULL)) {
+		if      ((kstr[0] == '<') &&
+				 (kstr[1] == '/') &&
+				 (!strncmp(&(kstr[2]),&(ktag[1]),(strcspn(ktag," >")-1)/sizeof(char)))) {
+			_pprintLine_("KMLFileTagSkip -- closing tag " << kstr << ".");
+			xDelete<char>(kstr);
+			return(0);
+		}
+
+/*  if next token is an opening tag, call recursively  */
+
+		else if ((kstr[0] == '<') &&
+				 (kstr[1] != '/')) {
+			_pprintLine_("KMLFileTagSkip -- opening tag " << kstr << ".");
+			KMLFileTagSkip(kstr,
+						   fid);
+		}
+
+/*  if next token is a closing tag, error out  */
+
+		else if ((kstr[0] == '<') &&
+				 (kstr[1] == '/')) {
+			_error_("KMLFileTagSkip -- Unexpected closing tag " << kstr << ".\n");
+		}
+
+		xDelete<char>(kstr);
+	}
+
+	_error_("KMLFileTokenParse -- Corresponding closing tag for " << ktag << " not found.\n");
+
+	return(0);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KMLFileReadUtils.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KMLFileReadUtils.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KMLFileReadUtils.h	(revision 15012)
@@ -0,0 +1,31 @@
+/*!\file:  KMLFileReadUtils.h
+ * \brief: header file for kml file reading utilities.
+ */ 
+
+#ifndef _KMLFILEREADUTILS_H
+#define _KMLFILEREADUTILS_H
+
+/*Headers:{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "../Object.h"
+/*}}}*/
+
+/* local prototypes: */
+char* KMLFileToken(FILE* fid, int* pncom,char*** ppcom);
+char* KMLFileTokenComment(FILE* fid);
+void KMLFileTokenBuffer(char** pbuffer,int* pibuf,int* pbuflen, int c, int bufblk);
+char* KMLFileTagName(char* pname, char* ktag);
+char* KMLFileTagName(char* pname,int *m,int maxlen, char* ktag);
+int KMLFileTagAttrib(KML_Object* kobj, char* ktag);
+int KMLFileTokenParse(int* pival, char* ktag, FILE* fid);
+int KMLFileTokenParse(bool* pbval, char* ktag, FILE* fid);
+char* KMLFileTokenParse(char* pstr, char* ktag, FILE* fid);
+char* KMLFileTokenParse(char* pstr,int *m,int maxlen, char* ktag, FILE* fid);
+int KMLFileTokenParse(float* pfval, char* ktag, FILE* fid);
+int KMLFileTokenParse(double* pdval, char* ktag, FILE* fid);
+int KMLFileTokenParse(double **pdval,int* m,int maxlen, char* ktag, FILE* fid);
+int KMLFileTokenParse(double **pdval,int* m,int n,int maxlen, char* ktag, FILE* fid);
+int KMLFileTagSkip(char* ktag, FILE* fid);
+
+#endif  /* _KMLFILEREADUTILS_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Attribute.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Attribute.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Attribute.cpp	(revision 15012)
@@ -0,0 +1,128 @@
+/*!\file KML_Attribute.cpp
+ * \brief: implementation of the kml_attribute object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Attribute::KML_Attribute(){{{*/
+KML_Attribute::KML_Attribute(){
+
+	name      =NULL;
+	value     =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::~KML_Attribute(){{{*/
+KML_Attribute::~KML_Attribute(){
+
+	if (name      ) xDelete<char>(name);
+	if (value     ) xDelete<char>(value);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Attribute::Echo {{{*/
+void  KML_Attribute::Echo(){
+
+	int   i;
+	bool  flag=true;
+
+	if(flag) _pprintString_("    ");
+	for (i=0;i<10-strlen(name);i++)
+		if(flag) _pprintString_(" ");
+	if(flag) _pprintLine_(name << ": \"" << value << "\"");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::DeepEcho {{{*/
+void  KML_Attribute::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Attribute::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::DeepEcho {{{*/
+void  KML_Attribute::DeepEcho(const char* indent){
+
+	int   i;
+	bool  flag=true;
+
+	if(flag) _pprintString_(indent << "    ");
+	for (i=0;i<10-strlen(name);i++)
+		if(flag) _pprintString_(" ");
+	if(flag) _pprintLine_(name << ": \"" << value << "\"");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::Write {{{*/
+void  KML_Attribute::Write(FILE* filout,const char* indent){
+
+//  attributes always written in keyword line of kml_object
+
+	fprintf(filout,"%s%s=\"%s\"",indent,name,value);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::Read {{{*/
+void  KML_Attribute::Read(FILE* fid,char* kstr){
+
+//  attributes always read in keyword line of kml_object
+
+	;
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::Alloc {{{*/
+void  KML_Attribute::Alloc(const char* namei,const char* valuei){
+
+	name =xNew<char>(strlen(namei )+1);
+	memcpy(name,namei,(strlen(namei)+1)*sizeof(char));
+
+	value=xNew<char>(strlen(valuei)+1);
+	memcpy(value,valuei,(strlen(valuei)+1)*sizeof(char));
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::Add {{{*/
+void  KML_Attribute::Add(DataSet* attrib){
+
+	attrib->AddObject((Object*)this);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Attribute::Get {{{*/
+void  KML_Attribute::Get(char** pvalueo,char* deflt){
+
+	if (!value || !strlen(value)) {
+		*pvalueo=xNew<char>(strlen(deflt)+1);
+		memcpy(*pvalueo,deflt,(strlen(deflt)+1)*sizeof(char));
+	}
+	else {
+		*pvalueo=xNew<char>(strlen(value)+1);
+		memcpy(*pvalueo,value,(strlen(value)+1)*sizeof(char));
+	}
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Attribute.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Attribute.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Attribute.h	(revision 15012)
@@ -0,0 +1,43 @@
+/*! \file KML_Attribute.h 
+ *  \brief: header file for kml_attribute object
+ */
+
+#ifndef _KML_ATTRIBUTE_H_
+#define _KML_ATTRIBUTE_H_
+
+/*Headers:{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "../Object.h"
+class DataSet;
+/*}}}*/
+
+class KML_Attribute: public Object {
+
+	public:
+
+		char* name;
+		char* value;
+
+		/*KML_Attribute constructors, destructors {{{*/
+		KML_Attribute();
+		~KML_Attribute();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		virtual void  Echo();
+		virtual void  DeepEcho();
+		virtual void  DeepEcho(const char* indent);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+		/*virtual functions: */
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  Alloc(const char* namei,const char* valuei);
+		void  Add(DataSet* attrib);
+		void  Get(char** pvalueo,char* deflt);
+
+};
+#endif  /* _KML_ATTRIBUTE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_ColorStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_ColorStyle.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_ColorStyle.cpp	(revision 15012)
@@ -0,0 +1,104 @@
+/*!\file KML_ColorStyle.cpp
+ * \brief: implementation of the kml_colorstyle abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_ColorStyle::KML_ColorStyle(){{{*/
+KML_ColorStyle::KML_ColorStyle(){
+
+	strcpy(color     ,"ffffffff");
+	strcpy(colormode ,"normal");
+
+}
+/*}}}*/
+/*FUNCTION KML_ColorStyle::~KML_ColorStyle(){{{*/
+KML_ColorStyle::~KML_ColorStyle(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_ColorStyle::Echo {{{*/
+void  KML_ColorStyle::Echo(){
+
+	bool  flag=true;
+
+	KML_SubStyle::Echo();
+
+	if(flag) _pprintLine_("         color: " << color);
+	if(flag) _pprintLine_("     colormode: " << colormode);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_ColorStyle::DeepEcho {{{*/
+void  KML_ColorStyle::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_ColorStyle::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_ColorStyle::DeepEcho {{{*/
+void  KML_ColorStyle::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	KML_SubStyle::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "         color: " << color);
+	if(flag) _pprintLine_(indent << "     colormode: " << colormode);
+}
+/*}}}*/
+/*FUNCTION KML_ColorStyle::Write {{{*/
+void  KML_ColorStyle::Write(FILE* filout,const char* indent){
+
+	KML_SubStyle::Write(filout,indent);
+
+	if (color     && strlen(color))
+		fprintf(filout,"%s  <color>%s</color>\n",indent,color);
+	if (colormode && strlen(colormode))
+		fprintf(filout,"%s  <colorMode>%s</colorMode>\n",indent,colormode);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_ColorStyle::Read {{{*/
+void  KML_ColorStyle::Read(FILE* fid,char* kstr){
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</ColorStyle",12))
+		return;
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_ColorStyle::Read -- Unexpected closing tag " << kstr);}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_ColorStyle::Read -- Unexpected field \"" << kstr << "\"");}
+
+	else if (!strcmp(kstr,"<color>"))
+		KMLFileTokenParse( color     ,NULL,KML_COLORSTYLE_COLOR_LENGTH, kstr, fid);
+	else if (!strcmp(kstr,"<colorMode>"))
+		KMLFileTokenParse( colormode ,NULL,KML_COLORSTYLE_COLORMODE_LENGTH, kstr, fid);
+
+	else if (!strncmp(kstr,"<",1))
+		KML_SubStyle::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_ColorStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_ColorStyle.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_ColorStyle.h	(revision 15012)
@@ -0,0 +1,42 @@
+/*! \file KML_ColorStyle.h 
+ *  \brief: header file for kml_colorstyle abstract object
+ */
+
+#ifndef _KML_COLORSTYLE_H_
+#define _KML_COLORSTYLE_H_
+
+#define KML_COLORSTYLE_COLOR_LENGTH      8
+#define KML_COLORSTYLE_COLORMODE_LENGTH  6
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_SubStyle.h"
+/*}}}*/
+
+class KML_ColorStyle: public KML_SubStyle {
+
+	public:
+
+		char  color[KML_COLORSTYLE_COLOR_LENGTH+1];
+		char  colormode[KML_COLORSTYLE_COLORMODE_LENGTH+1];
+
+		/*KML_ColorStyle constructors, destructors {{{*/
+		KML_ColorStyle();
+		~KML_ColorStyle();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_COLORSTYLE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Comment.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Comment.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Comment.cpp	(revision 15012)
@@ -0,0 +1,113 @@
+/*!\file KML_Comment.cpp
+ * \brief: implementation of the kml_comment object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Comment::KML_Comment(){{{*/
+KML_Comment::KML_Comment(){
+
+	value     =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_Comment::~KML_Comment(){{{*/
+KML_Comment::~KML_Comment(){
+
+	if (value     ) xDelete<char>(value);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Comment::Echo {{{*/
+void  KML_Comment::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintString_("    ");
+	if(flag) _pprintLine_(value);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::DeepEcho {{{*/
+void  KML_Comment::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Comment::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::DeepEcho {{{*/
+void  KML_Comment::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintString_(indent << "    ");
+	if(flag) _pprintLine_(value);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::Write {{{*/
+void  KML_Comment::Write(FILE* filout,const char* indent){
+
+	if (strncmp(&value[0]              ,"<!--",4))
+		fprintf(filout,"%s<!--\n",indent);
+	fprintf(filout,"%s  %s\n",indent,value);
+	if (strncmp(&value[strlen(value)-3],"-->" ,3))
+		fprintf(filout,"%s-->\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::Read {{{*/
+void  KML_Comment::Read(FILE* fid,char* kstr){
+
+//  comments always read as part of KMLFileToken
+
+	;
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::Alloc {{{*/
+void  KML_Comment::Alloc(const char* valuei){
+
+	value=xNew<char>(strlen(valuei)+1);
+	memcpy(value,valuei,(strlen(valuei)+1)*sizeof(char));
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::Add {{{*/
+void  KML_Comment::Add(DataSet* commnt){
+
+	commnt->AddObject((Object*)this);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Comment::Get {{{*/
+void  KML_Comment::Get(char** pvalueo){
+
+	*pvalueo=xNew<char>(strlen(value)+1);
+	memcpy(*pvalueo,value,(strlen(value)+1)*sizeof(char));
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Comment.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Comment.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Comment.h	(revision 15012)
@@ -0,0 +1,43 @@
+/*! \file KML_Comment.h 
+ *  \brief: header file for kml_comment object
+ */
+
+#ifndef _KML_COMMENT_H_
+#define _KML_COMMENT_H_
+
+/*Headers:{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "../Object.h"
+class DataSet;
+/*}}}*/
+
+class KML_Comment: public Object {
+
+	public:
+
+		char* name;
+		char* value;
+
+		/*KML_Comment constructors, destructors {{{*/
+		KML_Comment();
+		~KML_Comment();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		virtual void  Echo();
+		virtual void  DeepEcho();
+		virtual void  DeepEcho(const char* indent);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+		/*virtual functions: */
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  Alloc(const char* valuei);
+		void  Add(DataSet* commnt);
+		void  Get(char** pvalueo);
+
+};
+#endif  /* _KML_COMMENT_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Container.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Container.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Container.cpp	(revision 15012)
@@ -0,0 +1,163 @@
+/*!\file KML_Container.cpp
+ * \brief: implementation of the kml_container abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Container::KML_Container(){{{*/
+KML_Container::KML_Container(){
+
+	feature   =new DataSet;
+
+}
+/*}}}*/
+/*FUNCTION KML_Container::~KML_Container(){{{*/
+KML_Container::~KML_Container(){
+
+	if (feature) {
+		delete feature;
+		feature   =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Container::Echo {{{*/
+void  KML_Container::Echo(){
+
+	bool  flag=true;
+
+	KML_Feature::Echo();
+
+	if(flag) _pprintLine_("       feature: (size=" << feature->Size() << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Container::DeepEcho {{{*/
+void  KML_Container::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Container::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Container::DeepEcho {{{*/
+void  KML_Container::DeepEcho(const char* indent){
+
+	int   i;
+	char  indent2[81];
+	bool  flag=true;
+
+	KML_Feature::DeepEcho(indent);
+
+/*  loop over the features for the container  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (feature->Size())
+		for (i=0; i<feature->Size(); i++) {
+			if(flag) _pprintLine_(indent << "       feature: -------- begin [" << i << "] --------");
+			((KML_Feature *)feature->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "       feature: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "       feature: [empty]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Container::Write {{{*/
+void  KML_Container::Write(FILE* filout,const char* indent){
+
+	int   i;
+	char  indent2[81];
+
+	KML_Feature::Write(filout,indent);
+
+/*  loop over the features for the container  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+	for (i=0; i<feature->Size(); i++)
+		((KML_Feature *)feature->GetObjectByOffset(i))->Write(filout,indent2);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Container::Read {{{*/
+void  KML_Container::Read(FILE* fid,char* kstr){
+
+	KML_Object*  kobj;
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</Container",11)) {
+		xDelete<char>(kstr);
+		return;
+	}
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_Container::Read -- Unexpected closing tag " << kstr );}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_Container::Read -- Unexpected field \"" << kstr << "\"");}
+
+	else if (!strncmp(kstr,"<Placemark",10)) {
+		kobj=(KML_Object*)new KML_Placemark();
+		kobj->Read(fid,kstr);
+		feature   ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Folder", 7)) {
+		kobj=(KML_Object*)new KML_Folder();
+		kobj->Read(fid,kstr);
+		feature   ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Document", 9)) {
+		kobj=(KML_Object*)new KML_Document();
+		kobj->Read(fid,kstr);
+		feature   ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<GroundOverlay",14)) {
+		kobj=(KML_Object*)new KML_GroundOverlay();
+		kobj->Read(fid,kstr);
+		feature   ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<",1))
+		KML_Feature::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Container::WriteExp {{{*/
+void  KML_Container::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int   i;
+
+/*  loop over the features for the container  */
+
+	for (i=0; i<feature->Size(); i++)
+		((KML_Object *)feature->GetObjectByOffset(i))->WriteExp(fid,nstr,sgn,cm,sp);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Container.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Container.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Container.h	(revision 15012)
@@ -0,0 +1,39 @@
+/*! \file KML_Container.h 
+ *  \brief: header file for kml_container abstract object
+ */
+
+#ifndef _KML_CONTAINER_H_
+#define _KML_CONTAINER_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Feature.h"
+class DataSet;
+/*}}}*/
+
+class KML_Container: public KML_Feature {
+
+	public:
+
+		DataSet* feature;
+
+		/*KML_Container constructors, destructors {{{*/
+		KML_Container();
+		~KML_Container();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_CONTAINER_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Document.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Document.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Document.cpp	(revision 15012)
@@ -0,0 +1,121 @@
+/*!\file KML_Document.cpp
+ * \brief: implementation of the kml_document object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Document::KML_Document(){{{*/
+KML_Document::KML_Document(){
+
+	;
+
+}
+/*}}}*/
+/*FUNCTION KML_Document::~KML_Document(){{{*/
+KML_Document::~KML_Document(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Document::Echo {{{*/
+void  KML_Document::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Document:");
+	KML_Container::Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Document::DeepEcho {{{*/
+void  KML_Document::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Document::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Document::DeepEcho {{{*/
+void  KML_Document::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Document:");
+	KML_Container::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Document::Write {{{*/
+void  KML_Document::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<Document",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Container::Write(filout,indent);
+
+	fprintf(filout,"%s</Document>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Document::Read {{{*/
+void  KML_Document::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Document",10)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Document::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Document::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Container::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Document.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Document.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Document.h	(revision 15012)
@@ -0,0 +1,36 @@
+/*! \file KML_Document.h 
+ *  \brief: header file for kml_document object
+ */
+
+#ifndef _KML_DOCUMENT_H_
+#define _KML_DOCUMENT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Container.h"
+class KML_Feature;
+/*}}}*/
+
+class KML_Document: public KML_Container {
+
+	public:
+
+		/*KML_Document constructors, destructors {{{*/
+		KML_Document();
+		~KML_Document();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_DOCUMENT_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Feature.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Feature.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Feature.cpp	(revision 15012)
@@ -0,0 +1,174 @@
+/*!\file KML_Feature.cpp
+ * \brief: implementation of the kml_feature abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Feature::KML_Feature(){{{*/
+KML_Feature::KML_Feature(){
+
+	memcpy(name,"",(strlen("")+1)*sizeof(char));
+
+	visibility=true;
+	open      =false;
+	memcpy(snippet,"",(strlen("")+1)*sizeof(char));
+	memcpy(descript,"",(strlen("")+1)*sizeof(char));
+	memcpy(styleurl,"",(strlen("")+1)*sizeof(char));
+	style     =new DataSet;
+
+}
+/*}}}*/
+/*FUNCTION KML_Feature::~KML_Feature(){{{*/
+KML_Feature::~KML_Feature(){
+
+	if (style) {
+		delete style;
+		style     =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Feature::Echo {{{*/
+void  KML_Feature::Echo(){
+
+	bool  flag=true;
+
+	KML_Object::Echo();
+
+	if(flag) _pprintLine_("          name: \"" << name << "\"");
+	if(flag) _pprintLine_("    visibility: " << (visibility ? "true" : "false"));
+	if(flag) _pprintLine_("          open: " << (open ? "true" : "false"));
+	if(flag) _pprintLine_("       snippet: \"" << snippet << "\"");
+	if(flag) _pprintLine_("      descript: \"" << descript << "\"");
+	if(flag) _pprintLine_("      styleurl: \"" << styleurl << "\"");
+	if(flag) _pprintLine_("         style: (size=" << style->Size() << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Feature::DeepEcho {{{*/
+void  KML_Feature::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Feature::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Feature::DeepEcho {{{*/
+void  KML_Feature::DeepEcho(const char* indent){
+
+	int   i;
+	char  indent2[81];
+	bool  flag=true;
+
+	KML_Object::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "          name: \"" << name << "\"");
+	if(flag) _pprintLine_(indent << "    visibility: " << (visibility ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "          open: " << (open ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "       snippet: \"" << snippet << "\"");
+	if(flag) _pprintLine_(indent << "      descript: \"" << descript << "\"");
+	if(flag) _pprintLine_(indent << "      styleurl: \"" << styleurl << "\"");
+
+/*  loop over any styles for the feature  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (style->Size())
+		for (i=0; i<style->Size(); i++) {
+			if(flag) _pprintLine_(indent << "         style: -------- begin [" << i << "] --------");
+			((KML_Style *)style->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "         style: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "         style: [empty]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Feature::Write {{{*/
+void  KML_Feature::Write(FILE* filout,const char* indent){
+
+	int   i;
+	char  indent2[81];
+
+	KML_Object::Write(filout,indent);
+
+	if (name     && strlen(name))
+		fprintf(filout,"%s  <name>%s</name>\n",indent,name);
+	fprintf(filout,"%s  <visibility>%d</visibility>\n",indent,(visibility ? 1 : 0));
+	fprintf(filout,"%s  <open>%d</open>\n",indent,(open ? 1 : 0));
+	if (snippet  && strlen(snippet))
+		fprintf(filout,"%s  <Snippet maxLines=\"2\">%s</Snippet>\n",indent,snippet);
+	if (descript && strlen(descript))
+		fprintf(filout,"%s  <description>%s</description>\n",indent,descript);
+	if (styleurl && strlen(styleurl))
+		fprintf(filout,"%s  <styleUrl>%s</styleUrl>\n",indent,styleurl);
+
+/*  loop over any styles for the feature  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+    for (i=0; i<style->Size(); i++)
+        ((KML_Style *)style->GetObjectByOffset(i))->Write(filout,indent2);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Feature::Read {{{*/
+void  KML_Feature::Read(FILE* fid,char* kstr){
+
+	KML_Object*  kobj;
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</Feature", 9))
+		return;
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_Feature::Read -- Unexpected closing tag " << kstr);}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_Feature::Read -- Unexpected field \"" << kstr << "\"");}
+
+	else if (!strncmp(kstr,"<Style", 6)) {
+		kobj=(KML_Object*)new KML_Style();
+		kobj->Read(fid,kstr);
+		style     ->AddObject((Object*)kobj);
+	}
+
+	else if (!strcmp(kstr,"<name>"))
+		KMLFileTokenParse( name      ,NULL,KML_FEATURE_NAME_LENGTH, kstr, fid);
+	else if (!strcmp(kstr,"<visibility>"))
+		KMLFileTokenParse(&visibility, kstr, fid);
+	else if (!strcmp(kstr,"<open>"))
+		KMLFileTokenParse(&open      , kstr, fid);
+	else if (!strncmp(kstr,"<snippet", 8))
+		KMLFileTokenParse( snippet   ,NULL,KML_FEATURE_SNIPPET_LENGTH, kstr, fid);
+	else if (!strcmp(kstr,"<description>"))
+		KMLFileTokenParse( descript  ,NULL,KML_FEATURE_DESCRIPT_LENGTH, kstr, fid);
+	else if (!strcmp(kstr,"<styleUrl>"))
+		KMLFileTokenParse( styleurl  ,NULL,KML_FEATURE_STYLEURL_LENGTH, kstr, fid);
+
+	else if (!strncmp(kstr,"<",1))
+		KML_Object::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Feature.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Feature.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Feature.h	(revision 15012)
@@ -0,0 +1,50 @@
+/*! \file KML_Feature.h 
+ *  \brief: header file for kml_feature abstract object
+ */
+
+#ifndef _KML_FEATURE_H_
+#define _KML_FEATURE_H_
+
+#define KML_FEATURE_NAME_LENGTH         80
+#define KML_FEATURE_SNIPPET_LENGTH     160
+#define KML_FEATURE_DESCRIPT_LENGTH   3200
+#define KML_FEATURE_STYLEURL_LENGTH     80
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+class KML_Style;
+class DataSet;
+/*}}}*/
+
+class KML_Feature: public KML_Object {
+
+	public:
+
+		char  name[KML_FEATURE_NAME_LENGTH+1];
+		bool  visibility;
+		bool  open;
+		char  snippet[KML_FEATURE_SNIPPET_LENGTH+1];
+		char  descript[KML_FEATURE_DESCRIPT_LENGTH+1];
+		char  styleurl[KML_FEATURE_STYLEURL_LENGTH+1];
+		DataSet* style;
+
+		/*KML_Feature constructors, destructors {{{*/
+		KML_Feature();
+		~KML_Feature();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_FEATURE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_File.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_File.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_File.cpp	(revision 15012)
@@ -0,0 +1,134 @@
+/*!\file KML_File.cpp
+ * \brief: implementation of the kml_file object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_File::KML_File(){{{*/
+KML_File::KML_File(){
+
+	;
+
+}
+/*}}}*/
+/*FUNCTION KML_File::~KML_File(){{{*/
+KML_File::~KML_File(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_File::Echo {{{*/
+void  KML_File::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_File:");
+	KML_Object::Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_File::DeepEcho {{{*/
+void  KML_File::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_File::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_File::DeepEcho {{{*/
+void  KML_File::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_File:");
+	KML_Object::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_File::Write {{{*/
+void  KML_File::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<kml",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Object::Write(filout,indent);
+
+	fprintf(filout,"%s</kml>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_File::Read {{{*/
+void  KML_File::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</kml", 5)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_File::Read -- Unexpected closing tag " << kstri << ".");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_File::Read -- Unexpected field \"" << kstri << "\"");}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Object::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_File::WriteExp {{{*/
+void  KML_File::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int   i;
+
+/*  loop over the kml objects for the file  */
+
+	for (i=0; i<kmlobj->Size(); i++)
+		((KML_Object *)kmlobj->GetObjectByOffset(i))->WriteExp(fid,nstr,sgn,cm,sp);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_File.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_File.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_File.h	(revision 15012)
@@ -0,0 +1,38 @@
+/*! \file KML_File.h 
+ *  \brief: header file for kml_file object
+ */
+
+#ifndef _KML_FILE_H_
+#define _KML_FILE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+
+#include "./KML_Feature.h"
+class DataSet;
+/*}}}*/
+
+class KML_File: public KML_Object {
+
+	public:
+
+		/*KML_File constructors, destructors {{{*/
+		KML_File();
+		~KML_File();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_FILE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Folder.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Folder.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Folder.cpp	(revision 15012)
@@ -0,0 +1,121 @@
+/*!\file KML_Folder.cpp
+ * \brief: implementation of the kml_folder object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Folder::KML_Folder(){{{*/
+KML_Folder::KML_Folder(){
+
+	;
+
+}
+/*}}}*/
+/*FUNCTION KML_Folder::~KML_Folder(){{{*/
+KML_Folder::~KML_Folder(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Folder::Echo {{{*/
+void  KML_Folder::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Folder:");
+	KML_Container::Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Folder::DeepEcho {{{*/
+void  KML_Folder::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Folder::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Folder::DeepEcho {{{*/
+void  KML_Folder::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Folder:");
+	KML_Container::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Folder::Write {{{*/
+void  KML_Folder::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<Folder",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Container::Write(filout,indent);
+
+	fprintf(filout,"%s</Folder>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Folder::Read {{{*/
+void  KML_Folder::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Folder", 8)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Folder::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Folder::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Container::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Folder.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Folder.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Folder.h	(revision 15012)
@@ -0,0 +1,36 @@
+/*! \file KML_Folder.h 
+ *  \brief: header file for kml_folder object
+ */
+
+#ifndef _KML_FOLDER_H_
+#define _KML_FOLDER_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Container.h"
+class KML_Feature;
+/*}}}*/
+
+class KML_Folder: public KML_Container {
+
+	public:
+
+		/*KML_Folder constructors, destructors {{{*/
+		KML_Folder();
+		~KML_Folder();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_FOLDER_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Geometry.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Geometry.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Geometry.cpp	(revision 15012)
@@ -0,0 +1,85 @@
+/*!\file KML_Geometry.cpp
+ * \brief: implementation of the kml_geometry abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Geometry::KML_Geometry(){{{*/
+KML_Geometry::KML_Geometry(){
+
+	;
+
+}
+/*}}}*/
+/*FUNCTION KML_Geometry::~KML_Geometry(){{{*/
+KML_Geometry::~KML_Geometry(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Geometry::Echo {{{*/
+void  KML_Geometry::Echo(){
+
+	this->KML_Object::Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Geometry::DeepEcho {{{*/
+void  KML_Geometry::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Geometry::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Geometry::DeepEcho {{{*/
+void  KML_Geometry::DeepEcho(const char* indent){
+
+	this->KML_Object::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Geometry::Write {{{*/
+void  KML_Geometry::Write(FILE* filout,const char* indent){
+
+	KML_Object::Write(filout,indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Geometry::Read {{{*/
+void  KML_Geometry::Read(FILE* fid,char* kstr){
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</Geometry",10))
+		return;
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_Geometry::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_Geometry::Read -- Unexpected field \"" << kstr << "\".\n");}
+
+	else if (!strncmp(kstr,"<",1))
+		KML_Object::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Geometry.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Geometry.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Geometry.h	(revision 15012)
@@ -0,0 +1,35 @@
+/*! \file KML_Geometry.h 
+ *  \brief: header file for kml_geometry abstract object
+ */
+
+#ifndef _KML_GEOMETRY_H_
+#define _KML_GEOMETRY_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+/*}}}*/
+
+class KML_Geometry: public KML_Object {
+
+	public:
+
+		/*KML_Geometry constructors, destructors {{{*/
+		KML_Geometry();
+		~KML_Geometry();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_GEOMETRY_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_GroundOverlay.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_GroundOverlay.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_GroundOverlay.cpp	(revision 15012)
@@ -0,0 +1,159 @@
+/*!\file KML_GroundOverlay.cpp
+ * \brief: implementation of the kml_groundoverlay object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_GroundOverlay::KML_GroundOverlay(){{{*/
+KML_GroundOverlay::KML_GroundOverlay(){
+
+	altitude  = 0.;
+	memcpy(altmode,"clampToGround",(strlen("clampToGround")+1)*sizeof(char));
+
+	llbox     =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_GroundOverlay::~KML_GroundOverlay(){{{*/
+KML_GroundOverlay::~KML_GroundOverlay(){
+
+	if (llbox) {
+		delete llbox;
+		llbox     =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_GroundOverlay::Echo {{{*/
+void  KML_GroundOverlay::Echo(){
+
+	_printLine_("KML_GroundOverlay:");
+	KML_Overlay::Echo();
+
+	_printLine_("         altitude: " << altitude);
+	_printLine_("          altmode: " << altmode);
+	_printLine_("            llbox: " << llbox);
+}
+/*}}}*/
+/*FUNCTION KML_GroundOverlay::DeepEcho {{{*/
+void  KML_GroundOverlay::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_GroundOverlay::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_GroundOverlay::DeepEcho {{{*/
+void  KML_GroundOverlay::DeepEcho(const char* indent){
+
+	char  indent2[81];
+
+	_printLine_(indent << "KML_GroundOverlay:");
+	KML_Overlay::DeepEcho(indent);
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	_printLine_(indent<<"      altitude: " << altitude);
+	_printLine_(indent<<"       altmode: " << altmode);
+	if (llbox)
+	 llbox->DeepEcho(indent2);
+	else
+	 _printLine_(indent<<"         llbox: " << llbox);
+}
+/*}}}*/
+/*FUNCTION KML_GroundOverlay::Write {{{*/
+void  KML_GroundOverlay::Write(FILE* filout,const char* indent){
+
+	char  indent2[81];
+
+	fprintf(filout,"%s<GroundOverlay",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Overlay::Write(filout,indent);
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+	fprintf(filout,"%s  <altitude>%0.16g</altitude>\n",indent,altitude);
+	fprintf(filout,"%s  <altitudeMode>%s</altitudeMode>\n",indent,altmode);
+	if (llbox)
+		llbox->Write(filout,indent2);
+
+	fprintf(filout,"%s</GroundOverlay>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_GroundOverlay::Read {{{*/
+void  KML_GroundOverlay::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</GroundOverlay",15)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_GroundOverlay::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_GroundOverlay::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<altitude>"))
+			KMLFileTokenParse(&altitude  ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<altitudeMode>"))
+			KMLFileTokenParse( altmode   ,NULL,KML_GROUNDOVERLAY_ALTMODE_LENGTH,
+							  kstri,
+							  fid);
+		else if (!strncmp(kstri,"<LatLonBox",10)) {
+			llbox     =new KML_LatLonBox();
+			llbox     ->Read(fid,kstri);
+		}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Overlay::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_GroundOverlay.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_GroundOverlay.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_GroundOverlay.h	(revision 15012)
@@ -0,0 +1,43 @@
+/*! \file KML_GroundOverlay.h 
+ *  \brief: header file for kml_groundoverlay object
+ */
+
+#ifndef _KML_GROUNDOVERLAY_H_
+#define _KML_GROUNDOVERLAY_H_
+
+#define KML_GROUNDOVERLAY_ALTMODE_LENGTH    18
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+
+#include "./KML_Overlay.h"
+class KML_LatLonBox;
+/*}}}*/
+
+class KML_GroundOverlay: public KML_Overlay {
+
+	public:
+
+		double altitude;
+		char  altmode[KML_GROUNDOVERLAY_ALTMODE_LENGTH+1];
+		KML_LatLonBox* llbox;
+
+		/*KML_GroundOverlay constructors, destructors {{{*/
+		KML_GroundOverlay();
+		~KML_GroundOverlay();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_GROUNDOVERLAY_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Icon.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Icon.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Icon.cpp	(revision 15012)
@@ -0,0 +1,177 @@
+/*!\file KML_Icon.cpp
+ * \brief: implementation of the kml_feature abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Icon::KML_Icon(){{{*/
+KML_Icon::KML_Icon(){
+
+	strcpy(href      ,"");
+	strcpy(refmode   ,"onChange");
+	refint    = 4.;
+	strcpy(vrefmode  ,"never");
+	vreftime  = 4.;
+	vboundsc  = 1.;
+	strcpy(vformat   ,"");
+	strcpy(hquery    ,"");
+
+}
+/*}}}*/
+/*FUNCTION KML_Icon::~KML_Icon(){{{*/
+KML_Icon::~KML_Icon(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Icon::Echo {{{*/
+void  KML_Icon::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Icon:");
+	KML_Object::Echo();
+
+	if(flag) _pprintLine_("          href: \"" << href << "\"");
+	if(flag) _pprintLine_("       refmode: \"" << refmode << "\"");
+	if(flag) _pprintLine_("        refint: " << refint);
+	if(flag) _pprintLine_("      vrefmode: \"" << vrefmode << "\"");
+	if(flag) _pprintLine_("      vreftime: " << vreftime);
+	if(flag) _pprintLine_("      vboundsc: " << vboundsc);
+	if(flag) _pprintLine_("       vformat: \"" << vformat << "\"");
+	if(flag) _pprintLine_("        hquery: \"" << hquery << "\"");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Icon::DeepEcho {{{*/
+void  KML_Icon::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Icon::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Icon::DeepEcho {{{*/
+void  KML_Icon::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Icon:");
+	KML_Object::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "          href: \"" << href << "\"");
+	if(flag) _pprintLine_(indent << "       refmode: \"" << refmode << "\"");
+	if(flag) _pprintLine_(indent << "        refint: " << refint);
+	if(flag) _pprintLine_(indent << "      vrefmode: \"" << vrefmode << "\"");
+	if(flag) _pprintLine_(indent << "      vreftime: " << vreftime);
+	if(flag) _pprintLine_(indent << "      vboundsc: " << vboundsc);
+	if(flag) _pprintLine_(indent << "       vformat: \"" << vformat << "\"");
+	if(flag) _pprintLine_(indent << "        hquery: \"" << hquery << "\"");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Icon::Write {{{*/
+void  KML_Icon::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<Icon",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Object::Write(filout,indent);
+
+	if (href     && strlen(href))
+		fprintf(filout,"%s  <href>%s</href>\n",indent,href);
+	if (refmode  && strlen(refmode))
+		fprintf(filout,"%s  <refreshMode>%s</refreshMode>\n",indent,refmode);
+	fprintf(filout,"%s  <refreshInterval>%g</refreshInterval>\n",indent,refint);
+	if (vrefmode && strlen(vrefmode))
+		fprintf(filout,"%s  <viewRefreshMode>%s</viewRefreshMode>\n",indent,vrefmode);
+	fprintf(filout,"%s  <viewRefreshTime>%g</viewRefreshTime>\n",indent,vreftime);
+	fprintf(filout,"%s  <viewBoundScale>%g</viewBoundScale>\n",indent,vboundsc);
+	if (vformat  && strlen(vformat))
+		fprintf(filout,"%s  <viewFormat>%s</viewFormat>\n",indent,vformat);
+	if (hquery   && strlen(hquery))
+		fprintf(filout,"%s  <httpQuery>%s</httpQuery>\n",indent,hquery);
+
+	fprintf(filout,"%s</Icon>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Icon::Read {{{*/
+void  KML_Icon::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Icon", 6)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Icon::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Icon::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<href>"))
+			KMLFileTokenParse( href      ,NULL,KML_ICON_HREF_LENGTH, kstri, fid);
+		else if (!strcmp(kstri,"<refreshMode>"))
+			KMLFileTokenParse( refmode   ,NULL,KML_ICON_REFMODE_LENGTH, kstri, fid);
+		else if (!strcmp(kstri,"<refreshInterval>"))
+			KMLFileTokenParse(&refint    , kstri, fid);
+		else if (!strcmp(kstri,"<viewRefreshMode>"))
+			KMLFileTokenParse( vrefmode  ,NULL,KML_ICON_VREFMODE_LENGTH, kstri, fid);
+		else if (!strcmp(kstri,"<viewRefreshTime>"))
+			KMLFileTokenParse(&vreftime  , kstri, fid);
+		else if (!strcmp(kstri,"<viewBoundScale>"))
+			KMLFileTokenParse(&vboundsc  , kstri, fid);
+		else if (!strcmp(kstri,"<viewFormat>"))
+			KMLFileTokenParse( vformat   ,NULL,KML_ICON_VFORMAT_LENGTH, kstri, fid);
+		else if (!strcmp(kstri,"<httpQuery>"))
+			KMLFileTokenParse( hquery    ,NULL,KML_ICON_HQUERY_LENGTH, kstri, fid);
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Object::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Icon.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Icon.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Icon.h	(revision 15012)
@@ -0,0 +1,50 @@
+/*! \file KML_Icon.h 
+ *  \brief: header file for kml_icon object
+ */
+
+#ifndef _KML_ICON_H_
+#define _KML_ICON_H_
+
+#define KML_ICON_HREF_LENGTH      800
+#define KML_ICON_REFMODE_LENGTH    10
+#define KML_ICON_VREFMODE_LENGTH    9
+#define KML_ICON_VFORMAT_LENGTH   800
+#define KML_ICON_HQUERY_LENGTH    800
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+/*}}}*/
+
+class KML_Icon: public KML_Object {
+
+	public:
+
+		char  href[KML_ICON_HREF_LENGTH+1];
+		char  refmode[KML_ICON_REFMODE_LENGTH+1];
+		float refint;
+		char  vrefmode[KML_ICON_VREFMODE_LENGTH+1];
+		float vreftime;
+		float vboundsc;
+		char  vformat[KML_ICON_VFORMAT_LENGTH+1];
+		char  hquery[KML_ICON_HQUERY_LENGTH+1];
+
+		/*KML_Icon constructors, destructors {{{*/
+		KML_Icon();
+		~KML_Icon();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_ICON_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LatLonBox.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LatLonBox.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LatLonBox.cpp	(revision 15012)
@@ -0,0 +1,156 @@
+/*!\file KML_LatLonBox.cpp
+ * \brief: implementation of the kml_feature abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_LatLonBox::KML_LatLonBox(){{{*/
+KML_LatLonBox::KML_LatLonBox(){
+
+	north     = 0.;
+	south     = 0.;
+	east      = 0.;
+	west      = 0.;
+	rotation  = 0.;
+
+}
+/*}}}*/
+/*FUNCTION KML_LatLonBox::~KML_LatLonBox(){{{*/
+KML_LatLonBox::~KML_LatLonBox(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_LatLonBox::Echo {{{*/
+void  KML_LatLonBox::Echo(){
+
+	_printLine_("KML_LatLonBox:");
+	KML_Object::Echo();
+
+	_printLine_("         north: " << north);
+	_printLine_("         south: " << south);
+	_printLine_("          east: " << east);
+	_printLine_("          west: " << west);
+	_printLine_("      rotation: " << rotation);
+}
+/*}}}*/
+/*FUNCTION KML_LatLonBox::DeepEcho {{{*/
+void  KML_LatLonBox::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_LatLonBox::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LatLonBox::DeepEcho {{{*/
+void  KML_LatLonBox::DeepEcho(const char* indent){
+
+	_printLine_(indent << "KML_LatLonBox:");
+	KML_Object::DeepEcho(indent);
+
+	_printLine_("         north: " << north);
+	_printLine_("         south: " << south);
+	_printLine_("          east: " << east);
+	_printLine_("          west: " << west);
+	_printLine_("      rotation: " << rotation);
+}
+/*}}}*/
+/*FUNCTION KML_LatLonBox::Write {{{*/
+void  KML_LatLonBox::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<LatLonBox",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Object::Write(filout,indent);
+
+	fprintf(filout,"%s  <north>%0.16g</north>\n",indent,north);
+	fprintf(filout,"%s  <south>%0.16g</south>\n",indent,south);
+	fprintf(filout,"%s  <east>%0.16g</east>\n",indent,east);
+	fprintf(filout,"%s  <west>%0.16g</west>\n",indent,west);
+	fprintf(filout,"%s  <rotation>%0.16g</rotation>\n",indent,rotation);
+
+	fprintf(filout,"%s</LatLonBox>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LatLonBox::Read {{{*/
+void  KML_LatLonBox::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</LatLonBox",11)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_LatLonBox::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_LatLonBox::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<north>"))
+			KMLFileTokenParse(&north     ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<south>"))
+			KMLFileTokenParse(&south     ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<east>"))
+			KMLFileTokenParse(&east      ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<west>"))
+			KMLFileTokenParse(&west      ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<rotation>"))
+			KMLFileTokenParse(&rotation  ,
+							  kstri,
+							  fid);
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Object::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LatLonBox.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LatLonBox.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LatLonBox.h	(revision 15012)
@@ -0,0 +1,41 @@
+/*! \file KML_LatLonBox.h 
+ *  \brief: header file for kml_latlonbox object
+ */
+
+#ifndef _KML_LATLONBOX_H_
+#define _KML_LATLONBOX_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+/*}}}*/
+
+class KML_LatLonBox: public KML_Object {
+
+	public:
+
+		double north;
+		double south;
+		double east;
+		double west;
+		double rotation;
+
+		/*KML_LatLonBox constructors, destructors {{{*/
+		KML_LatLonBox();
+		~KML_LatLonBox();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LATLONBOX_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LineString.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LineString.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LineString.cpp	(revision 15012)
@@ -0,0 +1,231 @@
+/*!\file KML_LineString.cpp
+ * \brief: implementation of the kml_linestring object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+#include "modules/Ll2xyx/Ll2xyx.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_LineString::KML_LineString(){{{*/
+KML_LineString::KML_LineString(){
+
+	extrude   =false;
+	tessellate=false;
+	memcpy(altmode,"clampToGround",(strlen("clampToGround")+1)*sizeof(char));
+
+	ncoord    =0;
+	coords    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_LineString::~KML_LineString(){{{*/
+KML_LineString::~KML_LineString(){
+
+	if (coords) xDelete<double>(coords);
+
+	coords    =NULL;
+	ncoord    =0;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_LineString::Echo {{{*/
+void  KML_LineString::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_LineString:");
+	KML_Geometry::Echo();
+
+	if(flag) _pprintLine_("       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_("    tessellate: " << (tessellate ? "true" : "false"));
+	if(flag) _pprintLine_("       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_("        coords: (ncoord=" << ncoord << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineString::DeepEcho {{{*/
+void  KML_LineString::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_LineString::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineString::DeepEcho {{{*/
+void  KML_LineString::DeepEcho(const char* indent){
+
+	int   i;
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_LineString:");
+	KML_Geometry::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "    tessellate: " << (tessellate ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_(indent << "        coords: (ncoord=" << ncoord << ")");
+	for (i=0; i<ncoord; i++)
+		if(flag) _pprintLine_(indent << "                (" << coords[3*i+0] << "," << coords[3*i+1] << "," << coords[3*i+2] << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineString::Write {{{*/
+void  KML_LineString::Write(FILE* filout,const char* indent){
+
+	int   i;
+
+	fprintf(filout,"%s<LineString",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Geometry::Write(filout,indent);
+
+	fprintf(filout,"%s  <extrude>%d</extrude>\n",indent,(extrude ? 1 : 0));
+	fprintf(filout,"%s  <tessellate>%d</tessellate>\n",indent,(tessellate ? 1 : 0));
+	fprintf(filout,"%s  <altitudeMode>%s</altitudeMode>\n",indent,altmode);
+	fprintf(filout,"%s  <coordinates>\n",indent);
+
+/*  loop over the coordinates for the linestring  */
+
+	for (i=0; i<ncoord; i++)
+		fprintf(filout,"%s    %0.16g,%0.16g,%0.16g\n",indent, coords[3*i+0],coords[3*i+1],coords[3*i+2]);
+
+	fprintf(filout,"%s  </coordinates>\n",indent);
+	fprintf(filout,"%s</LineString>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineString::Read {{{*/
+void  KML_LineString::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</LineString",12)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_LineString::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_LineString::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<extrude>"))
+			KMLFileTokenParse(&extrude   ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<tessellate>"))
+			KMLFileTokenParse(&tessellate,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<altitudeMode>"))
+			KMLFileTokenParse( altmode   ,NULL,KML_LINESTRING_ALTMODE_LENGTH,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<coordinates>"))
+			KMLFileTokenParse(&coords    ,&ncoord    ,0,
+							  kstri,
+							  fid);
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Geometry::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineString::WriteExp {{{*/
+void  KML_LineString::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int     i;
+	double  *lat,*lon,*x,*y;
+	char    nstr2[81];
+
+/*  extract latitude and longitude into vectors  */
+
+	lat=xNew<IssmDouble>(ncoord);
+	lon=xNew<IssmDouble>(ncoord);
+	for (i=0; i<ncoord; i++) {
+		lon[i]=coords[3*i+0];
+		lat[i]=coords[3*i+1];
+	}
+
+/*  convert latitude and longitude to x and y  */
+
+	x  =xNew<IssmDouble>(ncoord);
+	y  =xNew<IssmDouble>(ncoord);
+	if (sgn) {
+		Ll2xyx(x,y,lat,lon,ncoord,sgn,cm,sp);
+	}
+	else {
+		memcpy(x,lon,ncoord*sizeof(IssmDouble));
+		memcpy(y,lat,ncoord*sizeof(IssmDouble));
+	}
+
+/*  write header  */
+
+	memcpy(nstr2,nstr,(strlen(nstr)+1)*sizeof(char));
+
+	for (i=0; i<strlen(nstr2); i++)
+		if ((nstr2[i] == ' ') || (nstr2[i] == '\t'))
+			nstr2[i]='_';
+	fprintf(fid,"## Name:%s\n",nstr2);
+	fprintf(fid,"## Icon:0\n");
+	fprintf(fid,"# Points Count	Value\n");
+    fprintf(fid,"%u	%s\n",ncoord  ,"1.");
+	fprintf(fid,"# X pos	Y pos\n");
+
+/*  write vertices  */
+
+	for (i=0; i<ncoord; i++)
+	    fprintf(fid,"%lf\t%lf\n",x[i],y[i]);
+
+/*  write blank line  */
+
+	fprintf(fid,"\n");
+
+	xDelete<IssmDouble>(y);
+	xDelete<IssmDouble>(x);
+	xDelete<IssmDouble>(lon);
+	xDelete<IssmDouble>(lat);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LineString.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LineString.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LineString.h	(revision 15012)
@@ -0,0 +1,44 @@
+/*! \file KML_LineString.h 
+ *  \brief: header file for kml_linestring object
+ */
+
+#ifndef _KML_LINESTRING_H_
+#define _KML_LINESTRING_H_
+
+#define KML_LINESTRING_ALTMODE_LENGTH    18
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Geometry.h"
+/*}}}*/
+
+class KML_LineString: public KML_Geometry {
+
+	public:
+
+		bool    extrude;
+		bool    tessellate;
+		char    altmode[KML_LINESTRING_ALTMODE_LENGTH+1];
+		int     ncoord;
+		double *coords;
+
+		/*KML_LineString constructors, destructors {{{*/
+		KML_LineString();
+		~KML_LineString();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LINESTRING_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LineStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LineStyle.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LineStyle.cpp	(revision 15012)
@@ -0,0 +1,132 @@
+/*!\file KML_LineStyle.cpp
+ * \brief: implementation of the kml_linestyle object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_LineStyle::KML_LineStyle(){{{*/
+KML_LineStyle::KML_LineStyle(){
+
+	width     =1.;
+
+}
+/*}}}*/
+/*FUNCTION KML_LineStyle::~KML_LineStyle(){{{*/
+KML_LineStyle::~KML_LineStyle(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_LineStyle::Echo {{{*/
+void  KML_LineStyle::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_LineStyle:");
+	KML_ColorStyle::Echo();
+
+	if(flag) _pprintLine_("         width: " << width);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineStyle::DeepEcho {{{*/
+void  KML_LineStyle::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_LineStyle::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineStyle::DeepEcho {{{*/
+void  KML_LineStyle::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_LineStyle:");
+	KML_ColorStyle::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "         width: " << width);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineStyle::Write {{{*/
+void  KML_LineStyle::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<LineStyle",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_ColorStyle::Write(filout,indent);
+
+	fprintf(filout,"%s  <width>%g</width>\n",indent,width);
+
+	fprintf(filout,"%s</LineStyle>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LineStyle::Read {{{*/
+void  KML_LineStyle::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</LineStyle",11)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_LineStyle::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_LineStyle::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<width>"))
+			KMLFileTokenParse(&width     ,
+							  kstri,
+							  fid);
+
+		else if (!strncmp(kstri,"<",1))
+			KML_ColorStyle::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LineStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LineStyle.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LineStyle.h	(revision 15012)
@@ -0,0 +1,37 @@
+/*! \file KML_LineStyle.h 
+ *  \brief: header file for kml_linestyle object
+ */
+
+#ifndef _KML_LINESTYLE_H_
+#define _KML_LINESTYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_ColorStyle.h"
+/*}}}*/
+
+class KML_LineStyle: public KML_ColorStyle {
+
+	public:
+
+		float width;
+
+		/*KML_LineStyle constructors, destructors {{{*/
+		KML_LineStyle();
+		~KML_LineStyle();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LINESTYLE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LinearRing.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LinearRing.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LinearRing.cpp	(revision 15012)
@@ -0,0 +1,225 @@
+/*!\file KML_LinearRing.cpp
+ * \brief: implementation of the kml_linearring object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+#include "modules/Ll2xyx/Ll2xyx.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_LinearRing::KML_LinearRing(){{{*/
+KML_LinearRing::KML_LinearRing(){
+
+	extrude   =false;
+	tessellate=false;
+	memcpy(altmode,"clampToGround",(strlen("clampToGround")+1)*sizeof(char));
+
+	ncoord    =0;
+	coords    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_LinearRing::~KML_LinearRing(){{{*/
+KML_LinearRing::~KML_LinearRing(){
+
+	if (coords) xDelete<double>(coords);
+
+	coords    =NULL;
+	ncoord    =0;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_LinearRing::Echo {{{*/
+void  KML_LinearRing::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_LinearRing:");
+	KML_Geometry::Echo();
+
+	if(flag) _pprintLine_("       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_("    tessellate: " << (tessellate ? "true" : "false"));
+	if(flag) _pprintLine_("       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_("        coords: (ncoord=" << ncoord << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LinearRing::DeepEcho {{{*/
+void  KML_LinearRing::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_LinearRing::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LinearRing::DeepEcho {{{*/
+void  KML_LinearRing::DeepEcho(const char* indent){
+
+	int   i;
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_LinearRing:");
+	KML_Geometry::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "    tessellate: " << (tessellate ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_(indent << "        coords: (ncoord=" << ncoord << ")");
+	for (i=0; i<ncoord; i++)
+		_printf_(flag,"%s                (%g,%g,%g)\n",indent,
+				coords[3*i+0],coords[3*i+1],coords[3*i+2]);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LinearRing::Write {{{*/
+void  KML_LinearRing::Write(FILE* filout,const char* indent){
+
+	int   i;
+
+	fprintf(filout,"%s<LinearRing",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Geometry::Write(filout,indent);
+
+	fprintf(filout,"%s  <extrude>%d</extrude>\n",indent,(extrude ? 1 : 0));
+	fprintf(filout,"%s  <tessellate>%d</tessellate>\n",indent,(tessellate ? 1 : 0));
+	fprintf(filout,"%s  <altitudeMode>%s</altitudeMode>\n",indent,altmode);
+	fprintf(filout,"%s  <coordinates>\n",indent);
+
+/*  loop over the coordinates for the linearring  */
+
+	for (i=0; i<ncoord; i++)
+		fprintf(filout,"%s    %0.16g,%0.16g,%0.16g\n",indent,coords[3*i+0],coords[3*i+1],coords[3*i+2]);
+
+	fprintf(filout,"%s  </coordinates>\n",indent);
+	fprintf(filout,"%s</LinearRing>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LinearRing::Read {{{*/
+void  KML_LinearRing::Read(FILE* fid,char* kstr){
+
+	char  *kstri = NULL;
+	int    ncom  = 0;
+	char **pcom  = NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,kstr)) return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,&ncom,&pcom)){
+		if (!strncmp(kstri,"</LinearRing",12)){
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_LinearRing::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_LinearRing::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<extrude>"))
+			KMLFileTokenParse(&extrude,kstri,fid);
+		else if (!strcmp(kstri,"<tessellate>"))
+			KMLFileTokenParse(&tessellate,kstri,fid);
+		else if (!strcmp(kstri,"<altitudeMode>"))
+			KMLFileTokenParse(altmode,NULL,KML_LINEARRING_ALTMODE_LENGTH,kstri,fid);
+		else if (!strcmp(kstri,"<coordinates>"))
+			KMLFileTokenParse(&coords,&ncoord,3,0,kstri,fid);
+		else if (!strncmp(kstri,"<",1))
+			KML_Geometry::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for(ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_LinearRing::WriteExp {{{*/
+void  KML_LinearRing::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int     i;
+	double  *lat,*lon,*x,*y;
+	char    nstr2[81];
+
+/*  extract latitude and longitude into vectors  */
+
+	lat=xNew<IssmDouble>(ncoord);
+	lon=xNew<IssmDouble>(ncoord);
+	for (i=0; i<ncoord; i++) {
+		lon[i]=coords[3*i+0];
+		lat[i]=coords[3*i+1];
+	}
+
+/*  convert latitude and longitude to x and y  */
+
+	x  =xNew<IssmDouble>(ncoord);
+	y  =xNew<IssmDouble>(ncoord);
+	if (sgn) {
+		Ll2xyx(x,y,lat,lon,ncoord,sgn,cm,sp);
+	}
+	else {
+		memcpy(x,lon,ncoord*sizeof(IssmDouble));
+		memcpy(y,lat,ncoord*sizeof(IssmDouble));
+	}
+
+/*  write header  */
+
+	memcpy(nstr2,nstr,(strlen(nstr)+1)*sizeof(char));
+
+	for (i=0; i<strlen(nstr2); i++)
+		if ((nstr2[i] == ' ') || (nstr2[i] == '\t'))
+			nstr2[i]='_';
+	fprintf(fid,"## Name:%s\n",nstr2);
+	fprintf(fid,"## Icon:0\n");
+	fprintf(fid,"# Points Count	Value\n");
+	if ((lat[ncoord-1] != lat[0]) || (lon[ncoord-1] != lon[0]))
+	    fprintf(fid,"%u	%s\n",ncoord+1,"1.");
+	else
+	    fprintf(fid,"%u	%s\n",ncoord  ,"1.");
+	fprintf(fid,"# X pos	Y pos\n");
+
+/*  write vertices, making sure ring is closed  */
+
+	for (i=0; i<ncoord; i++)
+	    fprintf(fid,"%lf\t%lf\n",x[i],y[i]);
+	if ((lat[ncoord-1] != lat[0]) || (lon[ncoord-1] != lon[0]))
+	    fprintf(fid,"%lf\t%lf\n",x[0],y[0]);
+
+/*  write blank line  */
+
+	fprintf(fid,"\n");
+
+	xDelete<double>(y);
+	xDelete<double>(x);
+	xDelete<double>(lon);
+	xDelete<double>(lat);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_LinearRing.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_LinearRing.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_LinearRing.h	(revision 15012)
@@ -0,0 +1,44 @@
+/*! \file KML_LinearRing.h 
+ *  \brief: header file for kml_linearring object
+ */
+
+#ifndef _KML_LINEARRING_H_
+#define _KML_LINEARRING_H_
+
+#define KML_LINEARRING_ALTMODE_LENGTH    18
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Geometry.h"
+/*}}}*/
+
+class KML_LinearRing: public KML_Geometry {
+
+	public:
+
+		bool     extrude;
+		bool     tessellate;
+		char     altmode[KML_LINEARRING_ALTMODE_LENGTH+1];
+		int      ncoord;
+		double  *coords;
+
+		/*KML_LinearRing constructors, destructors {{{*/
+		KML_LinearRing();
+		~KML_LinearRing();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LINEARRING_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_MultiGeometry.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_MultiGeometry.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_MultiGeometry.cpp	(revision 15012)
@@ -0,0 +1,198 @@
+/*!\file KML_MultiGeometry.cpp
+ * \brief: implementation of the kml_multigeometry object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_MultiGeometry::KML_MultiGeometry(){{{*/
+KML_MultiGeometry::KML_MultiGeometry(){
+
+	geometry  =new DataSet;
+
+}
+/*}}}*/
+/*FUNCTION KML_MultiGeometry::~KML_MultiGeometry(){{{*/
+KML_MultiGeometry::~KML_MultiGeometry(){
+
+	if (geometry) {
+		delete geometry;
+		geometry  =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_MultiGeometry::Echo {{{*/
+void  KML_MultiGeometry::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Multigeometry:");
+	KML_Geometry::Echo();
+
+	if(flag) _pprintLine_("      geometry: (size=" << geometry->Size() << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_MultiGeometry::DeepEcho {{{*/
+void  KML_MultiGeometry::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_MultiGeometry::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_MultiGeometry::DeepEcho {{{*/
+void  KML_MultiGeometry::DeepEcho(const char* indent){
+
+	int   i;
+	char  indent2[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Multigeometry:");
+	KML_Geometry::DeepEcho(indent);
+
+/*  loop over the geometry elements for the multigeometry  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (geometry->Size())
+		for (i=0; i<geometry->Size(); i++) {
+			if(flag) _pprintLine_(indent << "      geometry: -------- begin [" << i << "] --------");
+			((KML_Geometry *)geometry->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "      geometry: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "      geometry: [empty]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_MultiGeometry::Write {{{*/
+void  KML_MultiGeometry::Write(FILE* filout,const char* indent){
+
+	int   i;
+	char  indent2[81];
+
+	fprintf(filout,"%s<MultiGeometry",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Geometry::Write(filout,indent);
+
+/*  loop over the geometry elements for the multigeometry  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+	for (i=0; i<geometry->Size(); i++)
+		((KML_Geometry *)geometry->GetObjectByOffset(i))->Write(filout,indent2);
+
+	fprintf(filout,"%s</MultiGeometry>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_MultiGeometry::Read {{{*/
+void  KML_MultiGeometry::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+	KML_Object*  kobj;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</MultiGeometry",15)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_MultiGeometry::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_MultiGeometry::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strncmp(kstri,"<Point", 6)) {
+			kobj=(KML_Object*)new KML_Point();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<LineString",11)) {
+			kobj=(KML_Object*)new KML_LineString();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<LinearRing",11)) {
+			kobj=(KML_Object*)new KML_LinearRing();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<Polygon", 8)) {
+			kobj=(KML_Object*)new KML_Polygon();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<MultiGeometry",14)) {
+			kobj=(KML_Object*)new KML_MultiGeometry();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Geometry::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_MultiGeometry::WriteExp {{{*/
+void  KML_MultiGeometry::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int   i;
+
+/*  loop over the geometry elements for the multigeometry  */
+
+	for (i=0; i<geometry->Size(); i++)
+		((KML_Object *)geometry->GetObjectByOffset(i))->WriteExp(fid,nstr,sgn,cm,sp);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_MultiGeometry.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_MultiGeometry.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_MultiGeometry.h	(revision 15012)
@@ -0,0 +1,40 @@
+/*! \file KML_MultiGeometry.h 
+ *  \brief: header file for kml_multigeometry object
+ */
+
+#ifndef _KML_MULTIGEOMETRY_H_
+#define _KML_MULTIGEOMETRY_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Geometry.h"
+class KML_Geometry;
+class DataSet;
+/*}}}*/
+
+class KML_MultiGeometry: public KML_Geometry {
+
+	public:
+
+		DataSet* geometry;
+
+		/*KML_MultiGeometry constructors, destructors {{{*/
+		KML_MultiGeometry();
+		~KML_MultiGeometry();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_MULTIGEOMETRY_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Object.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Object.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Object.cpp	(revision 15012)
@@ -0,0 +1,382 @@
+/*!\file KML_Object.cpp
+ * \brief: implementation of the kml_object abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Object::KML_Object(){{{*/
+KML_Object::KML_Object(){
+
+	attrib    =new DataSet;
+	commnt    =new DataSet;
+	kmlobj    =new DataSet;
+
+}
+/*}}}*/
+/*FUNCTION KML_Object::~KML_Object(){{{*/
+KML_Object::~KML_Object(){
+
+	if (attrib) {
+		delete attrib;
+		attrib    =NULL;
+	}
+	if (commnt) {
+		delete commnt;
+		commnt    =NULL;
+	}
+	if (kmlobj) {
+		delete kmlobj;
+		kmlobj    =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Object::Echo {{{*/
+void  KML_Object::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("        attrib: (size=" << attrib->Size() << ")");
+	if(flag) _pprintLine_("        commnt: (size=" << commnt->Size() << ")");
+	if(flag) _pprintLine_("        kmlobj: (size=" << kmlobj->Size() << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::DeepEcho {{{*/
+void  KML_Object::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Object::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::DeepEcho {{{*/
+void  KML_Object::DeepEcho(const char* indent){
+
+	int   i;
+	char  indent2[81];
+	bool  flag=true;
+
+/*  loop over the attributes for the object  */
+
+	if (attrib->Size())
+		for (i=0; i<attrib->Size(); i++) {
+			((KML_Attribute *)attrib->GetObjectByOffset(i))->DeepEcho(indent);
+		}
+	else
+		if(flag) _pprintLine_(indent << "        attrib: [empty]");
+
+/*  loop over the comments for the object  */
+
+	if (commnt->Size())
+		for (i=0; i<commnt->Size(); i++) {
+			((KML_Comment *)commnt->GetObjectByOffset(i))->DeepEcho(indent);
+		}
+	else
+		if(flag) _pprintLine_(indent << "        commnt: [empty]");
+
+/*  loop over the unknown objects for the object  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (kmlobj->Size())
+		for (i=0; i<kmlobj->Size(); i++) {
+            if(flag) _pprintLine_(indent << "        kmlobj: -------- begin [" << i << "] --------");
+			((KML_Unknown *)kmlobj->GetObjectByOffset(i))->DeepEcho(indent2);
+            if(flag) _pprintLine_(indent << "        kmlobj: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "        kmlobj: [empty]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::Write {{{*/
+void  KML_Object::Write(FILE* filout,const char* indent){
+
+	int   i;
+	char  indent2[81];
+
+//  attributes always written in keyword line of derived classes
+//  comments always written after keyword line of derived classes
+
+/*  loop over the unknown objects for the object  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (kmlobj->Size())
+		for (i=0; i<kmlobj->Size(); i++) {
+			((KML_Unknown *)kmlobj->GetObjectByOffset(i))->Write(filout,indent2);
+		}
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::Read {{{*/
+void  KML_Object::Read(FILE* fid,char* kstr){
+
+	KML_Object*  kobj;
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</Object", 8))
+		return;
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_Object::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_Object::Read -- Unexpected field \"" << kstr << "\".\n");}
+
+	else if (!strncmp(kstr,"<Placemark",10)) {
+		kobj=(KML_Object*)new KML_Placemark();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Folder", 7)) {
+		kobj=(KML_Object*)new KML_Folder();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Document", 9)) {
+		kobj=(KML_Object*)new KML_Document();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<GroundOverlay",14)) {
+		kobj=(KML_Object*)new KML_GroundOverlay();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<LatLonBox",10)) {
+		kobj=(KML_Object*)new KML_LatLonBox();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Icon", 5)) {
+		kobj=(KML_Object*)new KML_Icon();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Point", 6)) {
+		kobj=(KML_Object*)new KML_Point();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<LineString",11)) {
+		kobj=(KML_Object*)new KML_LineString();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<LinearRing",11)) {
+		kobj=(KML_Object*)new KML_LinearRing();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<Polygon", 8)) {
+		kobj=(KML_Object*)new KML_Polygon();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<MultiGeometry",14)) {
+		kobj=(KML_Object*)new KML_MultiGeometry();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+//	else if (!strncmp(kstr,"<IconStyle",10)) {
+//		kobj=(KML_Object*)new KML_IconStyle();
+//		kobj->Read(fid,kstr);
+//		kmlobj    ->AddObject((Object*)kobj);
+//	}
+
+//	else if (!strncmp(kstr,"<LabelStyle",11)) {
+//		kobj=(KML_Object*)new KML_LabelStyle();
+//		kobj->Read(fid,kstr);
+//		kmlobj    ->AddObject((Object*)kobj);
+//	}
+
+	else if (!strncmp(kstr,"<LineStyle",10)) {
+		kobj=(KML_Object*)new KML_LineStyle();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	else if (!strncmp(kstr,"<PolyStyle",10)) {
+		kobj=(KML_Object*)new KML_PolyStyle();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+//	else if (!strncmp(kstr,"<BalloonStyle",13)) {
+//		kobj=(KML_Object*)new KML_BalloonStyle();
+//		kobj->Read(fid,kstr);
+//		kmlobj    ->AddObject((Object*)kobj);
+//	}
+
+//	else if (!strncmp(kstr,"<ListStyle",10)) {
+//		kobj=(KML_Object*)new KML_ListStyle();
+//		kobj->Read(fid,kstr);
+//		kmlobj    ->AddObject((Object*)kobj);
+//	}
+
+	else if (!strncmp(kstr,"<",1)) {
+		_pprintLine_("KML_Object::Read -- Unrecognized opening tag " << kstr << ".");
+//		KMLFileTagSkip(kstr,
+//					   fid);
+		kobj=(KML_Object*)new KML_Unknown();
+		kobj->Read(fid,kstr);
+		kmlobj    ->AddObject((Object*)kobj);
+	}
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::WriteExp {{{*/
+void  KML_Object::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	;
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::AddAttrib {{{*/
+void  KML_Object::AddAttrib(const char* name,const char* value){
+
+	KML_Attribute* katt=NULL;
+
+	katt=new KML_Attribute();
+	katt->Alloc(name,value);
+	katt->Add(attrib);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::FindAttrib {{{*/
+void  KML_Object::FindAttrib(char** pvalue,char* name,char* deflt){
+
+	int   i;
+	KML_Attribute* katt=NULL;
+
+/*  loop over any attributes for the object  */
+
+	if (attrib->Size())
+		for (i=0; i<attrib->Size(); i++)
+			if (!strcmp(((KML_Attribute *)attrib->GetObjectByOffset(i))->name,name)) {
+				katt=(KML_Attribute *)attrib->GetObjectByOffset(i);
+				break;
+			}
+
+/*  if found, get the value; otherwise use the default  */
+
+	if (katt)
+		katt->Get(pvalue,deflt);
+	else {
+		*pvalue=xNew<char>(strlen(deflt)+1);
+		memcpy(*pvalue,deflt,(strlen(deflt)+1)*sizeof(char));
+	}
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::WriteAttrib {{{*/
+void  KML_Object::WriteAttrib(FILE* filout,const char* indent){
+
+//  attributes always written in keyword line of kml_object
+
+/*  loop over any attributes for the object  */
+
+	if (attrib->Size())
+		for (int i=0; i<attrib->Size(); i++)
+			((KML_Attribute *)attrib->GetObjectByOffset(i))->Write(filout,indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::AddCommnt {{{*/
+void  KML_Object::AddCommnt(int ncom,char** pcom){
+
+	int   i;
+	KML_Comment* kcom=NULL;
+
+	for (i=0; i<ncom; i++) {
+		kcom=new KML_Comment();
+		kcom->Alloc(pcom[i]);
+		kcom->Add(commnt);
+	}
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::AddCommnt {{{*/
+void  KML_Object::AddCommnt(char* value){
+
+	KML_Comment* kcom=NULL;
+
+	kcom=new KML_Comment();
+	kcom->Alloc(value);
+	kcom->Add(commnt);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::FindCommnt {{{*/
+void  KML_Object::FindCommnt(char** pvalue,int inum){
+
+	KML_Comment* kcom=NULL;
+
+/*  loop over any comments for the object  */
+
+	if (inum <= commnt->Size())
+		kcom=(KML_Comment *)commnt->GetObjectByOffset(inum-1);
+
+/*  if found, get the value; otherwise use the NULL  */
+
+	if (kcom)
+		kcom->Get(pvalue);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Object::WriteCommnt {{{*/
+void  KML_Object::WriteCommnt(FILE* filout,const char* indent){
+
+	int   i;
+
+//  comments always written after keyword line of kml_object
+
+/*  loop over any comments for the object  */
+
+	if (commnt->Size())
+		for (i=0; i<commnt->Size(); i++)
+			((KML_Comment *)commnt->GetObjectByOffset(i))->Write(filout,indent);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Object.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Object.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Object.h	(revision 15012)
@@ -0,0 +1,49 @@
+/*! \file KML_Object.h 
+ *  \brief: header file for kml_object abstract object
+ */
+
+#ifndef _KML_OBJECT_H_
+#define _KML_OBJECT_H_
+
+/*Headers:{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "../Object.h"
+class DataSet;
+/*}}}*/
+
+class KML_Object: public Object {
+
+	public:
+
+		DataSet* attrib;
+		DataSet* commnt;
+		DataSet* kmlobj;
+
+		/*KML_Object constructors, destructors {{{*/
+		KML_Object();
+		~KML_Object();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		virtual void  Echo();
+		virtual void  DeepEcho();
+		virtual void  DeepEcho(const char* indent);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+		/*virtual functions: */
+		virtual void  Write(FILE* fid,const char* indent)=0;
+		virtual void  Read(FILE* fid,char* kstr)=0;
+		virtual void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		virtual void  AddAttrib(const char* name,const char* value);
+		virtual void  FindAttrib(char** pvalue,char* name,char* deflt);
+		virtual void  WriteAttrib(FILE* fid,const char* indent);
+		virtual void  AddCommnt(int ncom,char** pcom);
+		virtual void  AddCommnt(char* value);
+		virtual void  FindCommnt(char** pvalue,int inum);
+		virtual void  WriteCommnt(FILE* fid,const char* indent);
+
+};
+#endif  /* _KML_OBJECT_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Overlay.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Overlay.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Overlay.cpp	(revision 15012)
@@ -0,0 +1,130 @@
+/*!\file KML_Overlay.cpp
+ * \brief: implementation of the kml_overlay abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Overlay::KML_Overlay(){{{*/
+KML_Overlay::KML_Overlay(){
+
+	strcpy(color     ,"ffffffff");
+	memcpy(color,"ffffffff",(strlen("ffffffff")+1)*sizeof(char));
+
+	draword   = 0;
+	icon      =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_Overlay::~KML_Overlay(){{{*/
+KML_Overlay::~KML_Overlay(){
+
+	if (icon) {
+		delete icon;
+		icon      =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Overlay::Echo {{{*/
+void  KML_Overlay::Echo(){
+
+	KML_Feature::Echo();
+	_pprintLine_("         color: \"" << color << "\"");
+	_pprintLine_("       draword: " << draword);
+	_pprintLine_("          icon: " << icon);
+}
+/*}}}*/
+/*FUNCTION KML_Overlay::DeepEcho {{{*/
+void  KML_Overlay::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Overlay::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Overlay::DeepEcho {{{*/
+void  KML_Overlay::DeepEcho(const char* indent){
+
+	char  indent2[81];
+	KML_Feature::DeepEcho(indent);
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	_pprintLine_(indent << "         color: " << color);
+	_pprintLine_(indent << "       draword: " << draword);
+	if (icon)
+		icon->DeepEcho(indent2);
+	else
+		_pprintLine_(indent << "          icon: " << icon);
+}
+/*}}}*/
+/*FUNCTION KML_Overlay::Write {{{*/
+void  KML_Overlay::Write(FILE* filout,const char* indent){
+
+	char  indent2[81];
+
+	KML_Feature::Write(filout,indent);
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+	if (color     && strlen(color))
+		fprintf(filout,"%s  <color>%s</color>\n",indent,color);
+	fprintf(filout,"%s  <drawOrder>%d</drawOrder>\n",indent,draword);
+	if (icon)
+		icon->Write(filout,indent2);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Overlay::Read {{{*/
+void  KML_Overlay::Read(FILE* fid,char* kstr){
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</Overlay", 9)) {
+		xDelete<char>(kstr);
+		return;
+	}
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_Overlay::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_Overlay::Read -- Unexpected field \"" << kstr << "\".\n");}
+
+	else if (!strcmp(kstr,"<color>"))
+		KMLFileTokenParse( color     ,NULL,KML_OVERLAY_COLOR_LENGTH,
+						  kstr,
+						  fid);
+	else if (!strcmp(kstr,"<drawOrder>"))
+		KMLFileTokenParse(&draword   ,
+						  kstr,
+						  fid);
+
+	else if (!strncmp(kstr,"<Icon", 5)) {
+		icon      =new KML_Icon();
+		icon      ->Read(fid,kstr);
+	}
+
+	else if (!strncmp(kstr,"<",1))
+		KML_Feature::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Overlay.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Overlay.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Overlay.h	(revision 15012)
@@ -0,0 +1,42 @@
+/*! \file KML_Overlay.h 
+ *  \brief: header file for kml_overlay abstract object
+ */
+
+#ifndef _KML_OVERLAY_H_
+#define _KML_OVERLAY_H_
+
+#define KML_OVERLAY_COLOR_LENGTH  8
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Feature.h"
+class KML_Icon;
+/*}}}*/
+
+class KML_Overlay: public KML_Feature {
+
+	public:
+
+		char  color[KML_OVERLAY_COLOR_LENGTH+1];
+		int   draword;
+		KML_Icon* icon;
+
+		/*KML_Overlay constructors, destructors {{{*/
+		KML_Overlay();
+		~KML_Overlay();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_OVERLAY_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Placemark.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Placemark.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Placemark.cpp	(revision 15012)
@@ -0,0 +1,205 @@
+/*!\file KML_Placemark.cpp
+ * \brief: implementation of the kml_placemark object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Placemark::KML_Placemark(){{{*/
+KML_Placemark::KML_Placemark(){
+
+	geometry  =new DataSet;
+
+}
+/*}}}*/
+/*FUNCTION KML_Placemark::~KML_Placemark(){{{*/
+KML_Placemark::~KML_Placemark(){
+
+	if (geometry) {
+		delete geometry;
+		geometry  =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Placemark::Echo {{{*/
+void  KML_Placemark::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Placemark:");
+	KML_Feature::Echo();
+
+	if(flag) _pprintLine_("      geometry: (size=" << geometry->Size() << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Placemark::DeepEcho {{{*/
+void  KML_Placemark::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Placemark::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Placemark::DeepEcho {{{*/
+void  KML_Placemark::DeepEcho(const char* indent){
+
+	int   i;
+	char  indent2[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Placemark:");
+	KML_Feature::DeepEcho(indent);
+
+/*  loop over the geometry elements for the placemark  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (geometry->Size())
+		for (i=0; i<geometry->Size(); i++) {
+			if(flag) _pprintLine_(indent << "      geometry: -------- begin [" << i << "] --------");
+			((KML_Geometry *)geometry->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "      geometry: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "      geometry: [empty]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Placemark::Write {{{*/
+void  KML_Placemark::Write(FILE* filout,const char* indent){
+
+	int   i;
+	char  indent2[81];
+
+	fprintf(filout,"%s<Placemark",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Feature::Write(filout,indent);
+
+/*  loop over the geometry elements for the placemark  */
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+	for (i=0; i<geometry->Size(); i++)
+		((KML_Geometry *)geometry->GetObjectByOffset(i))->Write(filout,indent2);
+
+	fprintf(filout,"%s</Placemark>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Placemark::Read {{{*/
+void  KML_Placemark::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+	KML_Object*  kobj;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Placemark",11)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Placemark::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Placemark::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strncmp(kstri,"<Point", 6)) {
+			kobj=(KML_Object*)new KML_Point();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<LineString",11)) {
+			kobj=(KML_Object*)new KML_LineString();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<LinearRing",11)) {
+			kobj=(KML_Object*)new KML_LinearRing();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<Polygon", 8)) {
+			kobj=(KML_Object*)new KML_Polygon();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<MultiGeometry",14)) {
+			kobj=(KML_Object*)new KML_MultiGeometry();
+			kobj->Read(fid,kstri);
+			geometry  ->AddObject((Object*)kobj);
+		}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Feature::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Placemark::WriteExp {{{*/
+void  KML_Placemark::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int   i;
+	char  nstr2[81];
+
+/*  loop over the geometry elements for the placemark  */
+
+	for (i=0; i<geometry->Size(); i++) {
+		if (strlen(nstr))
+			sprintf(nstr2,"%s %s",nstr,name);
+		else
+			sprintf(nstr2,"%s",name);
+
+		((KML_Object *)geometry->GetObjectByOffset(i))->WriteExp(fid,nstr2,sgn,cm,sp);
+	}
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Placemark.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Placemark.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Placemark.h	(revision 15012)
@@ -0,0 +1,40 @@
+/*! \file KML_Placemark.h 
+ *  \brief: header file for kml_placemark object
+ */
+
+#ifndef _KML_PLACEMARK_H_
+#define _KML_PLACEMARK_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Feature.h"
+class KML_Geometry;
+class DataSet;
+/*}}}*/
+
+class KML_Placemark: public KML_Feature {
+
+	public:
+
+		DataSet* geometry;
+
+		/*KML_Placemark constructors, destructors {{{*/
+		KML_Placemark();
+		~KML_Placemark();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_PLACEMARK_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Point.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Point.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Point.cpp	(revision 15012)
@@ -0,0 +1,194 @@
+/*!\file KML_Point.cpp
+ * \brief: implementation of the kml_point object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+#include "modules/Ll2xyx/Ll2xyx.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Point::KML_Point(){{{*/
+KML_Point::KML_Point(){
+
+	extrude   =false;
+	memcpy(altmode,"clampToGround",(strlen("clampToGround")+1)*sizeof(char));
+
+	coords[0] = 0.;
+	coords[1] = 0.;
+	coords[2] = 0.;
+
+}
+/*}}}*/
+/*FUNCTION KML_Point::~KML_Point(){{{*/
+KML_Point::~KML_Point(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Point::Echo {{{*/
+void  KML_Point::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Point:");
+	KML_Geometry::Echo();
+
+	if(flag) _pprintLine_("       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_("       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_("        coords: (" << coords[0] << "," << coords[1] << "," << coords[2] << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Point::DeepEcho {{{*/
+void  KML_Point::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Point::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Point::DeepEcho {{{*/
+void  KML_Point::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Point:");
+	KML_Geometry::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_(indent << "        coords: (" << coords[0] << "," << coords[1] << "," << coords[2] << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Point::Write {{{*/
+void  KML_Point::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<Point",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Geometry::Write(filout,indent);
+
+	fprintf(filout,"%s  <extrude>%d</extrude>\n",indent,(extrude ? 1 : 0));
+	fprintf(filout,"%s  <altitudeMode>%s</altitudeMode>\n",indent,altmode);
+	fprintf(filout,"%s  <coordinates>%0.16g,%0.16g,%0.16g</coordinates>\n",
+			indent,coords[0],coords[1],coords[2]);
+
+	fprintf(filout,"%s</Point>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Point::Read {{{*/
+void  KML_Point::Read(FILE* fid,char* kstr){
+
+	double*      pcoords=&coords[0];
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Point", 7)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Point::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Point::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<extrude>"))
+			KMLFileTokenParse(&extrude   , kstri, fid);
+		else if (!strcmp(kstri,"<altitudeMode>"))
+			KMLFileTokenParse( altmode   ,NULL,KML_POINT_ALTMODE_LENGTH, kstri, fid);
+		else if (!strcmp(kstri,"<coordinates>"))
+			KMLFileTokenParse(&pcoords   ,NULL,3, kstri, fid);
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Geometry::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Point::WriteExp {{{*/
+void  KML_Point::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int     i;
+	double  lat,lon,x,y;
+	char    nstr2[81];
+
+/*  extract latitude and longitude  */
+
+	lon=coords[0];
+	lat=coords[1];
+
+/*  convert latitude and longitude to x and y  */
+
+	if (sgn) {
+		Ll2xyx(&x,&y,&lat,&lon,1,sgn,cm,sp);
+	}
+	else {
+		memcpy(&x,&lon,1*sizeof(IssmDouble));
+		memcpy(&y,&lat,1*sizeof(IssmDouble));
+	}
+
+/*  write header  */
+
+	memcpy(nstr2,nstr,(strlen(nstr)+1)*sizeof(char));
+
+	for (i=0; i<strlen(nstr2); i++)
+		if ((nstr2[i] == ' ') || (nstr2[i] == '\t'))
+			nstr2[i]='_';
+	fprintf(fid,"## Name:%s\n",nstr2);
+	fprintf(fid,"## Icon:0\n");
+	fprintf(fid,"# Points Count	Value\n");
+    fprintf(fid,"%u	%s\n",1,"1.");
+	fprintf(fid,"# X pos	Y pos\n");
+
+/*  write vertex  */
+
+    fprintf(fid,"%lf\t%lf\n",x,y);
+
+/*  write blank line  */
+
+	fprintf(fid,"\n");
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Point.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Point.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Point.h	(revision 15012)
@@ -0,0 +1,42 @@
+/*! \file KML_Point.h 
+ *  \brief: header file for kml_point object
+ */
+
+#ifndef _KML_POINT_H_
+#define _KML_POINT_H_
+
+#define KML_POINT_ALTMODE_LENGTH    18
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Geometry.h"
+/*}}}*/
+
+class KML_Point: public KML_Geometry {
+
+	public:
+
+		bool  extrude;
+		char  altmode[KML_POINT_ALTMODE_LENGTH+1];
+		double coords[3];
+
+		/*KML_Point constructors, destructors {{{*/
+		KML_Point();
+		~KML_Point();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_POINT_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_PolyStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_PolyStyle.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_PolyStyle.cpp	(revision 15012)
@@ -0,0 +1,140 @@
+/*!\file KML_PolyStyle.cpp
+ * \brief: implementation of the kml_polystyle object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_PolyStyle::KML_PolyStyle(){{{*/
+KML_PolyStyle::KML_PolyStyle(){
+
+	fill      =true;
+	outline   =true;
+
+}
+/*}}}*/
+/*FUNCTION KML_PolyStyle::~KML_PolyStyle(){{{*/
+KML_PolyStyle::~KML_PolyStyle(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_PolyStyle::Echo {{{*/
+void  KML_PolyStyle::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_PolyStyle:");
+	KML_ColorStyle::Echo();
+
+	if(flag) _pprintLine_("          fill: " << fill);
+	if(flag) _pprintLine_("       outline: " << outline);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_PolyStyle::DeepEcho {{{*/
+void  KML_PolyStyle::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_PolyStyle::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_PolyStyle::DeepEcho {{{*/
+void  KML_PolyStyle::DeepEcho(const char* indent){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_PolyStyle:");
+	KML_ColorStyle::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "          fill: " << fill);
+	if(flag) _pprintLine_(indent << "       outline: " << outline);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_PolyStyle::Write {{{*/
+void  KML_PolyStyle::Write(FILE* filout,const char* indent){
+
+	fprintf(filout,"%s<PolyStyle",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_ColorStyle::Write(filout,indent);
+
+	fprintf(filout,"%s  <fill>%d</fill>\n",indent,fill);
+	fprintf(filout,"%s  <outline>%d</outline>\n",indent,outline);
+
+	fprintf(filout,"%s</PolyStyle>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_PolyStyle::Read {{{*/
+void  KML_PolyStyle::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</PolyStyle",11)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_PolyStyle::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_PolyStyle::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<fill>"))
+			KMLFileTokenParse(&fill      ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<outline>"))
+			KMLFileTokenParse(&outline   ,
+							  kstri,
+							  fid);
+
+		else if (!strncmp(kstri,"<",1))
+			KML_ColorStyle::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_PolyStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_PolyStyle.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_PolyStyle.h	(revision 15012)
@@ -0,0 +1,38 @@
+/*! \file KML_PolyStyle.h 
+ *  \brief: header file for kml_polystyle object
+ */
+
+#ifndef _KML_POLYSTYLE_H_
+#define _KML_POLYSTYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_ColorStyle.h"
+/*}}}*/
+
+class KML_PolyStyle: public KML_ColorStyle {
+
+	public:
+
+		int   fill;
+		int   outline;
+
+		/*KML_PolyStyle constructors, destructors {{{*/
+		KML_PolyStyle();
+		~KML_PolyStyle();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_POLYSTYLE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Polygon.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Polygon.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Polygon.cpp	(revision 15012)
@@ -0,0 +1,292 @@
+/*!\file KML_Polygon.cpp
+ * \brief: implementation of the kml_polygon object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Polygon::KML_Polygon(){{{*/
+KML_Polygon::KML_Polygon(){
+
+	extrude   =false;
+	tessellate=false;
+	memcpy(altmode,"clampToGround",(strlen("clampToGround")+1)*sizeof(char));
+
+	outer     =new DataSet;
+	inner     =new DataSet;
+
+}
+/*}}}*/
+/*FUNCTION KML_Polygon::~KML_Polygon(){{{*/
+KML_Polygon::~KML_Polygon(){
+
+	if (inner) {
+		delete inner;
+		inner     =NULL;
+	}
+
+	if (outer) {
+		delete outer;
+		outer     =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Polygon::Echo {{{*/
+void  KML_Polygon::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Polygon:");
+	KML_Geometry::Echo();
+
+	if(flag) _pprintLine_("       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_("    tessellate: " << (tessellate ? "true" : "false"));
+	if(flag) _pprintLine_("       altmode: \"" << altmode << "\"");
+	if(flag) _pprintLine_("         outer: (size=" << outer->Size() << ")");
+	if(flag) _pprintLine_("         inner: (size=" << inner->Size() << ")");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Polygon::DeepEcho {{{*/
+void  KML_Polygon::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Polygon::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Polygon::DeepEcho {{{*/
+void  KML_Polygon::DeepEcho(const char* indent){
+
+	int   i;
+	char  indent2[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Polygon:");
+	KML_Geometry::DeepEcho(indent);
+
+	if(flag) _pprintLine_(indent << "       extrude: " << (extrude ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "    tessellate: " << (tessellate ? "true" : "false"));
+	if(flag) _pprintLine_(indent << "       altmode: \"" << altmode << "\"");
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+	if (outer->Size())
+		for (i=0; i<outer->Size(); i++) {
+			if(flag) _pprintLine_(indent << "         outer: -------- begin [" << i << "] --------");
+			((KML_LinearRing *)outer->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "         outer: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "         outer: [empty]");
+
+	if (inner->Size())
+		for (i=0; i<inner->Size(); i++) {
+			if(flag) _pprintLine_(indent << "         inner: -------- begin [" << i << "] --------");
+			((KML_LinearRing *)inner->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "         inner: --------  end  [" << i << "] --------");
+		}
+	else
+		if(flag) _pprintLine_(indent << "         inner: [empty]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Polygon::Write {{{*/
+void  KML_Polygon::Write(FILE* filout,const char* indent){
+
+	int   i;
+	char  indent4[81];
+
+	fprintf(filout,"%s<Polygon",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_Geometry::Write(filout,indent);
+
+	fprintf(filout,"%s  <extrude>%d</extrude>\n",indent,(extrude ? 1 : 0));
+	fprintf(filout,"%s  <tessellate>%d</tessellate>\n",indent,(tessellate ? 1 : 0));
+	fprintf(filout,"%s  <altitudeMode>%s</altitudeMode>\n",indent,altmode);
+
+	memcpy(indent4,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent4,"    ");
+
+/*  check outer boundary for the polygon  */
+
+	fprintf(filout,"%s  <outerBoundaryIs>\n",indent);
+	if (outer->Size())
+		((KML_LinearRing *)outer->GetObjectByOffset(0))->Write(filout,indent4);
+	fprintf(filout,"%s  </outerBoundaryIs>\n",indent);
+
+/*  loop over any inner boundaries for the polygon  */
+
+	for (i=0; i<inner->Size(); i++) {
+		fprintf(filout,"%s  <innerBoundaryIs>\n",indent);
+		((KML_LinearRing *)inner->GetObjectByOffset(i))->Write(filout,indent4);
+		fprintf(filout,"%s  </innerBoundaryIs>\n",indent);
+	}
+
+	fprintf(filout,"%s</Polygon>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Polygon::Read {{{*/
+void  KML_Polygon::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	char*        kstrj;
+	int          ncom=0;
+	char**       pcom=NULL;
+	KML_Object*  kobj;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Polygon", 9)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Polygon::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Polygon::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strcmp(kstri,"<extrude>"))
+			KMLFileTokenParse(&extrude   ,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<tessellate>"))
+			KMLFileTokenParse(&tessellate,
+							  kstri,
+							  fid);
+		else if (!strcmp(kstri,"<altitudeMode>"))
+			KMLFileTokenParse( altmode   ,NULL,KML_POLYGON_ALTMODE_LENGTH,
+							  kstri,
+							  fid);
+
+		else if (!strcmp(kstri,"<outerBoundaryIs>"))
+
+/*  loop over and process fields within outer boundary  */
+
+			while (kstrj=KMLFileToken(fid,
+									  &ncom,&pcom)) {
+				if      (!strncmp(kstrj,"</outerBoundaryIs",17)) {
+					xDelete<char>(kstrj);
+					break;
+				}
+				else if (!strncmp(kstrj,"</",2))
+				  {_error_("KML_Polygon::Read -- Unexpected closing tag " << kstrj << ".\n");}
+				else if (strncmp(kstrj,"<",1))
+				  {_error_("KML_Polygon::Read -- Unexpected field \"" << kstrj << "\".\n");}
+
+				else if (!strncmp(kstrj,"<LinearRing",11)) {
+					kobj=(KML_Object*)new KML_LinearRing();
+					kobj->Read(fid,kstrj);
+					outer     ->AddObject((Object*)kobj);
+				}
+
+				else if (!strncmp(kstrj,"<",1))
+					KML_Geometry::Read(fid,kstrj);
+
+				xDelete<char>(kstrj);
+			}
+
+		else if (!strcmp(kstri,"<innerBoundaryIs>"))
+
+/*  loop over and process fields within inner boundaries  */
+
+			while (kstrj=KMLFileToken(fid,
+									  &ncom,&pcom)) {
+				if      (!strncmp(kstrj,"</innerBoundaryIs",17)) {
+					xDelete<char>(kstrj);
+					break;
+				}
+				else if (!strncmp(kstrj,"</",2))
+				  {_error_("KML_Polygon::Read -- Unexpected closing tag " << kstrj << ".\n");}
+				else if (strncmp(kstrj,"<",1))
+				  {_error_("KML_Polygon::Read -- Unexpected field \"" << kstrj << "\".\n");}
+
+				else if (!strncmp(kstrj,"<LinearRing",11)) {
+					kobj=(KML_Object*)new KML_LinearRing();
+					kobj->Read(fid,kstrj);
+					inner     ->AddObject((Object*)kobj);
+				}
+
+				else if (!strncmp(kstrj,"<",1))
+					KML_Geometry::Read(fid,kstrj);
+
+				xDelete<char>(kstrj);
+			}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Geometry::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Polygon::WriteExp {{{*/
+void  KML_Polygon::WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp){
+
+	int   i;
+	char  nstr2[81];
+
+/*  check outer boundary for the polygon  */
+
+	if (outer->Size()) {
+		if (strlen(nstr))
+			sprintf(nstr2,"%s (outer)",nstr);
+		else
+			sprintf(nstr2,"(outer)");
+
+		((KML_LinearRing *)outer->GetObjectByOffset(0))->WriteExp(fid,nstr2,sgn,cm,sp);
+	}
+
+/*  loop over any inner boundaries for the polygon  */
+
+	for (i=0; i<inner->Size(); i++) {
+		if (strlen(nstr))
+			sprintf(nstr2,"%s (inner %d of %d)",nstr,i+1,inner->Size());
+		else
+			sprintf(nstr2,"(inner %d of %d)",i+1,inner->Size());
+
+		((KML_LinearRing *)inner->GetObjectByOffset(i))->WriteExp(fid,nstr2,sgn,cm,sp);
+	}
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Polygon.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Polygon.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Polygon.h	(revision 15012)
@@ -0,0 +1,46 @@
+/*! \file KML_Polygon.h 
+ *  \brief: header file for kml_polygon object
+ */
+
+#ifndef _KML_POLYGON_H_
+#define _KML_POLYGON_H_
+
+#define KML_POLYGON_ALTMODE_LENGTH    18
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Geometry.h"
+class KML_LinearRing;
+class DataSet;
+/*}}}*/
+
+class KML_Polygon: public KML_Geometry {
+
+	public:
+
+		bool  extrude;
+		bool  tessellate;
+		char  altmode[KML_POLYGON_ALTMODE_LENGTH+1];
+		DataSet* outer;
+		DataSet* inner;
+
+		/*KML_Polygon constructors, destructors {{{*/
+		KML_Polygon();
+		~KML_Polygon();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		void  WriteExp(FILE* fid,const char* nstr,int sgn,double cm,double sp);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_POLYGON_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Style.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Style.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Style.cpp	(revision 15012)
@@ -0,0 +1,234 @@
+/*!\file KML_Style.cpp
+ * \brief: implementation of the kml_style object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Style::KML_Style(){{{*/
+KML_Style::KML_Style(){
+
+	icon      =NULL;
+	label     =NULL;
+	line      =NULL;
+	poly      =NULL;
+	balloon   =NULL;
+	list      =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_Style::~KML_Style(){{{*/
+KML_Style::~KML_Style(){
+
+	if (list) {
+//		delete list;
+		list      =NULL;
+	}
+	if (balloon) {
+//		delete balloon;
+		balloon   =NULL;
+	}
+	if (poly) {
+		delete poly;
+		poly      =NULL;
+	}
+	if (line) {
+		delete line;
+		line      =NULL;
+	}
+	if (label) {
+//		delete label;
+		label     =NULL;
+	}
+	if (icon) {
+//		delete icon;
+		icon      =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Style::Echo {{{*/
+void  KML_Style::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Style:");
+	KML_StyleSelector::Echo();
+
+	if(flag) _pprintLine_("          icon: " << icon);
+	if(flag) _pprintLine_("         label: " << label);
+	if(flag) _pprintLine_("          line: " << line);
+	if(flag) _pprintLine_("          poly: " << poly);
+	if(flag) _pprintLine_("       balloon: " << balloon);
+	if(flag) _pprintLine_("          list: " << list);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Style::DeepEcho {{{*/
+void  KML_Style::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Style::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Style::DeepEcho {{{*/
+void  KML_Style::DeepEcho(const char* indent){
+
+	char  indent2[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Style:");
+	KML_StyleSelector::DeepEcho(indent);
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+	strcat(indent2,"  ");
+
+//	if (icon)
+//		icon->DeepEcho(indent2);
+//	else
+		if(flag) _pprintLine_(indent << "          icon: " << icon);
+//	if (label)
+//		label->DeepEcho(indent2);
+//	else
+		if(flag) _pprintLine_(indent << "         label: " << label);
+	if (line)
+		line->DeepEcho(indent2);
+	else
+		if(flag) _pprintLine_(indent << "          line: " << line);
+	if (poly)
+		poly->DeepEcho(indent2);
+	else
+		if(flag) _pprintLine_(indent << "          poly: " << poly);
+//	if (balloon)
+//		balloon->DeepEcho(indent2);
+//	else
+		if(flag) _pprintLine_(indent << "       balloon: " << balloon);
+//	if (list)
+//		list->DeepEcho(indent2);
+//	else
+		if(flag) _pprintLine_(indent << "          list: " << list);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Style::Write {{{*/
+void  KML_Style::Write(FILE* filout,const char* indent){
+
+	char  indent2[81];
+
+	fprintf(filout,"%s<Style",indent);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	KML_StyleSelector::Write(filout,indent);
+
+	memcpy(indent2,indent,(strlen(indent)+1)*sizeof(char));
+
+	strcat(indent2,"  ");
+
+//	if (icon)
+//		icon->Write(filout,indent2);
+//	if (label)
+//		label->Write(filout,indent2);
+	if (line)
+		line->Write(filout,indent2);
+	if (poly)
+		poly->Write(filout,indent2);
+//	if (balloon)
+//		balloon->Write(filout,indent2);
+//	if (list)
+//		list->Write(filout,indent2);
+
+	fprintf(filout,"%s</Style>\n",indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Style::Read {{{*/
+void  KML_Style::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	int          ncom=0;
+	char**       pcom=NULL;
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+		if      (!strncmp(kstri,"</Style", 7)) {
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Style::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error_("KML_Style::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+//		else if (!strncmp(kstri,"<IconStyle",10)) {
+//			icon      =new KML_IconStyle();
+//			icon      ->Read(fid,kstri);
+//		}
+
+//		else if (!strncmp(kstri,"<LabelStyle",11)) {
+//			label     =new KML_LabelStyle();
+//			label     ->Read(fid,kstri);
+//		}
+
+		else if (!strncmp(kstri,"<LineStyle",10)) {
+			line      =new KML_LineStyle();
+			line      ->Read(fid,kstri);
+		}
+
+		else if (!strncmp(kstri,"<PolyStyle",10)) {
+			poly      =new KML_PolyStyle();
+			poly      ->Read(fid,kstri);
+		}
+
+//		else if (!strncmp(kstri,"<BalloonStyle",13)) {
+//			balloon   =new KML_BalloonStyle();
+//			balloon   ->Read(fid,kstri);
+//		}
+
+//		else if (!strncmp(kstri,"<ListStyle",10)) {
+//			list      =new KML_ListStyle();
+//			list      ->Read(fid,kstri);
+//		}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_StyleSelector::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Style.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Style.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Style.h	(revision 15012)
@@ -0,0 +1,44 @@
+/*! \file KML_Style.h 
+ *  \brief: header file for kml_style object
+ */
+
+#ifndef _KML_STYLE_H_
+#define _KML_STYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_StyleSelector.h"
+class KML_LineStyle;
+class KML_PolyStyle;
+/*}}}*/
+
+class KML_Style: public KML_StyleSelector {
+
+	public:
+
+		void* icon;
+		void* label;
+		KML_LineStyle* line;
+		KML_PolyStyle* poly;
+		void* balloon;
+		void* list;
+
+		/*KML_Style constructors, destructors {{{*/
+		KML_Style();
+		~KML_Style();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_STYLE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_StyleSelector.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_StyleSelector.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_StyleSelector.cpp	(revision 15012)
@@ -0,0 +1,85 @@
+/*!\file KML_StyleSelector.cpp
+ * \brief: implementation of the kml_styleselector abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_StyleSelector::KML_StyleSelector(){{{*/
+KML_StyleSelector::KML_StyleSelector(){
+
+	;
+
+}
+/*}}}*/
+/*FUNCTION KML_StyleSelector::~KML_StyleSelector(){{{*/
+KML_StyleSelector::~KML_StyleSelector(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_StyleSelector::Echo {{{*/
+void  KML_StyleSelector::Echo(){
+
+	KML_Object::Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_StyleSelector::DeepEcho {{{*/
+void  KML_StyleSelector::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_StyleSelector::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_StyleSelector::DeepEcho {{{*/
+void  KML_StyleSelector::DeepEcho(const char* indent){
+
+	KML_Object::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_StyleSelector::Write {{{*/
+void  KML_StyleSelector::Write(FILE* filout,const char* indent){
+
+	KML_Object::Write(filout,indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_StyleSelector::Read {{{*/
+void  KML_StyleSelector::Read(FILE* fid,char* kstr){
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</StyleSelector",15))
+		return;
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_StyleSelector::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_StyleSelector::Read -- Unexpected field \"" << kstr << "\".\n");}
+
+	else if (!strncmp(kstr,"<",1))
+		KML_Object::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_StyleSelector.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_StyleSelector.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_StyleSelector.h	(revision 15012)
@@ -0,0 +1,35 @@
+/*! \file KML_StyleSelector.h 
+ *  \brief: header file for kml_styleselector abstract object
+ */
+
+#ifndef _KML_STYLESELECTOR_H_
+#define _KML_STYLESELECTOR_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+/*}}}*/
+
+class KML_StyleSelector: public KML_Object {
+
+	public:
+
+		/*KML_StyleSelector constructors, destructors {{{*/
+		KML_StyleSelector();
+		~KML_StyleSelector();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_STYLESELECTOR_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_SubStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_SubStyle.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_SubStyle.cpp	(revision 15012)
@@ -0,0 +1,85 @@
+/*!\file KML_SubStyle.cpp
+ * \brief: implementation of the kml_substyle abstract object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_SubStyle::KML_SubStyle(){{{*/
+KML_SubStyle::KML_SubStyle(){
+
+	;
+
+}
+/*}}}*/
+/*FUNCTION KML_SubStyle::~KML_SubStyle(){{{*/
+KML_SubStyle::~KML_SubStyle(){
+
+	;
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_SubStyle::Echo {{{*/
+void  KML_SubStyle::Echo(){
+
+	KML_Object::Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_SubStyle::DeepEcho {{{*/
+void  KML_SubStyle::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_SubStyle::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_SubStyle::DeepEcho {{{*/
+void  KML_SubStyle::DeepEcho(const char* indent){
+
+	KML_Object::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_SubStyle::Write {{{*/
+void  KML_SubStyle::Write(FILE* filout,const char* indent){
+
+	KML_Object::Write(filout,indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_SubStyle::Read {{{*/
+void  KML_SubStyle::Read(FILE* fid,char* kstr){
+
+/*  process field within opening and closing tags  */
+
+	if      (!strncmp(kstr,"</SubStyle",10))
+		return;
+	else if (!strncmp(kstr,"</",2))
+	  {_error_("KML_SubStyle::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error_("KML_SubStyle::Read -- Unexpected field \"" << kstr << "\".\n");}
+
+	else if (!strncmp(kstr,"<",1))
+		KML_Object::Read(fid,kstr);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_SubStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_SubStyle.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_SubStyle.h	(revision 15012)
@@ -0,0 +1,35 @@
+/*! \file KML_SubStyle.h 
+ *  \brief: header file for kml_substyle abstract object
+ */
+
+#ifndef _KML_SUBSTYLE_H_
+#define _KML_SUBSTYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+/*}}}*/
+
+class KML_SubStyle: public KML_Object {
+
+	public:
+
+		/*KML_SubStyle constructors, destructors {{{*/
+		KML_SubStyle();
+		~KML_SubStyle();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_SUBSTYLE_H */
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Unknown.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Unknown.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Unknown.cpp	(revision 15012)
@@ -0,0 +1,190 @@
+/*!\file KML_Unknown.cpp
+ * \brief: implementation of the kml_unknown object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION KML_Unknown::KML_Unknown(){{{*/
+KML_Unknown::KML_Unknown(){
+
+	name      =NULL;
+	value     =NULL;
+
+}
+/*}}}*/
+/*FUNCTION KML_Unknown::~KML_Unknown(){{{*/
+KML_Unknown::~KML_Unknown(){
+
+	if (name      ) xDelete<char>(name);
+	if (value     ) xDelete<char>(value);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION KML_Unknown::Echo {{{*/
+void  KML_Unknown::Echo(){
+
+	bool  flag=true;
+
+	if(flag) _pprintLine_("KML_Unknown " << name << ":");
+	KML_Object::Echo();
+
+	if (value     )
+		if(flag) _pprintLine_("         value: \"" << value << "\"");
+    else
+        if(flag) _pprintLine_("         value: [none]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Unknown::DeepEcho {{{*/
+void  KML_Unknown::DeepEcho(){
+
+	char  indent[81]="";
+
+	KML_Unknown::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Unknown::DeepEcho {{{*/
+void  KML_Unknown::DeepEcho(const char* indent){
+
+	char*        valuei;
+	char*        vtoken;
+	char         nl[]={'\n','\0'};
+	bool         flag=true;
+
+	if(flag) _pprintLine_(indent << "KML_Unknown " << name << ":");
+	KML_Object::DeepEcho(indent);
+
+	if (value     ) {
+		valuei=xNew<char>(strlen(value)+1);
+		memcpy(valuei,value,(strlen(value)+1)*sizeof(char)); 
+
+		vtoken=strtok(valuei,nl);
+		if(flag) _pprintString_(indent << "         value: \"" << vtoken);
+
+		while (vtoken=strtok(NULL,nl))
+			if(flag) _pprintString_("\n" << indent << "                 " << vtoken);
+		if(flag) _pprintLine_("\"");
+
+		xDelete<char>(valuei);
+	}
+    else
+        if(flag) _pprintLine_(indent << "         value: [none]");
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Unknown::Write {{{*/
+void  KML_Unknown::Write(FILE* filout,const char* indent){
+
+	char*        valuei;
+	char*        vtoken;
+	char         nl[]={'\n','\0'};
+
+	fprintf(filout,"%s<%s",indent,name);
+	WriteAttrib(filout," ");
+	fprintf(filout,">\n");
+	WriteCommnt(filout,indent);
+
+	if (value     ) {
+		valuei=xNew<char>(strlen(value)+1);
+		memcpy(valuei,value,(strlen(value)+1)*sizeof(char)); 
+
+		vtoken=strtok(valuei,nl);
+		fprintf(filout,"%s  %s\n",indent,vtoken);
+
+		while (vtoken=strtok(NULL,nl))
+			fprintf(filout,"%s  %s\n",indent,vtoken);
+
+		xDelete<char>(valuei);
+	}
+
+	KML_Object::Write(filout,indent);
+
+	fprintf(filout,"%s</%s>\n",indent,name);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION KML_Unknown::Read {{{*/
+void  KML_Unknown::Read(FILE* fid,char* kstr){
+
+	char*        kstri;
+	char*        value2=NULL;
+	int          ncom=0;
+	char**       pcom=NULL;
+	char         nl[]={'\n','\0'};
+
+/*  get object name  */
+
+	name=KMLFileTagName(NULL,
+						kstr);
+//	_pprintLine_("KML_Unknown::Read -- opening name=" << name << ".");
+
+/*  get object attributes and check for solo tag  */
+
+	if (KMLFileTagAttrib(this,
+						 kstr))
+		return;
+
+/*  loop over and process fields within opening and closing tags  */
+
+	while (kstri=KMLFileToken(fid,
+							  &ncom,&pcom)) {
+//		_pprintLine_("KML_Unknown::Read -- kstri=" << kstri << ".");
+		if      (!strncmp(&kstri[0],"</", 2) &&
+				 !strncmp(&kstri[2],name,strlen(name))) {
+//			_pprintLine_("KML_Unknown::Read -- closing name=" << name << ".");
+			xDelete<char>(kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error_("KML_Unknown::Read -- Unexpected closing tag " << kstri << ".\n");}
+
+		else if (strncmp(kstri,"<",1)) {
+			if (value) {
+				value2=xNew<char>(strlen(value)+1+strlen(kstri)+1);
+				memcpy(value2,value,(strlen(value)+1)*sizeof(char));
+				xDelete<char>(value);
+				value=value2;
+				value2=NULL;
+//				value=(char *) xrealloc(value,(strlen(value)+1+strlen(kstri)+1)*sizeof(char));
+				strcat(value,nl);
+				strcat(value,kstri);
+			}
+			else {
+				value=xNew<char>(strlen(kstri)+1);
+				memcpy(value,kstri,(strlen(kstri)+1)*sizeof(char));
+			}
+		}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Object::Read(fid,kstri);
+
+		xDelete<char>(kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xDelete<char>(pcom[ncom-1]);
+	xDelete<char*>(pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/KML/KML_Unknown.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/KML/KML_Unknown.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/KML/KML_Unknown.h	(revision 15012)
@@ -0,0 +1,38 @@
+/*! \file KML_Unknown.h 
+ *  \brief: header file for kml_unknown object
+ */
+
+#ifndef _KML_UNKNOWN_H_
+#define _KML_UNKNOWN_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "./KML_Object.h"
+/*}}}*/
+
+class KML_Unknown: public KML_Object {
+
+	public:
+
+		char* name;
+		char* value;
+
+		/*KML_Unknown constructors, destructors {{{*/
+		KML_Unknown();
+		~KML_Unknown();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(const char* indent);
+		void  Write(FILE* fid,const char* indent);
+		void  Read(FILE* fid,char* kstr);
+		int   Id(){_error_("Not implemented yet.");};
+		int   ObjectEnum(){_error_("Not implemented yet.");};
+		Object* copy(){_error_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_UNKNOWN_H */
Index: /issm/trunk-jpl/src/c/classes/Loads/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,15 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Loads)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Loads/Friction.cpp
+                 $ENV{ISSM_DIR}/src/c/classes/objects/Loads/Icefront.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/Loads/Numericalflux.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/Loads/Pengrid.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/Loads/Penpair.cpp PARENT_SCOPE)
+# }}}
+# RIFTS_SOURCES {{{
+set(RIFTS_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Loads/Riftfront.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Loads/Friction.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Friction.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Friction.cpp	(revision 15012)
@@ -0,0 +1,327 @@
+/*!\file Friction.c
+ * \brief: implementation of the Friction object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/	
+
+/*Constructors/destructors*/
+/*FUNCTION Friction::Friction() {{{*/
+Friction::Friction(){
+	this->element_type=NULL;
+	this->inputs=NULL;
+	this->matpar=NULL;
+}
+/*}}}*/
+/*FUNCTION Friction::Friction(const char* element_type, Inputs* inputs,Matpar* matpar,int analysis_type){{{*/
+Friction::Friction(const char* element_type_in,Inputs* inputs_in,Matpar* matpar_in, int in_analysis_type){
+
+	this->analysis_type=in_analysis_type;
+	this->inputs=inputs_in;
+	this->element_type=xNew<char>(strlen(element_type_in)+1);
+	xMemCpy<char>(this->element_type,element_type_in,(strlen(element_type_in)+1));
+
+	this->matpar=matpar_in;
+}
+/*}}}*/
+/*FUNCTION Friction::~Friction() {{{*/
+Friction::~Friction(){
+	xDelete<char>(element_type);
+}
+/*}}}*/
+
+/*methods: */
+/*FUNCTION Friction::Echo {{{*/
+void Friction::Echo(void){
+	_printLine_("Friction:");
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	_printLine_("   element_type: " << this->element_type);
+	inputs->Echo();
+	matpar->Echo();
+}
+/*}}}*/
+/*FUNCTION Friction::GetAlpha2(IssmDouble* palpha2, GaussTria* gauss,int vxenum,int vyenum,int vzenum){{{*/
+void Friction::GetAlpha2(IssmDouble* palpha2, GaussTria* gauss,int vxenum,int vyenum,int vzenum){
+
+	/*This routine calculates the basal friction coefficient 
+	  alpha2= drag^2 * Neff ^r * vel ^s, with Neff=rho_ice*g*thickness+rho_ice*g*bed, r=q/p and s=1/p**/
+
+	/*diverse: */
+	IssmDouble  r,s;
+	IssmDouble  drag_p, drag_q;
+	IssmDouble  gravity,rho_ice,rho_water;
+	IssmDouble  Neff;
+	IssmDouble  thickness,bed;
+	IssmDouble  vx,vy,vz,vmag;
+	IssmDouble  drag_coefficient;
+	IssmDouble  alpha2;
+
+	/*Recover parameters: */
+	inputs->GetInputValue(&drag_p,FrictionPEnum);
+	inputs->GetInputValue(&drag_q,FrictionQEnum);
+	this->GetInputValue(&thickness, gauss,ThicknessEnum);
+	this->GetInputValue(&bed, gauss,BedEnum);
+	this->GetInputValue(&drag_coefficient, gauss,FrictionCoefficientEnum);
+
+	/*Get material parameters: */
+	gravity=matpar->GetG();
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+
+	//compute r and q coefficients: */
+	r=drag_q/drag_p;
+	s=1./drag_p;
+
+	//From bed and thickness, compute effective pressure when drag is viscous:
+	Neff=gravity*(rho_ice*thickness+rho_water*bed);
+
+	/*If effective pressure becomes negative, sliding becomes unstable (Paterson 4th edition p 148). This is because 
+	  the water pressure is so high, the ice sheet elevates over its ice bumps and slides. But the limit behaviour 
+	  for friction should be an ice shelf sliding (no basal drag). Therefore, for any effective pressure Neff < 0, we should 
+	  replace it by Neff=0 (ie, equival it to an ice shelf)*/
+	if (Neff<0)Neff=0;
+
+	if(strcmp(element_type,"2d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2));
+	}
+	else if (strcmp(element_type,"3d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		this->GetInputValue(&vz, gauss,vzenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2)+pow(vz,2));
+	}
+	else _error_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+        if(vmag==0 && (s-1)<0) _error_("velocity is 0 and (s-1)=" << (s-1) << "<0, alpha_complement is Inf");
+
+	alpha2=pow(drag_coefficient,2)*pow(Neff,r)*pow(vmag,(s-1));
+	_assert_(!xIsNan<IssmDouble>(alpha2));
+
+	/*Assign output pointers:*/
+	*palpha2=alpha2;
+}
+/*}}}*/
+/*FUNCTION Friction::GetAlpha2(IssmDouble* palpha2, GaussPenta* gauss,int vxenum,int vyenum,int vzenum){{{*/
+void Friction::GetAlpha2(IssmDouble* palpha2, GaussPenta* gauss,int vxenum,int vyenum,int vzenum){
+
+	/*This routine calculates the basal friction coefficient 
+	  alpha2= drag^2 * Neff ^r * vel ^s, with Neff=rho_ice*g*thickness+rho_ice*g*bed, r=q/p and s=1/p**/
+
+	/*diverse: */
+	IssmDouble  r,s;
+	IssmDouble  drag_p, drag_q;
+	IssmDouble  gravity,rho_ice,rho_water;
+	IssmDouble  Neff;
+	IssmDouble  thickness,bed;
+	IssmDouble  vx,vy,vz,vmag;
+	IssmDouble  drag_coefficient;
+	IssmDouble  alpha2;
+
+	/*Recover parameters: */
+	inputs->GetInputValue(&drag_p,FrictionPEnum);
+	inputs->GetInputValue(&drag_q,FrictionQEnum);
+	this->GetInputValue(&thickness, gauss,ThicknessEnum);
+	this->GetInputValue(&bed, gauss,BedEnum);
+	this->GetInputValue(&drag_coefficient, gauss,FrictionCoefficientEnum);
+
+	/*Get material parameters: */
+	gravity=matpar->GetG();
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+
+	//compute r and q coefficients: */
+	r=drag_q/drag_p;
+	s=1./drag_p;
+
+	//From bed and thickness, compute effective pressure when drag is viscous:
+	Neff=gravity*(rho_ice*thickness+rho_water*bed);
+
+	/*If effective pressure becomes negative, sliding becomes unstable (Paterson 4th edition p 148). This is because 
+	  the water pressure is so high, the ice sheet elevates over its ice bumps and slides. But the limit behaviour 
+	  for friction should be an ice shelf sliding (no basal drag). Therefore, for any effective pressure Neff < 0, we should 
+	  replace it by Neff=0 (ie, equival it to an ice shelf)*/
+	if (Neff<0)Neff=0;
+
+	if(strcmp(element_type,"2d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2));
+	}
+	else if (strcmp(element_type,"3d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		this->GetInputValue(&vz, gauss,vzenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2)+pow(vz,2));
+	}
+	else _error_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+	if(vmag==0 && (s-1)<0) _error_("velocity is 0 and (s-1)=" << (s-1) << "<0, alpha_complement is Inf");
+
+	alpha2=pow(drag_coefficient,2)*pow(Neff,r)*pow(vmag,(s-1));
+	_assert_(!xIsNan<IssmDouble>(alpha2));
+
+	/*Assign output pointers:*/
+	*palpha2=alpha2;
+}
+/*}}}*/
+/*FUNCTION Friction::GetAlphaComplement(IssmDouble* palpha_complement, GaussTria* gauss,int vxenum,int vyenum,int vzenum) {{{*/
+void Friction::GetAlphaComplement(IssmDouble* palpha_complement, GaussTria* gauss,int vxenum,int vyenum,int vzenum){
+
+	/* FrictionGetAlpha2 computes alpha2= drag^2 * Neff ^r * vel ^s, with Neff=rho_ice*g*thickness+rho_ice*g*bed, r=q/p and s=1/p. 
+	 * FrictionGetAlphaComplement is used in control methods on drag, and it computes: 
+	 * alpha_complement= Neff ^r * vel ^s*/
+
+	/*diverse: */
+	IssmDouble  r,s;
+	IssmDouble  vx,vy,vz,vmag;
+	IssmDouble  drag_p,drag_q;
+	IssmDouble  Neff;
+	IssmDouble  drag_coefficient;
+	IssmDouble  bed,thickness;
+	IssmDouble  gravity,rho_ice,rho_water;
+	IssmDouble  alpha_complement;
+
+	/*Recover parameters: */
+	inputs->GetInputValue(&drag_p,FrictionPEnum);
+	inputs->GetInputValue(&drag_q,FrictionQEnum);
+	this->GetInputValue(&thickness, gauss,ThicknessEnum);
+	this->GetInputValue(&bed, gauss,BedEnum);
+	this->GetInputValue(&drag_coefficient, gauss,FrictionCoefficientEnum);
+
+	/*Get material parameters: */
+	gravity=matpar->GetG();
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+
+	//compute r and q coefficients: */
+	r=drag_q/drag_p;
+	s=1./drag_p;
+
+	//From bed and thickness, compute effective pressure when drag is viscous:
+	Neff=gravity*(rho_ice*thickness+rho_water*bed);
+
+	/*If effective pressure becomes negative, sliding becomes unstable (Paterson 4th edition p 148). This is because 
+	  the water pressure is so high, the ice sheet elevates over its ice bumps and slides. But the limit behaviour 
+	  for friction should be an ice shelf sliding (no basal drag). Therefore, for any effective pressure Neff < 0, we should 
+	  replace it by Neff=0 (ie, equival it to an ice shelf)*/
+	if (Neff<0)Neff=0;
+
+	//We need the velocity magnitude to evaluate the basal stress:
+	if(strcmp(element_type,"2d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2));
+	}
+	else if (strcmp(element_type,"3d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		this->GetInputValue(&vz, gauss,vzenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2)+pow(vz,2));
+	}
+	else _error_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+	if(vmag==0 && (s-1)<0) _error_("velocity is 0 and (s-1)=" << (s-1) << "<0, alpha_complement is Inf");
+
+	alpha_complement=pow(Neff,r)*pow(vmag,(s-1));            _assert_(!xIsNan<IssmDouble>(alpha_complement));
+
+	/*Assign output pointers:*/
+	*palpha_complement=alpha_complement;
+}
+/*}}}*/
+/*FUNCTION Friction::GetAlphaComplement(IssmDouble* palpha_complement, GaussPenta* gauss,int vxenum,int vyenum,int vzenum) {{{*/
+void Friction::GetAlphaComplement(IssmDouble* palpha_complement, GaussPenta* gauss,int vxenum,int vyenum,int vzenum){
+
+	/* FrictionGetAlpha2 computes alpha2= drag^2 * Neff ^r * vel ^s, with Neff=rho_ice*g*thickness+rho_ice*g*bed, r=q/p and s=1/p. 
+	 * FrictionGetAlphaComplement is used in control methods on drag, and it computes: 
+	 * alpha_complement= Neff ^r * vel ^s*/
+
+	/*diverse: */
+	IssmDouble  r,s;
+	IssmDouble  vx,vy,vz,vmag;
+	IssmDouble  drag_p,drag_q;
+	IssmDouble  Neff;
+	IssmDouble  drag_coefficient;
+	IssmDouble  bed,thickness;
+	IssmDouble  gravity,rho_ice,rho_water;
+	IssmDouble  alpha_complement;
+
+	/*Recover parameters: */
+	inputs->GetInputValue(&drag_p,FrictionPEnum);
+	inputs->GetInputValue(&drag_q,FrictionQEnum);
+	this->GetInputValue(&thickness, gauss,ThicknessEnum);
+	this->GetInputValue(&bed, gauss,BedEnum);
+	this->GetInputValue(&drag_coefficient, gauss,FrictionCoefficientEnum);
+
+	/*Get material parameters: */
+	gravity=matpar->GetG();
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+
+	//compute r and q coefficients: */
+	r=drag_q/drag_p;
+	s=1./drag_p;
+
+	//From bed and thickness, compute effective pressure when drag is viscous:
+	Neff=gravity*(rho_ice*thickness+rho_water*bed);
+
+	/*If effective pressure becomes negative, sliding becomes unstable (Paterson 4th edition p 148). This is because 
+	  the water pressure is so high, the ice sheet elevates over its ice bumps and slides. But the limit behaviour 
+	  for friction should be an ice shelf sliding (no basal drag). Therefore, for any effective pressure Neff < 0, we should 
+	  replace it by Neff=0 (ie, equival it to an ice shelf)*/
+	if (Neff<0)Neff=0;
+
+	//We need the velocity magnitude to evaluate the basal stress:
+	if(strcmp(element_type,"2d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2));
+	}
+	else if (strcmp(element_type,"3d")==0){
+		this->GetInputValue(&vx, gauss,vxenum);
+		this->GetInputValue(&vy, gauss,vyenum);
+		this->GetInputValue(&vz, gauss,vzenum);
+		vmag=sqrt(pow(vx,2)+pow(vy,2)+pow(vz,2));
+	}
+	else _error_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+	if(vmag==0 && (s-1)<0) _error_("velocity is 0 and (s-1)=" << (s-1) << "<0, alpha_complement is Inf");
+
+	alpha_complement=pow(Neff,r)*pow(vmag,(s-1));            _assert_(!xIsNan<IssmDouble>(alpha_complement));
+
+	/*Assign output pointers:*/
+	*palpha_complement=alpha_complement;
+}
+/*}}}*/
+/*FUNCTION Friction::GetInputValue{{{*/
+void Friction::GetInputValue(IssmDouble* pvalue,GaussTria* gauss,int enum_type){
+
+	Input* input=inputs->GetInput(enum_type);
+	if(!input) _error_("input " << EnumToStringx(enum_type) << " not found");
+	input->GetInputValue(pvalue,gauss);
+
+}
+/*}}}*/
+/*FUNCTION Friction::GetInputValue{{{*/
+void Friction::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,int enum_type){
+
+	Input* input=inputs->GetInput(enum_type);
+	if(!input) _error_("input " << EnumToStringx(enum_type) << " not found");
+	input->GetInputValue(pvalue,gauss);
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Friction.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Friction.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Friction.h	(revision 15012)
@@ -0,0 +1,40 @@
+/*!\file Friction.h
+ * \brief: header file for friction object
+ */
+
+#ifndef _FRICTION_H_
+#define _FRICTION_H_
+
+/*Headers:*/
+/*{{{*/
+class Inputs;
+class Matpar;
+class GaussPenta;
+class GaussTria;
+/*}}}*/
+
+class Friction{
+
+	public:
+		int analysis_type;
+
+		char* element_type;
+		Inputs* inputs;
+		Matpar* matpar;
+
+		/*methods: */
+		Friction();
+		Friction(const char* element_type, Inputs* inputs,Matpar* matpar, int analysis_type);
+		~Friction();
+
+		void  Echo(void);
+		void  GetAlpha2(IssmDouble* palpha2, GaussTria* gauss,int vxenum,int vyenum,int vzenum);
+		void  GetAlpha2(IssmDouble* palpha2, GaussPenta* gauss,int vxenum,int vyenum,int vzenum);
+		void  GetAlphaComplement(IssmDouble* alpha_complement, GaussTria* gauss,int vxenum,int vyenum,int vzenum);
+		void  GetAlphaComplement(IssmDouble* alpha_complement, GaussPenta* gauss,int vxenum,int vyenum,int vzenum);
+		void  GetInputValue(IssmDouble* pvalue,GaussTria* gauss,int enum_type);
+		void  GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,int enum_type);
+
+};
+
+#endif  /* _FRICTION_H_ */
Index: /issm/trunk-jpl/src/c/classes/Loads/Icefront.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Icefront.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Icefront.cpp	(revision 15012)
@@ -0,0 +1,850 @@
+/*!\file Icefront.c
+ * \brief: implementation of the Icefront object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/	
+
+/*Load macros*/
+#define NUMVERTICESSEG 2
+#define NUMVERTICESQUA 4
+
+/*Icefront constructors and destructor*/
+/*FUNCTION Icefront::Icefront() {{{*/
+Icefront::Icefront(){
+
+	this->inputs=NULL;
+	this->parameters=NULL;
+
+	this->hnodes=NULL;
+	this->nodes= NULL;
+	this->hvertices=NULL;
+	this->vertices= NULL;
+	this->helement=NULL;
+	this->element= NULL;
+	this->hmatpar=NULL;
+	this->matpar= NULL;
+}
+/*}}}*/
+/*FUNCTION Icefront::Icefront(int id, int i, IoModel* iomodel,int analysis_type) {{{*/
+Icefront::Icefront(int icefront_id,int i, IoModel* iomodel,int in_icefront_type, int in_analysis_type){
+
+	int segment_width;
+	int element;
+	int num_nodes; 
+	int dim;
+	int numberofelements;
+
+	/*icefront constructor data: */
+	int  icefront_eid;
+	int  icefront_mparid;
+	int  icefront_node_ids[NUMVERTICESQUA]; //initialize with largest size
+	int  icefront_vertex_ids[NUMVERTICESQUA]; //initialize with largest size
+	int  icefront_fill;
+
+	/*find parameters: */
+	iomodel->Constant(&dim,MeshDimensionEnum);
+	iomodel->Constant(&numberofelements,MeshNumberofelementsEnum);
+
+	/*First, retrieve element index and element type: */
+	if (dim==2){
+		segment_width=4;
+	}
+	else{
+		segment_width=6;
+	}
+	_assert_(iomodel->Data(DiagnosticIcefrontEnum));
+	element=reCast<int,IssmDouble>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+segment_width-2)-1); //element is in the penultimate column (node1 node2 ... elem fill)
+
+	/*Build ids for hook constructors: */
+	icefront_eid=reCast<int,IssmDouble>( *(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+segment_width-2)); //matlab indexing
+	icefront_mparid=numberofelements+1; //matlab indexing
+
+	if (in_icefront_type==MacAyeal2dIceFrontEnum || in_icefront_type==MacAyeal3dIceFrontEnum){
+		icefront_node_ids[0]=iomodel->nodecounter+reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+0));
+		icefront_node_ids[1]=iomodel->nodecounter+reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+1));
+		icefront_vertex_ids[0]=reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+0));
+		icefront_vertex_ids[1]=reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+1));
+	}
+	else if (in_icefront_type==PattynIceFrontEnum || in_icefront_type==StokesIceFrontEnum){
+		icefront_node_ids[0]=iomodel->nodecounter+reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+0));
+		icefront_node_ids[1]=iomodel->nodecounter+reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+1));
+		icefront_node_ids[2]=iomodel->nodecounter+reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+2));
+		icefront_node_ids[3]=iomodel->nodecounter+reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+3));
+		icefront_vertex_ids[0]=reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+0));
+		icefront_vertex_ids[1]=reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+1));
+		icefront_vertex_ids[2]=reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+2));
+		icefront_vertex_ids[3]=reCast<int>(*(iomodel->Data(DiagnosticIcefrontEnum)+segment_width*i+3));
+	}
+	else _error_("in_icefront_type " << EnumToStringx(in_icefront_type) << " not supported yet!");
+
+	if (in_icefront_type==PattynIceFrontEnum || in_icefront_type==StokesIceFrontEnum)
+	 num_nodes=4;
+	else 
+	 num_nodes=2;
+
+	/*Fill*/
+	icefront_fill=reCast<int>(iomodel->Data(DiagnosticIcefrontEnum)[segment_width*i+segment_width-1]);
+
+	/*Ok, we have everything to build the object: */
+	this->id=icefront_id;
+	this->analysis_type=in_analysis_type;
+
+	/*Hooks: */
+	this->hnodes=new Hook(icefront_node_ids,num_nodes);
+	this->hvertices=new Hook(icefront_vertex_ids,num_nodes);
+	this->helement=new Hook(&icefront_eid,1);
+	this->hmatpar=new Hook(&icefront_mparid,1);
+
+	//intialize  and add as many inputs per element as requested: 
+	this->inputs=new Inputs();
+	this->inputs->AddInput(new IntInput(FillEnum,icefront_fill));
+	this->inputs->AddInput(new IntInput(IceFrontTypeEnum,in_icefront_type));
+
+	//parameters and hooked fields: we still can't point to them, they may not even exist. Configure will handle this.
+	this->parameters = NULL;
+	this->nodes      = NULL;
+	this->vertices   = NULL;
+	this->element    = NULL;
+	this->matpar     = NULL;
+}
+
+/*}}}*/
+/*FUNCTION Icefront::~Icefront() {{{*/
+Icefront::~Icefront(){
+	delete inputs;
+	this->parameters=NULL;
+	delete hnodes;
+	delete hvertices;
+	delete helement;
+	delete hmatpar;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Icefront::Echo {{{*/
+void Icefront::Echo(void){
+	_printLine_("Icefront:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->Echo();
+	hvertices->Echo();
+	helement->Echo();
+	hmatpar->Echo();
+	_printLine_("   parameters: " << parameters);
+	if(parameters)parameters->Echo();
+	_printLine_("   inputs: " << inputs);
+	if(inputs)inputs->Echo();
+}
+/*}}}*/
+/*FUNCTION Icefront::DeepEcho{{{*/
+void Icefront::DeepEcho(void){
+
+	_printLine_("Icefront:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->DeepEcho();
+	hvertices->DeepEcho();
+	helement->DeepEcho();
+	hmatpar->DeepEcho();
+	_printLine_("   parameters: " << parameters);
+	if(parameters)parameters->DeepEcho();
+	_printLine_("   inputs: " << inputs);
+	if(inputs)inputs->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION Icefront::Id {{{*/
+int    Icefront::Id(void){ return id; }
+/*}}}*/
+/*FUNCTION Icefront::ObjectEnum{{{*/
+int Icefront::ObjectEnum(void){
+
+	return IcefrontEnum;
+
+}
+/*}}}*/
+/*FUNCTION Icefront::copy {{{*/
+Object* Icefront::copy() {
+
+	Icefront* icefront=NULL;
+
+	icefront=new Icefront();
+
+	/*copy fields: */
+	icefront->id=this->id;
+	icefront->analysis_type=this->analysis_type;
+	if(this->inputs){
+		icefront->inputs=(Inputs*)this->inputs->Copy();
+	}
+	else{
+		icefront->inputs=new Inputs();
+	}
+	/*point parameters: */
+	icefront->parameters=this->parameters;
+
+	/*now deal with hooks and objects: */
+	icefront->hnodes    = (Hook*)this->hnodes->copy();
+	icefront->hvertices = (Hook*)this->hvertices->copy();
+	icefront->helement  = (Hook*)this->helement->copy();
+	icefront->hmatpar   = (Hook*)this->hmatpar->copy();
+
+	/*corresponding fields*/
+	icefront->nodes    = (Node**)icefront->hnodes->deliverp();
+	icefront->vertices = (Vertex**)icefront->hvertices->deliverp();
+	icefront->element  = (Element*)icefront->helement->delivers();
+	icefront->matpar   = (Matpar*)icefront->hmatpar->delivers();
+
+	return icefront;
+
+}
+/*}}}*/
+
+/*Load virtual functions definitions:*/
+/*FUNCTION Icefront::Configure {{{*/
+void  Icefront::Configure(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+	/*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: */
+	hnodes->configure((DataSet*)nodesin);
+	hvertices->configure((DataSet*)verticesin);
+	helement->configure((DataSet*)elementsin);
+	hmatpar->configure((DataSet*)materialsin);
+
+	/*Initialize hooked fields*/
+	this->nodes    = (Node**)hnodes->deliverp();
+	this->vertices = (Vertex**)hvertices->deliverp();
+	this->element  = (Element*)helement->delivers();
+	this->matpar   = (Matpar*)hmatpar->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+}
+/*}}}*/
+/*FUNCTION Icefront::SetCurrentConfiguration {{{*/
+void  Icefront::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+}
+/*}}}*/
+/*FUNCTION Icefront::CreateKMatrix {{{*/
+void  Icefront::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+
+	/*No stiffness loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Icefront::CreatePVector {{{*/
+void  Icefront::CreatePVector(Vector<IssmDouble>* pf){
+
+	/*Checks in debugging mode*/
+	/*{{{*/
+	_assert_(nodes);
+	_assert_(element);
+	_assert_(matpar);
+	/*}}}*/
+
+	/*Retrieve parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Just branch to the correct element icefront vector generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum:
+			pe=CreatePVectorDiagnosticHoriz();
+			break;
+		#endif
+		#ifdef _HAVE_CONTROL_
+		case AdjointHorizAnalysisEnum:
+			pe=CreatePVectorAdjointHoriz();
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+}
+/*}}}*/
+/*FUNCTION Icefront::CreateJacobianMatrix{{{*/
+void  Icefront::CreateJacobianMatrix(Matrix<IssmDouble>* Jff){
+	this->CreateKMatrix(Jff,NULL);
+}
+/*}}}*/
+/*FUNCTION Icefront::GetNodesSidList{{{*/
+void Icefront::GetNodesSidList(int* sidlist){
+
+	int type;
+	inputs->GetInputValue(&type,IceFrontTypeEnum);
+	_assert_(sidlist);
+	_assert_(nodes);
+
+	switch(type){
+		case MacAyeal2dIceFrontEnum:
+		case MacAyeal3dIceFrontEnum:
+			for(int i=0;i<NUMVERTICESSEG;i++) sidlist[i]=nodes[i]->Sid();
+			return;
+#ifdef _HAVE_3D_
+		case PattynIceFrontEnum:
+		case StokesIceFrontEnum:
+			for(int i=0;i<NUMVERTICESQUA;i++) sidlist[i]=nodes[i]->Sid();
+			return;
+#endif
+		default:
+			_error_("Icefront type " << EnumToStringx(type) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Icefront::GetNumberOfNodes{{{*/
+int Icefront::GetNumberOfNodes(void){
+
+	int type;
+	inputs->GetInputValue(&type,IceFrontTypeEnum);
+
+	switch(type){
+		case MacAyeal2dIceFrontEnum:
+			return NUMVERTICESSEG;
+#ifdef _HAVE_3D_
+		case MacAyeal3dIceFrontEnum:
+			return NUMVERTICESSEG;
+		case PattynIceFrontEnum:
+			return NUMVERTICESQUA;
+		case StokesIceFrontEnum:
+			return NUMVERTICESQUA;
+#endif
+		default:
+			_error_("Icefront type " << EnumToStringx(type) << " not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Icefront::IsPenalty{{{*/
+bool Icefront::IsPenalty(void){
+	return false;
+}
+/*}}}*/
+/*FUNCTION Icefront::PenaltyCreateKMatrix {{{*/
+void  Icefront::PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs, IssmDouble kmax){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Icefront::PenaltyCreatePVector{{{*/
+void  Icefront::PenaltyCreatePVector(Vector<IssmDouble>* pf,IssmDouble kmax){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Icefront::PenaltyCreateJacobianMatrix{{{*/
+void  Icefront::PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax){
+	this->PenaltyCreateKMatrix(Jff,NULL,kmax);
+}
+/*}}}*/
+/*FUNCTION Icefront::SetwiseNodeConnectivity{{{*/
+void Icefront::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	/*Loop over all nodes*/
+	for(int i=0;i<this->GetNumberOfNodes();i++){
+
+		if(!flags[this->nodes[i]->Sid()]){
+
+			/*flag current node so that no other element processes it*/
+			flags[this->nodes[i]->Sid()]=true;
+
+			/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+			switch(set2_enum){
+				case FsetEnum:
+					if(nodes[i]->indexing.fsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case GsetEnum:
+					if(nodes[i]->indexing.gsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case SsetEnum:
+					if(nodes[i]->indexing.ssize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				default: _error_("not supported");
+			}
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+/*FUNCTION Icefront::InAnalysis{{{*/
+bool Icefront::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type)return true;
+	else return false;
+}
+/*}}}*/
+
+/*Update virtual functions definitions:*/
+/*FUNCTION Icefront::InputUpdateFromVector(IssmDouble* vector, int name, int type) {{{*/
+void  Icefront::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromVector(int* vector, int name, int type) {{{*/
+void  Icefront::InputUpdateFromVector(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromVector(bool* vector, int name, int type) {{{*/
+void  Icefront::InputUpdateFromVector(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type) {{{*/
+void  Icefront::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type) {{{*/
+void  Icefront::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromVectorDakota(int* vector, int name, int type) {{{*/
+void  Icefront::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromVectorDakota(bool* vector, int name, int type) {{{*/
+void  Icefront::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromConstant(IssmDouble constant, int name) {{{*/
+void  Icefront::InputUpdateFromConstant(IssmDouble constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromConstant(int constant, int name) {{{*/
+void  Icefront::InputUpdateFromConstant(int constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromConstant(bool constant, int name) {{{*/
+void  Icefront::InputUpdateFromConstant(bool constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Icefront::InputUpdateFromSolution{{{*/
+void  Icefront::InputUpdateFromSolution(IssmDouble* solution){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+
+/*Icefront numerics: */
+#ifdef _HAVE_DIAGNOSTIC_
+/*FUNCTION Icefront::CreatePVectorDiagnosticHoriz {{{*/
+ElementVector* Icefront::CreatePVectorDiagnosticHoriz(void){
+
+	int type;
+	inputs->GetInputValue(&type,IceFrontTypeEnum);
+
+	switch(type){
+		case MacAyeal2dIceFrontEnum:
+			return CreatePVectorDiagnosticMacAyeal2d();
+        #ifdef _HAVE_3D_
+		case MacAyeal3dIceFrontEnum:
+			return CreatePVectorDiagnosticMacAyeal3d();
+		case PattynIceFrontEnum:
+			return CreatePVectorDiagnosticPattyn();
+		case StokesIceFrontEnum:
+			return CreatePVectorDiagnosticStokes();
+	    #endif
+		default:
+			_error_("Icefront type " << EnumToStringx(type) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Icefront::CreatePVectorDiagnosticMacAyeal2d{{{*/
+ElementVector* Icefront::CreatePVectorDiagnosticMacAyeal2d(void){
+
+	/*Constants*/
+	const int numnodes= NUMVERTICESSEG;
+	const int numdofs = numnodes *NDOF2;
+
+	/*Intermediary*/
+	int        ig,index1,index2,fill;
+	IssmDouble     Jdet;
+	IssmDouble     thickness,bed,pressure,ice_pressure,rho_water,rho_ice,gravity;
+	IssmDouble     water_pressure,air_pressure,surface_under_water,base_under_water;
+	IssmDouble     xyz_list[numnodes][3];
+	IssmDouble     normal[2];
+	IssmDouble     L[2];
+	GaussTria *gauss;
+
+	Tria* tria=((Tria*)element);
+
+	/*Initialize Element vector and return if necessary*/
+	if(tria->IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICESSEG,this->parameters,MacAyealApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICESSEG);
+	Input* thickness_input=tria->inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+	Input* bed_input      =tria->inputs->GetInput(BedEnum);       _assert_(bed_input);
+	inputs->GetInputValue(&fill,FillEnum);
+	rho_water=matpar->GetRhoWater();
+	rho_ice  =matpar->GetRhoIce();
+	gravity  =matpar->GetG();
+	GetSegmentNormal(&normal[0],xyz_list);
+
+	/*Start looping on Gaussian points*/
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+	gauss=new GaussTria(index1,index2,3);
+
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		thickness_input->GetInputValue(&thickness,gauss);
+		bed_input->GetInputValue(&bed,gauss);
+
+		switch(fill){
+			case WaterEnum:
+				surface_under_water=min(0.,thickness+bed); // 0 if the top of the glacier is above water level
+				base_under_water=min(0.,bed);              // 0 if the bottom of the glacier is above water level
+				water_pressure=1.0/2.0*gravity*rho_water*(pow(surface_under_water,2) - pow(base_under_water,2));
+				break;
+			case AirEnum:
+				water_pressure=0;
+				break;
+			case IceEnum:
+				water_pressure=-1.0/2.0*gravity*rho_ice*pow(thickness,2); // we are facing a wall of ice. use water_pressure to cancel the lithostatic pressure.
+				break;
+			default:
+				_error_("fill type " << EnumToStringx(fill) << " not supported yet");
+		}
+		ice_pressure=1.0/2.0*gravity*rho_ice*pow(thickness,2);
+		air_pressure=0;
+		pressure = ice_pressure + water_pressure + air_pressure;
+
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		tria->GetSegmentNodalFunctions(&L[0],gauss,index1,index2);
+
+		for (int i=0;i<numnodes;i++){
+			pe->values[2*i+0]+= pressure*Jdet*gauss->weight*normal[0]*L[i];
+			pe->values[2*i+1]+= pressure*Jdet*gauss->weight*normal[1]*L[i];
+		}
+	}
+
+	/*Transform load vector*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICESSEG,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+#endif
+
+#ifdef _HAVE_CONTROL_
+/*FUNCTION Icefront::CreatePVectorAdjointHoriz {{{*/
+ElementVector* Icefront::CreatePVectorAdjointHoriz(void){
+
+	/*No load vector applied to the adjoint*/
+	return NULL;
+}
+/*}}}*/
+#endif
+#ifdef _HAVE_3D_
+/*FUNCTION Icefront::CreatePVectorDiagnosticMacAyeal3d{{{*/
+ElementVector* Icefront::CreatePVectorDiagnosticMacAyeal3d(void){
+
+	Icefront *icefront = NULL;
+	Penta    *penta    = NULL;
+	Tria     *tria     = NULL;
+
+	/*Cast element onto Penta*/
+	penta   =(Penta*)this->element;
+
+	/*Return if not on bed*/
+	if(!penta->IsOnBed() || penta->IsOnWater()) return NULL;
+
+	/*Spawn Tria and call MacAyeal2d*/
+	tria    =(Tria*)penta->SpawnTria(0,1,2);
+	icefront=(Icefront*)this->copy();
+	icefront->element=tria;
+	icefront->inputs->AddInput(new IntInput(IceFrontTypeEnum,MacAyeal2dIceFrontEnum));
+	ElementVector* pe=icefront->CreatePVectorDiagnosticMacAyeal2d();
+
+	/*clean-up and return*/
+	delete tria->material;
+	delete tria;
+	delete icefront;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Icefront::CreatePVectorDiagnosticPattyn{{{*/
+ElementVector* Icefront::CreatePVectorDiagnosticPattyn(void){
+
+	/*Constants*/
+	const int numdofs = NUMVERTICESQUA *NDOF2;
+
+	/*Intermediaries*/
+	int         i,j,ig,index1,index2,index3,index4;
+	int         fill;
+	IssmDouble      surface,pressure,ice_pressure,rho_water,rho_ice,gravity;
+	IssmDouble      water_pressure,air_pressure;
+	IssmDouble      Jdet,z_g;
+	IssmDouble      xyz_list[NUMVERTICESQUA][3];
+	IssmDouble      normal[3];
+	IssmDouble      l1l4[4];
+	GaussPenta *gauss = NULL;
+
+	Penta* penta=(Penta*)element;
+
+	/*Initialize Element vector and return if necessary*/
+	if(penta->IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICESQUA,this->parameters,PattynApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICESQUA);
+	Input* surface_input  =penta->inputs->GetInput(SurfaceEnum);   _assert_(surface_input);
+	inputs->GetInputValue(&fill,FillEnum);
+	rho_water=matpar->GetRhoWater();
+	rho_ice  =matpar->GetRhoIce();
+	gravity  =matpar->GetG();
+	GetQuadNormal(&normal[0],xyz_list);
+
+	/*Identify which nodes are in the quad: */
+	index1=element->GetNodeIndex(nodes[0]);
+	index2=element->GetNodeIndex(nodes[1]);
+	index3=element->GetNodeIndex(nodes[2]);
+	index4=element->GetNodeIndex(nodes[3]);
+
+	/* Start  looping on the number of gaussian points: */
+	IssmDouble zmax=xyz_list[0][2]; for(i=1;i<NUMVERTICESQUA;i++) if(xyz_list[i][2]>zmax) zmax=xyz_list[i][2];
+	IssmDouble zmin=xyz_list[0][2]; for(i=1;i<NUMVERTICESQUA;i++) if(xyz_list[i][2]<zmin) zmin=xyz_list[i][2];
+	if(zmax>0 && zmin<0) gauss=new GaussPenta(index1,index2,index3,index4,3,10); //refined in vertical because of the sea level discontinuity
+	else                 gauss=new GaussPenta(index1,index2,index3,index4,3,3);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		penta->GetQuadNodalFunctions(l1l4,gauss,index1,index2,index3,index4);
+		penta->GetQuadJacobianDeterminant(&Jdet,xyz_list,gauss);
+		z_g=penta->GetZcoord(gauss);
+		surface_input->GetInputValue(&surface,gauss);
+
+		switch(fill){
+			case WaterEnum:
+				water_pressure=rho_water*gravity*min(0.,z_g);//0 if the gaussian point is above water level
+				break;
+			case AirEnum:
+				water_pressure=0;
+				break;
+			default:
+				_error_("fill type " << EnumToStringx(fill) << " not supported yet");
+		}
+		ice_pressure=rho_ice*gravity*(surface-z_g);
+		air_pressure=0;
+		pressure = ice_pressure + water_pressure + air_pressure;
+
+		for(i=0;i<NUMVERTICESQUA;i++) for(j=0;j<NDOF2;j++) pe->values[i*NDOF2+j]+=Jdet*gauss->weight*pressure*l1l4[i]*normal[j];
+	}
+
+	/*Transform load vector*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICESQUA,XYEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Icefront::CreatePVectorDiagnosticStokes{{{*/
+ElementVector* Icefront::CreatePVectorDiagnosticStokes(void){
+
+	/*Constants*/
+	const int numdofs = NUMVERTICESQUA *NDOF4;
+
+	/*Intermediaries*/
+	int         i,j,ig,index1,index2,index3,index4;
+	int         fill;
+	IssmDouble      pressure,rho_water,gravity;
+	IssmDouble      water_pressure,air_pressure;
+	IssmDouble      Jdet,z_g;
+	IssmDouble      xyz_list[NUMVERTICESQUA][3];
+	IssmDouble      normal[3];
+	IssmDouble      l1l4[4];
+	GaussPenta *gauss = NULL;
+
+	Penta* penta=(Penta*)element;
+
+	/*Initialize Element vector and return if necessary*/
+	if(penta->IsOnWater()) return NULL;
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICESQUA,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICESQUA);
+	inputs->GetInputValue(&fill,FillEnum);
+	rho_water=matpar->GetRhoWater();
+	gravity  =matpar->GetG();
+	GetQuadNormal(&normal[0],xyz_list);
+
+	/*Identify which nodes are in the quad: */
+	index1=element->GetNodeIndex(nodes[0]);
+	index2=element->GetNodeIndex(nodes[1]);
+	index3=element->GetNodeIndex(nodes[2]);
+	index4=element->GetNodeIndex(nodes[3]);
+
+	/* Start  looping on the number of gaussian points: */
+	IssmDouble zmax=xyz_list[0][2]; for(i=1;i<NUMVERTICESQUA;i++) if(xyz_list[i][2]>zmax) zmax=xyz_list[i][2];
+	IssmDouble zmin=xyz_list[0][2]; for(i=1;i<NUMVERTICESQUA;i++) if(xyz_list[i][2]<zmin) zmin=xyz_list[i][2];
+	if(zmax>0 && zmin<0) gauss=new GaussPenta(index1,index2,index3,index4,3,30); //refined in vertical because of the sea level discontinuity
+	else                 gauss=new GaussPenta(index1,index2,index3,index4,3,3);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		penta->GetQuadNodalFunctions(l1l4,gauss,index1,index2,index3,index4);
+		penta->GetQuadJacobianDeterminant(&Jdet,xyz_list,gauss);
+		z_g=penta->GetZcoord(gauss);
+
+		switch(fill){
+			case WaterEnum:
+				water_pressure=rho_water*gravity*min(0.,z_g);//0 if the gaussian point is above water level
+				break;
+			case AirEnum:
+				water_pressure=0;
+				break;
+			default:
+				_error_("fill type " << EnumToStringx(fill) << " not supported yet");
+		}
+		air_pressure=0;
+		pressure = water_pressure + air_pressure; //no ice pressure fore Stokes
+
+		for(i=0;i<NUMVERTICESQUA;i++){
+			for(j=0;j<NDOF4;j++){
+				if(j<3)  pe->values[i*NDOF4+j]+=Jdet*gauss->weight*pressure*l1l4[i]*normal[j];
+				else     pe->values[i*NDOF4+j]+=0; //pressure term
+			}
+		}
+	}
+
+	/*Transform load vector*/
+	TransformLoadVectorCoord(pe,nodes,NUMVERTICESQUA,XYZPEnum);
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+#endif
+/*FUNCTION Icefront::GetDofList {{{*/
+void  Icefront::GetDofList(int** pdoflist,int approximation_enum,int setenum){
+
+	int numberofdofs=0;
+	int count=0;
+	int type;
+	int numberofnodes=2;
+
+	/*output: */
+	int* doflist=NULL;
+
+	/*recover type: */
+	inputs->GetInputValue(&type,IceFrontTypeEnum);
+
+	/*Some checks for debugging*/
+	_assert_(nodes);
+
+	/*How many nodes? :*/
+	if(type==MacAyeal2dIceFrontEnum || type==MacAyeal3dIceFrontEnum)
+	 numberofnodes=2;
+	else 
+	 numberofnodes=4;
+
+	/*Figure out size of doflist: */
+	for(int i=0;i<numberofnodes;i++){
+		numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+	}
+
+	/*Allocate: */
+	doflist=xNew<int>(numberofdofs);
+
+	/*Populate: */
+	count=0;
+	for(int i=0;i<numberofnodes;i++){
+		nodes[i]->GetDofList(doflist+count,approximation_enum,setenum);
+		count+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+	}
+
+	/*Assign output pointers:*/
+	*pdoflist=doflist;
+}
+/*}}}*/
+/*FUNCTION Icefront::GetSegmentNormal {{{*/
+void Icefront:: GetSegmentNormal(IssmDouble* normal,IssmDouble xyz_list[4][3]){
+
+	/*Build unit outward pointing vector*/
+	const int numnodes=NUMVERTICESSEG;
+	IssmDouble vector[2];
+	IssmDouble norm;
+
+	vector[0]=xyz_list[1][0] - xyz_list[0][0];
+	vector[1]=xyz_list[1][1] - xyz_list[0][1];
+
+	norm=sqrt(pow(vector[0],2.0)+pow(vector[1],2.0));
+
+	normal[0]= + vector[1]/norm;
+	normal[1]= - vector[0]/norm;
+}
+/*}}}*/
+/*FUNCTION Icefront::GetQuadNormal {{{*/
+void Icefront:: GetQuadNormal(IssmDouble* normal,IssmDouble xyz_list[4][3]){
+
+	/*Build unit outward pointing vector*/
+	IssmDouble AB[3];
+	IssmDouble AC[3];
+	IssmDouble norm;
+
+	AB[0]=xyz_list[1][0] - xyz_list[0][0];
+	AB[1]=xyz_list[1][1] - xyz_list[0][1];
+	AB[2]=xyz_list[1][2] - xyz_list[0][2];
+	AC[0]=xyz_list[2][0] - xyz_list[0][0];
+	AC[1]=xyz_list[2][1] - xyz_list[0][1];
+	AC[2]=xyz_list[2][2] - xyz_list[0][2];
+
+	cross(normal,AB,AC);
+	norm=sqrt(pow(normal[0],2.0)+pow(normal[1],2.0)+pow(normal[2],2.0));
+
+	for(int i=0;i<3;i++) normal[i]=normal[i]/norm;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Icefront.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Icefront.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Icefront.h	(revision 15012)
@@ -0,0 +1,104 @@
+/*!\file Icefront.h
+ * \brief: header file for icefront object
+ */
+
+#ifndef _ICEFRONT_H_
+#define _ICEFRONT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Load.h"
+class Hook;
+class Inputs;
+class Parameters;
+class Matpar;
+class Node;
+class Element;
+class IoModel;
+class ElementVector;
+class Vertex;
+/*}}}*/
+
+class Icefront: public Load {
+
+	public:
+		int id;
+		int analysis_type;
+
+		/*hooks: */
+		Hook *hnodes;
+		Hook *hvertices;
+		Hook *helement;
+		Hook *hmatpar;
+
+		/*Corresponding fields*/
+		Matpar   *matpar;
+		Node    **nodes;
+		Vertex  **vertices;
+		Element  *element;
+
+		/*inputs and parameters: */
+		Inputs     *inputs;
+		Parameters *parameters;
+
+		/*Icefront constructors, destructors: {{{*/
+		Icefront();
+		Icefront(int icefront_id,int i, IoModel* iomodel,int in_icefront_type, int analysis_type);
+		~Icefront();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions definitions: {{{*/
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix,int ncols,int nrows, int name, int type);
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solution);
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("not implemented yet");};
+		/*}}}*/
+		/*Load virtual functions definitions: {{{*/
+		void  Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void  CreatePVector(Vector<IssmDouble>* pf);
+		void  CreateJacobianMatrix(Matrix<IssmDouble>* Jff);
+		int   GetNumberOfNodes(void);
+		void  GetNodesSidList(int* sidlist);
+		bool  IsPenalty(void);
+		void  PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector<IssmDouble>*  pf, IssmDouble kmax);
+		void  PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax);
+		void  SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		bool  InAnalysis(int analysis_type);
+		/*}}}*/
+		/*Load management: {{{*/
+		void GetDofList(int** pdoflist,int approximation_enum,int setenum);
+		void GetSegmentNormal(IssmDouble* normal,IssmDouble xyz_list[2][3]);
+		void GetQuadNormal(IssmDouble* normal,IssmDouble xyz_list[4][3]);
+		#ifdef _HAVE_CONTROL_
+		ElementVector* CreatePVectorAdjointHoriz(void);
+		#endif
+		#ifdef _HAVE_DIAGNOSTIC_
+		ElementVector* CreatePVectorDiagnosticHoriz(void);
+		ElementVector* CreatePVectorDiagnosticMacAyeal2d(void);
+		#endif
+        #ifdef _HAVE_3D_
+		ElementVector* CreatePVectorDiagnosticMacAyeal3d(void);
+		ElementVector* CreatePVectorDiagnosticPattyn(void);
+		ElementVector* CreatePVectorDiagnosticStokes(void);
+	    #endif
+		/*}}}*/
+};
+
+#endif  /* _ICEFRONT_H_ */
Index: /issm/trunk-jpl/src/c/classes/Loads/Load.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Load.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Load.h	(revision 15012)
@@ -0,0 +1,46 @@
+/*!\file:  Load.h
+ * \brief abstract class for Load object
+ * This class is a place holder for the Icefront  and the Penpair loads.
+ * It is derived from Load, so DataSets can contain them.
+ */ 
+
+#ifndef _LOAD_H_
+#define _LOAD_H_
+
+/*Headers:*/
+/*{{{*/
+class Node;
+template <class doublematrix> class Matrix;
+template <class doubletype> class Vector;
+class Elements;
+class Loads;
+class Nodes;
+class Vertices;
+class Materials;
+class Parameters;
+
+#include "../Object.h"
+#include "../Update.h"
+
+/*}}}*/
+
+class Load: public Object,public Update{
+
+	public: 
+
+		virtual       ~Load(){};
+		virtual void  Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters)=0;
+		virtual bool  IsPenalty(void)=0;
+		virtual int   GetNumberOfNodes(void)=0;
+		virtual void  GetNodesSidList(int* sidlist)=0;
+		virtual void  SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters)=0;
+		virtual void  CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs)=0;
+		virtual void  CreatePVector(Vector<IssmDouble>* pf)=0;
+		virtual void  CreateJacobianMatrix(Matrix<IssmDouble>* Jff)=0;
+		virtual void  PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax)=0;
+		virtual void  PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs, IssmDouble kmax)=0;
+		virtual void  PenaltyCreatePVector(Vector<IssmDouble>* pf, IssmDouble kmax)=0;
+		virtual bool  InAnalysis(int analysis_type)=0;
+		virtual void  SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum)=0;
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Loads/Loads.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Loads.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Loads.cpp	(revision 15012)
@@ -0,0 +1,189 @@
+/*
+ * \file Loads.cpp
+ * \brief: Implementation of Loads class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <vector>
+#include <functional>
+#include <algorithm>
+
+#include "./Loads.h"
+#include "./Load.h"
+#include "../../shared/shared.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Loads::Loads(){{{*/
+Loads::Loads(){
+	enum_type=LoadsEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Loads::~Loads(){{{*/
+Loads::~Loads(){
+	return;
+}
+/*}}}*/
+
+/*Numerics:*/
+/*FUNCTION Loads::Configure{{{*/
+void Loads::Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Load* load=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		load=dynamic_cast<Load*>(*object);
+		load->Configure(elements,loads,nodes,vertices,materials,parameters);
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION Loads::IsPenalty{{{*/
+bool Loads::IsPenalty(int analysis_type){
+
+	int ispenalty=0;
+	int allispenalty=0;
+
+	/*Now go through all loads, and get how many nodes they own, unless they are clone nodes: */
+	for(int i=0;i<this->Size();i++){
+
+		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));
+		if (load->InAnalysis(analysis_type)){
+			if(load->IsPenalty()) ispenalty++;
+		}
+	}
+
+	/*Grab sum of all cpus: */
+#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)&ispenalty,(void*)&allispenalty,1,MPI_INT,MPI_SUM,IssmComm::GetComm());
+	ispenalty=allispenalty;
+#endif
+
+	if(ispenalty)
+	 return true;
+	else
+	 return false;
+}
+/*}}}*/
+/*FUNCTION Loads::MaxNumNodes{{{*/
+int Loads::MaxNumNodes(int analysis_type){
+
+	int max=0;
+	int allmax;
+	int numnodes=0;
+
+	/*Now go through all loads, and get how many nodes they own, unless they are clone nodes: */
+	for(int i=0;i<this->Size();i++){
+
+		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));
+		if (load->InAnalysis(analysis_type)){
+			numnodes=load->GetNumberOfNodes();
+			if(numnodes>max)max=numnodes;
+		}
+	}
+
+	/*Grab max of all cpus: */
+#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)&max,(void*)&allmax,1,MPI_INT,MPI_MAX,IssmComm::GetComm());
+	max=allmax;
+#endif
+
+	return max;
+}
+/*}}}*/
+/*FUNCTION Loads::NumberOfLoads(){{{*/
+int Loads::NumberOfLoads(void){
+
+	int localloads;
+	int numberofloads;
+
+	/*Get number of local loads*/
+	localloads=this->Size();
+
+	/*figure out total number of loads combining all the cpus (no clones here)*/
+	#ifdef _HAVE_MPI_
+	MPI_Reduce(&localloads,&numberofloads,1,MPI_INT,MPI_SUM,0,IssmComm::GetComm() );
+	MPI_Bcast(&numberofloads,1,MPI_INT,0,IssmComm::GetComm());
+	#else
+	numberofloads=localloads;
+	#endif
+
+	return numberofloads;
+}
+/*}}}*/
+/*FUNCTION Loads::NumberOfLoads(int analysis){{{*/
+int Loads::NumberOfLoads(int analysis_type){
+
+	int localloads = 0;
+	int numberofloads;
+
+	/*Get number of local loads*/
+	for(int i=0;i<this->Size();i++){
+
+		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));
+
+		/*Check that this load corresponds to our analysis currently being carried out: */
+		if (load->InAnalysis(analysis_type)) localloads++;
+	}
+
+	/*figure out total number of loads combining all the cpus (no clones here)*/
+#ifdef _HAVE_MPI_
+	MPI_Reduce(&localloads,&numberofloads,1,MPI_INT,MPI_SUM,0,IssmComm::GetComm() );
+	MPI_Bcast(&numberofloads,1,MPI_INT,0,IssmComm::GetComm());
+#else
+	numberofloads=localloads;
+#endif
+
+	return numberofloads;
+}
+/*}}}*/
+/*FUNCTION Loads::Size(){{{*/
+int Loads::Size(void){
+
+	return this->DataSet::Size();
+}
+/*}}}*/
+/*FUNCTION Loads::Size(int analysis){{{*/
+int Loads::Size(int analysis_type){
+
+	int localloads = 0;
+
+	/*Get number of local loads*/
+	for(int i=0;i<this->Size();i++){
+
+		Load* load=dynamic_cast<Load*>(this->GetObjectByOffset(i));
+
+		/*Check that this load corresponds to our analysis currently being carried out: */
+		if (load->InAnalysis(analysis_type)) localloads++;
+	}
+
+	return localloads;
+}
+/*}}}*/
+/*FUNCTION Loads::SetCurrentConfiguration{{{*/
+void Loads::SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Load* load=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		load=dynamic_cast<Load*>(*object);
+		load->SetCurrentConfiguration(elements,loads,nodes,vertices,materials,parameters);
+
+	}
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Loads.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Loads.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Loads.h	(revision 15012)
@@ -0,0 +1,36 @@
+#ifndef _CONTAINER_LOADS_H_
+#define  _CONTAINER_LOADS_H_
+
+/*forward declarations */
+#include "../DataSet.h"
+class Materials;
+class Parameters;
+class Elements;
+class Vertices;
+class Nodes;
+
+/*!\brief Declaration of Loads class.
+ *
+ * Declaration of Loads class.  Loads are vector lists (Containers) of Load objects.
+ */ 
+class Loads: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Loads();
+		~Loads();
+
+		/*numerics*/
+		void  Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+		bool  IsPenalty(int analysis);
+		int   MaxNumNodes(int analysis);
+		int   NumberOfLoads(void);
+		int   NumberOfLoads(int analysis);
+		void  SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+		int   Size(int analysis);
+		int   Size(void);
+
+};
+
+#endif //ifndef _LOADS_H_
Index: /issm/trunk-jpl/src/c/classes/Loads/Numericalflux.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Numericalflux.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Numericalflux.cpp	(revision 15012)
@@ -0,0 +1,976 @@
+/*!\file Numericalflux.c
+ * \brief: implementation of the Numericalflux object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "shared/shared.h"
+#include "../classes.h"
+/*}}}*/	
+
+/*Load macros*/
+#define NUMVERTICES 2
+#define NUMNODES_INTERNAL 4
+#define NUMNODES_BOUNDARY 2
+
+/*Numericalflux constructors and destructor*/
+/*FUNCTION Numericalflux::Numericalflux(){{{*/
+Numericalflux::Numericalflux(){
+	this->inputs     = NULL;
+	this->parameters = NULL;
+	this->helement   = NULL;
+	this->element    = NULL;
+	this->hnodes     = NULL;
+	this->hvertices  = NULL;
+	this->nodes      = NULL;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::Numericalflux(int id, int i, IoModel* iomodel, int analysis_type) {{{*/
+Numericalflux::Numericalflux(int numericalflux_id,int i, IoModel* iomodel, int in_analysis_type){
+
+	/* Intermediary */
+	int  e1,e2;
+	int  i1,i2;
+	int  j;
+	int  pos1,pos2,pos3,pos4;
+	int  num_nodes;
+	int  num_elems;
+
+	/*numericalflux constructor data: */
+	int   numericalflux_elem_ids[2];
+	int   numericalflux_mparid;
+	int   numericalflux_vertex_ids[2];
+	int   numericalflux_node_ids[4];
+	int   numericalflux_type;
+
+	int    numberofelements;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&numberofelements,MeshNumberofelementsEnum);
+
+	/* Get MatPar id */
+	numericalflux_mparid=numberofelements+1; //matlab indexing
+
+	/*First, see wether this is an internal or boundary edge (if e2=-1)*/
+	if (iomodel->Data(MeshEdgesEnum)[4*i+3]==-1.){ //edges are [node1 node2 elem1 elem2]
+		/* Boundary edge, only one element */
+		e1=reCast<int>(iomodel->Data(MeshEdgesEnum)[4*i+2]);
+		e2=reCast<int>(UNDEF);
+		num_elems=1;
+		num_nodes=2;
+		numericalflux_type=BoundaryEnum;
+		numericalflux_elem_ids[0]=e1;
+	}
+	else{
+		/* internal edge: connected to 2 elements */
+		e1=reCast<int>(iomodel->Data(MeshEdgesEnum)[4*i+2]);
+		e2=reCast<int>(iomodel->Data(MeshEdgesEnum)[4*i+3]);
+		num_elems=2;
+		num_nodes=4;
+		numericalflux_type=InternalEnum;
+		numericalflux_elem_ids[0]=e1;
+		numericalflux_elem_ids[1]=e2;
+	}
+
+	/*1: Get vertices ids*/
+	i1=reCast<int>(iomodel->Data(MeshEdgesEnum)[4*i+0]);
+	i2=reCast<int>(iomodel->Data(MeshEdgesEnum)[4*i+1]);
+	numericalflux_vertex_ids[0]=i1;
+	numericalflux_vertex_ids[1]=i2;
+
+	/*2: Get node ids*/
+	if (numericalflux_type==InternalEnum){
+
+		/*Now, we must get the nodes of the 4 nodes located on the edge*/
+
+		/*2: Get the column where these ids are located in the index*/
+		pos1=pos2=pos3=pos4=UNDEF;
+		for(j=0;j<3;j++){
+			if (iomodel->Data(MeshElementsEnum)[3*(e1-1)+j]==i1) pos1=j+1;
+			if (iomodel->Data(MeshElementsEnum)[3*(e1-1)+j]==i2) pos2=j+1;
+			if (iomodel->Data(MeshElementsEnum)[3*(e2-1)+j]==i1) pos3=j+1;
+			if (iomodel->Data(MeshElementsEnum)[3*(e2-1)+j]==i2) pos4=j+1;
+		}
+		_assert_(pos1!=UNDEF && pos2!=UNDEF && pos3!=UNDEF && pos4!=UNDEF);
+
+		/*3: We have the id of the elements and the position of the vertices in the index
+		 * we can compute their dofs!*/
+		numericalflux_node_ids[0]=iomodel->nodecounter+3*(e1-1)+pos1;
+		numericalflux_node_ids[1]=iomodel->nodecounter+3*(e1-1)+pos2;
+		numericalflux_node_ids[2]=iomodel->nodecounter+3*(e2-1)+pos3;
+		numericalflux_node_ids[3]=iomodel->nodecounter+3*(e2-1)+pos4;
+	}
+	else{
+
+		/*2: Get the column where these ids are located in the index*/
+		pos1=pos2=UNDEF;
+		for(j=0;j<3;j++){
+			if (iomodel->Data(MeshElementsEnum)[3*(e1-1)+j]==i1) pos1=j+1;
+			if (iomodel->Data(MeshElementsEnum)[3*(e1-1)+j]==i2) pos2=j+1;
+		}
+		_assert_(pos1!=UNDEF && pos2!=UNDEF);
+
+		/*3: We have the id of the elements and the position of the vertices in the index
+		 * we can compute their dofs!*/
+		numericalflux_node_ids[0]=iomodel->nodecounter+3*(e1-1)+pos1;
+		numericalflux_node_ids[1]=iomodel->nodecounter+3*(e1-1)+pos2;
+	}
+
+	/*Ok, we have everything to build the object: */
+	this->id=numericalflux_id;
+	this->analysis_type=in_analysis_type;
+
+	/*Hooks: */
+	this->hnodes    =new Hook(numericalflux_node_ids,num_nodes);
+	this->hvertices =new Hook(&numericalflux_vertex_ids[0],2);
+	this->helement  =new Hook(numericalflux_elem_ids,1); // take only the first element for now
+
+	//intialize  and add as many inputs per element as requested: 
+	this->inputs=new Inputs();
+	this->inputs->AddInput(new IntInput(NumericalfluxTypeEnum,numericalflux_type));
+
+	//this->parameters: we still can't point to it, it may not even exist. Configure will handle this.
+	this->parameters=NULL;
+	this->element=NULL;
+	this->nodes=NULL;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::~Numericalflux(){{{*/
+Numericalflux::~Numericalflux(){
+	delete inputs;
+	this->parameters=NULL;
+	delete helement;
+	delete hnodes;
+	delete hvertices;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Numericalflux::Echo {{{*/
+void Numericalflux::Echo(void){
+	_printLine_("Numericalflux:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->Echo();
+	hvertices->Echo();
+	helement->Echo();
+	_printLine_("   parameters: " << parameters);
+	_printLine_("   inputs: " << inputs);
+}
+/*}}}*/
+/*FUNCTION Numericalflux::DeepEcho {{{*/
+void Numericalflux::DeepEcho(void){
+
+	_printLine_("Numericalflux:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->DeepEcho();
+	hvertices->DeepEcho();
+	helement->DeepEcho();
+	_printLine_("   parameters");
+	if(parameters)
+	 parameters->DeepEcho();
+	else
+	 _printLine_("      NULL");
+	_printLine_("   inputs");
+	inputs->DeepEcho();
+
+}		
+/*}}}*/
+/*FUNCTION Numericalflux::Id {{{*/
+int    Numericalflux::Id(void){
+	return id;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::ObjectEnum{{{*/
+int Numericalflux::ObjectEnum(void){
+
+	return NumericalfluxEnum;
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::copy {{{*/
+Object* Numericalflux::copy() {
+
+	Numericalflux* numericalflux=NULL;
+
+	numericalflux=new Numericalflux();
+
+	/*copy fields: */
+	numericalflux->id=this->id;
+	numericalflux->analysis_type=this->analysis_type;
+	if(this->inputs){
+		numericalflux->inputs=(Inputs*)this->inputs->Copy();
+	}
+	else{
+		numericalflux->inputs=new Inputs();
+	}
+	/*point parameters: */
+	numericalflux->parameters=this->parameters;
+
+	/*now deal with hooks and objects: */
+	numericalflux->hnodes    = (Hook*)this->hnodes->copy();
+	numericalflux->hvertices = (Hook*)this->hvertices->copy();
+	numericalflux->helement  = (Hook*)this->helement->copy();
+
+	/*corresponding fields*/
+	numericalflux->nodes    = (Node**)numericalflux->hnodes->deliverp();
+	numericalflux->vertices = (Vertex**)numericalflux->hvertices->deliverp();
+	numericalflux->element  = (Element*)numericalflux->helement->delivers();
+
+	return numericalflux;
+}
+/*}}}*/
+
+/*Load virtual functions definitions:*/
+/*FUNCTION Numericalflux::Configure {{{*/
+void  Numericalflux::Configure(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+	/*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: */
+	hnodes->configure((DataSet*)nodesin);
+	hvertices->configure((DataSet*)verticesin);
+	helement->configure((DataSet*)elementsin);
+
+	/*Initialize hooked fields*/
+	this->nodes    = (Node**)hnodes->deliverp();
+	this->vertices = (Vertex**)hvertices->deliverp();
+	this->element  = (Element*)helement->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::SetCurrentConfiguration {{{*/
+void  Numericalflux::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrix {{{*/
+void  Numericalflux::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+
+	/*recover some parameters*/
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Just branch to the correct element stiffness matrix generator, according to the type of analysis we are carrying out: */
+	switch(analysis_type){
+		case PrognosticAnalysisEnum:
+			Ke=CreateKMatrixPrognostic();
+			break;
+		case BalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixBalancethickness();
+			break;
+		case AdjointBalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixAdjointBalancethickness();
+			break;
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVector {{{*/
+void  Numericalflux::CreatePVector(Vector<IssmDouble>* pf){
+
+	/*recover some parameters*/
+	ElementVector* pe=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		case PrognosticAnalysisEnum:
+			pe=CreatePVectorPrognostic();
+			break;
+		case BalancethicknessAnalysisEnum:
+			pe=CreatePVectorBalancethickness();
+			break;
+		case AdjointBalancethicknessAnalysisEnum:
+			pe=CreatePVectorAdjointBalancethickness();
+			break;
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::GetNodesSidList{{{*/
+void Numericalflux::GetNodesSidList(int* sidlist){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+	_assert_(sidlist);
+	_assert_(nodes);
+
+	switch(type){
+		case InternalEnum:
+			for(int i=0;i<NUMNODES_INTERNAL;i++) sidlist[i]=nodes[i]->Sid();
+			return;
+		case BoundaryEnum:
+			for(int i=0;i<NUMNODES_BOUNDARY;i++) sidlist[i]=nodes[i]->Sid();
+			return;
+		default:
+			_error_("Numericalflux type " << EnumToStringx(type) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::GetNumberOfNodes{{{*/
+int Numericalflux::GetNumberOfNodes(void){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return NUMNODES_INTERNAL;
+		case BoundaryEnum:
+			return NUMNODES_BOUNDARY;
+		default:
+			_error_("Numericalflux type " << EnumToStringx(type) << " not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::IsPenalty{{{*/
+bool Numericalflux::IsPenalty(void){
+	return false;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::PenaltyCreateKMatrix {{{*/
+void  Numericalflux::PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs,IssmDouble kmax){
+
+	/*No stiffness loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::PenaltyCreatePVector{{{*/
+void  Numericalflux::PenaltyCreatePVector(Vector<IssmDouble>* pf,IssmDouble kmax){
+
+	/*No penalty loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::InAnalysis{{{*/
+bool Numericalflux::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::SetwiseNodeConnectivity{{{*/
+void Numericalflux::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	/*Loop over all nodes*/
+	for(int i=0;i<this->GetNumberOfNodes();i++){
+
+		if(!flags[this->nodes[i]->Sid()]){
+
+			/*flag current node so that no other element processes it*/
+			flags[this->nodes[i]->Sid()]=true;
+
+			/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+			switch(set2_enum){
+				case FsetEnum:
+					if(nodes[i]->indexing.fsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case GsetEnum:
+					if(nodes[i]->indexing.gsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case SsetEnum:
+					if(nodes[i]->indexing.ssize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				default: _error_("not supported");
+			}
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+
+/*Numericalflux management*/
+/*FUNCTION Numericalflux::CreateKMatrixPrognostic{{{*/
+ElementMatrix* Numericalflux::CreateKMatrixPrognostic(void){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreateKMatrixPrognosticInternal();
+		case BoundaryEnum:
+			return CreateKMatrixPrognosticBoundary();
+		default:
+			_error_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixPrognosticInternal {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixPrognosticInternal(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMNODES_INTERNAL;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL1,DL2,Jdet,dt,vx,vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     normal[2];
+	IssmDouble     B[numdof];
+	IssmDouble     Bprime[numdof];
+	IssmDouble     Ke_g1[numdof][numdof];
+	IssmDouble     Ke_g2[numdof][numdof];
+	GaussTria *gauss;
+
+	/*Initialize Element matrix and return if necessary*/
+	Tria*  tria=(Tria*)element;
+	if(tria->IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMNODES_INTERNAL,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* vxaverage_input=tria->inputs->GetInput(VxEnum);
+	Input* vyaverage_input=tria->inputs->GetInput(VyEnum);
+	GetNormal(&normal[0],xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+	gauss=new GaussTria(index1,index2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		tria->GetSegmentBFlux(&B[0],gauss,index1,index2);
+		tria->GetSegmentBprimeFlux(&Bprime[0],gauss,index1,index2);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		UdotN=vx*normal[0]+vy*normal[1];
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		DL1=gauss->weight*Jdet*dt*UdotN/2;
+		DL2=gauss->weight*Jdet*dt*fabs(UdotN)/2;
+
+		TripleMultiply(&B[0],1,numdof,1,
+					&DL1,1,1,0,
+					&Bprime[0],1,numdof,0,
+					&Ke_g1[0][0],0);
+		TripleMultiply(&B[0],1,numdof,1,
+					&DL2,1,1,0,
+					&B[0],1,numdof,0,
+					&Ke_g2[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g1[i][j];
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g2[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixPrognosticBoundary {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixPrognosticBoundary(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMNODES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL,Jdet,dt,vx,vy,mean_vx,mean_vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     normal[2];
+	IssmDouble     L[numdof];
+	IssmDouble     Ke_g[numdof][numdof];
+	GaussTria *gauss;
+
+	/*Initialize Element matrix and return if necessary*/
+	ElementMatrix* Ke = NULL;
+	Tria*  tria=(Tria*)element;
+	if(tria->IsOnWater()) return NULL;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* vxaverage_input=tria->inputs->GetInput(VxEnum); _assert_(vxaverage_input);
+	Input* vyaverage_input=tria->inputs->GetInput(VyEnum); _assert_(vyaverage_input);
+	GetNormal(&normal[0],xyz_list);
+
+	/*Check wether it is an inflow or outflow BC (0 is the middle of the segment)*/
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+
+	gauss=new GaussTria();
+	gauss->GaussEdgeCenter(index1,index2);
+	vxaverage_input->GetInputValue(&mean_vx,gauss);
+	vyaverage_input->GetInputValue(&mean_vy,gauss);
+	delete gauss;
+
+	UdotN=mean_vx*normal[0]+mean_vy*normal[1];
+	if (UdotN<=0){
+		return NULL; /*(u,n)<0 -> inflow, PenaltyCreatePVector will take care of it*/
+	}
+	else{
+		Ke=new ElementMatrix(nodes,NUMNODES_BOUNDARY,this->parameters);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(index1,index2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		tria->GetSegmentNodalFunctions(&L[0],gauss,index1,index2);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		UdotN=vx*normal[0]+vy*normal[1];
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		DL=gauss->weight*Jdet*dt*UdotN;
+
+		TripleMultiply(&L[0],1,numdof,1,
+					&DL,1,1,0,
+					&L[0],1,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 Numericalflux::CreateKMatrixBalancethickness{{{*/
+ElementMatrix* Numericalflux::CreateKMatrixBalancethickness(void){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreateKMatrixBalancethicknessInternal();
+		case BoundaryEnum:
+			return CreateKMatrixBalancethicknessBoundary();
+		default:
+			_error_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixBalancethicknessInternal {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixBalancethicknessInternal(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMNODES_INTERNAL;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL1,DL2,Jdet,vx,vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     normal[2];
+	IssmDouble     B[numdof];
+	IssmDouble     Bprime[numdof];
+	IssmDouble     Ke_g1[numdof][numdof];
+	IssmDouble     Ke_g2[numdof][numdof];
+	GaussTria *gauss;
+
+	/*Initialize Element matrix and return if necessary*/
+	Tria*  tria=(Tria*)element;
+	if(tria->IsOnWater()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMNODES_INTERNAL,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vxaverage_input=tria->inputs->GetInput(VxEnum);
+	Input* vyaverage_input=tria->inputs->GetInput(VyEnum);
+	GetNormal(&normal[0],xyz_list);
+
+	/* Start  looping on the number of gaussian points: */
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+	gauss=new GaussTria(index1,index2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		tria->GetSegmentBFlux(&B[0],gauss,index1,index2);
+		tria->GetSegmentBprimeFlux(&Bprime[0],gauss,index1,index2);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		UdotN=vx*normal[0]+vy*normal[1];
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		DL1=gauss->weight*Jdet*UdotN/2;
+		DL2=gauss->weight*Jdet*fabs(UdotN)/2;
+
+		TripleMultiply(&B[0],1,numdof,1,
+					&DL1,1,1,0,
+					&Bprime[0],1,numdof,0,
+					&Ke_g1[0][0],0);
+		TripleMultiply(&B[0],1,numdof,1,
+					&DL2,1,1,0,
+					&B[0],1,numdof,0,
+					&Ke_g2[0][0],0);
+
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g1[i][j];
+		for(i=0;i<numdof;i++) for(j=0;j<numdof;j++) Ke->values[i*numdof+j]+=Ke_g2[i][j];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixBalancethicknessBoundary {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixBalancethicknessBoundary(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMNODES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL,Jdet,vx,vy,mean_vx,mean_vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     normal[2];
+	IssmDouble     L[numdof];
+	IssmDouble     Ke_g[numdof][numdof];
+	GaussTria *gauss;
+
+	/*Initialize Element matrix and return if necessary*/
+	ElementMatrix* Ke = NULL;
+	Tria*  tria=(Tria*)element;
+	if(tria->IsOnWater()) return NULL;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vxaverage_input=tria->inputs->GetInput(VxEnum);
+	Input* vyaverage_input=tria->inputs->GetInput(VyEnum);
+	GetNormal(&normal[0],xyz_list);
+
+	/*Check wether it is an inflow or outflow BC (0 is the middle of the segment)*/
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+
+	gauss=new GaussTria();
+	gauss->GaussEdgeCenter(index1,index2);
+	vxaverage_input->GetInputValue(&mean_vx,gauss);
+	vyaverage_input->GetInputValue(&mean_vy,gauss);
+	delete gauss;
+
+	UdotN=mean_vx*normal[0]+mean_vy*normal[1];
+	if (UdotN<=0){
+		return NULL; /*(u,n)<0 -> inflow, PenaltyCreatePVector will take care of it*/
+	}
+	else{
+		Ke=new ElementMatrix(nodes,NUMNODES_BOUNDARY,this->parameters);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(index1,index2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		tria->GetSegmentNodalFunctions(&L[0],gauss,index1,index2);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		UdotN=vx*normal[0]+vy*normal[1];
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		DL=gauss->weight*Jdet*UdotN;
+
+		TripleMultiply(&L[0],1,numdof,1,
+					&DL,1,1,0,
+					&L[0],1,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 Numericalflux::CreateKMatrixAdjointBalancethickness{{{*/
+ElementMatrix* Numericalflux::CreateKMatrixAdjointBalancethickness(void){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreateKMatrixAdjointBalancethicknessInternal();
+		case BoundaryEnum:
+			return CreateKMatrixAdjointBalancethicknessBoundary();
+		default:
+			_error_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixAdjointBalancethicknessInternal {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixAdjointBalancethicknessInternal(void){
+
+	ElementMatrix* Ke=CreateKMatrixBalancethicknessInternal();
+	if (Ke) Ke->Transpose();
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixAdjointBalancethicknessBoundary {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixAdjointBalancethicknessBoundary(void){
+
+	ElementMatrix* Ke=CreateKMatrixBalancethicknessBoundary();
+	if(Ke) Ke->Transpose();
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorPrognostic{{{*/
+ElementVector* Numericalflux::CreatePVectorPrognostic(void){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreatePVectorPrognosticInternal();
+		case BoundaryEnum:
+			return CreatePVectorPrognosticBoundary();
+		default:
+			_error_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorPrognosticInternal{{{*/
+ElementVector* Numericalflux::CreatePVectorPrognosticInternal(void){
+
+	/*Nothing added to PVector*/
+	return NULL;
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorPrognosticBoundary{{{*/
+ElementVector* Numericalflux::CreatePVectorPrognosticBoundary(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMNODES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,ig,index1,index2;
+	IssmDouble     DL,Jdet,dt,vx,vy,mean_vx,mean_vy,UdotN,thickness;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     normal[2];
+	IssmDouble     L[numdof];
+	GaussTria *gauss;
+
+	/*Initialize Load Vector and return if necessary*/
+	ElementVector* pe = NULL;
+	Tria*  tria=(Tria*)element;
+	if(tria->IsOnWater()) return NULL;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	Input* vxaverage_input   =tria->inputs->GetInput(VxEnum);                     _assert_(vxaverage_input); 
+	Input* vyaverage_input   =tria->inputs->GetInput(VyEnum);                     _assert_(vyaverage_input);
+	Input* spcthickness_input=tria->inputs->GetInput(PrognosticSpcthicknessEnum); _assert_(spcthickness_input);
+	GetNormal(&normal[0],xyz_list);
+
+	/*Check wether it is an inflow or outflow BC (0 is the middle of the segment)*/
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+
+	gauss=new GaussTria();
+	gauss->GaussEdgeCenter(index1,index2);
+	vxaverage_input->GetInputValue(&mean_vx,gauss);
+	vyaverage_input->GetInputValue(&mean_vy,gauss);
+	delete gauss;
+
+	UdotN=mean_vx*normal[0]+mean_vy*normal[1];
+	if (UdotN>0){
+		return NULL; /*(u,n)>0 -> outflow, PenaltyCreateKMatrix will take care of it*/
+	}
+	else{
+		pe=new ElementVector(nodes,NUMNODES_BOUNDARY,this->parameters);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(index1,index2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		tria->GetSegmentNodalFunctions(&L[0],gauss,index1,index2);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		spcthickness_input->GetInputValue(&thickness,gauss);
+		if(xIsNan<IssmDouble>(thickness)) _error_("Cannot weakly apply constraint because NaN was provided");
+
+		UdotN=vx*normal[0]+vy*normal[1];
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		DL= - gauss->weight*Jdet*dt*UdotN*thickness;
+
+		for(i=0;i<numdof;i++) pe->values[i] += DL*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorBalancethickness{{{*/
+ElementVector* Numericalflux::CreatePVectorBalancethickness(void){
+
+	int type;
+	inputs->GetInputValue(&type,NumericalfluxTypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreatePVectorBalancethicknessInternal();
+		case BoundaryEnum:
+			return CreatePVectorBalancethicknessBoundary();
+		default:
+			_error_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorBalancethicknessInternal{{{*/
+ElementVector* Numericalflux::CreatePVectorBalancethicknessInternal(void){
+
+	/*Nothing added to PVector*/
+	return NULL;
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorBalancethicknessBoundary{{{*/
+ElementVector* Numericalflux::CreatePVectorBalancethicknessBoundary(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMNODES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,ig,index1,index2;
+	IssmDouble DL,Jdet,vx,vy,mean_vx,mean_vy,UdotN,thickness;
+	IssmDouble xyz_list[NUMVERTICES][3];
+	IssmDouble normal[2];
+	IssmDouble L[numdof];
+	GaussTria *gauss;
+
+	/*Initialize Load Vector and return if necessary*/
+	ElementVector* pe = NULL;
+	Tria*  tria=(Tria*)element;
+	if(tria->IsOnWater()) return NULL;
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0],vertices,NUMVERTICES);
+	Input* vxaverage_input=tria->inputs->GetInput(VxEnum); _assert_(vxaverage_input); 
+	Input* vyaverage_input=tria->inputs->GetInput(VyEnum); _assert_(vyaverage_input);
+	Input* thickness_input=tria->inputs->GetInput(ThicknessEnum); _assert_(thickness_input);
+	GetNormal(&normal[0],xyz_list);
+
+	/*Check wether it is an inflow or outflow BC (0 is the middle of the segment)*/
+	index1=tria->GetNodeIndex(nodes[0]);
+	index2=tria->GetNodeIndex(nodes[1]);
+
+	gauss=new GaussTria();
+	gauss->GaussEdgeCenter(index1,index2);
+	vxaverage_input->GetInputValue(&mean_vx,gauss);
+	vyaverage_input->GetInputValue(&mean_vy,gauss);
+	delete gauss;
+	UdotN=mean_vx*normal[0]+mean_vy*normal[1];
+	if (UdotN>0){
+		return NULL; /*(u,n)>0 -> outflow, PenaltyCreateKMatrix will take care of it*/
+	}
+	else{
+		pe=new ElementVector(nodes,NUMNODES_BOUNDARY,this->parameters);
+	}
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(index1,index2,2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		tria->GetSegmentNodalFunctions(&L[0],gauss,index1,index2);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+		thickness_input->GetInputValue(&thickness,gauss);
+
+		UdotN=vx*normal[0]+vy*normal[1];
+		tria->GetSegmentJacobianDeterminant(&Jdet,&xyz_list[0][0],gauss);
+		DL= - gauss->weight*Jdet*UdotN*thickness;
+
+		for(i=0;i<numdof;i++) pe->values[i] += DL*L[i];
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreatePVectorAdjointBalancethickness{{{*/
+ElementVector* Numericalflux::CreatePVectorAdjointBalancethickness(void){
+
+	/*No PVector for the Adjoint*/
+	return NULL;
+}
+/*}}}*/
+/*FUNCTION Numericalflux::GetNormal {{{*/
+void Numericalflux:: GetNormal(IssmDouble* normal,IssmDouble xyz_list[4][3]){
+
+	/*Build unit outward pointing vector*/
+	IssmDouble vector[2];
+	IssmDouble norm;
+
+	vector[0]=xyz_list[1][0] - xyz_list[0][0];
+	vector[1]=xyz_list[1][1] - xyz_list[0][1];
+
+	norm=sqrt(pow(vector[0],2.0)+pow(vector[1],2.0));
+
+	normal[0]= + vector[1]/norm;
+	normal[1]= - vector[0]/norm;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Numericalflux.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Numericalflux.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Numericalflux.h	(revision 15012)
@@ -0,0 +1,100 @@
+/*!\file Numericalflux.h
+ * \brief: header file for icefront object
+ */
+
+#ifndef _NUMERICALFLUX_H_
+#define _NUMERICALFLUX_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Load.h"
+class Hook;
+class Parameters;
+class Inputs;
+class IoModel;
+class ElementMatrix;
+class ElementVector;
+/*}}}*/
+
+class Numericalflux: public Load {
+
+	public: 
+		int id;
+		int analysis_type;
+
+		/*Hooks*/
+		Hook *helement;
+		Hook *hnodes;
+		Hook *hvertices;
+
+		/*Corresponding fields*/
+		Element     *element;
+		Vertex     **vertices;
+		Node       **nodes;
+		Parameters  *parameters;
+		Inputs      *inputs;
+
+		/*Numericalflux constructors,destructors {{{*/
+		Numericalflux();
+		Numericalflux(int numericalflux_id,int i, IoModel* iomodel,int analysis_type);
+		~Numericalflux();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void InputUpdateFromVector(IssmDouble* vector, int name, int type){/*Do nothing*/}
+		void InputUpdateFromVector(int* vector, int name, int type){_error_("Not implemented yet!");}
+		void InputUpdateFromVector(bool* vector, int name, int type){_error_("Not implemented yet!");}
+		void InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){/*Do nothing*/}
+		void InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){/*Do nothing*/}
+		void InputUpdateFromVectorDakota(int* vector, int name, int type){_error_("Not implemented yet!");}
+		void InputUpdateFromVectorDakota(bool* vector, int name, int type){_error_("Not implemented yet!");}
+		void InputUpdateFromConstant(IssmDouble constant, int name){/*Do nothing*/};
+		void InputUpdateFromConstant(int constant, int name){/*Do nothing*/};
+		void InputUpdateFromConstant(bool constant, int name){_error_("Not implemented yet!");}
+		void InputUpdateFromSolution(IssmDouble* solution){_error_("Not implemented yet!");}
+		void InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("not implemented yet");};
+		/*}}}*/
+		/*Load virtual functions definitions: {{{*/
+		void Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void CreatePVector(Vector<IssmDouble>* pf);
+		void GetNodesSidList(int* sidlist);
+		int  GetNumberOfNodes(void);
+		void CreateJacobianMatrix(Matrix<IssmDouble>* Jff){_error_("Not implemented yet");};
+		bool IsPenalty(void);
+		void PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax){_error_("Not implemented yet");};
+		void PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* kfs, IssmDouble kmax);
+		void PenaltyCreatePVector(Vector<IssmDouble>* pf, IssmDouble kmax);
+		void SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		bool InAnalysis(int analysis_type);
+		/*}}}*/
+		/*Numericalflux management:{{{*/
+		void           GetNormal(IssmDouble* normal,IssmDouble xyz_list[4][3]);
+		ElementMatrix* CreateKMatrixPrognostic(void);
+		ElementMatrix* CreateKMatrixPrognosticInternal(void);
+		ElementMatrix* CreateKMatrixPrognosticBoundary(void);
+		ElementMatrix* CreateKMatrixBalancethickness(void);
+		ElementMatrix* CreateKMatrixBalancethicknessInternal(void);
+		ElementMatrix* CreateKMatrixBalancethicknessBoundary(void);
+		ElementMatrix* CreateKMatrixAdjointBalancethickness(void);
+		ElementMatrix* CreateKMatrixAdjointBalancethicknessInternal(void);
+		ElementMatrix* CreateKMatrixAdjointBalancethicknessBoundary(void);
+		ElementVector* CreatePVectorPrognostic(void);
+		ElementVector* CreatePVectorPrognosticInternal(void);
+		ElementVector* CreatePVectorPrognosticBoundary(void);
+		ElementVector* CreatePVectorBalancethickness(void);
+		ElementVector* CreatePVectorBalancethicknessInternal(void);
+		ElementVector* CreatePVectorBalancethicknessBoundary(void);
+		ElementVector* CreatePVectorAdjointBalancethickness(void);
+		/*}}}*/
+
+};
+
+#endif  /* _NUMERICALFLUX_H_ */
Index: /issm/trunk-jpl/src/c/classes/Loads/Pengrid.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Pengrid.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Pengrid.cpp	(revision 15012)
@@ -0,0 +1,775 @@
+/*!\file Pengrid.c
+ * \brief: implementation of the Pengrid object
+ */
+
+/*Headers*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES   1
+
+/*Pengrid constructors and destructor*/
+/*FUNCTION Pengrid::Pengrid(){{{*/
+Pengrid::Pengrid(){
+	this->inputs=NULL;
+	this->parameters=NULL;
+	this->hnode=NULL;
+	this->node=NULL;
+	this->helement=NULL;
+	this->element=NULL;
+	this->hmatpar=NULL;
+	this->matpar=NULL;
+
+	/*not active, not zigzagging: */
+	active=0;
+	zigzag_counter=0;
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::Pengrid(int index, int id, IoModel* iomodel,int analysis_type){{{*/
+Pengrid::Pengrid(int id, int index, IoModel* iomodel, int in_analysis_type){ //i is the element index
+
+	int pengrid_node_id;
+	int pengrid_matpar_id;
+	int pengrid_element_id;
+
+	int numberofvertices;
+	int numberofelements;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&numberofvertices,MeshNumberofverticesEnum);
+	iomodel->Constant(&numberofelements,MeshNumberofelementsEnum);
+
+	/*Some checks if debugging activated*/
+	_assert_(iomodel->singlenodetoelementconnectivity);
+	_assert_(index>=0 && index<numberofvertices);
+	_assert_(id);
+
+	/*id: */
+	this->id=id;
+	this->analysis_type=in_analysis_type;
+
+	/*hooks: */
+	pengrid_node_id=iomodel->nodecounter+index+1;
+	pengrid_element_id=iomodel->singlenodetoelementconnectivity[index];
+	_assert_(pengrid_element_id);
+	pengrid_matpar_id=numberofelements+1; //refers to the constant material parameters object
+
+	this->hnode=new Hook(&pengrid_node_id,1);
+	this->helement=new Hook(&pengrid_element_id,1);
+	this->hmatpar=new Hook(&pengrid_matpar_id,1);
+
+	//initialize inputs: none needed
+	this->inputs=new Inputs();
+
+	//this->parameters: we still can't point to it, it may not even exist. Configure will handle this.
+	this->parameters=NULL;
+	this->node=NULL;
+	this->element=NULL;
+	this->matpar=NULL;
+
+	//let's not forget internals
+	this->active=0;
+	this->zigzag_counter=0;
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::~Pengrid(){{{*/
+Pengrid::~Pengrid(){
+	delete inputs;
+	delete hnode;
+	delete helement;
+	delete hmatpar;
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Pengrid::Echo {{{*/
+void Pengrid::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION Pengrid::DeepEcho{{{*/
+void Pengrid::DeepEcho(void){
+
+	_printLine_("Pengrid:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnode->DeepEcho();
+	helement->DeepEcho();
+	hmatpar->DeepEcho();
+	_printLine_("   active " << this->active);
+	_printLine_("   zigzag_counter " << this->zigzag_counter);
+	_printLine_("   parameters");
+	parameters->DeepEcho();
+	_printLine_("   inputs");
+	inputs->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION Pengrid::Id {{{*/
+int    Pengrid::Id(void){ return id; }
+/*}}}*/
+/*FUNCTION Pengrid::ObjectEnum{{{*/
+int Pengrid::ObjectEnum(void){
+
+	return PengridEnum;
+}
+/*}}}*/
+/*FUNCTION Icefront::copy {{{*/
+Object* Pengrid::copy() {
+
+	Pengrid* pengrid=NULL;
+
+	pengrid=new Pengrid();
+
+	/*copy fields: */
+	pengrid->id=this->id;
+	pengrid->analysis_type=this->analysis_type;
+	if(this->inputs){
+		pengrid->inputs=(Inputs*)this->inputs->Copy();
+	}
+	else{
+		pengrid->inputs=new Inputs();
+	}
+	/*point parameters: */
+	pengrid->parameters=this->parameters;
+
+	/*now deal with hooks and objects: */
+	pengrid->hnode=(Hook*)this->hnode->copy();
+	pengrid->hmatpar=(Hook*)this->hmatpar->copy();
+	pengrid->helement=(Hook*)this->helement->copy();
+
+	/*corresponding fields*/
+	pengrid->node  =(Node*)pengrid->hnode->delivers();
+	pengrid->matpar =(Matpar*)pengrid->hmatpar->delivers();
+	pengrid->element=(Element*)pengrid->helement->delivers();
+
+	//let's not forget internals
+	pengrid->active=this->active=0;
+	pengrid->zigzag_counter=this->zigzag_counter=0;
+
+	return pengrid;
+
+}
+/*}}}*/
+
+/*Load virtual functions definitions:*/
+/*FUNCTION Pengrid::Configure {{{*/
+void  Pengrid::Configure(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+	/*Take care of hooking up all objects for this load, ie links the objects in the hooks to their respective 
+	 * datasets, using internal ids and offsets hidden in hooks: */
+	hnode->configure(nodesin);
+	helement->configure(elementsin);
+	hmatpar->configure(materialsin);
+
+	/*Get corresponding fields*/
+	node=(Node*)hnode->delivers();
+	element=(Element*)helement->delivers();
+	matpar=(Matpar*)hmatpar->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+}
+/*}}}*/
+/*FUNCTION Pengrid::SetCurrentConfiguration {{{*/
+void  Pengrid::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::CreateKMatrix {{{*/
+void  Pengrid::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::CreatePVector {{{*/
+void  Pengrid::CreatePVector(Vector<IssmDouble>* pf){
+
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::GetNodesSidList{{{*/
+void Pengrid::GetNodesSidList(int* sidlist){
+
+	_assert_(sidlist);
+	_assert_(node);
+
+	sidlist[0]=node->Sid();
+}
+/*}}}*/
+/*FUNCTION Pengrid::GetNumberOfNodes{{{*/
+int Pengrid::GetNumberOfNodes(void){
+
+	return NUMVERTICES;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreateMatrix {{{*/
+void  Pengrid::PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs,IssmDouble kmax){
+
+	/*Retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
+			Ke=PenaltyCreateKMatrixDiagnosticStokes(kmax);
+			break;
+		#endif
+		#ifdef _HAVE_THERMAL_
+		case ThermalAnalysisEnum:
+			Ke=PenaltyCreateKMatrixThermal(kmax);
+			break;
+		case MeltingAnalysisEnum:
+			Ke=PenaltyCreateKMatrixMelting(kmax);
+			break;
+		#endif
+		#ifdef _HAVE_HYDROLOGY_
+		case HydrologyDCInefficientAnalysisEnum:
+			Ke=PenaltyCreateKMatrixHydrologyDCInefficient(kmax);
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreatePVector {{{*/
+void  Pengrid::PenaltyCreatePVector(Vector<IssmDouble>* pf,IssmDouble kmax){
+
+	/*Retrieve parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		#ifdef _HAVE_THERMAL_
+		case ThermalAnalysisEnum:
+			pe=PenaltyCreatePVectorThermal(kmax);
+			break;
+		case MeltingAnalysisEnum:
+			pe=PenaltyCreatePVectorMelting(kmax);
+			break;
+		case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
+			break;
+		#endif
+		#ifdef _HAVE_HYDROLOGY_
+		case HydrologyDCInefficientAnalysisEnum:
+			pe=PenaltyCreatePVectorHydrologyDCInefficient(kmax);
+			break;
+		#endif
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+}
+/*}}}*/
+/*FUNCTION Pengrid::InAnalysis{{{*/
+bool Pengrid::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type)return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Pengrid::IsPenalty{{{*/
+bool Pengrid::IsPenalty(void){
+	return true;
+}
+/*}}}*/
+/*FUNCTION Pengrid::SetwiseNodeConnectivity{{{*/
+void Pengrid::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	if(!flags[this->node->Sid()]){
+
+		/*flag current node so that no other element processes it*/
+		flags[this->node->Sid()]=true;
+
+		/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+		switch(set2_enum){
+			case FsetEnum:
+				if(node->indexing.fsize){
+					if(this->node->IsClone())
+					 o_nz += 1;
+					else
+					 d_nz += 1;
+				}
+				break;
+			case GsetEnum:
+				if(node->indexing.gsize){
+					if(this->node->IsClone())
+					 o_nz += 1;
+					else
+					 d_nz += 1;
+				}
+				break;
+			case SsetEnum:
+				if(node->indexing.ssize){
+					if(this->node->IsClone())
+					 o_nz += 1;
+					else
+					 d_nz += 1;
+				}
+				break;
+			default: _error_("not supported");
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+
+/*Update virtual functions definitions:*/
+/*FUNCTION Pengrid::InputUpdateFromVector(IssmDouble* vector, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromVector(int* vector, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromVector(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromVector(bool* vector, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromVector(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromMatrixDakota(IssmDouble* vector, int nrows, int ncols, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromVectorDakota(int* vector, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromVectorDakota(bool* vector, int name, int type) {{{*/
+void  Pengrid::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromConstant(IssmDouble constant, int name) {{{*/
+void  Pengrid::InputUpdateFromConstant(IssmDouble constant, int name){
+	switch(name){
+
+		case MeltingOffsetEnum:
+			inputs->AddInput(new DoubleInput(name,constant));
+			return;
+
+	}
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromConstant(int constant, int name) {{{*/
+void  Pengrid::InputUpdateFromConstant(int constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromConstant(bool constant, int name) {{{*/
+void  Pengrid::InputUpdateFromConstant(bool constant, int name){
+
+	switch(name){
+
+		case ResetPenaltiesEnum:
+			if (constant) zigzag_counter=0;
+			return;
+
+	}
+}
+/*}}}*/
+/*FUNCTION Pengrid::InputUpdateFromSolution{{{*/
+void  Pengrid::InputUpdateFromSolution(IssmDouble* solution){
+	/*Nothing updated yet*/
+}
+/*}}}*/		
+
+/*Pengrid management:*/
+/*FUNCTION Pengrid::ConstraintActivate {{{*/
+void  Pengrid::ConstraintActivate(int* punstable){
+
+	int analysis_type;
+
+	/*Retrieve parameters: */
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	if (analysis_type==DiagnosticHorizAnalysisEnum){
+		/*No penalty to check*/
+		return;
+	}
+	#ifdef _HAVE_THERMAL_
+	else if (analysis_type==ThermalAnalysisEnum){
+		ConstraintActivateThermal(punstable);
+	}
+	else if (analysis_type==MeltingAnalysisEnum){
+		/*No penalty to check*/
+		return;
+	}
+	#endif
+	#ifdef _HAVE_HYDROLOGY_
+	else if (analysis_type==HydrologyDCInefficientAnalysisEnum){
+		ConstraintActivateHydrologyDCInefficient(punstable);
+		return;
+	}
+	#endif
+	else{
+		_error_("analysis: " << EnumToStringx(analysis_type) << " not supported yet");
+	}
+
+}
+/*}}}*/
+#ifdef _HAVE_DIAGNOSTIC_
+/*FUNCTION Pengrid::PenaltyCreateKMatrixDiagnosticStokes {{{*/
+ElementMatrix* Pengrid::PenaltyCreateKMatrixDiagnosticStokes(IssmDouble kmax){
+
+	const int numdof = NUMVERTICES *NDOF4;
+	IssmDouble    slope[2];
+	IssmDouble    penalty_offset;
+	int       approximation;
+
+	Penta* penta=(Penta*)element;
+
+	/*Initialize Element vector and return if necessary*/
+	penta->inputs->GetInputValue(&approximation,ApproximationEnum);
+	if(approximation!=StokesApproximationEnum &&  approximation!=PattynStokesApproximationEnum) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(&node,1,this->parameters,StokesApproximationEnum);
+
+	/*Retrieve all inputs and parameters*/
+	parameters->FindParam(&penalty_offset,DiagnosticPenaltyFactorEnum);
+	penta->GetInputValue(&slope[0],node,BedSlopeXEnum);
+	penta->GetInputValue(&slope[1],node,BedSlopeYEnum);
+
+	/*Create elementary matrix: add penalty to constrain wb (wb=ub*db/dx+vb*db/dy)*/
+	Ke->values[2*NDOF4+0]=-slope[0]*kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[2*NDOF4+1]=-slope[1]*kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[2*NDOF4+2]= kmax*pow((IssmDouble)10,penalty_offset);
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,&node,NUMVERTICES,XYZPEnum);
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+#endif
+#ifdef _HAVE_THERMAL_
+/*FUNCTION Pengrid::ConstraintActivateThermal {{{*/
+void  Pengrid::ConstraintActivateThermal(int* punstable){
+
+	//   The penalty is stable if it doesn't change during to successive iterations.   
+
+	int        found=0;
+	const int  numnodes=1;
+	IssmDouble pressure;
+	IssmDouble temperature;
+	IssmDouble t_pmp;
+	int        new_active;
+	int        unstable=0;
+	int        reset_penalties=0;
+	int        penalty_lock;
+
+	/*recover pointers: */
+	Penta* penta=(Penta*)element;
+
+	/*check that pengrid is not a clone (penalty to be added only once)*/
+	if (node->IsClone()){
+		unstable=0;
+		*punstable=unstable;
+		return;
+	}
+
+	//First recover pressure and temperature values, using the element: */
+	penta->GetInputValue(&pressure,node,PressureEnum);
+	penta->GetInputValue(&temperature,node,TemperaturePicardEnum);
+
+	//Recover our data:
+	parameters->FindParam(&penalty_lock,ThermalPenaltyLockEnum);
+
+	//Compute pressure melting point
+	t_pmp=matpar->TMeltingPoint(pressure);
+
+	//Figure out if temperature is over melting_point, in which case, this penalty needs to be activated.
+
+	if (temperature>t_pmp){
+		new_active=1;
+	}
+	else{
+		new_active=0;
+	}
+
+	//Figure out stability of this penalty
+	if (active==new_active){
+		unstable=0;
+	}
+	else{
+		unstable=1;
+		if(penalty_lock)zigzag_counter++;
+	}
+
+	/*If penalty keeps zigzagging more than 5 times: */
+	if(penalty_lock){
+		if(zigzag_counter>penalty_lock){
+			unstable=0;
+			active=1;
+		}
+	}
+
+	//Set penalty flag
+	active=new_active;
+
+	//*Assign output pointers:*/
+	*punstable=unstable;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreateKMatrixMelting {{{*/
+ElementMatrix* Pengrid::PenaltyCreateKMatrixMelting(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF1;
+	IssmDouble pressure,temperature,t_pmp;
+	IssmDouble penalty_factor;
+
+	Penta* penta=(Penta*)element;
+
+	/*check that pengrid is not a clone (penalty to be added only once)*/
+	if (node->IsClone()) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(&node,1,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	penta->GetInputValue(&pressure,node,PressureEnum);
+	penta->GetInputValue(&temperature,node,TemperatureEnum);
+	parameters->FindParam(&penalty_factor,ThermalPenaltyFactorEnum);
+
+	/*Compute pressure melting point*/
+	t_pmp=matpar->GetMeltingPoint()-matpar->GetBeta()*pressure;
+
+	/*Add penalty load*/
+	if (temperature<t_pmp){ //If T<Tpmp, there must be no melting. Therefore, melting should be  constrained to 0 when T<Tpmp, instead of using spcs, use penalties
+		Ke->values[0]=kmax*pow((IssmDouble)10,penalty_factor);
+	}
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreateKMatrixThermal {{{*/
+ElementMatrix* Pengrid::PenaltyCreateKMatrixThermal(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF1;
+	IssmDouble    penalty_factor;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(!this->active) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(&node,NUMVERTICES,this->parameters);
+
+	/*recover parameters: */
+	parameters->FindParam(&penalty_factor,ThermalPenaltyFactorEnum);
+
+	Ke->values[0]=kmax*pow((IssmDouble)10,penalty_factor);
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreatePVectorMelting {{{*/
+ElementVector* Pengrid::PenaltyCreatePVectorMelting(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF1;
+	IssmDouble pressure;
+	IssmDouble temperature;
+	IssmDouble melting_offset;
+	IssmDouble t_pmp;
+	IssmDouble dt,penalty_factor;
+
+	/*recover pointers: */
+	Penta* penta=(Penta*)element;
+
+	/*check that pengrid is not a clone (penalty to be added only once)*/
+	if (node->IsClone()) return NULL;
+	ElementVector* pe=new ElementVector(&node,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	penta->GetInputValue(&pressure,node,PressureEnum);
+	penta->GetInputValue(&temperature,node,TemperatureEnum);
+	inputs->GetInputValue(&melting_offset,MeltingOffsetEnum);
+	parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	parameters->FindParam(&penalty_factor,ThermalPenaltyFactorEnum);
+
+	/*Compute pressure melting point*/
+	t_pmp=matpar->GetMeltingPoint()-matpar->GetBeta()*pressure;
+
+	/*Add penalty load
+	  This time, the penalty must have the same value as the one used for the thermal computation
+	  so that the corresponding melting can be computed correctly
+	  In the thermal computation, we used kmax=melting_offset, and the same penalty_factor*/
+	if (temperature<t_pmp){ //%no melting
+		pe->values[0]=0;
+	}
+	else{
+		if (reCast<bool>(dt)) pe->values[0]=melting_offset*pow((IssmDouble)10,penalty_factor)*(temperature-t_pmp)/dt;
+		else    pe->values[0]=melting_offset*pow((IssmDouble)10,penalty_factor)*(temperature-t_pmp);
+	}
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreatePVectorThermal {{{*/
+ElementVector* Pengrid::PenaltyCreatePVectorThermal(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF1;
+	IssmDouble pressure;
+	IssmDouble t_pmp;
+	IssmDouble penalty_factor;
+
+	Penta* penta=(Penta*)element;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(!this->active) return NULL;
+	ElementVector* pe=new ElementVector(&node,1,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	penta->GetInputValue(&pressure,node,PressureEnum);
+	parameters->FindParam(&penalty_factor,ThermalPenaltyFactorEnum);
+
+	/*Compute pressure melting point*/
+	t_pmp=matpar->GetMeltingPoint()-matpar->GetBeta()*pressure;
+
+	pe->values[0]=kmax*pow((IssmDouble)10,penalty_factor)*t_pmp;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+#endif
+#ifdef _HAVE_HYDROLOGY_
+/*FUNCTION Pengrid::ConstraintActivateHydrologyDCInefficient{{{*/
+void  Pengrid::ConstraintActivateHydrologyDCInefficient(int* punstable){
+
+	//   The penalty is stable if it doesn't change during two consecutive iterations.   
+	const int  numnodes        = 1;
+	int        unstable        = 0;
+	int        reset_penalties = 0;
+	int        found           = 0;	
+	int        penalty_lock;
+	int        new_active;
+	IssmDouble pressure;
+	IssmDouble h;
+	IssmDouble h_max;	
+
+	/*check that pengrid is not a clone (penalty to be added only once)*/
+	if(node->IsClone()){
+		unstable=0;
+		*punstable=unstable;
+		return;
+	}
+
+	/*Get sediment water head h*/
+	element->GetInputValue(&h,node,SedimentHeadEnum);
+	element->GetHydrologyDCInefficientHmax(&h_max,node);
+
+	if (h>h_max)
+	 new_active=1;
+	else
+	 new_active=0;
+
+	if(this->active==new_active)
+	 unstable=0;
+	else
+	 unstable=1;
+
+	/*Set penalty flag*/
+	this->active=new_active;
+
+	/*Assign output pointers:*/
+	*punstable=unstable;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreateKMatrixHydrologyDCInefficient {{{*/
+ElementMatrix* Pengrid::PenaltyCreateKMatrixHydrologyDCInefficient(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF1;
+	IssmDouble    penalty_factor;
+
+	/*Retrieve parameters*/
+	parameters->FindParam(&penalty_factor,HydrologydcPenaltyFactorEnum);
+
+	/*Initialize Element matrix and return if necessary*/
+	if(!this->active) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(&node,NUMVERTICES,this->parameters);
+
+	Ke->values[0]=kmax*pow(10.,penalty_factor);
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreatePVectorHydrologyDCInefficient {{{*/
+ElementVector* Pengrid::PenaltyCreatePVectorHydrologyDCInefficient(IssmDouble kmax){
+
+	const int  numdof=NUMVERTICES*NDOF1;
+	IssmDouble h_max;
+	IssmDouble penalty_factor;
+
+	/*Initialize Element matrix and return if necessary*/
+	if(!this->active) return NULL;
+	ElementVector* pe=new ElementVector(&node,1,this->parameters);
+
+	/*Retrieve parameters*/
+	parameters->FindParam(&penalty_factor,HydrologydcPenaltyFactorEnum);
+
+	/*Get h_max and compute penalty*/
+	element->GetHydrologyDCInefficientHmax(&h_max,node);
+	pe->values[0]=kmax*pow(10.,penalty_factor)*h_max;
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+#endif
+/*FUNCTION Pengrid::ResetConstraint {{{*/
+void  Pengrid::ResetConstraint(void){
+	active=0;
+	zigzag_counter=0;
+}
+/*}}}*/
+/*FUNCTION Pengrid::UpdateInputs {{{*/
+void  Pengrid::UpdateInputs(IssmDouble* solution){
+	_error_("not supported yet!");
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Pengrid.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Pengrid.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Pengrid.h	(revision 15012)
@@ -0,0 +1,111 @@
+/*!\file Pengrid.h
+ * \brief: header file for pengrid object */
+
+#ifndef _PENGRID_H_
+#define _PENGRID_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+#include "./Load.h"
+class Hook;
+class Inputs;
+class Parameters;
+class IoModel;
+/*}}}*/
+
+class Pengrid: public Load{
+
+	private: 
+
+		int		id;
+		int analysis_type;
+
+		/*Hooks*/
+		Hook* hnode;  //hook to 1 node
+		Hook* helement;  //hook to 1 element
+		Hook* hmatpar; //hook to 1 matpar
+
+		/*Corresponding fields*/
+		Node    *node;
+		Element *element;
+		Matpar  *matpar;
+
+		Parameters* parameters; //pointer to solution parameters
+		Inputs*  inputs;
+
+		/*internals: */
+		int active;
+		int zigzag_counter;
+
+	public:
+
+		/*Pengrid constructors, destructors {{{*/
+		Pengrid();
+		Pengrid(int index, int id, IoModel* iomodel,int analysis_type);
+		~Pengrid();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix ,int nrows, int ncols, int name, int type);
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solution);
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("not implemented yet");};
+		/*}}}*/
+		/*Load virtual functions definitions: {{{*/
+		void  Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void  CreatePVector(Vector<IssmDouble>* pf);
+		void  CreateJacobianMatrix(Matrix<IssmDouble>* Jff){_error_("Not implemented yet");};
+		void  GetNodesSidList(int* sidlist);
+		int   GetNumberOfNodes(void);
+		bool  IsPenalty(void);
+		void  PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax){_error_("Not implemented yet");};
+		void  PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector<IssmDouble>* pf, IssmDouble kmax);
+		void  SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		bool  InAnalysis(int analysis_type);
+		/*}}}*/
+		/*Pengrid management {{{*/
+		#ifdef _HAVE_DIAGNOSTIC_
+		ElementMatrix* PenaltyCreateKMatrixDiagnosticStokes(IssmDouble kmax);
+		#endif
+		#ifdef _HAVE_THERMAL_
+		ElementMatrix* PenaltyCreateKMatrixThermal(IssmDouble kmax);
+		ElementMatrix* PenaltyCreateKMatrixMelting(IssmDouble kmax);
+		ElementVector* PenaltyCreatePVectorThermal(IssmDouble kmax);
+		ElementVector* PenaltyCreatePVectorMelting(IssmDouble kmax);
+		void           ConstraintActivateThermal(int* punstable);
+		#endif
+		#ifdef _HAVE_HYDROLOGY_
+		ElementMatrix* PenaltyCreateKMatrixHydrologyDCInefficient(IssmDouble kmax);
+		ElementVector* PenaltyCreatePVectorHydrologyDCInefficient(IssmDouble kmax);
+		void           ConstraintActivateHydrologyDCInefficient(int* punstable);
+		#endif
+		void  ConstraintActivate(int* punstable);
+		void  UpdateInputs(IssmDouble* solution);
+		void  ResetConstraint(void);
+		/*}}}*/
+
+};
+
+#endif  /* _PENGRID_H_ */
Index: /issm/trunk-jpl/src/c/classes/Loads/Penpair.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Penpair.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Penpair.cpp	(revision 15012)
@@ -0,0 +1,414 @@
+/*!\file Penpair.c
+ * \brief: implementation of the Penpair object
+ */
+
+/*Headers*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES 2
+
+/*Penpair constructors and destructor*/
+/*FUNCTION Penpair::constructor {{{*/
+Penpair::Penpair(){
+
+	this->hnodes=NULL;
+	this->nodes=NULL;
+	this->parameters=NULL;
+	return;
+}
+/*}}}*/
+/*FUNCTION Penpair::creation {{{*/
+Penpair::Penpair(int penpair_id, int* penpair_node_ids,int in_analysis_type){
+
+	this->id=penpair_id;
+	this->analysis_type=in_analysis_type;
+	this->hnodes=new Hook(penpair_node_ids,2);
+	this->parameters=NULL;
+	this->nodes=NULL;
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Penpair::destructor {{{*/
+Penpair::~Penpair(){
+	delete hnodes;
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Penpair::Echo {{{*/
+void Penpair::Echo(void){
+
+	_printLine_("Penpair:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->Echo();
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Penpair::DeepEcho {{{*/
+void Penpair::DeepEcho(void){
+
+	_printLine_("Penpair:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->DeepEcho();
+
+	return;
+}		
+/*}}}*/
+/*FUNCTION Penpair::Id {{{*/
+int    Penpair::Id(void){ return id; }
+/*}}}*/
+/*FUNCTION Penpair::ObjectEnum{{{*/
+int Penpair::ObjectEnum(void){
+
+	return PenpairEnum;
+}
+/*}}}*/
+/*FUNCTION Penpair::copy {{{*/
+Object* Penpair::copy() {
+
+	Penpair* penpair=NULL;
+
+	penpair=new Penpair();
+
+	/*copy fields: */
+	penpair->id=this->id;
+	penpair->analysis_type=this->analysis_type;
+
+	/*now deal with hooks and objects: */
+	penpair->hnodes=(Hook*)this->hnodes->copy();
+	penpair->nodes =(Node**)penpair->hnodes->deliverp();
+
+	/*point parameters: */
+	penpair->parameters=this->parameters;
+
+	return penpair;
+
+}
+/*}}}*/
+
+/*Load virtual functions definitions:*/
+/*FUNCTION Penpair::Configure {{{*/
+void  Penpair::Configure(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+	/*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: */
+	hnodes->configure((DataSet*)nodesin);
+
+	/*Initialize hooked fields*/
+	this->nodes  =(Node**)hnodes->deliverp();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+
+}
+/*}}}*/
+/*FUNCTION Penpair::SetCurrentConfiguration {{{*/
+void  Penpair::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Penpair::CreateKMatrix {{{*/
+void  Penpair::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+	/*If you code this piece, don't forget that a penalty will be inactive if it is dealing with clone nodes*/
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Penpair::CreatePVector {{{*/
+void  Penpair::CreatePVector(Vector<IssmDouble>* pf){
+
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Penpair::CreateJacobianMatrix{{{*/
+void  Penpair::CreateJacobianMatrix(Matrix<IssmDouble>* Jff){
+	this->CreateKMatrix(Jff,NULL);
+}
+/*}}}*/
+/*FUNCTION Penpair::GetNodesSidList{{{*/
+void Penpair::GetNodesSidList(int* sidlist){
+
+	_assert_(sidlist);
+	_assert_(nodes);
+
+	for(int i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->Sid();
+}
+/*}}}*/
+/*FUNCTION Penpair::GetNumberOfNodes{{{*/
+int Penpair::GetNumberOfNodes(void){
+
+	return NUMVERTICES;
+}
+/*}}}*/
+/*FUNCTION Penpair::IsPenalty{{{*/
+bool Penpair::IsPenalty(void){
+	return true;
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateKMatrix {{{*/
+void  Penpair::PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs,IssmDouble kmax){
+
+	/*Retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		case DiagnosticHorizAnalysisEnum:
+			Ke=PenaltyCreateKMatrixDiagnosticHoriz(kmax);
+			break;
+		case PrognosticAnalysisEnum:
+			Ke=PenaltyCreateKMatrixPrognostic(kmax);
+			break;
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreatePVector {{{*/
+void  Penpair::PenaltyCreatePVector(Vector<IssmDouble>* pf,IssmDouble kmax){
+	/*No loads applied, do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateJacobianMatrix{{{*/
+void  Penpair::PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax){
+	this->PenaltyCreateKMatrix(Jff,NULL,kmax);
+}
+/*}}}*/
+/*FUNCTION Penpair::InAnalysis{{{*/
+bool Penpair::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type)return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Penpair::SetwiseNodeConnectivity{{{*/
+void Penpair::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	/*Loop over all nodes*/
+	for(int i=0;i<NUMVERTICES;i++){
+
+		if(!flags[this->nodes[i]->Sid()]){
+
+			/*flag current node so that no other element processes it*/
+			flags[this->nodes[i]->Sid()]=true;
+
+			/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+			switch(set2_enum){
+				case FsetEnum:
+					if(nodes[i]->indexing.fsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case GsetEnum:
+					if(nodes[i]->indexing.gsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case SsetEnum:
+					if(nodes[i]->indexing.ssize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				default: _error_("not supported");
+			}
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+
+/*Update virtual functions definitions:*/
+/*FUNCTION Penpair::InputUpdateFromConstant(IssmDouble constant, int name) {{{*/
+void  Penpair::InputUpdateFromConstant(IssmDouble constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Penpair::InputUpdateFromConstant(int constant, int name) {{{*/
+void  Penpair::InputUpdateFromConstant(int constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Penpair::InputUpdateFromConstant(bool constant, int name) {{{*/
+void  Penpair::InputUpdateFromConstant(bool constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Penpair::InputUpdateFromVector(IssmDouble* vector, int name, int type) {{{*/
+void  Penpair::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Penpair::InputUpdateFromVector(int* vector, int name, int type) {{{*/
+void  Penpair::InputUpdateFromVector(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Penpair::InputUpdateFromVector(bool* vector, int name, int type) {{{*/
+void  Penpair::InputUpdateFromVector(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+
+/*Penpair management:*/
+/*FUNCTION Penpair::PenaltyCreateKMatrixDiagnosticHoriz{{{*/
+ElementMatrix* Penpair::PenaltyCreateKMatrixDiagnosticHoriz(IssmDouble kmax){
+
+	int    approximation0=nodes[0]->GetApproximation();
+	int    approximation1=nodes[1]->GetApproximation();
+
+	switch(approximation0){
+		case MacAyealApproximationEnum:
+			switch(approximation1){
+				case MacAyealApproximationEnum: return PenaltyCreateKMatrixDiagnosticMacAyealPattyn(kmax); 
+				case PattynApproximationEnum:   return PenaltyCreateKMatrixDiagnosticMacAyealPattyn(kmax); 
+				default: _error_("not supported yet");
+			}
+		case PattynApproximationEnum:
+			switch(approximation1){
+				case MacAyealApproximationEnum: return PenaltyCreateKMatrixDiagnosticMacAyealPattyn(kmax); 
+				case PattynApproximationEnum:   return PenaltyCreateKMatrixDiagnosticMacAyealPattyn(kmax); 
+				default: _error_("not supported yet");
+			}
+		case StokesApproximationEnum:
+			switch(approximation1){
+				case StokesApproximationEnum: return PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				case NoneApproximationEnum: return   PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				default: _error_("not supported yet");
+			}
+		case NoneApproximationEnum:
+			switch(approximation1){
+				case StokesApproximationEnum: return PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				case NoneApproximationEnum: return   PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				default: _error_("not supported yet");
+			}
+		default: _error_("not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateKMatrixDiagnosticMacAyealPattyn {{{*/
+ElementMatrix* Penpair::PenaltyCreateKMatrixDiagnosticMacAyealPattyn(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF2;
+	IssmDouble penalty_offset;
+
+	/*Initialize Element vector and return if necessary*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters);
+
+	/*recover parameters: */
+	parameters->FindParam(&penalty_offset,DiagnosticPenaltyFactorEnum);
+
+	//Create elementary matrix: add penalty to 
+	Ke->values[0*numdof+0]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[0*numdof+2]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[2*numdof+0]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[2*numdof+2]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+
+	Ke->values[1*numdof+1]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[1*numdof+3]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[3*numdof+1]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[3*numdof+3]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateKMatrixDiagnosticStokes {{{*/
+ElementMatrix* Penpair::PenaltyCreateKMatrixDiagnosticStokes(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF4;
+	IssmDouble penalty_offset;
+
+	/*Initialize Element vector and return if necessary*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters);
+
+	/*recover parameters: */
+	parameters->FindParam(&penalty_offset,DiagnosticPenaltyFactorEnum);
+
+	//Create elementary matrix: add penalty to 
+	Ke->values[0*numdof+0]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[0*numdof+4]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[4*numdof+0]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[4*numdof+4]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+
+	Ke->values[1*numdof+1]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[1*numdof+5]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[5*numdof+1]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[5*numdof+5]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+
+	Ke->values[2*numdof+2]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[2*numdof+6]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[6*numdof+2]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[6*numdof+6]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+
+	Ke->values[3*numdof+3]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[3*numdof+7]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[7*numdof+3]=-kmax*pow((IssmDouble)10.0,penalty_offset);
+	Ke->values[7*numdof+7]=+kmax*pow((IssmDouble)10.0,penalty_offset);
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateKMatrixPrognostic {{{*/
+ElementMatrix* Penpair::PenaltyCreateKMatrixPrognostic(IssmDouble kmax){
+
+	const int numdof=NUMVERTICES*NDOF1;
+	IssmDouble penalty_factor;
+
+	/*Initialize Element vector and return if necessary*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters);
+
+	/*recover parameters: */
+	parameters->FindParam(&penalty_factor,PrognosticPenaltyFactorEnum);
+
+	//Create elementary matrix: add penalty to 
+	Ke->values[0*numdof+0]=+kmax*pow((IssmDouble)10.0,penalty_factor);
+	Ke->values[0*numdof+1]=-kmax*pow((IssmDouble)10.0,penalty_factor);
+	Ke->values[1*numdof+0]=-kmax*pow((IssmDouble)10.0,penalty_factor);
+	Ke->values[1*numdof+1]=+kmax*pow((IssmDouble)10.0,penalty_factor);
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Penpair.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Penpair.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Penpair.h	(revision 15012)
@@ -0,0 +1,76 @@
+/*!\file Penpair.h
+ * \brief: header file for penpair object */
+
+#ifndef _PENPAIR_H_
+#define _PENPAIR_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Load.h"
+#include "../Node.h"
+#include "../Elements/Element.h"
+
+class Element;
+/*}}}*/
+
+class Penpair: public Load{
+
+	private: 
+		int          id;
+		int          analysis_type;
+		Hook        *hnodes;          //hook to 2 nodes
+		Node       **nodes;
+		Parameters  *parameters;      //pointer to solution parameters
+
+	public:
+
+		/*Penpair constructors, destructors: {{{*/
+		Penpair();
+		Penpair(int penpair_id,int* penpair_node_ids,int analysis_type);
+		~Penpair();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrow, int ncols,int name, int type){_error_("Not implemented yet!");}
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){_error_("Not implemented yet!");}
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type){_error_("Not implemented yet!");}
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type){_error_("Not implemented yet!");}
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solution){_error_("Not implemented yet!");}
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("not implemented yet");};
+		/*}}}*/
+			/*Load virtual functions definitions: {{{*/
+		void  Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void  CreatePVector(Vector<IssmDouble>* pf);
+		void  CreateJacobianMatrix(Matrix<IssmDouble>* Jff);
+		void  GetNodesSidList(int* sidlist);
+		int   GetNumberOfNodes(void);
+		bool  IsPenalty(void);
+		void  PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff,Matrix<IssmDouble>* Kfs,IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector<IssmDouble>* pf, IssmDouble kmax);
+		void  PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax);
+		void  SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		bool  InAnalysis(int analysis_type);
+		/*}}}*/
+			/*Penpair management: {{{*/
+		ElementMatrix* PenaltyCreateKMatrixDiagnosticHoriz(IssmDouble kmax);
+		ElementMatrix* PenaltyCreateKMatrixDiagnosticMacAyealPattyn(IssmDouble kmax);
+		ElementMatrix* PenaltyCreateKMatrixDiagnosticStokes(IssmDouble kmax);
+		ElementMatrix* PenaltyCreateKMatrixPrognostic(IssmDouble kmax);
+		/*}}}*/
+};
+
+#endif  /* _PENPAIR_H_ */
Index: /issm/trunk-jpl/src/c/classes/Loads/Riftfront.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Riftfront.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Riftfront.cpp	(revision 15012)
@@ -0,0 +1,961 @@
+/*!\file Riftfront.cpp
+ * \brief: implementation of the Riftfront object
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "shared/shared.h"
+#include "modules/ModelProcessorx/ModelProcessorx.h"
+#include "../classes.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES 2
+
+/*Riftfront constructors and destructor*/
+/*FUNCTION Riftfront::Riftfront(){{{*/
+Riftfront::Riftfront(){
+	this->inputs=NULL;
+	this->parameters=NULL;
+	this->hnodes=NULL;
+	this->helements=NULL;
+	this->hmatpar=NULL;
+	this->nodes=NULL;
+	this->elements=NULL;
+	this->matpar=NULL;
+}
+/*}}}*/
+/*FUNCTION Riftfront::Riftfront(int id, int i, IoModel* iomodel,int analysis_type){{{*/
+Riftfront::Riftfront(int riftfront_id,int i, IoModel* iomodel,int riftfront_analysis_type){
+
+	/*data: */
+	int    riftfront_node_ids[2];
+	int    riftfront_elem_ids[2];
+	int    riftfront_matpar_id;
+	int    riftfront_type;
+	int    riftfront_fill;
+	IssmDouble riftfront_friction;
+	IssmDouble riftfront_fractionincrement;
+	bool   riftfront_shelf;
+	int    numberofelements;
+	int    penalty_lock;
+
+	/*intermediary: */
+	int el1    ,el2;
+	int node1  ,node2;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&numberofelements,MeshNumberofelementsEnum);
+	iomodel->Constant(&penalty_lock,DiagnosticRiftPenaltyLockEnum);
+
+	/*Ok, retrieve all the data needed to add a penalty between the two nodes: */
+	el1=reCast<int,IssmDouble>(*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+2));
+	el2=reCast<int,IssmDouble>(*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+3)) ;
+
+	node1=reCast<int,IssmDouble>(*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+0));
+	node2=reCast<int,IssmDouble>(*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+1));
+
+	/*id: */
+	this->id=riftfront_id;
+	this->analysis_type=riftfront_analysis_type;
+
+	/*hooks: */
+	riftfront_node_ids[0]=iomodel->nodecounter+node1;
+	riftfront_node_ids[1]=iomodel->nodecounter+node2;
+	riftfront_elem_ids[0]=el1;
+	riftfront_elem_ids[1]=el2;
+	riftfront_matpar_id=numberofelements+1; //matlab indexing
+
+	/*Hooks: */
+	this->hnodes=new Hook(riftfront_node_ids,2);
+	this->helements=new Hook(riftfront_elem_ids,2);
+	this->hmatpar=new Hook(&riftfront_matpar_id,1);
+
+	/*computational parameters: */
+	this->active=0;
+	this->frozen=0;
+	this->counter=0;
+	this->prestable=0;
+	this->penalty_lock=penalty_lock;
+	this->material_converged=0;
+	this->normal[0]=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+4);
+	this->normal[1]=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+5);
+	this->length=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+6);
+	this->fraction=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+9);
+	this->state=reCast<int,IssmDouble>(*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+11));
+
+	//intialize inputs, and add as many inputs per element as requested: 
+	this->inputs=new Inputs();
+
+	riftfront_type=SegmentRiftfrontEnum;
+	riftfront_fill = reCast<int,IssmDouble>(*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+7));
+	riftfront_friction=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+8);
+	riftfront_fractionincrement=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+10);
+	riftfront_shelf=reCast<bool,IssmDouble>(iomodel->Data(MaskVertexonfloatingiceEnum)[node1-1]);
+
+	this->inputs->AddInput(new IntInput(RiftfrontTypeEnum,riftfront_type));
+	this->inputs->AddInput(new IntInput(FillEnum,riftfront_fill));
+	this->inputs->AddInput(new DoubleInput(FrictionEnum,riftfront_friction));
+	this->inputs->AddInput(new DoubleInput(FractionIncrementEnum,riftfront_fractionincrement));
+	this->inputs->AddInput(new BoolInput(SegmentOnIceShelfEnum,riftfront_shelf));
+
+	//parameters and hooked fields: we still can't point to them, they may not even exist. Configure will handle this.
+	this->parameters=NULL;
+	this->nodes= NULL;
+	this->elements= NULL;
+	this->matpar= NULL;
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::~Riftfront(){{{*/
+Riftfront::~Riftfront(){
+	delete inputs;
+	this->parameters=NULL;
+
+	delete hnodes;
+	delete helements;
+	delete hmatpar;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Riftfront::Echo {{{*/
+void Riftfront::Echo(void){
+
+	Input* input=NULL;
+	int fill;
+	IssmDouble friction,fractionincrement;
+
+	/*recover some inputs first: */
+	input=(Input*)this->inputs->GetInput(FillEnum); input->GetInputValue(&fill);
+	input=(Input*)this->inputs->GetInput(FrictionEnum); input->GetInputValue(&friction);
+	input=(Input*)this->inputs->GetInput(FractionIncrementEnum); input->GetInputValue(&fractionincrement);
+
+	_printLine_("Riftfront:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	_printLine_("   hnodes: " << hnodes);
+	_printLine_("   helements: " << helements);
+	_printLine_("   hmatpar: " << hmatpar);
+	_printLine_("   parameters: " << parameters);
+	_printLine_("   inputs: " << inputs);
+	_printLine_("   internal parameters: ");
+	_printLine_("   normal: " << normal[0] << "|" << normal[1]);
+	_printLine_("   length: " << length);
+	_printLine_("   penalty_lock: " << penalty_lock);
+	_printLine_("   active: " <<(active ? "true":"false"));
+	_printLine_("   counter: " << counter);
+	_printLine_("   prestable: " << (prestable ? "true":"false"));
+	_printLine_("   material_converged: " << (material_converged ? "true":"false"));
+	_printLine_("   fill: " << fill);
+	_printLine_("   friction: " << friction);
+	_printLine_("   fraction: " << fraction);
+	_printLine_("   fractionincrement: " << fractionincrement);
+	_printLine_("   state: " << state);
+	_printLine_("   frozen: " << (frozen ? "true":"false"));
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::DeepEcho{{{*/
+void Riftfront::DeepEcho(void){
+
+	_printLine_("Riftfront:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->DeepEcho();
+	helements->DeepEcho();
+	hmatpar->DeepEcho();
+	_printLine_("   parameters");
+	if(parameters)parameters->DeepEcho();
+	_printLine_("   inputs");
+	if(inputs)inputs->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION Riftfront::Id {{{*/
+int    Riftfront::Id(void){ return id; }
+/*}}}*/
+/*FUNCTION Riftfront::ObjectEnum{{{*/
+int Riftfront::ObjectEnum(void){
+
+	return RiftfrontEnum;
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::copy {{{*/
+Object* Riftfront::copy() {
+
+	Riftfront* riftfront=NULL;
+
+	riftfront=new Riftfront();
+
+	/*copy fields: */
+	riftfront->id=this->id;
+	riftfront->analysis_type=this->analysis_type;
+	if(this->inputs){
+		riftfront->inputs=(Inputs*)this->inputs->Copy();
+	}
+	else{
+		riftfront->inputs=new Inputs();
+	}
+	/*point parameters: */
+	riftfront->parameters=this->parameters;
+
+	/*now deal with hooks and objects: */
+	riftfront->hnodes=(Hook*)this->hnodes->copy();
+	riftfront->helements=(Hook*)this->helements->copy();
+	riftfront->hmatpar=(Hook*)this->hmatpar->copy();
+
+	/*corresponding fields*/
+	riftfront->nodes   =(Node**)riftfront->hnodes->deliverp();
+	riftfront->elements=(Element**)riftfront->helements->deliverp();
+	riftfront->matpar  =(Matpar*)riftfront->hmatpar->delivers();
+
+	/*internal data: */
+	riftfront->penalty_lock=this->penalty_lock;
+	riftfront->active=this->active;
+	riftfront->frozen=this->frozen;
+	riftfront->state=this->state;
+	riftfront->counter=this->counter;
+	riftfront->prestable=this->prestable;
+	riftfront->material_converged=this->material_converged;
+	riftfront->normal[0]=this->normal[0];
+	riftfront->normal[1]=this->normal[1];
+	riftfront->length=this->length;
+	riftfront->fraction=this->fraction;
+
+	return riftfront;
+
+}
+/*}}}*/
+
+/*Update virtual functions definitions:*/
+/*FUNCTION Riftfront::InputUpdateFromConstant(bool constant,int name) {{{*/
+void  Riftfront::InputUpdateFromConstant(bool constant,int name){
+
+	/*Check that name is a Riftfront input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	this->inputs->AddInput(new BoolInput(name,constant));
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::InputUpdateFromConstant(IssmDouble constant,int name) {{{*/
+void  Riftfront::InputUpdateFromConstant(IssmDouble constant,int name){
+
+	/*Check that name is a Riftfront input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	this->inputs->AddInput(new DoubleInput(name,constant));
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::InputUpdateFromConstant(IssmDouble* constant,int name) {{{*/
+void    Riftfront::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+
+	/*Check that name is a Riftfront input*/
+	if (!IsInput(name)) return;
+
+	/*update input*/
+	_error_("not implemented yet");
+	//this->inputs->AddInput(new DoubleInput(name,constant));
+
+}
+/*}}}*/
+
+/*Load virtual functions definitions:*/
+/*FUNCTION Riftfront::Configure {{{*/
+void  Riftfront::Configure(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+	/*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: */
+	hnodes->configure(nodesin);
+	helements->configure(elementsin);
+	hmatpar->configure(materialsin);
+
+	/*Initialize hooked fields*/
+	this->nodes   =(Node**)hnodes->deliverp();
+	this->elements=(Element**)helements->deliverp();
+	this->matpar  =(Matpar*)hmatpar->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::IsPenalty{{{*/
+bool Riftfront::IsPenalty(void){
+	return true;
+}
+/*}}}*/
+/*FUNCTION Riftfront::SetCurrentConfiguration {{{*/
+void  Riftfront::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::PenaltyCreateKMatrix {{{*/
+void  Riftfront::PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs,IssmDouble kmax){
+
+	/*Retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		case DiagnosticHorizAnalysisEnum:
+			Ke=PenaltyCreateKMatrixDiagnosticHoriz(kmax);
+			break;
+		case AdjointHorizAnalysisEnum:
+			Ke=PenaltyCreateKMatrixDiagnosticHoriz(kmax);
+			break;
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+}
+/*}}}*/
+/*FUNCTION Riftfront::PenaltyCreatePVector {{{*/
+void  Riftfront::PenaltyCreatePVector(Vector<IssmDouble>* pf,IssmDouble kmax){
+
+	/*Retrieve parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		case DiagnosticHorizAnalysisEnum:
+			pe=PenaltyCreatePVectorDiagnosticHoriz(kmax);
+			break;
+		case AdjointHorizAnalysisEnum:
+			/*No penalty applied on load vector*/
+			break;
+		default:
+			_error_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global Vector*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+}
+/*}}}*/
+/*FUNCTION Riftfront::CreateKMatrix {{{*/
+void  Riftfront::CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Riftfront::CreatePVector {{{*/
+void  Riftfront::CreatePVector(Vector<IssmDouble>* pf){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Riftfront::GetNodesSidList{{{*/
+void Riftfront::GetNodesSidList(int* sidlist){
+
+	_assert_(sidlist);
+	_assert_(nodes);
+
+	for(int i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->Sid();
+}
+/*}}}*/
+/*FUNCTION Riftfront::GetNumberOfNodes{{{*/
+int Riftfront::GetNumberOfNodes(void){
+
+	return NUMVERTICES;
+}
+/*}}}*/
+/*FUNCTION Riftfront::InAnalysis{{{*/
+bool Riftfront::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+/*FUNCTION Riftfront::SetwiseNodeConnectivity{{{*/
+void Riftfront::SetwiseNodeConnectivity(int* pd_nz,int* po_nz,Node* node,bool* flags,int set1_enum,int set2_enum){
+
+	/*Output */
+	int d_nz = 0;
+	int o_nz = 0;
+
+	/*Loop over all nodes*/
+	for(int i=0;i<NUMVERTICES;i++){
+
+		if(!flags[this->nodes[i]->Sid()]){
+
+			/*flag current node so that no other element processes it*/
+			flags[this->nodes[i]->Sid()]=true;
+
+			/*if node is clone, we have an off-diagonal non-zero, else it is a diagonal non-zero*/
+			switch(set2_enum){
+				case FsetEnum:
+					if(nodes[i]->indexing.fsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case GsetEnum:
+					if(nodes[i]->indexing.gsize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				case SsetEnum:
+					if(nodes[i]->indexing.ssize){
+						if(this->nodes[i]->IsClone())
+						 o_nz += 1;
+						else
+						 d_nz += 1;
+					}
+					break;
+				default: _error_("not supported");
+			}
+		}
+	}
+
+	/*Assign output pointers: */
+	*pd_nz=d_nz;
+	*po_nz=o_nz;
+}
+/*}}}*/
+
+/*Riftfront numerics*/
+/*FUNCTION Riftfront::PenaltyCreateKMatrixDiagnosticHoriz {{{*/
+ElementMatrix* Riftfront::PenaltyCreateKMatrixDiagnosticHoriz(IssmDouble kmax){
+
+	const int   numdof = NDOF2*NUMVERTICES;
+	int         dofs[1]             = {0};
+	IssmDouble  thickness;
+	IssmDouble  h[2];
+	IssmDouble  penalty_offset;
+	IssmDouble  friction;
+
+	/*Objects: */
+	Tria       *tria1               = NULL;
+	Tria       *tria2               = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	/*Initialize Element Matrix*/
+	if(!this->active) return NULL;
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters);
+
+	/*Get some parameters: */
+	this->parameters->FindParam(&penalty_offset,DiagnosticPenaltyFactorEnum);
+	this->inputs->GetInputValue(&friction,FrictionEnum);
+	tria1->GetInputValue(&h[0],nodes[0],ThicknessEnum);
+	tria2->GetInputValue(&h[1],nodes[1],ThicknessEnum);
+	if (h[0]!=h[1])_error_("different thicknesses not supported for rift fronts");
+	thickness=h[0];
+
+	/*There is contact, we need to constrain the normal velocities (zero penetration), and the 
+	 *contact slip friction. */
+
+	/*From Peter Wriggers book (Computational Contact Mechanics, p191): */
+	Ke->values[0*numdof+0]+= +pow(normal[0],2)*kmax*pow(10,penalty_offset);
+	Ke->values[0*numdof+1]+= +normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+	Ke->values[0*numdof+2]+= -pow(normal[0],2)*kmax*pow(10,penalty_offset);
+	Ke->values[0*numdof+3]+= -normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+
+	Ke->values[1*numdof+0]+= +normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+	Ke->values[1*numdof+1]+= +pow(normal[1],2)*kmax*pow(10,penalty_offset);
+	Ke->values[1*numdof+2]+= -normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+	Ke->values[1*numdof+3]+= -pow(normal[1],2)*kmax*pow(10,penalty_offset);
+
+	Ke->values[2*numdof+0]+= -pow(normal[0],2)*kmax*pow(10,penalty_offset);
+	Ke->values[2*numdof+1]+= -normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+	Ke->values[2*numdof+2]+= +pow(normal[0],2)*kmax*pow(10,penalty_offset);
+	Ke->values[2*numdof+3]+= +normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+
+	Ke->values[3*numdof+0]+= -normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+	Ke->values[3*numdof+1]+= -pow(normal[1],2)*kmax*pow(10,penalty_offset);
+	Ke->values[3*numdof+2]+= +normal[0]*normal[1]*kmax*pow(10,penalty_offset);
+	Ke->values[3*numdof+3]+= +pow(normal[1],2)*kmax*pow(10,penalty_offset);
+
+	/*Now take care of the friction: of type sigma=frictiontangent_velocity2-tangent_velocity1)*/
+
+	Ke->values[0*numdof+0]+= +pow(normal[1],2)*thickness*length*friction;
+	Ke->values[0*numdof+1]+= -normal[0]*normal[1]*thickness*length*friction;
+	Ke->values[0*numdof+2]+= -pow(normal[1],2)*thickness*length*friction;
+	Ke->values[0*numdof+3]+= +normal[0]*normal[1]*thickness*length*friction;
+
+	Ke->values[1*numdof+0]+= -normal[0]*normal[1]*thickness*length*friction;
+	Ke->values[1*numdof+1]+= +pow(normal[0],2)*thickness*length*friction;
+	Ke->values[1*numdof+2]+= +normal[0]*normal[1]*thickness*length*friction;
+	Ke->values[1*numdof+3]+= -pow(normal[0],2)*thickness*length*friction;
+
+	Ke->values[2*numdof+0]+= -pow(normal[1],2)*thickness*length*friction;
+	Ke->values[2*numdof+1]+= +normal[0]*normal[1]*thickness*length*friction;
+	Ke->values[2*numdof+2]+= +pow(normal[1],2)*thickness*length*friction;
+	Ke->values[2*numdof+3]+= -normal[0]*normal[1]*thickness*length*friction;
+
+	Ke->values[3*numdof+0]+= +normal[0]*normal[1]*thickness*length*friction;
+	Ke->values[3*numdof+1]+= -pow(normal[0],2)*thickness*length*friction;
+	Ke->values[3*numdof+2]+= -normal[0]*normal[1]*thickness*length*friction;
+	Ke->values[3*numdof+3]+= +pow(normal[0],2)*thickness*length*friction;
+
+	/*Clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Riftfront::PenaltyCreatePVectorDiagnosticHoriz {{{*/
+ElementVector* Riftfront::PenaltyCreatePVectorDiagnosticHoriz(IssmDouble kmax){
+
+	const int  numdof = NDOF2*NUMVERTICES;
+	int        j;
+	IssmDouble rho_ice;
+	IssmDouble rho_water;
+	IssmDouble gravity;
+	IssmDouble thickness;
+	IssmDouble h[2];
+	IssmDouble bed;
+	IssmDouble b[2];
+	IssmDouble pressure;
+	IssmDouble pressure_litho;
+	IssmDouble pressure_air;
+	IssmDouble pressure_melange;
+	IssmDouble pressure_water;
+	int        fill;
+	bool       shelf;
+
+	/*Objects: */
+	Tria *tria1 = NULL;
+	Tria *tria2 = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	/*Initialize Element Matrix*/
+	if(this->active) return NULL; /*The penalty is active. No loads implied here.*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Get some inputs: */
+	this->inputs->GetInputValue(&fill,FillEnum);
+	this->inputs->GetInputValue(&shelf,SegmentOnIceShelfEnum);
+	rho_ice=matpar->GetRhoIce();
+	rho_water=matpar->GetRhoWater();
+	gravity=matpar->GetG();
+	tria1->GetInputValue(&h[0],nodes[0],ThicknessEnum);
+	tria2->GetInputValue(&h[1],nodes[1],ThicknessEnum);
+	if (h[0]!=h[1])_error_("different thicknesses not supported for rift fronts");
+	thickness=h[0];
+	tria1->GetInputValue(&b[0],nodes[0],BedEnum);
+	tria2->GetInputValue(&b[1],nodes[1],BedEnum);
+	if (b[0]!=b[1])_error_("different beds not supported for rift fronts");
+	bed=b[0];
+
+	/*Ok, this rift is opening. We should put loads on both sides of the rift flanks. Because we are dealing with contact mechanics, 
+	 * and we want to avoid zigzagging of the loads, we want lump the loads onto nodes, not onto surfaces between nodes.:*/
+
+	/*Ok, to compute the pressure, we are going to need material properties, thickness and bed for the two nodes. We assume those properties to 
+	 * be the same across the rift.: */
+
+	/*Ok, now compute the pressure (in norm) that is being applied to the flanks, depending on the type of fill: */
+	if(fill==WaterEnum){
+		if(shelf){
+			/*We are on an ice shelf, hydrostatic equilibrium is used to determine the pressure for water fill: */
+			pressure=rho_ice*gravity*pow(thickness,(IssmDouble)2)/(IssmDouble)2  - rho_water*gravity*pow(bed,(IssmDouble)2)/(IssmDouble)2; 
+		}
+		else{
+			//We are on an icesheet, we assume the water column fills the entire front: */
+			pressure=rho_ice*gravity*pow(thickness,(IssmDouble)2)/(IssmDouble)2  - rho_water*gravity*pow(thickness,(IssmDouble)2)/(IssmDouble)2; 
+		}
+	}
+	else if(fill==AirEnum){
+		pressure=rho_ice*gravity*pow(thickness,(IssmDouble)2)/(IssmDouble)2;   //icefront on an ice sheet, pressure imbalance ice vs air.
+	}
+	else if(fill==IceEnum){ //icefront finding itself against another icefront (pressure imbalance is fully compensated, ice vs ice)
+		pressure=0;
+	}
+	else if(fill==MelangeEnum){ //icefront finding itself against another icefront (pressure imbalance is fully compensated, ice vs ice)
+
+		if(!shelf) _error_("fill type " << fill << " not supported on ice sheets yet.");
+
+		pressure_litho=rho_ice*gravity*pow(thickness,(IssmDouble)2)/(IssmDouble)2;
+		pressure_air=0;
+		pressure_melange=rho_ice*gravity*pow(fraction*thickness,(IssmDouble)2)/(IssmDouble)2;
+		pressure_water=1.0/2.0*rho_water*gravity*  ( pow(bed,2.0)-pow(rho_ice/rho_water*fraction*thickness,2.0) );
+
+		pressure=pressure_litho-pressure_air-pressure_melange-pressure_water;
+	}
+	else{
+		_error_("fill type " << fill << " not supported yet.");
+	}
+
+	/*Ok, add contribution to first node, along the normal i==0: */
+	for (j=0;j<2;j++){
+		pe->values[j]+=pressure*normal[j]*length;
+	}
+
+	/*Add contribution to second node, along the opposite normal: i==1 */
+	for (j=0;j<2;j++){
+		pe->values[2+j]+= -pressure*normal[j]*length;
+	}	
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Riftfront::Constrain {{{*/
+#define _ZIGZAGCOUNTER_
+
+int Riftfront::Constrain(int* punstable){
+
+	const int   numnodes        = 2;
+	IssmDouble      penetration;
+	int         activate;
+	int         unstable;
+	IssmDouble      vx1;
+	IssmDouble      vy1;
+	IssmDouble      vx2;
+	IssmDouble      vy2;
+	IssmDouble      fractionincrement;
+
+	/*Objects: */
+	Tria       *tria1           = NULL;
+	Tria       *tria2           = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+
+	/*recover elements on both side of rift: */
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	/*Is this constraint frozen? In which case we don't touch: */
+	if (this->frozen){
+		*punstable=0;
+		return 1;
+	}
+
+	/*Is this rift segment state specified by user input? :*/
+	if (this->state==OpenEnum || this->state==ClosedEnum){
+
+		if(this->state==OpenEnum)this->active=0;
+		if(this->state==ClosedEnum)this->active=1;
+
+		/*this segment is like frozen, no instability here: */
+		*punstable=0;
+		return 1;
+	}
+
+	/*recover parameters: */
+	this->inputs->GetInputValue(&fractionincrement,FractionIncrementEnum);
+
+	/*First recover velocity: */
+	tria1->GetInputValue(&vx1,nodes[0],VxEnum);
+	tria2->GetInputValue(&vx2,nodes[1],VxEnum);
+	tria1->GetInputValue(&vy1,nodes[0],VyEnum);
+	tria2->GetInputValue(&vy2,nodes[1],VyEnum);
+
+	/*Node 1 faces node 2, compute penetration of 2 into 1 (V2-V1).N (with N normal vector, and V velocity vector: */
+	penetration=(vx2-vx1)*normal[0]+(vy2-vy1)*normal[1];
+
+	/*activation: */
+	if(penetration<0)activate=1;
+	else  activate=0;
+
+	/*Here, we try to avoid zigzaging. When a penalty activates and deactivates for more than penalty_lock times, 
+	 * we increase the fraction of melange:*/
+	if(this->counter>this->penalty_lock){
+		/*reset counter: */
+		this->counter=0;
+		/*increase melange fraction: */
+		this->fraction+=fractionincrement;
+		if (this->fraction>1)this->fraction=(IssmDouble)1.0;
+		//_printLine_("riftfront " << this->Id() << " fraction: " << this->fraction);
+	}
+
+	//Figure out stability of this penalty
+	if(this->active==activate){
+		unstable=0;
+	}
+	else{
+		unstable=1;
+		this->counter++;
+	}
+
+	//Set penalty flag
+	this->active=activate;
+
+	//if ((penetration>0) && (this->active==1))_printLine_("Riftfront " << Id() << " wants to be released");
+
+	/*assign output pointer: */
+	*punstable=unstable;
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Riftfront::FreezeConstraints{{{*/
+void   Riftfront::FreezeConstraints(void){
+
+	/*Just set frozen flag to 1: */
+	this->frozen=1;
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::IsFrozen{{{*/
+bool   Riftfront::IsFrozen(void){
+
+	/*Just set frozen flag to 1: */
+	if(this->frozen)return 1;
+	else return 0;
+}
+/*}}}*/
+/*FUNCTION Riftfront::IsMaterialStable {{{*/
+int   Riftfront::IsMaterialStable(void){
+
+	IssmDouble converged=0;
+
+	this->inputs->GetInputValue(&converged,ConvergedEnum);
+
+	if(reCast<int,IssmDouble>(converged)){
+		/*ok, material non-linearity has converged. If that was already the case, we keep 
+		 * constraining the rift front. If it was not, and this is the first time the material 
+		 * has converged, we start constraining now!: */
+		this->material_converged=1;
+	}
+
+	return this->material_converged;
+}
+/*}}}*/
+/*FUNCTION Riftfront::MaxPenetration {{{*/
+int   Riftfront::MaxPenetration(IssmDouble* ppenetration){
+
+	const int     numnodes=2;
+	IssmDouble        penetration=0;
+	IssmDouble      vx1;
+	IssmDouble      vy1;
+	IssmDouble      vx2;
+	IssmDouble      vy2;
+
+	/*Objects: */
+	Tria       *tria1           = NULL;
+	Tria       *tria2           = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+
+	/*recover elements on both side of rift: */
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	//initialize: 
+	penetration=-1;
+
+	/*recover velocity: */
+	tria1->GetInputValue(&vx1,nodes[0],VxEnum);
+	tria2->GetInputValue(&vx2,nodes[1],VxEnum);
+	tria1->GetInputValue(&vy1,nodes[0],VyEnum);
+	tria2->GetInputValue(&vy2,nodes[1],VyEnum);
+
+	/*Node1 faces node2, compute penetration of 2 into 1 (V2-V1).N (with N normal vector, and V velocity vector: */
+	penetration=(vx2-vx1)*normal[0]+(vy2-vy1)*normal[1];
+
+	/*Now, we return penetration only if we are active!: */
+	if(this->active==0)penetration=-1;
+
+	/*If we are zigzag locked, same thing: */
+	if(this->counter>this->penalty_lock)penetration=-1;
+
+	/*assign output pointer: */
+	*ppenetration=penetration;
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Riftfront::Penetration {{{*/
+int   Riftfront::Penetration(IssmDouble* ppenetration){
+
+	IssmDouble    vx1;
+	IssmDouble    vy1;
+	IssmDouble    vx2;
+	IssmDouble    vy2;
+
+	IssmDouble    penetration;
+
+	/*Objects: */
+	Tria     *tria1       = NULL;
+	Tria     *tria2       = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+
+	/*recover elements on both side of rift: */
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	/*First recover velocity: */
+	tria1->GetInputValue(&vx1,nodes[0],VxEnum);
+	tria2->GetInputValue(&vx2,nodes[1],VxEnum);
+	tria1->GetInputValue(&vy1,nodes[0],VyEnum);
+	tria2->GetInputValue(&vy2,nodes[1],VyEnum);
+
+	/*Node 1 faces node 2, compute penetration of 2 into 1 (V2-V1).N (with N normal vector, and V velocity vector: */
+	penetration=(vx2-vx1)*normal[0]+(vy2-vy1)*normal[1];
+
+	/*Now, we return penetration only if we are active!: */
+	if(this->active==0)penetration=0;
+
+	/*assign output pointer: */
+	*ppenetration=penetration;
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Riftfront::PotentialUnstableConstraint {{{*/
+int   Riftfront::PotentialUnstableConstraint(int* punstable){
+
+	const int   numnodes        = 2;
+	IssmDouble  penetration;
+	int         unstable;
+	IssmDouble  vx1;
+	IssmDouble  vy1;
+	IssmDouble  vx2;
+	IssmDouble  vy2;
+
+	/*Objects: */
+	Tria       *tria1 = NULL;
+	Tria       *tria2 = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+
+	/*recover elements on both side of rift: */
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	/*First recover velocity: */
+	tria1->GetInputValue(&vx1,nodes[0],VxEnum);
+	tria2->GetInputValue(&vx2,nodes[1],VxEnum);
+	tria1->GetInputValue(&vy1,nodes[0],VyEnum);
+	tria2->GetInputValue(&vy2,nodes[1],VyEnum);
+
+	/*Node 1 faces node 2, compute penetration of 2 into 1 (V2-V1).N (with N normal vector, and V velocity vector: */
+	penetration=(vx2-vx1)*normal[0]+(vy2-vy1)*normal[1];
+
+	/*Ok, we are looking for positive penetration in an active constraint: */
+	if(this->active){
+		if (penetration>=0){
+			unstable=1;
+		}
+		else{
+			unstable=0;
+		}
+	}
+	else{
+		unstable=0;
+	}
+
+	/*assign output pointer: */
+	*punstable=unstable;
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Riftfront::PreConstrain {{{*/
+int   Riftfront::PreConstrain(int* punstable){
+
+	const int   numnodes    = 2;
+	IssmDouble      penetration;
+	int         unstable;
+	IssmDouble      vx1;
+	IssmDouble      vy1;
+	IssmDouble      vx2;
+	IssmDouble      vy2;
+
+	/*Objects: */
+	Tria       *tria1       = NULL;
+	Tria       *tria2       = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error_("only Tria element allowed for Riftfront load!");
+
+	/*recover elements on both side of rift: */
+	tria1=(Tria*)elements[0];
+	tria2=(Tria*)elements[1];
+
+	/*First recover velocity: */
+	tria1->GetInputValue(&vx1,nodes[0],VxEnum);
+	tria2->GetInputValue(&vx2,nodes[1],VxEnum);
+	tria1->GetInputValue(&vy1,nodes[0],VyEnum);
+	tria2->GetInputValue(&vy2,nodes[1],VyEnum);
+
+	/*Node 1 faces node 2, compute penetration of 2 into 1 (V2-V1).N (with N normal vector, and V velocity vector: */
+	penetration=(vx2-vx1)*normal[0]+(vy2-vy1)*normal[1];
+
+	/*Ok, we are preconstraining here. Ie, anything that penetrates is constrained until stability of the entire set 
+	 * of constraints is reached.: */
+	if(penetration<0){
+		if (!this->active){
+			/*This is the first time penetration happens: */
+			this->active=1;
+			unstable=1;
+		}
+		else{
+			/*This constraint was already active: */
+			this->active=1;
+			unstable=0;
+		}
+	}
+	else{
+		/*No penetration happening. : */
+		if (!this->active){
+			/*This penalty was not active, and no penetration happening. Do nonthing: */
+			this->active=0;
+			unstable=0; 
+		}
+		else{
+			/*Ok, this penalty wants to get released. But not now, this is preconstraint, not constraint: */
+			this->active=1;
+			unstable=0;
+		}
+	}
+
+	/*assign output pointer: */
+	*punstable=unstable;
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Riftfront::PreStable {{{*/
+bool  Riftfront::PreStable(){
+	return prestable;
+}
+/*}}}*/
+/*FUNCTION Riftfront::SetPreStable {{{*/
+void Riftfront::SetPreStable(){
+	prestable=1;
+}
+/*}}}*/
+/*FUNCTION Riftfront::IsInput{{{*/
+bool Riftfront::IsInput(int name){
+	if (
+				name==ConvergedEnum ||
+				name==ThicknessEnum ||
+				name==SurfaceEnum ||
+				name==BedEnum 
+		){
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Loads/Riftfront.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Loads/Riftfront.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Loads/Riftfront.h	(revision 15012)
@@ -0,0 +1,106 @@
+/*!\file Riftfront.h
+ * \brief: header file for riftfront object
+ */
+
+#ifndef _RIFTFRONT_H_
+#define _RIFTFRONT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Load.h"
+class Hook;
+class Parameters;
+class Inputs;
+class IoModel;
+/*}}}*/
+
+class Riftfront: public Load {
+
+	public:
+		int		id;
+		int     analysis_type;
+
+		/*hooks: */
+		Hook* hnodes;
+		Hook* helements;
+		Hook* hmatpar;
+
+		/*Corresponding fields*/
+		Matpar   *matpar;
+		Node    **nodes;
+		Element **elements;
+
+		/*computational: */
+		int         penalty_lock;
+		bool        active;
+		bool        frozen;
+		int         counter;
+		bool        prestable;
+		bool        material_converged;
+		IssmDouble  normal[2];
+		IssmDouble  length;
+		IssmDouble  fraction;
+		int         state;
+
+		Parameters *parameters;           //pointer to solution parameters
+		Inputs     *inputs;
+
+		/*Riftfrontconstructors,destructors: {{{*/
+		Riftfront();
+		Riftfront(int riftfront_id,int i, IoModel* iomodel,int analysis_type);
+		~Riftfront();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void    InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void    InputUpdateFromVector(int* vector, int name, int type){_error_("Not implemented yet!");}
+		void    InputUpdateFromVector(bool* vector, int name, int type){_error_("Not implemented yet!");}
+		void    InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows,int ncols, int name, int type){_error_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){_error_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(int* vector, int name, int type){_error_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(bool* vector, int name, int type){_error_("Not implemented yet!");}
+		void    InputUpdateFromConstant(IssmDouble constant, int name);
+		void    InputUpdateFromConstant(int constant, int name){_error_("Not implemented yet!");}
+		void    InputUpdateFromConstant(bool constant, int name);
+		void    InputUpdateFromSolution(IssmDouble* solution){_error_("Not implemented yet!");}
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("not implemented yet");};
+		/*}}}*/
+		/*Load virtual functions definitions: {{{*/
+		void  Configure(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void  CreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* Kfs);
+		void  CreatePVector(Vector<IssmDouble>* pf);
+		void  CreateJacobianMatrix(Matrix<IssmDouble>* Jff){_error_("Not implemented yet");};
+		void  GetNodesSidList(int* sidlist);
+		int   GetNumberOfNodes(void);
+		bool  IsPenalty(void);
+		void  PenaltyCreateJacobianMatrix(Matrix<IssmDouble>* Jff,IssmDouble kmax){_error_("Not implemented yet");};
+		void  PenaltyCreateKMatrix(Matrix<IssmDouble>* Kff, Matrix<IssmDouble>* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector<IssmDouble>* pf, IssmDouble kmax);
+		void  SetwiseNodeConnectivity(int* d_nz,int* o_nz,Node* node,bool* flags,int set1_enum,int set2_enum);
+		bool  InAnalysis(int analysis_type);
+		/*}}}*/
+		/*Riftfront specific routines: {{{*/
+		bool  PreStable();
+		ElementMatrix* PenaltyCreateKMatrixDiagnosticHoriz(IssmDouble kmax);
+		ElementVector* PenaltyCreatePVectorDiagnosticHoriz(IssmDouble kmax);
+		void  SetPreStable();
+		int   PreConstrain(int* punstable);
+		int   Constrain(int* punstable);
+		void  FreezeConstraints(void);
+		bool  IsFrozen(void);
+		int   Penetration(IssmDouble* ppenetration);
+		int   MaxPenetration(IssmDouble* ppenetration);
+		int   PotentialUnstableConstraint(int* punstable);
+		int   IsMaterialStable(void);
+		bool  IsInput(int name);
+		/*}}}*/
+};
+
+#endif  /* _RIFTFRONT_H_ */
Index: /issm/trunk-jpl/src/c/classes/Materials/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,10 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Materials)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Materials/Matdamageice.cpp
+                       $ENV{ISSM_DIR}/src/c/classes/objects/Materials/Matice.cpp
+                       $ENV{ISSM_DIR}/src/c/classes/objects/Materials/Matpar.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Materials/Matdamageice.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Matdamageice.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Matdamageice.cpp	(revision 15012)
@@ -0,0 +1,883 @@
+/*!\file Matdamageice.c
+ * \brief: implementation of the Matdamageice object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+
+/*Matdamageice constructors and destructor*/
+/*FUNCTION Matdamageice::Matdamageice(){{{*/
+Matdamageice::Matdamageice(){
+	this->inputs=NULL;
+	this->helement=NULL;
+	return;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::Matdamageice(int id, int index, IoModel* iomodel, int num_vertices){{{*/
+Matdamageice::Matdamageice(int matice_mid,int index, IoModel* iomodel){
+
+	/*Intermediaries:*/
+	int    matice_eid;
+
+	/*Initialize id*/
+	this->mid=matice_mid;
+
+	/*Initialize inputs*/
+	this->inputs=new Inputs();
+
+	/*Initialize inputs from IoModel*/
+	this->InputUpdateFromIoModel(index,iomodel);
+
+	/*Hooks: */
+	matice_eid=index+1;
+	this->helement=new Hook(&matice_eid,1);
+
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Matdamageice::~Matdamageice(){{{*/
+Matdamageice::~Matdamageice(){
+	delete helement;
+	delete inputs;
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Matdamageice::Echo {{{*/
+void Matdamageice::Echo(void){
+
+	_printLine_("Matdamageice:");
+	_printLine_("   mid: " << mid);
+	_printLine_("   inputs:");
+	inputs->Echo();
+	_printLine_("   element:");
+	helement->Echo();
+}
+/*}}}*/
+/*FUNCTION Matdamageice::DeepEcho {{{*/
+void Matdamageice::DeepEcho(void){
+
+	_printLine_("Matdamageice:");
+	_printLine_("   mid: " << mid);
+	_printLine_("   inputs:");
+	inputs->DeepEcho();
+	_printLine_("   element:");
+	helement->Echo();
+}		
+/*}}}*/
+/*FUNCTION Matdamageice::Id {{{*/
+int    Matdamageice::Id(void){ return mid; }
+/*}}}*/
+/*FUNCTION Matdamageice::ObjectEnum{{{*/
+int Matdamageice::ObjectEnum(void){
+
+	return MatdamageiceEnum;
+
+}
+/*}}}*/
+/*FUNCTION Matdamageice::copy {{{*/
+Object* Matdamageice::copy() {
+
+	/*Output*/
+	Matdamageice* matice=NULL;
+
+	/*Initialize output*/
+	matice=new Matdamageice();
+
+	/*copy fields: */
+	matice->mid=this->mid;
+	matice->helement=(Hook*)this->helement->copy();
+	if(this->inputs) matice->inputs=(Inputs*)this->inputs->Copy();
+	else  matice->inputs=new Inputs();
+
+	return matice;
+}
+/*}}}*/
+
+/*Matdamageice management*/
+/*FUNCTION Matdamageice::Configure {{{*/
+void  Matdamageice::Configure(Elements* elementsin){
+
+	/*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: */
+	helement->configure((DataSet*)elementsin);
+}
+/*}}}*/
+/*FUNCTION Matdamageice::SetCurrentConfiguration {{{*/
+void  Matdamageice::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetA {{{*/
+IssmDouble Matdamageice::GetA(){
+	/*
+	 * A = 1/B^n
+	 */
+
+	IssmDouble B,n;
+
+	inputs->GetInputAverage(&B,MaterialsRheologyBEnum);
+	n=this->GetN();
+
+	return pow(B,-n);
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetB {{{*/
+IssmDouble Matdamageice::GetB(){
+
+	/*Output*/
+	IssmDouble B;
+
+	inputs->GetInputAverage(&B,MaterialsRheologyBEnum);
+	return B;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetBbar {{{*/
+IssmDouble Matdamageice::GetBbar(){
+
+	/*Output*/
+	IssmDouble Bbar;
+
+	inputs->GetInputAverage(&Bbar,MaterialsRheologyBbarEnum);
+	return Bbar;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetN {{{*/
+IssmDouble Matdamageice::GetN(){
+
+	/*Output*/
+	IssmDouble n;
+
+	inputs->GetInputAverage(&n,MaterialsRheologyNEnum);
+	return n;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetZ {{{*/
+IssmDouble Matdamageice::GetZ(){
+
+	/*Output*/
+	IssmDouble Z;
+
+	inputs->GetInputAverage(&Z,MaterialsRheologyZEnum);
+	return Z;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetZbar {{{*/
+IssmDouble Matdamageice::GetZbar(){
+
+	/*Output*/
+	IssmDouble Zbar;
+
+	inputs->GetInputAverage(&Zbar,MaterialsRheologyZbarEnum);
+	return Zbar;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetVectorFromInputs{{{*/
+void  Matdamageice::GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum){
+
+	/*Intermediaries*/
+	Element *element= NULL;
+
+	/*Recover element*/
+	element=(Element*)helement->delivers();
+
+	/*Check that input_enum is a material input*/
+	if (!IsInput(input_enum)) return;
+
+	switch(element->ObjectEnum()){
+
+		case TriaEnum:{
+
+			/*Prepare index list*/
+			int doflist1[3];
+			for(int i=0;i<3;i++) doflist1[i]=((Tria*)element)->nodes[i]->GetVertexPid();
+
+			/*Get input (either in element or material)*/
+			Input* input=inputs->GetInput(input_enum);
+			if(!input) _error_("Input " << EnumToStringx(input_enum) << " not found in material");
+
+			/*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
+			input->GetVectorFromInputs(vector,&doflist1[0]);}
+			break;
+
+		default: _error_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosity2d {{{*/
+void  Matdamageice::GetViscosity2d(IssmDouble* pviscosity, IssmDouble* epsilon){
+	/*From a string tensor and a material object, return viscosity, using Glen's flow law.
+												   Z * B
+	  viscosity= -------------------------------------------------------------------
+						  2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+
+	  where viscosity is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	  vector, and n the flow law exponent.
+
+	  If epsilon is NULL, it means this is the first time SystemMatrices is being run, and we 
+	  return 10^14, initial viscosity.
+	  */
+
+	/*output: */
+	IssmDouble viscosity;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Intermediary: */
+	IssmDouble A,e;
+	IssmDouble Btmp,B,n,Z;
+
+	/*Get B and n*/
+	Btmp=GetBbar();
+	Z=GetZbar();
+	n=GetN();
+	B=Z*Btmp;
+
+	if (n==1){
+		/*Viscous behaviour! viscosity=B: */
+		viscosity=B/2;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0)){
+			viscosity=0.5*pow((IssmDouble)10,(IssmDouble)14);
+		}
+		else{
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			exy=*(epsilon+2);
+
+			/*Build viscosity: viscosity=B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+exx*eyy;
+			if(A==0){
+				/*Maxiviscositym viscosity for 0 shear areas: */
+				viscosity=2.5*pow(10.,17.);
+			}
+			else{
+				e=(n-1)/(2*n);
+				viscosity=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity<=0) _error_("Negative viscosity");
+	_assert_(B>0);
+	_assert_(n>0);
+
+	/*Return: */
+	*pviscosity=viscosity;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosity3d {{{*/
+void  Matdamageice::GetViscosity3d(IssmDouble* pviscosity3d, IssmDouble* epsilon){
+
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *                                               B
+	 * viscosity3d= -------------------------------------------------------------------
+	 *                      2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 *     where mu is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	 *     vector, and n the flow law exponent.
+	 *
+	 * If epsilon is NULL, it means this is the first time Emg is being run, and we 
+	 * return g, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity3d;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy,exz,eyz;
+
+	/*Intermediaries: */
+	IssmDouble A,e;
+	IssmDouble B,n,Z;
+
+	/*Get B, Z and n*/
+	n=GetN();
+	Z=GetZ();
+	B=Z*GetB();
+
+	if (n==1){
+		/*Viscous behaviour! viscosity3d=B: */
+		viscosity3d=B/2;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0)){
+			viscosity3d=0.5*pow((IssmDouble)10,(IssmDouble)14);
+		}
+		else{
+
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			exy=*(epsilon+2);
+			exz=*(epsilon+3);
+			eyz=*(epsilon+4);
+
+			/*Build viscosity: viscosity3d=2*B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+pow(exz,2)+pow(eyz,2)+exx*eyy;
+			if(A==0){
+				/*Maxiviscosity3dm viscosity for 0 shear areas: */
+				viscosity3d=2.25*pow((IssmDouble)10,(IssmDouble)17);
+			}
+			else{
+				e=(n-1)/2/n;
+
+				viscosity3d=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity3d<=0) _error_("Negative viscosity");
+	_assert_(B>0);
+	_assert_(n>0);
+
+	/*Assign output pointers:*/
+	*pviscosity3d=viscosity3d;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosity3dStokes {{{*/
+void  Matdamageice::GetViscosity3dStokes(IssmDouble* pviscosity3d, IssmDouble* epsilon){
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *                                          B
+	 * viscosity3d= -------------------------------------------------------------------
+	 *                   2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 *     where mu is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	 *     vector, and n the flow law exponent.
+	 *
+	 * If epsilon is NULL, it means this is the first time Emg is being run, and we 
+	 * return g, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity3d;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy,exz,eyz,ezz;
+
+	/*Intermediaries: */
+	IssmDouble A,e;
+	IssmDouble B,n,Z;
+	IssmDouble eps0;
+
+	/*Get B and n*/
+	eps0=pow((IssmDouble)10,(IssmDouble)-27);
+	n=GetN();
+	Z=GetZ();
+	B=Z*GetB();
+
+	if (n==1){
+		/*Viscous behaviour! viscosity3d=B: */
+		viscosity3d=B/2;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0) && (epsilon[5]==0)){
+			viscosity3d=0.5*pow((IssmDouble)10,(IssmDouble)14);
+		}
+		else{
+
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			ezz=*(epsilon+2); //not used
+			exy=*(epsilon+3);
+			exz=*(epsilon+4);
+			eyz=*(epsilon+5);
+
+			/*Build viscosity: viscosity3d=B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+pow(exz,2)+pow(eyz,2)+exx*eyy+pow(eps0,2);
+			if(A==0){
+				/*Maxiviscosity3dm viscosity for 0 shear areas: */
+				viscosity3d=2.25*pow((IssmDouble)10,(IssmDouble)17);
+			}
+			else{
+				e=(n-1)/2/n;
+				viscosity3d=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity3d<=0) _error_("Negative viscosity");
+	_assert_(B>0);
+	_assert_(n>0);
+
+	/*Assign output pointers:*/
+	*pviscosity3d=viscosity3d;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosityComplement {{{*/
+void  Matdamageice::GetViscosityComplement(IssmDouble* pviscosity_complement, IssmDouble* epsilon){
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *  										                1
+	 * viscosity= -------------------------------------------------------------------
+	 *  				  2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 * If epsilon is NULL, it means this is the first time Gradjb is being run, and we 
+	 * return mu20, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity_complement;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Intermediary value A and exponent e: */
+	IssmDouble A,e;
+	IssmDouble B,n;
+
+	/*Get B and n*/
+	B=GetBbar();
+	n=GetN();
+
+	if(epsilon){
+		exx=*(epsilon+0);
+		eyy=*(epsilon+1);
+		exy=*(epsilon+2);
+
+		/*Build viscosity: mu2=B/(2*A^e) */
+		A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+exx*eyy;
+		if(A==0){
+			/*Maximum viscosity_complement for 0 shear areas: */
+			viscosity_complement=2.25*pow((IssmDouble)10,(IssmDouble)17);
+		}
+		else{
+			e=(n-1)/(2*n);
+
+			viscosity_complement=1/(2*pow(A,e));
+		}
+	}
+	else{
+		viscosity_complement=4.5*pow((IssmDouble)10,(IssmDouble)17);
+	}
+
+	/*Checks in debugging mode*/
+	_assert_(B>0);
+	_assert_(n>0);
+	_assert_(viscosity_complement>0);
+
+	/*Return: */
+	*pviscosity_complement=viscosity_complement;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosityZComplement {{{*/
+void  Matdamageice::GetViscosityZComplement(IssmDouble* pviscosity_complement, IssmDouble* epsilon){
+	/*Return viscosity derivative for control method d(mu)/dZ: 
+	 *
+	 *  										               B 
+	 * dviscosity= -------------------------------------------------------------------
+	 *  				  2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 * If epsilon is NULL, it means this is the first time Gradjb is being run, and we 
+	 * return mu20, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity_complement;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Intermediary value A and exponent e: */
+	IssmDouble A,e;
+	IssmDouble B,n;
+
+	/*Get B and n*/
+	B=GetBbar();
+	n=GetN();
+
+	if(epsilon){
+		exx=*(epsilon+0);
+		eyy=*(epsilon+1);
+		exy=*(epsilon+2);
+
+		/*Build viscosity: mu2=B/(2*A^e) */
+		A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+exx*eyy;
+		if(A==0){
+			/*Maximum viscosity_complement for 0 shear areas: */
+			viscosity_complement=2.25*pow((IssmDouble)10,(IssmDouble)17);
+		}
+		else{
+			e=(n-1)/(2*n);
+
+			viscosity_complement=B/(2*pow(A,e));
+		}
+	}
+	else{
+		viscosity_complement=4.5*pow((IssmDouble)10,(IssmDouble)17);
+	}
+
+	/*Checks in debugging mode*/
+	_assert_(B>0);
+	_assert_(n>0);
+	_assert_(viscosity_complement>0);
+
+	/*Return: */
+	*pviscosity_complement=viscosity_complement;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosityDerivativeEpsSquare{{{*/
+void  Matdamageice::GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* epsilon){
+
+	/*output: */
+	IssmDouble mu_prime;
+	IssmDouble mu,n,eff2;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy,exz,eyz;
+
+	/*Get visocisty and n*/
+	GetViscosity3d(&mu,epsilon);
+	n=GetN();
+
+	if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0)){
+		mu_prime=0.5*pow((IssmDouble)10,(IssmDouble)14);
+	}
+	else{
+		/*Retrive strain rate components: */
+		exx=epsilon[0];
+		eyy=epsilon[1];
+		exy=epsilon[2];
+		exz=epsilon[3];
+		eyz=epsilon[4];
+		eff2 = exx*exx + eyy*eyy + exx*eyy + exy*exy + exz*exz + eyz*eyz;
+
+		mu_prime=(1-n)/(2*n) * mu/eff2;
+	}
+
+	/*Assign output pointers:*/
+	*pmu_prime=mu_prime;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::GetViscosity2dDerivativeEpsSquare{{{*/
+void  Matdamageice::GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* epsilon){
+
+	/*output: */
+	IssmDouble mu_prime;
+	IssmDouble mu,n,eff2;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Get visocisty and n*/
+	GetViscosity2d(&mu,epsilon);
+	n=GetN();
+
+	if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0)){
+		mu_prime=0.5*pow((IssmDouble)10,(IssmDouble)14);
+	}
+	else{
+		/*Retrive strain rate components: */
+		exx=epsilon[0];
+		eyy=epsilon[1];
+		exy=epsilon[2];
+		eff2 = exx*exx + eyy*eyy + exx*eyy + exy*exy ;
+
+		mu_prime=(1-n)/(2*n) * mu/eff2;
+	}
+
+	/*Assign output pointers:*/
+	*pmu_prime=mu_prime;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputDuplicate{{{*/
+void  Matdamageice::InputDuplicate(int original_enum,int new_enum){
+
+	/*Call inputs method*/
+	if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
+
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromVector(IssmDouble* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+
+	/*Intermediaries*/
+	Element *element      = NULL;
+
+	/*Recover element*/
+	element=(Element*)helement->delivers();
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			switch(element->ObjectEnum()){
+
+				case TriaEnum: {
+					IssmDouble values[3];
+					for (int i=0;i<3;i++) values[i]=vector[((Tria*)element)->nodes[i]->GetVertexPid()];
+					this->inputs->AddInput(new TriaP1Input(name,values));
+					return;
+				}
+				default: _error_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+			}
+		default: _error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromVector(int* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromVector(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromVector(bool* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromVector(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+
+	/*Intermediaries*/
+	Element *element      = NULL;
+	Parameters* parameters= NULL;
+	int         dim;
+
+	/*Recover element*/
+	element=(Element*)helement->delivers();
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			switch(element->ObjectEnum()){
+
+				case TriaEnum: {
+					IssmDouble values[3];
+					for (int i=0;i<3;i++) values[i]=vector[((Tria*)element)->nodes[i]->GetVertexSid()]; //use sid list, to index into serial oriented vector 
+					this->inputs->AddInput(new TriaP1Input(name,values));
+					/*Special case for rheology B in 2D: Pourave land for this solution{{{*/
+					if(name==MaterialsRheologyBEnum){
+						/*Are we in 2D?:*/
+						if(element->ObjectEnum()==TriaEnum){
+							parameters=((Tria*)(element))->parameters;
+						}
+						else{
+							parameters=((Penta*)(element))->parameters;
+						}
+						parameters->FindParam(&dim,MeshDimensionEnum);
+						if(dim==2){
+							/*Dupliacte rheology input: */
+							this->inputs->AddInput(new TriaP1Input(MaterialsRheologyBbarEnum,values));
+						}
+					}
+					/*}}}*/
+					return;
+				}
+				default: _error_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+			}
+		default: _error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromMatrixDakota(int* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols,int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromVectorDakota(int* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromVectorDakota(bool* vector, int name, int type) {{{*/
+void  Matdamageice::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromConstant(IssmDouble constant, int name) {{{*/
+void  Matdamageice::InputUpdateFromConstant(IssmDouble constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromConstant(int constant, int name) {{{*/
+void  Matdamageice::InputUpdateFromConstant(int constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromConstant(bool constant, int name) {{{*/
+void  Matdamageice::InputUpdateFromConstant(bool constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromSolution{{{*/
+void  Matdamageice::InputUpdateFromSolution(IssmDouble* solution){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matdamageice::InputUpdateFromIoModel{{{*/
+void Matdamageice::InputUpdateFromIoModel(int index, IoModel* iomodel){
+
+	int i,j;
+
+	int    dim;
+	bool   control_analysis;
+	int    num_control_type;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&dim,MeshDimensionEnum);
+	iomodel->Constant(&control_analysis,InversionIscontrolEnum);
+	if(control_analysis) iomodel->Constant(&num_control_type,InversionNumControlParametersEnum);
+
+	/*if 2d*/
+	if(dim==2){
+
+		/*Intermediaries*/
+		const int num_vertices = 3; //Tria has 3 vertices
+		IssmDouble    nodeinputs[num_vertices];
+		IssmDouble    cmmininputs[num_vertices];
+		IssmDouble    cmmaxinputs[num_vertices];
+
+		/*Get B*/
+		if (iomodel->Data(MaterialsRheologyBEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+i]-1)];
+			this->inputs->AddInput(new TriaP1Input(MaterialsRheologyBbarEnum,nodeinputs));
+		}
+
+		/*Get n*/
+		if (iomodel->Data(MaterialsRheologyNEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyNEnum)[index];
+			this->inputs->AddInput(new TriaP1Input(MaterialsRheologyNEnum,nodeinputs));
+		}
+
+		/*Get Z*/
+		if (iomodel->Data(MaterialsRheologyZEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyZEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+i]-1)];
+			this->inputs->AddInput(new TriaP1Input(MaterialsRheologyZbarEnum,nodeinputs));
+		}
+
+		/*Control Inputs*/
+		#ifdef _HAVE_CONTROL_
+		if (control_analysis && iomodel->Data(InversionControlParametersEnum)){
+			for(i=0;i<num_control_type;i++){
+				switch(reCast<int>(iomodel->Data(InversionControlParametersEnum)[i])){
+					case MaterialsRheologyBbarEnum:
+						if (iomodel->Data(MaterialsRheologyBEnum)){
+							_assert_(iomodel->Data(MaterialsRheologyBEnum));_assert_(iomodel->Data(InversionMinParametersEnum)); _assert_(iomodel->Data(InversionMaxParametersEnum)); 
+							for(j=0;j<num_vertices;j++)nodeinputs[j]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							this->inputs->AddInput(new ControlInput(MaterialsRheologyBbarEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+						}
+						break;
+					case MaterialsRheologyZbarEnum:
+						if (iomodel->Data(MaterialsRheologyZEnum)){
+							_assert_(iomodel->Data(MaterialsRheologyZEnum));_assert_(iomodel->Data(InversionMinParametersEnum)); _assert_(iomodel->Data(InversionMaxParametersEnum)); 
+							for(j=0;j<num_vertices;j++)nodeinputs[j]=iomodel->Data(MaterialsRheologyZEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							this->inputs->AddInput(new ControlInput(MaterialsRheologyZbarEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+						}
+						break;
+
+				}
+			}
+		}
+		#endif
+	}
+
+	/*if 3d*/
+	#ifdef _HAVE_3D_
+	else if(dim==3){
+
+		/*Intermediaries*/
+		const int num_vertices = 6; //Penta has 6 vertices
+		IssmDouble    nodeinputs[num_vertices];
+		IssmDouble    cmmininputs[num_vertices];
+		IssmDouble    cmmaxinputs[num_vertices];
+
+		/*Get B*/
+		if (iomodel->Data(MaterialsRheologyBEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+i]-1)];
+			this->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,nodeinputs));
+		}
+
+		/*Get n*/
+		if (iomodel->Data(MaterialsRheologyNEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyNEnum)[index];
+			this->inputs->AddInput(new PentaP1Input(MaterialsRheologyNEnum,nodeinputs));
+		}
+
+		/*Get Z*/
+		if (iomodel->Data(MaterialsRheologyZEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyZEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+i]-1)];
+			this->inputs->AddInput(new PentaP1Input(MaterialsRheologyZEnum,nodeinputs));
+		}
+
+		/*Control Inputs*/
+		#ifdef _HAVE_CONTROL_
+		if (control_analysis && iomodel->Data(InversionControlParametersEnum)){
+			for(i=0;i<num_control_type;i++){
+				switch(reCast<int>(iomodel->Data(InversionControlParametersEnum)[i])){
+					case MaterialsRheologyBbarEnum:
+						if (iomodel->Data(MaterialsRheologyBEnum)){
+							_assert_(iomodel->Data(MaterialsRheologyBEnum));_assert_(iomodel->Data(InversionMinParametersEnum)); _assert_(iomodel->Data(InversionMaxParametersEnum)); 
+							for(j=0;j<num_vertices;j++)nodeinputs[j]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							this->inputs->AddInput(new ControlInput(MaterialsRheologyBEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+						}
+						break;
+					case MaterialsRheologyZbarEnum:
+						if (iomodel->Data(MaterialsRheologyZEnum)){
+							_assert_(iomodel->Data(MaterialsRheologyZEnum));_assert_(iomodel->Data(InversionMinParametersEnum)); _assert_(iomodel->Data(InversionMaxParametersEnum)); 
+							for(j=0;j<num_vertices;j++)nodeinputs[j]=iomodel->Data(MaterialsRheologyZEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							this->inputs->AddInput(new ControlInput(MaterialsRheologyZEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+						}
+						break;
+				}
+			}
+		}
+		#endif
+	}
+	#endif
+	else{
+		_error_("Mesh type not supported yet!");
+	}
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Matdamageice::IsInput{{{*/
+bool Matdamageice::IsInput(int name){
+	if (
+				name==MaterialsRheologyBEnum ||
+				name==MaterialsRheologyBbarEnum ||
+				name==MaterialsRheologyNEnum ||
+				name==MaterialsRheologyZEnum ||
+				name==MaterialsRheologyZbarEnum
+		){
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Materials/Matdamageice.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Matdamageice.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Matdamageice.h	(revision 15012)
@@ -0,0 +1,69 @@
+/*!\file Matdamageice.h
+ * \brief: header file for matice object
+ */
+
+#ifndef MATDAMAGEICE_H_
+#define MATDAMAGEICE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Material.h"
+class IoModel;
+/*}}}*/
+
+class Matdamageice: public Material{
+
+	private: 
+		int	   mid;
+		Hook* helement;
+
+	public:
+		/*Matdamageice constructors, destructors: {{{*/
+		Matdamageice();
+		Matdamageice(int mid,int i, IoModel* iomodel);
+		~Matdamageice();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions definitions: {{{*/
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrow, int ncols, int name, int type);
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solution);
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel);
+		/*}}}*/
+		/*Material virtual functions resolution: {{{*/
+		void   InputDuplicate(int original_enum,int new_enum);
+		void   Configure(Elements* elements);
+		void   GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum);
+		void   SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin);
+		void   GetViscosity2d(IssmDouble* pviscosity, IssmDouble* pepsilon);
+		void   GetViscosity3d(IssmDouble* pviscosity3d, IssmDouble* pepsilon);
+		void   GetViscosity3dStokes(IssmDouble* pviscosity3d, IssmDouble* epsilon);
+		void   GetViscosityComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon);
+		void   GetViscosityZComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon);
+		void   GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon);
+		void   GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon);
+		IssmDouble GetA();
+		IssmDouble GetB();
+		IssmDouble GetBbar();
+		IssmDouble GetN();
+		IssmDouble GetZ();
+		IssmDouble GetZbar();
+		bool   IsInput(int name);
+		/*}}}*/
+};
+
+#endif  /* _MATICE_H_ */
Index: /issm/trunk-jpl/src/c/classes/Materials/Material.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Material.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Material.h	(revision 15012)
@@ -0,0 +1,43 @@
+/*!\file:  Material.h
+ * \brief abstract class for Material object
+ */ 
+
+#ifndef _MATERIAL_H_
+#define _MATERIAL_H_
+
+/*Headers:*/
+/*{{{*/
+class Inputs;
+template <class doubletype> class Vector;
+#include "../Object.h"
+#include "../Update.h"
+class Elements;
+/*}}}*/
+
+class Material: public Object,public Update{
+
+	public: 
+		Inputs*  inputs;
+		virtual       ~Material(){};
+		/*WARNING: input should not be public but it is an easy way to update B from T (using UpdateFromSolution) from Pentas*/
+
+		/*Numerics*/
+		virtual void       InputDuplicate(int original_enum,int new_enum)=0;
+		virtual void       Configure(Elements* elements)=0;
+		virtual void       GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum)=0;
+		virtual void       GetViscosity2d(IssmDouble* pviscosity, IssmDouble* pepsilon)=0;
+		virtual void       GetViscosity3d(IssmDouble* pviscosity3d, IssmDouble* pepsilon)=0;
+		virtual void       GetViscosity3dStokes(IssmDouble* pviscosity3d, IssmDouble* epsilon)=0;
+		virtual void       GetViscosityComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon)=0;
+		virtual void       GetViscosityZComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon)=0;
+		virtual void       GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon)=0;
+		virtual void       GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon)=0;
+		virtual IssmDouble GetA()=0;
+		virtual IssmDouble GetB()=0;
+		virtual IssmDouble GetBbar()=0;
+		virtual IssmDouble GetN()=0;
+		virtual IssmDouble GetZ()=0;
+		virtual IssmDouble GetZbar()=0;
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Materials/Materials.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Materials.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Materials.cpp	(revision 15012)
@@ -0,0 +1,48 @@
+/*
+ * \file Materials.cpp
+ * \brief: Implementation of Materials class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Materials.h"
+#include "./Material.h"
+#include "../../shared/shared.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Materials::Materials(){{{*/
+Materials::Materials(){
+	enum_type=MaterialsEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Materials::~Materials(){{{*/
+Materials::~Materials(){
+	return;
+}
+/*}}}*/
+
+/*Object management*/
+/*FUNCTION Materials::Configure{{{*/
+void Materials::Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Material* material=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		material=dynamic_cast<Material*>(*object);
+		material->Configure(elements);
+
+	}
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Materials/Materials.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Materials.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Materials.h	(revision 15012)
@@ -0,0 +1,29 @@
+#ifndef _CONTAINER_MATERIALS_H_
+#define  _CONTAINER_MATERIALS_H_
+
+/*forward declarations */
+#include "../DataSet.h"
+class Parameters;
+class Elements;
+class Vertices;
+class Loads;
+class Nodes;
+
+/*! \brief Declaration of Materials class.
+ *
+ * Declaration of Materials class.  Materials are vector lists (Containers) of Material objects.
+ */ 
+class Materials: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Materials();
+		~Materials();
+
+		/*numerics*/
+		void  Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+
+};
+
+#endif //ifndef _MATERIALS_H_
Index: /issm/trunk-jpl/src/c/classes/Materials/Matice.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Matice.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Matice.cpp	(revision 15012)
@@ -0,0 +1,783 @@
+/*!\file Matice.c
+ * \brief: implementation of the Matice object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Matice.h"
+#include "./Materials.h"
+#include "../Inputs/Input.h"
+#include "../Inputs/Inputs.h"
+#include "../Inputs/TriaP1Input.h"
+#include "../Inputs/PentaP1Input.h"
+#include "../Inputs/ControlInput.h"
+#include "../Elements/Element.h"
+#include "../Elements/Tria.h"
+#include "../Elements/Penta.h"
+#include "../Params/Parameters.h"
+#include "../Hook.h"
+#include "../Node.h"
+#include "../IoModel.h"
+#include "../../shared/shared.h"
+
+/*Matice constructors and destructor*/
+/*FUNCTION Matice::Matice(){{{*/
+Matice::Matice(){
+	this->inputs=NULL;
+	this->helement=NULL;
+	return;
+}
+/*}}}*/
+/*FUNCTION Matice::Matice(int id, int index, IoModel* iomodel, int num_vertices){{{*/
+Matice::Matice(int matice_mid,int index, IoModel* iomodel){
+
+	/*Intermediaries:*/
+	int    matice_eid;
+
+	/*Initialize id*/
+	this->mid=matice_mid;
+
+	/*Initialize inputs*/
+	this->inputs=new Inputs();
+
+	/*Initialize inputs from IoModel*/
+	this->InputUpdateFromIoModel(index,iomodel);
+
+	/*Hooks: */
+	matice_eid=index+1;
+	this->helement=new Hook(&matice_eid,1);
+
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Matice::~Matice(){{{*/
+Matice::~Matice(){
+	delete helement;
+	delete inputs;
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Matice::Echo {{{*/
+void Matice::Echo(void){
+
+	_printLine_("Matice:");
+	_printLine_("   mid: " << mid);
+	_printLine_("   inputs:");
+	inputs->Echo();
+	_printLine_("   element:");
+	helement->Echo();
+}
+/*}}}*/
+/*FUNCTION Matice::DeepEcho {{{*/
+void Matice::DeepEcho(void){
+
+	_printLine_("Matice:");
+	_printLine_("   mid: " << mid);
+	_printLine_("   inputs:");
+	inputs->DeepEcho();
+	_printLine_("   element:");
+	helement->Echo();
+}		
+/*}}}*/
+/*FUNCTION Matice::Id {{{*/
+int    Matice::Id(void){ return mid; }
+/*}}}*/
+/*FUNCTION Matice::ObjectEnum{{{*/
+int Matice::ObjectEnum(void){
+
+	return MaticeEnum;
+
+}
+/*}}}*/
+/*FUNCTION Matice::copy {{{*/
+Object* Matice::copy() {
+
+	/*Output*/
+	Matice* matice=NULL;
+
+	/*Initialize output*/
+	matice=new Matice();
+
+	/*copy fields: */
+	matice->mid=this->mid;
+	matice->helement=(Hook*)this->helement->copy();
+	if(this->inputs) matice->inputs=(Inputs*)this->inputs->Copy();
+	else  matice->inputs=new Inputs();
+
+	return matice;
+}
+/*}}}*/
+
+/*Matice management*/
+/*FUNCTION Matice::Configure {{{*/
+void  Matice::Configure(Elements* elementsin){
+
+	/*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: */
+	helement->configure((DataSet*)elementsin);
+}
+/*}}}*/
+/*FUNCTION Matice::SetCurrentConfiguration {{{*/
+void  Matice::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Matice::GetA {{{*/
+IssmDouble Matice::GetA(){
+	/*
+	 * A = 1/B^n
+	 */
+
+	IssmDouble B,n;
+
+	inputs->GetInputAverage(&B,MaterialsRheologyBEnum);
+	n=this->GetN();
+
+	return pow(B,-n);
+}
+/*}}}*/
+/*FUNCTION Matice::GetB {{{*/
+IssmDouble Matice::GetB(){
+
+	/*Output*/
+	IssmDouble B;
+
+	inputs->GetInputAverage(&B,MaterialsRheologyBEnum);
+	return B;
+}
+/*}}}*/
+/*FUNCTION Matice::GetBbar {{{*/
+IssmDouble Matice::GetBbar(){
+
+	/*Output*/
+	IssmDouble Bbar;
+
+	inputs->GetInputAverage(&Bbar,MaterialsRheologyBbarEnum);
+	return Bbar;
+}
+/*}}}*/
+/*FUNCTION Matice::GetN {{{*/
+IssmDouble Matice::GetN(){
+
+	/*Output*/
+	IssmDouble n;
+
+	inputs->GetInputAverage(&n,MaterialsRheologyNEnum);
+	return n;
+}
+/*}}}*/
+/*FUNCTION Matice::GetVectorFromInputs{{{*/
+void  Matice::GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum){
+
+	/*Intermediaries*/
+	Element *element= NULL;
+
+	/*Recover element*/
+	element=(Element*)helement->delivers();
+
+	/*Check that input_enum is a material input*/
+	if (!IsInput(input_enum)) return;
+
+	switch(element->ObjectEnum()){
+
+		case TriaEnum:{
+
+			/*Prepare index list*/
+			int doflist1[3];
+			for(int i=0;i<3;i++) doflist1[i]=((Tria*)element)->nodes[i]->GetVertexPid();
+
+			/*Get input (either in element or material)*/
+			Input* input=inputs->GetInput(input_enum);
+			if(!input) _error_("Input " << EnumToStringx(input_enum) << " not found in material");
+
+			/*We found the enum.  Use its values to fill into the vector, using the vertices ids: */
+			input->GetVectorFromInputs(vector,&doflist1[0]);}
+			break;
+
+		default: _error_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Matice::GetViscosity2d {{{*/
+void  Matice::GetViscosity2d(IssmDouble* pviscosity, IssmDouble* epsilon){
+	/*From a string tensor and a material object, return viscosity, using Glen's flow law.
+												    B
+	  viscosity= -------------------------------------------------------------------
+						  2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+
+	  where viscosity is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	  vector, and n the flow law exponent.
+
+	  If epsilon is NULL, it means this is the first time SystemMatrices is being run, and we 
+	  return 10^14, initial viscosity.
+	  */
+
+	/*output: */
+	IssmDouble viscosity;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Intermediary: */
+	IssmDouble A,e;
+	IssmDouble B,n;
+
+	/*Get B and n*/
+	B=GetBbar();
+	n=GetN();
+
+	if (n==1){
+		/*Viscous behaviour! viscosity=B: */
+		viscosity=B/2;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0)){
+			viscosity=0.5*pow((IssmDouble)10,(IssmDouble)14);
+		}
+		else{
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			exy=*(epsilon+2);
+
+			/*Build viscosity: viscosity=B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+exx*eyy;
+			if(A==0){
+				/*Maxiviscositym viscosity for 0 shear areas: */
+				viscosity=2.5*pow(10.,17.);
+			}
+			else{
+				e=(n-1)/(2*n);
+				viscosity=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity<=0) _error_("Negative viscosity");
+	_assert_(B>0);
+	_assert_(n>0);
+
+	/*Return: */
+	*pviscosity=viscosity;
+}
+/*}}}*/
+/*FUNCTION Matice::GetViscosity3d {{{*/
+void  Matice::GetViscosity3d(IssmDouble* pviscosity3d, IssmDouble* epsilon){
+
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *                                               B
+	 * viscosity3d= -------------------------------------------------------------------
+	 *                      2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 *     where mu is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	 *     vector, and n the flow law exponent.
+	 *
+	 * If epsilon is NULL, it means this is the first time Emg is being run, and we 
+	 * return g, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity3d;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy,exz,eyz;
+
+	/*Intermediaries: */
+	IssmDouble A,e;
+	IssmDouble B,n;
+
+	/*Get B and n*/
+	B=GetB();
+	n=GetN();
+
+	if (n==1){
+		/*Viscous behaviour! viscosity3d=B: */
+		viscosity3d=B/2;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0)){
+			viscosity3d=0.5*pow((IssmDouble)10,(IssmDouble)14);
+		}
+		else{
+
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			exy=*(epsilon+2);
+			exz=*(epsilon+3);
+			eyz=*(epsilon+4);
+
+			/*Build viscosity: viscosity3d=2*B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+pow(exz,2)+pow(eyz,2)+exx*eyy;
+			if(A==0){
+				/*Maxiviscosity3dm viscosity for 0 shear areas: */
+				viscosity3d=2.25*pow((IssmDouble)10,(IssmDouble)17);
+			}
+			else{
+				e=(n-1)/2/n;
+
+				viscosity3d=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity3d<=0) _error_("Negative viscosity");
+	_assert_(B>0);
+	_assert_(n>0);
+
+	/*Assign output pointers:*/
+	*pviscosity3d=viscosity3d;
+}
+/*}}}*/
+/*FUNCTION Matice::GetViscosity3dStokes {{{*/
+void  Matice::GetViscosity3dStokes(IssmDouble* pviscosity3d, IssmDouble* epsilon){
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *                                          B
+	 * viscosity3d= -------------------------------------------------------------------
+	 *                   2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 *     where mu is the viscotiy, B the flow law parameter , (u,v) the velocity 
+	 *     vector, and n the flow law exponent.
+	 *
+	 * If epsilon is NULL, it means this is the first time Emg is being run, and we 
+	 * return g, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity3d;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy,exz,eyz,ezz;
+
+	/*Intermediaries: */
+	IssmDouble A,e;
+	IssmDouble B,n;
+	IssmDouble eps0;
+
+	/*Get B and n*/
+	eps0=pow((IssmDouble)10,(IssmDouble)-27);
+	B=GetB();
+	n=GetN();
+
+	if (n==1){
+		/*Viscous behaviour! viscosity3d=B: */
+		viscosity3d=B/2;
+	}
+	else{
+		if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0) && (epsilon[5]==0)){
+			viscosity3d=0.5*pow((IssmDouble)10,(IssmDouble)14);
+		}
+		else{
+
+			/*Retrive strain rate components: */
+			exx=*(epsilon+0);
+			eyy=*(epsilon+1);
+			ezz=*(epsilon+2); //not used
+			exy=*(epsilon+3);
+			exz=*(epsilon+4);
+			eyz=*(epsilon+5);
+
+			/*Build viscosity: viscosity3d=B/(2*A^e) */
+			A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+pow(exz,2)+pow(eyz,2)+exx*eyy+pow(eps0,2);
+			if(A==0){
+				/*Maxiviscosity3dm viscosity for 0 shear areas: */
+				viscosity3d=2.25*pow((IssmDouble)10,(IssmDouble)17);
+			}
+			else{
+				e=(n-1)/2/n;
+				viscosity3d=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity3d<=0) _error_("Negative viscosity");
+	_assert_(B>0);
+	_assert_(n>0);
+
+	/*Assign output pointers:*/
+	*pviscosity3d=viscosity3d;
+}
+/*}}}*/
+/*FUNCTION Matice::GetViscosityComplement {{{*/
+void  Matice::GetViscosityComplement(IssmDouble* pviscosity_complement, IssmDouble* epsilon){
+	/*Return viscosity accounting for steady state power law creep [Thomas and MacAyeal, 1982]: 
+	 *
+	 *  										                1
+	 * viscosity= -------------------------------------------------------------------
+	 *  				  2[ exx^2+eyy^2+exx*eyy+exy^2+exz^2+eyz^2 ]^[(n-1)/2n]
+	 *
+	 * If epsilon is NULL, it means this is the first time Gradjb is being run, and we 
+	 * return mu20, initial viscosity.
+	 */
+
+	/*output: */
+	IssmDouble viscosity_complement;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Intermediary value A and exponent e: */
+	IssmDouble A,e;
+	IssmDouble B,n;
+
+	/*Get B and n*/
+	B=GetBbar();
+	n=GetN();
+
+	if(epsilon){
+		exx=*(epsilon+0);
+		eyy=*(epsilon+1);
+		exy=*(epsilon+2);
+
+		/*Build viscosity: mu2=B/(2*A^e) */
+		A=pow(exx,2)+pow(eyy,2)+pow(exy,2)+exx*eyy;
+		if(A==0){
+			/*Maximum viscosity_complement for 0 shear areas: */
+			viscosity_complement=2.25*pow((IssmDouble)10,(IssmDouble)17);
+		}
+		else{
+			e=(n-1)/(2*n);
+
+			viscosity_complement=1/(2*pow(A,e));
+		}
+	}
+	else{
+		viscosity_complement=4.5*pow((IssmDouble)10,(IssmDouble)17);
+	}
+
+	/*Checks in debugging mode*/
+	_assert_(B>0);
+	_assert_(n>0);
+	_assert_(viscosity_complement>0);
+
+	/*Return: */
+	*pviscosity_complement=viscosity_complement;
+}
+/*}}}*/
+/*FUNCTION Matice::GetViscosityDerivativeEpsSquare{{{*/
+void  Matice::GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* epsilon){
+
+	/*output: */
+	IssmDouble mu_prime;
+	IssmDouble mu,n,eff2;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy,exz,eyz;
+
+	/*Get visocisty and n*/
+	GetViscosity3d(&mu,epsilon);
+	n=GetN();
+
+	if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0) && 
+				(epsilon[3]==0) && (epsilon[4]==0)){
+		mu_prime=0.5*pow((IssmDouble)10,(IssmDouble)14);
+	}
+	else{
+		/*Retrive strain rate components: */
+		exx=epsilon[0];
+		eyy=epsilon[1];
+		exy=epsilon[2];
+		exz=epsilon[3];
+		eyz=epsilon[4];
+		eff2 = exx*exx + eyy*eyy + exx*eyy + exy*exy + exz*exz + eyz*eyz;
+
+		mu_prime=(1-n)/(2*n) * mu/eff2;
+	}
+
+	/*Assign output pointers:*/
+	*pmu_prime=mu_prime;
+}
+/*}}}*/
+/*FUNCTION Matice::GetViscosity2dDerivativeEpsSquare{{{*/
+void  Matice::GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* epsilon){
+
+	/*output: */
+	IssmDouble mu_prime;
+	IssmDouble mu,n,eff2;
+
+	/*input strain rate: */
+	IssmDouble exx,eyy,exy;
+
+	/*Get visocisty and n*/
+	GetViscosity2d(&mu,epsilon);
+	n=GetN();
+
+	if((epsilon[0]==0) && (epsilon[1]==0) && (epsilon[2]==0)){
+		mu_prime=0.5*pow((IssmDouble)10,(IssmDouble)14);
+	}
+	else{
+		/*Retrive strain rate components: */
+		exx=epsilon[0];
+		eyy=epsilon[1];
+		exy=epsilon[2];
+		eff2 = exx*exx + eyy*eyy + exx*eyy + exy*exy ;
+
+		mu_prime=(1-n)/(2*n) * mu/eff2;
+	}
+
+	/*Assign output pointers:*/
+	*pmu_prime=mu_prime;
+}
+/*}}}*/
+/*FUNCTION Matice::InputDuplicate{{{*/
+void  Matice::InputDuplicate(int original_enum,int new_enum){
+
+	/*Call inputs method*/
+	if (IsInput(original_enum)) inputs->DuplicateInput(original_enum,new_enum);
+
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromVector(IssmDouble* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+
+	/*Intermediaries*/
+	Element *element      = NULL;
+
+	/*Recover element*/
+	element=(Element*)helement->delivers();
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			switch(element->ObjectEnum()){
+
+				case TriaEnum: {
+					IssmDouble values[3];
+					for (int i=0;i<3;i++) values[i]=vector[((Tria*)element)->nodes[i]->GetVertexPid()];
+					this->inputs->AddInput(new TriaP1Input(name,values));
+					return;
+				}
+				default: _error_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+			}
+		default: _error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromVector(int* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromVector(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromVector(bool* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromVector(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+
+	/*Intermediaries*/
+	Element *element      = NULL;
+	Parameters* parameters= NULL;
+	int         dim;
+
+	/*Recover element*/
+	element=(Element*)helement->delivers();
+
+	/*Check that name is an element input*/
+	if (!IsInput(name)) return;
+
+	switch(type){
+
+		case VertexEnum:
+
+			switch(element->ObjectEnum()){
+
+				case TriaEnum: {
+					IssmDouble values[3];
+					for (int i=0;i<3;i++) values[i]=vector[((Tria*)element)->nodes[i]->GetVertexSid()]; //index into serial oriented vector 
+					this->inputs->AddInput(new TriaP1Input(name,values));
+					/*Special case for rheology B in 2D: Pourave land for this solution{{{*/
+					if(name==MaterialsRheologyBEnum){
+						/*Are we in 2D?:*/
+						if(element->ObjectEnum()==TriaEnum){
+							parameters=((Tria*)(element))->parameters;
+						}
+						else{
+							parameters=((Penta*)(element))->parameters;
+						}
+						parameters->FindParam(&dim,MeshDimensionEnum);
+						if(dim==2){
+							/*Dupliacte rheology input: */
+							this->inputs->AddInput(new TriaP1Input(MaterialsRheologyBbarEnum,values));
+						}
+					}
+					/*}}}*/
+					return;
+				}
+				default: _error_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+			}
+		default: _error_("type " << type << " (" << EnumToStringx(type) << ") not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromMatrixDakota(int* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols,int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromVectorDakota(int* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromVectorDakota(bool* vector, int name, int type) {{{*/
+void  Matice::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromConstant(IssmDouble constant, int name) {{{*/
+void  Matice::InputUpdateFromConstant(IssmDouble constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromConstant(int constant, int name) {{{*/
+void  Matice::InputUpdateFromConstant(int constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromConstant(bool constant, int name) {{{*/
+void  Matice::InputUpdateFromConstant(bool constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromSolution{{{*/
+void  Matice::InputUpdateFromSolution(IssmDouble* solution){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matice::InputUpdateFromIoModel{{{*/
+void Matice::InputUpdateFromIoModel(int index, IoModel* iomodel){
+
+	int i,j;
+
+	int    dim;
+	bool   control_analysis;
+	int    num_control_type;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&dim,MeshDimensionEnum);
+	iomodel->Constant(&control_analysis,InversionIscontrolEnum);
+	if(control_analysis) iomodel->Constant(&num_control_type,InversionNumControlParametersEnum);
+
+	/*if 2d*/
+	if(dim==2){
+
+		/*Intermediaries*/
+		const int num_vertices = 3; //Tria has 3 vertices
+		IssmDouble    nodeinputs[num_vertices];
+		IssmDouble    cmmininputs[num_vertices];
+		IssmDouble    cmmaxinputs[num_vertices];
+
+		/*Get B*/
+		if (iomodel->Data(MaterialsRheologyBEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+i]-1)];
+			this->inputs->AddInput(new TriaP1Input(MaterialsRheologyBbarEnum,nodeinputs));
+		}
+
+		/*Get n*/
+		if (iomodel->Data(MaterialsRheologyNEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyNEnum)[index];
+			this->inputs->AddInput(new TriaP1Input(MaterialsRheologyNEnum,nodeinputs));
+		}
+
+		/*Control Inputs*/
+		#ifdef _HAVE_CONTROL_
+		if (control_analysis && iomodel->Data(InversionControlParametersEnum)){
+			for(i=0;i<num_control_type;i++){
+				switch(reCast<int>(iomodel->Data(InversionControlParametersEnum)[i])){
+					case MaterialsRheologyBbarEnum:
+						if (iomodel->Data(MaterialsRheologyBEnum)){
+							_assert_(iomodel->Data(MaterialsRheologyBEnum));_assert_(iomodel->Data(InversionMinParametersEnum)); _assert_(iomodel->Data(InversionMaxParametersEnum)); 
+							for(j=0;j<num_vertices;j++)nodeinputs[j]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							this->inputs->AddInput(new ControlInput(MaterialsRheologyBbarEnum,TriaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+						}
+						break;
+				}
+			}
+		}
+		#endif
+	}
+
+	/*if 3d*/
+	#ifdef _HAVE_3D_
+	else if(dim==3){
+
+		/*Intermediaries*/
+		const int num_vertices = 6; //Penta has 6 vertices
+		IssmDouble    nodeinputs[num_vertices];
+		IssmDouble    cmmininputs[num_vertices];
+		IssmDouble    cmmaxinputs[num_vertices];
+
+		/*Get B*/
+		if (iomodel->Data(MaterialsRheologyBEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+i]-1)];
+			this->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,nodeinputs));
+		}
+
+		/*Get n*/
+		if (iomodel->Data(MaterialsRheologyNEnum)) {
+			for(i=0;i<num_vertices;i++) nodeinputs[i]=iomodel->Data(MaterialsRheologyNEnum)[index];
+			this->inputs->AddInput(new PentaP1Input(MaterialsRheologyNEnum,nodeinputs));
+		}
+
+		/*Control Inputs*/
+		#ifdef _HAVE_CONTROL_
+		if (control_analysis && iomodel->Data(InversionControlParametersEnum)){
+			for(i=0;i<num_control_type;i++){
+				switch(reCast<int>(iomodel->Data(InversionControlParametersEnum)[i])){
+					case MaterialsRheologyBbarEnum:
+						if (iomodel->Data(MaterialsRheologyBEnum)){
+							_assert_(iomodel->Data(MaterialsRheologyBEnum));_assert_(iomodel->Data(InversionMinParametersEnum)); _assert_(iomodel->Data(InversionMaxParametersEnum)); 
+							for(j=0;j<num_vertices;j++)nodeinputs[j]=iomodel->Data(MaterialsRheologyBEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[reCast<int,IssmDouble>(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							this->inputs->AddInput(new ControlInput(MaterialsRheologyBEnum,PentaP1InputEnum,nodeinputs,cmmininputs,cmmaxinputs,i+1));
+						}
+						break;
+				}
+			}
+		}
+		#endif
+	}
+	#endif
+	else{
+		_error_("Mesh type not supported yet!");
+	}
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Matice::IsInput{{{*/
+bool Matice::IsInput(int name){
+	if (
+				name==MaterialsRheologyBEnum ||
+				name==MaterialsRheologyBbarEnum ||
+				name==MaterialsRheologyNEnum
+		){
+		return true;
+	}
+	else return false;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Materials/Matice.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Matice.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Matice.h	(revision 15012)
@@ -0,0 +1,76 @@
+/*!\file Matice.h
+ * \brief: header file for matice object
+ */
+
+#ifndef MATICE_H_
+#define MATICE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Material.h"
+#include "../Hook.h"
+class IoModel;
+class Elements;
+class Loads;
+class Nodes;
+class Vertices;
+class Materials;
+class Parameters;
+/*}}}*/
+
+class Matice: public Material{
+
+	private: 
+		int   mid;
+		Hook *helement;
+
+	public:
+		/*Matice constructors, destructors: {{{*/
+		Matice();
+		Matice(int mid,int i, IoModel* iomodel);
+		~Matice();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions definitions: {{{*/
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrow, int ncols, int name, int type);
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solution);
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel);
+		/*}}}*/
+		/*Material virtual functions resolution: {{{*/
+		void   InputDuplicate(int original_enum,int new_enum);
+		void   Configure(Elements* elements);
+		void   GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum);
+		void       SetCurrentConfiguration(Elements* elements,Loads* loads,Nodes* nodes,Vertices* vertices,Materials* materials,Parameters* parameters);
+		void       GetViscosity2d(IssmDouble* pviscosity, IssmDouble* pepsilon);
+		void       GetViscosity3d(IssmDouble* pviscosity3d, IssmDouble* pepsilon);
+		void       GetViscosity3dStokes(IssmDouble* pviscosity3d, IssmDouble* epsilon);
+		void       GetViscosityComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon);
+		void GetViscosityZComplement(IssmDouble*, IssmDouble*){_error_("not supported");};
+		void       GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon);
+		void       GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon);
+		IssmDouble GetA();
+		IssmDouble GetB();
+		IssmDouble GetBbar();
+		IssmDouble GetZ(){_error_("not supported");};
+		IssmDouble GetZbar(){_error_("not supported");};
+		IssmDouble GetN();
+		bool       IsInput(int name);
+		/*}}}*/
+};
+
+#endif  /* _MATICE_H_ */
Index: /issm/trunk-jpl/src/c/classes/Materials/Matpar.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Matpar.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Matpar.cpp	(revision 15012)
@@ -0,0 +1,463 @@
+/*!\file Matpar.c
+ * \brief: implementation of the Matpar object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+
+/*Matpar constructors and destructor*/
+/*FUNCTION Matpar::Matpar() {{{*/
+Matpar::Matpar(){
+	return;
+}
+/*}}}*/
+/*FUNCTION Matpar::Matpar(int matpar_mid,IoModel* iomodel){{{*/
+Matpar::Matpar(int matpar_mid, IoModel* iomodel){
+
+	bool ispdd;
+	bool isefficientlayer;
+	int  hydrology_model;
+	iomodel->Constant(&hydrology_model,HydrologyModelEnum);
+	iomodel->Constant(&ispdd,SurfaceforcingsIspddEnum);
+
+	this->mid = matpar_mid;
+	iomodel->Constant(&this->rho_ice,MaterialsRhoIceEnum);
+	iomodel->Constant(&this->rho_water,MaterialsRhoWaterEnum);
+	iomodel->Constant(&this->rho_freshwater,MaterialsRhoFreshwaterEnum);
+	iomodel->Constant(&this->mu_water,MaterialsMuWaterEnum);
+	iomodel->Constant(&this->heatcapacity,MaterialsHeatcapacityEnum);
+	iomodel->Constant(&this->thermalconductivity,MaterialsThermalconductivityEnum);
+	iomodel->Constant(&this->latentheat,MaterialsLatentheatEnum);
+	iomodel->Constant(&this->beta,MaterialsBetaEnum);
+	iomodel->Constant(&this->meltingpoint,MaterialsMeltingpointEnum);
+	iomodel->Constant(&this->referencetemperature,ConstantsReferencetemperatureEnum);
+	iomodel->Constant(&this->mixed_layer_capacity,MaterialsMixedLayerCapacityEnum);
+	iomodel->Constant(&this->thermal_exchange_velocity,MaterialsThermalExchangeVelocityEnum);
+	iomodel->Constant(&this->g,ConstantsGEnum);
+
+	if(ispdd){
+		iomodel->Constant(&this->desfac,SurfaceforcingsDesfacEnum);
+		iomodel->Constant(&this->s0p,SurfaceforcingsS0pEnum);
+	}
+
+	if(hydrology_model==HydrologyshreveEnum){
+		iomodel->Constant(&this->hydro_CR,HydrologyshreveCREnum);
+		iomodel->Constant(&this->hydro_kn,HydrologyshreveKnEnum);
+		iomodel->Constant(&this->hydro_n,HydrologyshreveNEnum);
+		iomodel->Constant(&this->hydro_p,HydrologyshrevePEnum);
+		iomodel->Constant(&this->hydro_q,HydrologyshreveQEnum);
+	}
+	else if(hydrology_model==HydrologydcEnum){
+		iomodel->Constant(&this->sediment_compressibility,HydrologydcSedimentCompressibilityEnum);
+		iomodel->Constant(&this->sediment_porosity,HydrologydcSedimentPorosityEnum);
+		iomodel->Constant(&this->sediment_thickness,HydrologydcSedimentThicknessEnum);
+		iomodel->Constant(&this->sediment_transmitivity,HydrologydcSedimentTransmitivityEnum);
+		iomodel->Constant(&this->water_compressibility,HydrologydcWaterCompressibilityEnum);
+		iomodel->Constant(&isefficientlayer,HydrologydcIsefficientlayerEnum);
+
+		if(isefficientlayer){
+				iomodel->Constant(&this->epl_compressibility,HydrologydcEplCompressibilityEnum);
+				iomodel->Constant(&this->epl_porosity,HydrologydcEplPorosityEnum);
+				iomodel->Constant(&this->epl_thickness,HydrologydcEplThicknessEnum);
+				iomodel->Constant(&this->epl_transmitivity,HydrologydcEplTransmitivityEnum);
+		}
+	}
+	else{
+		_error_("Hydrology model "<<EnumToStringx(hydrology_model)<<" not supported yet");
+	}
+
+	/*gia: */
+	iomodel->Constant(&this->lithosphere_shear_modulus,MaterialsLithosphereShearModulusEnum);
+	iomodel->Constant(&this->lithosphere_density,MaterialsLithosphereDensityEnum);
+	iomodel->Constant(&this->mantle_shear_modulus,MaterialsMantleShearModulusEnum);
+	iomodel->Constant(&this->mantle_density,MaterialsMantleDensityEnum);
+
+	/*Unit conversion: */
+	this->UnitConversion();
+
+	this->inputs=NULL; /*not used here*/
+}
+/*}}}*/
+/*FUNCTION Matpar::~Matpar() {{{*/
+Matpar::~Matpar(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Matpar::Echo {{{*/
+void Matpar::Echo(void){
+
+	_printLine_("Matpar:");
+	_printLine_("   mid: " << mid);
+	_printLine_("   rho_ice: " << rho_ice);
+	_printLine_("   rho_water: " << rho_water);
+	_printLine_("   rho_freshwater: " << rho_freshwater);
+	_printLine_("   mu_water: " << mu_water);
+	_printLine_("   heatcapacity: " << heatcapacity);
+	_printLine_("   thermalconductivity: " << thermalconductivity);
+	_printLine_("   latentheat: " << latentheat);
+	_printLine_("   beta: " << beta);
+	_printLine_("   meltingpoint: " << meltingpoint);
+	_printLine_("   referencetemperature: " << referencetemperature);
+	_printLine_("   mixed_layer_capacity: " << mixed_layer_capacity);
+	_printLine_("   thermal_exchange_velocity: " << thermal_exchange_velocity);
+	_printLine_("   g: " << g);
+	_printLine_("   desfac: " << desfac);
+	_printLine_("   s0p: " << s0p);
+	return;
+}
+/*}}}*/
+/*FUNCTION Matpar::DeepEcho {{{*/
+void Matpar::DeepEcho(void){
+
+	this->Echo();
+}		
+/*}}}*/
+/*FUNCTION Matpar::Id {{{*/
+int    Matpar::Id(void){ return mid; }
+/*}}}*/
+/*FUNCTION Matpar::ObjectEnum{{{*/
+int Matpar::ObjectEnum(void){
+
+	return MatparEnum;
+
+}
+/*}}}*/
+/*FUNCTION Matpar::copy {{{*/
+Object* Matpar::copy() {
+	return new Matpar(*this); 
+}
+/*}}}*/
+
+/*Update virtual functions definitions:*/
+/*FUNCTION Matpar::InputUpdateFromVector(IssmDouble* vector, int name, int type) {{{*/
+void   Matpar::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromVector(int* vector, int name, int type) {{{*/
+void   Matpar::InputUpdateFromVector(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromVector(bool* vector, int name, int type) {{{*/
+void   Matpar::InputUpdateFromVector(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type) {{{*/
+void   Matpar::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromVectorDakota(int* vector, int name, int type) {{{*/
+void   Matpar::InputUpdateFromVectorDakota(int* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromVectorDakota(bool* vector, int name, int type) {{{*/
+void   Matpar::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromMatrixDakota(int* vector, int name, int type) {{{*/
+void  Matpar::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols,int name, int type){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromConstant(IssmDouble constant, int name) {{{*/
+void   Matpar::InputUpdateFromConstant(IssmDouble constant, int name){
+
+	switch(name){
+		case MaterialsRhoIceEnum:
+			this->rho_ice=constant;
+			break;
+		case MaterialsRhoWaterEnum:
+			this->rho_water=constant;
+			break;
+		case MaterialsRhoFreshwaterEnum:
+			this->rho_freshwater=constant;
+			break;
+		case MaterialsMuWaterEnum:
+			this->mu_water=constant;
+			break;
+		case MaterialsHeatcapacityEnum:
+			this->heatcapacity=constant;
+			break;
+		case MaterialsThermalconductivityEnum:
+			this->thermalconductivity=constant;
+			break;
+		case  MaterialsLatentheatEnum:
+			this->latentheat=constant;
+			break;
+		case  MaterialsBetaEnum:
+			this->beta=constant;
+			break;
+		case  MaterialsMeltingpointEnum:
+			this->meltingpoint=constant;
+			break;
+		case  ConstantsReferencetemperatureEnum:
+			this->referencetemperature=constant;
+			break;
+		case  MaterialsMixedLayerCapacityEnum:
+			this->mixed_layer_capacity=constant;
+			break;
+		case  MaterialsThermalExchangeVelocityEnum:
+			this->thermalconductivity=constant;
+			break;
+		case  ConstantsGEnum:
+			this->g=constant;
+			break;
+  	        case  SurfaceforcingsDesfacEnum:
+			this->desfac=constant;
+			break;
+		case SurfaceforcingsS0pEnum:
+			this->s0p=constant;
+			break;
+		default: 
+			break;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromConstant(int constant, int name) {{{*/
+void   Matpar::InputUpdateFromConstant(int constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromConstant(bool constant, int name) {{{*/
+void   Matpar::InputUpdateFromConstant(bool constant, int name){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Matpar::InputUpdateFromSolution{{{*/
+void   Matpar::InputUpdateFromSolution(IssmDouble* solution){
+	/*Nothing updated yet*/
+}
+/*}}}*/
+
+/*Matpar management: */
+/*FUNCTION Matpar::Configure {{{*/
+void  Matpar::Configure(Elements* elementsin){
+
+	/*nothing done yet!*/
+
+}
+/*}}}*/
+/*FUNCTION Matpar::GetBeta {{{*/
+IssmDouble Matpar::GetBeta(){
+	return beta;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetG {{{*/
+IssmDouble Matpar::GetG(){
+	return g;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetHeatCapacity {{{*/
+IssmDouble Matpar::GetHeatCapacity(){
+	return heatcapacity;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetLatentHeat {{{*/
+IssmDouble Matpar::GetLatentHeat(){
+	return latentheat;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetMeltingPoint {{{*/
+IssmDouble Matpar::GetMeltingPoint(){
+	return meltingpoint;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetReferenceTemperature {{{*/
+IssmDouble Matpar::GetReferenceTemperature(){
+	return referencetemperature;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetMixedLayerCapacity {{{*/
+IssmDouble Matpar::GetMixedLayerCapacity(){
+	return mixed_layer_capacity;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetRhoIce {{{*/
+IssmDouble Matpar::GetRhoIce(){
+
+	return rho_ice;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetRhoWater {{{*/
+IssmDouble Matpar::GetRhoWater(){
+	return rho_water;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetRhoFreshwater {{{*/
+IssmDouble Matpar::GetRhoFreshwater(){
+	return rho_freshwater;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetMuWater {{{*/
+IssmDouble Matpar::GetMuWater(){
+	return mu_water;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetDesFac {{{*/
+IssmDouble Matpar::GetDesFac(){
+	return desfac;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetS0p {{{*/
+IssmDouble Matpar::GetS0p(){
+	return s0p;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetThermalConductivity {{{*/
+IssmDouble Matpar::GetThermalConductivity(){
+	return thermalconductivity;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetThermalExchangeVelocity {{{*/
+IssmDouble Matpar::GetThermalExchangeVelocity(){
+	return thermal_exchange_velocity;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetHydrologyKn {{{*/
+IssmDouble Matpar::GetHydrologyKn(){
+	return hydro_kn;		 
+}		 
+/*}}}*/			 
+/*FUNCTION Matpar::GetHydrologyP {{{*/			 
+IssmDouble Matpar::GetHydrologyP(){		 
+	return hydro_p;			 
+}		 
+/*}}}*/			 
+/*FUNCTION Matqar::GetHydrologyQ {{{*/			 
+IssmDouble Matpar::GetHydrologyQ(){		 
+	return hydro_q;			 
+}		 
+/*}}}*/			 
+/*FUNCTION Matpar::GetHydrologyCR {{{*/		 
+IssmDouble Matpar::GetHydrologyCR(){		 
+	return hydro_CR;		 
+}		 
+/*}}}*/			 
+/*FUNCTION Matpar::GetHydrologyN {{{*/			 
+IssmDouble Matpar::GetHydrologyN(){		 
+	return hydro_n;			 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetSedimentStoring {{{*/
+IssmDouble Matpar::GetSedimentStoring(){
+	return this->rho_freshwater* this->g* this->sediment_porosity* this->sediment_thickness*
+    ( this->water_compressibility+( this->sediment_compressibility/ this->sediment_porosity));		 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetEplStoring {{{*/
+IssmDouble Matpar::GetEplStoring(){
+	return this->rho_freshwater* this->g* this->epl_porosity* this->epl_thickness*
+    ( this->water_compressibility+( this->epl_compressibility/ this->epl_porosity));		 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetSedimentTransitivity {{{*/
+IssmDouble Matpar::GetSedimentTransmitivity(){
+	return sediment_transmitivity;		 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetEplTransitivity {{{*/
+IssmDouble Matpar::GetEplTransmitivity(){
+	return epl_transmitivity;		 
+}		 
+/*}}}*/			 
+/*FUNCTION Matpar::TMeltingPoint {{{*/
+IssmDouble Matpar::TMeltingPoint(IssmDouble pressure){
+	return meltingpoint-beta*pressure;
+}
+/*}}}*/
+/*FUNCTION Matpar::PureIceEnthalpy{{{*/
+IssmDouble Matpar::PureIceEnthalpy(IssmDouble pressure){
+	return heatcapacity*(TMeltingPoint(pressure)-referencetemperature);
+}
+/*}}}*/
+/*FUNCTION Matpar::GetEnthalpyDiffusionParameter{{{*/
+IssmDouble Matpar::GetEnthalpyDiffusionParameter(IssmDouble enthalpy,IssmDouble pressure){
+	if(enthalpy<PureIceEnthalpy(pressure)){
+		return thermalconductivity/(rho_ice*heatcapacity);
+	}
+	else{
+		return 0.1*thermalconductivity/(rho_ice*heatcapacity);
+	}
+}
+/*}}}*/
+/*FUNCTION Matpar::EnthalpyToThermal {{{*/
+void Matpar::EnthalpyToThermal(IssmDouble* ptemperature,IssmDouble* pwaterfraction,IssmDouble enthalpy,IssmDouble pressure){
+
+	/*Ouput*/
+	IssmDouble temperature,waterfraction;
+
+	if(enthalpy<PureIceEnthalpy(pressure)){
+		temperature=referencetemperature+enthalpy/heatcapacity;
+		waterfraction=0;
+	}
+	else{
+		temperature=TMeltingPoint(pressure);
+		waterfraction=(enthalpy-PureIceEnthalpy(pressure))/latentheat;
+	}
+
+	/*Assign output pointers:*/
+	*pwaterfraction=waterfraction;
+	*ptemperature=temperature;
+}
+/*}}}*/
+/*FUNCTION Matpar::ThermalToEnthalpy {{{*/
+void Matpar::ThermalToEnthalpy(IssmDouble * penthalpy,IssmDouble temperature,IssmDouble waterfraction,IssmDouble pressure){
+
+	/*Ouput*/
+	IssmDouble enthalpy;
+
+	if(temperature<TMeltingPoint(pressure)){
+		enthalpy=heatcapacity*(temperature-referencetemperature);
+	}
+	else{
+		enthalpy=PureIceEnthalpy(pressure)+latentheat*waterfraction;
+	}
+
+	/*Assign output pointers:*/
+	*penthalpy=enthalpy;
+}
+/*}}}*/
+
+/*FUNCTION Matpar::GetLithosphereShearModulus {{{*/			 
+IssmDouble Matpar::GetLithosphereShearModulus(){		 
+	return lithosphere_shear_modulus;			 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetLithosphereDensity {{{*/			 
+IssmDouble Matpar::GetLithosphereDensity(){		 
+	return lithosphere_density;			 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetMantleDensity {{{*/			 
+IssmDouble Matpar::GetMantleDensity(){		 
+	return mantle_density;			 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::GetMantleShearModulus {{{*/			 
+IssmDouble Matpar::GetMantleShearModulus(){		 
+	return mantle_shear_modulus;			 
+}		 
+/*}}}*/ 
+/*FUNCTION Matpar::UnitConversion {{{*/			 
+void Matpar::UnitConversion(void){		 
+
+	/*convert units of fields that were allocated using the Ext unit system, into the Iu unit system: */
+	::UnitConversion(&this->lithosphere_density,1,ExtToIuEnum,MaterialsLithosphereDensityEnum);
+	::UnitConversion(&this->mantle_density,1,ExtToIuEnum,MaterialsMantleDensityEnum);
+
+}		 
+/*}}}*/ 
Index: /issm/trunk-jpl/src/c/classes/Materials/Matpar.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Materials/Matpar.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Materials/Matpar.h	(revision 15012)
@@ -0,0 +1,142 @@
+/*!\file Matpar.h
+ * \brief: header file for matpar object
+ */
+
+#ifndef _MATPAR_H_
+#define _MATPAR_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Material.h"
+class IoModel;
+/*}}}*/
+
+class Matpar: public Material{
+
+	private: 
+		int	  mid;
+		IssmDouble  rho_ice; 
+		IssmDouble  rho_water;
+		IssmDouble  rho_freshwater;
+		IssmDouble  mu_water;
+		IssmDouble  heatcapacity;
+		IssmDouble  thermalconductivity;
+		IssmDouble  latentheat;
+		IssmDouble  beta;
+		IssmDouble  meltingpoint;
+		IssmDouble  referencetemperature;
+		IssmDouble  mixed_layer_capacity;
+		IssmDouble  thermal_exchange_velocity;
+		IssmDouble  g;
+		IssmDouble  desfac;
+		IssmDouble  s0p;
+
+		/*hydrology Shreve: */	 
+		IssmDouble  hydro_kn;			 
+		IssmDouble  hydro_p;		 
+		IssmDouble  hydro_q;		 
+		IssmDouble  hydro_CR;			 
+		IssmDouble  hydro_n; 
+
+		/*hydrology Dual Porous Continuum: */	 
+		IssmDouble  sediment_compressibility;
+		IssmDouble  sediment_porosity;	 
+		IssmDouble  sediment_thickness;
+		IssmDouble  sediment_transmitivity;	 
+		IssmDouble  water_compressibility;
+
+		IssmDouble  epl_compressibility;
+		IssmDouble  epl_porosity;	 
+		IssmDouble  epl_thickness;
+		IssmDouble  epl_transmitivity;	 
+
+		/*gia: */
+		IssmDouble lithosphere_shear_modulus;
+		IssmDouble lithosphere_density;
+		IssmDouble mantle_shear_modulus;
+		IssmDouble mantle_density;
+
+	public:
+		Matpar();
+		Matpar(int matpar_id, IoModel* iomodel);
+		~Matpar();
+
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void   InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void   InputUpdateFromVector(int* vector, int name, int type);
+		void   InputUpdateFromVector(bool* vector, int name, int type);
+		void   InputUpdateFromMatrixDakota(IssmDouble* matrix,int nrows,int ncols, int name, int type);
+		void   InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void   InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void   InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void   InputUpdateFromConstant(IssmDouble constant, int name);
+		void   InputUpdateFromConstant(int constant, int name);
+		void   InputUpdateFromConstant(bool constant, int name);
+		void   InputUpdateFromSolution(IssmDouble* solution);
+		void   InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("not implemented yet");};
+		/*}}}*/
+		/*Material virtual functions resolution: {{{*/
+		void   InputDuplicate(int original_enum,int new_enum){_error_("not implemented yet");};
+		void   Configure(Elements* elements);
+		void   GetVectorFromInputs(Vector<IssmDouble>* vector,int input_enum){return;}
+		void       GetViscosity2d(IssmDouble* pviscosity, IssmDouble* pepsilon){_error_("not supported");};
+		void       GetViscosity3d(IssmDouble* pviscosity3d, IssmDouble* pepsilon){_error_("not supported");};
+		void       GetViscosity3dStokes(IssmDouble* pviscosity3d, IssmDouble* epsilon){_error_("not supported");};
+		void       GetViscosityComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon){_error_("not supported");};
+		void       GetViscosityZComplement(IssmDouble* pviscosity_complement, IssmDouble* pepsilon){_error_("not supported");};
+		void       GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon){_error_("not supported");};
+		void       GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon){_error_("not supported");};
+		IssmDouble GetA(){_error_("not supported");};
+		IssmDouble GetB(){_error_("not supported");};
+		IssmDouble GetBbar(){_error_("not supported");};
+		IssmDouble GetN(){_error_("not supported");};
+		IssmDouble GetZ(){_error_("not supported");};
+		IssmDouble GetZbar(){_error_("not supported");};
+		/*}}}*/
+		/*Numerics: {{{*/
+		IssmDouble GetG();
+		IssmDouble GetRhoIce();
+		IssmDouble GetRhoWater();
+		IssmDouble GetRhoFreshwater();
+		IssmDouble GetMuWater();
+		IssmDouble GetMixedLayerCapacity();
+		IssmDouble GetThermalExchangeVelocity();
+		IssmDouble GetHeatCapacity();
+		IssmDouble GetThermalConductivity();
+		IssmDouble GetLatentHeat();
+		IssmDouble GetBeta();
+		IssmDouble GetMeltingPoint();
+		IssmDouble GetReferenceTemperature();
+		IssmDouble GetHydrologyKn();
+		IssmDouble GetHydrologyP();
+		IssmDouble GetHydrologyQ();
+		IssmDouble GetHydrologyCR();
+		IssmDouble GetHydrologyN();
+		IssmDouble GetSedimentStoring();
+		IssmDouble GetEplStoring();
+		IssmDouble GetSedimentTransmitivity();
+		IssmDouble GetEplTransmitivity();
+		IssmDouble TMeltingPoint(IssmDouble pressure);
+		IssmDouble PureIceEnthalpy(IssmDouble pressure);
+		IssmDouble GetEnthalpyDiffusionParameter(IssmDouble enthalpy,IssmDouble pressure);
+		IssmDouble GetLithosphereShearModulus();
+		IssmDouble GetLithosphereDensity();
+		IssmDouble GetMantleShearModulus();
+		IssmDouble GetMantleDensity();
+		void   EnthalpyToThermal(IssmDouble* ptemperature,IssmDouble* pwaterfraction,IssmDouble enthalpy,IssmDouble pressure);
+		void   ThermalToEnthalpy(IssmDouble* penthalpy,IssmDouble temperature,IssmDouble waterfraction,IssmDouble pressure);
+		IssmDouble GetDesFac();
+		IssmDouble GetS0p(); 
+		void   UnitConversion(void);
+		/*}}}*/
+
+};
+
+#endif  /* _MATPAR_H_ */
Index: /issm/trunk-jpl/src/c/classes/Node.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Node.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Node.cpp	(revision 15012)
@@ -0,0 +1,1337 @@
+/*!\file Node.c
+ * \brief: implementation of the Node object
+ */
+
+/*Include files: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./classes.h"
+#include "shared/shared.h"
+#include "modules/ModelProcessorx/ModelProcessorx.h"
+/*}}}*/
+
+/*Node constructors and destructors:*/
+/*FUNCTION Node::Node() default constructor {{{*/
+Node::Node(){
+		 this->inputs=NULL;
+		 this->hvertex=NULL;
+		 return;
+}
+/*}}}*/
+/*FUNCTION Node::Node(int node_id,int node_sid,int vertex_id,int io_index, IoModel* iomodel,int analysis_type) {{{*/
+Node::Node(int node_id,int node_sid,int vertex_id,int io_index, IoModel* iomodel,int analysis_type){
+
+	/*Intermediary*/
+	int k,l;
+	int gsize;
+	int dim;
+
+	/*Fetch parameters: */
+	iomodel->Constant(&dim,MeshDimensionEnum);
+
+	/*id: */
+	this->id            = node_id;
+	this->sid           = node_sid;
+	this->analysis_type = analysis_type;
+
+	/*Initialize coord_system: Identity matrix by default*/
+	for(k=0;k<3;k++) for(l=0;l<3;l++) this->coord_system[k][l]=0.0;
+	for(k=0;k<3;k++) this->coord_system[k][k]=1.0;
+
+	/*indexing:*/
+	DistributeNumDofs(&this->indexing,analysis_type,iomodel->Data(FlowequationVertexEquationEnum)+io_index); //number of dofs per node
+	gsize=this->indexing.gsize;
+
+	/*Hooks*/
+	this->hvertex=new Hook(&vertex_id,1); //node id is the same as the vertex id, continuous galerkin!
+
+	//intialize inputs, and add as many inputs per element as requested: 
+	this->inputs=new Inputs();
+	if (iomodel->Data(MeshVertexonbedEnum))
+	 this->inputs->AddInput(new BoolInput(MeshVertexonbedEnum,reCast<bool>(iomodel->Data(MeshVertexonbedEnum)[io_index])));
+	if (iomodel->Data(MeshVertexonsurfaceEnum))
+	 this->inputs->AddInput(new BoolInput(MeshVertexonsurfaceEnum,reCast<bool>(iomodel->Data(MeshVertexonsurfaceEnum)[io_index])));
+	if (iomodel->Data(MaskVertexonfloatingiceEnum))
+	 this->inputs->AddInput(new BoolInput(MaskVertexonfloatingiceEnum,reCast<bool>(iomodel->Data(MaskVertexonfloatingiceEnum)[io_index])));
+	if (iomodel->Data(MaskVertexongroundediceEnum))
+	  this->inputs->AddInput(new BoolInput(MaskVertexongroundediceEnum,reCast<bool>(iomodel->Data(MaskVertexongroundediceEnum)[io_index])));
+	if (analysis_type==DiagnosticHorizAnalysisEnum)
+	 this->inputs->AddInput(new IntInput(ApproximationEnum,reCast<IssmInt>(iomodel->Data(FlowequationVertexEquationEnum)[io_index])));
+	/*set single point constraints: */
+
+	/*spc all nodes on water*/
+	if (!iomodel->Data(MaskVertexonwaterEnum)) _error_("iomodel->nodeonwater is NULL");
+	if (reCast<bool>(iomodel->Data(MaskVertexonwaterEnum)[io_index])){
+		for(k=1;k<=gsize;k++){
+			this->FreezeDof(k);
+		}
+	}
+
+	/*Diagnostic Horiz*/
+	#ifdef _HAVE_DIAGNOSTIC_
+	if (analysis_type==DiagnosticHorizAnalysisEnum){
+
+		/*Coordinate system provided, convert to coord_system matrix*/
+		_assert_(iomodel->Data(DiagnosticReferentialEnum)); 
+		XZvectorsToCoordinateSystem(&this->coord_system[0][0],iomodel->Data(DiagnosticReferentialEnum)+io_index*6);
+
+		if (dim==3){
+			/*We have a  3d mesh, we may have collapsed elements, hence dead nodes. Freeze them out: */
+			_assert_(iomodel->Data(MeshVertexonbedEnum)); 
+			_assert_(iomodel->Data(FlowequationVertexEquationEnum));
+			if (iomodel->Data(FlowequationVertexEquationEnum)[io_index]==MacAyealApproximationEnum && !reCast<int>(iomodel->Data(MeshVertexonbedEnum)[io_index])){
+				for(k=1;k<=gsize;k++) this->FreezeDof(k);
+			}
+			if (iomodel->Data(FlowequationVertexEquationEnum)[io_index]==L1L2ApproximationEnum && !reCast<int>(iomodel->Data(MeshVertexonbedEnum)[io_index])){
+				for(k=1;k<=gsize;k++) this->FreezeDof(k);
+			}
+			if (iomodel->Data(FlowequationVertexEquationEnum)[io_index]==MacAyealPattynApproximationEnum && reCast<int>(iomodel->Data(FlowequationBordermacayealEnum)[io_index])){
+				if(!reCast<int>(iomodel->Data(MeshVertexonbedEnum)[io_index])){
+					for(k=1;k<=gsize;k++) this->FreezeDof(k);
+				}
+			}
+			if (iomodel->Data(FlowequationVertexEquationEnum)[io_index]==MacAyealStokesApproximationEnum && reCast<int>(iomodel->Data(FlowequationBordermacayealEnum)[io_index])){
+				if(!reCast<int>(iomodel->Data(MeshVertexonbedEnum)[io_index])){
+					for(k=1;k<=2;k++) this->FreezeDof(k);
+				}
+			}
+		}
+		/*spc all nodes on hutter*/
+		if (iomodel->Data(FlowequationVertexEquationEnum)[io_index]==HutterApproximationEnum){
+			for(k=1;k<=gsize;k++){
+				this->FreezeDof(k);
+			}
+		}
+	}
+	#endif
+
+	/*Diagnostic Hutter*/
+	if (analysis_type==DiagnosticHutterAnalysisEnum){
+		_assert_(iomodel->Data(FlowequationVertexEquationEnum));
+		/*Constrain all nodes that are not Hutter*/
+		if (reCast<int>(iomodel->Data(FlowequationVertexEquationEnum)[io_index])!=HutterApproximationEnum){
+			for(k=1;k<=gsize;k++){
+				this->FreezeDof(k);
+			}
+		}
+	}
+
+	/*Prognostic/ Melting/ Slopecompute/ Balancethickness*/
+	if (
+				analysis_type==PrognosticAnalysisEnum || 
+				analysis_type==MeltingAnalysisEnum || 
+				analysis_type==BedSlopeAnalysisEnum || 
+				analysis_type==SurfaceSlopeAnalysisEnum || 
+				analysis_type==BalancethicknessAnalysisEnum
+				){
+		if (dim==3){
+			/*On a 3d mesh, we may have collapsed elements, hence dead nodes. Freeze them out: */
+			_assert_(iomodel->Data(MeshVertexonbedEnum));
+			if (!(reCast<bool>(iomodel->Data(MeshVertexonbedEnum)[io_index]))){
+				for(k=1;k<=gsize;k++){
+					this->FreezeDof(k);
+				}
+			}
+		}
+	}
+
+}
+/*}}}*/
+/*FUNCTION Node::~Node(){{{*/
+Node::~Node(){
+	delete inputs;
+	delete hvertex;
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Node::Echo{{{*/
+void Node::Echo(void){
+
+	_printLine_("Node:");
+	_printLine_("   id: " << id);
+	_printLine_("   sid: " << sid);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	indexing.Echo();
+	_printLine_("   hvertex:     not displayed");
+	_printLine_("   inputs:      " << inputs);
+
+}
+/*}}}*/
+/*FUNCTION Node::DeepEcho{{{*/
+void Node::DeepEcho(void){
+
+	_printLine_("Node:");
+	_printLine_("   id: " << id);
+	_printLine_("   sid: " << sid);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	indexing.DeepEcho();
+	_printLine_("Vertex:");
+	hvertex->DeepEcho();
+	_printLine_("   inputs");
+
+}
+/*}}}*/
+/*FUNCTION Node::Id{{{*/
+int    Node::Id(void){ return id; }
+/*}}}*/
+/*FUNCTION Node::ObjectEnum{{{*/
+int Node::ObjectEnum(void){
+
+	return NodeEnum;
+
+}
+/*}}}*/
+
+/*Node management:*/
+/*FUNCTION Node::Configure {{{*/
+void  Node::Configure(DataSet* nodesin,Vertices* verticesin){
+
+	/*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 off_sets hidden in hooks: */
+	hvertex->configure(verticesin);
+
+}/*}}}*/
+/*FUNCTION Node::SetCurrentConfiguration {{{*/
+void  Node::SetCurrentConfiguration(DataSet* nodesin,Vertices* verticesin){
+
+}/*}}}*/
+/*FUNCTION Node::GetDof {{{*/
+int   Node::GetDof(int dofindex,int setenum){
+
+	if(setenum==GsetEnum){
+		_assert_(dofindex>=0 && dofindex<indexing.gsize);
+		return indexing.gdoflist[dofindex];
+	}
+	else if(setenum==FsetEnum){
+		_assert_(dofindex>=0 && dofindex<indexing.fsize);
+		return indexing.fdoflist[dofindex];
+	}
+	else if(setenum==SsetEnum){
+		_assert_(dofindex>=0 && dofindex<indexing.ssize);
+		return indexing.sdoflist[dofindex];
+	}
+	else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+
+} /*}}}*/
+/*FUNCTION Node::GetDofList{{{*/
+void  Node::GetDofList(int* outdoflist,int approximation_enum,int setenum){
+	int i;
+	int count=0;
+	int count2=0;
+
+	if(approximation_enum==NoneApproximationEnum){
+		if(setenum==GsetEnum)for(i=0;i<this->indexing.gsize;i++) outdoflist[i]=indexing.gdoflist[i];
+		if(setenum==FsetEnum)for(i=0;i<this->indexing.fsize;i++) outdoflist[i]=indexing.fdoflist[i];
+		if(setenum==SsetEnum)for(i=0;i<this->indexing.ssize;i++) outdoflist[i]=indexing.sdoflist[i];
+	}
+	else{
+
+		if(setenum==GsetEnum){
+			if(indexing.doftype){
+				count=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.doftype[i]==approximation_enum){
+						outdoflist[count]=indexing.gdoflist[i];
+						count++;
+					}
+				}
+				_assert_(count); //at least one dof should be the approximation requested
+			}
+			else for(i=0;i<this->indexing.gsize;i++) outdoflist[i]=indexing.gdoflist[i];
+		}
+		else if(setenum==FsetEnum){
+			if(indexing.doftype){
+				count=0;
+				count2=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.f_set[i]){
+						if(indexing.doftype[i]==approximation_enum){
+							outdoflist[count]=indexing.fdoflist[count2];
+							count++;
+						}
+						count2++;
+					}
+				}
+			}
+			else for(i=0;i<this->indexing.fsize;i++) outdoflist[i]=indexing.fdoflist[i];
+		}
+		else if(setenum==SsetEnum){
+			if(indexing.doftype){
+				count=0;
+				count2=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.s_set[i]){
+						if(indexing.doftype[i]==approximation_enum){
+							outdoflist[count]=indexing.sdoflist[count2];
+							count++;
+						}
+						count2++;
+					}
+				}
+			}
+			else for(i=0;i<this->indexing.ssize;i++) outdoflist[i]=indexing.sdoflist[i];
+		}
+		else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+}
+/*}}}*/
+/*FUNCTION Node::GetLocalDofList{{{*/
+void  Node::GetLocalDofList(int* outdoflist,int approximation_enum,int setenum){
+	int i;
+	int count=0;
+	int count2=0;
+
+	if(approximation_enum==NoneApproximationEnum){
+		if(setenum==GsetEnum)for(i=0;i<this->indexing.gsize;i++) outdoflist[i]=i;
+		else if(setenum==FsetEnum){
+			count=0;
+			for(i=0;i<this->indexing.gsize;i++){
+				if(indexing.f_set[i]){
+					outdoflist[count]=i;
+					count++;
+				}
+			}
+		}
+		else if(setenum==SsetEnum){
+			count=0;
+			for(i=0;i<this->indexing.gsize;i++){
+				if(indexing.s_set[i]){
+					outdoflist[count]=i;
+					count++;
+				}
+			}
+		}
+		else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+	else{
+
+		if(setenum==GsetEnum){
+			if(indexing.doftype){
+				count=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.doftype[i]==approximation_enum){
+						outdoflist[count]=count;
+						count++;
+					}
+				}
+				_assert_(count);
+			}
+			else for(i=0;i<this->indexing.gsize;i++) outdoflist[i]=i;
+		}
+		else if(setenum==FsetEnum){
+
+			if(indexing.doftype){
+				count=0;
+				count2=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.doftype[i]==approximation_enum){
+						if(indexing.f_set[i]){
+							outdoflist[count]=count2;
+							count++;
+						}
+						count2++;
+					}
+				}
+				_assert_(count2);
+			}
+			else{
+
+				count=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.f_set[i]){
+						outdoflist[count]=i;
+						count++;
+					}
+				}
+			}
+		}
+		else if(setenum==SsetEnum){
+			if(indexing.doftype){
+				count=0;
+				count2=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.doftype[i]==approximation_enum){
+						if(indexing.s_set[i]){
+							outdoflist[count]=count2;
+							count++;
+						}
+						count2++;
+					}
+				}
+				_assert_(count2);
+			}
+			else{
+				count=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(indexing.s_set[i]){
+						outdoflist[count]=i;
+						count++;
+					}
+				}
+			}
+		}
+		else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+}
+/*}}}*/
+/*FUNCTION Node::Sid{{{*/
+int    Node::Sid(void){ return sid; }
+/*}}}*/
+/*FUNCTION Node::GetVertexId {{{*/
+int   Node::GetVertexId(void){
+
+	Vertex*  vertex=NULL;
+
+	vertex=(Vertex*)hvertex->delivers();
+	return vertex->id;
+}
+/*}}}*/
+/*FUNCTION Node::GetVertexPid{{{*/
+int   Node::GetVertexPid(void){
+
+	Vertex*  vertex=NULL;
+
+	vertex=(Vertex*)hvertex->delivers();
+	return vertex->pid;
+}
+/*}}}*/
+/*FUNCTION Node::GetVertexSid{{{*/
+int  Node::GetVertexSid(void){
+
+	Vertex* vertex=NULL;
+
+	vertex=(Vertex*)this->hvertex->delivers();
+
+	return vertex->sid;
+}
+/*}}}*/
+#ifdef _HAVE_DIAGNOSTIC_
+/*FUNCTION Node::GetCoordinateSystem{{{*/
+void Node::GetCoordinateSystem(IssmDouble* coord_system_out){
+
+	/*Copy coord_system*/
+	for(int k=0;k<3;k++) for(int l=0;l<3;l++) coord_system_out[3*k+l]=this->coord_system[k][l];
+
+}
+/*}}}*/
+#endif
+/*FUNCTION Node::InAnalysis{{{*/
+bool Node::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+
+/*Node numerics:*/
+/*FUNCTION Node::ApplyConstraints{{{*/
+void  Node::ApplyConstraint(int dof,IssmDouble value){
+
+	/*Dof should be added in the s set, describing which 
+	 * dofs are constrained to a certain value (dirichlet boundary condition*/
+	DofInSSet(dof-1);
+	this->indexing.svalues[dof-1]=value;
+}
+/*}}}*/
+/*FUNCTION Node::RelaxConstraint{{{*/
+void  Node::RelaxConstraint(int dof){
+
+	/*Dof should be added to the f-set, and taken out of the s-set:*/
+	DofInFSet(dof-1);
+	this->indexing.svalues[dof-1]=NAN;
+}
+/*}}}*/
+/*FUNCTION Node::CreateVecSets {{{*/
+void  Node::CreateVecSets(Vector<IssmDouble>* pv_g,Vector<IssmDouble>* pv_f,Vector<IssmDouble>* pv_s){
+
+	IssmDouble gvalue=1.0; //all nodes are in the g set;
+	IssmDouble value;
+
+	int i;
+
+	for(i=0;i<this->indexing.gsize;i++){
+
+		/*g set: */
+		pv_g->SetValue(indexing.gdoflist[i],gvalue,INS_VAL);
+
+		/*f set: */
+		value=(IssmDouble)this->indexing.f_set[i];
+		pv_f->SetValue(indexing.gdoflist[i],value,INS_VAL);
+
+		/*s set: */
+		value=(IssmDouble)this->indexing.s_set[i];
+		pv_s->SetValue(indexing.gdoflist[i],value,INS_VAL);
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION Node::CreateNodalConstraints{{{*/
+void  Node::CreateNodalConstraints(Vector<IssmDouble>* ys){
+
+	int i;
+	IssmDouble* values=NULL;
+	int count;
+
+	/*Recover values for s set and plug them in constraints vector: */
+	if(this->indexing.ssize){
+		values=xNew<IssmDouble>(this->indexing.ssize);
+		count=0;
+		for(i=0;i<this->indexing.gsize;i++){
+			if(this->indexing.s_set[i]){
+				values[count]=this->indexing.svalues[i];
+				_assert_(!xIsNan<IssmDouble>(values[count]));
+				count++;
+			}
+		}
+
+		/*Add values into constraint vector: */
+		ys->SetValues(this->indexing.ssize,this->indexing.sdoflist,values,INS_VAL);
+	}
+
+	/*Free ressources:*/
+	xDelete<IssmDouble>(values);
+
+}
+/*}}}*/
+/*FUNCTION Node::DofInSSet {{{*/
+void  Node::DofInSSet(int dof){
+
+	/*Put dof for this node into the s set (ie, this dof will be constrained 
+	 * to a fixed value during computations. */
+
+	this->indexing.f_set[dof]=0; //n splits into f (for which we solve) and s (single point constraints)
+	this->indexing.s_set[dof]=1;
+}
+/*}}}*/
+/*FUNCTION Node::DofInFSet {{{*/
+void  Node::DofInFSet(int dof){
+
+	/*Put dof for this node into the f set (ie, this dof will NOT be constrained 
+	 * to a fixed value during computations. */
+
+	this->indexing.f_set[dof]=1; 
+	this->indexing.s_set[dof]=0;
+}
+/*}}}*/
+/*FUNCTION Node::FreezeDof{{{*/
+void  Node::FreezeDof(int dof){
+
+	DofInSSet(dof-1); //with 0 displacement for this dof.
+
+}
+/*}}}*/
+/*FUNCTION Node::GetApproximation {{{*/
+int   Node::GetApproximation(){
+
+	int approximation;
+
+	/*recover parameters: */
+	inputs->GetInputValue(&approximation,ApproximationEnum);
+
+	return approximation;
+}
+/*}}}*/
+/*FUNCTION Node::GetConnectivity {{{*/
+int Node::GetConnectivity(){
+
+	Vertex*  vertex=NULL;
+	vertex=(Vertex*)hvertex->delivers();
+	return vertex->connectivity;
+}
+/*}}}*/
+/*FUNCTION Node::GetNumberOfDofs{{{*/
+int   Node::GetNumberOfDofs(int approximation_enum,int setenum){
+
+	/*Get number of degrees of freedom in a node, for a certain set (g,f or s-set)
+	 *and for a certain approximation type: */
+
+	int i;
+	int numdofs=0;
+
+	if(approximation_enum==NoneApproximationEnum){
+		if (setenum==GsetEnum) numdofs=this->indexing.gsize;
+		else if (setenum==FsetEnum) numdofs=this->indexing.fsize;
+		else if (setenum==SsetEnum) numdofs=this->indexing.ssize;
+		else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+	else{
+		if(setenum==GsetEnum){
+			if(this->indexing.doftype){
+				numdofs=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if(this->indexing.doftype[i]==approximation_enum) numdofs++;
+				}
+			}
+			else numdofs=this->indexing.gsize;
+		}
+		else if (setenum==FsetEnum){
+			if(this->indexing.doftype){
+				numdofs=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if((this->indexing.doftype[i]==approximation_enum) && (this->indexing.f_set[i])) numdofs++;
+				}
+			}
+			else numdofs=this->indexing.fsize;
+		}
+		else if (setenum==SsetEnum){
+			if(this->indexing.doftype){
+				numdofs=0;
+				for(i=0;i<this->indexing.gsize;i++){
+					if((this->indexing.doftype[i]==approximation_enum) && (this->indexing.s_set[i])) numdofs++;
+				}
+			}
+			else numdofs=this->indexing.ssize;
+		}
+		else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+	return numdofs;
+}
+/*}}}*/
+/*FUNCTION Node::IsClone {{{*/
+int   Node::IsClone(){
+
+	return indexing.clone;
+
+}
+/*}}}*/
+/*FUNCTION Node::IsOnBed {{{*/
+int   Node::IsOnBed(){
+
+	bool onbed;
+
+	/*recover parameters: */
+	inputs->GetInputValue(&onbed,MeshVertexonbedEnum);
+
+	return onbed;
+}
+/*}}}*/
+/*FUNCTION Node::IsGrounded {{{*/
+int   Node::IsGrounded(){
+
+	bool onsheet;
+
+	/*recover parameters: */
+	inputs->GetInputValue(&onsheet,MaskVertexongroundediceEnum);
+
+	return onsheet;
+}		
+/*}}}*/
+/*FUNCTION Node::IsFloating {{{*/
+int   Node::IsFloating(){
+
+	bool onshelf;
+
+	/*recover parameters: */
+	inputs->GetInputValue(&onshelf,MaskVertexonfloatingiceEnum);
+
+	return onshelf;
+}
+/*}}}*/
+/*FUNCTION Node::IsOnSurface {{{*/
+int   Node::IsOnSurface(){
+
+	bool onsurface;
+
+	/*recover parameters: */
+	inputs->GetInputValue(&onsurface,MeshVertexonsurfaceEnum);
+
+	return onsurface;
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromVector(IssmDouble* vector, int name, int type){{{*/
+void  Node::InputUpdateFromVector(IssmDouble* vector, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromVector(int* vector, int name, int type){{{*/
+void  Node::InputUpdateFromVector(int* vector, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromVector(bool* vector, int name, int type){{{*/
+void  Node::InputUpdateFromVector(bool* vector, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){{{*/
+void  Node::InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){{{*/
+void  Node::InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows, int ncols, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromVectorDakota(int* vector, int name, int type){{{*/
+void  Node::InputUpdateFromVectorDakota(int* vector, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromVectorDakota(bool* vector, int name, int type){{{*/
+void  Node::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromConstant(IssmDouble constant, int name){{{*/
+void  Node::InputUpdateFromConstant(IssmDouble constant, int name){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromConstant(int constant, int name){{{*/
+void  Node::InputUpdateFromConstant(int constant, int name){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::InputUpdateFromConstant(bool constant, int name){{{*/
+void  Node::InputUpdateFromConstant(bool constant, int name){
+
+	/*Nothing updated yet*/
+}
+/*}}}*/
+/*FUNCTION Node::UpdateSpcs {{{*/
+void   Node::UpdateSpcs(IssmDouble* ys){
+
+	int     count=0;
+	int     i;
+
+	count=0;
+	for(i=0;i<this->indexing.gsize;i++){
+		if(this->indexing.s_set[i]){
+			this->indexing.svalues[i]=ys[this->indexing.sdoflist[count]];
+			count++;
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION Node::VecMerge {{{*/
+void   Node::VecMerge(Vector<IssmDouble>* ug, IssmDouble* vector_serial,int setenum){
+
+	IssmDouble* values=NULL;
+	int*    indices=NULL;
+	int     count=0;
+	int     i;
+
+	if(setenum==FsetEnum){
+		if(this->indexing.fsize){
+			indices=xNew<int>(this->indexing.fsize);
+ 			values=xNew<IssmDouble>(this->indexing.fsize);
+
+			for(i=0;i<this->indexing.gsize;i++){
+				if(this->indexing.f_set[i]){
+					_assert_(vector_serial);
+					values[count]=vector_serial[this->indexing.fdoflist[count]];
+					indices[count]=this->indexing.gdoflist[i];
+					count++;
+				}
+			}
+
+			/*Add values into ug: */
+			ug->SetValues(this->indexing.fsize,indices,values,INS_VAL);
+		}
+	}
+	else if(setenum==SsetEnum){
+		if(this->indexing.ssize){
+			indices=xNew<int>(this->indexing.ssize);
+			values=xNew<IssmDouble>(this->indexing.ssize);
+
+			for(i=0;i<this->indexing.gsize;i++){
+				if(this->indexing.s_set[i]){
+					_assert_(vector_serial);
+					values[count]=vector_serial[this->indexing.sdoflist[count]];
+					indices[count]=this->indexing.gdoflist[i];
+					count++;
+				}
+			}
+
+			/*Add values into ug: */
+			ug->SetValues(this->indexing.ssize,indices,values,INS_VAL);
+		}
+	}
+	else _error_("VecMerge can only merge from the s or f-set onto the g-set!");
+
+	/*Free ressources:*/
+	xDelete<IssmDouble>(values);
+	xDelete<int>(indices);
+}
+/*}}}*/
+/*FUNCTION Node::VecReduce {{{*/
+void   Node::VecReduce(Vector<IssmDouble>* vector, IssmDouble* ug_serial,int setenum){
+
+	IssmDouble* values=NULL;
+	int     count=0;
+	int     i;
+
+	if(setenum==FsetEnum){
+		if(this->indexing.fsize){
+ 			values=xNew<IssmDouble>(this->indexing.fsize);
+
+			for(i=0;i<this->indexing.gsize;i++){
+				if(this->indexing.f_set[i]){
+					_assert_(ug_serial);
+					values[count]=ug_serial[this->indexing.gdoflist[i]];
+					count++;
+				}
+			}
+
+			/*Add values into ug: */
+			vector->SetValues(this->indexing.fsize,this->indexing.fdoflist,values,INS_VAL);
+		}
+	}
+	else if(setenum==SsetEnum){
+		if(this->indexing.ssize){
+			values=xNew<IssmDouble>(this->indexing.ssize);
+
+			for(i=0;i<this->indexing.gsize;i++){
+				if(this->indexing.s_set[i]){
+					_assert_(ug_serial);
+					values[count]=ug_serial[this->indexing.gdoflist[i]];
+					count++;
+				}
+			}
+
+			/*Add values into ug: */
+			vector->SetValues(this->indexing.ssize,this->indexing.sdoflist,values,INS_VAL);
+		}
+	}
+	else _error_("VecReduce can only merge from the s or f-set onto the g-set!");
+
+	/*Free ressources:*/
+	xDelete<IssmDouble>(values);
+}
+/*}}}*/
+
+/* indexing routines:*/
+/*FUNCTION Node::DistributeDofs{{{*/
+void  Node::DistributeDofs(int* pdofcount,int setenum){
+
+	int i;
+	int dofcount;
+
+	dofcount=*pdofcount;
+
+	/*Initialize: */
+	if(setenum==FsetEnum) this->indexing.InitSet(setenum);
+	if(setenum==SsetEnum) this->indexing.InitSet(setenum);
+
+	/*For clone nodfs, don't distribute dofs, we will get them from another cpu in UpdateCloneDofs!*/
+	if(indexing.clone){
+		return;
+	}
+
+	/*This node should distribute dofs for setenum set (eg, f_set or s_set), go ahead: */
+	if(setenum==GsetEnum){
+		for(i=0;i<this->indexing.gsize;i++){
+			indexing.gdoflist[i]=dofcount+i;
+		}
+		dofcount+=this->indexing.gsize;
+	}
+	else if(setenum==FsetEnum){
+		for(i=0;i<this->indexing.fsize;i++){
+			indexing.fdoflist[i]=dofcount+i;
+		}
+		dofcount+=this->indexing.fsize;
+	}
+	else if(setenum==SsetEnum){
+		for(i=0;i<this->indexing.ssize;i++){
+			indexing.sdoflist[i]=dofcount+i;
+		}
+		dofcount+=this->indexing.ssize;
+	}
+	else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+
+	/*Assign output pointers: */
+	*pdofcount=dofcount;
+}
+/*}}}*/
+/*FUNCTION Node::OffsetDofs{{{*/
+void  Node::OffsetDofs(int dofcount,int setenum){
+
+	int i;
+
+	if(indexing.clone){
+		/*This node is a clone, don't off_set the dofs!: */
+		return;
+	}
+
+	/*This node should off_set the dofs, go ahead: */
+	if(setenum==GsetEnum){
+		for(i=0;i<this->indexing.gsize;i++) indexing.gdoflist[i]+=dofcount;
+	}
+	else if(setenum==FsetEnum){
+		for(i=0;i<this->indexing.fsize;i++) indexing.fdoflist[i]+=dofcount;
+	}
+	else if(setenum==SsetEnum){
+		for(i=0;i<this->indexing.ssize;i++) indexing.sdoflist[i]+=dofcount;
+	}
+	else _error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Node::ShowTrueDofs{{{*/
+void  Node::ShowTrueDofs(int* truedofs, int ncols,int setenum){
+
+	int j;
+
+	/*Are we a clone? : */
+	if(indexing.clone) return;
+
+	/*Ok, we are not a clone, just plug our dofs into truedofs: */
+	switch(setenum){
+		case GsetEnum:
+			for(j=0;j<this->indexing.gsize;j++) truedofs[ncols*sid+j]=indexing.gdoflist[j];
+			break;
+		case FsetEnum:
+			for(j=0;j<this->indexing.fsize;j++) truedofs[ncols*sid+j]=indexing.fdoflist[j];
+			break;
+		case SsetEnum:
+			for(j=0;j<this->indexing.ssize;j++) truedofs[ncols*sid+j]=indexing.sdoflist[j];
+			break;
+		default:
+			_error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Node::UpdateCloneDofs{{{*/
+void  Node::UpdateCloneDofs(int* alltruedofs,int ncols,int setenum){
+
+	int j;
+
+	/*If we are not a clone, don't update, we already have dofs!: */
+	if(!indexing.clone)return;
+
+	/*Ok, we are a clone node, but we did not create the dofs for this node.
+	 *Therefore, our doflist is garbage right now. Go pick it up in the alltruedofs: */
+	switch(setenum){
+		case GsetEnum:
+			for(j=0;j<this->indexing.gsize;j++) indexing.gdoflist[j]=alltruedofs[ncols*sid+j];
+			break;
+		case FsetEnum:
+			for(j=0;j<this->indexing.fsize;j++) indexing.fdoflist[j]=alltruedofs[ncols*sid+j];
+			break;
+		case SsetEnum:
+			for(j=0;j<this->indexing.ssize;j++) indexing.sdoflist[j]=alltruedofs[ncols*sid+j];
+			break;
+		default:
+			_error_("set of enum type " << EnumToStringx(setenum) << " not supported yet!");
+	}
+}
+/*}}}*/
+/*FUNCTION Node::SetClone {{{*/
+void  Node::SetClone(int* minranks){
+
+	int my_rank;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	if (minranks[sid]==my_rank){
+		indexing.clone=false;
+	}
+	else{
+		/*!there is a cpu with lower rank that has the same node, 
+		therefore, I am a clone*/
+		indexing.clone=true;	
+	}
+}
+/*}}}*/
+
+
+/*Methods inherent to Node: */
+int* GetLocalDofList(Node** nodes,int numnodes,int setenum,int approximation){ /*{{{*/
+
+	int  i,j,count,numdof,numgdof;
+	int* ndof_list=NULL;
+	int* ngdof_list_cumulative=NULL;
+	int *doflist = NULL;
+
+	if(numnodes){
+		/*allocate: */
+		ndof_list=xNew<int>(numnodes);
+		ngdof_list_cumulative=xNew<int>(numnodes);
+
+		/*Get number of dofs per node, and total for this given set*/
+		numdof=0;
+		numgdof=0;
+		for(i=0;i<numnodes;i++){
+
+			/*Cumulative list= number of dofs before node i*/
+			ngdof_list_cumulative[i]=numgdof;
+
+			/*Number of dofs for node i for given set and for the g set*/
+			ndof_list[i]=nodes[i]->GetNumberOfDofs(approximation,setenum);
+			numgdof    +=nodes[i]->GetNumberOfDofs(approximation,GsetEnum);
+			numdof     +=ndof_list[i];
+		}
+
+		if(numdof){
+			/*Allocate: */
+			doflist=xNew<int>(numdof);
+
+			/*Populate: */
+			count=0;
+			for(i=0;i<numnodes;i++){
+				nodes[i]->GetLocalDofList(&doflist[count],approximation,setenum);
+				count+=ndof_list[i];
+			}
+
+			/*We now have something like: [0 1 0 2 1 2]. Offset by gsize, to get something like: [0 1 2 4 6 7]:*/
+			count=0;
+			for(i=0;i<numnodes;i++){
+				for(j=0;j<ndof_list[i];j++){
+					doflist[count+j]+=ngdof_list_cumulative[i];
+				}
+				count+=ndof_list[i];
+			}
+		}
+		else doflist=NULL;
+	}
+
+	/*Free ressources:*/
+	xDelete<int>(ndof_list);
+	xDelete<int>(ngdof_list_cumulative);
+
+	/*CLean-up and return*/
+	return doflist;
+}
+/*}}}*/
+int* GetGlobalDofList(Node** nodes,int numnodes,int setenum,int approximation){/*{{{*/
+
+
+	int  i,numdof,count;
+	int* ndof_list=NULL;
+	int *doflist = NULL;
+
+	if(numnodes){
+
+		/*Allocate:*/
+		ndof_list=xNew<int>(numnodes);
+
+		/*First, figure out size of doflist: */
+		numdof=0;
+		for(i=0;i<numnodes;i++){
+			ndof_list[i]=nodes[i]->GetNumberOfDofs(approximation,setenum);
+			numdof+=ndof_list[i];
+		}
+
+		if(numdof){
+			/*Allocate: */
+			doflist=xNew<int>(numdof);
+
+			/*Populate: */
+			count=0;
+			for(i=0;i<numnodes;i++){
+				nodes[i]->GetDofList(&doflist[count],approximation,setenum);
+				count+=ndof_list[i];
+			}
+		}
+		else doflist=NULL;
+	}
+	/*Free ressources:*/
+	xDelete<int>(ndof_list);
+
+	return doflist;
+}
+/*}}}*/
+int GetNumberOfDofs(Node** nodes,int numnodes,int setenum,int approximation){/*{{{*/
+
+
+	/*output: */
+	int numberofdofs=0;
+
+	for(int i=0;i<numnodes;i++){
+		numberofdofs+=nodes[i]->GetNumberOfDofs(approximation,setenum);
+	}
+
+	return numberofdofs;
+}
+/*}}}*/
+#ifdef _HAVE_DIAGNOSTIC_
+void TransformInvStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int cs_enum){/*{{{*/
+
+
+	int* cs_array=NULL;
+
+	/*All nodes have the same Coordinate System*/
+	cs_array=xNew<int>(numnodes);
+	for(int i=0;i<numnodes;i++) cs_array[i]=cs_enum;
+
+	/*Call core*/
+	TransformInvStiffnessMatrixCoord(Ke,nodes,numnodes,cs_array);
+
+	/*Clean-up*/
+	xDelete<int>(cs_array);
+}
+/*}}}*/
+void TransformInvStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int* cs_array){/*{{{*/
+
+
+	int     i,j;
+	int     numdofs   = 0;
+	IssmDouble *transform = NULL;
+	IssmDouble *values    = NULL;
+
+	/*Get total number of dofs*/
+	for(i=0;i<numnodes;i++){
+		switch(cs_array[i]){
+			case XYEnum:   numdofs+=2; break;
+			case XYZPEnum: numdofs+=4; break;
+			default: _error_("Coordinate system " << EnumToStringx(cs_array[i]) << " not supported yet");
+		}
+	}
+
+	/*Copy current stiffness matrix*/
+	values=xNew<IssmDouble>(Ke->nrows*Ke->ncols);
+	for(i=0;i<Ke->nrows;i++) for(j=0;j<Ke->ncols;j++) values[i*Ke->ncols+j]=Ke->values[i*Ke->ncols+j];
+
+	/*Get Coordinate Systems transform matrix*/
+	CoordinateSystemTransform(&transform,nodes,numnodes,cs_array);
+
+	/*Transform matrix: R*Ke*R^T */
+	TripleMultiply(transform,numdofs,numdofs,0,
+				values,Ke->nrows,Ke->ncols,0,
+				transform,numdofs,numdofs,1,
+				&Ke->values[0],0);
+
+	/*Free Matrix*/
+	xDelete<IssmDouble>(transform);
+	xDelete<IssmDouble>(values);
+}
+/*}}}*/
+void TransformLoadVectorCoord(ElementVector* pe,Node** nodes,int numnodes,int cs_enum){/*{{{*/
+
+	int* cs_array=NULL;
+
+	/*All nodes have the same Coordinate System*/
+	cs_array=xNew<int>(numnodes);
+	for(int i=0;i<numnodes;i++) cs_array[i]=cs_enum;
+
+	/*Call core*/
+	TransformLoadVectorCoord(pe,nodes,numnodes,cs_array);
+
+	/*Clean-up*/
+	xDelete<int>(cs_array);
+}
+/*}}}*/
+void TransformLoadVectorCoord(ElementVector* pe,Node** nodes,int numnodes,int* cs_array){/*{{{*/
+
+
+	int     i;
+	int     numdofs   = 0;
+	IssmDouble *transform = NULL;
+	IssmDouble *values    = NULL;
+
+	/*Get total number of dofs*/
+	for(i=0;i<numnodes;i++){
+		switch(cs_array[i]){
+			case XYEnum:   numdofs+=2; break;
+			case XYZPEnum: numdofs+=4; break;
+			default: _error_("Coordinate system " << EnumToStringx(cs_array[i]) << " not supported yet");
+		}
+	}
+
+	/*Copy current load vector*/
+	values=xNew<IssmDouble>(pe->nrows);
+	for(i=0;i<pe->nrows;i++) values[i]=pe->values[i];
+
+	/*Get Coordinate Systems transform matrix*/
+	CoordinateSystemTransform(&transform,nodes,numnodes,cs_array);
+
+	/*Transform matrix: R^T*pe */
+	MatrixMultiply(transform,numdofs,numdofs,1,
+				values,pe->nrows,1,0,
+				&pe->values[0],0);
+
+	/*Free Matrices*/
+	xDelete<IssmDouble>(transform);
+	xDelete<IssmDouble>(values);
+}
+/*}}}*/
+void TransformSolutionCoord(IssmDouble* solution,Node** nodes,int numnodes,int cs_enum){/*{{{*/
+
+
+	int* cs_array=NULL;
+
+	/*All nodes have the same Coordinate System*/
+	cs_array=xNew<int>(numnodes);
+	for(int i=0;i<numnodes;i++) cs_array[i]=cs_enum;
+
+	/*Call core*/
+	TransformSolutionCoord(solution,nodes,numnodes,cs_array);
+
+	/*Clean-up*/
+	xDelete<int>(cs_array);
+}
+/*}}}*/
+void TransformSolutionCoord(IssmDouble* solution,Node** nodes,int numnodes,int* cs_array){/*{{{*/
+
+
+	int     i;
+	int     numdofs   = 0;
+	IssmDouble *transform = NULL;
+	IssmDouble *values    = NULL;
+
+	/*Get total number of dofs*/
+	for(i=0;i<numnodes;i++){
+		switch(cs_array[i]){
+			case XYEnum:   numdofs+=2; break;
+			case XYZPEnum: numdofs+=4; break;
+			default: _error_("Coordinate system " << EnumToStringx(cs_array[i]) << " not supported yet");
+		}
+	}
+
+	/*Copy current solution vector*/
+	values=xNew<IssmDouble>(numdofs);
+	for(i=0;i<numdofs;i++) values[i]=solution[i];
+
+	/*Get Coordinate Systems transform matrix*/
+	CoordinateSystemTransform(&transform,nodes,numnodes,cs_array);
+
+	/*Transform matrix: R*U */
+	MatrixMultiply(transform,numdofs,numdofs,0,
+				values,numdofs,1,0,
+				&solution[0],0);
+
+	/*Free Matrices*/
+	xDelete<IssmDouble>(transform);
+	xDelete<IssmDouble>(values);
+}
+/*}}}*/
+void TransformStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int cs_enum){/*{{{*/
+
+
+	int* cs_array=NULL;
+
+	/*All nodes have the same Coordinate System*/
+	cs_array=xNew<int>(numnodes);
+	for(int i=0;i<numnodes;i++) cs_array[i]=cs_enum;
+
+	/*Call core*/
+	TransformStiffnessMatrixCoord(Ke,nodes,numnodes,cs_array);
+
+	/*Clean-up*/
+	xDelete<int>(cs_array);
+}
+/*}}}*/
+void TransformStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int* cs_array){/*{{{*/
+
+
+	int     i,j;
+	int     numdofs   = 0;
+	IssmDouble *transform = NULL;
+	IssmDouble *values    = NULL;
+
+	/*Get total number of dofs*/
+	for(i=0;i<numnodes;i++){
+		switch(cs_array[i]){
+			case XYEnum:   numdofs+=2; break;
+			case XYZPEnum: numdofs+=4; break;
+			default: _error_("Coordinate system " << EnumToStringx(cs_array[i]) << " not supported yet");
+		}
+	}
+
+	/*Copy current stiffness matrix*/
+	values=xNew<IssmDouble>(Ke->nrows*Ke->ncols);
+	for(i=0;i<Ke->nrows;i++) for(j=0;j<Ke->ncols;j++) values[i*Ke->ncols+j]=Ke->values[i*Ke->ncols+j];
+
+	/*Get Coordinate Systems transform matrix*/
+	CoordinateSystemTransform(&transform,nodes,numnodes,cs_array);
+
+	/*Transform matrix: R^T*Ke*R */
+	TripleMultiply(transform,numdofs,numdofs,1,
+				values,Ke->nrows,Ke->ncols,0,
+				transform,numdofs,numdofs,0,
+				&Ke->values[0],0);
+
+	/*Free Matrix*/
+	xDelete<IssmDouble>(transform);
+	xDelete<IssmDouble>(values);
+}
+/*}}}*/
+void CoordinateSystemTransform(IssmDouble** ptransform,Node** nodes,int numnodes,int* cs_array){/*{{{*/
+
+
+	int     i,counter;
+	int     numdofs           = 0;
+	IssmDouble  norm;
+	IssmDouble *transform         = NULL;
+	IssmDouble *values            = NULL;
+	IssmDouble  coord_system[3][3];
+
+	/*Some checks in debugging mode*/
+	_assert_(numnodes && nodes);
+
+	/*Get total number of dofs*/
+	for(i=0;i<numnodes;i++){
+		switch(cs_array[i]){
+			case XYEnum:   numdofs+=2; break;
+			case XYZPEnum: numdofs+=4; break;
+			default: _error_("Coordinate system " << EnumToStringx(cs_array[i]) << " not supported yet");
+		}
+	}
+
+	/*Allocate and initialize transform matrix*/
+	transform=xNew<IssmDouble>(numdofs*numdofs);
+	for(i=0;i<numdofs*numdofs;i++) transform[i]=0.0;
+
+	/*Create transform matrix for all nodes (x,y for 2d and x,y,z for 3d). It is a block matrix
+	 *for 3 nodes:
+
+	 *     | T1 0  0 |
+	 * Q = | 0  T2 0 |
+	 *     | 0  0  T3|
+	 *
+	 * Where T1 is the transform matrix for node 1. It is a simple copy of the coordinate system
+	 * associated to this node*/
+	counter=0;
+	for(i=0;i<numnodes;i++){
+		nodes[i]->GetCoordinateSystem(&coord_system[0][0]);
+		switch(cs_array[i]){
+			case XYEnum:
+				/*We remove the z component, we need to renormalize x and y: x=[x1 x2 0] y=[-x2 x1 0]*/
+				norm = sqrt( coord_system[0][0]*coord_system[0][0] + coord_system[1][0]*coord_system[1][0]); _assert_(norm>1.e-4);
+				transform[(numdofs)*(counter+0) + counter+0] =   coord_system[0][0]/norm;
+				transform[(numdofs)*(counter+0) + counter+1] = - coord_system[1][0]/norm;
+				transform[(numdofs)*(counter+1) + counter+0] =   coord_system[1][0]/norm;
+				transform[(numdofs)*(counter+1) + counter+1] =   coord_system[0][0]/norm;
+				counter+=2;
+				break;
+			case XYZPEnum:
+				/*Only the first 3 coordinates are changed (x,y,z), leave the others (P) unchanged*/
+				transform[(numdofs)*(counter+0) + counter+0] = coord_system[0][0];
+				transform[(numdofs)*(counter+0) + counter+1] = coord_system[0][1];
+				transform[(numdofs)*(counter+0) + counter+2] = coord_system[0][2];
+				transform[(numdofs)*(counter+1) + counter+0] = coord_system[1][0];
+				transform[(numdofs)*(counter+1) + counter+1] = coord_system[1][1];
+				transform[(numdofs)*(counter+1) + counter+2] = coord_system[1][2];
+				transform[(numdofs)*(counter+2) + counter+0] = coord_system[2][0];
+				transform[(numdofs)*(counter+2) + counter+1] = coord_system[2][1];
+				transform[(numdofs)*(counter+2) + counter+2] = coord_system[2][2];
+				transform[(numdofs)*(counter+3) + counter+3] = 1.0;
+				counter+=4;
+				break;
+			default:
+				_error_("Coordinate system " << EnumToStringx(cs_array[i]) << " not supported yet");
+		}
+	}
+
+	/*Assign output pointer*/
+	*ptransform=transform;
+}
+/*}}}*/
+#endif
Index: /issm/trunk-jpl/src/c/classes/Node.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Node.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Node.h	(revision 15012)
@@ -0,0 +1,120 @@
+/*!\file Node.h
+ * \brief: header file for node object
+ */
+
+#ifndef _NODE_H_
+#define _NODE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Object.h"
+#include "../shared/shared.h"
+#include "./DofIndexing.h"
+class  Inputs;
+class  Hook;
+class  IoModel;
+class  DataSet;
+class  Vertices;
+template <class doubletype> class  Vector;
+template <class doubletype> class  Matrix;
+class ElementVector;
+class ElementMatrix;
+#include "Update.h"
+/*}}}*/
+
+class Node: public Object ,public Update{
+
+	public: 
+
+		int id;    //unique arbitrary id.
+		int sid;   //"serial" id (rank of this node if the dataset was serial on 1 cpu)
+
+		DofIndexing  indexing;
+		Hook        *hvertex;
+		Inputs      *inputs;               //properties of this node
+		int          analysis_type;
+		IssmDouble   coord_system[3][3];
+
+		/*Node constructors, destructors {{{*/
+		Node();
+		Node(int node_id,int node_sid, int vertex_id,int io_index, IoModel* iomodel,int analysis_type);
+		~Node();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy()        {_error_("Not implemented yet (similar to Elements)"); };
+		/*}}}*/
+		/*Update virtual functions definitions: {{{*/
+		void  InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVector(int* vector, int name, int type);
+		void  InputUpdateFromVector(bool* vector, int name, int type);
+		void  InputUpdateFromMatrixDakota(IssmDouble* matrix,int nrows, int ncols, int name, int type);
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type);
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type);
+		void  InputUpdateFromConstant(IssmDouble constant, int name);
+		void  InputUpdateFromConstant(int constant, int name);
+		void  InputUpdateFromConstant(bool constant, int name);
+		void  InputUpdateFromSolution(IssmDouble* solution){_error_("Not implemented yet!");}
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error_("Not implemented yet!");}
+		/*}}}*/
+		/*Node numerical routines {{{*/
+		void   Configure(DataSet* nodes,Vertices* vertices);
+		void   CreateNodalConstraints(Vector<IssmDouble>* ys);
+		void   SetCurrentConfiguration(DataSet* nodes,Vertices* vertices);
+		int    Sid(void); 
+#ifdef _HAVE_DIAGNOSTIC_
+		void   GetCoordinateSystem(IssmDouble* coord_system_out);
+#endif
+		bool   InAnalysis(int analysis_type);
+		int    GetApproximation();
+		int    GetNumberOfDofs(int approximation_enum,int setenum);
+		int    IsClone();
+		void   ApplyConstraint(int dof,IssmDouble value);
+		void   RelaxConstraint(int dof);
+		void   DofInSSet(int dof);
+		void   DofInFSet(int dof);
+		int    GetDof(int dofindex,int setenum);
+		void   CreateVecSets(Vector<IssmDouble>* pv_g,Vector<IssmDouble>* pv_f,Vector<IssmDouble>* pv_s);
+		int    GetConnectivity();
+		void   GetDofList(int* poutdoflist,int approximation_enum,int setenum);
+		void   GetLocalDofList(int* poutdoflist,int approximation_enum,int setenum);
+		int    GetVertexId(void);
+		int    GetVertexPid(void);
+		int    GetVertexSid(void);
+		int    IsOnBed();
+		int    IsOnSurface();
+		void   FreezeDof(int dof);
+		int    IsFloating();
+		int    IsGrounded();
+		void   UpdateSpcs(IssmDouble* ys);
+		void   VecMerge(Vector<IssmDouble>* ug, IssmDouble* vector_serial,int setenum);
+		void   VecReduce(Vector<IssmDouble>* vector, IssmDouble* ug_serial,int setnum);
+		void  DistributeDofs(int* pdofcount,int setenum);
+		void  OffsetDofs(int dofcount,int setenum);
+		void  ShowTrueDofs(int* truerows,int ncols,int setenum);
+		void  UpdateCloneDofs(int* alltruerows,int ncols,int setenum);
+		void  SetClone(int* minranks);
+		/*}}}*/
+};
+
+/*Methods inherent to Node: */
+int* GetLocalDofList(Node** nodes,int numnodes,int setenum,int approximation);
+int* GetGlobalDofList(Node** nodes,int numnodes,int setenum,int approximation);
+int  GetNumberOfDofs(Node** nodes,int numnodes,int setenum,int approximation);
+#ifdef _HAVE_DIAGNOSTIC_
+void TransformInvStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int cs_enum);
+void TransformInvStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int* cs_array);
+void TransformLoadVectorCoord(ElementVector* pe,Node** nodes,int numnodes,int cs_enum);
+void TransformLoadVectorCoord(ElementVector* pe,Node** nodes,int numnodes,int* cs_array);
+void TransformSolutionCoord(IssmDouble* solution,Node** nodes,int numnodes,int cs_enum);
+void TransformSolutionCoord(IssmDouble* solution,Node** nodes,int numnodes,int* cs_array);
+void TransformStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int cs_enum);
+void TransformStiffnessMatrixCoord(ElementMatrix* Ke,Node** nodes,int numnodes,int* cs_array);
+void CoordinateSystemTransform(IssmDouble** ptransform,Node** nodes,int numnodes,int* cs_array);
+#endif
+
+#endif  /* _NODE_H_ */
Index: /issm/trunk-jpl/src/c/classes/Nodes.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Nodes.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Nodes.cpp	(revision 15012)
@@ -0,0 +1,355 @@
+/*
+ * \file Nodes.cpp
+ * \brief: Implementation of Nodes class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Nodes.h"
+#include "../shared/shared.h"
+#include "./Node.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Nodes::Nodes(){{{*/
+Nodes::Nodes(){
+	enum_type=NodesEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Nodes::~Nodes(){{{*/
+Nodes::~Nodes(){
+	return;
+}
+/*}}}*/
+
+/*Numerics*/
+/*FUNCTION Nodes::Configure{{{*/
+void Nodes::Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Node* node=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		node=dynamic_cast<Node*>(*object);
+		node->Configure(nodes,vertices);
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION Nodes::DistributeDofs{{{*/
+void  Nodes::DistributeDofs(int analysis_type,int setenum){
+
+	int  i;
+	int  dofcount=0;
+	int  maxdofspernode=0;
+	int* alldofcount=NULL;
+	int* truedofs=NULL;
+	int* alltruedofs=NULL;
+	int  numnodes=0;
+
+	/*recover my_rank:*/
+	int my_rank   = IssmComm::GetRank();
+	int num_procs = IssmComm::GetSize();
+
+	/*some check: */
+	_assert_(setenum==GsetEnum || setenum==FsetEnum || setenum==SsetEnum);
+
+	/*Go through objects, and distribute dofs locally, from 0 to numberofdofsperobject*/
+	for (i=0;i<this->Size();i++){
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		if (node->InAnalysis(analysis_type)){
+			node->DistributeDofs(&dofcount,setenum);
+		}
+	}
+
+	/* Now every object has distributed dofs, but locally, and with a dof count starting from 
+	 * 0. This means the dofs between all the cpus are not unique. We now offset the dofs of eache
+	 * cpus by the total last dofs of the previus cpu, starting from 0.
+	 * First: get number of dofs for each cpu*/
+	alldofcount=xNew<int>(num_procs);
+	#ifdef _HAVE_MPI_
+	MPI_Gather(&dofcount,1,MPI_INT,alldofcount,1,MPI_INT,0,IssmComm::GetComm());
+	MPI_Bcast(alldofcount,num_procs,MPI_INT,0,IssmComm::GetComm());
+	#else
+	alldofcount[0]=dofcount;
+	#endif
+
+	/* Every cpu should start its own dof count at the end of the dofcount from cpu-1*/
+	dofcount=0;
+	for(i=0;i<my_rank;i++){
+		dofcount+=alldofcount[i];
+	}
+	for (i=0;i<this->Size();i++){
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+		if (node->InAnalysis(analysis_type)){
+			node->OffsetDofs(dofcount,setenum);
+		}
+	}
+
+	/* Finally, remember that cpus may have skipped some objects, because they were clones. For every 
+	 * object that is not a clone, tell them to show their dofs, so that later on, they can get picked 
+	 * up by their clones: */
+	maxdofspernode=this->MaxNumDofs(analysis_type,setenum);
+	numnodes=this->NumberOfNodes(analysis_type);
+	if(numnodes*maxdofspernode){
+		truedofs=   xNewZeroInit<int>(numnodes*maxdofspernode); //initialize to 0, so that we can pick up the max
+		alltruedofs=xNewZeroInit<int>(numnodes*maxdofspernode);
+	}
+
+	for (i=0;i<this->Size();i++){
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+		if (node->InAnalysis(analysis_type)){
+			node->ShowTrueDofs(truedofs,maxdofspernode,setenum);//give maxdofspernode, column size, so that nodes can index into truedofs
+		}
+	}
+
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)truedofs,(void*)alltruedofs,numnodes*maxdofspernode,MPI_INT,MPI_MAX,IssmComm::GetComm());
+	#else
+	for(i=0;i<numnodes*maxdofspernode;i++)alltruedofs[i]=truedofs[i];
+	#endif
+
+	/* Now every cpu knows the true dofs of everyone else that is not a clone*/
+	for (i=0;i<this->Size();i++){
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+		if (node->InAnalysis(analysis_type)){
+			node->UpdateCloneDofs(alltruedofs,maxdofspernode,setenum);
+		}
+	}
+
+	/* Free ressources: */
+	xDelete<int>(alldofcount);
+	xDelete<int>(truedofs);
+	xDelete<int>(alltruedofs);
+}
+/*}}}*/
+/*FUNCTION Nodes::FlagClones{{{*/
+void  Nodes::FlagClones(int analysis_type){
+
+	int i;
+	int num_procs;
+	int numnodes;
+
+	/*recover num_procs: */
+	num_procs=IssmComm::GetSize();
+
+	/*Figure out number of nodes for this analysis: */
+	numnodes=this->NumberOfNodes(analysis_type);
+
+	/*Allocate ranks: */
+	int* ranks    = xNew<int>(numnodes);
+	int* minranks = xNew<int>(numnodes);
+	for(i=0;i<numnodes;i++)ranks[i]=num_procs; //no cpu can have rank num_procs. This is the maximum limit.
+
+	/*Now go through all our objects and ask them to report to who they belong (which rank): */
+	Ranks(ranks,analysis_type);
+
+	/*We need to take the minimum rank for each vertex, and every cpu needs to get that result. That way, 
+	 * when we start building the dof list for all vertexs, a cpu can check whether its vertex already has been 
+	 * dealt with by another cpu. We take the minimum because we are going to manage dof assignment in increasing 
+	 * order of cpu rank. This is also why we initialized this array to num_procs.*/
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)ranks,(void*)minranks,numnodes,MPI_INT,MPI_MIN,IssmComm::GetComm());
+	#else
+	for(i=0;i<numnodes;i++)minranks[i]=ranks[i];
+	#endif
+
+	/*Now go through all objects, and use minranks to flag which objects are cloned: */
+	for(i=0;i<this->Size();i++){
+
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		if (node->InAnalysis(analysis_type)){
+
+			/*For this object, decide whether it is a clone: */
+			node->SetClone(minranks);
+		}
+	}
+
+	/*Free ressources: */
+	xDelete<int>(ranks); 
+	xDelete<int>(minranks);
+
+}
+/*}}}*/
+/*FUNCTION Nodes::MaxNumDofs{{{*/
+int   Nodes::MaxNumDofs(int analysis_type,int setenum){
+
+	int i;
+	int max=0;
+	int allmax;
+	int numdofs=0;
+
+	/*Now go through all nodes, and get how many dofs they own, unless they are clone nodes: */
+	for(i=0;i<this->Size();i++){
+
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		if (node->InAnalysis(analysis_type)){
+
+			numdofs=node->GetNumberOfDofs(NoneApproximationEnum,setenum);
+			if(numdofs>max)max=numdofs;
+		}
+	}
+
+	/*Grab max of all cpus: */
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)&max,(void*)&allmax,1,MPI_INT,MPI_MAX,IssmComm::GetComm());
+	max=allmax;
+	#endif
+
+	return max;
+}
+/*}}}*/
+/*FUNCTION Nodes::NumberOfDofs{{{*/
+int   Nodes::NumberOfDofs(int analysis_type,int setenum){
+
+	int   allnumdofs;
+
+	/*Get number of dofs on current cpu (excluding clones)*/
+	int numdofs=this->NumberOfDofsLocal(analysis_type,setenum);
+
+	/*Gather from all cpus: */
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce ( (void*)&numdofs,(void*)&allnumdofs,1,MPI_INT,MPI_SUM,IssmComm::GetComm());
+	#else
+	allnumdofs=numdofs;
+	#endif
+	return allnumdofs;
+}
+/*}}}*/
+/*FUNCTION Nodes::NumberOfDofsLocal{{{*/
+int   Nodes::NumberOfDofsLocal(int analysis_type,int setenum){
+
+	int   numdofs=0;
+
+	/*Now go through all nodes, and get how many dofs they own, unless they are clone nodes: */
+	for(int i=0;i<this->Size();i++){
+
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		if (node->InAnalysis(analysis_type)){
+
+			/*Ok, this object is a node, ask it to plug values into partition: */
+			if (!node->IsClone()){
+				numdofs+=node->GetNumberOfDofs(NoneApproximationEnum,setenum);
+			}
+		}
+	}
+
+	return numdofs;
+}
+/*}}}*/
+/*FUNCTION Nodes::NumberOfNodes(){{{*/
+int Nodes::NumberOfNodes(void){
+
+	/*Careful! only use once all clones have been setup for all nodes!: */
+
+	int numnodes=0;
+	int allnumnodes=0;
+
+	/*Now go through all nodes, and get how many dofs they own, unless they are clone nodes: */
+	for(int i=0;i<this->Size();i++){
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Ok, this object is a node, ask it to plug values into partition: */
+		if (!node->IsClone()) numnodes++;
+	}
+
+	/*Gather from all cpus: */
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce ( (void*)&numnodes,(void*)&allnumnodes,1,MPI_INT,MPI_SUM,IssmComm::GetComm());
+	#else
+	allnumnodes=numnodes;
+	#endif
+
+	return allnumnodes;
+}
+/*}}}*/
+/*FUNCTION Nodes::NumberOfNodes(analysis){{{*/
+int Nodes::NumberOfNodes(int analysis_type){
+
+	int i;
+
+	int max_sid=-1;
+	int sid;
+	int node_max_sid;
+
+	for(i=0;i<this->Size();i++){
+
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		if (node->InAnalysis(analysis_type)){
+
+			sid=node->Sid();
+			if (sid>max_sid)max_sid=sid;
+		}
+	}
+
+	#ifdef _HAVE_MPI_
+	MPI_Reduce (&max_sid,&node_max_sid,1,MPI_INT,MPI_MAX,0,IssmComm::GetComm() );
+	MPI_Bcast(&node_max_sid,1,MPI_INT,0,IssmComm::GetComm());
+	max_sid=node_max_sid;
+	#endif
+
+	/*sid starts at 0*/
+	max_sid++;
+
+	/*return*/
+	return max_sid;
+}
+/*}}}*/
+/*FUNCTION Nodes::Ranks{{{*/
+void   Nodes::Ranks(int* ranks,int analysis_type){
+
+	int my_rank;
+	int sid;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	/*Go through nodes, and for each object, report it cpu: */
+	for(int i=0;i<this->Size();i++){
+
+		Node* node=dynamic_cast<Node*>(this->GetObjectByOffset(i));
+
+		/*Check that this node corresponds to our analysis currently being carried out: */
+		if (node->InAnalysis(analysis_type)){
+			/*Plug rank into ranks, according to sid: */
+			sid=node->Sid();
+			ranks[sid]=my_rank; 
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION Nodes::SetCurrentConfiguration{{{*/
+void Nodes::SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters){
+
+	vector<Object*>::iterator object;
+	Node* node=NULL;
+
+	for (object=objects.begin() ; object < objects.end(); object++ ){
+
+		node=dynamic_cast<Node*>(*object);
+		node->SetCurrentConfiguration(nodes,vertices);
+
+	}
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Nodes.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Nodes.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Nodes.h	(revision 15012)
@@ -0,0 +1,41 @@
+#ifndef _CONTAINER_NODES_H_
+#define  _CONTAINER_NODES_H_
+
+#include "./DataSet.h"
+class Parameters;
+class Elements;
+class Vertices;
+class Loads;
+class Nodes;
+class Materials;
+
+
+/*!\brief Declaration of Nodes class.
+ *
+ * Declaration of Nodes class.  Nodes are vector lists of objects (Containers) of Node objects.
+ * Node objects are the degrees of freedom (DOFs) for a particular analysis type (not to be 
+ * confused with a vertex, which defines the (x,y,z) location of a point).
+ */ 
+class Nodes: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Nodes();
+		~Nodes();
+
+		/*numerics*/
+		void  Configure(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+		void  DistributeDofs(int analysis_type,int SETENUM);
+		void  FlagClones(int analysis_type);
+		int   MaxNumDofs(int analysis_type,int setenum);
+		int   NumberOfDofs(int analysis_type,int setenum);
+		int   NumberOfDofsLocal(int analysis_type,int setenum);
+		int   NumberOfNodes(int analysis_type);
+		int   NumberOfNodes(void);
+		void  Ranks(int* ranks,int analysis_type);
+		void  SetCurrentConfiguration(Elements* elements,Loads* loads, Nodes* nodes, Vertices* vertices, Materials* materials,Parameters* parameters);
+
+};
+
+#endif //ifndef _NODES_H_
Index: /issm/trunk-jpl/src/c/classes/Object.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Object.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Object.h	(revision 15012)
@@ -0,0 +1,25 @@
+/*
+ * Object.h:
+ * \brief prototype for abstract Object class
+ * \file Object.h
+ * This prototype describes the Object class. This is an abstract class, parent 
+ * to any other objects (Quad, Tria, Node , etc ...), that can be included in a 
+ * DataSet.
+ */
+
+#ifndef _OBJECT_H_
+#define _OBJECT_H_
+
+class Object {
+
+	public: 
+
+		virtual       ~Object() {};
+		virtual void  Echo()=0;
+		virtual void  DeepEcho()=0;
+		virtual int   Id()=0;
+		virtual int   ObjectEnum()=0;
+		virtual Object* copy()=0;
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Options/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,8 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Options)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Options/OptionUtilities.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Options/GenericOption.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/GenericOption.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/GenericOption.h	(revision 15012)
@@ -0,0 +1,134 @@
+/*! \file GenericOption.h 
+ *  \brief: header file for generic option object
+ */
+
+#ifndef _GENERIC_OPTION_
+#define _GENERIC_OPTION_
+
+/*Headers:{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <cstring>
+#include "../../shared/shared.h"
+#include "./OptionUtilities.h"
+#include "../Object.h"
+/*}}}*/
+
+template <class OptionType> 
+class GenericOption: public Option {
+
+	public:
+
+		char       *name;
+		OptionType  value;
+
+		int         numel;   //in case OptionType is an array
+		int         ndims;   //in case OptionType is a multi-dimensional array: */
+		int        *size;
+
+		/*GenericOption constructors, destructors*/
+		GenericOption(){ /*{{{*/
+
+			name   = NULL;
+			numel  = 0;
+			ndims  = 0;
+			size   = NULL;
+
+		} /*}}}*/
+		~GenericOption(){ /*{{{*/
+
+			if(name)   xDelete<char>(name);
+			if(size)   xDelete<int>(size);
+
+		} /*}}}*/
+
+		/*Object virtual functions definitions:*/
+		void Echo(){ /*{{{*/
+
+			this->DeepEcho();
+
+		} /*}}}*/
+		void DeepEcho(){ /*{{{*/
+
+			char  indent[81]="";
+			this->DeepEcho(indent);
+
+		} /*}}}*/
+		void DeepEcho(char* indent){ /*{{{*/
+
+			char  cstr[81];
+			bool  flag=true;
+
+			if(flag) _pprintLine_(indent << "         name: \"" << name << "\"");
+			if(flag) _pprintLine_(indent << "         numel: " << numel);
+			if(flag) _pprintLine_(indent << "         ndims: " << ndims);
+			if(size){
+				StringFromSize(cstr,size,ndims);
+				if(flag) _pprintLine_(indent << "          size: " << cstr);
+			}
+			else if(flag) _pprintLine_(indent << "          size: [empty]");
+			_printLine_(indent << "         value: " << value);;
+		} /*}}}*/
+		int  Id(){/*{{{*/
+			_error_("Not implemented yet");
+		};/*}}}*/
+		int  ObjectEnum(){/*{{{*/
+			return GenericOptionEnum;
+		};/*}}}*/
+		Object* copy(){/*{{{*/
+			_error_("Not implemented yet");
+		};/*}}}*/
+
+		/*GenericOption functions: */
+		char* Name(){/*{{{*/
+			return name;
+		};/*}}}*/
+		int   NumEl(){/*{{{*/
+			return numel;
+		};/*}}}*/
+		int   NDims(){/*{{{*/
+			return ndims;
+		};/*}}}*/
+		int*  Size(){/*{{{*/
+			return size;
+		};/*}}}*/
+		void  Get(OptionType* pvalue){/*{{{*/
+			*pvalue=value; 
+		};/*}}}*/
+};
+
+#if defined(_HAVE_ADOLC_) && !defined(_WRAPPERS_)  //We hook off this specific specialization when not running ADOLC, otherwise we get a redeclaration with the next specialization. 
+template <> inline void GenericOption<IssmPDouble*>::Get(IssmPDouble** pvalue){ /*{{{*/
+
+	/*Copy vector*/
+	IssmPDouble* outvalue=xNew<IssmPDouble>(this->NumEl());
+	for(int i=0;i<this->NumEl();i++) outvalue[i]=this->value[i];
+
+	/*Assign output pointer*/
+	*pvalue=outvalue;
+} /*}}}*/
+#endif
+template <> inline void GenericOption<IssmDouble*>::Get(IssmDouble** pvalue){ /*{{{*/
+
+	/*Copy vector*/
+	IssmDouble* outvalue=xNew<IssmDouble>(this->NumEl());
+	for(int i=0;i<this->NumEl();i++) outvalue[i]=this->value[i];
+
+	/*Assign output pointer*/
+	*pvalue=outvalue;
+} /*}}}*/
+template <> inline void GenericOption<char*>::Get(char** pvalue){ /*{{{*/
+
+	int   stringsize=strlen(this->value)+1;
+	char* outstring=xNew<char>(stringsize);
+	xMemCpy<char>(outstring,this->value,stringsize);
+
+	*pvalue=outstring;
+} 
+/*}}}*/
+
+#endif  /* _OPTIONOBJECT_H */
Index: /issm/trunk-jpl/src/c/classes/Options/Option.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/Option.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/Option.h	(revision 15012)
@@ -0,0 +1,37 @@
+/*! \file Option.h 
+ *  \brief: header file for option abstract object
+ */
+
+#ifndef _OPTIONOBJECT_H_
+#define _OPTIONOBJECT_H_
+
+/*Headers:{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+#include "../Object.h"
+/*}}}*/
+
+class Option: public Object {
+
+	public:
+
+		/*Option constructors, destructors*/
+		Option(){};
+		~Option(){};
+
+		/*Object virtual functions definitions*/
+		virtual void  Echo()= 0;
+		virtual void  DeepEcho()= 0;
+		virtual void  DeepEcho(char  *indent)=0;
+		int           Id(){_error_("Not implemented yet"); };
+		int           ObjectEnum(){return OptionEnum;              };
+		Object       *copy(){_error_("Not implemented yet"); };
+
+		/*virtual functions: */
+		virtual char* Name()=0;
+		virtual int   NumEl()=0;
+		virtual int   NDims()=0;
+		virtual int*  Size()=0;
+
+};
+#endif  /* _OPTIONOBJECT_H */
Index: /issm/trunk-jpl/src/c/classes/Options/OptionUtilities.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/OptionUtilities.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/OptionUtilities.cpp	(revision 15012)
@@ -0,0 +1,110 @@
+/*!\file OptionUtilities.cpp
+ * \brief: implementation of the options utilities
+ */
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*FUNCTION ColumnWiseDimsFromIndex{{{*/
+int ColumnWiseDimsFromIndex(int* dims,int index,int* size,int ndims){
+
+	int   i;
+	int   aprod=1;
+
+	/*check for index too large  */
+	for (i=0;i<ndims;i++) aprod*=size[i];
+	if (index >= aprod) _error_("Index " << index << " exceeds number of elements " << aprod << ".");
+
+	/*calculate the dimensions (being careful of integer division)  */
+	for (i=ndims-1; i>=0; i--) {
+		aprod=reCast<int>(((IssmPDouble)aprod+0.5)/(IssmPDouble)size[i]);
+		dims[i]=(int)floor(((IssmPDouble)index+0.5)/(IssmPDouble)aprod);
+		index-=dims[i]*aprod;
+	}
+
+	return(0);
+}/*}}}*/
+/*FUNCTION IndexFromColumnWiseDims{{{*/
+int IndexFromColumnWiseDims(int* dims, int* size, int ndims) {
+
+	int   i;
+	int   index=0;
+
+	/*check for any dimension too large  */
+	for (i=0;i<ndims;i++){
+		if (dims[i] >= size[i]) _error_("Dimension " << i << " of " << dims[i] << " exceeds size of " << size[i] << ".");
+	}
+
+	/*calculate the index  */
+	for (i=ndims-1; i>=0; i--){
+		index*=size[i];
+		index+=dims[i];
+	}
+
+	return(index);
+}/*}}}*/
+/*FUNCTION RowWiseDimsFromIndex{{{*/
+int RowWiseDimsFromIndex(int* dims, int index, int* size, int ndims) {
+
+	int   i;
+	int   aprod=1;
+
+	/*check for index too large  */
+	for (i=0; i<ndims; i++) aprod*=size[i];
+	if (index >= aprod) _error_("Index " << index << " exceeds number of elements " << aprod << ".");
+
+	/*calculate the dimensions (being careful of integer division)  */
+	for (i=0; i<ndims; i++) {
+		aprod=(int)(((IssmPDouble)aprod+0.5)/(IssmPDouble)size[i]);
+		dims[i]=(int)floor(((IssmPDouble)index+0.5)/(IssmPDouble)aprod);
+		index-=dims[i]*aprod;
+	}
+
+	return(0);
+}/*}}}*/
+/*FUNCTION IndexFromRowWiseDims{{{*/
+int IndexFromRowWiseDims(int* dims, int* size, int ndims) {
+
+	int   i;
+	int   index=0;
+
+	/*check for any dimension too large  */
+	for (i=0; i<ndims; i++){
+		if (dims[i] >= size[i]) _error_("Dimension " << i << " of " << dims[i] << " exceeds size of " << size[i] << ".");
+	}
+
+	/*calculate the index  */
+	for (i=0; i<ndims; i++) {
+		index*=size[i];
+		index+=dims[i];
+	}
+
+	return(index);
+}/*}}}*/
+/*FUNCTION StringFromDims{{{*/
+int StringFromDims(char* cstr, int* dims, int ndims) {
+
+	sprintf(&cstr[0],"[");
+	for(int i=0; i<ndims-1; i++) sprintf(&cstr[strlen(cstr)],"%d,",dims[i]);
+	sprintf(&cstr[strlen(cstr)],"%d]",dims[ndims-1]);
+
+	return(0);
+}/*}}}*/
+/*FUNCTION StringFromSize{{{*/
+int StringFromSize(char* cstr, int* size, int ndims) {
+
+	sprintf(&cstr[0],"[");
+	for(int i=0; i<ndims-1; i++) sprintf(&cstr[strlen(cstr)],"%dx",size[i]);
+	sprintf(&cstr[strlen(cstr)],"%d]",size[ndims-1]);
+
+	return(0);
+}/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Options/OptionUtilities.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/OptionUtilities.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/OptionUtilities.h	(revision 15012)
@@ -0,0 +1,22 @@
+/*! \file OptionUtilities.h 
+ *  \brief: header file for option object utilities
+ */
+
+#ifndef _OPTIONUTILITIES_H_
+#define _OPTIONUTILITIES_H_
+
+/*Headers:{{{*/
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../shared/Enum/Enum.h"
+
+#include "./Option.h"
+/*}}}*/
+
+int ColumnWiseDimsFromIndex(int* dims, int index, int* size, int ndims);
+int IndexFromColumnWiseDims(int* dims, int* size, int ndims);
+int RowWiseDimsFromIndex(int* dims, int index, int* size, int ndims);
+int IndexFromRowWiseDims(int* dims, int* size, int ndims);
+int StringFromDims(char* cstr, int* dims, int ndims);
+int StringFromSize(char* cstr, int* size, int ndims);
+
+#endif  /* _OPTIONUTILITIES_H */
Index: /issm/trunk-jpl/src/c/classes/Options/Options.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/Options.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/Options.cpp	(revision 15012)
@@ -0,0 +1,111 @@
+/*
+ * \file Options.cpp
+ * \brief: Implementation of Options class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <vector>
+#include <algorithm>
+#include <cstring>
+
+#include "../DataSet.h"
+#include "./Options.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Options::Options(){{{*/
+Options::Options(){
+	return;
+}
+/*}}}*/
+/*FUNCTION Options::~Options(){{{*/
+Options::~Options(){
+	return;
+}
+/*}}}*/
+
+/*Object management*/
+/*FUNCTION Options::AddOption{{{*/
+int  Options::AddOption(Option* in_option){
+
+	char* name=NULL;
+
+	vector<Object*>::iterator object;
+	Option* option=NULL;
+
+	/*In debugging mode, check that the option is not a NULL pointer*/
+	_assert_(in_option);
+
+	/*Also, check the option name*/
+	name=in_option->Name();
+
+	if(!name) _error_("input option has an empty name");
+	if(strchr(name,'.')) _error_("Option \"" << name << "\" has a protected character \".\"");
+	if(strchr(name,'[')) _error_("Option \"" << name << "\" has a protected character \"[\"");
+	if(strchr(name,']')) _error_("Option \"" << name << "\" has a protected character \"]\"");
+
+	/*Finally, check that no option of the same name already exists in the dataset*/
+	for(object=objects.begin();object<objects.end();object++){
+
+		option=dynamic_cast<Option*>(*object);
+		if (!strcmp(option->Name(),name)){
+			_error_("Options \"" << name << "\" found multiple times");
+			break;
+		}
+	}
+
+	/*OK, all checks went well, add option to dataset*/
+	this->AddObject(in_option);
+
+	return 1;
+}
+/*}}}*/
+/*FUNCTION Options::GetOption{{{*/
+Option* Options::GetOption(const char* name){
+
+	vector<Object*>::iterator object;
+	Option* option=NULL;
+
+	/*Go through options and find option: */
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		option=dynamic_cast<Option*>(*object);
+		if (!strncmp(name,option->Name(),strlen(option->Name()))){
+
+			/*OK, now do we have a complete name? If not, it is a cell or a structure, we need to go further*/
+			if(!strcmp(name,option->Name())){
+				return option;
+			}
+			else{
+				/*If the object is a Cell, recursive call to its options*/ 
+				if(option->ObjectEnum()==OptionCellEnum){
+					GenericOption<Options*>* celloption=(GenericOption<Options*>*)option;
+					return celloption->value->GetOption(name);
+				}
+				/*If the object is a Struct loop over its size and recursive call*/
+				else if(option->ObjectEnum()==OptionStructEnum){
+					for(int i=0;i<option->NumEl();i++){
+						GenericOption<Options**>* structoption=(GenericOption<Options**>*)option;
+						_assert_(structoption->value[i]);
+						return structoption->value[i]->GetOption(name);
+					}
+				}
+				/*Else: not supported*/
+				else{
+					_error_("Cannot recover field \"" << name << "\" for an option of type " << EnumToStringx(option->ObjectEnum()));
+				}
+			}
+		}
+	}
+
+	/*Option not found return NULL pointer*/
+	return NULL;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Options/Options.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Options/Options.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Options/Options.h	(revision 15012)
@@ -0,0 +1,108 @@
+#ifndef _CONTAINER_OPTIONS_H_
+#define _CONTAINER_OPTIONS_H_
+
+/*forward declarations */
+class Option;
+#include "../DataSet.h"
+#include "./GenericOption.h"
+
+/*!\brief Declaration of Options class. 
+ * 
+ * Declaration of Options class.  Options are vector lists (Containers) of Option objects.
+ */ 
+class Options: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/
+		Options();
+		~Options();
+
+		/*numerics*/
+		int  AddOption(Option* in_oobject);
+		Option* GetOption(const char* name);
+
+		template <class OptionType> void Get(OptionType* pvalue,const char* name){ /*{{{*/
+
+			/*Get option*/
+			GenericOption<OptionType>* genericoption=dynamic_cast<GenericOption<OptionType>*>(GetOption(name));
+
+			/*If the pointer is not NULL, the option has been found*/
+			if(genericoption){
+				genericoption->Get(pvalue);
+			}
+			/*Else, the Option does not exist, no default provided*/
+			else{
+				_error_("option of name \"" << name << "\" not found, and no default value has been provided");
+			}
+		}
+		/*}}}*/
+		template <class OptionType> void Get(OptionType* pvalue,int* pnumel, const char* name){ /*{{{*/
+
+			/*Get option*/
+			GenericOption<OptionType>* genericoption=dynamic_cast<GenericOption<OptionType>*>(GetOption(name));
+
+			/*If the pointer is not NULL, the option has been found*/
+			if(genericoption){
+				genericoption->Get(pvalue);
+				*pnumel=genericoption->NumEl();
+			}
+			/*Else, the Option does not exist, no default provided*/
+			else{
+				_error_("option of name \"" << name << "\" not found, and no default value has been provided");
+			}
+		}
+		/*}}}*/
+		template <class OptionType> void Get(OptionType* pvalue,const char* name,OptionType default_value){ /*{{{*/
+
+			/*Get option*/
+			GenericOption<OptionType>* genericoption=dynamic_cast<GenericOption<OptionType>*>(GetOption(name));
+
+			/*If the pointer is not NULL, the option has been found*/
+			if(genericoption){
+				genericoption->Get(pvalue);
+			}
+			else{
+				if(GetOption(name)) _printLine_("WARNING: option "<<name<<" found but fetched format not consistent, defaulting...");
+				*pvalue=default_value;
+			}
+		}
+		/*}}}*/
+		template <class OptionType> void Get(OptionType* pvalue,int* pnumel, const char* name,OptionType default_value){ /*{{{*/
+
+			/*Get option*/
+			GenericOption<OptionType>* genericoption=dynamic_cast<GenericOption<OptionType>*>(GetOption(name));
+
+			/*If the pointer is not NULL, the option has been found*/
+			if(genericoption){
+				genericoption->Get(pvalue);
+				*pnumel=genericoption->NumEl();
+			}
+			else{
+				*pvalue=default_value;
+			}
+		}
+		/*}}}*/
+
+};
+
+#endif //ifndef _INPUTS_H_
+
+template <> inline void Options::Get(char** pvalue,const char* name,char* default_value){ /*{{{*/
+
+	/*Get option*/
+	GenericOption<char*>* genericoption=dynamic_cast<GenericOption<char*>*>(GetOption(name));
+
+	/*If the pointer is not NULL, the option has been found*/
+	if(genericoption){
+		genericoption->Get(pvalue);
+	}
+	else{
+		/*Make a copy*/
+		int   stringsize=strlen(default_value)+1;
+		char* outstring=xNew<char>(stringsize);
+		xMemCpy<char>(outstring,default_value,stringsize);
+		*pvalue=outstring;
+	}
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/BoolParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/BoolParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/BoolParam.cpp	(revision 15012)
@@ -0,0 +1,78 @@
+/*!\file BoolParam.c
+ * \brief: implementation of the BoolParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*BoolParam constructors and destructor*/
+/*FUNCTION BoolParam::BoolParam(){{{*/
+BoolParam::BoolParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolParam::BoolParam(int enum_type,bool value){{{*/
+BoolParam::BoolParam(int in_enum_type,bool in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION BoolParam::~BoolParam(){{{*/
+BoolParam::~BoolParam(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION BoolParam::Echo {{{*/
+void BoolParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION BoolParam::DeepEcho{{{*/
+void BoolParam::DeepEcho(void){
+
+	_printLine_("BoolParam:");
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " <<(this->value?"true":"false"));
+}
+/*}}}*/
+/*FUNCTION BoolParam::Id{{{*/
+int    BoolParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION BoolParam::ObjectEnum{{{*/
+int BoolParam::ObjectEnum(void){
+
+	return BoolParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION BoolParam::copy{{{*/
+Object* BoolParam::copy() {
+
+	return new BoolParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*BoolParam virtual functions definitions: */
+/*FUNCTION BoolParam::GetParameterName{{{*/
+void BoolParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION BoolParam::UnitConversion{{{*/
+void  BoolParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/BoolParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/BoolParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/BoolParam.h	(revision 15012)
@@ -0,0 +1,75 @@
+/*! \file BoolParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _BOOLPARAM_H_
+#define _BOOLPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class BoolParam: public Param{
+
+	public:
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		bool value;
+
+		/*BoolParam constructors, destructors: {{{*/
+		BoolParam();
+		BoolParam(int enum_type,bool value);
+		~BoolParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){*pbool=value;}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){this->value=boolean;}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an int");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmPDouble");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+		/*}}}*/
+};
+#endif  /* _BOOLPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/CMakeLists.txt
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/CMakeLists.txt	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/CMakeLists.txt	(revision 15012)
@@ -0,0 +1,23 @@
+# Subdirectories {{{
+# }}}
+# Include Directory {{{
+include_directories(AFTER $ENV{ISSM_DIR}/src/c/classes/objects/Params)
+# }}}
+# CORE_SOURCES {{{
+set(CORE_SOURCES $ENV{ISSM_DIR}/src/c/classes/objects/Params/BoolParam.cpp
+              $ENV{ISSM_DIR}/src/c/classes/objects/Params/DataSetParam.cpp
+       $ENV{ISSM_DIR}/src/c/classes/objects/Params/DoubleMatArrayParam.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/Params/DoubleMatParam.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Params/DoubleParam.cpp
+   $ENV{ISSM_DIR}/src/c/classes/objects/Params/DoubleTransientMatParam.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/Params/DoubleVecParam.cpp
+                 $ENV{ISSM_DIR}/src/c/classes/objects/Params/FileParam.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Params/IntMatParam.cpp
+                  $ENV{ISSM_DIR}/src/c/classes/objects/Params/IntParam.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Params/IntVecParam.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Params/MatrixParam.cpp
+          $ENV{ISSM_DIR}/src/c/classes/objects/Params/StringArrayParam.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Params/StringParam.cpp
+            $ENV{ISSM_DIR}/src/c/classes/objects/Params/TransientParam.cpp
+               $ENV{ISSM_DIR}/src/c/classes/objects/Params/VectorParam.cpp PARENT_SCOPE)
+# }}}
Index: /issm/trunk-jpl/src/c/classes/Params/DataSetParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DataSetParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DataSetParam.cpp	(revision 15012)
@@ -0,0 +1,84 @@
+/*!\file DataSetParam.c
+ * \brief: implementation of the DataSetParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*DataSetParam constructors and destructor*/
+/*FUNCTION DataSetParam::DataSetParam(){{{*/
+DataSetParam::DataSetParam(){
+	value=NULL;
+	return;
+}
+/*}}}*/
+/*FUNCTION DataSetParam::DataSetParam(int enum_type,DataSet *value){{{*/
+DataSetParam::DataSetParam(int in_enum_type,DataSet* in_value){
+
+	enum_type=in_enum_type;
+	value=in_value->Copy();;
+}
+/*}}}*/
+/*FUNCTION DataSetParam::~DataSetParam(){{{*/
+DataSetParam::~DataSetParam(){
+	delete value;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DataSetParam::Echo {{{*/
+void DataSetParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION DataSetParam::DeepEcho{{{*/
+void DataSetParam::DeepEcho(void){
+
+	_printLine_("DataSetParam:");
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	this->value->Echo();
+}
+/*}}}*/
+/*FUNCTION DataSetParam::Id{{{*/
+int    DataSetParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DataSetParam::ObjectEnum{{{*/
+int DataSetParam::ObjectEnum(void){
+
+	return DataSetParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION DataSetParam::copy{{{*/
+Object* DataSetParam::copy() {
+
+	return new DataSetParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*DataSetParam virtual functions definitions: */
+/*FUNCTION DataSetParam::GetParameterName{{{*/
+void DataSetParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DataSetParam::UnitConversion{{{*/
+void  DataSetParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
+/*FUNCTION DataSetParam::GetParameterValue{{{*/
+void DataSetParam::GetParameterValue(DataSet** pdataset){
+	*pdataset=value->Copy();
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/DataSetParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DataSetParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DataSetParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file DataSetParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _DATASETPARAM_H_
+#define _DATASETPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class DataSetParam: public Param{
+
+	private: 
+		int   enum_type;
+		DataSet* value;
+
+	public:
+		/*DataSetParam constructors, destructors: {{{*/
+		DataSetParam();
+		DataSetParam(int enum_type,DataSet* dataset);
+		~DataSetParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){  _error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(FILE** pfile){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a file pointer");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("DataSet param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(DataSet** pdataset);
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a file pointer");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(DataSet* dataset){_error_("DataSet param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a DataSet yet");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("DataSet param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _INTPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.cpp	(revision 15012)
@@ -0,0 +1,239 @@
+/*!\file DoubleMatArrayParam.c
+ * \brief: implementation of the DoubleMatArrayParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*DoubleMatArrayParam constructors and destructor*/
+/*FUNCTION DoubleMatArrayParam::DoubleMatArrayParam(){{{*/
+DoubleMatArrayParam::DoubleMatArrayParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::DoubleMatArrayParam(int enum_type,IssmDouble** array, int M, int* mdim_array, int* ndim_array){{{*/
+DoubleMatArrayParam::DoubleMatArrayParam(int in_enum_type,IssmDouble** in_array, int in_M, int* in_mdim_array, int* in_ndim_array){
+
+	int i;
+	IssmDouble* matrix=NULL;
+	int     m,n;
+
+	enum_type=in_enum_type;
+	M=in_M;
+	if(M){
+		array=xNew<IssmDouble*>(M);
+		mdim_array=xNew<int>(M);
+		ndim_array=xNew<int>(M);
+
+		for(i=0;i<M;i++){
+			m=in_mdim_array[i]; 
+			n=in_ndim_array[i];
+
+			mdim_array[i]=m;
+			ndim_array[i]=n;
+
+			if(m*n){
+				matrix=xNew<IssmDouble>(m*n);
+				xMemCpy<IssmDouble>(matrix,in_array[i],m*n);
+			}
+			else{
+				matrix=NULL;
+			}
+			array[i]=matrix;
+		}
+	}
+	else{
+		array=NULL;
+		mdim_array=NULL;
+		ndim_array=NULL;
+	}
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::~DoubleMatArrayParam(){{{*/
+DoubleMatArrayParam::~DoubleMatArrayParam(){
+
+	int i;
+	IssmDouble* matrix=NULL;
+
+	xDelete<int>(mdim_array);
+	xDelete<int>(ndim_array);
+
+	for(i=0;i<M;i++){
+		matrix=array[i];
+		xDelete<IssmDouble>(matrix);
+	}
+
+	xDelete<IssmDouble*>(array);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleMatArrayParam::Echo {{{*/
+void DoubleMatArrayParam::Echo(void){
+
+	_printLine_("DoubleMatArrayParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   array size: " << this->M);
+	_printLine_("   array pointer: " << this->array);
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::DeepEcho{{{*/
+void DoubleMatArrayParam::DeepEcho(void){
+
+	int i,j,k;
+	int m,n;
+	IssmDouble* matrix=NULL;
+
+	_printLine_("DoubleMatArrayParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   array size: " << this->M);
+	for(i=0;i<M;i++){
+		_printLine_("   array " << i << " (" << mdim_array[i] << "x" << ndim_array[i] << "):");
+		matrix=array[i];
+		m=mdim_array[i];
+		n=ndim_array[i];
+
+		for(j=0;j<m;j++){
+			_printString_("   ");
+			for(k=0;k<n;k++)_printString_(*(matrix+n*j+k) << " ");
+			_printLine_("");
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::Id{{{*/
+int    DoubleMatArrayParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::ObjectEnum{{{*/
+int DoubleMatArrayParam::ObjectEnum(void){
+
+	return DoubleMatArrayParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::copy{{{*/
+Object* DoubleMatArrayParam::copy() {
+
+	return new DoubleMatArrayParam(this->enum_type,this->array, this->M, this->mdim_array,this->ndim_array);
+
+}
+/*}}}*/
+
+/*DoubleMatArrayParam virtual functions definitions: */
+/*FUNCTION DoubleMatArrayParam::GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){{{*/
+void  DoubleMatArrayParam::GetParameterValue(IssmDouble*** pout_array, int* pout_M,int** pout_mdim_array, int** pout_ndim_array){
+
+	int i,m,n;
+	IssmDouble* matrix=NULL;
+	IssmDouble* out_matrix=NULL;
+
+	/*output: */
+	IssmDouble** out_array=NULL;
+	int      out_M;
+	int*     out_mdim_array=NULL;
+	int*     out_ndim_array=NULL;
+
+	out_M=this->M;
+	if(out_M){
+		out_array=xNew<IssmDouble*>(M);
+		out_mdim_array=xNew<int>(M);
+		out_ndim_array=xNew<int>(M);
+
+		xMemCpy<int>(out_mdim_array,this->mdim_array,M);
+		xMemCpy<int>(out_ndim_array,this->ndim_array,M);
+
+		for(i=0;i<this->M;i++){
+			matrix=this->array[i];
+			m=this->mdim_array[i];
+			n=this->ndim_array[i];
+
+			if(m*n){
+				out_matrix=xNew<IssmDouble>(m*n);
+				xMemCpy<IssmDouble>(out_matrix,matrix,m*n);
+			}
+			else{
+				out_matrix=NULL;
+			}
+			out_array[i]=out_matrix;
+		}
+	}
+	else{
+		out_array=NULL;
+		out_matrix=NULL;
+		out_ndim_array=NULL;
+	}
+
+	/*Assign output pointers:*/
+	if(pout_M) *pout_M=out_M;
+	if(pout_mdim_array) *pout_mdim_array=out_mdim_array;
+	if(pout_ndim_array) *pout_ndim_array=out_ndim_array;
+	*pout_array=out_array;
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::GetParameterName{{{*/
+void DoubleMatArrayParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){{{*/
+void  DoubleMatArrayParam::SetValue(IssmDouble** in_array, int in_M, int* in_mdim_array, int* in_ndim_array){
+
+	int i,m,n;
+	IssmDouble* in_matrix=NULL;
+	IssmDouble* matrix=NULL;
+
+	/*avoid leak: */
+	xDelete<int>(mdim_array);
+	xDelete<int>(ndim_array);
+	for(i=0;i<M;i++){
+		matrix=array[i];
+		xDelete<IssmDouble>(matrix);
+	}
+	xDelete<IssmDouble*>(array);
+
+	/*copy data: */
+	this->M=in_M;
+	this->array=xNew<IssmDouble*>(M);
+	this->mdim_array=xNew<int>(M);
+	this->ndim_array=xNew<int>(M);
+
+	xMemCpy<int>(this->mdim_array,in_mdim_array,M);
+	xMemCpy<int>(this->ndim_array,in_ndim_array,M);
+
+	for(i=0;i<M;i++){
+		in_matrix=in_array[i];
+		m=in_mdim_array[i];
+		n=in_ndim_array[i];
+
+		matrix=xNew<IssmDouble>(m*n);
+		xMemCpy<IssmDouble>(matrix,in_matrix,m*n);
+
+		this->array[i]=matrix;
+	}
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatArrayParam::UnitConversion{{{*/
+void  DoubleMatArrayParam::UnitConversion(int direction_enum){
+	/*go through all matrices and convert: */
+	for (int i=0;i<this->M;i++){
+		IssmDouble* matrix=this->array[i];
+		int     m=this->mdim_array[i];
+		int     n=this->ndim_array[i];
+		::UnitConversion(matrix,m*n,direction_enum,this->enum_type);
+	}
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.h	(revision 15012)
@@ -0,0 +1,79 @@
+/*! \file DoubleMatArrayParam.h 
+ *  \brief: header file for object holding an array of serial matrices
+ */
+
+#ifndef _DOUBLEMATARRAYPARAM_H_
+#define _DOUBLEMATARRAYPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class DoubleMatArrayParam: public Param{
+
+	private: 
+		int          enum_type;
+		IssmDouble **array;        //array of matrices
+		int          M;            //size of array
+		int         *mdim_array;   //m-dimensions of matrices in the array
+		int         *ndim_array;   //n-dimensions -f matrices in the array
+
+	public:
+		/*DoubleMatArrayParam constructors, destructors: {{{*/
+		DoubleMatArrayParam();
+		DoubleMatArrayParam(int enum_type,IssmDouble** array, int M, int* mdim_array, int* ndim_array);
+		~DoubleMatArrayParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << "cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << "cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << "cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims);
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << "cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a IssmDouble mat array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a int vec array");}
+		void  SetValue(int* intarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a int mat array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << "cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Bool param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array);
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _DOUBLEMATARRAYPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.cpp	(revision 15012)
@@ -0,0 +1,125 @@
+/*!\file DoubleMatParam.c
+ * \brief: implementation of the DoubleMatParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*DoubleMatParam constructors and destructor*/
+/*FUNCTION DoubleMatParam::DoubleMatParam(){{{*/
+DoubleMatParam::DoubleMatParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::DoubleMatParam(int enum_type,IssmDoubleMat value){{{*/
+DoubleMatParam::DoubleMatParam(int in_enum_type,IssmDouble* in_value, int in_M,int in_N){
+
+	enum_type=in_enum_type;
+	M=in_M;
+	N=in_N;
+
+	value=xNew<IssmDouble>(M*N);
+	xMemCpy<IssmDouble>(value,in_value,M*N);
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::~DoubleMatParam(){{{*/
+DoubleMatParam::~DoubleMatParam(){
+	xDelete<IssmDouble>(value);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleMatParam::Echo {{{*/
+void DoubleMatParam::Echo(void){
+
+	_printLine_("DoubleMatParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   matrix size: " << this->M << "x" << this->N);
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::DeepEcho{{{*/
+void DoubleMatParam::DeepEcho(void){
+
+	int i,j;
+
+	_printLine_("DoubleMatParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   matrix size: " << this->M << "x" << this->N);
+	for(i=0;i<this->M;i++){
+		for(i=0;i<this->N;i++){
+			_printLine_(i << " " << j << " " << *(this->value+N*i+j));
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::Id{{{*/
+int    DoubleMatParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleMatParam::ObjectEnum{{{*/
+int DoubleMatParam::ObjectEnum(void){
+
+	return DoubleMatParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::copy{{{*/
+Object* DoubleMatParam::copy() {
+
+	return new DoubleMatParam(this->enum_type,this->value,this->M,this->N);
+
+}
+/*}}}*/
+
+/*DoubleMatParam virtual functions definitions: */
+/*FUNCTION DoubleMatParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){{{*/
+void  DoubleMatParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){
+	IssmDouble* output=NULL;
+
+	output=xNew<IssmDouble>(M*N);
+	xMemCpy<IssmDouble>(output,value,M*N);
+
+	/*Assign output pointers:*/
+	if(pM) *pM=M;
+	if(pN) *pN=N;
+	*pIssmDoublearray=output;
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::GetParameterValue(int** pintarray,int* pM,int* pN){{{*/
+void  DoubleMatParam::GetParameterValue(int** pintarray,int* pM,int* pN){
+	_error_("DoubleMat of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an array of int");
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::GetParameterName{{{*/
+void DoubleMatParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::SetValue{{{*/
+void  DoubleMatParam::SetValue(IssmDouble* IssmDoublearray,int in_M,int in_N){
+
+	/*avoid leak: */
+	xDelete<IssmDouble>(this->value);
+
+	this->value=xNew<IssmDouble>(in_M*in_N);
+	xMemCpy<IssmDouble>(this->value,IssmDoublearray,in_M*in_N);
+
+	this->M=in_M;
+	this->N=in_N;
+}
+/*}}}*/
+/*FUNCTION DoubleMatParam::UnitConversion{{{*/
+void  DoubleMatParam::UnitConversion(int direction_enum){
+	::UnitConversion(this->value,this->M*this->N,direction_enum,this->enum_type);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.h	(revision 15012)
@@ -0,0 +1,78 @@
+/*! \file DoubleMatParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _DOUBLEMATPARAM_H_
+#define _DOUBLEMATPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class DoubleMatParam: public Param{
+
+	protected: 
+		int         enum_type;
+		IssmDouble *value;
+		int         M;
+		int         N;
+
+	public:
+		/*DoubleMatParam constructors, destructors: {{{*/
+		DoubleMatParam();
+		DoubleMatParam(int enum_type,IssmDouble* value,int M,int N);
+		~DoubleMatParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN);
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN);
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N);
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int vec array");}
+		void  SetValue(int* intarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");};
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _DOUBLEMATPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleParam.cpp	(revision 15012)
@@ -0,0 +1,105 @@
+/*!\file DoubleParam.c
+ * \brief: implementation of the DoubleParam object
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+
+/*DoubleParam constructors and destructor*/
+/*FUNCTION DoubleParam::DoubleParam(){{{*/
+DoubleParam::DoubleParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleParam::DoubleParam(int enum_type,IssmDouble value){{{*/
+DoubleParam::DoubleParam(int in_enum_type,IssmDouble in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION DoubleParam::~DoubleParam(){{{*/
+DoubleParam::~DoubleParam(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleParam::Echo {{{*/
+void DoubleParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION DoubleParam::DeepEcho{{{*/
+void DoubleParam::DeepEcho(void){
+
+	_printLine_("DoubleParam:");
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+}
+/*}}}*/
+/*FUNCTION DoubleParam::Id{{{*/
+int    DoubleParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleParam::ObjectEnum{{{*/
+int DoubleParam::ObjectEnum(void){
+
+	return DoubleParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleParam::copy{{{*/
+Object* DoubleParam::copy() {
+
+	return new DoubleParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*DoubleParam virtual functions definitions: */
+/*FUNCTION DoubleParam::GetParameterName{{{*/
+void DoubleParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(int* pinteger){{{*/
+void DoubleParam::GetParameterValue(int* pinteger){
+	_error_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an integer");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(bool* pbool){{{*/
+void DoubleParam::GetParameterValue(bool* pbool){
+	_error_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an bool");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(int** pintarray,int* pM){{{*/
+void DoubleParam::GetParameterValue(int** pintarray,int* pM){
+	_error_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an array of integers");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(int** pintarray,int* pM,int* pN){{{*/
+void DoubleParam::GetParameterValue(int** pintarray,int* pM,int* pN){
+	_error_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an array of integers");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){{{*/
+void DoubleParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){
+	_error_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an array of IssmDouble");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){{{*/
+void DoubleParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){
+	_error_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an array of IssmDouble");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::UnitConversion{{{*/
+void  DoubleParam::UnitConversion(int direction_enum){
+	::UnitConversion(&this->value,1,direction_enum,this->enum_type);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file DoubleParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _DOUBLEPARAM_H_
+#define _DOUBLEPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class DoubleParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int        enum_type;
+		IssmDouble value;
+
+	public:
+		/*DoubleParam constructors, destructors: {{{*/
+		DoubleParam();
+		DoubleParam(int enum_type,IssmDouble value);
+		~DoubleParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool);
+		void  GetParameterValue(int* pinteger);
+		void  GetParameterValue(int** pintarray,int* pM);
+		void  GetParameterValue(int** pintarray,int* pM,int* pN);
+		void  GetParameterValue(IssmDouble* pIssmDouble){*pIssmDouble=value;}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM);
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN);
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){this->value=(IssmDouble)boolean;}
+		void  SetValue(int integer){this->value=(IssmDouble)integer;}
+		void  SetValue(IssmDouble scalar){this->value=(IssmDouble)scalar;}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _DOUBLEPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleTransientMatParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleTransientMatParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleTransientMatParam.cpp	(revision 15012)
@@ -0,0 +1,25 @@
+/*!\file DoubleTransientMatParam.c
+ * \brief: implementation of the DoubleTransientMatParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*FUNCTION DoubleTransientMatParam::DoubleTransientMatParam(int enum_type,IssmDoubleMat value){{{*/
+DoubleTransientMatParam::DoubleTransientMatParam(int in_enum_type,IssmDouble* in_value, int in_M,int in_N):DoubleMatParam(in_enum_type,in_value,in_M,in_N){
+}
+/*}}}*/
+/*FUNCTION DoubleTransientMatParam::UnitConversion{{{*/
+void  DoubleTransientMatParam::UnitConversion(int direction_enum){
+	::UnitConversion(this->value,(this->M-1)*this->N,direction_enum,this->enum_type);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleTransientMatParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleTransientMatParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleTransientMatParam.h	(revision 15012)
@@ -0,0 +1,30 @@
+/*! \file DoubleTransientMatParam.h 
+ *  \brief: header file for DoubleTransientMatParam object
+ */
+
+#ifndef _DOUBLETRANSIENTMATPARAM_H_
+#define _DOUBLETRANSIENTMATPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class DoubleTransientMatParam: public DoubleMatParam{
+
+	public:
+		/*DoubleTransientMatParam constructors, destructors: {{{*/
+		DoubleTransientMatParam(int enum_type,IssmDouble* value,int M,int N);
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		void  UnitConversion(int direction_enum);
+		/*}}}*/
+};
+#endif  /* _DOUBLETRANSIENTMATPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.cpp	(revision 15012)
@@ -0,0 +1,139 @@
+/*!\file DoubleVecParam.c
+ * \brief: implementation of the DoubleVecParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*DoubleVecParam constructors and destructor*/
+/*FUNCTION DoubleVecParam::DoubleVecParam(){{{*/
+DoubleVecParam::DoubleVecParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::DoubleVecParam(int enum_type,IssmDoubleVec values,int M){{{*/
+DoubleVecParam::DoubleVecParam(int in_enum_type,IssmDouble* in_values, int in_M){
+
+	enum_type=in_enum_type;
+	M=in_M;
+
+	values=xNew<IssmDouble>(M);
+	xMemCpy<IssmDouble>(values,in_values,M);
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::~DoubleVecParam(){{{*/
+DoubleVecParam::~DoubleVecParam(){
+	xDelete<IssmDouble>(values);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleVecParam::Echo {{{*/
+void DoubleVecParam::Echo(void){
+
+	_printLine_("DoubleVecParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   vector size: " << this->M);
+
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::DeepEcho{{{*/
+void DoubleVecParam::DeepEcho(void){
+
+	int i;
+
+	_printLine_("DoubleVecParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   vector size: " << this->M);
+	for(i=0;i<this->M;i++){
+		_printLine_(i << " " << this->values[i]);
+	}
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::Id{{{*/
+int    DoubleVecParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleVecParam::ObjectEnum{{{*/
+int DoubleVecParam::ObjectEnum(void){
+
+	return DoubleVecParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::copy{{{*/
+Object* DoubleVecParam::copy() {
+
+	return new DoubleVecParam(this->enum_type,this->values,this->M);
+
+}
+/*}}}*/
+
+/*DoubleVecParam virtual functions definitions: */
+/*FUNCTION DoubleVecParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){{{*/
+void  DoubleVecParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){
+	IssmDouble* output=NULL;
+	int M;
+
+	M=this->M;
+	output=xNew<IssmDouble>(M);
+	xMemCpy<IssmDouble>(output,values,M);
+
+	/*Assign output pointers:*/
+	if(pM) *pM=M;
+	*pIssmDoublearray=output;
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){{{*/
+void  DoubleVecParam::GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){
+	IssmDouble* output=NULL;
+	int M;
+	int N;
+
+	N=1;
+	M=this->M;
+	output=xNew<IssmDouble>(M);
+	xMemCpy<IssmDouble>(output,values,M);
+
+	/*Assign output pointers:*/
+	if(pM) *pM=M;
+	if(pN) *pN=N;
+	*pIssmDoublearray=output;
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::GetParameterValue(int** pintarray,int* pM){{{*/
+void  DoubleVecParam::GetParameterValue(int** pintarray,int* pM){
+	_error_("DoubleVec param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an array of int");
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::GetParameterName{{{*/
+void DoubleVecParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::SetValue{{{*/
+void  DoubleVecParam::SetValue(IssmDouble* IssmDoublearray,int in_M){
+
+	/*avoid leak: */
+	xDelete<IssmDouble>(this->values);
+
+	this->values=xNew<IssmDouble>(in_M);
+	xMemCpy<IssmDouble>(this->values,IssmDoublearray,in_M);
+
+	this->M=in_M;
+}
+/*}}}*/
+/*FUNCTION DoubleVecParam::UnitConversion{{{*/
+void  DoubleVecParam::UnitConversion(int direction_enum){
+	::UnitConversion(this->values,this->M,direction_enum,this->enum_type);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.h	(revision 15012)
@@ -0,0 +1,76 @@
+/*! \file DoubleVecParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _DOUBLEVECPARAM_H_
+#define _DOUBLEVECPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class DoubleVecParam: public Param{
+
+	private: 
+		int         enum_type;
+		IssmDouble *values;
+		int         M;
+
+	public:
+		/*DoubleVecParam constructors, destructors: {{{*/
+		DoubleVecParam();
+		DoubleVecParam(int enum_type,IssmDouble* values,int M);
+		~DoubleVecParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param virtual functions definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM);
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");};
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM);
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN);
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M);
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");};
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+		/*}}}*/
+};
+#endif  /* _DOUBLEVECPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/FileParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/FileParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/FileParam.cpp	(revision 15012)
@@ -0,0 +1,78 @@
+/*!\file FileParam.c
+ * \brief: implementation of the FileParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*FileParam constructors and destructor*/
+/*FUNCTION FileParam::FileParam(){{{*/
+FileParam::FileParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION FileParam::FileParam(int enum_type,FILE *value){{{*/
+FileParam::FileParam(int in_enum_type,FILE* in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION FileParam::~FileParam(){{{*/
+FileParam::~FileParam(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION FileParam::Echo {{{*/
+void FileParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION FileParam::DeepEcho{{{*/
+void FileParam::DeepEcho(void){
+
+	_printLine_("FileParam:");
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+}
+/*}}}*/
+/*FUNCTION FileParam::Id{{{*/
+int    FileParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION FileParam::ObjectEnum{{{*/
+int FileParam::ObjectEnum(void){
+
+	return FileParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION FileParam::copy{{{*/
+Object* FileParam::copy() {
+
+	return new FileParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*FileParam virtual functions definitions: */
+/*FUNCTION FileParam::GetParameterName{{{*/
+void FileParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION FileParam::UnitConversion{{{*/
+void  FileParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/FileParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/FileParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/FileParam.h	(revision 15012)
@@ -0,0 +1,76 @@
+/*! \file FileParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _FILEPARAM_H_
+#define _FILEPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class FileParam: public Param{
+
+	private: 
+		int   enum_type;
+		FILE* value;
+
+	public:
+		/*FileParam constructors, destructors: {{{*/
+		FileParam();
+		FileParam(int enum_type,FILE* fid);
+		~FileParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){  _error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("File param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){*pfid=value;};
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("File param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("File param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _INTPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/GenericParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/GenericParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/GenericParam.h	(revision 15012)
@@ -0,0 +1,97 @@
+/*
+ * GenericParam.h
+ *
+ *  Created on: Aug 29, 2012
+ *      Author: utke
+ */
+
+#ifndef GENERICPARAM_H_
+#define GENERICPARAM_H_
+
+/*Headers:*/
+#ifdef HAVE_CONFIG_H
+        #include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+#include "./Param.h"
+#include "../../shared/shared.h"
+
+/**
+ * here we have a class that holds an instance of P
+ * but because it should live side by side with
+ * the other instances derived from Param it - unfortunately -
+ * inherits all the accessors that are useless in this context
+ */
+template <class P> class GenericParam: public Param{
+
+        private:
+                P myP;
+                int myEnumVal;
+
+        public:
+                /*GenericParam constructors, destructors: {{{*/
+                GenericParam(int enumVal) : myEnumVal(enumVal){};
+                ~GenericParam(){};
+                /*}}}*/
+                /*Object virtual functions definitions:{{{ */
+                // unfortunately,  having to implement such a printer method implies
+                // that any structured P must provide the friend << operator
+                void  DeepEcho() {
+                  _printLine_("GenericParam:");
+                  _printLine_("   enum:  " << myEnumVal << " (" << EnumToStringx(myEnumVal) << ")");
+                  _printLine_("   value: " << myP);;
+                }
+                void  Echo() {DeepEcho();};
+                int   Id(){ return -1; };
+                int   ObjectEnum() {return AdolcParamEnum;};
+
+                // the "copy"  has to implement the base class abstract function
+                // but I would prefer to drop this not to hide a "new" in here because
+                // it does not clarify  ownership of the newed up instance...
+                // use the default copy constructor instead
+                Object* copy() { return new GenericParam<P>(*this); };
+                /*}}}*/
+                /*Param vritual function definitions: {{{*/
+                int   InstanceEnum(){return myEnumVal;}
+                void GetParameterName(char**pname) {EnumToStringx(pname,this->myEnumVal);}
+
+                P& GetParameterValue() { return myP;}
+                const P& GetParameterValue()const { return myP;};
+
+                // none of these apply ...
+                void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a bool");}
+                void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return an integer");}
+                void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return an array of integers");}
+                void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return an array of integers");}
+                void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a IssmDouble");}
+                void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a IssmDouble for a given time");}
+                void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a string");}
+                void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a string array");}
+                void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a IssmDouble array");}
+                void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a IssmDouble array");}
+                void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a matrix array");}
+                void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a Vec");}
+                void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a Mat");}
+                void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a FILE");}
+				void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot return a DataSet");}
+
+                void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a bool");}
+                void  SetValue(int integer){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an integer");}
+                void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an int array");}
+                void  SetValue(int* intarray,int M,int N){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an int array");}
+                void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an IssmDouble");}
+                void  SetValue(char* string){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a string");}
+                void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a string array");}
+                void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a IssmDouble array");}
+                void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a IssmDouble array");}
+                void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a Vec");}
+                void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a Mat");}
+                void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a FILE");}
+                void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an array of matrices");}
+                void  UnitConversion(int direction_enum) {/* nothing useful here either */};
+
+                /*}}}*/
+};
+
+#endif /* GENERICPARAM_H_ */
Index: /issm/trunk-jpl/src/c/classes/Params/IntMatParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/IntMatParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/IntMatParam.cpp	(revision 15012)
@@ -0,0 +1,120 @@
+/*!\file IntMatParam.c
+ * \brief: implementation of the IntMatParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*IntMatParam constructors and destructor*/
+/*FUNCTION IntMatParam::IntMatParam(){{{*/
+IntMatParam::IntMatParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION IntMatParam::IntMatParam(int enum_type,IssmIntMat value){{{*/
+IntMatParam::IntMatParam(int in_enum_type,int* in_value, int in_M,int in_N){
+
+	enum_type=in_enum_type;
+	M=in_M;
+	N=in_N;
+
+	value=xNew<int>(M*N);
+	xMemCpy<int>(value,in_value,M*N);
+}
+/*}}}*/
+/*FUNCTION IntMatParam::~IntMatParam(){{{*/
+IntMatParam::~IntMatParam(){
+	xDelete<int>(value);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION IntMatParam::Echo {{{*/
+void IntMatParam::Echo(void){
+
+	_printLine_("IntMatParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   matrix size: " << this->M << "x" << this->N);
+
+}
+/*}}}*/
+/*FUNCTION IntMatParam::DeepEcho{{{*/
+void IntMatParam::DeepEcho(void){
+
+	int i,j;
+
+	_printLine_("IntMatParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   matrix size: " << this->M << "x" << this->N);
+	for(i=0;i<this->M;i++){
+		for(i=0;i<this->N;i++){
+			_printLine_("(" << i << "," << j << ") " << *(this->value+N*i+j));
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION IntMatParam::Id{{{*/
+int    IntMatParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION IntMatParam::ObjectEnum{{{*/
+int IntMatParam::ObjectEnum(void){
+
+	return IntMatParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION IntMatParam::copy{{{*/
+Object* IntMatParam::copy() {
+
+	return new IntMatParam(this->enum_type,this->value,this->M,this->N);
+
+}
+/*}}}*/
+
+/*IntMatParam virtual functions definitions: */
+/*FUNCTION IntMatParam::GetParameterValue{{{*/
+void  IntMatParam::GetParameterValue(int** pintarray,int* pM,int* pN){
+	int* output=NULL;
+
+	output=xNew<int>(M*N);
+	xMemCpy<int>(output,value,M*N);
+
+	/*Assign output pointers:*/
+	if(pM) *pM=M;
+	if(pN) *pN=N;
+	*pintarray=output;
+}
+/*}}}*/
+/*FUNCTION IntMatParam::GetParameterName{{{*/
+void IntMatParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION IntMatParam::SetValue{{{*/
+void  IntMatParam::SetValue(int* intarray,int in_M,int in_N){
+
+	/*avoid leak: */
+	xDelete<int>(this->value);
+
+	this->value=xNew<int>(in_M*in_N);
+	xMemCpy<int>(this->value,intarray,in_M*in_N);
+
+	this->M=in_M;
+	this->N=in_N;
+}
+/*}}}*/
+/*FUNCTION IntMatParam::UnitConversion{{{*/
+void  IntMatParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/IntMatParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/IntMatParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/IntMatParam.h	(revision 15012)
@@ -0,0 +1,78 @@
+/*! \file IntMatParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _INTMATPARAM_H_
+#define _INTMATPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class IntMatParam: public Param{
+
+	private: 
+		int enum_type;
+		int* value;
+		int M;
+		int N;
+
+	public:
+		/*IntMatParam constructors, destructors: {{{*/
+		IntMatParam();
+		IntMatParam(int enum_type,int* value,int M,int N);
+		~IntMatParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN);
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");};
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");};
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int vec array");};
+		void  SetValue(int* intarray,int M,int N);
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _INTMATPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/IntParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/IntParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/IntParam.cpp	(revision 15012)
@@ -0,0 +1,78 @@
+/*!\file IntParam.c
+ * \brief: implementation of the IntParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*IntParam constructors and destructor*/
+/*FUNCTION IntParam::IntParam(){{{*/
+IntParam::IntParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION IntParam::IntParam(int enum_type,IssmInt value){{{*/
+IntParam::IntParam(int in_enum_type,IssmInt in_value){
+
+	enum_type=in_enum_type;
+	value=in_value;
+}
+/*}}}*/
+/*FUNCTION IntParam::~IntParam(){{{*/
+IntParam::~IntParam(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION IntParam::Echo {{{*/
+void IntParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION IntParam::DeepEcho{{{*/
+void IntParam::DeepEcho(void){
+
+	_printLine_("IntParam:");
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+}
+/*}}}*/
+/*FUNCTION IntParam::Id{{{*/
+int    IntParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION IntParam::ObjectEnum{{{*/
+int IntParam::ObjectEnum(void){
+
+	return IntParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION IntParam::copy{{{*/
+Object* IntParam::copy() {
+
+	return new IntParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*IntParam virtual functions definitions: */
+/*FUNCTION IntParam::GetParameterName{{{*/
+void IntParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION IntParam::UnitConversion{{{*/
+void  IntParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/IntParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/IntParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/IntParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file IntParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _INTPARAM_H_
+#define _INTPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class IntParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		IssmInt value;
+
+	public:
+		/*IntParam constructors, destructors: {{{*/
+		IntParam();
+		IntParam(int enum_type,IssmInt value);
+		~IntParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){*pinteger=value;}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a bool");}
+		void  SetValue(int integer){this->value=integer;}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an int array");}
+		void  SetValue(int* intarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an int array");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _INTPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/IntVecParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/IntVecParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/IntVecParam.cpp	(revision 15012)
@@ -0,0 +1,136 @@
+/*!\file IntVecParam.c
+ * \brief: implementation of the IntVecParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*IntVecParam constructors and destructor*/
+/*FUNCTION IntVecParam::IntVecParam(){{{*/
+IntVecParam::IntVecParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION IntVecParam::IntVecParam(int enum_type,int* values,int M){{{*/
+IntVecParam::IntVecParam(int in_enum_type,int* in_values, int in_M){
+
+	enum_type=in_enum_type;
+	M=in_M;
+
+	if(M){
+		values=xNew<int>(M);
+		xMemCpy<int>(values,in_values,M);
+	}
+	else values=NULL;
+}
+/*}}}*/
+/*FUNCTION IntVecParam::IntVecParam(int enum_type,IssmDouble* values,int M){{{*/
+IntVecParam::IntVecParam(int in_enum_type,IssmDouble* in_values, int in_M){
+
+	enum_type=in_enum_type;
+	M=in_M;
+
+	if(M){
+		values=xNew<int>(M);
+		for(int i=0;i<in_M;i++) values[i]=reCast<int>(in_values[i]);
+	}
+	else values=NULL;
+}
+/*}}}*/
+/*FUNCTION IntVecParam::~IntVecParam(){{{*/
+IntVecParam::~IntVecParam(){
+	xDelete<int>(values);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION IntVecParam::Echo {{{*/
+void IntVecParam::Echo(void){
+
+	_printLine_("IntVecParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   vector size: " << this->M);
+
+}
+/*}}}*/
+/*FUNCTION IntVecParam::DeepEcho{{{*/
+void IntVecParam::DeepEcho(void){
+
+	int i;
+
+	_printLine_("IntVecParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   vector size: " << this->M);
+	for(i=0;i<this->M;i++){
+		_printLine_(i << " " << this->values[i]);
+	}
+}
+/*}}}*/
+/*FUNCTION IntVecParam::Id{{{*/
+int    IntVecParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION IntVecParam::ObjectEnum{{{*/
+int IntVecParam::ObjectEnum(void){
+
+	return IntVecParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION IntVecParam::copy{{{*/
+Object* IntVecParam::copy() {
+
+	return new IntVecParam(this->enum_type,this->values,this->M);
+
+}
+/*}}}*/
+
+/*IntVecParam virtual functions definitions: */
+/*FUNCTION IntVecParam::GetParameterValue{{{*/
+void  IntVecParam::GetParameterValue(int** pintarray,int* pM){
+	int* output=NULL;
+
+	if(M){
+		output=xNew<int>(M);
+		xMemCpy<int>(output,values,M);
+	}
+
+	/*Assign output pointers:*/
+	if(pM) *pM=M;
+	*pintarray=output;
+}
+/*}}}*/
+/*FUNCTION IntVecParam::GetParameterName{{{*/
+void IntVecParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION IntVecParam::SetValue{{{*/
+void  IntVecParam::SetValue(int* intarray,int in_M){
+
+	/*avoid leak: */
+	xDelete<int>(this->values);
+
+	if(in_M){
+		this->values=xNew<int>(in_M);
+		xMemCpy<int>(this->values,intarray,in_M);
+	}
+	else this->values=NULL;
+
+	this->M=in_M;
+}
+/*}}}*/
+/*FUNCTION IntVecParam::UnitConversion{{{*/
+void  IntVecParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/IntVecParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/IntVecParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/IntVecParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file IntVecParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _INTVECPARAM_H_
+#define _INTVECPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class IntVecParam: public Param{
+
+	private: 
+		int enum_type;
+		int* values;
+		int M;
+
+	public:
+		/*IntVecParam constructors, destructors: {{{*/
+		IntVecParam();
+		IntVecParam(int enum_type,int* values,int M);
+		IntVecParam(int enum_type,IssmDouble* values,int M);
+		~IntVecParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param virtual functions definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM);
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array (maybe in serial?)");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(int* intarray,int M);
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+		/*}}}*/
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Params/MatrixParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/MatrixParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/MatrixParam.cpp	(revision 15012)
@@ -0,0 +1,105 @@
+/*!\file MatrixParam.c
+ * \brief: implementation of the MatrixParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*MatrixParam constructors and destructor*/
+/*FUNCTION MatrixParam::MatrixParam(){{{*/
+MatrixParam::MatrixParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION MatrixParam::MatrixParam(int enum_type,Matrix<IssmDouble>* value){{{*/
+MatrixParam::MatrixParam(int in_enum_type,Matrix<IssmDouble>* in_value){
+
+	enum_type=in_enum_type;
+	value=NULL;
+
+	if(in_value){
+		value=in_value->Duplicate();
+	}
+}
+/*}}}*/
+/*FUNCTION MatrixParam::~MatrixParam(){{{*/
+MatrixParam::~MatrixParam(){
+	delete value;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION MatrixParam::Echo {{{*/
+void MatrixParam::Echo(void){
+
+	_printLine_("MatrixParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+
+}
+/*}}}*/
+/*FUNCTION MatrixParam::DeepEcho{{{*/
+void MatrixParam::DeepEcho(void){
+
+	_printLine_("MatrixParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	this->value->Echo();
+}
+/*}}}*/
+/*FUNCTION MatrixParam::Id{{{*/
+int    MatrixParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION MatrixParam::ObjectEnum{{{*/
+int MatrixParam::ObjectEnum(void){
+
+	return MatrixParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION MatrixParam::copy{{{*/
+Object* MatrixParam::copy() {
+
+	return new MatrixParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*MatrixParam virtual functions definitions: */
+/*FUNCTION MatrixParam::GetParameterValue{{{*/
+void  MatrixParam::GetParameterValue(Matrix<IssmDouble>** poutput){
+	Matrix<IssmDouble>* output=NULL;
+
+	if(value){
+		output=value->Duplicate();
+	}
+	*poutput=output;
+}
+/*}}}*/
+/*FUNCTION MatrixParam::GetParameterName{{{*/
+void MatrixParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION MatrixParam::SetValue{{{*/
+void  MatrixParam::SetValue(Matrix<IssmDouble>* matrix){
+
+	/*avoid leak: */
+	delete value;
+
+	/*copy: */
+	value=matrix->Duplicate();
+}
+/*}}}*/
+/*FUNCTION MatrixParam::UnitConversion{{{*/
+void  MatrixParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/MatrixParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/MatrixParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/MatrixParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file MatrixParam.h 
+ *  \brief: header file for MatrixParam object
+ */
+
+#ifndef _MATRIXPARAM_H_
+#define _MATRIXPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class MatrixParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		Matrix<IssmDouble>* value;
+
+	public:
+		/*MatrixParam constructors, destructors: {{{*/
+		MatrixParam();
+		MatrixParam(int enum_type,Matrix<IssmDouble>* value);
+		~MatrixParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** poutput);
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat);
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _MATRIXPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/Param.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/Param.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/Param.h	(revision 15012)
@@ -0,0 +1,60 @@
+/*!\file:  Param.h
+ * \brief abstract class for Param object
+ */ 
+
+#ifndef _PARAM_H_
+#define _PARAM_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../Object.h"
+#include "../Node.h"
+/*}}}*/
+
+class Param: public Object{
+
+	public: 
+		virtual        ~Param(){};
+
+		/*Virtual functions:*/
+		virtual int   InstanceEnum()=0;
+		virtual void  GetParameterValue(bool* pbool)=0;
+		virtual void  GetParameterValue(int* pinteger)=0;
+		virtual void  GetParameterValue(int** pintarray,int* pM)=0;
+		virtual void  GetParameterValue(int** pintarray,int* pM,int* pN)=0;
+		virtual void  GetParameterValue(IssmDouble* pIssmDouble)=0;
+		virtual void  GetParameterValue(IssmDouble* pdouble,IssmDouble time)=0;
+		virtual void  GetParameterValue(char** pstring)=0;
+		virtual void  GetParameterValue(char*** pstringarray,int* pM)=0;
+		virtual void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM)=0;
+		virtual void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN)=0;
+		virtual void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims)=0;
+		virtual void  GetParameterValue(Vector<IssmDouble>** pvec)=0;
+		virtual void  GetParameterValue(Matrix<IssmDouble>** pmat)=0;
+		virtual void  GetParameterValue(FILE** pfid)=0;
+		virtual void  GetParameterValue(DataSet** pdataset)=0;
+
+		virtual void  SetValue(bool boolean)=0;
+		virtual void  SetValue(int integer)=0;
+		virtual void  SetValue(IssmDouble scalar)=0;
+		virtual void  SetValue(char* string)=0;
+		virtual void  SetValue(char** stringarray,int M)=0;
+		virtual void  SetValue(IssmDouble* IssmDoublearray,int M)=0;
+		virtual void  SetValue(IssmDouble* pIssmDoublearray,int M,int N)=0;
+		virtual void  SetValue(int* intarray,int M)=0;
+		virtual void  SetValue(int* pintarray,int M,int N)=0;
+		virtual void  SetValue(Vector<IssmDouble>* vec)=0;
+		virtual void  SetValue(Matrix<IssmDouble>* mat)=0;
+		virtual void  SetValue(FILE* fid)=0;
+		virtual void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array)=0;
+		virtual void  UnitConversion(int direction_enum)=0;
+		virtual void  GetParameterName(char**pname)=0;
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/Params/Parameters.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/Parameters.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/Parameters.cpp	(revision 15012)
@@ -0,0 +1,605 @@
+/*
+ * \file Parameters.cpp
+ * \brief: Implementation of the Parameters class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <vector>
+#include <functional>
+#include <algorithm>
+#include <iostream>
+
+#include "./Parameters.h"
+#include "./Param.h"
+
+#include "./BoolParam.h"
+#include "./DoubleMatParam.h"
+#include "./DoubleParam.h"
+#include "./DoubleVecParam.h"
+#include "./IntParam.h"
+#include "./IntVecParam.h"
+#include "./IntMatParam.h"
+#include "./FileParam.h"
+#include "./MatrixParam.h"
+#include "./VectorParam.h"
+#include "./StringArrayParam.h"
+#include "./StringParam.h"
+
+#include "../../shared/shared.h"
+#include "../../toolkits/toolkits.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Parameters::Parameters(){{{*/
+Parameters::Parameters(){
+	enum_type=ParametersEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Parameters::~Parameters(){{{*/
+Parameters::~Parameters(){
+	return;
+}
+/*}}}*/
+
+/*Object management*/
+/*FUNCTION Parameters::Exist{{{*/
+bool Parameters::Exist(int enum_type){
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type) return true;
+	}
+	return false;
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(bool* pbool,int enum_type){{{*/
+void Parameters::FindParam(bool* pbool,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pbool);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(int* pinteger,int enum_type){{{*/
+void Parameters::FindParam(int* pinteger,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pinteger);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(IssmDouble* pscalar, int enum_type){{{*/
+void Parameters::FindParam(IssmDouble* pscalar, int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pscalar);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(IssmDouble* pscalar, int enum_type,IssmDouble time){{{*/
+void Parameters::FindParam(IssmDouble* pscalar, int enum_type,IssmDouble time){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pscalar,time);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(char** pstring,int enum_type){{{*/
+void Parameters::FindParam(char** pstring,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pstring);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(char*** pstringarray,int* pM,int enum_type){{{*/
+void Parameters::FindParam(char*** pstringarray,int* pM,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pstringarray,pM);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(int** pintarray,int* pM,int enum_type){{{*/
+void Parameters::FindParam(int** pintarray,int* pM, int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pintarray,pM);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(int** pintarray,int* pM,int* pN,int enum_type){{{*/
+void Parameters::FindParam(int** pintarray,int* pM,int *pN,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pintarray,pM,pN);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM,int enum_type){{{*/
+void Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM, int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pIssmDoublearray,pM);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM, int* pN,int enum_type){{{*/
+void Parameters::FindParam(IssmDouble** pIssmDoublearray,int* pM, int* pN,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pIssmDoublearray,pM,pN);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(IssmDouble*** parray,int* pM,int** pmdims_array,int** pndims_array,int enum_type){{{*/
+void Parameters::FindParam(IssmDouble*** parray,int* pM,int** pmdims_array,int** pndims_array,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(parray,pM,pmdims_array,pndims_array);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(Vector<IssmDouble>** pvec,int enum_type){{{*/
+void Parameters::FindParam(Vector<IssmDouble>** pvec,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pvec);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(Matrix<IssmDouble>** pmat,int enum_type){{{*/
+void Parameters::FindParam(Matrix<IssmDouble>** pmat,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pmat);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(FILE** pfid,int enum_type){{{*/
+void Parameters::FindParam(FILE** pfid,int enum_type){ _assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pfid);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+/*FUNCTION Parameters::FindParam(DataSet** pdataset,int enum_type){{{*/
+void Parameters::FindParam(DataSet** pdataset,int enum_type){ 
+	_assert_(this);
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			param->GetParameterValue(pdataset);
+			return;
+		}
+	}
+	_error_("could not find parameter " << EnumToStringx(enum_type));
+}
+/*}}}*/
+
+/*FUNCTION Parameters::SetParam(bool boolean,int enum_type);{{{*/
+void   Parameters::SetParam(bool boolean,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(boolean); //already exists, just set it.
+	else this->AddObject(new BoolParam(enum_type,boolean)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(int integer,int enum_type);{{{*/
+void   Parameters::SetParam(int integer,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(integer); //already exists, just set it.
+	else this->AddObject(new IntParam(enum_type,integer)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(IssmDouble scalar,int enum_type);{{{*/
+void   Parameters::SetParam(IssmDouble scalar,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(scalar); //already exists, just set it.
+	else this->AddObject(new DoubleParam(enum_type,scalar)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(char* string,int enum_type);{{{*/
+void   Parameters::SetParam(char* string,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(string); //already exists, just set it.
+	else this->AddObject(new StringParam(enum_type,string)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(char** stringarray,int M, int enum_type);{{{*/
+void   Parameters::SetParam(char** stringarray,int M, int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(stringarray,M); //already exists, just set it.
+	else this->AddObject(new StringArrayParam(enum_type,stringarray,M)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(IssmDouble* IssmDoublearray,int M,int enum_type);{{{*/
+void   Parameters::SetParam(IssmDouble* IssmDoublearray,int M, int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(IssmDoublearray,M); //already exists, just set it.
+	else this->AddObject(new DoubleVecParam(enum_type,IssmDoublearray,M)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(IssmDouble* IssmDoublearray,int M,int N, int enum_type);{{{*/
+void   Parameters::SetParam(IssmDouble* IssmDoublearray,int M, int N, int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(IssmDoublearray,M,N); //already exists, just set it.
+	else this->AddObject(new DoubleMatParam(enum_type,IssmDoublearray,M,N)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(int* intarray,int M,int enum_type);{{{*/
+void   Parameters::SetParam(int* intarray,int M, int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(intarray,M); //already exists, just set it.
+	else this->AddObject(new IntVecParam(enum_type,intarray,M)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(int* intarray,int M,int N, int enum_type);{{{*/
+void   Parameters::SetParam(int* intarray,int M, int N, int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(intarray,M,N); //already exists, just set it.
+	else this->AddObject(new IntMatParam(enum_type,intarray,M,N)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(Vector<IssmDouble>* vector,int enum_type);{{{*/
+void   Parameters::SetParam(Vector<IssmDouble>* vector,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(vector); //already exists, just set it.
+	else this->AddObject(new VectorParam(enum_type,vector)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(Matrix<IssmDouble>* matrix,int enum_type);{{{*/
+void   Parameters::SetParam(Matrix<IssmDouble>* matrix,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(matrix); //already exists, just set it.
+	else this->AddObject(new MatrixParam(enum_type,matrix)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::SetParam(FILE* fid,int enum_type);{{{*/
+void   Parameters::SetParam(FILE* fid,int enum_type){
+
+	Param* param=NULL;
+
+	/*first, figure out if the param has already been created: */
+	param=dynamic_cast<Param*>(this->FindParamObject(enum_type));
+
+	if(param) param->SetValue(fid); //already exists, just set it.
+	else this->AddObject(new FileParam(enum_type,fid)); //just add the new parameter.
+}
+/*}}}*/
+/*FUNCTION Parameters::UnitConversion(int direction_enum);{{{*/
+void   Parameters::UnitConversion(int direction_enum){
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+		param=dynamic_cast<Param*>(*object);
+		param->UnitConversion(direction_enum);
+	}
+
+}
+/*}}}*/
+
+/*FUNCTION Parameters::FindParamObject{{{*/
+Object* Parameters::FindParamObject(int enum_type){
+
+	vector<Object*>::iterator object;
+	Param* param=NULL;
+
+	for ( object=objects.begin() ; object < objects.end(); object++ ){
+
+		param=dynamic_cast<Param*>(*object);
+		if(param->InstanceEnum()==enum_type){
+			return (*object);
+		}
+	}
+	return NULL;
+}
+/*}}}*/
+
+/*Methods relating to parameters: */
+char* OptionsFromAnalysis(Parameters* parameters,int analysis_type){ /*{{{*/
+
+	/* figure out ISSM options for current analysis, return a string. */ 
+
+	/*output: */
+	char*   outstring=NULL;
+
+	/*intermediary: */
+	int          dummy;
+	IssmDouble  *analyses    = NULL;
+	char       **strings     = NULL;
+	char        *string      = NULL;
+	int          numanalyses;
+	int          found       = -1;
+	int          i;
+
+	numanalyses=0;
+	parameters->FindParam(&strings,&numanalyses,ToolkitsOptionsStringsEnum);
+
+	parameters->FindParam(&analyses,&dummy,ToolkitsOptionsAnalysesEnum);
+
+	if(numanalyses==0)return NULL; //we did not find petsc options, don't bother.
+
+	/*ok, go through analyses and figure out if it corresponds to our analysis_type: */
+	for(i=0;i<numanalyses;i++){
+		if(analyses[i]==analysis_type){
+			found=i;
+			break;
+		}
+	}
+	if(found==-1){
+		/*still haven't found a list of petsc options, go find the default one, for analysis type NoneAnalysisEnum: */
+		for(i=0;i<numanalyses;i++){
+			if(analyses[i]==DefaultAnalysisEnum){
+				found=i;
+				break;
+			}
+		}
+	}
+	if (found==-1){
+		_error_("could find neither a default analysis nor analysis " << EnumToStringx(analysis_type));
+	}
+
+	/*ok, grab the option string: */
+	outstring=xNew<char>(strlen(strings[found])+1);
+	strcpy(outstring,strings[found]);
+
+	/*Free ressources*/
+	xDelete<IssmDouble>(analyses);
+	for(i=0;i<numanalyses;i++){
+		string=strings[i];
+		xDelete<char>(string);
+	}
+	xDelete<char*>(strings);
+	return outstring;
+} 
+/*}}}*/
+void ToolkitsOptionsFromAnalysis(Parameters* parameters,int analysis_type){ /*{{{*/
+
+	/*!\file:  ToolkitsOptionsFromAnalysis.cpp
+	 * \brief: for each analysis, setup the issmoptions string. 
+	 * This is mainly for the case where we run our toolkits using petsc. In this case, we need to 
+	 * plug our toolkits options directly into the petsc options database. This is the case for each analysis type 
+	 * and parameters
+	 */ 
+
+
+	char* options=NULL;
+
+	/*Recover first the options string for this analysis: */
+	options=OptionsFromAnalysis(parameters,analysis_type);
+
+	/*Initialize our Toolkit Options: */
+	ToolkitOptions::Init(options);
+
+	#ifdef _HAVE_PETSC_
+		/*In case we are using PETSC, we do not rely on issmoptions. Instead, we dump issmoptions into the Petsc 
+		 * options database: */
+
+		#if _PETSC_MAJOR_ == 2 
+		PetscOptionsDestroy();
+		PetscOptionsCreate();
+		//PetscOptionsCheckInitial_Private();
+		//PetscOptionsCheckInitial_Components();
+		PetscOptionsSetFromOptions();
+		PetscOptionsInsertMultipleString(options); //our patch
+		#else
+		PetscOptionsSetFromOptions();
+		PetscOptionsClear();
+		//PetscOptionsSetFromOptions();
+		PetscOptionsInsertMultipleString(options); //our patch
+		#endif
+
+	#endif
+
+	xDelete<char>(options);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/Parameters.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/Parameters.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/Parameters.h	(revision 15012)
@@ -0,0 +1,65 @@
+#ifndef _CONTAINER_PARAMETERS_H_
+#define  _CONTAINER_PARAMETERS_H_
+#include <stdio.h>
+
+/*forward declarations */
+template <class doublematrix> class Matrix;
+template <class doubletype> class Vector;
+#include "../DataSet.h"
+#include "../../shared/shared.h"
+
+/*!\brief Declaration of Parameters class.  
+ *
+ * Declaration of Parameters class.  Parameters are vector lists (Containers) of Parameter objects.
+ */ 
+class Parameters: public DataSet{
+
+	public:
+
+		/*constructors, destructors*/ 
+		Parameters();
+		~Parameters();
+
+		/*numerics*/
+		bool  Exist(int enum_type);
+
+		void  FindParam(bool* pinteger,int enum_type);
+		void  FindParam(int* pinteger,int enum_type);
+		void  FindParam(IssmDouble* pscalar, int enum_type);
+		void  FindParam(IssmDouble* pscalar, int enum_type,IssmDouble time);
+		void  FindParam(char** pstring,int enum_type);
+		void  FindParam(char*** pstringarray,int* pM,int enum_type);
+		void  FindParam(int** pintarray,int* pM,int enum_type);
+		void  FindParam(int** pintarray,int* pM,int* PN,int enum_type);
+		void  FindParam(IssmDouble** pIssmDoublearray,int* pM,int enum_type);
+		void  FindParam(IssmDouble** pIssmDoublearray,int* pM,int* pN,int enum_type);
+		void  FindParam(IssmDouble*** parray,int* pM, int** pmdims_array,int** pndims_array,int enum_type);
+		void  FindParam(Vector<IssmDouble>** pvec,int enum_type);
+		void  FindParam(Matrix<IssmDouble>** pmat,int enum_type);
+		void  FindParam(FILE** pfid,int enum_type);
+		void  FindParam(DataSet** pdataset, int enum_type);
+
+		void  SetParam(bool boolean,int enum_type);
+		void  SetParam(int integer,int enum_type);
+		void  SetParam(IssmDouble scalar, int enum_type);
+		void  SetParam(char* string,int enum_type);
+		void  SetParam(char** stringarray,int M,int enum_type);
+		void  SetParam(IssmDouble* IssmDoublearray,int M,int enum_type);
+		void  SetParam(IssmDouble* IssmDoublearray,int M,int N,int enum_type);
+		void  SetParam(int* intarray,int M,int enum_type);
+		void  SetParam(int* intarray,int M,int N,int enum_type);
+		void  SetParam(Vector<IssmDouble>* vec,int enum_type);
+		void  SetParam(Matrix<IssmDouble>* mat,int enum_type);
+		void  SetParam(FILE* fid,int enum_type);
+		void  UnitConversion(int direction_enum);
+
+		Object* FindParamObject(int enum_type);
+
+};
+
+/*Methods relating to parameters: */
+char       *OptionsFromAnalysis(Parameters *parameters,int analysis_type);
+void        ToolkitsOptionsFromAnalysis(Parameters* parameters,int analysis_type);
+
+
+#endif //ifndef _PARAMETERS_H_
Index: /issm/trunk-jpl/src/c/classes/Params/StringArrayParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/StringArrayParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/StringArrayParam.cpp	(revision 15012)
@@ -0,0 +1,168 @@
+/*!\file StringArrayParam.c
+ * \brief: implementation of the StringArrayParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*StringArrayParam constructors and destructor*/
+/*FUNCTION StringArrayParam::StringArrayParam(){{{*/
+StringArrayParam::StringArrayParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::StringArrayParam(int enum_type,char** in_values,int in_numstrings){{{*/
+StringArrayParam::StringArrayParam(int in_enum_type,char** in_values, int in_numstrings){
+
+	int i;
+	int size;
+
+	enum_type=in_enum_type;
+	numstrings=in_numstrings;
+
+	if(numstrings){
+		value=xNew<char*>(numstrings);
+		for(i=0;i<numstrings;i++){
+			char* string=NULL;
+			size=strlen(in_values[i])+1;
+			string=xNew<char>(size);
+			xMemCpy<char>(string,in_values[i],size);
+			value[i]=string;
+		}
+	}
+	else value=NULL;
+
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::~StringArrayParam(){{{*/
+StringArrayParam::~StringArrayParam(){
+
+	int i;
+
+	char* string=NULL;
+	for(i=0;i<this->numstrings;i++){
+		string=value[i];
+		xDelete<char>(string);
+	}
+	xDelete<char*>(value);
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION StringArrayParam::Echo {{{*/
+void StringArrayParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::DeepEcho{{{*/
+void StringArrayParam::DeepEcho(void){
+
+	int i;
+	char* string=NULL;
+
+	_printLine_("StringArrayParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	for(i=0;i<this->numstrings;i++){
+		string=this->value[i];
+		_printLine_("   " << i << ": " << string);
+	}
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::Id{{{*/
+int    StringArrayParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION StringArrayParam::ObjectEnum{{{*/
+int StringArrayParam::ObjectEnum(void){
+
+	return StringArrayParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::copy{{{*/
+Object* StringArrayParam::copy() {
+
+	return new StringArrayParam(this->enum_type,this->value,this->numstrings);
+
+}
+/*}}}*/
+
+/*StringArrayParam virtual functions definitions: */
+/*FUNCTION StringArrayParam::GetParameterValue{{{*/
+void  StringArrayParam::GetParameterValue(char*** pstringarray,int* pM){
+
+	int   i;
+	char** outstrings=NULL;
+	int   M;
+	char* string=NULL;
+	char* string2=NULL;
+	int   stringsize;
+
+	M=this->numstrings;
+	if(this->numstrings){
+		outstrings=xNew<char*>(this->numstrings);
+
+		for(i=0;i<this->numstrings;i++){
+			string=this->value[i];
+			stringsize=strlen(string)+1;
+
+			string2=xNew<char>(stringsize);
+			xMemCpy<char>(string2,string,stringsize);
+
+			outstrings[i]=string2;
+		}
+	}
+	else outstrings=NULL;
+
+	/*Assign output pointers:*/
+	*pM=M;
+	*pstringarray=outstrings;
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::GetParameterName{{{*/
+void StringArrayParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::SetValue{{{*/
+void  StringArrayParam::SetValue(char** stringarray,int M){
+
+	int   i;
+	char *string     = NULL;
+	char *string2    = NULL;
+	int   stringsize;
+
+	/*first, avoid leak: */
+	for(i=0;i<this->numstrings;i++){
+		string=this->value[i];
+		xDelete<char>(string);
+	}
+	xDelete<char*>(this->value);
+
+	/*copy: */
+	this->numstrings=M;
+	this->value=xNew<char*>(this->numstrings);
+	for(i=0;i<this->numstrings;i++){
+		string=stringarray[i];
+		stringsize=strlen(string)+1;
+
+		string2=xNew<char>(stringsize);
+		xMemCpy<char>(string2,string,stringsize);
+
+		this->value[i]=string2;
+	}
+}
+/*}}}*/
+/*FUNCTION StringArrayParam::UnitConversion{{{*/
+void  StringArrayParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/StringArrayParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/StringArrayParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/StringArrayParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file StringArrayParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _STRINGARRAYPARAM_H_
+#define _STRINGARRAYPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class StringArrayParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int      enum_type;
+		char**   value;
+		int      numstrings;
+
+	public:
+		/*StringArrayParam constructors, destructors: {{{*/
+		StringArrayParam();
+		StringArrayParam(int enum_type,char** values, int numstrings);
+		~StringArrayParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM);
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Vec param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M);
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+		/*}}}*/
+};
+#endif  /* _STRINGARRAYPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/StringParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/StringParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/StringParam.cpp	(revision 15012)
@@ -0,0 +1,109 @@
+/*!\file StringParam.c
+ * \brief: implementation of the StringParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*StringParam constructors and destructor*/
+/*FUNCTION StringParam::StringParam(){{{*/
+StringParam::StringParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION StringParam::StringParam(int enum_type,IssmString value){{{*/
+StringParam::StringParam(int in_enum_type,char* in_value){
+
+	enum_type=in_enum_type;
+	value=xNew<char>(strlen(in_value)+1);
+	xMemCpy<char>(value,in_value,(strlen(in_value)+1));
+
+}
+/*}}}*/
+/*FUNCTION StringParam::~StringParam(){{{*/
+StringParam::~StringParam(){
+	xDelete<char>(value);
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION StringParam::Echo {{{*/
+void StringParam::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION StringParam::DeepEcho{{{*/
+void StringParam::DeepEcho(void){
+	_printLine_("StringParam:");
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+}
+/*}}}*/
+/*FUNCTION StringParam::Id{{{*/
+int    StringParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION StringParam::ObjectEnum{{{*/
+int StringParam::ObjectEnum(void){
+
+	return StringParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION StringParam::copy{{{*/
+Object* StringParam::copy() {
+
+	return new StringParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*StringParam virtual functions definitions: */
+/*FUNCTION StringParam::GetParameterValue{{{*/
+void  StringParam::GetParameterValue(char** pstring){
+
+	char* outstring=NULL;
+	int   stringsize;
+
+	stringsize=strlen(this->value)+1;
+
+	outstring=xNew<char>(stringsize);
+	xMemCpy<char>(outstring,this->value,stringsize);
+
+	*pstring=outstring;
+
+}
+/*}}}*/
+/*FUNCTION StringParam::GetParameterName{{{*/
+void StringParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION StringParam::SetValue{{{*/
+void  StringParam::SetValue(char* string){
+
+	int   stringsize;
+
+	/*avoid leak: */
+	xDelete<char>(this->value);
+
+	/*copy: */
+	stringsize=strlen(string)+1;
+	this->value=xNew<char>(stringsize);
+	xMemCpy<char>(this->value,string,stringsize);
+
+}
+/*}}}*/
+/*FUNCTION StringParam::UnitConversion{{{*/
+void  StringParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/StringParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/StringParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/StringParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file StringParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _STRINGPARAM_H_
+#define _STRINGPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class StringParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int   enum_type;
+		char *value;
+
+	public:
+		/*StringParam constructors, destructors: {{{*/
+		StringParam();
+		StringParam(int enum_type,char* value);
+		~StringParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring);
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Bool param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string);
+		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _STRINGPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/TransientParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/TransientParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/TransientParam.cpp	(revision 15012)
@@ -0,0 +1,138 @@
+/*!\file TransientParam.c
+ * \brief: implementation of the TransientParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*TransientParam constructors and destructor*/
+/*FUNCTION TransientParam::TransientParam(){{{*/
+TransientParam::TransientParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION TransientParam::TransientParam(int enum_type,IssmDoubleMat value){{{*/
+TransientParam::TransientParam(int in_enum_type,IssmDouble* in_values,IssmDouble* in_time,int in_N){
+
+	_assert_(in_values && in_time);
+
+	enum_type=in_enum_type;
+	N=in_N;
+
+	values=xNew<IssmDouble>(N);
+	xMemCpy<IssmDouble>(values,in_values,N);
+
+	timesteps=xNew<IssmDouble>(N);
+	xMemCpy<IssmDouble>(timesteps,in_time,N);
+}
+/*}}}*/
+/*FUNCTION TransientParam::~TransientParam(){{{*/
+TransientParam::~TransientParam(){
+	xDelete<IssmDouble>(values);
+	xDelete<IssmDouble>(timesteps);
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION TransientParam::Echo {{{*/
+void TransientParam::Echo(void){
+
+	_printLine_("TransientParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   size: " << this->N);
+
+}
+/*}}}*/
+/*FUNCTION TransientParam::DeepEcho{{{*/
+void TransientParam::DeepEcho(void){
+
+	_printLine_("TransientParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   size: " << this->N);
+	for(int i=0;i<this->N;i++){
+		_printLine_(   "time: " << this->timesteps[i] << " value: " << this->values[i]);
+	}
+}
+/*}}}*/
+/*FUNCTION TransientParam::Id{{{*/
+int    TransientParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION TransientParam::ObjectEnum{{{*/
+int TransientParam::ObjectEnum(void){
+
+	return TransientParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION TransientParam::copy{{{*/
+Object* TransientParam::copy() {
+
+	return new TransientParam(this->enum_type,this->values,this->timesteps,this->N);
+
+}
+/*}}}*/
+
+/*TransientParam virtual functions definitions: */
+/*FUNCTION TransientParam::GetParameterValue(IssmDouble* pdouble,IssmDouble time){{{*/
+void  TransientParam::GetParameterValue(IssmDouble* pdouble,IssmDouble time){
+
+	IssmDouble output;
+	bool   found;
+
+	/*Ok, we have the time, go through the timesteps, and figure out which interval we 
+	 *fall within. Then interpolate the values on this interval: */
+	if(time<this->timesteps[0]){
+		/*get values for the first time: */
+		output=this->values[0];
+		found=true;
+	}
+	else if(time>this->timesteps[this->N-1]){
+		/*get values for the last time: */
+		output=this->values[this->N-1];
+		found=true;
+	}
+	else{
+		/*Find which interval we fall within: */
+		for(int i=0;i<this->N;i++){
+			if(time==this->timesteps[i]){
+				/*We are right on one step time: */
+				output=this->values[i];
+				found=true;
+				break; //we are done with the time interpolation.
+			}
+			else{
+				if(this->timesteps[i]<time && time<this->timesteps[i+1]){
+					/*ok, we have the interval ]i:i+1[. Interpolate linearly for now: */
+					IssmDouble deltat=this->timesteps[i+1]-this->timesteps[i];
+					IssmDouble alpha=(time-this->timesteps[i])/deltat;
+					output=(1.0-alpha)*this->values[i] + alpha*this->values[i+1];
+					found=true;
+					break;
+				}
+				else continue; //keep looking on the next interval
+			}
+		}
+	}
+	if(!found)_error_("did not find time interval on which to interpolate values");
+	*pdouble=output;
+}
+/*}}}*/
+/*FUNCTION TransientParam::GetParameterName{{{*/
+void TransientParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION TransientParam::UnitConversion{{{*/
+void  TransientParam::UnitConversion(int direction_enum){
+	::UnitConversion(this->values,this->N,direction_enum,this->enum_type);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/TransientParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/TransientParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/TransientParam.h	(revision 15012)
@@ -0,0 +1,78 @@
+/*! \file TransientParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _TRANSIENTPARAM_H_
+#define _TRANSIENTPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class TransientParam: public Param{
+
+	protected: 
+		int         enum_type;
+		int         N;
+		IssmDouble *values;
+		IssmDouble *timesteps;
+
+	public:
+		/*TransientParam constructors, destructors: {{{*/
+		TransientParam();
+		TransientParam(int in_enum_type,IssmDouble* in_values,IssmDouble* in_time,int in_N);
+		~TransientParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time);
+		void  GetParameterValue(char** pstring){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector<IssmDouble>** pvec){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a int vec array");}
+		void  SetValue(int* intarray,int M,int N){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a int mat array");};
+		void  SetValue(Vector<IssmDouble>* vec){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _TRANSIENTPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Params/VectorParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/VectorParam.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/VectorParam.cpp	(revision 15012)
@@ -0,0 +1,109 @@
+/*!\file VectorParam.c
+ * \brief: implementation of the VectorParam object
+ */
+
+/*header files: */
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "../classes.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+/*VectorParam constructors and destructor*/
+/*FUNCTION VectorParam::VectorParam(){{{*/
+VectorParam::VectorParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION VectorParam::VectorParam(int enum_type,IssmVector value){{{*/
+VectorParam::VectorParam(int in_enum_type,Vector<IssmDouble>* in_value){
+
+	enum_type=in_enum_type;
+
+	value=NULL;
+
+	if(in_value){
+		value=in_value->Duplicate();
+		in_value->Copy(value);
+	}
+}
+/*}}}*/
+/*FUNCTION VectorParam::~VectorParam(){{{*/
+VectorParam::~VectorParam(){
+	delete value;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION VectorParam::Echo {{{*/
+void VectorParam::Echo(void){
+
+	_printLine_("VectorParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+
+}
+/*}}}*/
+/*FUNCTION VectorParam::DeepEcho{{{*/
+void VectorParam::DeepEcho(void){
+
+	_printLine_("VectorParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	value->Echo();
+}
+/*}}}*/
+/*FUNCTION VectorParam::Id{{{*/
+int    VectorParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION VectorParam::ObjectEnum{{{*/
+int VectorParam::ObjectEnum(void){
+
+	return VectorParamEnum;
+
+}
+/*}}}*/
+/*FUNCTION VectorParam::copy{{{*/
+Object* VectorParam::copy() {
+
+	return new VectorParam(this->enum_type,this->value);
+
+}
+/*}}}*/
+
+/*VectorParam virtual functions definitions: */
+/*FUNCTION VectorParam::GetParameterValue{{{*/
+void  VectorParam::GetParameterValue(Vector<IssmDouble>** poutput){
+	Vector<IssmDouble>*  output=NULL;
+
+	if(value){
+		output=value->Duplicate();
+		value->Copy(output);
+	}
+	*poutput=output;
+}
+/*}}}*/
+/*FUNCTION VectorParam::GetParameterName{{{*/
+void VectorParam::GetParameterName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION VectorParam::SetValue{{{*/
+void  VectorParam::SetValue(Vector<IssmDouble>* vector){
+
+	/*avoid leak: */
+	delete value;
+
+	/*copy: */
+	value=vector->Duplicate();
+	vector->Copy(value);
+}
+/*}}}*/
+/*FUNCTION VectorParam::UnitConversion{{{*/
+void  VectorParam::UnitConversion(int direction_enum){
+	/*do nothing, no unit conversion*/
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Params/VectorParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Params/VectorParam.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Params/VectorParam.h	(revision 15012)
@@ -0,0 +1,77 @@
+/*! \file VectorParam.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+#ifndef _VECTORPARAM_H_
+#define _VECTORPARAM_H_
+
+/*Headers:*/
+/*{{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Param.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class VectorParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		Vector<IssmDouble>* value;
+
+	public:
+		/*VectorParam constructors, destructors: {{{*/
+		VectorParam();
+		VectorParam(int enum_type,Vector<IssmDouble>* value);
+		~VectorParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Matrix<IssmDouble>** pmat){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(Vector<IssmDouble>** poutput);
+		void  GetParameterValue(FILE** pfid){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a FILE");}
+		void  GetParameterValue(DataSet** pdataset){_error_("Param "<< EnumToStringx(enum_type) << " cannot return a DataSet");}
+
+		void  SetValue(bool boolean){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a boolean");}
+		void  SetValue(int integer){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a scalar");}
+		void  SetValue(char* string){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a int array");}
+		void  SetValue(Vector<IssmDouble>* vec);
+		void  SetValue(Matrix<IssmDouble>* mat){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _VECTORPARAM_H */
Index: /issm/trunk-jpl/src/c/classes/Profiler.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Profiler.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Profiler.cpp	(revision 15012)
@@ -0,0 +1,177 @@
+/*!\file Profiler.c
+ * \brief: implementation of the Profiler object
+ */
+
+/*Include files: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./Profiler.h"
+#include "./Params/Parameters.h"
+#include "./Params/DoubleParam.h"
+#include "../toolkits/toolkits.h"
+/*}}}*/
+
+/*Profiler constructors and destructors:*/
+/*FUNCTION Profiler::Profiler() default constructor {{{*/
+Profiler::Profiler(){
+		 this->time=new Parameters();
+		 this->flops=new Parameters();
+		 this->memory=new Parameters();
+}
+/*}}}*/
+/*FUNCTION Profiler::~Profiler(){{{*/
+Profiler::~Profiler(){
+	delete time;
+	delete flops;
+	delete memory;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Profiler::Echo{{{*/
+void Profiler::Echo(void){
+
+	_printLine_("Profiler:");
+	_printLine_("   time tags: ");
+	this->time->Echo();
+
+}
+/*}}}*/
+/*FUNCTION Profiler::DeepEcho{{{*/
+void Profiler::DeepEcho(void){
+
+	_printLine_("Profiler:");
+	_printLine_("   time tags: ");
+	this->time->DeepEcho();
+
+}
+/*}}}*/
+/*FUNCTION Profiler::Id{{{*/
+int    Profiler::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION Profiler::ObjectEnum{{{*/
+int Profiler::ObjectEnum(void){
+
+	return ProfilerEnum;
+
+}
+/*}}}*/
+
+/*Profiler routines:*/
+/*FUNCTION Profiler::Tag {{{*/
+void  Profiler::Tag(int tagenum,bool dontmpisync){
+
+	IssmDouble t;
+	IssmDouble f;
+	IssmDouble m;
+
+	/*If mpisync requested, make sure all the cpus are at the same point 
+	 *in the execution: */
+	if(!dontmpisync){
+		#ifdef _HAVE_MPI_
+		MPI_Barrier(IssmComm::GetComm()); 
+		#endif
+	}
+
+	/*Capture time: */
+	#ifdef _HAVE_MPI_
+	t=MPI_Wtime();
+	#else
+	t=(IssmPDouble)clock();
+	#endif
+
+	/*Capture flops: */
+	#ifdef _HAVE_PETSC_
+		PetscGetFlops(&f);
+		PetscMemoryGetCurrentUsage(&m);
+	#else
+		/*do nothing for now:*/
+	#endif
+
+	/*Plug into this->time: */
+	this->time->AddObject(new DoubleParam(tagenum,t));
+	this->flops->AddObject(new DoubleParam(tagenum,f));
+	this->memory->AddObject(new DoubleParam(tagenum,m));
+
+}
+/*}}}*/
+/*FUNCTION Profiler::DeltaTime {{{*/
+IssmDouble  Profiler::DeltaTime(int inittag, int finaltag){
+
+	IssmDouble init, final;
+	this->time->FindParam(&init,inittag);
+	this->time->FindParam(&final,finaltag);
+
+	#ifdef _HAVE_MPI_
+	return final-init;
+	#else
+	return (final-init)/CLOCKS_PER_SEC;
+	#endif
+}
+/*}}}*/
+/*FUNCTION Profiler::DeltaFlops {{{*/
+IssmDouble  Profiler::DeltaFlops(int inittag, int finaltag){
+
+	IssmDouble init, final;
+	this->flops->FindParam(&init,inittag);
+	this->flops->FindParam(&final,finaltag);
+
+	return final-init;
+}
+/*}}}*/
+/*FUNCTION Profiler::DeltaTimeModHour {{{*/
+int Profiler::DeltaTimeModHour(int inittag, int finishtag){
+
+	IssmDouble init, finish;
+	this->time->FindParam(&init,inittag);
+	this->time->FindParam(&finish,finishtag);
+
+	#ifdef _HAVE_MPI_
+	return int((reCast<int,IssmDouble>(finish-init))/3600);
+	#else
+	return int((reCast<int,IssmDouble>(finish-init))/CLOCKS_PER_SEC/3600);
+	#endif
+
+}
+/*}}}*/
+/*FUNCTION Profiler::DeltaTimeModMin {{{*/
+int Profiler::DeltaTimeModMin(int inittag, int finishtag){
+
+	IssmDouble init, finish;
+	this->time->FindParam(&init,inittag);
+	this->time->FindParam(&finish,finishtag);
+
+	#ifdef _HAVE_MPI_
+	return int(int(reCast<int,IssmDouble>(finish-init))%3600/60);
+	#else
+	return int(int(reCast<int,IssmDouble>(finish-init))/CLOCKS_PER_SEC%3600/60);
+	#endif
+}
+/*}}}*/
+/*FUNCTION Profiler::DeltaTimeModSec {{{*/
+int Profiler::DeltaTimeModSec(int inittag, int finishtag){
+
+	IssmDouble init, finish;
+	this->time->FindParam(&init,inittag);
+	this->time->FindParam(&finish,finishtag);
+
+	#ifdef _HAVE_MPI_
+	return int(reCast<int,IssmDouble>(finish-init))%60;
+	#else
+	return int(reCast<int,IssmDouble>(finish-init))/CLOCKS_PER_SEC%60;
+	#endif
+}
+/*}}}*/
+/*FUNCTION Profiler::Memory {{{*/
+IssmDouble  Profiler::Memory(int tag){
+
+	IssmDouble m;
+	this->memory->FindParam(&m,tag);
+
+	return m;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Profiler.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Profiler.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Profiler.h	(revision 15012)
@@ -0,0 +1,57 @@
+/*!\file Profiler.h
+ * \brief: header file for node object
+ */
+
+#ifndef _PROFILER_H_
+#define _PROFILER_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Object.h"
+#include "../shared/shared.h"
+/*}}}*/
+
+class DataSet;
+class Parameters;
+
+enum ProfilerEnums {
+	Start,
+	StartInit,
+	FinishInit,
+	StartCore,
+	FinishCore,
+	StartAdCore,
+	FinishAdCore,
+	Finish
+};
+
+class Profiler: public Object{
+
+	public: 
+		Parameters*  time;
+		Parameters*  flops;
+		Parameters*  memory;
+
+		/*Profiler constructors, destructors {{{*/
+		Profiler();
+		~Profiler();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void    Echo();
+		void    DeepEcho();
+		int     Id();
+		int     ObjectEnum();
+		Object *copy()        {_error_("Not implemented yet"); };
+		/*}}}*/
+		/*Profiler routines {{{*/
+		void    Tag(int tagenum,bool dontmpisync=false);
+		IssmDouble  Memory(int tag);
+		IssmDouble  DeltaTime(int inittag, int finaltag);
+		IssmDouble  DeltaFlops(int inittag, int finaltag);
+		int     DeltaTimeModHour(int inittag, int finaltag);
+		int     DeltaTimeModMin(int inittag, int finaltag);
+		int     DeltaTimeModSec(int inittag, int finaltag);
+		/*}}}*/
+};
+
+#endif  /* _PROFILER_H_ */
Index: /issm/trunk-jpl/src/c/classes/Segment.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Segment.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Segment.h	(revision 15012)
@@ -0,0 +1,84 @@
+/*!\file Segment.h
+ * \brief: header file for node object
+ */
+
+#ifndef _SEGMENT_H_
+#define _SEGMENT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Object.h"
+#include "../shared/Numerics/constants.h"
+/*}}}*/
+
+template <class doubletype> 
+class Segment: public Object{
+
+	public:
+		int        eid;
+		doubletype x1;
+		doubletype y1;
+		doubletype x2;
+		doubletype y2;
+
+		/*Segment constructors, destructors :*/
+		/*FUNCTION Segment() default constructor {{{*/
+		Segment(){
+			this->eid = UNDEF;
+			this->x1  = UNDEF;
+			this->y1  = UNDEF;
+			this->x2  = UNDEF;
+			this->y2  = UNDEF;
+		}
+		/*}}}*/
+		/*FUNCTION Segment(int eid, doubletype x1,doubletype y1,doubletype x2, doubletype y2){{{*/
+		Segment(int segment_eid, doubletype segment_x1,doubletype segment_y1,doubletype segment_x2, doubletype segment_y2){
+
+			this->eid = segment_eid;
+			this->x1  = segment_x1;
+			this->y1  = segment_y1;
+			this->x2  = segment_x2;
+			this->y2  = segment_y2;
+
+		}
+		/*}}}*/
+		/*FUNCTION ~Segment(){{{*/
+		~Segment(){
+		}
+		/*}}}*/
+
+		/*Object virtual functions definitions:*/
+		/*FUNCTION Echo{{{*/
+		void Echo(void){
+
+			_printLine_("Segment:");
+			_printLine_("   eid: " << eid);
+			_printLine_("   node 1: " << this->x1 << "|" << this->y1);
+			_printLine_("   node 2: " << this->x2 << "|" << this->y2);
+
+		}
+		/*}}}*/
+		/*FUNCTION DeepEcho{{{*/
+		void DeepEcho(void){
+			this->Echo();
+		}
+		/*}}}*/
+		/*FUNCTION Id{{{*/
+		int    Id(void){ return eid; }
+		/*}}}*/
+		/*FUNCTION ObjectEnum{{{*/
+		int ObjectEnum(void){
+
+			return SegmentEnum;
+
+		}
+		/*}}}*/
+		/*FUNCTION copy {{{*/
+		Object* copy() {
+			return new Segment(this->eid,this->x1,this->y1,this->x2,this->y2);
+		}
+		/*}}}*/
+
+};
+
+#endif  /* _SEGMENT_H_ */
Index: /issm/trunk-jpl/src/c/classes/Vertex.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Vertex.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Vertex.cpp	(revision 15012)
@@ -0,0 +1,251 @@
+/*!\file Vertex.c
+ * \brief: implementation of the Vertex object
+ */
+
+/*Include files: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <string.h>
+#include "classes.h"
+#include "shared/shared.h"
+/*}}}*/
+
+/*Vertex constructors and destructor:*/
+/*FUNCTION Vertex::Vertex() {{{*/
+Vertex::Vertex(){
+	return;
+}
+/*}}}*/
+/*FUNCTION Vertex::Vertex(int vertex_id, IssmDouble vertex_x, IssmDouble vertex_y, IssmDouble vertex_z, IssmDouble vertex_sigma){{{*/
+Vertex::Vertex(int vertex_id, int vertex_sid,IssmDouble vertex_x, IssmDouble vertex_y, IssmDouble vertex_z, IssmDouble vertex_sigma,int vertex_connectivity){
+	this->Init(vertex_id, vertex_sid,vertex_x, vertex_y, vertex_z, vertex_sigma,vertex_connectivity);
+}
+/*}}}*/
+/*FUNCTION Vertex::Vertex(int vertex_id, int vertex_sid,int i, IoModel* iomodel) {{{*/
+Vertex::Vertex(int vertex_id, int vertex_sid,int i, IoModel* iomodel){
+
+	_assert_(iomodel->Data(MeshXEnum) && iomodel->Data(MeshYEnum) && iomodel->Data(MeshZEnum));
+	_assert_(iomodel->Data(BedEnum) && iomodel->Data(ThicknessEnum) && iomodel->numbernodetoelementconnectivity);
+
+	this->Init(vertex_id, vertex_sid, iomodel->Data(MeshXEnum)[i],iomodel->Data(MeshYEnum)[i],iomodel->Data(MeshZEnum)[i],(iomodel->Data(MeshZEnum)[i]-iomodel->Data(BedEnum)[i])/(iomodel->Data(ThicknessEnum)[i]),iomodel->numbernodetoelementconnectivity[i]);
+
+}
+/*}}}*/
+/*FUNCTION Vertex::~Vertex() {{{*/
+Vertex::~Vertex(){
+	return;
+}
+/*}}}*/
+/*FUNCTION Vertex::Init{{{*/
+void Vertex::Init(int vertex_id, int vertex_sid,IssmDouble vertex_x, IssmDouble vertex_y, IssmDouble vertex_z, IssmDouble vertex_sigma,int vertex_connectivity){
+
+	/*all the initialization has been done by the initializer, just fill in the id: */
+	this->id=vertex_id;
+	this->sid=vertex_sid;
+	this->pid=UNDEF;
+	this->x=vertex_x;
+	this->y=vertex_y;
+	this->z=vertex_z;
+	this->sigma=vertex_sigma;
+	this->connectivity=vertex_connectivity;
+
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Vertex::Echo{{{*/
+void Vertex::Echo(void){
+
+	_printLine_("Vertex:");
+	_printLine_("   id: " << id);
+	_printLine_("   sid: " << sid);
+	_printLine_("   pid: " << pid);
+	_printLine_("   x: " << x);
+	_printLine_("   y: " << y);
+	_printLine_("   z: " << z);
+	_printLine_("   sigma: " << sigma);
+	_printLine_("   connectivity: " << connectivity);
+	_printLine_("   clone: " << clone);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Vertex::DeepEcho{{{*/
+void Vertex::DeepEcho(void){
+	this->Echo();
+}
+/*}}}*/
+/*FUNCTION Vertex::Id{{{*/
+int    Vertex::Id(void){ return id; }
+/*}}}*/
+/*FUNCTION Vertex::ObjectEnum{{{*/
+int Vertex::ObjectEnum(void){
+
+	return VertexEnum;
+
+}
+/*}}}*/
+/*FUNCTION Vertex::copy {{{*/
+Object* Vertex::copy() {
+
+	return new Vertex(*this); 
+
+}
+/*}}}*/
+
+/*Vertex management: */
+/*FUNCTION Vertex::Connectivity{{{*/
+int    Vertex::Connectivity(void){return connectivity;}
+/*}}}*/
+/*FUNCTION Vertex::GetX {{{*/
+IssmDouble Vertex::GetX(){
+	return this->x;
+}
+/*}}}*/
+/*FUNCTION Vertex::GetY {{{*/
+IssmDouble Vertex::GetY(){
+	return this->y;
+}
+/*}}}*/
+/*FUNCTION Vertex::GetZ {{{*/
+IssmDouble Vertex::GetZ(){
+	return this->z;
+}
+/*}}}*/
+/*FUNCTION Vertex::Sid{{{*/
+int    Vertex::Sid(void){ return sid; }
+/*}}}*/
+/*FUNCTION Vertex::UpdateVertexPosition {{{*/
+void  Vertex::UpdatePosition(Vector<IssmDouble>* vz,Parameters* parameters,IssmDouble* thickness,IssmDouble* bed){
+
+	IssmDouble oldz,newz;
+	IssmDouble dt,velz;
+
+	/*Get time stepping*/
+	parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+
+	/*sigma remains constant. z=bed+sigma*thickness*/
+	oldz = this->z;
+	newz = bed[this->pid]+sigma*thickness[this->pid];
+	velz = (newz-oldz)/dt;
+	this->z = newz;
+
+	/*put vz in vector*/
+	vz->SetValue(this->pid,velz,INS_VAL);
+}
+/*}}}*/
+/*FUNCTION Vertex::DistributePids{{{*/
+void  Vertex::DistributePids(int* ppidcount){
+
+	/*retrieve current pid*/
+	int pidcount=*ppidcount;
+
+	/*This vertex is a clone! Don't distribute pids, it will get them from another cpu!*/
+	if(this->clone) return;
+
+	/*This vertex should distribute its pid*/
+	this->pid=pidcount;
+	pidcount++;
+
+	/*Assign output pointers: */
+	*ppidcount=pidcount;
+}
+/*}}}*/
+/*FUNCTION Vertex::OffsetPids{{{*/
+void  Vertex::OffsetPids(int pidcount){
+
+	/*This vertex is a clone, don't offset the pids*/
+	if(this->clone) return;
+
+	/*This vertex should offset his pid, go ahead: */
+	this->pid+=pidcount;
+}
+/*}}}*/
+/*FUNCTION Vertex::ShowTruePids{{{*/
+void  Vertex::ShowTruePids(int* truepids){
+
+	/*Are we a clone? : */
+	if(this->clone)return;
+
+	/*Ok, we are not a clone, just plug our pid into truepids: */
+	truepids[this->sid]=this->pid;
+}
+/*}}}*/
+/*FUNCTION Vertex::UpdateClonePids{{{*/
+void  Vertex::UpdateClonePids(int* alltruepids){
+
+	/*If we are not a clone, don't update, we already have pids: */
+	if(!this->clone)return;
+
+	/*Ok, we are a clone node, but we did not create the pid for this vertex 
+	 * Therefore, our pid is garbage right now. Go pick it up in the alltruepids: */
+	this->pid=alltruepids[this->sid];
+}
+/*}}}*/
+/*FUNCTION Vertex::SetClone {{{*/
+void  Vertex::SetClone(int* minranks){
+
+	int my_rank;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	if (minranks[this->sid]==my_rank){
+		this->clone=false;
+	}
+	else{
+		/*!there is a cpu with lower rank that has the same vertex, 
+		therefore, I am a clone*/
+		this->clone=true;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Vertex::ToXYZ {{{*/
+void  Vertex::ToXYZ(Matrix<IssmDouble>* matrix){
+
+	IssmDouble xyz[3];
+	int        indices[3];
+
+	if (this->clone==true) return;
+
+	xyz[0]=x;
+	xyz[1]=y; 
+	xyz[2]=z;
+	indices[0]=0;
+	indices[1]=1; 
+	indices[2]=2;
+
+	matrix->SetValues(1,&sid,3,&indices[0],&xyz[0],INS_VAL);
+}
+/*}}}*/
+/*FUNCTION Vertex::VertexCoordinates {{{*/
+void  Vertex::VertexCoordinates(Vector<IssmDouble>* vx,Vector<IssmDouble>* vy,Vector<IssmDouble>* vz){
+
+	if (this->clone==true) return;
+
+	vx->SetValue(this->sid,this->x,INS_VAL);
+	vy->SetValue(this->sid,this->y,INS_VAL);
+	vz->SetValue(this->sid,this->z,INS_VAL);
+
+	return;
+}
+/*}}}*/
+
+/*Methods relating to Vertex, but not internal methods: */
+void GetVerticesCoordinates(IssmDouble* xyz,Vertex** vertices, int numvertices){ /*{{{*/
+
+	_assert_(vertices);
+	_assert_(xyz);
+
+	for(int i=0;i<numvertices;i++) {
+		xyz[i*3+0]=vertices[i]->GetX();
+		xyz[i*3+1]=vertices[i]->GetY();
+		xyz[i*3+2]=vertices[i]->GetZ();
+	}
+}/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Vertex.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Vertex.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Vertex.h	(revision 15012)
@@ -0,0 +1,65 @@
+/*! \file Vertex.h 
+ *  \brief: header file for vertex object
+ */
+
+#ifndef _VERTEX_H_
+#define _VERTEX_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./classes.h"
+#include "../shared/Exceptions/exceptions.h"
+#include "../toolkits/toolkits.h"
+template <class doubletype> class Vector;
+template <class doubletype> class Matrix;
+class Parameters;
+class IoModel;
+/*}}}*/
+
+class Vertex: public Object{
+
+	public: 
+		bool       clone;
+		int        id;           // random index
+		int        sid;          // "serial" id (rank of this vertex if the dataset was on 1 cpu)
+		int        pid;          // "parallel" id
+		IssmDouble x;
+		IssmDouble y;
+		IssmDouble z;
+		IssmDouble sigma;        //sigma coordinate: (z-bed)/thickness
+		int        connectivity; //number of vertices connected to this vertex
+
+		/*Vertex constructors, destructors {{{*/
+		Vertex();
+		Vertex(int id, int sid,IssmDouble x, IssmDouble y, IssmDouble z, IssmDouble sigma, int connectivity); 
+		void Init(int id, int sid, IssmDouble x, IssmDouble y, IssmDouble z, IssmDouble sigma,int connectivity);
+		Vertex(int id, int sid, int i, IoModel* iomodel);
+		~Vertex();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Vertex management:*/ 
+		int        Sid(void); 
+		int        Connectivity(void); 
+		IssmDouble GetX(void); 
+		IssmDouble GetY(void); 
+		IssmDouble GetZ(void); 
+		void       UpdatePosition(Vector<IssmDouble>* vz,Parameters* parameters,IssmDouble* thickness,IssmDouble* bed);
+		void       DistributePids(int* ppidcount);
+		void       OffsetPids(int pidcount);
+		void       ShowTruePids(int* borderpids);
+		void       UpdateClonePids(int* allborderpids);
+		void       SetClone(int* minranks);
+		void       ToXYZ(Matrix<IssmDouble>* matrix);
+		void       VertexCoordinates(Vector<IssmDouble>* vx,Vector<IssmDouble>* vy,Vector<IssmDouble>* vz);
+};
+
+/*Methods relating to Vertex object: */
+void GetVerticesCoordinates(IssmDouble* xyz,Vertex** vertices, int numvertices);
+
+#endif  /* _VERTEX_H */
Index: /issm/trunk-jpl/src/c/classes/Vertices.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/Vertices.cpp	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Vertices.cpp	(revision 15012)
@@ -0,0 +1,242 @@
+/*
+ * \file Vertices.cpp
+ * \brief: Implementation of Vertices class, derived from DataSet class.
+ */
+
+/*Headers: {{{*/
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <vector>
+#include <functional>
+#include <algorithm>
+#include <iostream>
+
+#include "./Vertices.h"
+#include "../shared/shared.h"
+#include "./Vertex.h"
+
+using namespace std;
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION Vertices::Vertices(){{{*/
+Vertices::Vertices(){
+	enum_type=VerticesEnum;
+	return;
+}
+/*}}}*/
+/*FUNCTION Vertices::~Vertices(){{{*/
+Vertices::~Vertices(){
+	return;
+}
+/*}}}*/
+
+/*Numerics management*/
+/*FUNCTION Vertices::DistributePids{{{*/
+void  Vertices::DistributePids(int numberofobjects){
+
+	int num_procs;
+	int my_rank;
+
+	int  i;
+	int  pidcount    = 0;
+	int *allpidcount = NULL;
+	int *truepids    = NULL;
+	int *alltruepids = NULL;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+	num_procs=IssmComm::GetSize();
+
+	/*Go through objects, and distribute pids locally, from 0 to numberofpidsperobject*/
+	for (i=0;i<this->Size();i++){
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		vertex->DistributePids(&pidcount);
+	}
+
+	/* Now every object has distributed pids, but locally, and with a pid count starting from 
+	 * 0. This means the pids between all the cpus are not unique. We now offset the pids of each
+	 * cpus by the total last pids of the previus cpu, starting from 0.
+	 * First: get number of pids for each cpu*/
+	allpidcount=xNew<int>(num_procs);
+	#ifdef _HAVE_MPI_
+	MPI_Gather(&pidcount,1,MPI_INT,allpidcount,1,MPI_INT,0,IssmComm::GetComm());
+	MPI_Bcast(allpidcount,num_procs,MPI_INT,0,IssmComm::GetComm());
+	#else
+	allpidcount[0]=pidcount;
+	#endif
+
+	/* Every cpu should start its own pid count at the end of the pidcount from cpu-1*/
+	pidcount=0;
+	if(my_rank!=0){
+		for(i=0;i<my_rank;i++){
+			pidcount+=allpidcount[i];
+		}
+	}
+	for (i=0;i<this->Size();i++){
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		vertex->OffsetPids(pidcount);
+	}
+
+	/* Finally, remember that cpus may have skipped some objects, because they were clones. For every 
+	 * object that is not a clone, tell them to show their pids, so that later on, they can get picked 
+	 * up by their clones: */
+	truepids   =xNewZeroInit<int>(numberofobjects);
+	alltruepids=xNewZeroInit<int>(numberofobjects);
+	for (i=0;i<this->Size();i++){
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		vertex->ShowTruePids(truepids);
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce((void*)truepids,(void*)alltruepids,numberofobjects,MPI_INT,MPI_MAX,IssmComm::GetComm());
+	#else
+	for(i=0;i<numberofobjects;i++)alltruepids[i]=truepids[i];
+	#endif
+
+	/* Now every cpu knows the true pids of everyone else that is not a clone*/
+	for(i=0;i<this->Size();i++){
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		vertex->UpdateClonePids(alltruepids);
+	}
+
+	/* Free ressources: */
+	xDelete<int>(allpidcount);
+	xDelete<int>(truepids);
+	xDelete<int>(alltruepids);
+}
+/*}}}*/
+/*FUNCTION Vertices::FlagClones{{{*/
+void  Vertices::FlagClones(int numberofobjects){
+
+	int i;
+	int num_procs;
+
+	int* ranks=NULL;
+	int* minranks=NULL;
+
+	/*recover num_procs:*/
+	num_procs=IssmComm::GetSize();
+
+	/*Allocate ranks: */
+	ranks=xNew<int>(numberofobjects);
+	minranks=xNew<int>(numberofobjects);
+
+	for(i=0;i<numberofobjects;i++)ranks[i]=num_procs; //no cpu can have rank num_procs. This is the maximum limit.
+
+	/*Now go through all our objects and ask them to report to who they belong (which rank): */
+	Ranks(ranks);
+
+	/*We need to take the minimum rank for each vertex, and every cpu needs to get that result. That way, 
+	 * when we start building the dof list for all vertexs, a cpu can check whether its vertex already has been 
+	 * dealt with by another cpu. We take the minimum because we are going to manage dof assignment in increasing 
+	 * order of cpu rank. This is also why we initialized this array to num_procs.*/
+	#ifdef _HAVE_MPI_
+	MPI_Allreduce ( (void*)ranks,(void*)minranks,numberofobjects,MPI_INT,MPI_MIN,IssmComm::GetComm());
+	#else
+	for(i=0;i<numberofobjects;i++)minranks[i]=ranks[i];
+	#endif
+
+	/*Now go through all objects, and use minranks to flag which objects are cloned: */
+	for(i=0;i<this->Size();i++){
+		/*For this object, decide whether it is a clone: */
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		vertex->SetClone(minranks);
+	}
+
+	/*Free ressources: */
+	xDelete<int>(ranks); 
+	xDelete<int>(minranks);
+
+}
+/*}}}*/
+/*FUNCTION Vertices::NumberOfVertices{{{*/
+int Vertices::NumberOfVertices(void){
+
+	int i,sid;
+	int max_sid=0;
+	int vertex_max_sid;
+
+	for(i=0;i<this->Size();i++){
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		sid=vertex->Sid();
+		if (sid>max_sid)max_sid=sid;
+	}
+
+	#ifdef _HAVE_MPI_
+	MPI_Reduce (&max_sid,&vertex_max_sid,1,MPI_INT,MPI_MAX,0,IssmComm::GetComm() );
+	MPI_Bcast(&vertex_max_sid,1,MPI_INT,0,IssmComm::GetComm());
+	max_sid=vertex_max_sid;
+	#endif
+
+	/*sid starts at 0*/
+	max_sid++;
+
+	/*return:*/
+	return max_sid;
+}
+/*}}}*/
+/*FUNCTION Vertices::Ranks{{{*/
+void   Vertices::Ranks(int* ranks){
+
+	int my_rank;
+	int        sid;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	/*Go through a dataset, and for each object, report it cpu: */
+	for(int i=0;i<this->Size();i++){
+		/*Plug rank into ranks, according to id: */
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		sid=vertex->Sid();
+		ranks[sid]=my_rank; 
+	}
+}
+/*}}}*/
+/*FUNCTION Vertices::ToXYZ{{{*/
+IssmDouble* Vertices::ToXYZ(void){
+
+	/*intermediary: */
+	int i;
+	int my_rank;
+	int num_vertices;
+
+	/*output: */
+	Matrix<IssmDouble>* xyz = NULL;
+	IssmDouble* xyz_serial=NULL;
+
+	/*recover my_rank:*/
+	my_rank=IssmComm::GetRank();
+
+	/*First, figure out number of vertices: */
+	num_vertices=this->NumberOfVertices();
+
+	/*Now, allocate matrix to hold all the vertices x,y and z values: */
+	xyz= new Matrix<IssmDouble>(num_vertices,3);
+
+	/*Go through vertices, and for each vertex, object, report it cpu: */
+	for(i=0;i<this->Size();i++){
+
+		/*let vertex fill matrix: */
+		Vertex* vertex=dynamic_cast<Vertex*>(this->GetObjectByOffset(i));
+		vertex->ToXYZ(xyz);
+	}
+
+	/*Assemble:*/
+	xyz->Assemble();
+
+	/*gather on cpu 0: */
+	xyz_serial=xyz->ToSerial();
+
+	/*free ressources: */
+	delete xyz;
+	if(my_rank!=0)delete xyz_serial;
+
+	/*return matrix: */
+	return xyz_serial;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/Vertices.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/Vertices.h	(revision 15012)
+++ /issm/trunk-jpl/src/c/classes/Vertices.h	(revision 15012)
@@ -0,0 +1,30 @@
+#ifndef _CONTAINER_VERTICES_H_
+#define  _CONTAINER_VERTICES_H_
+
+/*forward declarations */
+#include "./DataSet.h"
+#include "../shared/shared.h"
+
+/*!\brief Declaration of Vertices class.
+ *
+ * Declaration of Vertices class.  Vertices are vector lists (Containers) of Vertex objects.
+ * A vertex is a set of (x,y,z) coordinates defining the location of points in the mesh (not
+ * to be confused with a node, which is a degree of freedom (DOF) for a particular analysis).
+ */ 
+class Vertices: public DataSet{
+
+	public:
+
+		/*constructors, destructors:*/ 
+		Vertices();
+		~Vertices();
+
+		/*numerics:*/
+		void  DistributePids(int numberofnodes);
+		void  FlagClones(int numberofnodes);
+		int   NumberOfVertices(void);
+		void  Ranks(int* ranks);
+		IssmDouble* ToXYZ(void);
+};
+
+#endif //ifndef _VERTICES_H_
Index: /issm/trunk-jpl/src/c/classes/bamg/BamgGeom.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/BamgGeom.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/BamgGeom.cpp	(revision 15012)
@@ -1,5 +1,3 @@
-#include <stdio.h>
-#include "../objects/objects.h"
-#include "../../shared/io/io.h"
+#include "../classes.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/bamg/BamgMesh.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/BamgMesh.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/BamgMesh.cpp	(revision 15012)
@@ -1,5 +1,3 @@
-#include <stdio.h>
-#include "../objects/objects.h"
-#include "../../shared/io/io.h"
+#include "../classes.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/bamg/BamgOpts.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/BamgOpts.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/BamgOpts.cpp	(revision 15012)
@@ -1,6 +1,4 @@
-#include <stdio.h>
+#include "../classes.h"
 #include "../../shared/shared.h"
-#include "../objects/objects.h"
-#include "../../shared/io/io.h"
 
 /*Constructors/Destructors*/
Index: /issm/trunk-jpl/src/c/classes/bamg/BamgQuadtree.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/BamgQuadtree.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/BamgQuadtree.cpp	(revision 15012)
@@ -3,5 +3,5 @@
 #include <stdlib.h>
 
-#include "../objects/objects.h"
+#include "../classes.h"
 
 namespace bamg {
Index: /issm/trunk-jpl/src/c/classes/bamg/BamgQuadtree.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/BamgQuadtree.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/BamgQuadtree.h	(revision 15012)
@@ -4,5 +4,5 @@
 
 #include "./include.h"
-#include "../objects/Object.h"
+#include "../Object.h"
 class DataSet;
 
Index: /issm/trunk-jpl/src/c/classes/bamg/BamgVertex.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/BamgVertex.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/BamgVertex.cpp	(revision 15012)
@@ -4,5 +4,5 @@
 #include <ctime>
 
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "./det.h"
 
Index: /issm/trunk-jpl/src/c/classes/bamg/Geometry.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/Geometry.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/Geometry.cpp	(revision 15012)
@@ -4,5 +4,5 @@
 #include <ctime>
 
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "../../shared/Exceptions/exceptions.h"
 
Index: /issm/trunk-jpl/src/c/classes/bamg/ListofIntersectionTriangles.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/ListofIntersectionTriangles.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/ListofIntersectionTriangles.cpp	(revision 15012)
@@ -4,5 +4,5 @@
 #include <ctime>
 
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "./det.h"
 
Index: /issm/trunk-jpl/src/c/classes/bamg/Mesh.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/Mesh.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/Mesh.cpp	(revision 15012)
@@ -4,5 +4,5 @@
 #include <ctime>
 
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "./det.h"
 
Index: /issm/trunk-jpl/src/c/classes/bamg/SetOfE4.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/SetOfE4.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/SetOfE4.cpp	(revision 15012)
@@ -1,3 +1,3 @@
-#include "../objects/objects.h"
+#include "../classes.h"
 
 using namespace std;
Index: /issm/trunk-jpl/src/c/classes/bamg/Triangle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/bamg/Triangle.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/bamg/Triangle.cpp	(revision 15012)
@@ -4,5 +4,5 @@
 #include <ctime>
 
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "./det.h"
 
Index: /issm/trunk-jpl/src/c/classes/classes.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/classes.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/classes.h	(revision 15012)
@@ -3,9 +3,136 @@
  */
 
-#ifndef ALL_CLASSES_H_
-#define ALL_CLASSES_H_
+#ifndef _ALL_CLASSES_H_
+#define _ALL_CLASSES_H_
 
-/*Objects derived classes, which are used in our containers: */
-#include "./objects/objects.h"
+/*Abstract classes: */
+#include "./Object.h"
+#include "./DataSet.h"
+
+/*Objects: */
+#include "./Contour.h"
+#include "./Vertices.h"
+#include "./Vertex.h"
+#include "./Nodes.h"
+#include "./Node.h"
+#include "./Profiler.h"
+#include "./DependentObject.h"
+#include "./IndependentObject.h"
+#include "./Segment.h"
+#include "./Bucket.h"
+
+/*Constraints: */
+#include "./Constraints/Constraints.h"
+#include "./Constraints/Constraint.h"
+#include "./Constraints/SpcStatic.h"
+#include "./Constraints/SpcTransient.h"
+#include "./Constraints/SpcDynamic.h"
+
+/*Loads: */
+#include "./Loads/Loads.h"
+#include "./Loads/Load.h"
+#include "./Loads/Friction.h"
+#include "./Loads/Icefront.h"
+#include "./Loads/Numericalflux.h"
+#include "./Loads/Riftfront.h"
+#include "./Loads/Penpair.h"
+#include "./Loads/Pengrid.h"
+
+/*Elements: */
+#include "./Elements/Elements.h"
+#include "./Elements/Element.h"
+#include "./Elements/Penta.h"
+#include "./Elements/PentaHook.h"
+#include "./Elements/PentaRef.h"
+#include "./Elements/Tria.h"
+#include "./Elements/TriaHook.h"
+#include "./Elements/TriaRef.h"
+
+/*KML parsing objects: */
+#include "./KML/KML_Attribute.h"
+#include "./KML/KML_Comment.h"
+#include "./KML/KML_ColorStyle.h"
+#include "./KML/KML_Container.h"
+#include "./KML/KML_Document.h"
+#include "./KML/KML_Feature.h"
+#include "./KML/KML_File.h"
+#include "./KML/KML_Folder.h"
+#include "./KML/KML_Geometry.h"
+#include "./KML/KML_GroundOverlay.h"
+#include "./KML/KML_Icon.h"
+#include "./KML/KML_LatLonBox.h"
+#include "./KML/KML_LinearRing.h"
+#include "./KML/KML_LineString.h"
+#include "./KML/KML_LineStyle.h"
+#include "./KML/KML_MultiGeometry.h"
+#include "./KML/KML_Object.h"
+#include "./KML/KML_Overlay.h"
+#include "./KML/KML_Point.h"
+#include "./KML/KML_Placemark.h"
+#include "./KML/KML_Polygon.h"
+#include "./KML/KML_PolyStyle.h"
+#include "./KML/KML_Style.h"
+#include "./KML/KML_StyleSelector.h"
+#include "./KML/KML_SubStyle.h"
+#include "./KML/KML_Unknown.h"
+#include "./KML/KMLFileReadUtils.h"
+
+/*Option parsing objects: */
+#include "./Options/Option.h"
+#include "./Options/Options.h"
+#include "./Options/GenericOption.h"
+#include "./Options/OptionUtilities.h"
+
+/*Inputs: */
+#include "./Inputs/Inputs.h"
+#include "./Inputs/Input.h"
+#include "./Inputs/BoolInput.h"
+#include "./Inputs/DoubleInput.h"
+#include "./Inputs/IntInput.h"
+#include "./Inputs/PentaP1Input.h"
+#include "./Inputs/TriaP1Input.h"
+#include "./Inputs/ControlInput.h"
+#include "./Inputs/DatasetInput.h"
+#include "./Inputs/TransientInput.h"
+
+/*ElementResults: */
+#include "./ElementResults/ElementResult.h"
+#include "./ElementResults/DoubleElementResult.h"
+#include "./ElementResults/TriaP1ElementResult.h"
+#include "./ElementResults/PentaP1ElementResult.h" 
+#include "./ElementResults/BoolElementResult.h"
+
+/*ExternalResults: */
+#include "./ExternalResults/Results.h"
+#include "./ExternalResults/ExternalResult.h"
+#include "./ExternalResults/GenericExternalResult.h"
+
+/*Materials: */
+#include "./Materials/Materials.h"
+#include "./Materials/Material.h"
+#include "./Materials/Matice.h"
+#include "./Materials/Matdamageice.h"
+#include "./Materials/Matpar.h"
+
+/*Params: */
+#include "./Params/GenericParam.h"
+#include "./Params/BoolParam.h"
+#include "./Params/DoubleMatParam.h"
+#include "./Params/DoubleTransientMatParam.h"
+#include "./Params/DoubleMatArrayParam.h"
+#include "./Params/DoubleParam.h"
+#include "./Params/DoubleVecParam.h"
+#include "./Params/IntParam.h"
+#include "./Params/IntVecParam.h"
+#include "./Params/IntMatParam.h"
+#include "./Params/FileParam.h"
+#include "./Params/Parameters.h"
+#include "./Params/Param.h"
+#include "./Params/MatrixParam.h"
+#include "./Params/VectorParam.h"
+#include "./Params/StringArrayParam.h"
+#include "./Params/StringParam.h"
+#include "./Params/TransientParam.h"
+#include "./Params/DataSetParam.h"
 
 /*matrix: */
Index: /issm/trunk-jpl/src/c/classes/kriging/ExponentialVariogram.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/ExponentialVariogram.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/ExponentialVariogram.cpp	(revision 15012)
@@ -9,7 +9,5 @@
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/kriging/GaussianVariogram.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/GaussianVariogram.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/GaussianVariogram.cpp	(revision 15012)
@@ -9,7 +9,5 @@
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/kriging/Observation.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/Observation.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/Observation.cpp	(revision 15012)
@@ -4,5 +4,5 @@
 
 #include <stdlib.h>
-#include "../objects/objects.h"
+#include "../classes.h"
 
 /*Observation constructors and destructor*/
Index: /issm/trunk-jpl/src/c/classes/kriging/Observation.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/Observation.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/Observation.h	(revision 15012)
@@ -6,5 +6,5 @@
 #define _OBSERVATION_H_
 
-#include "../objects/Object.h"
+#include "../Object.h"
 
 class Observation: public Object{
Index: /issm/trunk-jpl/src/c/classes/kriging/Observations.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/Observations.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/Observations.cpp	(revision 15012)
@@ -16,6 +16,6 @@
 #include <iostream>
 
-#include "../objects/DataSet.h"
-#include "../objects/Options/Options.h"
+#include "../DataSet.h"
+#include "../Options/Options.h"
 #include "./Observations.h"
 #include "./Observation.h"
Index: /issm/trunk-jpl/src/c/classes/kriging/Observations.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/Observations.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/Observations.h	(revision 15012)
@@ -5,5 +5,5 @@
 class Variogram;
 class Options;
-#include "../objects/DataSet.h"
+#include "../DataSet.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/kriging/PowerVariogram.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/PowerVariogram.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/PowerVariogram.cpp	(revision 15012)
@@ -9,7 +9,5 @@
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/kriging/Quadtree.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/Quadtree.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/Quadtree.cpp	(revision 15012)
@@ -1,3 +1,3 @@
-#include "../objects/objects.h"
+#include "../classes.h"
 
 /*DOCUMENTATION What is a Quadtree? {{{
Index: /issm/trunk-jpl/src/c/classes/kriging/SphericalVariogram.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/SphericalVariogram.cpp	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/SphericalVariogram.cpp	(revision 15012)
@@ -9,7 +9,5 @@
 #endif
 
-#include <stdio.h>
-#include <string.h>
-#include "../objects/objects.h"
+#include "../classes.h"
 #include "../../shared/shared.h"
 
Index: /issm/trunk-jpl/src/c/classes/kriging/Variogram.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/kriging/Variogram.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/kriging/Variogram.h	(revision 15012)
@@ -6,5 +6,5 @@
 #define _VARIOGRAM_H_
 
-#include "../objects/Object.h"
+#include "../Object.h"
 
 class Variogram: public Object{
Index: /issm/trunk-jpl/src/c/classes/matrix/ElementMatrix.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/matrix/ElementMatrix.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/matrix/ElementMatrix.h	(revision 15012)
@@ -11,5 +11,5 @@
 /*Headers:*/
 /*{{{*/
-#include "../objects/Object.h"
+#include "../Object.h"
 #include "../../toolkits/toolkits.h"
 #include "../../shared/Enum/Enum.h"
Index: /issm/trunk-jpl/src/c/classes/matrix/ElementVector.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/matrix/ElementVector.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/classes/matrix/ElementVector.h	(revision 15012)
@@ -11,5 +11,5 @@
 /*Headers:*/
 /*{{{*/
-#include "../objects/Object.h"
+#include "../Object.h"
 #include "../../toolkits/toolkits.h"
 #include "../../shared/Enum/Enum.h"
Index: /issm/trunk-jpl/src/c/toolkits/issm/IssmMpiDenseMat.h
===================================================================
--- /issm/trunk-jpl/src/c/toolkits/issm/IssmMpiDenseMat.h	(revision 15011)
+++ /issm/trunk-jpl/src/c/toolkits/issm/IssmMpiDenseMat.h	(revision 15012)
@@ -21,6 +21,6 @@
 #include "../../shared/MemOps/MemOps.h"
 #include "../../shared/io/Comm/Comm.h"
-#include "../../classes/objects/DataSet.h"
-#include "../../classes/objects/Bucket.h"
+#include "../../classes/DataSet.h"
+#include "../../classes/Bucket.h"
 #include "../mumps/mumpsincludes.h"
 #include "./IssmMpiVec.h"
