Index: /issm/trunk-jpl/src/c/classes/IoModel.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/IoModel.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/IoModel.cpp	(revision 12822)
@@ -0,0 +1,1250 @@
+/*! \file IoModel.cpp
+ * \brief  file containing the methods that will help in processing the input data coming 
+ * into ISSM, from Matlab, or through a binary file opened for reading.
+ */
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "./objects.h"
+#include "../io/io.h"
+#include "./Container/Parameters.h"
+#include "../shared/shared.h"
+#include "../io/io.h"
+#include "../include/include.h"
+
+/*FUNCTION IoModel::IoModel(){{{*/
+IoModel::IoModel(){
+	this->fid=NULL;
+	this->data=NULL;
+	this->constants=NULL;
+	
+	this->my_elements=NULL;
+	this->my_nodes=NULL;
+	this->my_vertices=NULL;
+	this->singlenodetoelementconnectivity=NULL;
+	this->numbernodetoelementconnectivity=NULL;
+	
+	this->nodecounter=0;
+	this->loadcounter=0;
+	this->constraintcounter=0;
+}
+/*}}}*/
+/*FUNCTION IoModel::IoModel(FILE*  iomodel_handle){{{*/
+IoModel::IoModel(FILE* iomodel_handle){
+	
+	/*First, keep track of the file handle: */
+	this->fid=iomodel_handle;
+
+	/*Check that Enums are Synchronized*/
+	this->CheckEnumSync();
+
+	/*Initialize and read constants:*/
+	this->constants=new Parameters();
+	this->FetchConstants(); /*this routine goes through the input file, and fetches bools, ints, IssmDoubles and strings only, nothing memory intensive*/
+
+	/*Initialize data: */
+	this->data=xNew<IssmDouble*>(MaximumNumberOfEnums);
+	for(int i=0;i<MaximumNumberOfEnums;i++) this->data[i]=NULL;
+	
+	/*Initialize permanent data: */
+	this->my_elements=NULL;
+	this->my_nodes=NULL;
+	this->my_vertices=NULL;
+	this->singlenodetoelementconnectivity=NULL;
+	this->numbernodetoelementconnectivity=NULL;
+	
+	this->nodecounter=0;
+	this->loadcounter=0;
+	this->constraintcounter=0;
+}
+/*}}}*/
+/*FUNCTION IoModel::~IoModel(){{{*/
+IoModel::~IoModel(){
+
+	if(this->constants) delete this->constants;
+
+	/*Some checks in debugging mode*/
+	#ifdef _ISSM_DEBUG_
+	if(this->data){
+		for(int i=0;i<MaximumNumberOfEnums;i++){
+			if(this->data[i]){
+				_pprintLine_("Info: previous pointer of " << EnumToStringx(i) << " has not been freed (DeleteData has not been called)");
+			}
+		}
+	}
+	#endif
+
+	xDelete<IssmDouble*>(this->data);
+	xDelete<bool>(this->my_elements);
+	xDelete<bool>(this->my_nodes);
+	xDelete<int>(this->my_vertices);
+	xDelete<int>(this->singlenodetoelementconnectivity);
+	xDelete<int>(this->numbernodetoelementconnectivity);
+}
+/*}}}*/
+
+/*FUNCTION IoModel::CheckEnumSync{{{*/
+void  IoModel::CheckEnumSync(void){
+
+	extern int my_rank;
+	int record_enum = 0;
+
+	/*Check that some fields have been allocated*/
+	_assert_(this->fid || my_rank);
+
+	/*Go find in the binary file, the position of the data we want to fetch: */
+	if(my_rank==0){ //cpu 0
+
+		/*First set FILE* position to the beginning of the file: */
+		fseek(this->fid,0,SEEK_SET);
+
+		/*Get first Enum*/
+		if(fread(&record_enum,sizeof(int),1,this->fid)==0){
+			_error2_("Marshalled file is empty");
+		}
+		else{
+			if(record_enum!=MaximumNumberOfEnums){
+				_printLine_("");
+				_printLine_("=========================================================================");
+				_printLine_(" Enums in marshalled file are not compatible with compiled code          ");
+				_printLine_("                                                                         ");
+				_printLine_("   * If you are running ISSM on a remote cluster:                        ");
+				_printLine_("     make sure that you are using the same version of ISSM on your local ");
+				_printLine_("     machine and remote cluster (you might need to run svn update)       ");
+				_printLine_("   * If you are running ISSM on your local machine:                      ");
+				_printLine_("     make sure that all the code is compiled (modules and executables)   ");
+				_printLine_("   * If you are a developer and just added a new Enum:                   ");
+				_printLine_("     you might need to run ./Synchronize.sh in src/c/EnumDefinitions     ");
+				_printLine_("     and recompile                                                       ");
+				_printLine_("=========================================================================");
+				_printLine_("");
+				_error2_("Enums not consistent (See error message above)");
+			}
+		}
+	}
+}
+/*}}}*/
+/*FUNCTION IoModel::Constant(bool* poutput,int constant_enum){{{*/
+void IoModel::Constant(bool* poutput,int constant_enum){
+
+	_assert_(constant_enum>=0);
+	_assert_(this->constants);
+
+	this->constants->FindParam(poutput,constant_enum);
+}
+/*}}}*/
+/*FUNCTION IoModel::Constant(int* poutput,int constant_enum){{{*/
+void IoModel::Constant(int* poutput,int constant_enum){
+
+	_assert_(constant_enum>=0);
+	_assert_(this->constants);
+
+	this->constants->FindParam(poutput,constant_enum);
+}
+/*}}}*/
+/*FUNCTION IoModel::Constant(IssmDouble* poutput,int constant_enum){{{*/
+void IoModel::Constant(IssmDouble* poutput,int constant_enum){
+
+	_assert_(constant_enum>=0);
+	_assert_(this->constants);
+
+	this->constants->FindParam(poutput,constant_enum);
+}
+/*}}}*/
+/*FUNCTION IoModel::Constant(char** poutput,int constant_enum){{{*/
+void IoModel::Constant(char** poutput,int constant_enum){
+
+	_assert_(constant_enum>=0);
+	_assert_(this->constants);
+
+	this->constants->FindParam(poutput,constant_enum);
+}
+/*}}}*/
+/*FUNCTION IoModel::CopyConstantObject{{{*/
+Param* IoModel::CopyConstantObject(int constant_enum){
+
+	_assert_(this->constants);
+
+	/*Find constant*/
+	Param* param=(Param*)this->constants->FindParamObject(constant_enum);
+	if(!param) _error2_("Constant " << EnumToStringx(constant_enum) << " not found in iomodel");
+
+	return (Param*)param->copy();
+}
+/*}}}*/
+/*FUNCTION IoModel::Data{{{*/
+IssmDouble* IoModel::Data(int data_enum){
+
+	_assert_(data_enum<MaximumNumberOfEnums);
+	_assert_(data_enum>=0);
+
+	return this->data[data_enum];
+}
+/*}}}*/
+/*FUNCTION IoModel::DeleteData{{{*/
+void  IoModel::DeleteData(int num,...){
+
+	va_list ap;
+	int     dataenum;
+	int     i;
+	DoubleMatParam* parameter=NULL;
+
+	/*Go through the entire list of enums and delete the corresponding data from the iomodel-data dataset: */
+
+	va_start(ap,num);
+	for(i = 0; i <num; i++){
+		dataenum=va_arg(ap, int);
+		_assert_(dataenum<MaximumNumberOfEnums);
+		xDelete<IssmDouble>(this->data[dataenum]);
+	}
+	va_end(ap);
+} /*}}}*/
+/*FUNCTION IoModel::FetchConstants{{{*/
+void  IoModel::FetchConstants(void){
+
+	extern int my_rank;
+	extern int num_procs;
+	
+	/*record descriptions; */
+	int record_enum;
+	int record_length;
+	int record_code; //1 to 7 number
+
+	/*records: */
+	int  booleanint=0;
+	int  integer=0;
+	IssmPDouble scalar=0;
+	char* string=NULL;
+	int   string_size;
+
+	/*Check that some fields have been allocated*/
+	_assert_(this->fid || my_rank);
+	_assert_(this->constants);
+
+	/*Go find in the binary file, the position of the data we want to fetch: */
+	if(my_rank==0){ //cpu 0{{{
+	
+		/*First set FILE* position to the beginning of the file: */
+		fseek(this->fid,0,SEEK_SET);
+
+		/*Now march through file looking for the correct data identifiers (bool,int,IssmDouble or string): */
+		for(;;){
+			if(fread(&record_enum,sizeof(int),1,this->fid)==0){
+
+				/*Ok, we have reached the end of the file. break: */
+				record_code=0; //0 means bailout
+				#ifdef _HAVE_MPI_
+				MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD);  /*tell others cpus we are bailing: */
+				#endif
+				break;
+			}
+			else{
+			
+				/* Read the record length and the data type code: */
+				fread(&record_length,sizeof(int),1,this->fid);
+				fread(&record_code,sizeof(int),1,this->fid);
+					
+				#ifdef _HAVE_MPI_
+				/*Tell other cpus what we are doing: */
+				MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD);  /*tell other cpus what we are going to do: */
+
+				/*Tell other cpus the name of the data, then branch according to the data type: */
+				MPI_Bcast(&record_enum,1,MPI_INT,0,MPI_COMM_WORLD);  
+				MPI_Bcast(&record_length,1,MPI_INT,0,MPI_COMM_WORLD);  
+				#endif
+				
+				switch(record_code){
+					case 1: 
+						/*Read the boolean and broadcast it to other cpus:*/
+						if(fread(&booleanint,sizeof(int),1,this->fid)!=1) _error2_("could not read boolean ");
+						#ifdef _HAVE_MPI_
+						MPI_Bcast(&booleanint,1,MPI_INT,0,MPI_COMM_WORLD); 
+						#endif
+
+						/*create BoolParam: */
+						this->constants->AddObject(new BoolParam(record_enum,(bool)booleanint)); //cast to boolean
+
+						break;
+					case 2:
+						/*Read the integer and broadcast it to other cpus:*/
+						if(fread(&integer,sizeof(int),1,this->fid)!=1) _error2_("could not read integer ");
+						#ifdef _HAVE_MPI_
+						MPI_Bcast(&integer,1,MPI_INT,0,MPI_COMM_WORLD); 
+						#endif
+
+						/*create IntParam: */
+						this->constants->AddObject(new IntParam(record_enum,integer));
+
+						break;
+					case 3:
+						/*Read the scalar and broadcast it to other cpus:*/
+						if(fread(&scalar,sizeof(IssmPDouble),1,this->fid)!=1) _error2_("could not read scalar ");
+						#ifdef _HAVE_MPI_
+						MPI_Bcast(&scalar,1,MPI_DOUBLE,0,MPI_COMM_WORLD); 
+						#endif
+
+						/*create DoubleParam: */
+						this->constants->AddObject(new DoubleParam(record_enum,scalar));
+
+						break;
+					case 4: 
+						/*We have to read a string from disk. First read the dimensions of the string, then the string: */
+						if(fread(&string_size,sizeof(int),1,this->fid)!=1) _error2_("could not read length of string ");
+						#ifdef _HAVE_MPI_
+						MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
+						#endif
+
+						if(string_size){
+							string=xNew<char>(string_size+1);
+							string[string_size]='\0';
+
+							/*Read string, then broadcast: */
+							if(fread(string,string_size*sizeof(char),1,this->fid)!=1)_error2_(" could not read string ");
+							#ifdef _HAVE_MPI_
+							MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
+							#endif
+						}
+						else{
+							string=xNew<char>(1);
+							string[0]='\0';
+						}
+						
+						/*Add string to parameters: */
+						this->constants->AddObject(new StringParam(record_enum,string));
+
+						/*Free string*/
+						xDelete<char>(string);
+
+						break;
+					case 5: 
+							/*We are not interested in this record, too memory intensive. Skip it: */
+							/*skip: */
+							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
+							fseek(fid,record_length,SEEK_CUR);
+							break;
+					case 6: 
+							/*We are not interested in this record, too memory intensive. Skip it: */
+							/*skip: */
+							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
+							fseek(fid,record_length,SEEK_CUR);
+							break;
+					case 7: 
+							/*We are not interested in this record, too memory intensive. Skip it: */
+							/*skip: */
+							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
+							fseek(fid,record_length,SEEK_CUR);
+							break;
+
+					case 8: 
+							/*We are not interested in this record, too memory intensive. Skip it: */
+							/*skip: */
+							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
+							fseek(fid,record_length,SEEK_CUR);
+							break;
+
+					case 9: 
+							/*We are not interested in this record, too memory intensive. Skip it: */
+							/*skip: */
+							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
+							fseek(fid,record_length,SEEK_CUR);
+							break;
+
+					default: 
+						_error2_("unknown record type:" << record_code); 
+						break;;
+				}
+			}
+		}
+	} //}}}
+	#ifdef _HAVE_MPI_
+	else{ //cpu ~0 {{{
+		for(;;){ //wait on cpu 0
+			MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD);  /*get from cpu 0 what we are going to do: */
+			if(record_code==0){
+				break; //we are done, break from the loop
+			}
+			else{
+				MPI_Bcast(&record_enum,1,MPI_INT,0,MPI_COMM_WORLD);   //get from cpu 0 name of the data
+				MPI_Bcast(&record_length,1,MPI_INT,0,MPI_COMM_WORLD);  
+				switch(record_code){
+				case 1: 
+					/*boolean. get it from cpu 0 */
+					MPI_Bcast(&booleanint,1,MPI_INT,0,MPI_COMM_WORLD); 
+						
+					/*create BoolParam: */
+					this->constants->AddObject(new BoolParam(record_enum,(bool)booleanint)); //cast to a boolean
+					break;
+
+				case 2:
+					/*integer. get it from cpu 0 */
+					MPI_Bcast(&integer,1,MPI_INT,0,MPI_COMM_WORLD); 
+						
+					/*create IntParam: */
+					this->constants->AddObject(new IntParam(record_enum,integer));
+
+					break;
+				case 3:
+					/*scalar. get it from cpu 0 */
+					MPI_Bcast(&scalar,1,MPI_DOUBLE,0,MPI_COMM_WORLD); 
+						
+					/*create DoubleParam: */
+					this->constants->AddObject(new DoubleParam(record_enum,scalar));
+
+					break;
+				case 4: 
+					MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
+					if(string_size){
+						string=xNew<char>((string_size+1));
+						string[string_size]='\0';
+
+						/*Read string from cpu 0: */
+						MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
+					}
+					else{
+						string=xNew<char>(1);
+						string[0]='\0';
+					}
+					/*Add string to parameters: */
+					this->constants->AddObject(new StringParam(record_enum,string));
+
+					/*Free string*/
+					xDelete<char>(string);
+
+					break;
+				case 5: break; //do nothing. not interested in this type of data, which is memory intensive.
+				case 6: break; //do nothing. not interested in this type of data, which is memory intensive.
+				case 7: break; //do nothing. not interested in this type of data, which is memory intensive.
+				case 8: break; //do nothing. not interested in this type of data, which is memory intensive.
+				case 9: break; //do nothing. not interested in this type of data, which is memory intensive.
+
+				default: 
+					_error2_("unknown record type:" << record_code); 
+					break;;
+				}
+
+
+			}
+		}
+	} //}}}
+	#endif
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(bool*     pbool,int data_enum){{{*/
+void  IoModel::FetchData(bool* pboolean,int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+	
+
+	/*output: */
+	int   booleanint;
+	int   code;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,NULL,data_enum);
+
+	if(code!=1)_error2_("expecting a boolean for enum " << EnumToStringx(data_enum));
+	
+	/*We have to read a boolean from disk. */
+	if(my_rank==0){  
+		if(fread(&booleanint,sizeof(int),1,fid)!=1) _error2_("could not read boolean ");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&booleanint,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	/*cast to bool: */
+	/*Assign output pointers: */
+	*pboolean=(bool)booleanint;
+
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(int*      pinteger,int data_enum){{{*/
+void  IoModel::FetchData(int* pinteger,int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+
+	/*output: */
+	int   integer;
+	int   code;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,NULL,data_enum);
+	
+	if(code!=2)_error2_("expecting an integer for enum " << EnumToStringx(data_enum));
+	
+	/*We have to read a integer from disk. First read the dimensions of the integer, then the integer: */
+	if(my_rank==0){  
+		if(fread(&integer,sizeof(int),1,fid)!=1) _error2_("could not read integer ");
+	}
+
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&integer,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	/*Assign output pointers: */
+	*pinteger=integer;
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(IssmDouble*   pscalar,int data_enum){{{*/
+void  IoModel::FetchData(IssmDouble* pscalar,int data_enum){
+
+
+	extern int my_rank;
+	extern int num_procs;
+	
+
+	/*output: */
+	IssmPDouble   scalar;
+	int      code;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,NULL,data_enum);
+	
+	if(code!=3)_error2_("expecting a IssmDouble for enum " << EnumToStringx(data_enum));
+	
+	/*We have to read a scalar from disk. First read the dimensions of the scalar, then the scalar: */
+	if(my_rank==0){
+		if(fread(&scalar,sizeof(IssmPDouble),1,fid)!=1)_error2_("could not read scalar ");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&scalar,1,MPI_DOUBLE,0,MPI_COMM_WORLD); 
+	#endif
+
+	/*Assign output pointers: */
+	*pscalar=scalar;
+		 
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(char**    pstring,int data_enum){{{*/
+void  IoModel::FetchData(char** pstring,int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+	
+
+	/*output: */
+	char* string=NULL;
+	int   string_size;
+	int code=0;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,NULL,data_enum);
+	
+	if(code!=4)_error2_("expecting a string for enum " << EnumToStringx(data_enum));
+	
+	/*Now fetch: */
+	
+	/*We have to read a string from disk. First read the dimensions of the string, then the string: */
+	if(my_rank==0){  
+		if(fread(&string_size,sizeof(int),1,fid)!=1) _error2_("could not read length of string ");
+	}
+
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	/*Now allocate string: */
+	if(string_size){
+		string=xNew<char>((string_size+1));
+		string[string_size]='\0';
+
+		/*Read string on node 0, then broadcast: */
+		if(my_rank==0){  
+			if(fread(string,string_size*sizeof(char),1,fid)!=1)_error2_(" could not read string ");
+		}
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
+		#endif
+	}
+	else{
+		string=xNew<char>(1);
+		string[0]='\0';
+	}
+
+
+	/*Assign output pointers: */
+	*pstring=string;
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(int**     pintegerematrix,int* pM,int* pN,int data_enum){{{*/
+void  IoModel::FetchData(int** pmatrix,int* pM,int* pN,int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+	int i,j;
+
+	/*output: */
+	int M,N;
+	IssmPDouble* matrix=NULL;
+	int*    integer_matrix=NULL;
+	int code=0;
+	int vector_type=0;
+	
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,&vector_type,data_enum);
+
+	if((code!=5) && (code!=6) && (code!=7))_error2_("expecting a IssmDouble, integer or boolean matrix for enum " << EnumToStringx(data_enum));
+	
+	/*Now fetch: */
+
+	/*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) _error2_("could not read number of rows for matrix ");
+	}
+
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&M,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	if(my_rank==0){  
+		if(fread(&N,sizeof(int),1,fid)!=1) _error2_("could not read number of columns for matrix ");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD);
+	#endif
+
+	/*Now allocate matrix: */
+	if(M*N){
+		matrix=xNew<IssmPDouble>(M*N);
+
+		/*Read matrix on node 0, then broadcast: */
+		if(my_rank==0){  
+			if(fread(matrix,M*N*sizeof(IssmPDouble),1,fid)!=1) _error2_("could not read matrix ");
+		}
+		
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,MPI_COMM_WORLD); 
+		#endif
+	}
+
+	/*Now cast to integer: */
+	if(M*N){
+		integer_matrix=xNew<int>(M*N);
+		for (i=0;i<M;i++){
+			for (j=0;j<N;j++){
+				integer_matrix[i*N+j]=(int)matrix[i*N+j];
+			}
+		}
+	}
+	else{
+		integer_matrix=NULL;
+	}
+	/*Free ressources:*/
+	xDelete<IssmPDouble>(matrix);
+
+	/*Assign output pointers: */
+	*pmatrix=integer_matrix;
+	if (pM)*pM=M;
+	if (pN)*pN=N;
+
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(IssmDouble**  pIssmDoublematrix,int* pM,int* pN,int data_enum){{{*/
+void  IoModel::FetchData(IssmDouble** pmatrix,int* pM,int* pN,int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+
+	/*output: */
+	int M,N;
+	IssmPDouble* matrix=NULL;
+	int code=0;
+	int vector_type=0;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,&vector_type,data_enum);
+	if((code!=5) && (code!=6) && (code!=7))_error2_("expecting a IssmDouble, integer or boolean matrix for enum " << EnumToStringx(data_enum));
+	
+	/*Now fetch: */
+
+	/*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) _error2_("could not read number of rows for matrix ");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&M,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	if(my_rank==0){  
+		if(fread(&N,sizeof(int),1,fid)!=1) _error2_("could not read number of columns for matrix ");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	/*Now allocate matrix: */
+	if(M*N){
+		matrix=xNew<IssmPDouble>(M*N);
+
+		/*Read matrix on node 0, then broadcast: */
+		if(my_rank==0){  
+			if(fread(matrix,M*N*sizeof(IssmPDouble),1,fid)!=1) _error2_("could not read matrix ");
+		}
+		#ifdef _HAVE_MPI_
+		MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,MPI_COMM_WORLD); 
+		#endif
+	        *pmatrix=xNew<IssmDouble>(M*N);
+	        for (int i=0;i<M*N;++i) (*pmatrix)[i]=matrix[i];
+	        xDelete<IssmPDouble>(matrix);
+	}
+	else
+	  *pmatrix=NULL;
+	/*Assign output pointers: */
+	if (pM)*pM=M;
+	if (pN)*pN=N;
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(char***   pstrings,int* pnumstrings,int data_enum){{{*/
+void  IoModel::FetchData(char*** pstrings,int* pnumstrings,int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+	
+	int i;
+
+	/*output: */
+	int   numstrings=0;
+	char** strings=NULL;
+	
+	/*intermediary: */
+	char* string=NULL;
+	int   string_size;
+	int   code;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,NULL,data_enum);
+	
+	if(code!=9)_error2_("expecting a string array for enum " << EnumToStringx(data_enum));
+	
+	/*We have to read a bunch of strings from disk. First read the number of strings, and allocate: */
+	if(my_rank==0){  
+		if(fread(&numstrings,sizeof(int),1,fid)!=1) _error2_("could not read length of string array");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&numstrings,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	/*Now allocate string array: */
+	if(numstrings){
+		strings=xNew<char*>(numstrings);
+		for(i=0;i<numstrings;i++)strings[i]=NULL;
+
+		/*Go through strings, and read: */
+		for(i=0;i<numstrings;i++){
+			
+			if(my_rank==0){  
+				if(fread(&string_size,sizeof(int),1,fid)!=1) _error2_("could not read length of string ");
+			}
+			#ifdef _HAVE_MPI_
+			MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
+			#endif
+			if(string_size){
+				string=xNew<char>((string_size+1));
+				string[string_size]='\0';
+
+				/*Read string on node 0, then broadcast: */
+				if(my_rank==0){  
+					if(fread(string,string_size*sizeof(char),1,fid)!=1)_error2_(" could not read string ");
+				}
+				#ifdef _HAVE_MPI_
+				MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
+				#endif
+			}
+			else{
+				string=xNew<char>(1);
+				string[0]='\0';
+			}
+
+			strings[i]=string;
+		}
+	}
+
+	/*Assign output pointers: */
+	*pstrings=strings;
+	*pnumstrings=numstrings;
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(IssmDouble*** pmatrices,int** pmdims,int** pndims, int* pM,int data_enum){{{*/
+void  IoModel::FetchData(IssmDouble*** pmatrices,int** pmdims,int** pndims, int* pnumrecords,int data_enum){
+
+	int i;
+
+	extern int my_rank;
+	extern int num_procs;
+
+	/*output: */
+	IssmDouble** matrices=NULL;
+	int*     mdims=NULL;
+	int*     ndims=NULL;
+	int      numrecords=0;
+
+	/*intermediary: */
+	int     M, N;
+	IssmPDouble *matrix = NULL;
+	int     code;
+	
+	/*Set file pointer to beginning of the data: */
+	fid=this->SetFilePointerToData(&code,NULL,data_enum);
+	if(code!=8)_error2_("expecting a IssmDouble mat array for enum " << EnumToStringx(data_enum));
+	
+	/*Now fetch: */
+	if(my_rank==0){  
+		if(fread(&numrecords,sizeof(int),1,fid)!=1) _error2_("could not read number of records in matrix array ");
+	}
+	#ifdef _HAVE_MPI_
+	MPI_Bcast(&numrecords,1,MPI_INT,0,MPI_COMM_WORLD); 
+	#endif
+
+	if(numrecords){
+
+		/*Allocate matrices :*/
+		matrices=xNew<IssmDouble*>(numrecords);
+		mdims=xNew<int>(numrecords);
+		ndims=xNew<int>(numrecords);
+
+		for(i=0;i<numrecords;i++){
+			matrices[i]=NULL;
+			mdims[i]=0;
+			ndims[i]=0;
+		}
+
+		/*Loop through records and fetch matrix: */
+		for(i=0;i<numrecords;i++){
+
+			if(my_rank==0){  
+				if(fread(&M,sizeof(int),1,fid)!=1) _error2_("could not read number of rows in " << i << "th matrix of matrix array");
+			}
+			#ifdef _HAVE_MPI_
+			MPI_Bcast(&M,1,MPI_INT,0,MPI_COMM_WORLD); 
+			#endif
+
+			if(my_rank==0){  
+				if(fread(&N,sizeof(int),1,fid)!=1) _error2_("could not read number of columns in " << i << "th matrix of matrix array");
+			}
+			#ifdef _HAVE_MPI_
+			MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD); 
+			#endif
+
+			/*Now allocate matrix: */
+			if(M*N){
+				matrix=xNew<IssmPDouble>(M*N);
+
+				/*Read matrix on node 0, then broadcast: */
+				if(my_rank==0){  
+					if(fread(matrix,M*N*sizeof(IssmPDouble),1,fid)!=1) _error2_("could not read matrix ");
+				}
+
+				#ifdef _HAVE_MPI_
+				MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,MPI_COMM_WORLD); 
+				#endif
+				matrices[i]=xNew<IssmDouble>(M*N);
+				for (int j=0;j<M*N;++j) {matrices[i][j]=matrix[j];}
+				xDelete<IssmPDouble>(matrix);
+			}
+			else
+			  matrices[i]=NULL;
+			/*Assign: */
+			mdims[i]=M;
+			ndims[i]=N;
+		}
+	}
+
+	/*Assign output pointers: */
+	*pmatrices=matrices;
+	*pmdims=mdims;
+	*pndims=ndims;
+	*pnumrecords=numrecords;
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(Option**  poption,int data_enum){{{*/
+void  IoModel::FetchData(Option** poption,int index){
+
+	extern int my_rank;
+	extern int num_procs;
+
+	/*output: */
+	int     code;
+	Option *option      = NULL;
+	char   *name        = NULL;
+
+	/*First get option name*/
+	this->FetchData(&name,index);
+
+	/*Get option value*/
+	fid=this->SetFilePointerToData(&code,NULL,index+1);
+	switch(code){
+		case 3: {//IssmDouble
+			  IssmDouble *value = NULL;
+			  value=xNew<IssmDouble>(1);
+			  FetchData(value,index+1);
+			  option = new OptionDouble();
+			  ((OptionDouble*)option)->values = value;
+			  option->name  = name;
+			  option->numel = 1;
+			  option->ndims = 1;
+			  option->size  = NULL;
+			  break;
+			  }
+		case 4: {//char
+			  char* value = NULL;
+			  FetchData(&value,index+1);
+			  option = new OptionChar();
+			  ((OptionChar*)option)->values = value;
+			  option->name  = name;
+			  option->numel = 1;
+			  option->ndims = 1;
+			  option->size  = NULL;
+			  break;
+			  }
+		default:
+			  _error2_("Option of format " << code << " not supported yet");
+	}
+
+	/*Assign output pointers: */
+	*poption=option;
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchData(int num,...){{{*/
+void  IoModel::FetchData(int num,...){
+
+	va_list ap;
+	int     dataenum;
+	IssmDouble* matrix=NULL;
+	int     M,N;
+	int     i;
+
+	/*Go through the entire list of enums and fetch the corresponding data. Add it to the iomodel->data dataset. Everything
+	 *we fetch is a IssmDouble* : */
+	
+	va_start(ap,num);
+	for(i=0; i<num; i++){
+		
+		dataenum=va_arg(ap, int);
+
+		/*Some checks in debugging mode*/
+		/*{{{*/
+		#ifdef _ISSM_DEBUG_
+		_assert_(dataenum<MaximumNumberOfEnums);
+		if(this->data[dataenum]){
+			_error2_("Info: trying to fetch " << EnumToStringx(dataenum) << " but previous pointer has not been freed (DeleteData has not been called)");
+		}
+		#endif
+		/*}}}*/
+
+		/*Add to this->data: */
+		this->FetchData(&matrix,&M,&N,dataenum);
+		this->data[dataenum]=matrix;
+	}
+	va_end(ap);
+
+}
+/*}}}*/
+/*FUNCTION IoModel::FetchDataToInput{{{*/
+void IoModel::FetchDataToInput(Elements* elements,int vector_enum,int default_vector_enum,IssmDouble default_value){
+
+	/*intermediary: */
+	int     i;
+	bool    defaulting    = false;
+	bool    transient     = false;
+
+	FILE   *fid           = NULL;
+	int     code          = 0;
+	int     vector_layout = 0;
+	int     counter;
+	int     nods;
+	int     nel;
+	int     numberofelements;
+
+
+	/*variables being fetched: */
+	bool    boolean;
+	int     integer;
+	IssmDouble  scalar;
+	char   *string        = NULL;
+	IssmDouble *IssmDoublevector  = NULL;
+	int     M,N;
+
+	/*Fetch parameters: */
+	this->constants->FindParam(&numberofelements,MeshNumberofelementsEnum);
+
+	/*First of, find the record for the enum, and get code  of data type: */
+	fid=this->SetFilePointerToData(&code, &vector_layout,vector_enum);
+
+	switch(code){
+		case 1: //boolean constant.  {{{
+			this->FetchData(&boolean,vector_enum);
+
+			/*Add boolean constant input to all elements: */
+			counter=0;
+			for (i=0;i<numberofelements;i++){
+				if(this->my_elements[i]){
+					Element* element=(Element*)elements->GetObjectByOffset(counter);
+					element->InputCreate((IssmDouble)boolean,vector_enum,code);
+					counter++;
+				}
+			}
+			break; /*}}}*/
+		case 2: //integer constant.  {{{
+			this->FetchData(&integer,vector_enum);
+
+			/*Add integer constant input to all elements: */
+			counter=0;
+			for (i=0;i<numberofelements;i++){
+				if(this->my_elements[i]){
+					Element* element=(Element*)elements->GetObjectByOffset(counter);
+					element->InputCreate((IssmDouble)integer,vector_enum,code);
+					counter++;
+				}
+			}
+			break; /*}}}*/
+		case 3: //IssmDouble constant.  {{{
+			this->FetchData(&scalar,vector_enum);
+
+			/*Add IssmDouble constant input to all elements: */
+			counter=0;
+			for (i=0;i<numberofelements;i++){
+				if(this->my_elements[i]){
+					Element* element=(Element*)elements->GetObjectByOffset(counter);
+					element->InputCreate(scalar,vector_enum,code); 
+					counter++;
+				}
+			}
+			break; /*}}}*/
+		case 5: //boolean vector.  {{{
+
+			/*Fetch vector:*/
+			this->FetchData(&IssmDoublevector,&M,&N,vector_enum); //we still have a IssmDoublevector, because it might include times in transient mode
+			/*Check we got something, otherwise fetch default: */
+			if(IssmDoublevector){
+				defaulting=false;  //we are not defaulting, because  we do have a vector
+			}
+			else{
+				/*do we have a default enum to go fetch? */
+				if(default_vector_enum!=NoneEnum){
+					/*yes. fetch it: */
+					this->FetchData(&IssmDoublevector,&M,&N,default_vector_enum);
+					if(IssmDoublevector){
+						defaulting=false;  //we are not defaulting, because  we do have a vector
+					}
+					else{
+						/*even the default vector is non existent. we are defaulting to the default value: */
+						defaulting=true;
+					}
+				}
+				else{
+					/*we are left with the default value: */
+					defaulting=true;
+				}
+			}
+
+			/*Create inputs:*/
+			counter=0;
+			for (i=0;i<numberofelements;i++){
+				if(this->my_elements[i]){
+					Element* element=(Element*)elements->GetObjectByOffset(counter);
+					if(defaulting) element->InputCreate(default_value,vector_enum,code); 
+					else           element->InputCreate(IssmDoublevector,i,this,M,N,vector_layout,vector_enum,code);//we need i to index into elements.
+					counter++;
+				}
+			}
+			break; /*}}}*/
+		case 6: //int vector{{{
+
+			/*Fetch vector:*/
+			this->FetchData(&IssmDoublevector,&M,&N,vector_enum); //we still have a IssmDoublevector, because it might include times in transient mode
+			/*Check we got something, otherwise fetch default: */
+			if(IssmDoublevector){
+				defaulting=false;  //we are not defaulting, because  we do have a vector
+			}
+			else{
+				/*do we have a default enum to go fetch? */
+				if(default_vector_enum!=NoneEnum){
+					/*yes. fetch it: */
+					this->FetchData(&IssmDoublevector,&M,&N,default_vector_enum);
+					if(IssmDoublevector){
+						defaulting=false;  //we are not defaulting, because  we do have a vector
+					}
+					else{
+						/*even the default vector is non existent. we are defaulting to the default value: */
+						defaulting=true;
+					}
+				}
+				else{
+					/*we are left with the default value: */
+					defaulting=true;
+				}
+			}
+
+			/*Create inputs:*/
+			counter=0;
+			for (i=0;i<numberofelements;i++){
+				if(this->my_elements[i]){
+					Element* element=(Element*)elements->GetObjectByOffset(counter);
+					if(defaulting) element->InputCreate(default_value,vector_enum,code); 
+					else           element->InputCreate(IssmDoublevector,i,this,M,N,vector_layout,vector_enum,code);//we need i to index into elements.
+					counter++;
+				}
+			}
+			break; /*}}}*/
+		case 7: //IssmDouble vector{{{
+
+			/*Fetch vector:*/
+			this->FetchData(&IssmDoublevector,&M,&N,vector_enum);
+			/*Check we got something, otherwise fetch default: */
+			if(IssmDoublevector){
+				defaulting=false;  //we are not defaulting, because  we do have a vector
+			}
+			else{
+				/*do we have a default enum to go fetch? */
+				if(default_vector_enum!=NoneEnum){
+					/*yes. fetch it: */
+					this->FetchData(&IssmDoublevector,&M,&N,default_vector_enum);
+					if(IssmDoublevector){
+						defaulting=false;  //we are not defaulting, because  we do have a vector
+					}
+					else{
+						/*even the default vector is non existent. we are defaulting to the default value: */
+						defaulting=true;
+					}
+				}
+				else{
+					/*we are left with the default value: */
+					defaulting=true;
+				}
+			}
+
+			/*Create inputs:*/
+			counter=0;
+			for (i=0;i<numberofelements;i++){
+				if(this->my_elements[i]){
+					Element* element=(Element*)elements->GetObjectByOffset(counter);
+					if(defaulting) element->InputCreate(default_value,vector_enum,code); 
+					else           element->InputCreate(IssmDoublevector,i,this,M,N,vector_layout,vector_enum,code);//we need i to index into elements.
+					counter++;
+				}
+			}
+
+			break; /*}}}*/
+		default: /*{{{*/
+			_error2_("data code " << code << " not supported yet!");
+			break;
+			/*}}}*/
+	}
+	/*Free ressources:*/
+	xDelete<IssmDouble>(IssmDoublevector);
+	xDelete<char>(string);
+}
+/*FUNCTION IoModel::LastIndex{{{*/
+void IoModel::LastIndex(int *pindex){
+
+	extern int my_rank;
+	int        lastindex,index;
+	int        record_length;
+
+	/*Go find in the binary file, the position of the data we want to fetch: */
+	if(my_rank==0){
+
+		/*First set FILE* position to the beginning of the file: */
+		fseek(fid,0,SEEK_SET);
+
+		/*Now march through file looking for the correct data identifier: */
+		for(;;){
+			/*Read enum for this size of first string name: */
+			if(fread(&index,sizeof(int),1,fid)==0){
+				/*Ok, we have reached the end of the file. break: */
+				break;
+			}
+
+			/*read the record length, and use it to skip this record: */
+			fread(&record_length,sizeof(int),1,fid);
+			fseek(fid,record_length,SEEK_CUR);
+			lastindex=index;
+		}
+	}
+	/*Broadcast code and vector type: */
+#ifdef _HAVE_MPI_
+	MPI_Bcast(&lastindex,1,MPI_INT,0,MPI_COMM_WORLD); 
+#endif
+
+	/*Assign output pointers:*/
+	*pindex=lastindex;
+}
+/*FUNCTION IoModel::SetFilePointerToData{{{*/
+FILE* IoModel::SetFilePointerToData(int* pcode,int* pvector_type, int data_enum){
+
+	extern int my_rank;
+	extern int num_procs;
+
+	int found=0;
+	int record_enum;
+	int record_length;
+	int record_code; //1 to 7 number
+	int vector_type; //nodal or elementary
+
+	/*Go find in the binary file, the position of the data we want to fetch: */
+	if(my_rank==0){
+
+		/*First set FILE* position to the beginning of the file: */
+		fseek(fid,0,SEEK_SET);
+
+		/*Now march through file looking for the correct data identifier: */
+		for(;;){
+			/*Read enum for this size of first string name: */
+			if(fread(&record_enum,sizeof(int),1,fid)==0){
+				/*Ok, we have reached the end of the file. break: */
+				found=0;
+				break;
+			}
+
+			/*Is this the record sought for? : */
+			if (data_enum==record_enum){
+				/*Ok, we have found the correct string. Pass the record length, and read data type code: */
+				fseek(fid,sizeof(int),SEEK_CUR);
+				fread(&record_code,sizeof(int),1,fid);
+
+				/*if record_code points to a vector, get its type (nodal or elementary): */
+				if(5<=record_code && record_code<=7)fread(&vector_type,sizeof(int),1,fid);
+				found=1;
+				break;
+			}
+			else{
+				/*This is not the correct string, read the record length, and use it to skip this record: */
+				fread(&record_length,sizeof(int),1,fid);
+				/*skip: */
+				fseek(fid,record_length,SEEK_CUR);
+			}
+		}
+	}
+#ifdef _HAVE_MPI_
+	MPI_Bcast(&found,1,MPI_INT,0,MPI_COMM_WORLD); 
+	if(!found)_error2_("could not find data with name" << " " << EnumToStringx(data_enum) << " ");
+#endif
+
+	/*Broadcast code and vector type: */
+#ifdef _HAVE_MPI_
+	MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD); 
+	MPI_Bcast(&vector_type,1,MPI_INT,0,MPI_COMM_WORLD); 
+	if(record_code==5) MPI_Bcast(&vector_type,1,MPI_INT,0,MPI_COMM_WORLD); 
+#endif
+
+	/*Assign output pointers:*/
+	*pcode=record_code;
+	if(pvector_type)*pvector_type=vector_type;
+
+	return fid;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/IoModel.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/IoModel.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/IoModel.h	(revision 12822)
@@ -0,0 +1,67 @@
+/* \file IoModel.h
+ * \brief  Header file defining the IoModel structure that will help in processing the input data coming 
+ * into ISSM, from Matlab, or through a binary file opened for reading.
+ * \sa IoModel.cpp
+ */
+
+#ifndef _IOMODEL_H
+#define _IOMODEL_H
+
+#include "../include/include.h"
+#include "../EnumDefinitions/EnumDefinitions.h"
+
+class Elements;
+class Param;
+class Option;
+
+class IoModel {
+
+	private: 
+		IssmDouble **data;        //this dataset holds temporary data, memory intensive.
+		Parameters  *constants;   //this dataset holds all IssmDouble, int, bool and char *parameters read in from the input file.*
+
+	public:
+		/*This data needs to stay memory resident at all time, even if it's memory intensive: */
+		FILE *fid;         //pointer to input file
+		bool *my_elements;
+		bool *my_nodes;
+		int  *my_vertices;
+		int  *singlenodetoelementconnectivity;
+		int  *numbernodetoelementconnectivity;
+
+		/*Data to synchronize through low level object drivers: */
+		int nodecounter;         //keep track of how many nodes are being created in each analysis type
+		int loadcounter;         //keep track of how many loads are being created in each analysis type
+		int constraintcounter;   //keep track of how many constraints are being created in each analysis type
+
+		/*Methods*/
+		~IoModel();
+		IoModel();
+		IoModel(FILE* iomodel_handle);
+
+		/*Input/Output*/
+		void        CheckEnumSync(void);
+		void        Constant(bool *poutput,int constant_enum);
+		void        Constant(int *poutput,int constant_enum);
+		void        Constant(IssmDouble *poutput,int constant_enum);
+		void        Constant(char **poutput,int constant_enum);
+		Param      *CopyConstantObject(int constant_enum);
+		IssmDouble *Data(int dataenum);
+		void        DeleteData(int num,...);
+		void        FetchConstants(void);
+		void        FetchData(bool* pboolean,int data_enum);
+		void        FetchData(int* pinteger,int data_enum);
+		void        FetchData(IssmDouble* pscalar,int data_enum);
+		void        FetchData(char** pstring,int data_enum);
+		void        FetchData(int** pmatrix,int* pM,int* pN,int data_enum);
+		void        FetchData(IssmDouble**  pscalarmatrix,int* pM,int* pN,int data_enum);
+		void        FetchData(char***   pstringarray,int* pnumstrings,int data_enum);
+		void        FetchData(IssmDouble*** pmatrixarray,int** pmdims,int** pndims, int* pnumrecords,int data_enum);
+		void        FetchData(Option **poption,int data_enum);
+		void        FetchData(int num,...);
+		void        FetchDataToInput(Elements* elements,int vector_enum,int default_vector_enum=NoneEnum,IssmDouble default_value=0);
+		void        LastIndex(int *pindex);
+		FILE*       SetFilePointerToData(int* pcode,int* pvector_type, int data_enum);
+};
+
+#endif  /* _IOMODEL_H */
Index: /issm/trunk-jpl/src/c/classes/OptArgs.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/OptArgs.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/OptArgs.h	(revision 12822)
@@ -0,0 +1,13 @@
+/*!\file:  OptArgs.h
+ * \brief place holder for optimization function arguments
+ */ 
+
+#ifndef _OPTARGS_H_
+#define _OPTARGS_H_
+
+class Model;
+struct OptArgs{
+	FemModel* femmodel;
+};
+
+#endif
Index: /issm/trunk-jpl/src/c/classes/OptPars.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/OptPars.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/OptPars.h	(revision 12822)
@@ -0,0 +1,17 @@
+/*!\file:  OptPars.h
+ * \brief place holder for optimization parameters
+ */ 
+
+#ifndef _OPTPARS_H_
+#define _OPTPARS_H_
+
+struct OptPars{
+
+	IssmDouble xmin;
+	IssmDouble xmax;
+	IssmDouble cm_jump;
+	int maxiter;
+
+};
+
+#endif
Index: /issm/trunk-jpl/src/c/classes/gauss/GaussPenta.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/gauss/GaussPenta.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/gauss/GaussPenta.cpp	(revision 12822)
@@ -0,0 +1,406 @@
+/*!\file GaussPenta.c
+ * \brief: implementation of the GaussPenta object
+ */
+
+/*Include files: {{{*/
+#include "./../objects.h"
+/*}}}*/
+
+/*GaussPenta constructors and destructors:*/
+/*FUNCTION GaussPenta::GaussPenta() {{{*/
+GaussPenta::GaussPenta(){
+
+	numgauss=-1;
+
+	weights=NULL;
+	coords1=NULL;
+	coords2=NULL;
+	coords3=NULL;
+	coords4=NULL;
+
+	weight=UNDEF;
+	coord1=UNDEF;
+	coord2=UNDEF;
+	coord3=UNDEF;
+	coord4=UNDEF;
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussPenta(int order_horiz,int order_vert) {{{*/
+GaussPenta::GaussPenta(int order_horiz,int order_vert){
+
+	/*Intermediaries*/
+	int     ighoriz,igvert;
+	int     numgauss_horiz;
+	int     numgauss_vert;
+	double *coords1_horiz = NULL;
+	double *coords2_horiz = NULL;
+	double *coords3_horiz = NULL;
+	double *weights_horiz  = NULL;
+	double *coords_vert = NULL;
+	double *weights_vert   = NULL;
+
+	/*Get gauss points*/
+	GaussLegendreTria(&numgauss_horiz,&coords1_horiz,&coords2_horiz,&coords3_horiz,&weights_horiz,order_horiz);
+	GaussLegendreLinear(&coords_vert,&weights_vert,order_vert);
+	numgauss_vert=order_vert;
+
+	/*Allocate GaussPenta fields*/
+	numgauss=numgauss_horiz*numgauss_vert;
+	coords1=xNew<double>(numgauss);
+	coords2=xNew<double>(numgauss);
+	coords3=xNew<double>(numgauss);
+	coords4=xNew<double>(numgauss);
+	weights=xNew<double>(numgauss);
+
+	/*Combine Horizontal and vertical points*/
+	for (ighoriz=0; ighoriz<numgauss_horiz; ighoriz++){
+		for (igvert=0; igvert<numgauss_vert; igvert++){
+			coords1[numgauss_vert*ighoriz+igvert]=coords1_horiz[ighoriz];
+			coords2[numgauss_vert*ighoriz+igvert]=coords2_horiz[ighoriz];
+			coords3[numgauss_vert*ighoriz+igvert]=coords3_horiz[ighoriz];
+			coords4[numgauss_vert*ighoriz+igvert]=coords_vert[igvert];
+			weights[numgauss_vert*ighoriz+igvert]=weights_horiz[ighoriz]*weights_vert[igvert];
+		}
+	}
+
+	/*Initialize static fields as undefinite*/
+	weight=UNDEF;
+	coord1=UNDEF;
+	coord2=UNDEF;
+	coord3=UNDEF;
+	coord4=UNDEF;
+
+	/*Clean up*/
+	xDelete<double>(coords1_horiz);
+	xDelete<double>(coords2_horiz);
+	xDelete<double>(coords3_horiz);
+	xDelete<double>(coords_vert);
+	xDelete<double>(weights_horiz);
+	xDelete<double>(weights_vert);
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussPenta(int index1, int index2, int order){{{*/
+GaussPenta::GaussPenta(int index1, int index2,int order){
+
+	/*Intermediaties*/
+	double *seg_coords  = NULL;
+	double *seg_weights = NULL;
+	int     i;
+
+	/*Get Segment gauss points*/
+	numgauss=order;
+	GaussLegendreLinear(&seg_coords,&seg_weights,numgauss);
+
+	/*Allocate GaussPenta fields*/
+	coords1=xNew<double>(numgauss);
+	coords2=xNew<double>(numgauss);
+	coords3=xNew<double>(numgauss);
+	coords4=xNew<double>(numgauss);
+	weights=xNew<double>(numgauss);
+
+	if(index1==0 && index2==3){
+		for(i=0;i<numgauss;i++) coords1[i]=1.0;
+		for(i=0;i<numgauss;i++) coords2[i]=0.0;
+		for(i=0;i<numgauss;i++) coords3[i]=0.0;
+		for(i=0;i<numgauss;i++) coords4[i]=seg_coords[i];
+		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
+	}
+	else if (index1==1 && index2==4){
+		for(i=0;i<numgauss;i++) coords1[i]=0.0;
+		for(i=0;i<numgauss;i++) coords2[i]=1.0;
+		for(i=0;i<numgauss;i++) coords3[i]=0.0;
+		for(i=0;i<numgauss;i++) coords4[i]=seg_coords[i];
+		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
+	}
+	else if (index1==2 && index2==5){
+		for(i=0;i<numgauss;i++) coords1[i]=0.0;
+		for(i=0;i<numgauss;i++) coords2[i]=0.0;
+		for(i=0;i<numgauss;i++) coords3[i]=1.0;
+		for(i=0;i<numgauss;i++) coords4[i]=seg_coords[i];
+		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
+	}
+	else{
+		_error2_("Penta not supported yet");
+	}
+
+	/*Initialize static fields as undefined*/
+	weight=UNDEF;
+	coord1=UNDEF;
+	coord2=UNDEF;
+	coord3=UNDEF;
+	coord4=UNDEF;
+
+	/*clean up*/
+	xDelete<double>(seg_coords);
+	xDelete<double>(seg_weights);
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussPenta(int index1, int index2, int index3, int order){{{*/
+GaussPenta::GaussPenta(int index1, int index2, int index3, int order){
+
+	/*Basal Tria*/
+	if(index1==0 && index2==1 && index3==2){
+
+		/*Get GaussTria*/
+		GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
+
+		/*compute z coordinate*/
+		coords4=xNew<double>(numgauss);
+		for(int i=0;i<numgauss;i++) coords4[i]=-1.0;
+	}
+	/*Upper surface Tria*/
+	else if(index1==3 && index2==4 && index3==5){
+
+		/*Get GaussTria*/
+		GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
+
+		/*compute z coordinate*/
+		coords4=xNew<double>(numgauss);
+		for(int i=0;i<numgauss;i++) coords4[i]=1.0;
+	}
+	else{
+		_error2_("Tria not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussPenta(int index1, int index2, int index3, int index4,int order_horiz,int order_vert){{{*/
+GaussPenta::GaussPenta(int index1, int index2, int index3, int index4,int order_horiz,int order_vert){
+
+	/*Intermediaties*/
+	double *seg_horiz_coords  = NULL;
+	double *seg_horiz_weights = NULL;
+	double *seg_vert_coords   = NULL;
+	double *seg_vert_weights  = NULL;
+	int     i,j;
+
+	/*get the gauss points using the product of two line rules*/
+	GaussLegendreLinear(&seg_horiz_coords,&seg_horiz_weights,order_horiz);
+	GaussLegendreLinear(&seg_vert_coords, &seg_vert_weights, order_vert);
+
+	/*Allocate GaussPenta fields*/
+	numgauss=order_horiz*order_vert;
+	coords1=xNew<double>(numgauss);
+	coords2=xNew<double>(numgauss);
+	coords3=xNew<double>(numgauss);
+	coords4=xNew<double>(numgauss);
+	weights=xNew<double>(numgauss);
+
+	/*Quads: get the gauss points using the product of two line rules  */
+	if(index1==0 && index2==1 && index3==4 && index4==3){
+		for(i=0;i<order_horiz;i++){
+			for(j=0;j<order_vert;j++){
+				coords1[i*order_vert+j]=  0.5*(1-seg_horiz_coords[i]);
+				coords2[i*order_vert+j]=1-0.5*(1-seg_horiz_coords[i]);
+				coords3[i*order_vert+j]=0.0;
+				coords4[i*order_vert+j]=seg_vert_coords[j];
+				weights[i*order_vert+j]=seg_horiz_weights[i]*seg_vert_weights[j];
+			}
+		}
+	}
+	else if(index1==1 && index2==2 && index3==5 && index4==4){
+		for(i=0;i<order_horiz;i++){
+			for(j=0;j<order_vert;j++){
+				coords1[i*order_vert+j]=0.0;
+				coords2[i*order_vert+j]=  0.5*(1-seg_horiz_coords[i]);
+				coords3[i*order_vert+j]=1-0.5*(1-seg_horiz_coords[i]);
+				coords4[i*order_vert+j]=seg_vert_coords[j];
+				weights[i*order_vert+j]=seg_horiz_weights[i]*seg_vert_weights[j];
+			}
+		}
+	}
+	else if(index1==2 && index2==0 && index3==3 && index4==5){
+		for(i=0;i<order_horiz;i++){
+			for(j=0;j<order_vert;j++){
+				coords1[i*order_vert+j]=1-0.5*(1-seg_horiz_coords[i]);
+				coords2[i*order_vert+j]=0.0;
+				coords3[i*order_vert+j]=  0.5*(1-seg_horiz_coords[i]);
+				coords4[i*order_vert+j]=seg_vert_coords[j];
+				weights[i*order_vert+j]=seg_horiz_weights[i]*seg_vert_weights[j];
+			}
+		}
+	}
+	else{
+		_error2_("Tria not supported yet (user provided indices " << index1 << " " << index2 << " " << index3 << " " << index4 << ")");
+	}
+
+	/*clean-up*/
+	xDelete<double>(seg_horiz_coords);
+	xDelete<double>(seg_horiz_weights);
+	xDelete<double>(seg_vert_coords);
+	xDelete<double>(seg_vert_weights);
+}
+/*}}}*/
+/*FUNCTION GaussPenta::~GaussPenta(){{{*/
+GaussPenta::~GaussPenta(){
+	xDelete<double>(weights);
+	xDelete<double>(coords1);
+	xDelete<double>(coords2);
+	xDelete<double>(coords3);
+	xDelete<double>(coords4);
+}
+/*}}}*/
+
+/*Methods*/
+/*FUNCTION GaussPenta::Echo{{{*/
+void GaussPenta::Echo(void){
+
+	_printLine_("GaussPenta:");
+	_printLine_("   numgauss: " << numgauss);
+
+	if (weights){
+	 _printString_("   weights = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << weights[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("weights = NULL");
+	if (coords1){
+	 _printString_("   coords1 = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords1[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("coords1 = NULL");
+	if (coords2){
+	 _printString_("   coords2 = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords2[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("coords2 = NULL");
+	if (coords3){
+	 _printString_("   coords3 = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords3[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("coords3 = NULL");
+	if (coords4){
+		_printString_("   coords4 = ["); 
+		for(int i=0;i<numgauss;i++) _printLine_(" " << coords4[i]);
+		_printLine_("]");
+	}
+	else _printLine_("coords4 = NULL");
+
+	_printLine_("   weight = " << weight);
+	_printLine_("   coord1 = " << coord1);
+	_printLine_("   coord2 = " << coord2);
+	_printLine_("   coord3 = " << coord3);
+	_printLine_("   coord4 = " << coord4);
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussCenter{{{*/
+void GaussPenta::GaussCenter(void){
+
+	/*update static arrays*/
+	coord1=ONETHIRD;
+	coord2=ONETHIRD;
+	coord3=ONETHIRD;
+	coord4=0.0;
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussPoint{{{*/
+void GaussPenta::GaussPoint(int ig){
+
+	/*Check input in debugging mode*/
+	 _assert_(ig>=0 && ig< numgauss);
+
+	 /*update static arrays*/
+	 weight=weights[ig];
+	 coord1=coords1[ig];
+	 coord2=coords2[ig];
+	 coord3=coords3[ig];
+	 coord4=coords4[ig];
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussVertex{{{*/
+void GaussPenta::GaussVertex(int iv){
+
+	/*in debugging mode: check that the default constructor has been called*/
+	_assert_(numgauss==-1);
+
+	/*update static arrays*/
+	switch(iv){
+		case 0:
+			coord1=1; coord2=0; coord3=0; coord4= -1;
+			break;
+		case 1:
+			coord1=0; coord2=1; coord3=0; coord4= -1;
+			break;
+		case 2:
+			coord1=0; coord2=0; coord3=1; coord4= -1;
+			break;
+		case 3:
+			coord1=1; coord2=0; coord3=0; coord4= +1;
+			break;
+		case 4:
+			coord1=0; coord2=1; coord3=0; coord4= +1;
+			break;
+		case 5:
+			coord1=0; coord2=0; coord3=1; coord4= +1;
+			break;
+		default:
+			_error2_("vertex index should be in [0 5]");
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::GaussFaceTria{{{*/
+void GaussPenta::GaussFaceTria(int index1, int index2, int index3, int order){
+
+	/*in debugging mode: check that the default constructor has been called*/
+	_assert_(numgauss==-1);
+
+	/*Basal Tria*/
+	if(index1==0 && index2==1 && index3==2){
+		GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
+		coords4=xNew<double>(numgauss);
+		for(int i=0;i<numgauss;i++) coords4[i]=-1.0;
+	}
+	else{
+		_error2_("Tria not supported yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION GaussPenta::begin{{{*/
+int GaussPenta::begin(void){
+
+	/*Check that this has been initialized*/
+	_assert_(numgauss>0);
+	_assert_(weights);
+	_assert_(coords1);
+	_assert_(coords2);
+	_assert_(coords3);
+	_assert_(coords4);
+
+	/*return first gauss index*/
+	return 0;
+}
+/*}}}*/
+/*FUNCTION GaussPenta::end{{{*/
+int GaussPenta::end(void){
+
+	/*Check that this has been initialized*/
+	_assert_(numgauss>0);
+	_assert_(weights);
+	_assert_(coords1);
+	_assert_(coords2);
+	_assert_(coords3);
+	_assert_(coords4);
+
+	/*return last gauss index +1*/
+	return numgauss;
+}
+/*}}}*/
+/*FUNCTION GaussPenta::SynchronizeGaussTria{{{*/
+void GaussPenta::SynchronizeGaussTria(GaussTria* gauss_tria){
+
+	gauss_tria->coord1=this->coord1;
+	gauss_tria->coord2=this->coord2;
+	gauss_tria->coord3=this->coord3;
+	gauss_tria->weight=UNDEF;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/gauss/GaussPenta.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/gauss/GaussPenta.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/gauss/GaussPenta.h	(revision 12822)
@@ -0,0 +1,51 @@
+/*!\file GaussPenta.h
+ * \brief: header file for node object
+ */
+
+#ifndef _GAUSSPENTA_H_
+#define _GAUSSPENTA_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./../../shared/shared.h"
+class GaussTria;
+/*}}}*/
+
+class GaussPenta{
+
+	private:
+		int numgauss;
+		double* weights;
+		double* coords1;
+		double* coords2;
+		double* coords3;
+		double* coords4;
+
+	public:
+		double weight;
+		double coord1;
+		double coord2;
+		double coord3;
+		double coord4;
+		
+	public:
+
+		/*GaussPenta constructors, destructors*/
+		GaussPenta();
+		GaussPenta(int order_horiz,int order_vert);
+		GaussPenta(int index1, int index2,int order);
+		GaussPenta(int index1, int index2, int index3, int order);
+		GaussPenta(int index1, int index2, int index3, int index4,int order_horiz,int order_vert);
+		~GaussPenta();
+
+		/*Methods*/
+		int  begin(void);
+		int  end(void);
+		void Echo(void);
+		void GaussPoint(int ig);
+		void GaussVertex(int iv);
+		void GaussFaceTria(int index1, int index2, int index3, int order);
+		void GaussCenter(void);
+		void SynchronizeGaussTria(GaussTria* gauss_tria);
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/gauss/GaussTria.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/gauss/GaussTria.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/gauss/GaussTria.cpp	(revision 12822)
@@ -0,0 +1,278 @@
+/*!\file GaussTria.c
+ * \brief: implementation of the GaussTria object
+ */
+
+/*Include files: {{{*/
+#include "./../objects.h"
+/*}}}*/
+
+/*GaussTria constructors and destructors:*/
+/*FUNCTION GaussTria::GaussTria() {{{*/
+GaussTria::GaussTria(){
+
+	numgauss=-1;
+
+	weights=NULL;
+	coords1=NULL;
+	coords2=NULL;
+	coords3=NULL;
+
+	weight=UNDEF;
+	coord1=UNDEF;
+	coord2=UNDEF;
+	coord3=UNDEF;
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussTria(int order) {{{*/
+GaussTria::GaussTria(int order){
+
+	/*Get gauss points*/
+	GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
+
+	/*Initialize static fields as undefinite*/
+	weight=UNDEF;
+	coord1=UNDEF;
+	coord2=UNDEF;
+	coord3=UNDEF;
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussTria(int index1,int index2,int order) {{{*/
+GaussTria::GaussTria(int index1,int index2,int order){
+
+	/*Intermediaties*/
+	IssmPDouble *seg_coords  = NULL;
+	IssmPDouble *seg_weights = NULL;
+	int     i,index3;
+
+	/*Get Segment gauss points*/
+	numgauss=order;
+	GaussLegendreLinear(&seg_coords,&seg_weights,numgauss);
+
+	/*Allocate GaussTria fields*/
+	coords1=xNew<IssmPDouble>(numgauss);
+	coords2=xNew<IssmPDouble>(numgauss);
+	coords3=xNew<IssmPDouble>(numgauss);
+	weights=xNew<IssmPDouble>(numgauss);
+
+	/*Reverse index1 and 2 if necessary*/
+	if (index1>index2){
+		index3=index1; index1=index2; index2=index3;
+		for(i=0;i<numgauss;i++) seg_coords[i]=-seg_coords[i];
+	}
+
+	/*Build Triangle Gauss point*/
+	if (index1==0 && index2==1){
+		for(i=0;i<numgauss;i++) coords1[i]=  0.5*(1-seg_coords[i]);
+		for(i=0;i<numgauss;i++) coords2[i]=1-0.5*(1.-seg_coords[i]);
+		for(i=0;i<numgauss;i++) coords3[i]=0;
+		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
+	}
+	else if (index1==0 && index2==2){
+		for(i=0;i<numgauss;i++) coords1[i]=  0.5*(1-seg_coords[i]);
+		for(i=0;i<numgauss;i++) coords2[i]= 0 ;
+		for(i=0;i<numgauss;i++) coords3[i]=1-0.5*(1.-seg_coords[i]);
+		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
+	}
+	else if (index1==1 && index2==2){
+		for(i=0;i<numgauss;i++) coords1[i]=0;
+		for(i=0;i<numgauss;i++) coords2[i]=  0.5*(1-seg_coords[i]);
+		for(i=0;i<numgauss;i++) coords3[i]=1-0.5*(1.-seg_coords[i]);
+		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
+	}
+	else
+	 _error2_("The 2 indices provided are not supported yet (user provided " << index1 << " and " << index2 << ")");
+
+	/*Initialize static fields as undefined*/
+	weight=UNDEF;
+	coord1=UNDEF;
+	coord2=UNDEF;
+	coord3=UNDEF;
+
+	/*clean up*/
+	xDelete<double>(seg_coords);
+	xDelete<double>(seg_weights);
+}
+/*}}}*/
+/*FUNCTION GaussTria::~GaussTria(){{{*/
+GaussTria::~GaussTria(){
+	xDelete<IssmPDouble>(weights);
+	xDelete<IssmPDouble>(coords1);
+	xDelete<IssmPDouble>(coords2);
+	xDelete<IssmPDouble>(coords3);
+}
+/*}}}*/
+
+/*Methods*/
+/*FUNCTION GaussTria::Echo{{{*/
+void GaussTria::Echo(void){
+
+	_printLine_("GaussTria:");
+	_printLine_("   numgauss: " << numgauss);
+
+	if (weights){
+	 _printString_("   weights = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << weights[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("weights = NULL");
+	if (coords1){
+	 _printString_("   coords1 = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords1[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("coords1 = NULL");
+	if (coords2){
+	 _printString_("   coords2 = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords2[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("coords2 = NULL");
+	if (coords3){
+	 _printString_("   coords3 = ["); 
+	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords3[i]);
+	 _printLine_("]");
+	}
+	else _printLine_("coords3 = NULL");
+
+	_printLine_("   weight = " << weight);
+	_printLine_("   coord1 = " << coord1);
+	_printLine_("   coord2 = " << coord2);
+	_printLine_("   coord3 = " << coord3);
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussCenter{{{*/
+void GaussTria::GaussCenter(void){
+
+	/*update static arrays*/
+	coord1=ONETHIRD;
+	coord2=ONETHIRD;
+	coord3=ONETHIRD;
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussEdgeCenter{{{*/
+void GaussTria::GaussEdgeCenter(int index1,int index2){
+
+	int     index3;
+
+	/*Reverse index1 and 2 if necessary*/
+	if (index1>index2){
+		index3=index1; index1=index2; index2=index3;
+	}
+
+	/*update static arrays*/
+	if (index1==0 && index2==1){
+		coord1=0.5;
+		coord2=0.5;
+		coord3=0.0;
+	}
+	else if (index1==0 && index2==2){
+		coord1=0.5;
+		coord2=0.0;
+		coord3=0.5;
+	}
+	else if (index1==1 && index2==2){
+		coord1=0.0;
+		coord2=0.5;
+		coord3=0.5;
+	}
+	else
+	 _error2_("The 2 indices provided are not supported yet (user provided " << index1 << " and " << index2 << ")");
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussPoint{{{*/
+void GaussTria::GaussPoint(int ig){
+
+	/*Check input in debugging mode*/
+	 _assert_(ig>=0 && ig< numgauss);
+
+	 /*update static arrays*/
+	 weight=weights[ig];
+	 coord1=coords1[ig];
+	 coord2=coords2[ig];
+	 coord3=coords3[ig];
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussFromCoords{{{*/
+void GaussTria::GaussFromCoords(IssmPDouble x,IssmPDouble y,IssmPDouble* xyz_list){
+
+	/*Intermediaries*/
+	IssmPDouble    area = 0;
+	IssmPDouble    x1,y1,x2,y2,x3,y3;
+
+	/*in debugging mode: check that the default constructor has been called*/
+	_assert_(numgauss==-1);
+
+	x1=*(xyz_list+3*0+0); y1=*(xyz_list+3*0+1);
+	x2=*(xyz_list+3*1+0); y2=*(xyz_list+3*1+1);
+	x3=*(xyz_list+3*2+0); y3=*(xyz_list+3*2+1);
+
+	area=(x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
+
+	/*Get first area coordinate = det(x-x3  x2-x3 ; y-y3   y2-y3)/area*/
+	coord1=((x-x3)*(y2-y3)-(x2-x3)*(y-y3))/area;
+
+	/*Get second area coordinate = det(x1-x3  x-x3 ; y1-y3   y-y3)/area*/
+	coord2=((x1-x3)*(y-y3)-(x-x3)*(y1-y3))/area;
+
+	/*Get third  area coordinate 1-area1-area2: */
+	coord3=1-coord1-coord2;
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::GaussVertex{{{*/
+void GaussTria::GaussVertex(int iv){
+
+	/*in debugging mode: check that the default constructor has been called*/
+	_assert_(numgauss==-1);
+
+	/*update static arrays*/
+	switch(iv){
+		case 0:
+			coord1=1; coord2=0; coord3=0;
+			break;
+		case 1:
+			coord1=0; coord2=1; coord3=0;
+			break;
+		case 2:
+			coord1=0; coord2=0; coord3=1;
+			break;
+		default:
+			_error2_("vertex index should be in [0 2]");
+
+	}
+
+}
+/*}}}*/
+/*FUNCTION GaussTria::begin{{{*/
+int GaussTria::begin(void){
+
+	/*Check that this has been initialized*/
+	_assert_(numgauss>0);
+	_assert_(weights);
+	_assert_(coords1);
+	_assert_(coords2);
+	_assert_(coords3);
+
+	/*return first gauss index*/
+	return 0;
+}
+/*}}}*/
+/*FUNCTION GaussTria::end{{{*/
+int GaussTria::end(void){
+
+	/*Check that this has been initialized*/
+	_assert_(numgauss>0);
+	_assert_(weights);
+	_assert_(coords1);
+	_assert_(coords2);
+	_assert_(coords3);
+
+	/*return last gauss index +1*/
+	return numgauss;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/gauss/GaussTria.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/gauss/GaussTria.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/gauss/GaussTria.h	(revision 12822)
@@ -0,0 +1,46 @@
+/*!\file GaussTria.h
+ * \brief: header file for node object
+ */
+
+#ifndef _GAUSSTRIA_H_
+#define _GAUSSTRIA_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./../../shared/shared.h"
+/*}}}*/
+
+class GaussTria{
+
+	private:
+		int numgauss;
+		IssmPDouble* weights;
+		IssmPDouble* coords1;
+		IssmPDouble* coords2;
+		IssmPDouble* coords3;
+
+	public:
+		IssmPDouble weight;
+		IssmPDouble coord1;
+		IssmPDouble coord2;
+		IssmPDouble coord3;
+		
+	public:
+
+		/*GaussTria constructors, destructors*/
+		GaussTria();
+		GaussTria(int order);
+		GaussTria(int index1,int index2,int order);
+		~GaussTria();
+
+		/*Methods*/
+		int  begin(void);
+		int  end(void);
+		void Echo(void);
+		void GaussFromCoords(IssmPDouble x1,IssmPDouble y1,IssmPDouble* xyz_list);
+		void GaussPoint(int ig);
+		void GaussVertex(int iv);
+		void GaussCenter(void);
+		void GaussEdgeCenter(int index1,int index2);
+};
+#endif  /* _GAUSSTRIA_H_ */
Index: /issm/trunk-jpl/src/c/classes/objects/Constraints/Constraint.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/Constraint.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/Constraint.h	(revision 12822)
@@ -0,0 +1,28 @@
+/*!\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/objects/Constraints/SpcDynamic.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcDynamic.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcDynamic.cpp	(revision 12822)
@@ -0,0 +1,141 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../Container/Container.h"
+#include "../objects.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::MyRank {{{*/
+int    SpcDynamic::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Constraints/SpcDynamic.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcDynamic.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcDynamic.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*!\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   MyRank();
+		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/objects/Constraints/SpcStatic.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcStatic.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcStatic.cpp	(revision 12822)
@@ -0,0 +1,129 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../Container/Container.h"
+#include "../objects.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::MyRank {{{*/
+int    SpcStatic::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Constraints/SpcStatic.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcStatic.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcStatic.h	(revision 12822)
@@ -0,0 +1,50 @@
+/*!\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   MyRank();
+		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/objects/Constraints/SpcTransient.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcTransient.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcTransient.cpp	(revision 12822)
@@ -0,0 +1,176 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../Container/Container.h"
+#include "../objects.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::MyRank {{{*/
+int    SpcTransient::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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)_error2_("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/objects/Constraints/SpcTransient.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcTransient.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Constraints/SpcTransient.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*!\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   MyRank();
+		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/objects/ElementResults/BoolElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/BoolElementResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/BoolElementResult.cpp	(revision 12822)
@@ -0,0 +1,136 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "./ElementResultLocal.h"
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    BoolElementResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	_error2_("cannot return vector on vertices");
+} /*}}}*/
+/*FUNCTION BoolElementResult::GetElementVectorFromResults{{{*/
+void BoolElementResult::GetElementVectorFromResults(Vector* vector,int dof){
+
+	vector->SetValue(dof,value,INS_VAL);
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/BoolElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/BoolElementResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/BoolElementResult.h	(revision 12822)
@@ -0,0 +1,54 @@
+/*! \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"
+#include "../../include/include.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   MyRank();
+		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* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector* vector,int dof);
+		/*}}}*/
+};
+#endif  /* _BOOLELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/DoubleElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/DoubleElementResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/DoubleElementResult.cpp	(revision 12822)
@@ -0,0 +1,137 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "./ElementResultLocal.h"
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DoubleElementResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	_error_("cannot return vector on vertices");
+} /*}}}*/
+/*FUNCTION DoubleElementResult::GetElementVectorFromResults{{{1*/
+void DoubleElementResult::GetElementVectorFromResults(Vector* vector,int dof){
+
+	vector->SetValue(dof,value,INS_VAL);
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/DoubleElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/DoubleElementResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/DoubleElementResult.h	(revision 12822)
@@ -0,0 +1,54 @@
+/*! \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"
+#include "../../include/include.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   MyRank();
+		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* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector* vector,int dof);
+		/*}}}*/
+};
+#endif  /* _DOUBLEELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/ElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/ElementResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/ElementResult.h	(revision 12822)
@@ -0,0 +1,32 @@
+/*!\file:  ElementResult.h
+ * \brief abstract class for ElementResult object
+ */ 
+
+
+#ifndef _ELEMENTRESULT_H_
+#define _ELEMENTRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Object.h"
+/*}}}*/
+
+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* vector,int* doflist,int* connectivitylist,int numdof)=0;
+		virtual void    GetElementVectorFromResults(Vector* vector,int dof)=0;
+
+};
+
+#endif
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/ElementResultLocal.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/ElementResultLocal.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/ElementResultLocal.h	(revision 12822)
@@ -0,0 +1,11 @@
+/*!\file: ElementResultLocal.h
+ * \brief prototypes for ElementResultLocal.h
+ */ 
+
+#ifndef _ELEMENTRESULTLOCAL_H_
+#define  _ELEMENTRESULTLOCAL_H_
+
+class Parameters;
+
+#endif //ifndef _ELEMENTRESULTLOCAL_H_
+
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/PentaP1ElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/PentaP1ElementResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/PentaP1ElementResult.cpp	(revision 12822)
@@ -0,0 +1,153 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "./ElementResultLocal.h"
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    PentaP1ElementResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	IssmDouble data[6];
+
+	if(numdofs!=6)_error2_("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* vector,int dof){
+
+	_error2_("Result " << EnumToStringx(enum_type) << " is a PentaP1ElementResult and should not write vector of size numberofelemenrs");
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/PentaP1ElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/PentaP1ElementResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/PentaP1ElementResult.h	(revision 12822)
@@ -0,0 +1,54 @@
+/*! \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"
+#include "../../include/include.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   MyRank();
+		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* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector* vector,int dof);
+		/*}}}*/
+
+};
+#endif  /* _PENTAP1ELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/TriaP1ElementResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/TriaP1ElementResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/TriaP1ElementResult.cpp	(revision 12822)
@@ -0,0 +1,140 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "./ElementResultLocal.h"
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    TriaP1ElementResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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* vector,int* doflist,int* connectivitylist,int numdofs){
+
+	IssmDouble data[3];
+
+	if(numdofs!=3)_error2_("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* vector,int dof){
+	_error2_("Result " << EnumToStringx(enum_type) << " is a TriaP1ElementResult and should not write vector of size numberofelemenrs");
+} /*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ElementResults/TriaP1ElementResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ElementResults/TriaP1ElementResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ElementResults/TriaP1ElementResult.h	(revision 12822)
@@ -0,0 +1,53 @@
+/*! \file TriaP1ElementResult.h 
+ *  \brief: header file for TriaP1ElementResult object
+ */
+
+
+#ifndef _TRIAP1ELEMENTRESULT_H_
+#define _TRIAP1ELEMENTRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../Inputs/Input.h"
+#include "../../include/include.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   MyRank();
+		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* vector,int* doflist,int* connectivitylist,int numdofs);
+		void GetElementVectorFromResults(Vector* vector,int dof);
+		/*}}}*/
+
+};
+#endif  /* _TRIAP1ELEMENTRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/Element.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/Element.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/Element.h	(revision 12822)
@@ -0,0 +1,117 @@
+/*!\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"
+
+class DataSet;
+class Parameters;
+class Patch;
+class Matrix;
+class Vector;
+
+#include "../../toolkits/toolkits.h"
+/*}}}*/
+
+class Element: public Object,public Update{
+
+	public: 
+		
+		virtual        ~Element(){};
+	
+		virtual void   Configure(Elements* elements,Loads* loads,DataSet* nodes,Materials* materials,Parameters* parameters)=0;
+		virtual void   SetCurrentConfiguration(Elements* elements,Loads* loads,DataSet* nodes,Materials* materials,Parameters* parameters)=0;
+		virtual void   CreateKMatrix(Matrix* Kff, Matrix*  Kfs,Vector* df)=0;
+		virtual void   CreatePVector(Vector* pf)=0;
+		virtual void   CreateJacobianMatrix(Matrix* Jff)=0;
+		virtual void   GetSolutionFromInputs(Vector* solution)=0;
+		virtual int    GetNodeIndex(Node* node)=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* sigma_b)=0;
+		virtual void   ComputeStrainRate(Vector* 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* vector, int name_enum)=0;
+		virtual void   GetVectorFromResults(Vector* 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* partition_contributions,Vector* 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   PotentialSheetUngrounding(Vector* 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    UpdatePotentialSheetUngrounding(IssmDouble* potential_sheet_ungrounding,Vector* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf)=0;
+		virtual void   ResetCoordinateSystem()=0;
+		virtual void   SmearFunction(Vector* 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_CONTROL_
+		virtual void   Gradj(Vector* 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 RheologyBbarAbsGradient(bool process_units,int weight_index)=0;
+		virtual IssmDouble DragCoefficientAbsGradient(bool process_units,int weight_index)=0;
+		virtual void   ControlInputGetGradient(Vector* 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* 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
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/Penta.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/Penta.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/Penta.cpp	(revision 12822)
@@ -0,0 +1,8784 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../Container/Container.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES   6
+#define NUMVERTICES2D 3
+
+/*Constructors/destructor/copy*/
+/*FUNCTION Penta::Penta(){{{*/
+Penta::Penta(){
+
+	int i;
+
+	this->nodes=NULL;
+	this->matice=NULL;
+	this->matpar=NULL;
+	this->verticalneighbors=NULL;
+	this->inputs=NULL;
+	this->parameters=NULL;
+	this->results=NULL;
+	for(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: matice 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])) penta_elements_ids[1]=this->id; //upper penta is the same penta
+	else                                    penta_elements_ids[1]=(int)(iomodel->Data(MeshUpperelementsEnum)[index]);
+	if (xIsNan<IssmDouble>(iomodel->Data(MeshLowerelementsEnum)[index])) penta_elements_ids[0]=this->id; //lower penta is the same penta
+	else                                    penta_elements_ids[0]=(int)(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]=(int)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->matice=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->hmatice=(Hook*)this->hmatice->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->matice=(Matice*)penta->hmatice->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* partition_contributions,Vector* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part){
+	_error2_("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,ig;
+	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(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* sigma_b){
+
+	int         i,j,ig;
+	int         dofv[3]={0,1,2};
+	int         dofp[1]={3};
+	int         analysis_type,approximation;
+	int         doflist[NUMVERTICES];
+	IssmDouble      xyz_list[NUMVERTICES][3];
+	IssmDouble      xyz_list_tria[3][3];
+	IssmDouble      rho_ice,gravity,stokesreconditioning;
+	IssmDouble      pressure,viscosity,bed,Jdet2d;
+	IssmDouble      bed_normal[3];
+	IssmDouble      basalforce[3];
+	IssmDouble      epsilon[6]; /* epsilon=[exx,eyy,ezz,exy,exz,eyz];*/
+	IssmDouble      devstresstensor[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) _error2_("Not supported yet!");
+	if (approximation!=StokesApproximationEnum) _error2_("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], nodes, 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 (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);
+		matice->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* eps){
+
+	_error2_("Not implemented yet");
+
+}
+/*}}}*/
+/*FUNCTION Penta::ComputeStressTensor {{{*/
+void  Penta::ComputeStressTensor(){
+
+	int         iv;
+	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], nodes, 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);
+		matice->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, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+
+	int analysis_counter;
+	
+	/*go into parameters and get the analysis_counter: */
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective 
+	 * datasets, using internal ids and offsets hidden in hooks: */
+	if (this->hnodes[analysis_counter]) this->hnodes[analysis_counter]->configure(nodesin);
+	this->hmatice->configure(materialsin);
+	this->hmatpar->configure(materialsin);
+	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->matice=(Matice*)this->hmatice->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* Kff, Matrix* Kfs,Vector* df){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	ElementVector* De=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->matice && 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(); De=CreateDVectorDiagnosticHoriz();
+			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=CreateKMatrixSlope();
+			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:
+			_error2_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(Ke){
+		Ke->AddToGlobal(Kff,Kfs);
+		delete Ke;
+	}
+	/*Add to global Vector*/
+	if(De){
+		De->InsertIntoGlobal(df);
+		delete De;
+	}
+}
+/*}}}*/
+/*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->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixSlope {{{*/
+ElementMatrix* Penta::CreateKMatrixSlope(void){
+
+	if (!IsOnBed()) return NULL;
+
+	Tria* tria=(Tria*)SpawnTria(0,1,2); //nodes 0, 1 and 2 make the new tria.
+	ElementMatrix* Ke=tria->CreateKMatrixSlope();
+	delete tria->matice; delete tria;
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVector {{{*/
+void  Penta::CreatePVector(Vector* 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->matice && 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:
+			_error2_("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->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreatePVectorSlope {{{*/
+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->matice; delete tria;
+
+	/*clean up and return*/
+	return pe;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianMatrix{{{*/
+void  Penta::CreateJacobianMatrix(Matrix* Jff){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->matice && 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:
+			_error2_("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){
+
+	int i;
+	
+	_printLine_("Penta:");
+	_printLine_("   id: " << id);
+	nodes[0]->DeepEcho();
+	nodes[1]->DeepEcho();
+	nodes[2]->DeepEcho();
+	nodes[3]->DeepEcho();
+	nodes[4]->DeepEcho();
+	nodes[5]->DeepEcho();
+	matice->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]);
+
+	return;
+}
+/*}}}*/
+/*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){
+
+	IssmDouble monthlytemperatures[NUMVERTICES][12],monthlyprec[NUMVERTICES][12];
+	IssmDouble TemperaturesPresentday[NUMVERTICES][12],TemperaturesLgm[NUMVERTICES][12];
+	IssmDouble PrecipitationsPresentday[NUMVERTICES][12];
+	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);
+			monthlyprec[iv][month]=monthlyprec[iv][month]*yts; // convertion to m/yr
+		}
+	}
+
+	/*Recover delta18o and Delta18oSurface at present day, lgm and at time t*/
+	this->parameters->FindParam(&Delta18oPresent,SurfaceforcingsDelta18oEnum,finaltime*yts);
+	this->parameters->FindParam(&Delta18oLgm,SurfaceforcingsDelta18oEnum,(finaltime-21000)*yts);
+	this->parameters->FindParam(&Delta18oTime,SurfaceforcingsDelta18oEnum,time*yts);
+	this->parameters->FindParam(&Delta18oSurfacePresent,SurfaceforcingsDelta18oSurfaceEnum,finaltime*yts);
+	this->parameters->FindParam(&Delta18oSurfaceLgm,SurfaceforcingsDelta18oSurfaceEnum,(finaltime-21000)*yts);
+	this->parameters->FindParam(&Delta18oSurfaceTime,SurfaceforcingsDelta18oSurfaceEnum,time*yts);
+
+	/*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(int iv=0;iv<NUMVERTICES;iv++) {
+			PentaP1Input* newmonthinput1 = new PentaP1Input(SurfaceforcingsMonthlytemperaturesEnum,&monthlytemperatures[iv][imonth]);
+			NewTemperatureInput->AddTimeInput(newmonthinput1,imonth/12.*yts);
+			PentaP1Input* newmonthinput2 = new PentaP1Input(SurfaceforcingsPrecipitationEnum,&monthlyprec[iv][imonth]);
+			NewPrecipitationInput->AddTimeInput(newmonthinput2,imonth/12.*yts);
+		}
+	}
+	this->inputs->AddInput(NewTemperatureInput);
+	this->inputs->AddInput(NewPrecipitationInput);
+
+	/*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,j,count=0;
+	int  numberofdofs=0;
+	int* doflist=NULL;
+
+	/*First, figure out size of doflist: */
+	for(i=0;i<6;i++) numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+
+	/*Allocate: */
+	doflist=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::GetDofList1 {{{*/
+void  Penta::GetDofList1(int* doflist){
+
+	int i;
+	for(i=0;i<6;i++) doflist[i]=nodes[i]->GetDofList1();
+
+}
+/*}}}*/
+/*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],nodes,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;
+	}
+	_error2_("Node provided not found among element nodes");
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetInputListOnVertices(IssmDouble* pvalue,int enumtype) {{{*/
+void Penta::GetInputListOnVertices(IssmDouble* pvalue,int enumtype){
+
+	/*Intermediaries*/
+	IssmDouble     value[NUMVERTICES];
+	GaussPenta *gauss              = NULL;
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+	if (!input) _error2_("Input " << EnumToStringx(enumtype) << " not found in element");
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	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){
+
+	/*Intermediaries*/
+	IssmDouble     value[NUMVERTICES];
+	GaussPenta *gauss              = NULL;
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		gauss=new GaussPenta();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&pvalue[iv],gauss);
+		}
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*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) _error2_("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::GetSidList{{{*/
+void  Penta::GetSidList(int* sidlist){
+
+	int i;
+	for(i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
+
+}
+/*}}}*/
+/*FUNCTION Penta::GetSolutionFromInputs{{{*/
+void  Penta::GetSolutionFromInputs(Vector* 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:
+		_error2_("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){
+		_error2_("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){
+		_error2_("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* vector,int input_enum){
+
+	int doflist1[NUMVERTICES];
+
+	/*Get out if this is not an element input*/
+	if (!IsInput(input_enum)) return;
+
+	/*Prepare index list*/
+	this->GetDofList1(&doflist1[0]);
+
+	/*Get input (either in element or material)*/
+	Input* input=inputs->GetInput(input_enum);
+	if(!input) _error2_("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,&doflist1[0]);
+}
+/*}}}*/
+/*FUNCTION Penta::GetVectorFromResults{{{*/
+void  Penta::GetVectorFromResults(Vector* 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 %i is %s, when %s was expected",offset,EnumToStringx(elementresult->InstanceEnum()),EnumToStringx(enum_in));
+	}  
+	if(interp==P1Enum){
+		int doflist1[NUMVERTICES];
+		int connectivity[NUMVERTICES];
+		this->GetSidList(&doflist1[0]);
+		this->GetConnectivityList(&connectivity[0]);
+		elementresult->GetVectorFromResults(vector,&doflist1[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], nodes, 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)_error2_("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])_error2_("could not find input with enum " << EnumToStringx(enums[2*i+0]));
+		if(!old_inputs[i])_error2_("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,(bool)scalar));
+	}
+	else if ((code==6) || (code==2)){ //integer
+		this->inputs->AddInput(new IntInput(name,(int)scalar));
+	}
+	else if ((code==7) || (code==3)){ //IssmDouble
+		this->inputs->AddInput(new DoubleInput(name,(IssmDouble)scalar));
+	}
+	else _error2_("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,j,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]=(int)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 _error2_("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,(bool)vector[index]));
+			}
+			else if (code==6){ //integer
+				this->inputs->AddInput(new IntInput(vector_enum,(int)vector[index]));
+			}
+			else if (code==7){ //IssmDouble
+				this->inputs->AddInput(new DoubleInput(vector_enum,(IssmDouble)vector[index]));
+			}
+			else _error2_("could not recognize nature of vector from code " << code);
+		}
+		else {
+			_error2_("transient elementary inputs not supported yet!");
+		}
+	}
+	else{
+		_error2_("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->matice->inputs->GetInput(enum_type);
+		else
+		 _error2_("object " << EnumToStringx(object_enum) << " not supported yet");
+		if(!original_input) _error2_("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
+			 _error2_("object " << EnumToStringx(original_input->ObjectEnum()) << " not supported yet");
+		}
+
+		/*Step2: Create element thickness input*/
+		GetVerticesCoordinates(&xyz_list[0][0],penta->nodes,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->matice->inputs->AddInput((Input*)depth_averaged_input);
+	else
+	 _error2_("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*)matice->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{
+		_error2_("object of type " << EnumToStringx(object_type) << " not supported yet");
+	}
+	for(i=0;i<num_inputs;i++){
+		if(!base_inputs[i]) _error2_("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->matice->inputs->AddInput((Input*)copy);
+			}
+			else if(object_type==NodeEnum){
+				penta->nodes[i+3]->inputs->AddInput((Input*)copy); //change only the three upper nodes
+			}
+			else{
+				_error2_("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)_error2_("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){
+
+	int    i;
+	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->matice->inputs->GetInput(MaterialsRheologyBEnum);
+	else input=this->inputs->GetInput(enum_type);
+	//if (!input) _error2_("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]=(int)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((int)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:
+					/*Matice will take care of it*/ break;
+				default:
+					_error2_("Control " << EnumToStringx((int)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)==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{
+			_error2_("Approximation type " << EnumToStringx((int)*(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: 
+		_error2_("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])) _error2_("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 _error2_("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])) _error2_("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])) _error2_("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]->GetVertexDof()];
+			}
+
+			/*update input*/
+			this->inputs->AddInput(new PentaP1Input(name,values));
+			return;
+
+		default:
+
+			_error2_("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){
+	_error2_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVector(bool* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVector(bool* vector, int name, int type){
+	_error2_("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==GradientEnum ||
+				name==OldGradientEnum  ||
+				name==ConvergedEnum || 
+				name==QmuVxEnum ||
+				name==QmuVyEnum ||
+				name==QmuPressureEnum ||
+				name==QmuBedEnum ||
+				name==QmuThicknessEnum ||
+				name==QmuSurfaceEnum ||
+				name==QmuTemperatureEnum ||
+				name==QmuMeltingEnum
+				) {
+		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 (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,unground;
+	bool    elementonshelf = false;
+	IssmDouble  bed_hydro,yts,gl_melting_rate;
+	IssmDouble  rho_water,rho_ice,density;
+	IssmDouble  melting[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(&yts,ConstantsYtsEnum);
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&s[0],SurfaceEnum);
+	GetInputListOnVertices(&b[0],BedEnum);
+	GetInputListOnVertices(&ba[0],BathymetryEnum);
+	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(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){
+					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 && 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));
+				}
+			}
+		}
+	}
+
+	/*If at least one vertex is now floating, the element is now floating*/
+	for(i=0;i<NUMVERTICES;i++){
+		if(nodes[i]->IsFloating()){
+			elementonshelf=true;
+			break;
+		}
+	}
+	
+   /*Add basal melting rate if element just ungrounded*/
+	if(!this->IsFloating() && elementonshelf==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,elementonshelf));
+
+	/*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::MyRank {{{*/
+int    Penta::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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;
+
+   /*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();
+
+   /*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);
+   }
+
+   /*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::PotentialSheetUngrounding{{{*/
+void  Penta::PotentialSheetUngrounding(Vector* potential_sheet_ungrounding){
+
+	int     i;
+	IssmDouble  h[NUMVERTICES],ba[NUMVERTICES];
+	IssmDouble  bed_hydro;
+	IssmDouble  rho_water,rho_ice,density;
+	bool    elementonshelf = false;
+
+	/*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_sheet_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){
+
+	_error2_("not implemented yet");
+}
+/*}}}*/
+/*FUNCTION Penta::SetCurrentConfiguration {{{*/
+void  Penta::SetCurrentConfiguration(Elements* elementsin, Loads* loadsin, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+
+	int analysis_counter;
+
+	/*go into parameters and get the analysis_counter: */
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*Pick up nodes */
+	if (this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
+	else this->nodes=NULL;
+}
+/*}}}*/
+/*FUNCTION Penta::SpawnTria {{{*/
+Tria*  Penta::SpawnTria(int g0, int g1, int g2){
+
+	int   i,analysis_counter;
+	int   indices[3];
+	int   zero=0;
+	Tria*       tria            = NULL;
+	Inputs*     tria_inputs     = NULL;
+	Results*    tria_results    = NULL;
+	Parameters* tria_parameters = NULL;
+
+	/*go into parameters and get the analysis_counter: */
+	this->parameters->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	indices[0]=g0;
+	indices[1]=g1;
+	indices[2]=g2;
+
+	tria_parameters=this->parameters;
+	tria_inputs=(Inputs*)this->inputs->SpawnTriaInputs(indices);
+	tria_results=(Results*)this->results->SpawnTriaResults(indices);
+
+	tria=new Tria();
+	tria->id=this->id;
+	tria->inputs=tria_inputs;
+	tria->results=tria_results;
+	tria->parameters=tria_parameters;
+	tria->element_type=P1Enum; //Only P1 CG for now (TO BE CHANGED)
+	this->SpawnTriaHook(dynamic_cast<TriaHook*>(tria),&indices[0]);
+
+	/*Spawn matice*/
+	tria->matice=NULL;
+	tria->matice=(Matice*)this->matice->copy();
+	delete tria->matice->inputs;
+	tria->matice->inputs=(Inputs*)this->matice->inputs->SpawnTriaInputs(indices);
+
+	/*recover nodes, matice and matpar: */
+	tria->nodes=(Node**)tria->hnodes[analysis_counter]->deliverp();
+	tria->matpar=(Matpar*)tria->hmatpar->delivers();
+
+	return tria;
+}
+/*}}}*/
+/*FUNCTION Penta::SmbGradients{{{*/
+void Penta::SmbGradients(void){
+
+	int i;
+
+	// input
+   IssmDouble h[NUMVERTICES];					// ice thickness (m)		
+	IssmDouble s[NUMVERTICES];					// surface elevation (m)
+	IssmDouble a_pos[NUMVERTICES];				// Hs-SMB relation parameter 
+	IssmDouble b_pos[NUMVERTICES];				// Hs-SMB relation parameter
+	IssmDouble a_neg[NUMVERTICES];				// Hs-SMB relation parameter
+	IssmDouble b_neg[NUMVERTICES];				// Hs-SMB relation paremeter
+	IssmDouble Hc[NUMVERTICES];					// elevation of transition between accumulation regime and ablation regime
+	IssmDouble smb_pos_max[NUMVERTICES];		// maximum SMB value in the accumulation regime
+	IssmDouble smb_pos_min[NUMVERTICES];		// minimum SMB value in the accumulation regime
+   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(&Hc[0],SurfaceforcingsHcEnum);
+	GetInputListOnVertices(&smb_pos_max[0],SurfaceforcingsSmbPosMaxEnum);
+	GetInputListOnVertices(&smb_pos_min[0],SurfaceforcingsSmbPosMinEnum);
+	GetInputListOnVertices(&a_pos[0],SurfaceforcingsAPosEnum);
+	GetInputListOnVertices(&b_pos[0],SurfaceforcingsBPosEnum);
+	GetInputListOnVertices(&a_neg[0],SurfaceforcingsANegEnum);
+	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(s[i]>Hc[i]){
+	    smb[i]=a_pos[i]+b_pos[i]*s[i];
+		 if(smb[i]>smb_pos_max[i]){smb[i]=smb_pos_max[i];}
+		 if(smb[i]<smb_pos_min[i]){smb[i]=smb_pos_min[i];}
+	  }
+	  else{
+	    smb[i]=a_neg[i]+b_neg[i]*s[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->matice; 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->matice; 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], this->nodes, 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*/
+	IssmInt i,j;
+	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]=(int)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+(int)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 _error2_("temperature and waterfraction required for the enthalpy solution");
+			break;
+
+		default:
+			/*No update for other solution types*/
+			break;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::UpdatePotentialSheetUngrounding{{{*/
+int Penta::UpdatePotentialSheetUngrounding(IssmDouble* vertices_potentially_ungrounding,Vector* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf){
+
+	int i;
+	int nflipped=0;
+
+	/*Go through nodes, and whoever is on the potential_sheet_ungrounding, ends up in nodes_on_iceshelf: */
+	for(i=0;i<NUMVERTICES;i++){
+		if (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*/
+	int    iv;
+	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], nodes, 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);
+		matice->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* smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius){
+	_error2_("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], nodes, 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->matice; 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->matice->GetBbar();
+			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;
+		default:  
+			_error2_("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], nodes, 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_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,ig,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], nodes, 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 (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(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(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(dt){
+			GetNodalFunctionsP1(&L[0], gauss);
+			D_scalar_trans=gauss->weight*Jdet;
+			D_scalar_trans=D_scalar_trans;
+
+			TripleMultiply(&L[0],numdof,1,0,
+						&D_scalar_trans,1,1,0,
+						&L[0],1,numdof,0,
+						&Ke->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(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(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,ig;
+	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], nodes, 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 (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(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->matice; 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,ig,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], nodes, 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 (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(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(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(dt){
+			GetNodalFunctionsP1(&L[0], gauss);
+			D_scalar_trans=gauss->weight*Jdet;
+			D_scalar_trans=D_scalar_trans;
+
+			TripleMultiply(&L[0],numdof,1,0,
+						&D_scalar_trans,1,1,0,
+						&L[0],1,numdof,0,
+						&Ke->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(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(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,ig;
+	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], nodes, 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 (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(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,ig,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], nodes, 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(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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(&L[0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		GetPhi(&phi, &epsilon[0], viscosity);
+
+		scalar_def=phi/rho_ice*Jdet*gauss->weight;
+		if(dt) scalar_def=scalar_def*dt;
+
+		for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
+
+		/* Build transient now */
+		if(dt){
+			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(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,ig;
+	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], nodes, 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(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(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,ig;
+	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], nodes, 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(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(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,ig,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], nodes, 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 (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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctionsP1(&L[0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		GetPhi(&phi, &epsilon[0], viscosity);
+
+		scalar_def=phi/(rho_ice*heatcapacity)*Jdet*gauss->weight;
+		if(dt) scalar_def=scalar_def*dt;
+
+		for(i=0;i<NUMVERTICES;i++)  pe->values[i]+=scalar_def*L[i];
+
+		/* Build transient now */
+		if(dt){
+			temperature_input->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(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,ig;
+	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], nodes, 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(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(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,ig;
+	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], nodes, 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(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(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* 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* 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])) _error2_("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], nodes, 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->matice->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),
+							matice->GetN());
+				for(i=0;i<numdof;i++) B[i]=B_average;
+				this->matice->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,B));
+				break;
+			default:
+				_error2_("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])) _error2_("NaN found in solution vector");
+	}
+
+	/*Get all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, 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) _error2_("Negative water fraction found in solution vector");
+			//if(waterfraction[i]>1) _error2_("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->matice->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),
+							matice->GetN());
+				for(i=0;i<numdof;i++) B[i]=B_average;
+				this->matice->inputs->AddInput(new PentaP1Input(MaterialsRheologyBEnum,B));
+				break;
+			default:
+				_error2_("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* gradient,int enum_type,int control_index){
+
+	int doflist1[NUMVERTICES];
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		if(!IsOnBed()) return;
+		input=(Input*)matice->inputs->GetInput(MaterialsRheologyBEnum);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error2_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error2_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&doflist1[0],control_index);
+	((ControlInput*)input)->GetGradient(gradient,&doflist1[0]);
+
+}/*}}}*/
+/*FUNCTION Penta::ControlInputScaleGradient{{{*/
+void Penta::ControlInputScaleGradient(int enum_type,IssmDouble scale){
+
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(MaterialsRheologyBEnum);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error2_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error2_("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    doflist1[NUMVERTICES];
+	IssmDouble grad_list[NUMVERTICES];
+	Input* grad_input=NULL;
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(MaterialsRheologyBEnum);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error2_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error2_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&doflist1[0],control_index);
+	for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[doflist1[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:
+			_error2_("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 Averaging B*/
+	this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+
+	/*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->matice; delete tria;
+
+	/*Delete B averaged*/
+	this->matice->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateKMatrixAdjointPattyn{{{*/
+ElementMatrix* Penta::CreateKMatrixAdjointPattyn(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	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], nodes, 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 (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);
+		matice->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,ig;
+	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     phi[NUMVERTICES];
+	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], nodes, 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 (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);
+		matice->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:
+			_error2_("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->matice; 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->matice; 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->matice; 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]->GetVertexDof() + control_index;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Penta::Gradj {{{*/
+void  Penta::Gradj(Vector* 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:
+					_error2_("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:
+					_error2_("approximation " << EnumToStringx(approximation) << " not supported yet");
+			}
+			break;
+
+		default:
+			_error2_("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->matice; 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->matice; delete tria;
+			break;
+		default:
+			_error2_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+	}
+	xDelete<int>(responses);
+}
+/*}}}*/
+/*FUNCTION Penta::GradjDragMacAyeal {{{*/
+void  Penta::GradjDragMacAyeal(Vector* 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->matice; delete tria;
+
+} /*}}}*/
+/*FUNCTION Penta::GradjDragPattyn {{{*/
+void  Penta::GradjDragPattyn(Vector* gradient,int control_index){
+
+	int        i,j,ig;
+	int        analysis_type;
+	int        doflist1[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(&doflist1[0],control_index);
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, 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 (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,doflist1,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+}
+/*}}}*/
+/*FUNCTION Penta::GradjDragStokes {{{*/
+void  Penta::GradjDragStokes(Vector* gradient,int control_index){
+
+	int        i,j,ig;
+	int        analysis_type;
+	int        doflist1[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], nodes, NUMVERTICES);
+	for(i=0;i<NUMVERTICES2D;i++) for(j=0;j<2;j++) xyz_list_tria[i][j]=xyz_list[i][j];
+	GradientIndexing(&doflist1[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(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,doflist1,grade_g,ADD_VAL);
+
+	delete friction;
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Penta::GradjBbarMacAyeal {{{*/
+void  Penta::GradjBbarMacAyeal(Vector* 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->matice; delete tria;
+
+	/*delete Average B*/
+	this->matice->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+
+} /*}}}*/
+/*FUNCTION Penta::GradjBbarPattyn {{{*/
+void  Penta::GradjBbarPattyn(Vector* 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->matice; delete tria;
+
+	/*delete Average B*/
+	this->matice->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+} /*}}}*/
+/*FUNCTION Penta::GradjBbarStokes {{{*/
+void  Penta::GradjBbarStokes(Vector* 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->matice; delete tria;
+
+	/*delete Average B*/
+	this->matice->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*)matice->inputs->GetInput(MaterialsRheologyBEnum); _assert_(input);
+		}
+		else{
+			input=(Input*)this->inputs->GetInput(control_type[i]); _assert_(input);
+		}
+
+		if (input->ObjectEnum()!=ControlInputEnum) _error2_("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);
+		}
+	}
+
+	/*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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambday[i])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambdaz[i])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambdap[i])) _error2_("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]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambday[i]))       _error2_("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->matice; 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->matice; 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->matice; 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->matice; 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->matice; 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->matice; 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->matice; 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->matice; 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->matice; 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->matice; delete tria;
+		return J;
+	}
+}
+/*}}}*/
+/*FUNCTION Penta::ThicknessAbsGradient{{{*/
+IssmDouble Penta::ThicknessAbsGradient(bool process_units,int weight_index){
+
+	_error2_("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;
+	_error2_("Not implemented yet");
+
+	tria=(Tria*)SpawnTria(0,1,2);
+	J=tria->ThicknessAbsMisfit(process_units,weight_index);
+	delete tria->matice; 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->matice; 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->matice; delete tria;
+	return J;
+}
+/*}}}*/
+/*FUNCTION Penta::GetVectorFromControlInputs{{{*/
+void  Penta::GetVectorFromControlInputs(Vector* vector,int control_enum,int control_index,const char* data){
+
+	int doflist1[NUMVERTICES];
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(control_enum)) return;
+
+	/*Prepare index list*/
+	GradientIndexing(&doflist1[0],control_index);
+
+	/*Get input (either in element or material)*/
+	Input* input=inputs->GetInput(control_enum);
+	if(!input) _error2_("Input " << EnumToStringx(control_enum) << " not found in element");
+
+	/*Check that it is a ControlInput*/
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error2_("input " << EnumToStringx(control_enum) << " is not a ControlInput");
+	}
+
+	((ControlInput*)input)->GetVectorFromInputs(vector,&doflist1[0],data);
+}
+/*}}}*/
+/*FUNCTION Penta::SetControlInputsFromVector{{{*/
+void  Penta::SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index){
+
+	IssmDouble  values[NUMVERTICES];
+	int     doflist1[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(&doflist1[0],control_index);
+
+	/*Get values on vertices*/
+	for (int i=0;i<NUMVERTICES;i++){
+		values[i]=vector[doflist1[i]];
+	}
+	new_input = new PentaP1Input(control_enum,values);
+
+
+	if(control_enum==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(control_enum); _assert_(input);
+	}
+	else{
+		input=(Input*)this->inputs->GetInput(control_enum);   _assert_(input);
+	}
+
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error2_("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]->GetSidList()]; //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:
+			_error2_("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){
+	_error2_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{*/
+void  Penta::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	_error2_("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]->GetSidList();
+					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:
+			_error2_("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,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		gauss->SynchronizeGaussTria(gauss_tria);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBMacAyealPattyn(&B[0][0], &xyz_list[0][0], gauss);
+		tria->GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss_tria);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity3d(&viscosity, &epsilon[0]);
+		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
+
+		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+		D_scalar=2*newviscosity*gauss->weight*Jdet;
+		for (i=0;i<3;i++) D[i][i]=D_scalar;
+
+		TripleMultiply( &B[0][0],3,numdofp,1,
+					&D[0][0],3,3,0,
+					&Bprime[0][0],3,numdofm,0,
+					&Ke_gg_gaussian[0][0],0);
+
+		for( i=0; i<numdofp; i++) for(j=0;j<numdofm; j++) Ke_gg[i][j]+=Ke_gg_gaussian[i][j];
+	} 
+	for(i=0;i<numdofp;i++) for(j=0;j<numdofm;j++) Ke->values[(i+2*numdofm)*numdoftotal+j]+=Ke_gg[i][j];
+	for(i=0;i<numdofm;i++) for(j=0;j<numdofp;j++) Ke->values[i*numdoftotal+(j+2*numdofm)]+=Ke_gg[j][i];
+
+	/*Transform Coordinate System*/
+	TransformStiffnessMatrixCoord(Ke,node_list,numnodes,cs_list);
+
+	/*Clean-up and return*/
+	delete tria->matice; 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,ig,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], nodes, 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 (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,ig;
+	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], nodes, 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 (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);
+		matice->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->matice; 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,ig;
+	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], nodes, 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 (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);
+		matice->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 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:
+			_error2_("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 Averaging B*/
+	this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+
+	/*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->matice; delete tria;
+
+	/*Delete B averaged*/
+	this->matice->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+
+	/*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,ig,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]; //stiffness matrix evaluated at the gaussian point.
+	Tria*       tria=NULL;
+	Penta*      pentabase=NULL;
+	GaussPenta *gauss=NULL;
+	GaussTria  *gauss_tria=NULL;
+
+	/*Find penta on bed as this is a macayeal elements: */
+	pentabase=GetBasalElement();
+	tria=pentabase->SpawnTria(0,1,2); //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], nodes,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 (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);
+			matice->GetViscosity3d(&viscosity, &epsilon[0]);
+			matice->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);
+			matice->GetViscosity3dStokes(&newviscosity,&epsilons[0]);
+		}
+		else _error2_("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->matice;
+	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->matice; 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::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,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBPattyn(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimePattyn(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate3dPattyn(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate3dPattyn(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity3d(&viscosity, &epsilon[0]);
+		matice->GetViscosity3d(&oldviscosity, &oldepsilon[0]);
+		newviscosity=viscosity+viscosity_overshoot*(viscosity-oldviscosity);
+
+		D_scalar=2*newviscosity*gauss->weight*Jdet;
+		for (i=0;i<5;i++) D[i][i]=D_scalar;
+
+		TripleMultiply( &B[0][0],5,numdof,1,
+					&D[0][0],5,5,0,
+					&Bprime[0][0],5,numdof,0,
+					&Ke->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,ig;
+	int       analysis_type;
+	IssmDouble    xyz_list[NUMVERTICES][3];
+	IssmDouble    xyz_list_tria[NUMVERTICES2D][3]={0.0};
+	IssmDouble    slope_magnitude,alpha2,Jdet;
+	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], nodes, 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 (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 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,j,ig,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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBStokes(&B[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0],gauss); 
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		D_scalar=gauss->weight*Jdet;
+		for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
+		for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
+
+		TripleMultiply( &B[0][0],8,27,1,
+					&D[0][0],8,8,0,
+					&B_prime[0][0],8,27,0,
+					&Ke_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,ig;
+	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], nodes, 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 (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);
+		matice->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 */
+	int         i,j,ig;
+	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], nodes, NUMVERTICES);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussPenta(2,2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBVert(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimeVert(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		DL_scalar=gauss->weight*Jdet;
+
+		TripleMultiply( &B[0][0],1,NUMVERTICES,1,
+					&DL_scalar,1,1,0,
+					&Bprime[0][0],1,NUMVERTICES,0,
+					&Ke->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,ig;
+	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], nodes, 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 (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,ig;
+	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], nodes, 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 (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);
+		matice->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,ig;
+	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], nodes, 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(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);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
+
+		for(i=0;i<NUMVERTICES2D;i++){
+			pe->values[i*NDOF4+0]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[0]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[0])*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,j,ig;
+	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], nodes, 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 (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);
+		matice->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,ig;
+	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], nodes, 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(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);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+		friction->GetAlpha2(&alpha2_gauss, gauss,VxEnum,VyEnum,VzEnum);
+
+		for(i=0;i<NUMVERTICES2D;i++){
+			pe->values[i*NDOF4+0]+=Jdet2d*gauss->weight*(alpha2_gauss*w*bed_normal[0]*bed_normal[2]+2*viscosity*dw[2]*bed_normal[0])*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 HutterApproximationEnum:
+			return NULL;
+		case NoneApproximationEnum:
+			return NULL;
+		case StokesApproximationEnum:
+			return CreatePVectorDiagnosticStokes();
+		case MacAyealPattynApproximationEnum:
+			return CreatePVectorDiagnosticMacAyealPattyn();
+		case MacAyealStokesApproximationEnum:
+			return CreatePVectorDiagnosticMacAyealStokes();
+		case PattynStokesApproximationEnum:
+			return CreatePVectorDiagnosticPattynStokes();
+		default:
+			_error2_("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){
+
+	/*Constants*/
+	const int numdofs=NDOF2*NUMVERTICES;
+
+	/*Intermediaries*/
+	int          i,j,k,ig;
+	int          node0,node1;
+	int          connectivity[2];
+	IssmDouble       Jdet;
+	IssmDouble       xyz_list[NUMVERTICES][3];
+	IssmDouble       xyz_list_segment[2][3];
+	IssmDouble       z_list[NUMVERTICES];
+	IssmDouble       z_segment[2],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], nodes, NUMVERTICES);
+	rho_ice=matpar->GetRhoIce();
+	gravity=matpar->GetG();
+	n=matice->GetN();
+	B=matice->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(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->matice; 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,ig;
+	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], nodes, 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 (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,ig;
+	int        approximation;
+	IssmDouble     Jdet,viscosity;
+	IssmDouble     gravity,rho_ice,stokesreconditioning;
+	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 
+	IssmDouble     Ke_gaussian[numdofbubble][3];
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant(&Jdet, &xyz_list[0][0],gauss);
+		GetBStokes(&B[0][0],&xyz_list[0][0],gauss); 
+		GetBprimeStokes(&B_prime[0][0],&xyz_list[0][0], gauss); 
+		GetNodalFunctionsMINI(&l1l7[0], gauss);
+
+		this->GetStrainRate3d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input,vz_input);
+		matice->GetViscosity3dStokes(&viscosity,&epsilon[0]);
+
+		for(i=0;i<NUMVERTICES+1;i++){
+			Pe_gaussian[i*NDOF4+2]+=-rho_ice*gravity*Jdet*gauss->weight*l1l7[i];
+		}
+
+		/*Get bubble part of Bprime */
+		for(i=0;i<8;i++) for(j=0;j<3;j++) B_prime_bubble[i][j]=B_prime[i][j+24];
+
+		D_scalar=gauss->weight*Jdet;
+		for (i=0;i<6;i++) D[i][i]=D_scalar*2*viscosity;
+		for (i=6;i<8;i++) D[i][i]=-D_scalar*stokesreconditioning;
+
+		TripleMultiply(&B[0][0],8,numdofbubble,1,
+					&D[0][0],8,8,0,
+					&B_prime_bubble[0][0],8,3,0,
+					&Ke_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,ig;
+	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], nodes, 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(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        i,ig;
+	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], nodes, 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 (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 (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,ig;
+	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], nodes, 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(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:
+			_error2_("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 Averaging B*/
+	this->InputDepthAverageAtBase(MaterialsRheologyBEnum,MaterialsRheologyBbarEnum,MaterialsEnum);
+
+	/*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->matice; delete tria;
+
+	/*Delete B averaged*/
+	this->matice->inputs->DeleteInput(MaterialsRheologyBbarEnum);
+
+	/*clean up and return*/
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Penta::CreateJacobianDiagnosticPattyn{{{*/
+ElementMatrix* Penta::CreateJacobianDiagnosticPattyn(void){
+
+	/*Constants*/
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	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)*/
+	ElementMatrix* Ke=CreateKMatrixDiagnosticPattyn();
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, 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 (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);
+		matice->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,ig;
+	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     phi[NUMVERTICES];
+	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], nodes, 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 (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);
+		matice->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* 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* 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* 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* 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::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;
+		}
+	}
+	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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error2_("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->nodes,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], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof2d;i++){
+		pattyn_values[i]=solution[doflistp[i]];
+		macayeal_values[i]=solution[doflistm[i]];
+	}
+	for(i=numdof2d;i<numdof;i++){
+		pattyn_values[i]=solution[doflistp[i]];
+		macayeal_values[i]=macayeal_values[i-numdof2d];
+	}
+
+	/*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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error2_("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], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof2d;i++){
+		macayeal_values[i]=solution[doflistm[i]];
+		macayeal_values[i+numdof2d]=solution[doflistm[i]];
+	}
+	for(i=0;i<numdofs;i++){
+		stokes_values[i]=solution[doflists[i]];
+	}
+
+	/*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]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vzstokes[i])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(pressure[i])) _error2_("NaN found in solution vector");
+	}
+
+	/*Get Vz*/
+	Input* vzmacayeal_input=inputs->GetInput(VzMacAyealEnum);
+	if (vzmacayeal_input){
+		if (vzmacayeal_input->ObjectEnum()!=PentaP1InputEnum){
+			_error2_("Cannot compute Vel as VzMacAyeal is of type " << EnumToStringx(vzmacayeal_input->ObjectEnum()));
+		}
+		GetInputListOnVertices(&vzmacayeal[0],VzMacAyealEnum);
+	}
+	else{
+		_error2_("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::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], nodes, 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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error2_("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], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdofp;i++) pattyn_values[i]=solution[doflistp[i]];
+	for(i=0;i<numdofs;i++) stokes_values[i]=solution[doflists[i]];
+
+	/*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]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vzstokes[i])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(pressure[i])) _error2_("NaN found in solution vector");
+	}
+
+	/*Get Vz*/
+	Input* vzpattyn_input=inputs->GetInput(VzPattynEnum);
+	if (vzpattyn_input){
+		if (vzpattyn_input->ObjectEnum()!=PentaP1InputEnum){
+			_error2_("Cannot compute Vel as VzPattyn is of type " << EnumToStringx(vzpattyn_input->ObjectEnum()));
+		}
+		GetInputListOnVertices(&vzpattyn[0],VzPattynEnum);
+	}
+	else{
+		_error2_("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], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+
+	/*Ok, we have vx and vy in values, fill in vx and vy arrays: */
+	for(i=0;i<NUMVERTICES;i++){
+		vx[i]=values[i*NDOF2+0];
+		vy[i]=values[i*NDOF2+1];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vx[i])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error2_("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], nodes, NUMVERTICES);
+
+	/*Use the dof list to index into the solution vector vz: */
+	for(i=0;i<numdof;i++) values[i]=solution[doflist[i]];
+	for(i=0;i<NUMVERTICES;i++){
+		vz[i]=values[i*NDOF1+0];
+
+		/*Check solution*/
+		if(xIsNan<IssmDouble>(vz[i])) _error2_("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) _error2_("Cannot compute Vel as VzStokes is of type " << EnumToStringx(vzstokes_input->ObjectEnum()));
+			GetInputListOnVertices(&vzstokes[0],VzStokesEnum);
+		}
+		else _error2_("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) _error2_("Cannot compute Vel as VzStokes is of type " << EnumToStringx(vzstokes_input->ObjectEnum()));
+			GetInputListOnVertices(&vzstokes[0],VzStokesEnum);
+		}
+		else _error2_("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]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vz[i]))       _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(pressure[i])) _error2_("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->matice; 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->matice; delete tria;
+
+	/*Delete Vx and Vy averaged*/
+	this->inputs->DeleteInput(VxAverageEnum);
+	this->inputs->DeleteInput(VyAverageEnum);
+
+	/*Clean up and return*/
+	return pe;
+}
+/*}}}*/
+#endif
+
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/Penta.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/Penta.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/Penta.h	(revision 12822)
@@ -0,0 +1,317 @@
+/*! \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 IoModel;
+class Node;
+class Matice;
+class Matpar;
+class Tria;
+class ElementMatrix;
+class ElementVector;
+
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+/*}}}*/
+
+class Penta: public Element,public PentaHook,public PentaRef{
+
+	public:
+
+		int          id;
+		int          sid;
+
+		Node       **nodes;        // 6 nodes
+		Matice      *matice;       // 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(); 
+		int		  MyRank();
+		/*}}}*/
+		/*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* partition_contributions,Vector* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part);
+		void   BasalFrictionCreateInput(void);
+		void   ComputeBasalStress(Vector* sigma_b);
+		void   ComputeStrainRate(Vector* eps);
+		void   ComputeStressTensor();
+		void   Configure(Elements* elements,Loads* loads,DataSet* nodes,Materials* materials,Parameters* parameters);
+		void   SetCurrentConfiguration(Elements* elements,Loads* loads,DataSet* nodes,Materials* materials,Parameters* parameters);
+		void   CreateKMatrix(Matrix* Kff, Matrix* Kfs,Vector* df);
+		void   CreatePVector(Vector* pf);
+		void   CreateJacobianMatrix(Matrix* Jff);
+		void   Delta18oParameterization(void);
+		void   DeleteResults(void);
+		int    GetNodeIndex(Node* node);
+		void   GetSolutionFromInputs(Vector* solution);
+		IssmDouble GetZcoord(GaussPenta* gauss);
+		void   GetVectorFromInputs(Vector* vector,int name_enum);
+		void   GetVectorFromResults(Vector* 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   PotentialSheetUngrounding(Vector* 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    UpdatePotentialSheetUngrounding(IssmDouble* potential_sheet_ungrounding,Vector* 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* 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_CONTROL_
+		IssmDouble DragCoefficientAbsGradient(bool process_units,int weight_index);
+		void   GradientIndexing(int* indexing,int control_index);
+		void   Gradj(Vector* gradient,int control_type,int control_index);
+		void   GradjDragMacAyeal(Vector* gradient,int control_index);
+		void   GradjDragPattyn(Vector* gradient,int control_index);
+		void   GradjDragStokes(Vector* gradient,int control_index);
+		void   GradjBbarMacAyeal(Vector* gradient,int control_index);
+		void   GradjBbarPattyn(Vector* gradient,int control_index);
+		void   GradjBbarStokes(Vector* gradient,int control_index);
+		void   GetVectorFromControlInputs(Vector* gradient,int control_enum,int control_index,const char* data);
+		void   SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index);
+		void   ControlInputGetGradient(Vector* 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);
+		void   InputControlUpdate(IssmDouble scalar,bool save_parameter);
+		#endif
+		/*}}}*/
+		/*Penta specific routines:{{{*/
+		void	  BedNormal(IssmDouble* bed_normal, IssmDouble xyz_list[3][3]);
+		ElementMatrix* CreateKMatrixPrognostic(void);
+		ElementMatrix* CreateKMatrixSlope(void);
+		ElementVector* CreatePVectorPrognostic(void);
+		ElementVector* CreatePVectorSlope(void);
+		void	  GetDofList(int** pdoflist,int approximation_enum,int setenum);
+		void	  GetDofList1(int* doflist);
+		void    GetSidList(int* sidlist);
+		void    GetConnectivityList(int* connectivity);
+		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* 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* 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           InputUpdateFromSolutionDiagnosticPattyn( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticPattynStokes( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticHutter( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticVert( IssmDouble* solutiong);
+		void           InputUpdateFromSolutionDiagnosticStokes( IssmDouble* solutiong);
+		void	         GetSolutionFromInputsDiagnosticHoriz(Vector* solutiong);
+		void	         GetSolutionFromInputsDiagnosticHutter(Vector* solutiong);
+		void	         GetSolutionFromInputsDiagnosticStokes(Vector* solutiong);
+		void	         GetSolutionFromInputsDiagnosticVert(Vector* 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* CreatePVectorDiagnosticPattyn(void);
+		ElementVector* CreatePVectorDiagnosticPattynStokes(void);
+		ElementVector* CreatePVectorDiagnosticStokes(void);
+		ElementVector* CreatePVectorDiagnosticStokesViscous(void);
+		ElementVector* CreatePVectorDiagnosticStokesShelf(void);
+		ElementVector* CreatePVectorDiagnosticVert(void);
+		ElementVector* CreatePVectorDiagnosticVertVolume(void);
+		ElementVector* CreatePVectorDiagnosticVertBase(void);
+		#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);
+		#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* 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/objects/Elements/PentaHook.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/PentaHook.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/PentaHook.cpp	(revision 12822)
@@ -0,0 +1,104 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION PentaHook::PentaHook(){{{*/
+PentaHook::PentaHook(){
+	numanalyses=UNDEF;
+	this->hnodes=NULL;
+	this->hmatice=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 hmatice;
+	delete hmatpar;
+	delete hneighbors;
+}
+/*}}}*/
+/*FUNCTION PentaHook::PentaHook(int in_numanalyses,int matice_id, int matpar_id){{{*/
+PentaHook::PentaHook(int in_numanalyses,int matice_id, IoModel* iomodel){
+
+	/*intermediary: */
+	int matpar_id;
+	
+	/*retrieve parameters: */
+	iomodel->Constant(&matpar_id,MeshNumberofelementsEnum); matpar_id++;
+
+	this->numanalyses=in_numanalyses;
+	this->hnodes=new Hook*[in_numanalyses];
+	this->hmatice=new Hook(&matice_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 hmatice. matice will be taken care of by Penta
+	triahook->hmatice=NULL;
+	triahook->hmatpar=(Hook*)this->hmatpar->copy();
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/PentaHook.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/PentaHook.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/PentaHook.h	(revision 12822)
@@ -0,0 +1,33 @@
+/*!\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; // 6 nodes for each analysis type
+		Hook*  hmatice; // 1 ice material
+		Hook*  hmatpar; // 1 material parameter
+		Hook*  hneighbors; // 2 elements, first down, second up
+
+		/*FUNCTION constructors, destructors {{{*/
+		PentaHook();
+		PentaHook(int in_numanalyses,int matice_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/objects/Elements/PentaRef.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/PentaRef.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/PentaRef.cpp	(revision 12822)
@@ -0,0 +1,1267 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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){
+
+	int i,j;
+
+	/*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) _error2_("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) _error2_("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) _error2_("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) _error2_("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/objects/Elements/PentaRef.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/PentaRef.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/PentaRef.h	(revision 12822)
@@ -0,0 +1,63 @@
+/*!\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 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){_error2_("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){_error2_("only PentaGauss are supported");};
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/Tria.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/Tria.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/Tria.cpp	(revision 12822)
@@ -0,0 +1,5718 @@
+/*!\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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMVERTICES 3
+
+/*Constructors/destructor/copy*/
+/*FUNCTION Tria::Tria(){{{*/
+Tria::Tria(){
+
+	int i;
+
+	this->nodes=NULL;
+	this->matice=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){
+		
+		int i;
+		/*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->matice=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->hmatice=(Hook*)this->hmatice->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->matice=(Matice*)tria->hmatice->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* partition_contributions,Vector* 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;
+	IssmDouble    values[3];
+
+	/*First, get the area: */
+	area=this->GetArea();
+
+	/*Figure out the average for this element: */
+	this->GetSidList(&offsetsid[0]);
+	this->GetDofList1(&offsetdof[0]);
+	mean=0;
+	for(i=0;i<NUMVERTICES;i++){
+		partition[i]=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::CreateKMatrix {{{*/
+void  Tria::CreateKMatrix(Matrix* Kff, Matrix* Kfs,Vector* df){
+
+	/*retreive parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging mode{{{*/
+	_assert_(this->nodes && this->matice && 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 AdjointHorizAnalysisEnum:
+			Ke=CreateKMatrixAdjointMacAyeal();
+			break;
+		case DiagnosticHutterAnalysisEnum:
+			Ke=CreateKMatrixDiagnosticHutter();
+			break;
+		 #endif
+		case BedSlopeXAnalysisEnum: case SurfaceSlopeXAnalysisEnum: case BedSlopeYAnalysisEnum: case SurfaceSlopeYAnalysisEnum:
+			Ke=CreateKMatrixSlope();
+			break;
+		case PrognosticAnalysisEnum:
+			Ke=CreateKMatrixPrognostic();
+			break;
+		#ifdef _HAVE_HYDROLOGY_
+		case HydrologyAnalysisEnum:
+			Ke=CreateKMatrixHydrology();
+			break;
+		#endif
+		#ifdef _HAVE_BALANCED_
+		case BalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixBalancethickness();
+			break;
+		#endif
+		#ifdef _HAVE_CONTROL_
+		case AdjointBalancethicknessAnalysisEnum:
+			Ke=CreateKMatrixAdjointBalancethickness();
+			break;
+		#endif
+		default:
+			_error2_("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 */
+	int        i,j,ig;
+	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], nodes, NUMVERTICES);
+	latentheat=matpar->GetLatentHeat();
+	heatcapacity=matpar->GetHeatCapacity();
+
+	/* Start looping on the number of gauss  (nodes on the bedrock) */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0], gauss);
+
+		D_scalar=latentheat/heatcapacity*gauss->weight*Jdet;
+
+		TripleMultiply(&L[0],numdof,1,0,
+					&D_scalar,1,1,0,
+					&L[0],1,numdof,0,
+					&Ke->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:
+			_error2_("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        i,j,ig,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};
+	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], nodes, 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: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		vxaverage_input->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(pow(vx,2.)+pow(vy,2.))+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        i,j,ig,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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		vxaverage_input->GetInputValue(&vx,gauss);
+		vyaverage_input->GetInputValue(&vy,gauss);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		DL_scalar=gauss->weight*Jdettria;
+
+		TripleMultiply( &L[0],1,numdof,1,
+					&DL_scalar,1,1,0,
+					&L[0],1,numdof,0,
+					&Ke->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::CreateKMatrixSlope {{{*/
+ElementMatrix* Tria::CreateKMatrixSlope(void){
+
+	/*constants: */
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/* Intermediaries */
+	int        i,j,ig;
+	IssmDouble     DL_scalar,Jdet;
+	IssmDouble     xyz_list[NUMVERTICES][3];
+	IssmDouble     L[1][3];
+	GaussTria *gauss = NULL;
+
+	/*Initialize Element matrix*/
+	ElementMatrix* Ke=new ElementMatrix(nodes,NUMVERTICES,this->parameters,NoneApproximationEnum);
+
+	GetVerticesCoordinates(&xyz_list[0][0],nodes,NUMVERTICES);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+		
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		DL_scalar=gauss->weight*Jdet;
+
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF1);
+
+		TripleMultiply(&L[0][0],1,3,1,
+					&DL_scalar,1,1,0,
+					&L[0][0],1,3,0,
+					&Ke->values[0],1);
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Ke;
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVector {{{*/
+void  Tria::CreatePVector(Vector* 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->matice && 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 HydrologyAnalysisEnum:
+			pe=CreatePVectorHydrology();
+			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:
+			_error2_("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:
+			_error2_("Element type " << EnumToStringx(GetElementType()) << " not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Tria::CreatePVectorPrognostic_CG {{{*/
+ElementVector* Tria::CreatePVectorPrognostic_CG(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	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], nodes, 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(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		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(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 */
+	int        i,j,ig;
+	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], nodes, 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(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		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(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,j,ig;
+	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], nodes, 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(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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* Jff){
+
+	/*retrieve parameters: */
+	ElementMatrix* Ke=NULL;
+	int analysis_type;
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*Checks in debugging {{{*/
+	_assert_(this->nodes && this->matice && 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:
+			_error2_("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* eps){
+	_error2_("Not Implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeStrainRate {{{*/
+void  Tria::ComputeStrainRate(Vector* eps){
+	_error2_("Not Implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::ComputeStressTensor {{{*/
+void  Tria::ComputeStressTensor(){
+
+	int         iv;
+	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], nodes, 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);
+		matice->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, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+	
+	/*go into parameters and get the analysis_counter: */
+	int analysis_counter;
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*Take care of hooking up all objects for this element, ie links the objects in the hooks to their respective 
+	 * datasets, using internal ids and offsets hidden in hooks: */
+	if(this->hnodes[analysis_counter]) this->hnodes[analysis_counter]->configure(nodesin);
+	this->hmatice->configure(materialsin);
+	this->hmatpar->configure(materialsin);
+
+	/*Now, go pick up the objects inside the hooks: */
+	if(this->hnodes[analysis_counter]) this->nodes=(Node**)this->hnodes[analysis_counter]->deliverp();
+	else this->nodes=NULL;
+	this->matice=(Matice*)this->hmatice->delivers();
+	this->matpar=(Matpar*)this->hmatpar->delivers();
+
+	/*point parameters to real dataset: */
+	this->parameters=parametersin;
+
+	/*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 (matice) matice->DeepEcho();
+	else _printLine_("matice = 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){
+	IssmDouble monthlytemperatures[NUMVERTICES][12],monthlyprec[NUMVERTICES][12];
+	IssmDouble TemperaturesPresentday[NUMVERTICES][12],TemperaturesLgm[NUMVERTICES][12];
+	IssmDouble PrecipitationsPresentday[NUMVERTICES][12];
+	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);
+	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);
+			monthlyprec[iv][month]=monthlyprec[iv][month]*yts; // convertion to m/yr
+		}
+	}
+	/*Recover delta18o and Delta18oSurface at present day, lgm and at time t*/
+	this->parameters->FindParam(&Delta18oPresent,SurfaceforcingsDelta18oEnum,finaltime*yts);
+	this->parameters->FindParam(&Delta18oLgm,SurfaceforcingsDelta18oEnum,(finaltime-21000)*yts);
+	this->parameters->FindParam(&Delta18oTime,SurfaceforcingsDelta18oEnum,time*yts);
+	this->parameters->FindParam(&Delta18oSurfacePresent,SurfaceforcingsDelta18oSurfaceEnum,finaltime*yts);
+	this->parameters->FindParam(&Delta18oSurfaceLgm,SurfaceforcingsDelta18oSurfaceEnum,(finaltime-21000)*yts);
+	this->parameters->FindParam(&Delta18oSurfaceTime,SurfaceforcingsDelta18oSurfaceEnum,time*yts);
+
+	/*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(int iv=0;iv<NUMVERTICES;iv++) {
+			TriaP1Input* newmonthinput1 = new TriaP1Input(SurfaceforcingsMonthlytemperaturesEnum,&monthlytemperatures[iv][imonth]);
+			NewTemperatureInput->AddTimeInput(newmonthinput1,imonth/12.*yts);
+			TriaP1Input* newmonthinput2 = new TriaP1Input(SurfaceforcingsPrecipitationEnum,&monthlyprec[iv][imonth]);
+			NewPrecipitationInput->AddTimeInput(newmonthinput2,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 (matice) matice->Echo();
+	else _printLine_("matice = 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], nodes, NUMVERTICES);
+	x1=xyz_list[0][0]; y1=xyz_list[0][1];
+	x2=xyz_list[1][0]; y2=xyz_list[1][1];
+	x3=xyz_list[2][0]; y3=xyz_list[2][1];
+ 
+	_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::GetDofList1 {{{*/
+void  Tria::GetDofList1(int* doflist){
+
+	int i;
+	for(i=0;i<3;i++) doflist[i]=nodes[i]->GetDofList1();
+
+}
+/*}}}*/
+/*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::GetNodeIndex {{{*/
+int Tria::GetNodeIndex(Node* node){
+
+	_assert_(nodes);
+	for(int i=0;i<NUMVERTICES;i++){
+		if(node==nodes[i])
+		 return i;
+	}
+	_error2_("Node provided not found among element nodes");
+}
+/*}}}*/
+/*FUNCTION Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype) {{{*/
+void Tria::GetInputListOnVertices(IssmDouble* pvalue,int enumtype){
+
+	/*Intermediaries*/
+	IssmDouble     value[NUMVERTICES];
+	GaussTria *gauss              = NULL;
+
+	/*Recover input*/
+	Input* input=inputs->GetInput(enumtype);
+	if (!input) _error2_("Input " << EnumToStringx(enumtype) << " not found in element");
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	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){
+
+	IssmDouble     value[NUMVERTICES];
+	GaussTria *gauss = NULL;
+	Input     *input = inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		gauss=new GaussTria();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&pvalue[iv],gauss);
+		}
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*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){
+
+	IssmDouble     value[NUMVERTICES];
+	GaussTria *gauss = NULL;
+	Input     *input = inputs->GetInput(enumtype);
+
+	/*Checks in debugging mode*/
+	_assert_(pvalue);
+
+	/* Start looping on the number of vertices: */
+	if (input){
+		gauss=new GaussTria();
+		for (int iv=0;iv<NUMVERTICES;iv++){
+			gauss->GaussVertex(iv);
+			input->GetInputValue(&pvalue[iv],gauss,index);
+		}
+	}
+	else{
+		for (int iv=0;iv<NUMVERTICES;iv++) pvalue[iv]=defaultvalue;
+	}
+
+	/*clean-up*/
+	delete gauss;
+}
+/*}}}*/
+/*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) _error2_("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::GetSidList {{{*/
+void  Tria::GetSidList(int* sidlist){
+	for(int i=0;i<NUMVERTICES;i++) sidlist[i]=nodes[i]->GetSidList();
+}
+/*}}}*/
+/*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* 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 HydrologyAnalysisEnum:
+		GetSolutionFromInputsHydrology(solution);
+		break;
+	#endif
+	default:
+		_error2_("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){
+		_error2_("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* vector,int input_enum){
+
+	int doflist1[NUMVERTICES];
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(input_enum)) return;
+
+	/*Prepare index list*/
+	this->GetDofList1(&doflist1[0]);
+
+	/*Get input (either in element or material)*/
+	Input* input=inputs->GetInput(input_enum);
+	if(!input) _error2_("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,&doflist1[0]);
+}
+/*}}}*/
+/*FUNCTION Tria::GetVectorFromResults{{{*/
+void  Tria::GetVectorFromResults(Vector* 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 %i is %s, when %s was expected",offset,EnumToStringx(elementresult->InstanceEnum()),EnumToStringx(enum_in));
+	}
+	if(interp==P1Enum){
+		int doflist1[NUMVERTICES];
+		int connectivity[NUMVERTICES];
+		this->GetSidList(&doflist1[0]);
+		this->GetConnectivityList(&connectivity[0]);
+		elementresult->GetVectorFromResults(vector,&doflist1[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)_error2_("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])_error2_("could not find input with enum " << EnumToStringx(enums[2*i+0]));
+		if(!old_inputs[i])_error2_("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->matice->inputs->GetInput(enum_type);
+	else
+	 _error2_("object " << EnumToStringx(object_enum) << " not supported yet");
+	if(!oldinput)_error2_("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->matice->inputs->AddInput((Input*)newinput);
+	else
+	 _error2_("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)_error2_("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){
+
+	int    i;
+	Input *input = NULL;
+
+	/*Go through all the input objects, and find the one corresponding to enum_type, if it exists: */
+	if (enum_type==MaterialsRheologyBbarEnum) input=this->matice->inputs->GetInput(enum_type);
+	else input=this->inputs->GetInput(enum_type);
+	//if (!input) _error2_("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((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 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:
+					/*Matice will take care of it*/ break;
+				default:
+					_error2_("Control " << EnumToStringx((int)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 HydrologyAnalysisEnum:
+			InputUpdateFromSolutionHydrology(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:
+			_error2_("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])) _error2_("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])) _error2_("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 _error2_("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){
+
+	/*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 (int i=0;i<3;i++){
+				values[i]=vector[this->nodes[i]->GetVertexDof()];
+			}
+
+			/*update input*/
+			if (name==MaterialsRheologyBbarEnum || name==MaterialsRheologyBEnum){
+				matice->inputs->AddInput(new TriaP1Input(name,values));
+			}
+			else{
+				this->inputs->AddInput(new TriaP1Input(name,values));
+			}
+			return;
+		}
+		default:
+			_error2_("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){
+	_error2_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVector(bool* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVector(bool* vector, int name, int type){
+	_error2_("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 _error2_("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 _error2_("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 _error2_("could not recognize nature of vector from code " << code);
+		}
+		else {
+			_error2_("transient elementary inputs not supported yet!");
+		}
+	}
+	else{
+		_error2_("Cannot add input for vector type " << vector_type << " (not supported)");
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::IsInput{{{*/
+bool Tria::IsInput(int name){
+	if (
+				name==ThicknessEnum ||
+				name==SurfaceEnum ||
+				name==BedEnum ||
+				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==GradientEnum ||
+				name==OldGradientEnum ||
+				name==QmuVxEnum ||
+				name==QmuVyEnum ||
+				name==QmuPressureEnum ||
+				name==QmuBedEnum ||
+				name==QmuThicknessEnum ||
+				name==QmuSurfaceEnum ||
+				name==QmuTemperatureEnum ||
+				name==QmuMeltingEnum
+		){
+		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,unground;
+	bool    elementonshelf = false;
+	IssmDouble  bed_hydro,yts,gl_melting_rate;
+	IssmDouble  rho_water,rho_ice,density;
+	IssmDouble  melting[NUMVERTICES];
+	IssmDouble  h[NUMVERTICES],s[NUMVERTICES],b[NUMVERTICES],ba[NUMVERTICES];
+
+	/*Recover info at the vertices: */
+	parameters->FindParam(&migration_style,GroundinglineMigrationEnum);
+	parameters->FindParam(&yts,ConstantsYtsEnum);
+	GetInputListOnVertices(&h[0],ThicknessEnum);
+	GetInputListOnVertices(&s[0],SurfaceEnum);
+	GetInputListOnVertices(&b[0],BedEnum);
+	GetInputListOnVertices(&ba[0],BathymetryEnum);
+	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){
+					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));
+				}
+			}
+		}
+	}
+
+	/*If at least one vertex is now floating, the element is now floating*/
+	for(i=0;i<NUMVERTICES;i++){
+		if(nodes[i]->IsFloating()){
+			elementonshelf=true;
+			break;
+		}
+	}
+	
+   /*Add basal melting rate if element just ungrounded*/
+	if(!this->IsFloating() && elementonshelf==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,elementonshelf));
+
+	/*Update inputs*/    
+	this->inputs->AddInput(new TriaP1Input(SurfaceEnum,&s[0]));
+	this->inputs->AddInput(new TriaP1Input(BedEnum,&b[0]));
+}
+/*}}}*/
+/*FUNCTION Tria::MyRank {{{*/
+int    Tria::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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::PotentialSheetUngrounding{{{*/
+void  Tria::PotentialSheetUngrounding(Vector* potential_sheet_ungrounding){
+
+	int     i;
+	IssmDouble  h[NUMVERTICES],ba[NUMVERTICES];
+	IssmDouble  bed_hydro;
+	IssmDouble  rho_water,rho_ice,density;
+	bool    elementonshelf = false;
+
+	/*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_sheet_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]; // ,b
+   IssmDouble rho_water,rho_ice;
+
+   /*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 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();
+
+   /*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);
+   }
+
+   /*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){
+
+	_error2_("not implemented yet");
+}
+/*}}}*/
+/*FUNCTION Tria::SmearFunction {{{*/
+void  Tria::SmearFunction(Vector*  smearedvector,IssmDouble (*WeightFunction)(IssmDouble distance,IssmDouble radius),IssmDouble radius){
+	_error2_("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 a_pos[NUMVERTICES];				// Hs-SMB relation parameter 
+	IssmDouble b_pos[NUMVERTICES];				// Hs-SMB relation parameter
+	IssmDouble a_neg[NUMVERTICES];				// Hs-SMB relation parameter
+	IssmDouble b_neg[NUMVERTICES];				// Hs-SMB relation paremeter
+	IssmDouble Hc[NUMVERTICES];					// elevation of transition between accumulation regime and ablation regime
+	IssmDouble smb_pos_max[NUMVERTICES];		// maximum SMB value in the accumulation regime
+	IssmDouble smb_pos_min[NUMVERTICES];		// minimum SMB value in the accumulation regime
+   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(&Hc[0],SurfaceforcingsHcEnum);
+	GetInputListOnVertices(&smb_pos_max[0],SurfaceforcingsSmbPosMaxEnum);
+	GetInputListOnVertices(&smb_pos_min[0],SurfaceforcingsSmbPosMinEnum);
+	GetInputListOnVertices(&a_pos[0],SurfaceforcingsAPosEnum);
+	GetInputListOnVertices(&b_pos[0],SurfaceforcingsBPosEnum);
+	GetInputListOnVertices(&a_neg[0],SurfaceforcingsANegEnum);
+	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(s[i]>Hc[i]){
+	    smb[i]=a_pos[i]+b_pos[i]*s[i];
+		 if(smb[i]>smb_pos_max[i]){smb[i]=smb_pos_max[i];}
+		 if(smb[i]<smb_pos_min[i]){smb[i]=smb_pos_min[i];}
+	  }
+	  else{
+	    smb[i]=a_neg[i]+b_neg[i]*s[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, DataSet* nodesin, Materials* materialsin, Parameters* parametersin){
+	
+	/*go into parameters and get the analysis_counter: */
+	int analysis_counter;
+	parametersin->FindParam(&analysis_counter,AnalysisCounterEnum);
+
+	/*Get Element type*/
+	this->element_type=this->element_type_list[analysis_counter];
+
+	/*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){
+
+	int    i;
+	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], nodes, NUMVERTICES);
+
+	for (i=0;i<3;i++){
+		v13[i]=xyz_list[0][i]-xyz_list[2][i];
+		v23[i]=xyz_list[1][i]-xyz_list[2][i];
+	}
+
+	normal[0]=v13[1]*v23[2]-v13[2]*v23[1];
+	normal[1]=v13[2]*v23[0]-v13[0]*v23[2];
+	normal[2]=v13[0]*v23[1]-v13[1]*v23[0];
+
+	S = 0.5 * sqrt(pow(normal[0],(IssmDouble)2)+pow(normal[1],(IssmDouble)2)+pow(normal[2],(IssmDouble)2));
+
+	/*Return: */
+	return S;
+}
+/*}}}*/
+/*FUNCTION Tria::SurfaceNormal{{{*/
+void Tria::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],(IssmDouble)2)+pow(normal[1],(IssmDouble)2)+pow(normal[2],(IssmDouble)2) );
+
+	*(surface_normal)=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
+		_error2_("ISSM was not compiled with responses compiled in, exiting!");
+	#endif
+
+	/* Get node coordinates and dof list: */
+	GetVerticesCoordinates(&xyz_list[0][0], this->nodes, NUMVERTICES);
+
+	minx=xyz_list[0][0];
+	maxx=xyz_list[0][0];
+	miny=xyz_list[0][1];
+	maxy=xyz_list[0][1];
+
+	for(i=1;i<NUMVERTICES;i++){
+		if (xyz_list[i][0]<minx)minx=xyz_list[i][0];
+		if (xyz_list[i][0]>maxx)maxx=xyz_list[i][0];
+		if (xyz_list[i][1]<miny)miny=xyz_list[i][1];
+		if (xyz_list[i][1]>maxy)maxy=xyz_list[i][1];
+	}
+	dx=maxx-minx;
+	dy=maxy-miny;
+
+	/*CFL criterion: */
+	dt=C/(maxabsvy/dx+maxabsvy/dy);
+
+	return dt;
+}
+/*}}}*/
+/*FUNCTION Tria::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::UpdatePotentialSheetUngrounding{{{*/
+int Tria::UpdatePotentialSheetUngrounding(IssmDouble* vertices_potentially_ungrounding,Vector* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf){
+
+	int i;
+	int nflipped=0;
+
+	/*Go through nodes, and whoever is on the potential_sheet_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], nodes, 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        i,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 ((int)*(segment+4)!=this->id)_error2_("error message: segment with id " << (int)*(segment+4) << " does not belong to element with id:" << this->id);
+
+	/*Recover segment node locations: */
+	x1=*(segment+0); y1=*(segment+1); x2=*(segment+2); y2=*(segment+3);
+
+	/*Get xyz list: */
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, NUMVERTICES);
+
+	/*get area coordinates of 0 and 1 locations: */
+	gauss_1=new GaussTria();
+	gauss_1->GaussFromCoords(x1,y1,&xyz_list[0][0]);
+	gauss_2=new GaussTria();
+	gauss_2->GaussFromCoords(x2,y2,&xyz_list[0][0]);
+
+	normal[0]=cos(atan2(x1-x2,y2-y1));
+	normal[1]=sin(atan2(x1-x2,y2-y1));
+
+	length=sqrt(pow(x2-x1,2.0)+pow(y2-y1,2));
+
+	Input* thickness_input=inputs->GetInput(ThicknessEnum); _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->matice->GetBbar();
+			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;
+		default:  
+			_error2_("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], nodes, 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_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,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetBMacAyeal(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimeMacAyeal(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		this->GetStrainRate2d(&epsilon[0],&xyz_list[0][0],gauss,vx_input,vy_input);
+		this->GetStrainRate2d(&oldepsilon[0],&xyz_list[0][0],gauss,vxold_input,vyold_input);
+		matice->GetViscosity2d(&viscosity, &epsilon[0]);
+		matice->GetViscosity2d(&oldviscosity, &oldepsilon[0]);
+		thickness_input->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,ig;
+	int        analysis_type;
+	IssmDouble     MAXSLOPE  = .06; // 6 %
+	IssmDouble     MOUNTAINKEXPONENT = 10;
+	IssmDouble     slope_magnitude,alpha2;
+	IssmDouble     Jdet;
+	IssmDouble     L[2][numdof];
+	IssmDouble     DL[2][2]  = {{ 0,0 },{0,0}};
+	IssmDouble     DL_scalar;
+	IssmDouble     slope[2]  = {0.0,0.0};
+	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], nodes, NUMVERTICES);
+	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);
+	parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	/*build friction object, used later on: */
+	friction=new Friction("2d",inputs,matpar,analysis_type);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		// If we have a slope > 6% for this element,  it means  we are on a mountain. In this particular case, 
+		//velocity should be = 0. To achieve this result, we set alpha2_list to a very high value: */
+		surface_input->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);
+		else friction->GetAlpha2(&alpha2, gauss,VxEnum,VyEnum,VzEnum);
+
+		GetL(&L[0][0], &xyz_list[0][0], gauss,NDOF2);
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		DL_scalar=alpha2*gauss->weight*Jdet;
+		for (i=0;i<2;i++) DL[i][i]=DL_scalar;
+		
+		TripleMultiply( &L[0][0],2,numdof,1,
+					&DL[0][0],2,2,0,
+					&L[0][0],2,numdof,0,
+					&Ke->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,ig;
+	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], nodes, 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(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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=matice->GetN();
+	B=matice->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,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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);
+		matice->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* 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* 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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error2_("NaN found in solution vector");
+	}
+
+	/*Get Vz and compute vel*/
+	GetInputListOnVertices(&vz[0],VzEnum,0);
+	for(i=0;i<NUMVERTICES;i++) vel[i]=pow( pow(vx[i],2.0) + pow(vy[i],2.0) + pow(vz[i],2.0) , 0.5);
+
+	/*For pressure: we have not computed pressure in this analysis, for this element. We are in 2D, 
+	 *so the pressure is just the pressure at the bedrock: */
+	rho_ice=matpar->GetRhoIce();
+	g=matpar->GetG();
+	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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(vy[i])) _error2_("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 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::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){
+			input=(Input*)matice->inputs->GetInput(control_type[i]); _assert_(input);
+		}
+		else{
+			input=(Input*)this->inputs->GetInput(control_type[i]);   _assert_(input);
+		}
+
+		if (input->ObjectEnum()!=ControlInputEnum){
+			_error2_("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* gradient,int enum_type,int control_index){
+
+	int doflist1[NUMVERTICES];
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error2_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error2_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&doflist1[0],control_index);
+	((ControlInput*)input)->GetGradient(gradient,&doflist1[0]);
+
+}/*}}}*/
+/*FUNCTION Tria::ControlInputScaleGradient{{{*/
+void Tria::ControlInputScaleGradient(int enum_type,IssmDouble scale){
+
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error2_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error2_("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    doflist1[NUMVERTICES];
+	IssmDouble grad_list[NUMVERTICES];
+	Input* grad_input=NULL;
+	Input* input=NULL;
+
+	if(enum_type==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(enum_type);
+	}
+	else{
+		input=inputs->GetInput(enum_type);
+	}
+	if (!input) _error2_("Input " << EnumToStringx(enum_type) << " not found");
+	if (input->ObjectEnum()!=ControlInputEnum) _error2_("Input " << EnumToStringx(enum_type) << " is not a ControlInput");
+
+	GradientIndexing(&doflist1[0],control_index);
+	for(int i=0;i<NUMVERTICES;i++) grad_list[i]=gradient[doflist1[i]];
+	grad_input=new TriaP1Input(GradientEnum,grad_list);
+
+	((ControlInput*)input)->SetGradient(grad_input);
+
+}/*}}}*/
+/*FUNCTION Tria::Gradj {{{*/
+void  Tria::Gradj(Vector* 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 BalancethicknessThickeningRateEnum:
+			GradjDhDtBalancedthickness(gradient,control_index);
+			break;
+		case VxEnum:
+			GradjVxBalancedthickness(gradient,control_index);
+			break;
+		case VyEnum:
+			GradjVyBalancedthickness(gradient,control_index);
+			break;
+		default:
+			_error2_("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 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:
+			_error2_("response " << EnumToStringx(responses[resp]) << " not supported yet");
+	}
+
+	xDelete<int>(responses);
+}
+/*}}}*/
+/*FUNCTION Tria::GradjBGradient{{{*/
+void  Tria::GradjBGradient(Vector* gradient,int weight_index,int control_index){
+
+	int        i,ig;
+	int        doflist1[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], nodes, NUMVERTICES);
+	GradientIndexing(&doflist1[0],control_index);
+	Input* rheologyb_input=matice->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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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,doflist1,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjBMacAyeal{{{*/
+void  Tria::GradjBMacAyeal(Vector* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i,ig;
+	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], nodes, 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=matice->inputs->GetInput(MaterialsRheologyBbarEnum); _assert_(rheologyb_input);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(4);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		thickness_input->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);
+		matice->GetViscosityComplement(&viscosity_complement,&epsilon[0]);
+
+		GetJacobianDeterminant2d(&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* gradient,int control_index){
+
+	int        i,ig;
+	int        analysis_type;
+	int        doflist1[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], nodes, NUMVERTICES);
+	GradientIndexing(&doflist1[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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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,doflist1,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+	delete friction;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDragGradient{{{*/
+void  Tria::GradjDragGradient(Vector* gradient, int weight_index,int control_index){
+
+	int        i,ig;
+	int        doflist1[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], nodes, NUMVERTICES);
+	GradientIndexing(&doflist1[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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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,doflist1,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjDhDtBalancedthickness{{{*/
+void  Tria::GradjDhDtBalancedthickness(Vector* gradient,int control_index){
+
+	/*Intermediaries*/
+	int    doflist1[NUMVERTICES];
+	IssmDouble lambda[NUMVERTICES];
+	IssmDouble gradient_g[NUMVERTICES];
+
+	/*Compute Gradient*/
+	GradientIndexing(&doflist1[0],control_index);
+	GetInputListOnVertices(&lambda[0],AdjointEnum);
+	for(int i=0;i<NUMVERTICES;i++) gradient_g[i]=-lambda[i];
+
+	gradient->SetValues(NUMVERTICES,doflist1,gradient_g,INS_VAL);
+}
+/*}}}*/
+/*FUNCTION Tria::GradjVxBalancedthickness{{{*/
+void  Tria::GradjVxBalancedthickness(Vector* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i,ig;
+	int        doflist1[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], nodes, NUMVERTICES);
+	GradientIndexing(&doflist1[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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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,doflist1,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*FUNCTION Tria::GradjVyBalancedthickness{{{*/
+void  Tria::GradjVyBalancedthickness(Vector* gradient,int control_index){
+
+	/*Intermediaries*/
+	int        i,ig;
+	int        doflist1[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], nodes, NUMVERTICES);
+	GradientIndexing(&doflist1[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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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,doflist1,grade_g,ADD_VAL);
+
+	/*Clean up and return*/
+	delete gauss;
+}
+/*}}}*/
+/*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]->GetVertexDof() + control_index;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Tria::RheologyBbarAbsGradient{{{*/
+IssmDouble Tria::RheologyBbarAbsGradient(bool process_units,int weight_index){
+
+	/* Intermediaries */
+	int        ig;
+	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], nodes, NUMVERTICES);
+	Input* weights_input  =inputs->GetInput(InversionCostFunctionsCoefficientsEnum);              _assert_(weights_input);
+	Input* rheologyb_input=matice->inputs->GetInput(MaterialsRheologyBbarEnum); _assert_(rheologyb_input);
+
+	/* Start looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get 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){
+
+	const int    numdof=2*NUMVERTICES;
+
+	int        i,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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*pow( pow(vx-vxobs,2.) + pow(vy-vyobs,2.) ,0.5);
+
+		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){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int        i,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int        i,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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){
+
+	const int    numdof=NDOF2*NUMVERTICES;
+
+	int        i,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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){
+	const int  numdof=2*NUMVERTICES;
+
+	int        i,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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 */
+	int        ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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*(pow(dp[0],2.)+pow(dp[1],2.))*Jdet*gauss->weight;
+	}
+
+	/*Clean up and return*/
+	delete gauss;
+	return Jelem;
+}
+/*}}}*/
+/*FUNCTION Tria::ThicknessAbsMisfit {{{*/
+IssmDouble Tria::ThicknessAbsMisfit(bool process_units,int weight_index){
+
+	/*Intermediaries*/
+	int        i,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+
+		/*Get parameters at gauss point*/
+		thickness_input->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*pow(thickness-thicknessobs,2.0)*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,ig,resp;
+	IssmDouble      Jdet;
+	IssmDouble      thickness,thicknessobs,weight;
+	int        *responses = NULL;
+	int         num_responses;
+	IssmDouble      xyz_list[NUMVERTICES][3];
+	IssmDouble      basis[3];
+	IssmDouble      dbasis[NDOF2][NUMVERTICES];
+	IssmDouble      dH[2];
+	GaussTria*  gauss=NULL;
+
+	/*Initialize Element vector*/
+	ElementVector* pe=new ElementVector(nodes,NUMVERTICES,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes, 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);
+
+	/* Start  looping on the number of gaussian points: */
+	gauss=new GaussTria(2);
+	for(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdet, &xyz_list[0][0],gauss);
+		GetNodalFunctions(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;
+			default:
+				_error2_("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,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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 = - pow(meanvel,2.) * log((fabs(vx)+epsvel)/(fabs(vxobs)+epsvel)) / (vx+epsvel);
+						duy = - pow(meanvel,2.) * 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 RheologyBbarAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				default:
+					_error2_("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,ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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 = - pow(meanvel,2.) * log((fabs(vx)+epsvel)/(fabs(vxobs)+epsvel)) / (vx+epsvel);
+						duy = - pow(meanvel,2.) * 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 RheologyBbarAbsGradientEnum:
+					/*Nothing in P vector*/
+					break;
+				default:
+					_error2_("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 */
+	int        ig;
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		/* Get Jacobian determinant: */
+		GetJacobianDeterminant2d(&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*(pow(dp[0],2.)+pow(dp[1],2.))*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:
+			_error2_("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,ig;
+	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     phi[NUMVERTICES];
+	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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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);
+		matice->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])) _error2_("NaN found in solution vector");
+		if(xIsNan<IssmDouble>(lambday[i])) _error2_("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])) _error2_("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* vector,int control_enum,int control_index,const char* data){
+
+	int doflist1[NUMVERTICES];
+	Input *input=NULL;
+
+	/*Get out if this is not an element input*/
+	if(!IsInput(control_enum)) return;
+
+	/*Prepare index list*/
+	GradientIndexing(&doflist1[0],control_index);
+
+	/*Get input (either in element or material)*/
+	if(control_enum==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->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){
+		_error2_("input " << EnumToStringx(control_enum) << " is not a ControlInput");
+	}
+
+	((ControlInput*)input)->GetVectorFromInputs(vector,&doflist1[0],data);
+}
+/*}}}*/
+/*FUNCTION Tria::SetControlInputsFromVector{{{*/
+void  Tria::SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index){
+
+	IssmDouble  values[NUMVERTICES];
+	int     doflist1[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(&doflist1[0],control_index);
+
+	/*Get values on vertices*/
+	for (int i=0;i<NUMVERTICES;i++){
+		values[i]=vector[doflist1[i]];
+	}
+	new_input = new TriaP1Input(control_enum,values);
+
+	if(control_enum==MaterialsRheologyBbarEnum){
+		input=(Input*)matice->inputs->GetInput(control_enum); _assert_(input);
+	}
+	else{
+		input=(Input*)this->inputs->GetInput(control_enum);   _assert_(input);
+	}
+
+	if (input->ObjectEnum()!=ControlInputEnum){
+		_error2_("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*pow(CR,2)*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]= - pow(w,2)/(12 * mu_water)*(rho_ice*g*dsdx+(rho_water-rho_ice)*g*dbdx);
+	//	vy[iv]= - pow(w,2)/(12 * mu_water)*(rho_ice*g*dsdy+(rho_water-rho_ice)*g*dbdy);
+	
+		vx[iv]= - pow(w,2)/(VelocityFactor* mu_water)*(rho_ice*g*dsdx+(rho_water-rho_ice)*g*dbdx);
+		vy[iv]= - pow(w,2)/(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::CreateKMatrixHydrology{{{*/
+ElementMatrix* Tria::CreateKMatrixHydrology(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	IssmDouble     diffusivity;
+	int        i,j,ig;
+	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], nodes, NUMVERTICES);
+	this->parameters->FindParam(&dt,TimesteppingTimeStepEnum);
+	this->parameters->FindParam(&diffusivity,HydrologyStabilizationEnum);
+	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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		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(pow(vx,2.)+pow(vy,2.));
+		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::CreatePVectorHydrology {{{*/
+ElementVector* Tria::CreatePVectorHydrology(void){
+
+	/*Constants*/
+	const int    numdof=NDOF1*NUMVERTICES;
+
+	/*Intermediaries */
+	int        i,j,ig;
+	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], nodes, 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(ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&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(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::GetSolutionFromInputsHydrology{{{*/
+void  Tria::GetSolutionFromInputsHydrology(Vector* 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::InputUpdateFromSolutionHydrology{{{*/
+void  Tria::InputUpdateFromSolutionHydrology(IssmDouble* solution){
+
+	/*Intermediaries*/
+	const int numdof = NDOF1*NUMVERTICES;
+
+	int       i;
+	int*      doflist=NULL;
+	IssmDouble    values[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]];
+		if(xIsNan<IssmDouble>(values[i])) _error2_("NaN found in solution vector");
+		if (values[i]<pow((IssmDouble)10,(IssmDouble)-10))values[i]=pow((IssmDouble)10,(IssmDouble)-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);
+}
+/*}}}*/
+#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]->GetSidList()]; //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:
+			_error2_("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){
+	_error2_("not supported yet!");
+}
+/*}}}*/
+/*FUNCTION Tria::InputUpdateFromVectorDakota(bool* vector, int name, int type);{{{*/
+void  Tria::InputUpdateFromVectorDakota(bool* vector, int name, int type){
+	_error2_("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]->GetSidList();
+					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:
+			_error2_("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:
+			_error2_("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,ig,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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetBPrognostic(&B[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+
+		vxaverage_input->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(pow(vx,2.)+pow(vy,2.));
+			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,ig,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], nodes, 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 (ig=gauss->begin();ig<gauss->end();ig++){
+
+		gauss->GaussPoint(ig);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		/*WARNING: B and Bprime are inverted compared to usual prognostic!!!!*/
+		GetBPrognostic(&Bprime[0][0], &xyz_list[0][0], gauss);
+		GetBprimePrognostic(&B[0][0], &xyz_list[0][0], gauss);
+
+		vx_input->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:
+			_error2_("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,ig;
+	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], nodes, 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(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);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(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,ig;
+	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], nodes, 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(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);
+
+		GetJacobianDeterminant2d(&Jdettria, &xyz_list[0][0],gauss);
+		GetL(&L[0], &xyz_list[0][0], gauss,NDOF1);
+
+		for(i=0;i<numdof;i++) pe->values[i]+=Jdettria*gauss->weight*(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/objects/Elements/Tria.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/Tria.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/Tria.h	(revision 12822)
@@ -0,0 +1,239 @@
+/*! \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 Matice;
+class Matpar;
+class ElementMatrix;
+class ElementVector;
+
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+/*}}}*/
+
+class Tria: public Element,public TriaHook,public TriaRef{
+
+	public:
+
+		int  id;
+		int  sid;
+
+		Node   **nodes;    // 3 nodes
+		Matice  *matice;   // 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   MyRank();
+		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* partition_contributions,Vector* partition_areas,IssmDouble* vertex_response,IssmDouble* qmu_part);
+		void   ComputeBasalStress(Vector* sigma_b);
+		void   ComputeStrainRate(Vector* eps);
+		void   ComputeStressTensor();
+		void   Configure(Elements* elements,Loads* loads,DataSet* nodes,Materials* materials,Parameters* parameters);
+		void   SetCurrentConfiguration(Elements* elements,Loads* loads,DataSet* nodes,Materials* materials,Parameters* parameters);
+		void   CreateKMatrix(Matrix* Kff, Matrix* Kfs,Vector* df);
+		void   CreatePVector(Vector* pf);
+		void   CreateJacobianMatrix(Matrix* Jff);
+		void   Delta18oParameterization(void);
+		int    GetNodeIndex(Node* node);
+		int    Sid();
+		bool   IsOnBed();
+		bool   IsFloating(); 
+		bool   IsNodeOnShelf(); 
+		bool   IsNodeOnShelfFromFlags(IssmDouble* flags);
+		bool   IsOnWater(); 
+		void   GetSolutionFromInputs(Vector* solution);
+		void   GetVectorFromInputs(Vector* vector, int name_enum);
+		void   GetVectorFromResults(Vector* 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){_error2_("not implemented yet");};
+		void   MigrateGroundingLine(IssmDouble* oldfloating,IssmDouble* sheet_ungrounding);
+		int    NodalValue(IssmDouble* pvalue, int index, int natureofdataenum,bool process_units);
+		void   PotentialSheetUngrounding(Vector* 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){_error2_("not implemented yet");};
+		void	 SmbGradients();
+		IssmDouble SurfaceArea(void);
+		void   Update(int index, IoModel* iomodel,int analysis_counter,int analysis_type);
+		int    UpdatePotentialSheetUngrounding(IssmDouble* vertices_potentially_ungrounding,Vector* vec_nodes_on_iceshelf,IssmDouble* nodes_on_iceshelf);
+		IssmDouble TimeAdapt();
+		int*   GetHorizontalNeighboorSids(void);
+		void   SmearFunction(Vector* 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_CONTROL_
+		IssmDouble DragCoefficientAbsGradient(bool process_units,int weight_index);
+		void   GradientIndexing(int* indexing,int control_index);
+		void   Gradj(Vector* gradient,int control_type,int control_index);
+		void   GradjBGradient(Vector* gradient,int weight_index,int control_index);
+		void   GradjBMacAyeal(Vector* gradient,int control_index);
+		void   GradjDragMacAyeal(Vector* gradient,int control_index);
+		void   GradjDragStokes(Vector* gradient,int control_index);
+		void   GradjDragGradient(Vector* gradient,int weight_index,int control_index);
+		void   GradjDhDtBalancedthickness(Vector* gradient,int control_index);
+		void   GradjVxBalancedthickness(Vector* gradient,int control_index);
+		void   GradjVyBalancedthickness(Vector* gradient,int control_index);
+		void   GetVectorFromControlInputs(Vector* gradient,int control_enum,int control_index,const char* data);
+		void   SetControlInputsFromVector(IssmDouble* vector,int control_enum,int control_index);
+		void   ControlInputGetGradient(Vector* 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 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* CreateKMatrixSlope(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	         GetDofList1(int* doflist);
+		void           GetSidList(int* sidlist);
+		void           GetConnectivityList(int* connectivity);
+		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* solution);
+		void	  GetSolutionFromInputsDiagnosticHutter(Vector* 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* CreateKMatrixHydrology(void);
+		ElementVector* CreatePVectorHydrology(void);
+		void      CreateHydrologyWaterVelocityInput(void);
+		void	  GetSolutionFromInputsHydrology(Vector* solution);
+		void	  InputUpdateFromSolutionHydrology(IssmDouble* solution);
+		#endif
+		#ifdef _HAVE_BALANCED_
+		#endif
+
+		/*}}}*/
+
+};
+#endif  /* _TRIA_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/TriaHook.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/TriaHook.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/TriaHook.cpp	(revision 12822)
@@ -0,0 +1,72 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Object constructors and destructor*/
+/*FUNCTION TriaHook::TriaHook(){{{*/
+TriaHook::TriaHook(){
+	numanalyses=UNDEF;
+	this->hnodes=NULL;
+	this->hmatice=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 [] this->hnodes;
+	delete hmatice;
+	delete hmatpar;
+
+}
+/*}}}*/
+/*FUNCTION TriaHook::TriaHook(int in_numanalyses,int matice_id, int matpar_id){{{*/
+TriaHook::TriaHook(int in_numanalyses,int matice_id, IoModel* iomodel){
+
+	/*intermediary: */
+	int matpar_id;
+
+	/*retrieve parameters: */
+	iomodel->Constant(&matpar_id,MeshNumberofelementsEnum); matpar_id++;
+	
+	this->numanalyses=in_numanalyses;
+	this->hnodes= new Hook*[in_numanalyses];
+	this->hmatice=new Hook(&matice_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/objects/Elements/TriaHook.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/TriaHook.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/TriaHook.h	(revision 12822)
@@ -0,0 +1,31 @@
+/*!\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; // 3 nodes for each analysis type
+		Hook*  hmatice; // 1 ice material
+		Hook*  hmatpar; // 1 material parameter
+
+
+		/*FUNCTION constructors, destructors {{{*/
+		TriaHook();
+		TriaHook(int in_numanalyses,int matice_id, IoModel* iomodel);
+		~TriaHook();
+		void SetHookNodes(int* node_ids,int analysis_counter);
+		/*}}}*/
+
+};
+
+
+#endif //ifndef _TRIAHOOK_H_
+
Index: /issm/trunk-jpl/src/c/classes/objects/Elements/TriaRef.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/TriaRef.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/TriaRef.cpp	(revision 12822)
@@ -0,0 +1,503 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Element macros*/
+#define NUMNODES 3
+
+/*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::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*NUMNODES)
+	 */
+
+	int i;
+	IssmDouble dbasis[NDOF2][NUMNODES];
+
+	/*Get dh1dh2dh3 in actual coordinate system: */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B: */
+	for (i=0;i<NUMNODES;i++){
+		*(B+NDOF2*NUMNODES*0+NDOF2*i)=dbasis[0][i]; //B[0][NDOF2*i]=dbasis[0][i];
+		*(B+NDOF2*NUMNODES*0+NDOF2*i+1)=0;
+		*(B+NDOF2*NUMNODES*1+NDOF2*i)=0;
+		*(B+NDOF2*NUMNODES*1+NDOF2*i+1)=dbasis[1][i];
+		*(B+NDOF2*NUMNODES*2+NDOF2*i)=(float).5*dbasis[1][i]; 
+		*(B+NDOF2*NUMNODES*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*NUMNODES)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODES];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODES;i++){
+		*(B+NDOF2*NUMNODES*0+NDOF2*i)=dbasis[0][i]; 
+		*(B+NDOF2*NUMNODES*0+NDOF2*i+1)=0; 
+		*(B+NDOF2*NUMNODES*1+NDOF2*i)=0; 
+		*(B+NDOF2*NUMNODES*1+NDOF2*i+1)=dbasis[1][i]; 
+		*(B+NDOF2*NUMNODES*2+NDOF2*i)=0.5*dbasis[1][i]; 
+		*(B+NDOF2*NUMNODES*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[NUMNODES];
+
+	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[NUMNODES];
+
+	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*NUMNODES)
+	 */
+
+	IssmDouble basis[NUMNODES];
+
+	/*Get dh1dh2dh3 in actual coordinate system: */
+	GetNodalFunctions(&basis[0],gauss);
+
+	/*Build B_prog: */
+	for (int i=0;i<NUMNODES;i++){
+		*(B_prog+NDOF1*NUMNODES*0+NDOF1*i)=basis[i];
+		*(B_prog+NDOF1*NUMNODES*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*NUMNODES)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODES];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODES;i++){
+		*(Bprime+NDOF2*NUMNODES*0+NDOF2*i)=2*dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODES*0+NDOF2*i+1)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODES*1+NDOF2*i)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODES*1+NDOF2*i+1)=2*dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODES*2+NDOF2*i)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODES*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*NUMNODES)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODES];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build Bprime: */
+	for (int i=0;i<NUMNODES;i++){
+		*(Bprime+NDOF2*NUMNODES*0+NDOF2*i)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODES*0+NDOF2*i+1)=0; 
+		*(Bprime+NDOF2*NUMNODES*1+NDOF2*i)=0; 
+		*(Bprime+NDOF2*NUMNODES*1+NDOF2*i+1)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODES*2+NDOF2*i)=dbasis[1][i]; 
+		*(Bprime+NDOF2*NUMNODES*2+NDOF2*i+1)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODES*3+NDOF2*i)=dbasis[0][i]; 
+		*(Bprime+NDOF2*NUMNODES*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*NUMNODES)
+	 */
+
+	/*Same thing in the actual coordinate system: */
+	IssmDouble dbasis[NDOF2][NUMNODES];
+
+	/*Get dh1dh2dh3 in actual coordinates system : */
+	GetNodalFunctionsDerivatives(&dbasis[0][0],xyz_list,gauss);
+
+	/*Build B': */
+	for (int i=0;i<NUMNODES;i++){
+		*(Bprime_prog+NDOF1*NUMNODES*0+NDOF1*i)=dbasis[0][i]; 
+		*(Bprime_prog+NDOF1*NUMNODES*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: NUMNODES (numdof=1), or numdofx(numdof*NUMNODES) (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<NUMNODES;i++){
+			L[i]=basis[i]; 
+		}
+	}
+	else{
+		for (i=0;i<NUMNODES;i++){
+			*(L+numdof*NUMNODES*0+numdof*i)=basis[i]; //L[0][NDOF2*i]=dbasis[0][i];
+			*(L+numdof*NUMNODES*0+numdof*i+1)=0;
+			*(L+numdof*NUMNODES*1+numdof*i)=0;
+			*(L+numdof*NUMNODES*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+NUMNODES*0+0);
+	y1=*(xyz_list+NUMNODES*0+1);
+	x2=*(xyz_list+NUMNODES*1+0);
+	y2=*(xyz_list+NUMNODES*1+1);
+	x3=*(xyz_list+NUMNODES*2+0);
+	y3=*(xyz_list+NUMNODES*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) _error2_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetJacobianDeterminant2d{{{*/
+void TriaRef::GetJacobianDeterminant2d(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) _error2_("negative jacobian determinant!");
+
+}
+/*}}}*/
+/*FUNCTION TriaRef::GetJacobianDeterminant3d {{{*/
+void TriaRef::GetJacobianDeterminant3d(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 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=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) _error2_("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::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][NUMNODES];
+	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<NUMNODES;i++){
+		dbasis[NUMNODES*0+i]=Jinv[0][0]*dbasis_ref[0][i]+Jinv[0][1]*dbasis_ref[1][i];
+		dbasis[NUMNODES*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+NUMNODES*0+0)=-0.5; 
+	*(dl1dl3+NUMNODES*1+0)=-1.0/(2.0*SQRT3);
+
+	/*Second nodal function: */
+	*(dl1dl3+NUMNODES*0+1)=0.5;
+	*(dl1dl3+NUMNODES*1+1)=-1.0/(2.0*SQRT3);
+
+	/*Third nodal function: */
+	*(dl1dl3+NUMNODES*0+2)=0;
+	*(dl1dl3+NUMNODES*1+2)=1.0/SQRT3;
+
+}
+/*}}}*/
+/*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/objects/Elements/TriaRef.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Elements/TriaRef.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Elements/TriaRef.h	(revision 12822)
@@ -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 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 GetJacobianDeterminant2d(IssmDouble* Jdet, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetJacobianDeterminant3d(IssmDouble* Jdet, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetJacobianInvert(IssmDouble*  Jinv, IssmDouble* xyz_list,GaussTria* gauss);
+		void GetNodalFunctions(IssmDouble* l1l2l3,GaussTria* gauss);
+		void GetSegmentNodalFunctions(IssmDouble* l1l2l3,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* l1l2l3,IssmDouble* xyz_list, GaussTria* gauss);
+		void GetNodalFunctionsDerivativesReference(IssmDouble* dl1dl3,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/objects/ExternalResults/BoolExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/BoolExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/BoolExternalResult.cpp	(revision 12822)
@@ -0,0 +1,132 @@
+/*!\file BoolExternalResult.c
+ * \brief: implementation of the BoolExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*BoolExternalResult constructors and destructor*/
+/*FUNCTION BoolExternalResult::BoolExternalResult(){{{*/
+BoolExternalResult::BoolExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::BoolExternalResult(int enum_type,bool value){{{*/
+BoolExternalResult::BoolExternalResult(int in_id, int in_enum_type,bool 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;
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::~BoolExternalResult(){{{*/
+BoolExternalResult::~BoolExternalResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION BoolExternalResult::Echo {{{*/
+void BoolExternalResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::DeepEcho{{{*/
+void BoolExternalResult::DeepEcho(void){
+
+	_printLine_("BoolExternalResult:");
+	_printLine_("   id: " << this->id);
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " <<(this->value?"true":"false"));
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::Id{{{*/
+int    BoolExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION BoolExternalResult::MyRank{{{*/
+int    BoolExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::ObjectEnum{{{*/
+int BoolExternalResult::ObjectEnum(void){
+
+	return BoolExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::copy{{{*/
+Object* BoolExternalResult::copy() {
+	
+	return new BoolExternalResult(this->id,this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*BoolExternalResult management: */
+/*FUNCTION BoolExternalResult::WriteData{{{*/
+void   BoolExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	int     size;
+	IssmPDouble  passiveDouble;
+	extern  int my_rank;
+	char*   name = NULL;
+
+	/*return if now on cpu 0: */
+	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, type is 1, size is 1: */
+	type=1;
+	size=1;
+	fwrite(&type,sizeof(int),1,fid);
+	fwrite(&size,sizeof(int),1,fid);
+        /*Now write bool, after casting it: */
+        passiveDouble=reCast<IssmPDouble>(this->value);
+        fwrite(&passiveDouble,size*sizeof(IssmPDouble),1,fid);
+
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::GetResultName{{{*/
+void BoolExternalResult::GetResultName(char** pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION BoolExternalResult::GetStep{{{*/
+int BoolExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/BoolExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/BoolExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/BoolExternalResult.h	(revision 12822)
@@ -0,0 +1,54 @@
+/*! \file BoolExternalResult.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _BOOLEXTERNALRESULT_H_
+#define _BOOLEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../include/include.h"
+/*}}}*/
+
+class BoolExternalResult: public ExternalResult{
+
+	public:
+		int    id;
+		int    enum_type;
+		bool   value;
+		int    step;
+		IssmDouble time;
+
+		/*BoolExternalResult constructors, destructors: {{{*/
+		BoolExternalResult();
+		BoolExternalResult(int id, int enum_type,bool value,int step,IssmDouble time);
+		~BoolExternalResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult management: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleExternalResult.cpp	(revision 12822)
@@ -0,0 +1,131 @@
+/*!\file DoubleExternalResult.c
+ * \brief: implementation of the DoubleExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*DoubleExternalResult constructors and destructor*/
+/*FUNCTION DoubleExternalResult::DoubleExternalResult(){{{*/
+DoubleExternalResult::DoubleExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::DoubleExternalResult(int enum_type,IssmDouble value){{{*/
+DoubleExternalResult::DoubleExternalResult(int in_id, int in_enum_type,IssmDouble 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;
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::~DoubleExternalResult(){{{*/
+DoubleExternalResult::~DoubleExternalResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleExternalResult::Echo {{{*/
+void DoubleExternalResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::DeepEcho{{{*/
+void DoubleExternalResult::DeepEcho(void){
+
+	_printLine_("DoubleExternalResult:");
+	_printLine_("   id: " << this->id);
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::Id{{{*/
+int    DoubleExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleExternalResult::MyRank{{{*/
+int    DoubleExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::ObjectEnum{{{*/
+int DoubleExternalResult::ObjectEnum(void){
+
+	return DoubleExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::copy{{{*/
+Object* DoubleExternalResult::copy() {
+	
+	return new DoubleExternalResult(this->id,this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*DoubleExternalResult management: */
+/*FUNCTION DoubleExternalResult::WriteData{{{*/
+void   DoubleExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	int     size;
+	char   *name    = NULL;
+	extern  int my_rank;
+	IssmPDouble passiveDouble;
+
+	/*return if now on cpu 0: */
+	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, type is 1, size is 1: */
+	type=1;
+	size=1;
+	fwrite(&type,sizeof(int),1,fid);
+	fwrite(&size,sizeof(int),1,fid);
+        passiveDouble=reCast<IssmPDouble>(this->value);
+	fwrite(&passiveDouble,size*sizeof(IssmPDouble),1,fid);
+
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::GetResultName{{{*/
+void DoubleExternalResult::GetResultName(char** pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleExternalResult::GetStep{{{*/
+int DoubleExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleExternalResult.h	(revision 12822)
@@ -0,0 +1,56 @@
+/*! \file DoubleExternalResult.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _DOUBLEEXTERNALRESULT_H_
+#define _DOUBLEEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../include/include.h"
+/*}}}*/
+
+class DoubleExternalResult: public ExternalResult{
+
+	public:
+		int    id;
+		int    enum_type;
+		IssmDouble value;
+		int    step;
+		IssmDouble time;
+
+
+		/*DoubleExternalResult constructors, destructors: {{{*/
+		DoubleExternalResult();
+		DoubleExternalResult(int id,int enum_type,IssmDouble value,int step,IssmDouble time);
+		~DoubleExternalResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult management: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif  /* _DOUBLEEXTERNALRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleMatExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleMatExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleMatExternalResult.cpp	(revision 12822)
@@ -0,0 +1,166 @@
+/*!\file DoubleMatExternalResult.c
+ * \brief: implementation of the DoubleMatExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*DoubleMatExternalResult constructors and destructor*/
+/*FUNCTION DoubleMatExternalResult::DoubleMatExternalResult(){{{*/
+DoubleMatExternalResult::DoubleMatExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::DoubleMatExternalResult(int in_id, int enum_type,IssmDoubleMat values,int M,int N,int in_step,IssmDouble in_time){{{*/
+DoubleMatExternalResult::DoubleMatExternalResult(int in_id, int in_enum_type,IssmDouble* 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;
+
+	/*Copy result in values*/
+	if(M*N){
+		values=xNew<IssmDouble>(M*N);
+		xMemCpy<IssmDouble>(values,in_values,M*N);
+	}
+	else values=NULL;
+
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::~DoubleMatExternalResult(){{{*/
+DoubleMatExternalResult::~DoubleMatExternalResult(){
+
+	xDelete<IssmDouble>(this->values);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleMatExternalResult::Echo {{{*/
+void DoubleMatExternalResult::Echo(void){
+
+	_printLine_("DoubleMatExternalResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+	_printLine_("   matrix size: " << this->M << "-" << this->N);
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::DeepEcho{{{*/
+void DoubleMatExternalResult::DeepEcho(void){
+
+	int i,j;
+	
+	_printLine_("DoubleMatExternalResult:");
+	_printLine_("   id: " << this->id);
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+	_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->values[i*this->N+j]);
+		}  
+		_printLine_(" ]");
+	}  
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::Id{{{*/
+int    DoubleMatExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::MyRank{{{*/
+int    DoubleMatExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::ObjectEnum{{{*/
+int DoubleMatExternalResult::ObjectEnum(void){
+
+	return DoubleMatExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::copy{{{*/
+Object* DoubleMatExternalResult::copy() {
+	
+	return new DoubleMatExternalResult(this->id,this->enum_type,this->values,this->M,this->N,this->step,this->time);
+
+}
+/*}}}*/
+
+/*DoubleMatExternalResult management: */
+/*FUNCTION DoubleMatExternalResult::WriteData{{{*/
+void   DoubleMatExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	int     rows,cols;
+	char   *name    = NULL;
+	extern  int my_rank;
+	IssmPDouble *passiveDouble_p=NULL;
+	IssmPDouble passiveDouble;
+
+	if(io_gather){
+		/*we are gathering the data on cpu 0, don't write on other cpus: */
+		if(my_rank) return;
+	}
+
+	passiveDouble_p=xNew<IssmPDouble>(M*N);
+
+	/*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);
+	for (int i=0; i<N*M; ++i) passiveDouble_p[i]=reCast<IssmPDouble>(values[i]);
+	fwrite(passiveDouble_p,cols*rows*sizeof(IssmPDouble),1,fid);
+	xDelete(passiveDouble_p);
+
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::GetResultName{{{*/
+void DoubleMatExternalResult::GetResultName(char** pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleMatExternalResult::GetStep{{{*/
+int DoubleMatExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleMatExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleMatExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleMatExternalResult.h	(revision 12822)
@@ -0,0 +1,56 @@
+/*! \file DoubleMatExternalResult.h 
+ */
+
+
+#ifndef _DOUBLEMATEXTERNALRESULT_H_
+#define _DOUBLEMATEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../include/include.h"
+/*}}}*/
+
+class DoubleMatExternalResult: public ExternalResult{
+
+	private: 
+		int id;
+		int enum_type;
+		IssmDouble* values;
+		int M;
+		int N;
+		int step;
+		IssmDouble time;
+
+	public:
+		/*DoubleMatExternalResult constructors, destructors: {{{*/
+		DoubleMatExternalResult();
+		DoubleMatExternalResult(int id,int enum_type,IssmDouble* values,int M,int N,int step, IssmDouble time);
+		~DoubleMatExternalResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult managemnet: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif  /* _DOUBLEMATEXTERNALRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleVecExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleVecExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleVecExternalResult.cpp	(revision 12822)
@@ -0,0 +1,152 @@
+/*!\file DoubleVecExternalResult.c
+ * \brief: implementation of the DoubleVecExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*DoubleVecExternalResult constructors and destructor*/
+/*FUNCTION DoubleVecExternalResult::DoubleVecExternalResult(){{{*/
+DoubleVecExternalResult::DoubleVecExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::DoubleVecExternalResult(int enum_type,IssmDoubleVec values,int M,int in_step,IssmDouble in_time){{{*/
+DoubleVecExternalResult::DoubleVecExternalResult(int in_id, int in_enum_type,IssmDouble* in_values, int in_M,int in_step,IssmDouble in_time){
+
+	id=in_id;
+	enum_type=in_enum_type;
+	M=in_M;
+
+	if(M){
+		values=xNew<IssmDouble>(M);
+		xMemCpy<IssmDouble>(values,in_values,M);
+	}
+	else values=NULL;
+
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::~DoubleVecExternalResult(){{{*/
+DoubleVecExternalResult::~DoubleVecExternalResult(){
+	xDelete<IssmDouble>(values);
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION DoubleVecExternalResult::Echo {{{*/
+void DoubleVecExternalResult::Echo(void){
+
+	_printLine_("DoubleVecExternalResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   vector size: " << this->M);
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::DeepEcho{{{*/
+void DoubleVecExternalResult::DeepEcho(void){
+
+	int i;
+	
+	_printLine_("DoubleVecExternalResult:");
+	_printLine_("   id: " << this->id);
+	_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]);
+	}
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::Id{{{*/
+int    DoubleVecExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::MyRank{{{*/
+int    DoubleVecExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::ObjectEnum{{{*/
+int DoubleVecExternalResult::ObjectEnum(void){
+
+	return DoubleVecExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::copy{{{*/
+Object* DoubleVecExternalResult::copy() {
+	
+	return new DoubleVecExternalResult(this->id,this->enum_type,this->values,this->M,this->step,this->time);
+
+}
+/*}}}*/
+
+/*DoubleVecExternalResult management: */
+/*FUNCTION DoubleVecExternalResult::WriteData{{{*/
+void   DoubleVecExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	int     size;
+	char   *name    = NULL;
+	extern  int my_rank;
+	IssmPDouble *passiveDouble_p=NULL;
+	IssmPDouble passiveDouble;
+
+	/*return if now on cpu 0: */
+	if(my_rank)return;
+
+	passiveDouble_p=xNew<IssmPDouble>(M);
+	/*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, type is 1, size is 1: */
+	type=1;
+	size=this->M;
+	fwrite(&type,sizeof(int),1,fid);
+	fwrite(&size,sizeof(int),1,fid);
+        for (int i=0; i<M; ++i) passiveDouble_p[i]=reCast<IssmPDouble>(values[i]);
+	fwrite(passiveDouble_p,size*sizeof(IssmPDouble),1,fid);
+        xDelete(passiveDouble_p);
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::GetResultName{{{*/
+void DoubleVecExternalResult::GetResultName(char** pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION DoubleVecExternalResult::GetStep{{{*/
+int DoubleVecExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleVecExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleVecExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/DoubleVecExternalResult.h	(revision 12822)
@@ -0,0 +1,55 @@
+/*! \file DoubleVecExternalResult.h 
+ */
+
+
+#ifndef _DOUBLEVECEXTERNALRESULT_H_
+#define _DOUBLEVECEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../include/include.h"
+/*}}}*/
+
+class DoubleVecExternalResult: public ExternalResult{
+
+	private: 
+		int id;
+		int enum_type;
+		IssmDouble* values;
+		int M;
+		int step;
+		IssmDouble time;
+
+	public:
+		/*DoubleVecExternalResult constructors, destructors: {{{*/
+		DoubleVecExternalResult();
+		DoubleVecExternalResult(int id,int enum_type,IssmDouble* values,int M,int step, IssmDouble time);
+		~DoubleVecExternalResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult management: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif  /* _DOUBLEVECEXTERNALRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/ExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/ExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/ExternalResult.h	(revision 12822)
@@ -0,0 +1,34 @@
+/*!\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/objects/ExternalResults/IntExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/IntExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/IntExternalResult.cpp	(revision 12822)
@@ -0,0 +1,132 @@
+/*!\file IntExternalResult.c
+ * \brief: implementation of the IntExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*IntExternalResult constructors and destructor*/
+/*FUNCTION IntExternalResult::IntExternalResult(){{{*/
+IntExternalResult::IntExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::IntExternalResult(int in_id, int in_enum_type,int in_value,int in_step, IssmDouble in_time){{{*/
+IntExternalResult::IntExternalResult(int in_id, int in_enum_type,int 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;
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::~IntExternalResult(){{{*/
+IntExternalResult::~IntExternalResult(){
+	return;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION IntExternalResult::Echo {{{*/
+void IntExternalResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::DeepEcho{{{*/
+void IntExternalResult::DeepEcho(void){
+
+	_printLine_("IntExternalResult:");
+	_printLine_("   id: " << this->id);
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::Id{{{*/
+int    IntExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION IntExternalResult::MyRank{{{*/
+int    IntExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::ObjectEnum{{{*/
+int IntExternalResult::ObjectEnum(void){
+
+	return IntExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::copy{{{*/
+Object* IntExternalResult::copy() {
+	
+	return new IntExternalResult(this->id,this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*IntExternalResult management: */
+/*FUNCTION IntExternalResult::WriteData{{{*/
+void   IntExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	int     size;
+	char   *name    = NULL;
+	IssmPDouble  passiveDouble;
+	extern  int my_rank;
+
+	/*return if now on cpu 0: */
+	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 IssmPDouble, 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);
+
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::GetResultName{{{*/
+void IntExternalResult::GetResultName(char** pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION IntExternalResult::GetStep{{{*/
+int IntExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/IntExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/IntExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/IntExternalResult.h	(revision 12822)
@@ -0,0 +1,54 @@
+/*! \file IntExternalResult.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _INTEXTERNALRESULT_H_
+#define _INTEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class IntExternalResult: public ExternalResult{
+
+	public:
+		int    id;
+		int    enum_type;
+		int    value;
+		int    step;
+		IssmDouble time;
+
+
+		/*IntExternalResult constructors, destructors: {{{*/
+		IntExternalResult();
+		IntExternalResult(int id,int enum_type,int value,int step,IssmDouble time);
+		~IntExternalResult();
+
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult managemnet: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif  /* _INTEXTERNALRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/PetscVecExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/PetscVecExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/PetscVecExternalResult.cpp	(revision 12822)
@@ -0,0 +1,149 @@
+/*!\file PetscVecExternalResult.c
+ * \brief: implementation of the PetscVecExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*PetscVecExternalResult constructors and destructor*/
+/*FUNCTION PetscVecExternalResult::PetscVecExternalResult(){{{*/
+PetscVecExternalResult::PetscVecExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::PetscVecExternalResult(int enum_type,IssmPetscVec value){{{*/
+PetscVecExternalResult::PetscVecExternalResult(int in_id, int in_enum_type,Vector* in_value,int in_step, IssmDouble in_time){
+
+	id=in_id;
+	enum_type=in_enum_type;
+
+	value=NULL;
+
+	if(in_value){
+		value=in_value->Duplicate();
+		in_value->Copy(value);
+	}
+	else value=NULL;
+
+	step=in_step;
+	time=in_time;
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::~PetscVecExternalResult(){{{*/
+PetscVecExternalResult::~PetscVecExternalResult(){
+	VecFree(&value);
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION PetscVecExternalResult::Echo {{{*/
+void PetscVecExternalResult::Echo(void){
+
+	_printLine_("PetscVecExternalResult:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::DeepEcho{{{*/
+void PetscVecExternalResult::DeepEcho(void){
+
+	int i;
+	_printLine_("PetscVecExternalResult:");
+	_printLine_("   id: " << this->id);
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+	VecView(value,PETSC_VIEWER_STDOUT_WORLD);
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::Id{{{*/
+int    PetscVecExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::MyRank{{{*/
+int    PetscVecExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::ObjectEnum{{{*/
+int PetscVecExternalResult::ObjectEnum(void){
+
+	return PetscVecExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::copy{{{*/
+Object* PetscVecExternalResult::copy() {
+	
+	return new PetscVecExternalResult(this->id,this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*PetscVecExternalResult management: */
+/*FUNCTION PetscVecExternalResult::WriteData{{{*/
+void   PetscVecExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	int     size;
+	char   *name      = NULL;
+	IssmPDouble *serialvec = NULL;
+	extern int my_rank;
+	IssmPDouble passiveDouble;
+
+	/*serialize: */
+	VecGetSize(this->value,&size);
+	VecToMPISerial(&serialvec,this->value);
+
+	/*now, exit if we are not on cpu 0: */
+	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, type is 1, size is 1: */
+	type=1;
+	
+	fwrite(&type,sizeof(int),1,fid);
+	fwrite(&size,sizeof(int),1,fid);
+	fwrite(serialvec,size*sizeof(IssmPDouble),1,fid);
+
+	/*Free ressources:*/
+	xDelete<IssmPDouble>(serialvec);
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::GetResultName{{{*/
+void PetscVecExternalResult::GetResultName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION PetscVecExternalResult::GetStep{{{*/
+int PetscVecExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/PetscVecExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/PetscVecExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/PetscVecExternalResult.h	(revision 12822)
@@ -0,0 +1,55 @@
+/*! \file PetscVecExternalResult.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _PETSCVECEXTERNALRESULT_H_
+#define _PETSCVECEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../include/include.h"
+/*}}}*/
+
+class PetscVecExternalResult: public ExternalResult{
+
+	private: 
+		int id;
+		int enum_type;
+		Vector* value;
+		int step;
+		IssmDouble time;
+
+	public:
+		/*PetscVecExternalResult constructors, destructors: {{{*/
+		PetscVecExternalResult();
+		PetscVecExternalResult(int id,int enum_type,Vector* value, int step, IssmDouble time);
+		~PetscVecExternalResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult management: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif  /* _PETSCVECEXTERNALRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/StringExternalResult.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/StringExternalResult.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/StringExternalResult.cpp	(revision 12822)
@@ -0,0 +1,132 @@
+/*!\file StringExternalResult.c
+ * \brief: implementation of the StringExternalResult object
+ */
+
+/*header files: */
+/*{{{*/
+#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 "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*StringExternalResult constructors and destructor*/
+/*FUNCTION StringExternalResult::StringExternalResult(){{{*/
+StringExternalResult::StringExternalResult(){
+	return;
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::StringExternalResult(int enum_type,IssmString value){{{*/
+StringExternalResult::StringExternalResult(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;
+	
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::~StringExternalResult(){{{*/
+StringExternalResult::~StringExternalResult(){
+	xDelete<char>(value);
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION StringExternalResult::Echo {{{*/
+void StringExternalResult::Echo(void){
+	this->DeepEcho();
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::DeepEcho{{{*/
+void StringExternalResult::DeepEcho(void){
+
+	_printLine_("StringExternalResult:");
+	_printLine_("   id: " << this->id);
+	_printLine_("   enum:  " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   value: " << this->value);
+	_printLine_("   step: " << this->step);
+	_printLine_("   time: " << this->time);
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::Id{{{*/
+int    StringExternalResult::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION StringExternalResult::MyRank{{{*/
+int    StringExternalResult::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::ObjectEnum{{{*/
+int StringExternalResult::ObjectEnum(void){
+
+	return StringExternalResultEnum;
+
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::copy{{{*/
+Object* StringExternalResult::copy() {
+	
+	return new StringExternalResult(this->id,this->enum_type,this->value,this->step,this->time);
+
+}
+/*}}}*/
+
+/*StringExternalResult management: */
+/*FUNCTION StringExternalResult::WriteData{{{*/
+void   StringExternalResult::WriteData(FILE* fid,bool io_gather){
+
+	int     length;
+	int     type;
+	char   *name      = NULL;
+	extern  int my_rank;
+        IssmPDouble passiveDouble;
+
+	/*return if now on cpu 0: */
+	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 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);
+
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::GetResultName{{{*/
+void StringExternalResult::GetResultName(char**pname){
+	EnumToStringx(pname,this->enum_type);
+}
+/*}}}*/
+/*FUNCTION StringExternalResult::GetStep{{{*/
+int StringExternalResult::GetStep(void){
+
+	return this->step;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/ExternalResults/StringExternalResult.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/ExternalResults/StringExternalResult.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/ExternalResults/StringExternalResult.h	(revision 12822)
@@ -0,0 +1,55 @@
+/*! \file StringExternalResult.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _STRINGEXTERNALRESULT_H_
+#define _STRINGEXTERNALRESULT_H_
+
+/*Headers:*/
+/*{{{*/
+
+#ifdef HAVE_CONFIG_H
+	#include <config.h>
+#else
+#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
+#endif
+
+#include "./ExternalResult.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../include/include.h"
+/*}}}*/
+
+class StringExternalResult: public ExternalResult{
+
+	private: 
+		int    id;
+		int    enum_type;
+		char*  value;
+		int    step;
+		IssmDouble time;
+
+	public:
+		/*StringExternalResult constructors, destructors: {{{*/
+		StringExternalResult();
+		StringExternalResult(int id,int enum_type,char* value,int step, IssmDouble time);
+		~StringExternalResult();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ExternalResult management: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  WriteData(FILE* fid,bool io_gather);
+		void  GetResultName(char**);
+		int   GetStep(void);
+		/*}}}*/
+};
+#endif  /* _STRINGEXTERNALRESULT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/BoolInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/BoolInput.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/BoolInput.cpp	(revision 12822)
@@ -0,0 +1,193 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+
+/*BoolInput constructors and destructor*/
+/*FUNCTION BoolInput::BoolInput(){{{*/
+BoolInput::BoolInput(){
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolInput::BoolInput(IssmDouble* values){{{*/
+BoolInput::BoolInput(int in_enum_type,IssmBool 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::MyRank{{{*/
+int    BoolInput::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(IssmDouble* pvalue){{{*/
+void BoolInput::GetInputValue(IssmDouble* pvalue){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void BoolInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void BoolInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void BoolInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error2_("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:
+			_error2_("not implemented yet");
+	}
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::Extrude{{{*/
+void BoolInput::Extrude(void){
+
+	/*do nothing*/
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolInput::GetVectorFromInputs{{{*/
+void BoolInput::GetVectorFromInputs(Vector* vector,int* doflist){
+
+	_error2_("not supporte yet!");
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::GetValuesPtr{{{*/
+void BoolInput::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	_error2_("not supported yet!");
+
+}
+/*}}}*/
+/*FUNCTION BoolInput::Configure{{{*/
+void BoolInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/BoolInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/BoolInput.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/BoolInput.h	(revision 12822)
@@ -0,0 +1,85 @@
+/*! \file BoolInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _BOOLINPUT_H_
+#define _BOOLINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../../include/include.h"
+class GaussTria;
+/*}}}*/
+
+class BoolInput: public Input{
+
+	public:
+		/*just hold 3 values for 3 vertices: */
+		int    enum_type;
+		IssmBool value;
+
+		/*BoolInput constructors, destructors: {{{*/
+		BoolInput();
+		BoolInput(int enum_type,IssmBool value);
+		~BoolInput();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*BoolInput management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error2_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void Configure(Parameters* parameters);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error2_("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){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("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){_error2_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum){_error2_("not implemented yet");};
+		IssmDouble InfinityNorm(void){_error2_("InfinityNorm not implemented for booleans");};
+		IssmDouble Max(void){_error2_("Max not implemented for booleans");};
+		IssmDouble MaxAbs(void){_error2_("Max not implemented for booleans");};
+		IssmDouble Min(void){_error2_("Min not implemented for booleans");};
+		IssmDouble MinAbs(void){_error2_("Min not implemented for booleans");};
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error2_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max){_error2_("Constrain not implemented for booleans");};
+		void Extrude(void);
+		void VerticallyIntegrate(Input* thickness_input){_error2_("not supported yet");};
+		void GetVectorFromInputs(Vector* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _BOOLINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/ControlInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/ControlInput.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/ControlInput.cpp	(revision 12822)
@@ -0,0 +1,282 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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:
+			_error2_("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::MyRank{{{*/
+int    ControlInput::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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=(Input*)this->values->copy();
+	if(savedvalues) output->savedvalues=(Input*)this->savedvalues->copy();
+	if(minvalues)   output->minvalues=(Input*)this->minvalues->copy();
+	if(maxvalues)   output->maxvalues=(Input*)this->maxvalues->copy();
+	if(gradient)    output->gradient=(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* gradient_vec,int* doflist){
+	if(gradient) gradient->GetVectorFromInputs(gradient_vec,doflist);
+}/*}}}*/
+/*FUNCTION ControlInput::ScaleGradient{{{*/
+void ControlInput::ScaleGradient(IssmDouble scaling_factor){
+	if(!gradient) _error2_("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:
+			_error2_("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* vector,int* doflist){{{*/
+void ControlInput::GetVectorFromInputs(Vector* vector,int* doflist){
+	values->GetVectorFromInputs(vector,doflist);
+}/*}}}*/
+/*FUNCTION ControlInput::GetVectorFromInputs(Vector* vector,int* doflist,const char* data){{{*/
+void ControlInput::GetVectorFromInputs(Vector* 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{
+		 _error2_("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) _error2_("Values of " << EnumToStringx(this->enum_type) << " not found");
+
+	if(savedvalues) delete this->savedvalues;
+	this->savedvalues=(Input*)this->values->copy();
+}/*}}}*/
+/*FUNCTION ControlInput::UpdateValue{{{*/
+void ControlInput::UpdateValue(IssmDouble scalar){
+	if(!gradient)    _error2_("Gradient of " << EnumToStringx(this->enum_type) << " not found");
+	if(!savedvalues) _error2_("Values of " << EnumToStringx(this->enum_type) << " not found");
+
+	if(values) delete this->values;
+	this->values=(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/objects/Inputs/ControlInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/ControlInput.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/ControlInput.h	(revision 12822)
@@ -0,0 +1,98 @@
+/*! \file ControlInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _CONTROLINPUT_H_
+#define _CONTROLINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../../include/include.h"
+class GaussTria;
+/*}}}*/
+
+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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*ControlInput management: {{{*/
+		int    InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error2_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error2_("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){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("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 GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void ChangeEnum(int newenumtype){_error2_("not implemented yet");};
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){_error2_("not implemented yet");};
+		void ConstrainMin(IssmDouble minimum){_error2_("not implemented yet");};
+		void Scale(IssmDouble scale_factor){_error2_("not implemented yet");};
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error2_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar){_error2_("not implemented yet");};
+		void Constrain(void);
+		void Constrain(IssmDouble min,IssmDouble max);
+		IssmDouble InfinityNorm(void){_error2_("not implemented yet");};
+		IssmDouble Max(void){_error2_("not implemented yet");};
+		IssmDouble MaxAbs(void){_error2_("not implemented yet");};
+		IssmDouble Min(void){_error2_("not implemented yet");};
+		IssmDouble MinAbs(void){_error2_("not implemented yet");};
+		void Extrude(void);
+		void VerticallyIntegrate(Input* thickness_input);
+		void GetVectorFromInputs(Vector* vector,int* doflist,const char* data);
+		void GetVectorFromInputs(Vector* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values){_error2_("not implemented yet");};
+		ElementResult* SpawnGradient(int step, IssmDouble time);
+		void GetGradient(Vector* 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/objects/Inputs/DatasetInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/DatasetInput.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/DatasetInput.cpp	(revision 12822)
@@ -0,0 +1,122 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DatasetInput::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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=(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) _error2_("index requested (" << index << ") exceeds dataset size (" << inputs->Size() << ")");
+	Input* input=(Input*)this->inputs->GetObjectByOffset(index);
+	
+	input->GetInputValue(pvalue,gauss);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/DatasetInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/DatasetInput.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/DatasetInput.h	(revision 12822)
@@ -0,0 +1,92 @@
+/*! \file DatasetInput.h 
+ *  \brief: header file for datasetinput object
+ */
+
+
+#ifndef _DATASETINPUT_H_
+#define _DATASETINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../../include/include.h"
+class GaussTria;
+/*}}}*/
+
+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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*DatasetInput management: {{{*/
+		int    InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error2_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time){_error2_("not implemented yet");};
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error2_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(int* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetInputAverage(IssmDouble* pvalue){_error2_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void ChangeEnum(int newenumtype){_error2_("not implemented yet");};
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters){_error2_("not implemented yet");};
+		void ConstrainMin(IssmDouble minimum){_error2_("not implemented yet");};
+		void Scale(IssmDouble scale_factor){_error2_("not implemented yet");};
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error2_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar){_error2_("not implemented yet");};
+		void Constrain(void){_error2_("not implemented yet");};
+		void Constrain(IssmDouble min,IssmDouble max){_error2_("not implemented yet");};
+		IssmDouble InfinityNorm(void){_error2_("not implemented yet");};
+		IssmDouble Max(void){_error2_("not implemented yet");};
+		IssmDouble MaxAbs(void){_error2_("not implemented yet");};
+		IssmDouble Min(void){_error2_("not implemented yet");};
+		IssmDouble MinAbs(void){_error2_("not implemented yet");};
+		void Extrude(void){_error2_("not implemented yet");};
+		void VerticallyIntegrate(Input* thickness_input){_error2_("not implemented yet");};
+		void GetVectorFromInputs(Vector* vector,int* doflist){_error2_("not implemented yet");};
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values){_error2_("not implemented yet");};
+		ElementResult* SpawnGradient(int step, IssmDouble time){_error2_("not implemented yet");};
+		void GetGradient(Vector* gradient_vec,int* doflist){_error2_("not implemented yet");};
+		void ScaleGradient(IssmDouble scale){_error2_("not implemented yet");};
+		void SetGradient(Input* gradient_in){_error2_("not implemented yet");};
+		void UpdateValue(IssmDouble scalar){_error2_("not implemented yet");};
+		void SaveValue(void){_error2_("not implemented yet");};
+		/*}}}*/
+
+};
+#endif  /* _DATASETINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/DoubleInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/DoubleInput.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/DoubleInput.cpp	(revision 12822)
@@ -0,0 +1,359 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DoubleInput::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){
+	_error2_("Double input of enum " << EnumToStringx(enum_type) << " cannot return a boolean");
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputValue(int* pvalue){{{*/
+void DoubleInput::GetInputValue(int* pvalue){
+	_error2_("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){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION DoubleInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void DoubleInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error2_("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:
+			_error2_("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* vector,int* doflist){
+
+	_error2_("not supporte yet!");
+
+}
+/*}}}*/
+/*FUNCTION DoubleInput::GetValuesPtr{{{*/
+void DoubleInput::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	_error2_("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) _error2_("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:
+			_error2_("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/objects/Inputs/DoubleInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/DoubleInput.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/DoubleInput.h	(revision 12822)
@@ -0,0 +1,84 @@
+/*! \file DoubleInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _DOUBLEINPUT_H_
+#define _DOUBLEINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../../include/include.h"
+class GaussTria;
+/*}}}*/
+
+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   MyRank();
+		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){_error2_("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){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("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 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){_error2_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max);
+		IssmDouble InfinityNorm(void){_error2_("not implemented yet");};
+		IssmDouble Max(void);
+		IssmDouble MaxAbs(void);
+		IssmDouble Min(void);
+		IssmDouble MinAbs(void);
+		void Extrude(void){_error2_("not supported yet");};
+		void VerticallyIntegrate(Input* thickness_input);
+		void GetVectorFromInputs(Vector* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _DOUBLEINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/Input.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/Input.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/Input.h	(revision 12822)
@@ -0,0 +1,69 @@
+/*!\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 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 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* 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/objects/Inputs/IntInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/IntInput.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/IntInput.cpp	(revision 12822)
@@ -0,0 +1,199 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    IntInput::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){
+	
+	_error2_("not supported yet!");
+
+}
+/*}}}*/
+
+/*Object functions*/
+/*FUNCTION IntInput::GetInputValue(bool* pvalue) {{{*/
+void IntInput::GetInputValue(bool* pvalue){_error2_("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){
+	_error2_("IntInput cannot return a IssmDouble in parallel");
+}
+/*}}}*/
+/*FUNCTION IntInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){{{*/
+void IntInput::GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){{{*/
+void IntInput::GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){{{*/
+void IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error2_("not supported yet!");}
+/*}}}*/
+/*FUNCTION IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){{{*/
+void IntInput::GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error2_("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:
+			_error2_("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* vector,int* doflist){
+
+	_error2_("not supporte yet!");
+
+}
+/*}}}*/
+/*FUNCTION IntInput::GetValuesPtr{{{*/
+void IntInput::GetValuesPtr(IssmDouble** pvalues,int* pnum_values){
+
+	_error2_("not supported yet!");
+
+}
+/*}}}*/
+/*FUNCTION IntInput::Configure{{{*/
+void IntInput::Configure(Parameters* parameters){
+	/*do nothing: */
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/IntInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/IntInput.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/IntInput.h	(revision 12822)
@@ -0,0 +1,85 @@
+/*! \file IntInput.h 
+ *  \brief: header file for triavertexinput object
+ */
+
+
+#ifndef _INTINPUT_H_
+#define _INTINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+#include "../../include/include.h"
+class GaussTria;
+/*}}}*/
+
+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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*IntInput management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMin(Input* inputB){_error2_("not implemented yet");};
+		Input* PointwiseMax(Input* inputB){_error2_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void AddTimeValues(IssmDouble* values,int step,IssmDouble time){_error2_("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){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("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){_error2_("not implemented yet");};
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum){_error2_("not implemented yet");};
+		void Scale(IssmDouble scale_factor);
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error2_("not implemented yet");};
+		void AXPY(Input* xinput,IssmDouble scalar);
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max);
+		IssmDouble InfinityNorm(void){_error2_("InfinityNorm not implemented for integers");};
+		IssmDouble Max(void){_error2_("Max not implemented for integers");};
+		IssmDouble MaxAbs(void){_error2_("Max not implemented for integers");};
+		IssmDouble Min(void){_error2_("Min not implemented for integers");};
+		IssmDouble MinAbs(void){_error2_("Min not implemented for integers");};
+		void Extrude(void){_error2_("not supported yet");};
+		void VerticallyIntegrate(Input* thickness_input){_error2_("not supported yet");};
+		void GetVectorFromInputs(Vector* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _INTINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/PentaP1Input.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/PentaP1Input.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/PentaP1Input.cpp	(revision 12822)
@@ -0,0 +1,629 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    PentaP1Input::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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) _error2_("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:
+			_error2_("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) _error2_("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:
+			_error2_("not implemented yet");
+	}
+}
+/*}}}*/
+/*FUNCTION PentaP1Input::PointwiseDivide{{{*/
+Input* PentaP1Input::PointwiseDivide(Input* inputB){
+
+	/*Ouput*/
+	PentaP1Input* outinput=NULL;
+
+	/*Intermediaries*/
+	int               i;
+	PentaP1Input *xinputB     = NULL;
+	int               B_numvalues;
+	const int         numnodes    = 6;
+	IssmDouble            AdotBvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=PentaP1InputEnum) _error2_("Operation not permitted because inputB is of type " << EnumToStringx(inputB->ObjectEnum()));
+	xinputB=(PentaP1Input*)inputB;
+
+	/*Create point wise sum*/
+	for(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;
+	int               B_numvalues;
+	const int         numnodes    = 6;
+	IssmDouble            minvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=PentaP1InputEnum) _error2_("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;
+	int               B_numvalues;
+	const int         numnodes    = 6;
+	IssmDouble            maxvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=PentaP1InputEnum) _error2_("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* 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/objects/Inputs/PentaP1Input.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/PentaP1Input.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/PentaP1Input.h	(revision 12822)
@@ -0,0 +1,86 @@
+/*! \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 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   MyRank();
+		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){_error2_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(int* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss);
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error2_("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){_error2_("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* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _PENTAP1INPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/TransientInput.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/TransientInput.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/TransientInput.cpp	(revision 12822)
@@ -0,0 +1,486 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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<IssmDouble>(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::MyRank{{{*/
+int    TransientInput::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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);
+   memcpy(output->timesteps,this->timesteps,this->numtimesteps*sizeof(IssmDouble));
+	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);
+	memcpy(outinput->timesteps,this->timesteps,this->numtimesteps*sizeof(IssmDouble));
+	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;
+
+}
+/*}}}*/
+
+/*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);
+		memcpy(old_timesteps,this->timesteps,this->numtimesteps*sizeof(IssmDouble));
+		xDelete<IssmDouble>(this->timesteps); 
+	}
+
+	this->numtimesteps=this->numtimesteps+1;
+	this->timesteps=xNew<IssmDouble>(this->numtimesteps);
+
+	if (this->numtimesteps > 1){
+		memcpy(this->timesteps,old_timesteps,(this->numtimesteps-1)*sizeof(IssmDouble));
+		xDelete<IssmDouble>(old_timesteps);
+	}
+
+	/*go ahead and plug: */
+	this->timesteps[this->numtimesteps-1]=time;
+	inputs->AddObject(input);
+
+}
+/*}}}*/
+/*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* 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){
+
+	int     i,j;
+	IssmDouble  deltat;
+	IssmDouble  alpha1,alpha2;
+	bool    found=false;
+	Input*  input=NULL;
+	Input*  input1=NULL;
+	Input*  input2=NULL;
+
+	/*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(intime<this->timesteps[0]){
+		/*get values for the first time: */
+		input=(Input*)((Input*)this->inputs->GetObjectByOffset(0))->copy();
+		found=true;
+	}
+	else if(intime>this->timesteps[this->numtimesteps-1]){
+		/*get values for the last time: */
+		input=(Input*)((Input*)this->inputs->GetObjectByOffset(numtimesteps-1))->copy();
+		found=true;
+	}
+	else{
+		/*Find which interval we fall within: */
+		for(i=0;i<this->numtimesteps;i++){
+			if(intime==this->timesteps[i]){
+				/*We are right on one step time: */
+				input=(Input*)((Input*)this->inputs->GetObjectByOffset(i))->copy();
+				found=true;
+				break; //we are done with the time interpolation.
+			}
+			else{
+				if(this->timesteps[i]<intime && intime<this->timesteps[i+1]){
+					/*ok, we have the interval ]i:i+1[. Interpolate linearly for now: */
+					deltat=this->timesteps[i+1]-this->timesteps[i];
+					alpha2=(intime-this->timesteps[i])/deltat;
+					alpha1=(1.0-alpha2);
+
+					input1=(Input*)this->inputs->GetObjectByOffset(i); 
+					input2=(Input*)this->inputs->GetObjectByOffset(i+1);
+
+					input=(Input*)input1->copy();
+					input->Scale(alpha1);
+					input->AXPY(input2,alpha2);
+
+					found=true;
+					break;
+				}
+				else continue; //keep looking on the next interval
+			}
+		}
+	}
+	if(!found)_error2_("did not find time interval on which to interpolate forcing values!");
+
+	/*Assign output pointer*/
+	return input;
+}
+/*}}}*/
+/*FUNCTION TransientInput::Configure{{{*/
+void TransientInput::Configure(Parameters* parameters){
+	this->parameters=parameters;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/TransientInput.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/TransientInput.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/TransientInput.h	(revision 12822)
@@ -0,0 +1,90 @@
+/*! \file TransientInput.h 
+ *  \brief: header file for transientinput object
+ */
+
+
+#ifndef _TRANSIENTINPUT_H_
+#define _TRANSIENTINPUT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Input.h"
+class GaussTria;
+class Parameters;
+/*}}}*/
+
+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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*TransientInput management: {{{*/
+		int    InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* forcingB){_error2_("not implemented yet");};
+		Input* PointwiseMin(Input* forcingB){_error2_("not implemented yet");};
+		Input* PointwiseMax(Input* forcingB){_error2_("not implemented yet");};
+		ElementResult* SpawnResult(int step, IssmDouble time);
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(int* pvalue){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue){_error2_("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){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetInputAverage(IssmDouble* pvalue);
+		void GetVxStrainRate2d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate2d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussTria* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3d(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void ChangeEnum(int newenumtype);
+
+		void SquareMin(IssmDouble* psquaremin, bool process_units,Parameters* parameters);
+		void ConstrainMin(IssmDouble minimum){_error2_("not implemented yet");};
+		void Scale(IssmDouble scale_factor){_error2_("not implemented yet");};
+		void ArtificialNoise(IssmDouble min,IssmDouble max){_error2_("not implemented yet");};
+		void AXPY(Input* xforcing,IssmDouble scalar){_error2_("not implemented yet");};
+		void Constrain(IssmDouble cm_min, IssmDouble cm_max){_error2_("not implemented yet");};
+		IssmDouble InfinityNorm(void);
+		IssmDouble Max(void);
+		IssmDouble MaxAbs(void);
+		IssmDouble Min(void);
+		IssmDouble MinAbs(void);
+		void Extrude(void){_error2_("not supported yet");}
+		void VerticallyIntegrate(Input* thickness_forcing){_error2_("not supported yet");};
+		void GetVectorFromInputs(Vector* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values){_error2_("not supported yet");};
+      void GetTimeValues(IssmDouble* values,IssmDouble time){_error2_("not implemented yet");};
+		Input* GetTimeInput(IssmDouble time);
+		/*}}}*/
+
+};
+#endif  /* _TRANSIENTINPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/Inputs/TriaP1Input.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/TriaP1Input.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/TriaP1Input.cpp	(revision 12822)
@@ -0,0 +1,422 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    TriaP1Input::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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]);
+}
+/*}}}*/
+
+/*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 :
+			_error2_("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* 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;
+	int               B_numvalues;
+	const int         numnodes    = 3;
+	IssmDouble            minvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=TriaP1InputEnum) _error2_("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;
+	int               B_numvalues;
+	const int         numnodes    = 3;
+	IssmDouble            maxvalues[numnodes];
+
+	/*Check that inputB is of the same type*/
+	if (inputB->ObjectEnum()!=TriaP1InputEnum) _error2_("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/objects/Inputs/TriaP1Input.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Inputs/TriaP1Input.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Inputs/TriaP1Input.h	(revision 12822)
@@ -0,0 +1,86 @@
+/*! \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 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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*TriaP1Input management: {{{*/
+		int   InstanceEnum();
+		Input* SpawnTriaInput(int* indices);
+		Input* PointwiseDivide(Input* inputB){_error2_("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){_error2_("not supported yet");};
+		void Configure(Parameters* parameters);
+		/*}}}*/
+		/*numerics: {{{*/
+		void GetInputValue(bool* pvalue){_error2_("not implemented yet");}
+		void GetInputValue(int* pvalue){_error2_("not implemented yet");}
+		void GetInputValue(IssmDouble* pvalue){_error2_("not implemented yet");}
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss);
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,IssmDouble time){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussTria* gauss ,int index){_error2_("not implemented yet");};
+		void GetInputValue(IssmDouble* pvalue,GaussPenta* gauss,int index){_error2_("not implemented yet");};
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussTria* gauss);
+		void GetInputDerivativeValue(IssmDouble* derivativevalues, IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetInputAverage(IssmDouble* pvalue);
+		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){_error2_("not implemented yet");};
+		void GetVyStrainRate3d(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVzStrainRate3d(IssmDouble* epsilonvz,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVxStrainRate3dPattyn(IssmDouble* epsilonvx,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("not implemented yet");};
+		void GetVyStrainRate3dPattyn(IssmDouble* epsilonvy,IssmDouble* xyz_list, GaussPenta* gauss){_error2_("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){_error2_("not supported yet");};
+		void VerticallyIntegrate(Input* thickness_input){_error2_("not supported yet");};
+		void GetVectorFromInputs(Vector* vector,int* doflist);
+		void GetValuesPtr(IssmDouble** pvalues,int* pnum_values);
+		/*}}}*/
+
+};
+#endif  /* _TRIAP1INPUT_H */
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KMLFileReadUtils.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KMLFileReadUtils.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KMLFileReadUtils.cpp	(revision 12822)
@@ -0,0 +1,700 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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;
+
+	buffer=(char *) xmalloc(buflen*sizeof(char));
+	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)++;
+						*ppcom=(char **) xrealloc(*ppcom,*pncom*sizeof(char*));
+						(*ppcom)[*pncom-1]=bufferc;
+					}
+					else
+						xfree((void**)&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)++;
+						*ppcom=(char **) xrealloc(*ppcom,*pncom*sizeof(char*));
+						(*ppcom)[*pncom-1]=bufferc;
+					}
+					else
+						xfree((void**)&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)
+		xfree((void**)&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=(char *) xmalloc(buflen*sizeof(char));
+	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);
+				xfree((void**)&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)
+		xfree((void**)&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*   buffer=NULL;
+
+/*  check buffer length and realloc if necessary  */
+
+	if (*pibuf+2 > *pbuflen) {
+		*pbuflen+=bufblk;
+		*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))
+		_error2_("KMLFileTagName -- Missing tag delimiters in " << ktag << ".\n");
+
+/*  strtok modifies ktag, so work on copy  */
+
+	ktagi=(char *) xmalloc((strlen(ktag)+1)*sizeof(char));
+	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=(char *) xmalloc((maxlen       +1)*sizeof(char));
+		else
+			pname=(char *) xmalloc((strlen(ktokn)+1)*sizeof(char));
+	}
+
+	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));
+
+	xfree((void**)&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=(char *) xmalloc((strlen(ktag)+1)*sizeof(char));
+	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);
+	}
+
+	xfree((void**)&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] == '<'))
+		_error2_("KMLFileTokenParse -- Missing integer field for " << ktag << ".\n");
+
+	sscanf(kstr,"%d",pival);
+	xfree((void**)&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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&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] == '<'))
+	  {_error2_("KMLFileTokenParse -- Missing bool field for " << ktag << ".\n");}
+
+	sscanf(kstr,"%d",&ival);
+	*pbval=(bool)ival;
+	xfree((void**)&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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&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] == '<'))
+		_error2_("KMLFileTokenParse -- Missing string field for " << ktag << ".\n");
+
+	if (!pstr) {
+		if (maxlen)
+			pstr=(char *) xmalloc((maxlen      +1)*sizeof(char));
+		else
+			pstr=(char *) xmalloc((strlen(kstr)+1)*sizeof(char));
+	}
+
+	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));
+
+	xfree((void**)&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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&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] == '<'))
+	  {_error2_("KMLFileTokenParse -- Missing integer field for " << ktag << ".\n");}
+
+	sscanf(kstr,"%g",pfval);
+	xfree((void**)&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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&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] == '<'))
+		_error2_("KMLFileTokenParse -- Missing integer field for " << ktag << ".\n");
+
+	sscanf(kstr,"%lg",pdval);
+	xfree((void**)&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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=" << *pdval << ".");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(double **pdval,int* m,int maxlen,
+					  char* ktag,
+					  FILE* fid){
+
+	int     i=-1,j;
+	char*   kstr;
+	char*   ktok;
+	char    delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
+
+/*  get next token and allocate if necessary  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error2_("KMLFileTokenParse -- Missing double [m] field for " << ktag << ".\n");
+
+	if (!*pdval)
+		if (maxlen)
+			*pdval=(double *) xmalloc(maxlen              *sizeof(double));
+		else
+			*pdval=(double *) xmalloc(((strlen(kstr)+1)/2)*sizeof(double));
+
+/*  loop through string to get all values  */
+
+	ktok=strtok(kstr,delim);
+	while (ktok) {
+		i++;
+		if (maxlen && (maxlen < i+1))
+			_error2_("KMLFileTokenParse -- Double [m] field too short for " << ktag << ".\n");
+		sscanf(ktok,"%lg",&((*pdval)[i]));
+		ktok=strtok(NULL,delim);
+	}
+	xfree((void**)&kstr);
+
+	if (!maxlen)
+		*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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=...");
+//	for (j=0; j<=i; j++)
+//		_pprintLine_("   [" << j << "]: " << (*pdval)[j] << "g");
+
+	return(0);
+}
+/*}}}*/
+/*FUNCTION  KMLFileTokenParse {{{*/
+int KMLFileTokenParse(double (**pdval3)[3],int* m,int maxlen,
+					  char* ktag,
+					  FILE* fid){
+
+	int     i=0,j=-1;
+	char*   kstr;
+	char*   ktok;
+	char    delim[]={' ',',','\f','\n','\r','\t','\v','\0'};
+
+/*  get next token and allocate if necessary  */
+
+	if (!(kstr=KMLFileToken(fid,
+							NULL,NULL)) ||
+		(kstr[0] == '<'))
+		_error2_("KMLFileTokenParse -- Missing double [m x 3] field for " << ktag << ".\n");
+
+	if (!*pdval3)
+		if (maxlen)
+			*pdval3=(double (*)[3]) xmalloc((maxlen*3)          *sizeof(double));
+		else
+			*pdval3=(double (*)[3]) xmalloc(((strlen(kstr)+1)/2)*sizeof(double));
+
+/*  loop through string to get all values  */
+
+	ktok=strtok(kstr,delim);
+	while (ktok) {
+		j++;
+		if (j == 3) {
+			i++;
+			j=0;
+			if (maxlen && (maxlen < i+1))
+				_error2_("KMLFileTokenParse -- Double [m x 3] field too short for " << ktag << ".\n");
+		}
+		sscanf(ktok,"%lg",&((*pdval3)[i][j]));
+		ktok=strtok(NULL,delim);
+	}
+	xfree((void**)&kstr);
+
+	if (!maxlen)
+		*pdval3=(double (*)[3]) xrealloc(*pdval3,((i+1)*3)*sizeof(double));
+
+	if (m)
+		*m=i+1;
+
+	if (j != 2)
+		_pprintLine_("KMLFileTokenParse -- Double [m x 3] field for " << ktag << " does not have multiple of 3 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)))
+		  {_error2_("KMLFileTokenParse -- Missing closing tag for " << ktag << ".\n");}
+		else
+			xfree((void**)&kstr);
+
+//	_pprintLine_("KMLFileTokenParse -- " << ktag << "=...");
+//	for (j=0; j<=i; j++)
+//		_pprintLine_("   [" << j << "][0-2]: " << (*pdval3)[j][0] << "g," << (*pdval3)[j][1] << "g," << (*pdval3)[j][2] << "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 << ".");
+			xfree((void**)&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] == '/')) {
+			_error2_("KMLFileTagSkip -- Unexpected closing tag " << kstr << ".\n");
+		}
+
+		xfree((void**)&kstr);
+	}
+
+	_error2_("KMLFileTokenParse -- Corresponding closing tag for " << ktag << " not found.\n");
+
+	return(0);
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KMLFileReadUtils.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KMLFileReadUtils.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KMLFileReadUtils.h	(revision 12822)
@@ -0,0 +1,57 @@
+/*!\file:  KMLFileReadUtils.h
+ * \brief: header file for kml file reading utilities.
+ */ 
+
+#ifndef _KMLFILEREADUTILS_H
+#define _KMLFILEREADUTILS_H
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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 (**pdval3)[3],int* m,int maxlen,
+					  char* ktag,
+					  FILE* fid);
+int KMLFileTagSkip(char* ktag,
+				   FILE* fid);
+
+#endif  /* _KMLFILEREADUTILS_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Attribute.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Attribute.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Attribute.cpp	(revision 12822)
@@ -0,0 +1,133 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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      ) xfree((void**)&name);
+	if (value     ) xfree((void**)&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 =(char *) xmalloc((strlen(namei )+1)*sizeof(char));
+	memcpy(name,namei,(strlen(namei)+1)*sizeof(char));
+
+	value=(char *) xmalloc((strlen(valuei)+1)*sizeof(char));
+	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=(char *) xmalloc((strlen(deflt)+1)*sizeof(char));
+		memcpy(*pvalueo,deflt,(strlen(deflt)+1)*sizeof(char));
+	}
+	else {
+		*pvalueo=(char *) xmalloc((strlen(value)+1)*sizeof(char));
+		memcpy(*pvalueo,value,(strlen(value)+1)*sizeof(char));
+	}
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Attribute.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Attribute.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Attribute.h	(revision 12822)
@@ -0,0 +1,50 @@
+/*! \file KML_Attribute.h 
+ *  \brief: header file for kml_attribute object
+ */
+
+#ifndef _KML_ATTRIBUTE_H_
+#define _KML_ATTRIBUTE_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("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/objects/KML/KML_ColorStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_ColorStyle.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_ColorStyle.cpp	(revision 12822)
@@ -0,0 +1,109 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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))
+	  {_error2_("KML_ColorStyle::Read -- Unexpected closing tag " << kstr);}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_ColorStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_ColorStyle.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_ColorStyle.h	(revision 12822)
@@ -0,0 +1,48 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_COLORSTYLE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Comment.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Comment.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Comment.cpp	(revision 12822)
@@ -0,0 +1,118 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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     ) xfree((void**)&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=(char *) xmalloc((strlen(valuei)+1)*sizeof(char));
+	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=(char *) xmalloc((strlen(value)+1)*sizeof(char));
+	memcpy(*pvalueo,value,(strlen(value)+1)*sizeof(char));
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Comment.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Comment.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Comment.h	(revision 12822)
@@ -0,0 +1,50 @@
+/*! \file KML_Comment.h 
+ *  \brief: header file for kml_comment object
+ */
+
+#ifndef _KML_COMMENT_H_
+#define _KML_COMMENT_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("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/objects/KML/KML_Container.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Container.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Container.cpp	(revision 12822)
@@ -0,0 +1,168 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+		xfree((void**)&kstr);
+		return;
+	}
+	else if (!strncmp(kstr,"</",2))
+	  {_error2_("KML_Container::Read -- Unexpected closing tag " << kstr );}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_Container.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Container.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Container.h	(revision 12822)
@@ -0,0 +1,46 @@
+/*! \file KML_Container.h 
+ *  \brief: header file for kml_container abstract object
+ */
+
+#ifndef _KML_CONTAINER_H_
+#define _KML_CONTAINER_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_CONTAINER_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Document.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Document.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Document.cpp	(revision 12822)
@@ -0,0 +1,131 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Document::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("KML_Document::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Container::Read(fid,kstri);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Document.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Document.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Document.h	(revision 12822)
@@ -0,0 +1,43 @@
+/*! \file KML_Document.h 
+ *  \brief: header file for kml_document object
+ */
+
+#ifndef _KML_DOCUMENT_H_
+#define _KML_DOCUMENT_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_DOCUMENT_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Feature.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Feature.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Feature.cpp	(revision 12822)
@@ -0,0 +1,179 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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))
+	  {_error2_("KML_Feature::Read -- Unexpected closing tag " << kstr);}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_Feature.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Feature.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Feature.h	(revision 12822)
@@ -0,0 +1,57 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_FEATURE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_File.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_File.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_File.cpp	(revision 12822)
@@ -0,0 +1,140 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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;
+	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,"</kml", 5)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_File::Read -- Unexpected closing tag " << kstri << ".");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("KML_File::Read -- Unexpected field \"" << kstri << "\"");}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Object::Read(fid,kstri);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&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/objects/KML/KML_File.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_File.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_File.h	(revision 12822)
@@ -0,0 +1,44 @@
+/*! \file KML_File.h 
+ *  \brief: header file for kml_file object
+ */
+
+#ifndef _KML_FILE_H_
+#define _KML_FILE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_FILE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Folder.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Folder.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Folder.cpp	(revision 12822)
@@ -0,0 +1,131 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Folder::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("KML_Folder::Read -- Unexpected field \"" << kstri << "\".\n");}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Container::Read(fid,kstri);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Folder.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Folder.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Folder.h	(revision 12822)
@@ -0,0 +1,43 @@
+/*! \file KML_Folder.h 
+ *  \brief: header file for kml_folder object
+ */
+
+#ifndef _KML_FOLDER_H_
+#define _KML_FOLDER_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_FOLDER_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Geometry.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Geometry.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Geometry.cpp	(revision 12822)
@@ -0,0 +1,94 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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))
+	  {_error2_("KML_Geometry::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_Geometry.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Geometry.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Geometry.h	(revision 12822)
@@ -0,0 +1,42 @@
+/*! \file KML_Geometry.h 
+ *  \brief: header file for kml_geometry abstract object
+ */
+
+#ifndef _KML_GEOMETRY_H_
+#define _KML_GEOMETRY_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_GEOMETRY_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_GroundOverlay.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_GroundOverlay.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_GroundOverlay.cpp	(revision 12822)
@@ -0,0 +1,164 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_GroundOverlay::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_GroundOverlay.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_GroundOverlay.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_GroundOverlay.h	(revision 12822)
@@ -0,0 +1,49 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_GROUNDOVERLAY_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Icon.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Icon.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Icon.cpp	(revision 12822)
@@ -0,0 +1,182 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Icon::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Icon.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Icon.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Icon.h	(revision 12822)
@@ -0,0 +1,57 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_ICON_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LatLonBox.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LatLonBox.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LatLonBox.cpp	(revision 12822)
@@ -0,0 +1,162 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_LatLonBox::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LatLonBox.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LatLonBox.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LatLonBox.h	(revision 12822)
@@ -0,0 +1,48 @@
+/*! \file KML_LatLonBox.h 
+ *  \brief: header file for kml_latlonbox object
+ */
+
+#ifndef _KML_LATLONBOX_H_
+#define _KML_LATLONBOX_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LATLONBOX_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineString.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineString.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineString.cpp	(revision 12822)
@@ -0,0 +1,230 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_LineString::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&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=(double *) xmalloc(ncoord*sizeof(double));
+	lon=(double *) xmalloc(ncoord*sizeof(double));
+	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  =(double *) xmalloc(ncoord*sizeof(double));
+	y  =(double *) xmalloc(ncoord*sizeof(double));
+	Ll2xyx(x,y,lat,lon,ncoord,sgn,cm,sp);
+
+/*  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");
+
+	xfree((void**)&y);
+	xfree((void**)&x);
+	xfree((void**)&lon);
+	xfree((void**)&lat);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineString.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineString.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineString.h	(revision 12822)
@@ -0,0 +1,51 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LINESTRING_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineStyle.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineStyle.cpp	(revision 12822)
@@ -0,0 +1,138 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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){
+
+	int   i;
+	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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_LineStyle::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineStyle.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LineStyle.h	(revision 12822)
@@ -0,0 +1,44 @@
+/*! \file KML_LineStyle.h 
+ *  \brief: header file for kml_linestyle object
+ */
+
+#ifndef _KML_LINESTYLE_H_
+#define _KML_LINESTYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LINESTYLE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_LinearRing.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LinearRing.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LinearRing.cpp	(revision 12822)
@@ -0,0 +1,223 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+#include "../../io/io.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))
+		  {_error2_("KML_LinearRing::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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,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<double>(ncoord);
+	lon=xNew<double>(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<double>(ncoord);
+	y  =xNew<double>(ncoord);
+	Ll2xyx(x,y,lat,lon,ncoord,sgn,cm,sp);
+
+/*  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/objects/KML/KML_LinearRing.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_LinearRing.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_LinearRing.h	(revision 12822)
@@ -0,0 +1,51 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_LINEARRING_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_MultiGeometry.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_MultiGeometry.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_MultiGeometry.cpp	(revision 12822)
@@ -0,0 +1,203 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_MultiGeometry::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&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/objects/KML/KML_MultiGeometry.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_MultiGeometry.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_MultiGeometry.h	(revision 12822)
@@ -0,0 +1,47 @@
+/*! \file KML_MultiGeometry.h 
+ *  \brief: header file for kml_multigeometry object
+ */
+
+#ifndef _KML_MULTIGEOMETRY_H_
+#define _KML_MULTIGEOMETRY_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_MULTIGEOMETRY_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Object.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Object.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Object.cpp	(revision 12822)
@@ -0,0 +1,387 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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))
+	  {_error2_("KML_Object::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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=(char *) xmalloc((strlen(deflt)+1)*sizeof(char));
+		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/objects/KML/KML_Object.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Object.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Object.h	(revision 12822)
@@ -0,0 +1,56 @@
+/*! \file KML_Object.h 
+ *  \brief: header file for kml_object abstract object
+ */
+
+#ifndef _KML_OBJECT_H_
+#define _KML_OBJECT_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("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/objects/KML/KML_Overlay.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Overlay.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Overlay.cpp	(revision 12822)
@@ -0,0 +1,135 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+		xfree((void**)&kstr);
+		return;
+	}
+	else if (!strncmp(kstr,"</",2))
+	  {_error2_("KML_Overlay::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_Overlay.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Overlay.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Overlay.h	(revision 12822)
@@ -0,0 +1,49 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_OVERLAY_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Placemark.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Placemark.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Placemark.cpp	(revision 12822)
@@ -0,0 +1,210 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Placemark::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&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/objects/KML/KML_Placemark.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Placemark.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Placemark.h	(revision 12822)
@@ -0,0 +1,47 @@
+/*! \file KML_Placemark.h 
+ *  \brief: header file for kml_placemark object
+ */
+
+#ifndef _KML_PLACEMARK_H_
+#define _KML_PLACEMARK_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_PLACEMARK_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Point.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Point.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Point.cpp	(revision 12822)
@@ -0,0 +1,193 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Point::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&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  */
+
+	Ll2xyx(&x,&y,&lat,&lon,1,sgn,cm,sp);
+
+/*  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/objects/KML/KML_Point.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Point.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Point.h	(revision 12822)
@@ -0,0 +1,49 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_POINT_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_PolyStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_PolyStyle.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_PolyStyle.cpp	(revision 12822)
@@ -0,0 +1,146 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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){
+
+	int   i;
+	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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_PolyStyle::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_PolyStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_PolyStyle.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_PolyStyle.h	(revision 12822)
@@ -0,0 +1,45 @@
+/*! \file KML_PolyStyle.h 
+ *  \brief: header file for kml_polystyle object
+ */
+
+#ifndef _KML_POLYSTYLE_H_
+#define _KML_POLYSTYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_POLYSTYLE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Polygon.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Polygon.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Polygon.cpp	(revision 12822)
@@ -0,0 +1,298 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Polygon::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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)) {
+					xfree((void**)&kstrj);
+					break;
+				}
+				else if (!strncmp(kstrj,"</",2))
+				  {_error2_("KML_Polygon::Read -- Unexpected closing tag " << kstrj << ".\n");}
+				else if (strncmp(kstrj,"<",1))
+				  {_error2_("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);
+
+				xfree((void**)&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)) {
+					xfree((void**)&kstrj);
+					break;
+				}
+				else if (!strncmp(kstrj,"</",2))
+				  {_error2_("KML_Polygon::Read -- Unexpected closing tag " << kstrj << ".\n");}
+				else if (strncmp(kstrj,"<",1))
+				  {_error2_("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);
+
+				xfree((void**)&kstrj);
+			}
+
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Geometry::Read(fid,kstri);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&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/objects/KML/KML_Polygon.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Polygon.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Polygon.h	(revision 12822)
@@ -0,0 +1,53 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_POLYGON_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Style.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Style.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Style.cpp	(revision 12822)
@@ -0,0 +1,243 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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;
+		if (list      ) xfree((void**)&list);
+		list      =NULL;
+	}
+	if (balloon) {
+//		delete balloon;
+		if (balloon   ) xfree((void**)&balloon);
+		balloon   =NULL;
+	}
+	if (poly) {
+		delete poly;
+		poly      =NULL;
+	}
+	if (line) {
+		delete line;
+		line      =NULL;
+	}
+	if (label) {
+//		delete label;
+		if (label     ) xfree((void**)&label);
+		label     =NULL;
+	}
+	if (icon) {
+//		delete icon;
+		if (icon      ) xfree((void**)&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)) {
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Style::Read -- Unexpected closing tag " << kstri << ".\n");}
+		else if (strncmp(kstri,"<",1))
+		  {_error2_("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);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Style.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Style.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Style.h	(revision 12822)
@@ -0,0 +1,51 @@
+/*! \file KML_Style.h 
+ *  \brief: header file for kml_style object
+ */
+
+#ifndef _KML_STYLE_H_
+#define _KML_STYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_STYLE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_StyleSelector.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_StyleSelector.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_StyleSelector.cpp	(revision 12822)
@@ -0,0 +1,94 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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))
+	  {_error2_("KML_StyleSelector::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_StyleSelector.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_StyleSelector.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_StyleSelector.h	(revision 12822)
@@ -0,0 +1,42 @@
+/*! \file KML_StyleSelector.h 
+ *  \brief: header file for kml_styleselector abstract object
+ */
+
+#ifndef _KML_STYLESELECTOR_H_
+#define _KML_STYLESELECTOR_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_STYLESELECTOR_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_SubStyle.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_SubStyle.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_SubStyle.cpp	(revision 12822)
@@ -0,0 +1,94 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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))
+	  {_error2_("KML_SubStyle::Read -- Unexpected closing tag " << kstr << ".\n");}
+	else if (strncmp(kstr,"<",1))
+	  {_error2_("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/objects/KML/KML_SubStyle.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_SubStyle.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_SubStyle.h	(revision 12822)
@@ -0,0 +1,42 @@
+/*! \file KML_SubStyle.h 
+ *  \brief: header file for kml_substyle abstract object
+ */
+
+#ifndef _KML_SUBSTYLE_H_
+#define _KML_SUBSTYLE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_SUBSTYLE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Unknown.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Unknown.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Unknown.cpp	(revision 12822)
@@ -0,0 +1,189 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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      ) xfree((void**)&name);
+	if (value     ) xfree((void**)&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=(char *) xmalloc((strlen(value)+1)*sizeof(char));
+		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_("\"");
+
+		xfree((void**)&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=(char *) xmalloc((strlen(value)+1)*sizeof(char));
+		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);
+
+		xfree((void**)&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;
+	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 << ".");
+			xfree((void**)&kstri);
+			break;
+		}
+		else if (!strncmp(kstri,"</",2))
+		  {_error2_("KML_Unknown::Read -- Unexpected closing tag " << kstri << ".\n");}
+
+		else if (strncmp(kstri,"<",1)) {
+			if (value) {
+				value=(char *) xrealloc(value,(strlen(value)+1+strlen(kstri)+1)*sizeof(char));
+				strcat(value,nl);
+				strcat(value,kstri);
+			}
+			else {
+				value=(char *) xmalloc((strlen(kstri)+1)*sizeof(char));
+				memcpy(value,kstri,(strlen(kstri)+1)*sizeof(char));
+			}
+		}
+
+		else if (!strncmp(kstri,"<",1))
+			KML_Object::Read(fid,kstri);
+
+		xfree((void**)&kstri);
+	}
+
+	this->AddCommnt(ncom,pcom);
+
+	for (ncom; ncom>0; ncom--)
+		xfree((void**)&(pcom[ncom-1]));
+	xfree((void**)&pcom);
+
+	return;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/KML/KML_Unknown.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/KML/KML_Unknown.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/KML/KML_Unknown.h	(revision 12822)
@@ -0,0 +1,45 @@
+/*! \file KML_Unknown.h 
+ *  \brief: header file for kml_unknown object
+ */
+
+#ifndef _KML_UNKNOWN_H_
+#define _KML_UNKNOWN_H_
+
+/*Headers:*/
+/*{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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(){_error2_("Not implemented yet.");};
+		int   MyRank(){_error2_("Not implemented yet.");};
+		void  Marshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   MarshallSize(){_error2_("Not implemented yet.");};
+		void  Demarshall(char** pmarshalled_dataset){_error2_("Not implemented yet.");};
+		int   ObjectEnum(){_error2_("Not implemented yet.");};
+		Object* copy(){_error2_("Not implemented yet.");};
+		/*}}}*/
+
+};
+#endif  /* _KML_UNKNOWN_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Loads/Friction.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Friction.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Friction.cpp	(revision 12822)
@@ -0,0 +1,334 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../Container/Container.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../include/include.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 _error2_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+        if(vmag==0 && (s-1)<0) _error2_("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 _error2_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+	if(vmag==0 && (s-1)<0) _error2_("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: */
+	int     i;
+	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 _error2_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+	if(vmag==0 && (s-1)<0) _error2_("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: */
+	int     i;
+	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 _error2_("element_type "<< element_type << " not supported yet");
+
+	/*Checks that s-1>0 if v=0*/
+	if(vmag==0 && (s-1)<0) _error2_("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) _error2_("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) _error2_("input " << EnumToStringx(enum_type) << " not found");
+	input->GetInputValue(pvalue,gauss);
+
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Loads/Friction.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Friction.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Friction.h	(revision 12822)
@@ -0,0 +1,38 @@
+/*!\file Friction.h
+ * \brief: header file for friction object
+ */
+
+#ifndef _FRICTION_H_
+#define _FRICTION_H_
+
+/*Headers:*/
+/*{{{*/
+class Inputs;
+class Matpar;
+/*}}}*/
+
+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/objects/Loads/Icefront.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Icefront.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Icefront.cpp	(revision 12822)
@@ -0,0 +1,743 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../include/include.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->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_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));
+	}
+	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));
+	}
+	else _error2_("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->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(TypeEnum,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->element= NULL;
+	this->matpar= NULL;
+}
+
+
+/*}}}*/
+/*FUNCTION Icefront::~Icefront() {{{*/
+Icefront::~Icefront(){
+	delete inputs;
+	this->parameters=NULL;
+	delete hnodes;
+	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();
+	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();
+	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::MyRank {{{*/
+int    Icefront::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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->helement=(Hook*)this->helement->copy();
+	icefront->hmatpar=(Hook*)this->hmatpar->copy();
+
+	/*corresponding fields*/
+	icefront->nodes  =(Node**)icefront->hnodes->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(nodesin);
+	helement->configure(elementsin);
+	hmatpar->configure(materialsin);
+
+	/*Initialize hooked fields*/
+	this->nodes  =(Node**)hnodes->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* Kff, Matrix* Kfs){
+
+	/*No stiffness loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Icefront::CreatePVector {{{*/
+void  Icefront::CreatePVector(Vector* 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:
+			_error2_("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* Jff){
+	this->CreateKMatrix(Jff,NULL);
+}
+/*}}}*/
+/*FUNCTION Icefront::PenaltyCreateKMatrix {{{*/
+void  Icefront::PenaltyCreateKMatrix(Matrix* Kff, Matrix* Kfs, IssmDouble kmax){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Icefront::PenaltyCreatePVector{{{*/
+void  Icefront::PenaltyCreatePVector(Vector* pf,IssmDouble kmax){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Icefront::PenaltyCreateJacobianMatrix{{{*/
+void  Icefront::PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax){
+	this->PenaltyCreateKMatrix(Jff,NULL,kmax);
+}
+/*}}}*/
+/*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,TypeEnum);
+
+	switch(type){
+		case MacAyeal2dIceFrontEnum:
+			return CreatePVectorDiagnosticMacAyeal2d();
+        #ifdef _HAVE_3D_
+		case MacAyeal3dIceFrontEnum:
+			return CreatePVectorDiagnosticMacAyeal3d();
+		case PattynIceFrontEnum:
+			return CreatePVectorDiagnosticPattyn();
+		case StokesIceFrontEnum:
+			return CreatePVectorDiagnosticStokes();
+	    #endif
+		default:
+			_error2_("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],nodes,numnodes);
+	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:
+				_error2_("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;
+	bool      onbed;
+
+	/*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(TypeEnum,MacAyeal2dIceFrontEnum));
+	ElementVector* pe=icefront->CreatePVectorDiagnosticMacAyeal2d();
+
+	/*clean-up and return*/
+	delete tria->matice;
+	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], nodes, 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:
+				_error2_("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], nodes, 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:
+				_error2_("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 i,j;
+	int numberofdofs=0;
+	int count=0;
+	int type;
+	int numberofnodes=2;
+
+	/*output: */
+	int* doflist=NULL;
+
+	
+	/*recover type: */
+	inputs->GetInputValue(&type,TypeEnum);
+
+	/*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(i=0;i<numberofnodes;i++){
+		numberofdofs+=nodes[i]->GetNumberOfDofs(approximation_enum,setenum);
+	}
+
+	/*Allocate: */
+	doflist=xNew<int>(numberofdofs);
+
+	/*Populate: */
+	count=0;
+	for(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/objects/Loads/Icefront.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Icefront.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Icefront.h	(revision 12822)
@@ -0,0 +1,98 @@
+/*!\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 Icefront: public Load {
+
+	public:
+		int id;
+		int analysis_type;
+
+		/*hooks: */
+		Hook* hnodes;
+		Hook* helement;
+		Hook* hmatpar;
+
+		/*Corresponding fields*/
+		Matpar   *matpar;
+		Node    **nodes;
+		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   MyRank();
+		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){_error2_("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* Kff, Matrix* Kfs);
+		void  CreatePVector(Vector* pf);
+		void  CreateJacobianMatrix(Matrix* Jff);
+		void  PenaltyCreateKMatrix(Matrix* Kff, Matrix* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector*  pf, IssmDouble kmax);
+		void  PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax);
+		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/objects/Loads/Load.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Load.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Load.h	(revision 12822)
@@ -0,0 +1,40 @@
+/*!\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 Object;
+class Matrix;
+class Vector;
+
+#include "../Object.h"
+#include "../../toolkits/toolkits.h"
+#include "../../Container/Container.h"
+/*}}}*/
+
+class Load: public Object,public Update{
+
+	public: 
+
+		virtual       ~Load(){};
+		
+		/*Virtual functions: {{{*/
+		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,Vertices* vertices,Materials* materials,Parameters* parameters)=0;
+		virtual void  CreateKMatrix(Matrix* Kff, Matrix* Kfs)=0;
+		virtual void  CreatePVector(Vector* pf)=0;
+		virtual void  CreateJacobianMatrix(Matrix* Jff)=0;
+		virtual void  PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax)=0;
+		virtual void  PenaltyCreateKMatrix(Matrix* Kff, Matrix* Kfs, IssmDouble kmax)=0;
+		virtual void  PenaltyCreatePVector(Vector* pf, IssmDouble kmax)=0;
+		virtual bool  InAnalysis(int analysis_type)=0;
+		/*}}}*/
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/objects/Loads/Numericalflux.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Numericalflux.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Numericalflux.cpp	(revision 12822)
@@ -0,0 +1,880 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../objects.h"
+/*}}}*/	
+
+/*Load macros*/
+#define NUMVERTICES_INTERNAL 4
+#define NUMVERTICES_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->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_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]);
+
+	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->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(TypeEnum,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;
+}
+/*}}}*/
+
+/*Object virtual functions definitions:*/
+/*FUNCTION Numericalflux::Echo {{{*/
+void Numericalflux::Echo(void){
+	_printLine_("Numericalflux:");
+	_printLine_("   id: " << id);
+	_printLine_("   analysis_type: " << EnumToStringx(analysis_type));
+	hnodes->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();
+	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::MyRank {{{*/
+int    Numericalflux::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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->helement=(Hook*)this->helement->copy();
+
+	/*corresponding fields*/
+	numericalflux->nodes  =(Node**)numericalflux->hnodes->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(nodesin);
+	helement->configure(elementsin);
+
+	/*Initialize hooked fields*/
+	this->nodes  =(Node**)hnodes->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* Kff, Matrix* 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:
+			_error2_("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* 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:
+			_error2_("analysis " << analysis_type << " (" << EnumToStringx(analysis_type) << ") not supported yet");
+	}
+
+	/*Add to global matrix*/
+	if(pe){
+		pe->AddToGlobal(pf);
+		delete pe;
+	}
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::PenaltyCreateKMatrix {{{*/
+void  Numericalflux::PenaltyCreateKMatrix(Matrix* Kff, Matrix* Kfs,IssmDouble kmax){
+
+	/*No stiffness loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Numericalflux::PenaltyCreatePVector{{{*/
+void  Numericalflux::PenaltyCreatePVector(Vector* 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;
+}
+/*}}}*/
+
+/*Numericalflux management*/
+/*FUNCTION Numericalflux::CreateKMatrixPrognostic{{{*/
+ElementMatrix* Numericalflux::CreateKMatrixPrognostic(void){
+
+	int type;
+	inputs->GetInputValue(&type,TypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreateKMatrixPrognosticInternal();
+		case BoundaryEnum:
+			return CreateKMatrixPrognosticBoundary();
+		default:
+			_error2_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixPrognosticInternal {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixPrognosticInternal(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMVERTICES_INTERNAL;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL1,DL2,Jdet,dt,vx,vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES_INTERNAL][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,NUMVERTICES_INTERNAL,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes,NUMVERTICES_INTERNAL);
+	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*NUMVERTICES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL,Jdet,dt,vx,vy,mean_vx,mean_vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES_BOUNDARY][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],nodes,NUMVERTICES_BOUNDARY);
+	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,NUMVERTICES_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,TypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreateKMatrixBalancethicknessInternal();
+		case BoundaryEnum:
+			return CreateKMatrixBalancethicknessBoundary();
+		default:
+			_error2_("type not supported yet");
+	}
+}
+/*}}}*/
+/*FUNCTION Numericalflux::CreateKMatrixBalancethicknessInternal {{{*/
+ElementMatrix* Numericalflux::CreateKMatrixBalancethicknessInternal(void){
+
+	/* constants*/
+	const int numdof=NDOF1*NUMVERTICES_INTERNAL;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL1,DL2,Jdet,vx,vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES_INTERNAL][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,NUMVERTICES_INTERNAL,this->parameters);
+
+	/*Retrieve all inputs and parameters*/
+	GetVerticesCoordinates(&xyz_list[0][0], nodes,NUMVERTICES_INTERNAL);
+	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*NUMVERTICES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL,Jdet,vx,vy,mean_vx,mean_vy,UdotN;
+	IssmDouble     xyz_list[NUMVERTICES_BOUNDARY][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],nodes,NUMVERTICES_BOUNDARY);
+	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,NUMVERTICES_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,TypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreateKMatrixAdjointBalancethicknessInternal();
+		case BoundaryEnum:
+			return CreateKMatrixAdjointBalancethicknessBoundary();
+		default:
+			_error2_("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,TypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreatePVectorPrognosticInternal();
+		case BoundaryEnum:
+			return CreatePVectorPrognosticBoundary();
+		default:
+			_error2_("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*NUMVERTICES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL,Jdet,dt,vx,vy,mean_vx,mean_vy,UdotN,thickness;
+	IssmDouble     xyz_list[NUMVERTICES_BOUNDARY][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],nodes,NUMVERTICES_BOUNDARY);
+	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,NUMVERTICES_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)) _error2_("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,TypeEnum);
+
+	switch(type){
+		case InternalEnum:
+			return CreatePVectorBalancethicknessInternal();
+		case BoundaryEnum:
+			return CreatePVectorBalancethicknessBoundary();
+		default:
+			_error2_("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*NUMVERTICES_BOUNDARY;
+
+	/* Intermediaries*/
+	int        i,j,ig,index1,index2;
+	IssmDouble     DL,Jdet,vx,vy,mean_vx,mean_vy,UdotN,thickness;
+	IssmDouble     xyz_list[NUMVERTICES_BOUNDARY][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],nodes,NUMVERTICES_BOUNDARY);
+	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,NUMVERTICES_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/objects/Loads/Numericalflux.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Numericalflux.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Numericalflux.h	(revision 12822)
@@ -0,0 +1,97 @@
+/*!\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;
+
+		/*Corresponding fields*/
+		Element* element;
+		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   MyRank();
+		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){_error2_("Not implemented yet!");}
+		void    InputUpdateFromVector(bool* vector, int name, int type){_error2_("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){_error2_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(bool* vector, int name, int type){_error2_("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){_error2_("Not implemented yet!");}
+		void    InputUpdateFromSolution(IssmDouble* solution){_error2_("Not implemented yet!");}
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error2_("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* Kff, Matrix* Kfs);
+		void  CreatePVector(Vector* pf);
+		void  CreateJacobianMatrix(Matrix* Jff){_error2_("Not implemented yet");};
+		void  PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax){_error2_("Not implemented yet");};
+		void  PenaltyCreateKMatrix(Matrix* Kff, Matrix* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector* pf, IssmDouble kmax);
+		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/objects/Loads/Pengrid.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Pengrid.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Pengrid.cpp	(revision 12822)
@@ -0,0 +1,620 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../include/include.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.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 i,j;
+	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::MyRank {{{*/
+int    Pengrid::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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* Kff, Matrix* Kfs){
+
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::CreatePVector {{{*/
+void  Pengrid::CreatePVector(Vector* pf){
+
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Pengrid::PenaltyCreateMatrix {{{*/
+void  Pengrid::PenaltyCreateKMatrix(Matrix* Kff, Matrix* 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
+		default:
+			_error2_("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* pf,IssmDouble kmax){
+
+	/*Retrieve parameters: */
+	ElementVector* pe=NULL;
+	int analysis_type;
+	this->parameters->FindParam(&analysis_type,AnalysisTypeEnum);
+
+	switch(analysis_type){
+		#ifdef _HAVE_DIAGNOSTIC_
+		case ThermalAnalysisEnum:
+			pe=PenaltyCreatePVectorThermal(kmax);
+			break;
+		#endif
+		#ifdef _HAVE_THERMAL_
+		case MeltingAnalysisEnum:
+			pe=PenaltyCreatePVectorMelting(kmax);
+			break;
+		case DiagnosticHorizAnalysisEnum: case AdjointHorizAnalysisEnum:
+			break;
+		#endif
+		default:
+			_error2_("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;
+}
+/*}}}*/
+
+/*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;
+	}
+	else if (analysis_type==ThermalAnalysisEnum){
+		ConstraintActivateThermal(punstable);
+	}
+	else if (analysis_type==MeltingAnalysisEnum){
+		/*No penalty to check*/
+		return;
+	}
+	else{
+		_error2_("analysis: " << EnumToStringx(analysis_type) << " not supported yet");
+	}
+
+}
+/*}}}*/
+/*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;
+}
+/*}}}*/
+#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::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 (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
+/*FUNCTION Pengrid::ResetConstraint {{{*/
+void  Pengrid::ResetConstraint(void){
+	active=0;
+	zigzag_counter=0;
+}
+/*}}}*/
+/*FUNCTION Pengrid::UpdateInputs {{{*/
+void  Pengrid::UpdateInputs(IssmDouble* solution){
+	_error2_("not supported yet!");
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Loads/Pengrid.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Pengrid.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Pengrid.h	(revision 12822)
@@ -0,0 +1,100 @@
+/*!\file Pengrid.h
+ * \brief: header file for pengrid object */
+
+#ifndef _PENGRID_H_
+#define _PENGRID_H_
+
+/*Headers:*/
+/*{{{*/
+#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   MyRank();
+		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){_error2_("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* Kff, Matrix* Kfs);
+		void  CreatePVector(Vector* pf);
+		void  CreateJacobianMatrix(Matrix* Jff){_error2_("Not implemented yet");};
+		void  PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax){_error2_("Not implemented yet");};
+		void  PenaltyCreateKMatrix(Matrix* Kff, Matrix* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector* pf, IssmDouble kmax);
+		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);
+		#endif
+		void  ConstraintActivate(int* punstable);
+		void  ConstraintActivateThermal(int* punstable);
+		void  UpdateInputs(IssmDouble* solution);
+		void  ResetConstraint(void);
+		/*}}}*/
+
+};
+
+#endif  /* _PENGRID_H_ */
+
+
Index: /issm/trunk-jpl/src/c/classes/objects/Loads/Penpair.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Penpair.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Penpair.cpp	(revision 12822)
@@ -0,0 +1,355 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../include/include.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){
+
+	int i;
+
+	_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::MyRank {{{*/
+int    Penpair::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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(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* Kff, Matrix* 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* pf){
+
+	/*No loads applied, do nothing: */
+	return;
+
+}
+/*}}}*/
+/*FUNCTION Penpair::CreateJacobianMatrix{{{*/
+void  Penpair::CreateJacobianMatrix(Matrix* Jff){
+	this->CreateKMatrix(Jff,NULL);
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateKMatrix {{{*/
+void  Penpair::PenaltyCreateKMatrix(Matrix* Kff, Matrix* 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:
+			_error2_("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* pf,IssmDouble kmax){
+	/*No loads applied, do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Penpair::PenaltyCreateJacobianMatrix{{{*/
+void  Penpair::PenaltyCreateJacobianMatrix(Matrix* 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;
+}
+/*}}}*/
+
+/*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: _error2_("not supported yet");
+			}
+		case PattynApproximationEnum:
+			switch(approximation1){
+				case MacAyealApproximationEnum: return PenaltyCreateKMatrixDiagnosticMacAyealPattyn(kmax); 
+				case PattynApproximationEnum:   return PenaltyCreateKMatrixDiagnosticMacAyealPattyn(kmax); 
+				default: _error2_("not supported yet");
+			}
+		case StokesApproximationEnum:
+			switch(approximation1){
+				case StokesApproximationEnum: return PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				case NoneApproximationEnum: return   PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				default: _error2_("not supported yet");
+			}
+		case NoneApproximationEnum:
+			switch(approximation1){
+				case StokesApproximationEnum: return PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				case NoneApproximationEnum: return   PenaltyCreateKMatrixDiagnosticStokes(kmax); 
+				default: _error2_("not supported yet");
+			}
+		default: _error2_("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/objects/Loads/Penpair.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Penpair.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Penpair.h	(revision 12822)
@@ -0,0 +1,77 @@
+/*!\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   MyRank();
+		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){_error2_("Not implemented yet!");}
+		void  InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){_error2_("Not implemented yet!");}
+		void  InputUpdateFromVectorDakota(int* vector, int name, int type){_error2_("Not implemented yet!");}
+		void  InputUpdateFromVectorDakota(bool* vector, int name, int type){_error2_("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){_error2_("Not implemented yet!");}
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error2_("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* Kff, Matrix* Kfs);
+		void  CreatePVector(Vector* pf);
+		void  CreateJacobianMatrix(Matrix* Jff);
+		void  PenaltyCreateKMatrix(Matrix* Kff,Matrix* Kfs,IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector* pf, IssmDouble kmax);
+		void  PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax);
+		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/objects/Loads/Riftfront.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Riftfront.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Riftfront.cpp	(revision 12822)
@@ -0,0 +1,916 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../modules/ModelProcessorx/ModelProcessorx.h"
+#include "../objects.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=(int)*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+2);
+	el2=(int)*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+3); 
+
+	node1=(int)*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+0); 
+	node2=(int)*(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=(int)*(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 = (int)*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+7);
+	riftfront_friction=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+8);
+	riftfront_fractionincrement=*(iomodel->Data(RiftsRiftstructEnum)+RIFTINFOSIZE*i+10);
+	riftfront_shelf=(bool)iomodel->Data(MaskVertexonfloatingiceEnum)[node1-1];
+
+	this->inputs->AddInput(new IntInput(TypeEnum,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::MyRank {{{*/
+int    Riftfront::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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*/
+	_error2_("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::SetCurrentConfiguration {{{*/
+void  Riftfront::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*FUNCTION Riftfront::PenaltyCreateKMatrix {{{*/
+void  Riftfront::PenaltyCreateKMatrix(Matrix* Kff, Matrix* 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:
+			_error2_("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* 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:
+			_error2_("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* Kff, Matrix* Kfs){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Riftfront::CreatePVector {{{*/
+void  Riftfront::CreatePVector(Vector* pf){
+	/*do nothing: */
+	return;
+}
+/*}}}*/
+/*FUNCTION Riftfront::InAnalysis{{{*/
+bool Riftfront::InAnalysis(int in_analysis_type){
+	if (in_analysis_type==this->analysis_type) return true;
+	else return false;
+}
+/*}}}*/
+
+/*Riftfront numerics*/
+/*FUNCTION Riftfront::PenaltyCreateKMatrixDiagnosticHoriz {{{*/
+ElementMatrix* Riftfront::PenaltyCreateKMatrixDiagnosticHoriz(IssmDouble kmax){
+
+	const int   numdof = NDOF2*NUMVERTICES;
+	int         i,j;
+	int         dofs[1]             = {0};
+	IssmDouble      Ke_gg[4][4];
+	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)_error2_("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])_error2_("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         i,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)_error2_("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])_error2_("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])_error2_("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) _error2_("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{
+		_error2_("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      max_penetration;
+	IssmDouble      penetration;
+	int         activate;
+	int         found;
+	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)_error2_("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){
+
+	int found=0;
+	IssmDouble converged=0;
+
+	this->inputs->GetInputValue(&converged,ConvergedEnum);
+
+	if(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        max_penetration;
+	IssmDouble        penetration=0;
+	int           found;
+	IssmDouble      vx1;
+	IssmDouble      vy1;
+	IssmDouble      vx2;
+	IssmDouble      vy2;
+
+	/*Objects: */
+	Tria       *tria1           = NULL;
+	Tria       *tria2           = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error2_("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;
+	int       found;
+
+	/*Objects: */
+	Tria     *tria1       = NULL;
+	Tria     *tria2       = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error2_("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      max_penetration;
+	IssmDouble      penetration;
+	int         activate;
+	int         unstable;
+	int         found;
+	IssmDouble      vx1;
+	IssmDouble      vy1;
+	IssmDouble      vx2;
+	IssmDouble      vy2;
+
+	/*Objects: */
+	Tria       *tria1           = NULL;
+	Tria       *tria2           = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error2_("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;
+	int         found;
+	IssmDouble      vx1;
+	IssmDouble      vy1;
+	IssmDouble      vx2;
+	IssmDouble      vy2;
+
+	/*Objects: */
+	Tria       *tria1       = NULL;
+	Tria       *tria2       = NULL;
+
+	/*enum of element? */
+	if(elements[0]->ObjectEnum()!=TriaEnum)_error2_("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/objects/Loads/Riftfront.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Loads/Riftfront.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Loads/Riftfront.h	(revision 12822)
@@ -0,0 +1,104 @@
+/*!\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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Update virtual functions resolution: {{{*/
+		void    InputUpdateFromVector(IssmDouble* vector, int name, int type);
+		void    InputUpdateFromVector(int* vector, int name, int type){_error2_("Not implemented yet!");}
+		void    InputUpdateFromVector(bool* vector, int name, int type){_error2_("Not implemented yet!");}
+		void    InputUpdateFromMatrixDakota(IssmDouble* matrix, int nrows,int ncols, int name, int type){_error2_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(IssmDouble* vector, int name, int type){_error2_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(int* vector, int name, int type){_error2_("Not implemented yet!");}
+		void    InputUpdateFromVectorDakota(bool* vector, int name, int type){_error2_("Not implemented yet!");}
+		void    InputUpdateFromConstant(IssmDouble constant, int name);
+		void    InputUpdateFromConstant(int constant, int name){_error2_("Not implemented yet!");}
+		void    InputUpdateFromConstant(bool constant, int name);
+		void    InputUpdateFromSolution(IssmDouble* solution){_error2_("Not implemented yet!");}
+		void  InputUpdateFromIoModel(int index, IoModel* iomodel){_error2_("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* Kff, Matrix* Kfs);
+		void  CreatePVector(Vector* pf);
+		void  CreateJacobianMatrix(Matrix* Jff){_error2_("Not implemented yet");};
+		void  PenaltyCreateJacobianMatrix(Matrix* Jff,IssmDouble kmax){_error2_("Not implemented yet");};
+		void  PenaltyCreateKMatrix(Matrix* Kff, Matrix* kfs, IssmDouble kmax);
+		void  PenaltyCreatePVector(Vector* pf, IssmDouble kmax);
+		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/objects/Materials/Material.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Materials/Material.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Materials/Material.h	(revision 12822)
@@ -0,0 +1,27 @@
+/*!\file:  Material.h
+ * \brief abstract class for Material object
+ */ 
+
+
+#ifndef _MATERIAL_H_
+#define _MATERIAL_H_
+
+/*Headers:*/
+/*{{{*/
+class Object;
+#include "../Object.h"
+#include "../../toolkits/toolkits.h"
+/*}}}*/
+
+class Material: public Object,public Update{
+
+	public: 
+		virtual       ~Material(){};
+
+		/*Numerics*/
+		virtual void   InputDuplicate(int original_enum,int new_enum)=0;
+		virtual void   Configure(Elements* elements)=0;
+		virtual void   GetVectorFromInputs(Vector* vector,int input_enum)=0;
+
+};
+#endif
Index: /issm/trunk-jpl/src/c/classes/objects/Materials/Matice.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Materials/Matice.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Materials/Matice.cpp	(revision 12822)
@@ -0,0 +1,769 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../include/include.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    i;
+	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::MyRank {{{*/
+int    Matice::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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(elementsin);
+}
+/*}}}*/
+/*FUNCTION Matice::SetCurrentConfiguration {{{*/
+void  Matice::SetCurrentConfiguration(Elements* elementsin,Loads* loadsin,Nodes* nodesin,Vertices* verticesin,Materials* materialsin,Parameters* parametersin){
+
+}
+/*}}}*/
+/*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* 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]->GetVertexDof();
+
+			/*Get input (either in element or material)*/
+			Input* input=inputs->GetInput(input_enum);
+			if(!input) _error2_("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: _error2_("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((IssmDouble)10,(IssmDouble)17);
+			}
+			else{
+				e=(n-1)/(2*n);
+				viscosity=B/(2*pow(A,e));
+			}
+		}
+	}
+
+	/*Checks in debugging mode*/
+	if(viscosity<=0) _error2_("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) _error2_("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) _error2_("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,exz;
+
+	/*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]->GetVertexDof()];
+					this->inputs->AddInput(new TriaP1Input(name,values));
+					return;
+				}
+				default: _error2_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+			}
+		default: _error2_("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]->GetSidList()]; //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: _error2_("element " << EnumToStringx(element->ObjectEnum()) << " not implemented yet");
+			}
+		default: _error2_("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((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)[int(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[int(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[int(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)[int(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((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)[int(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)];
+							for(j=0;j<num_vertices;j++)cmmininputs[j]=iomodel->Data(InversionMinParametersEnum)[int(iomodel->Data(MeshElementsEnum)[num_vertices*index+j]-1)*num_control_type+i];
+							for(j=0;j<num_vertices;j++)cmmaxinputs[j]=iomodel->Data(InversionMaxParametersEnum)[int(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{
+		_error2_("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/objects/Materials/Matice.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Materials/Matice.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Materials/Matice.h	(revision 12822)
@@ -0,0 +1,74 @@
+/*!\file Matice.h
+ * \brief: header file for matice object
+ */
+
+#ifndef MATICE_H_
+#define MATICE_H_
+
+/*Headers:*/
+/*{{{*/
+#include "./Material.h"
+class IoModel;
+/*}}}*/
+
+class Matice: public Material{
+
+	private: 
+		/*Id*/
+		int	   mid;
+
+		/*hooks: */
+		Hook* helement;
+
+	public:
+		/*WARNING: input should not be public but it is an easy way to update B from T (using UpdateFromSolution) from Pentas*/
+		Inputs*  inputs;
+
+		/*Matice constructors, destructors: {{{*/
+		Matice();
+		Matice(int mid,int i, IoModel* iomodel);
+		~Matice();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		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* vector,int input_enum);
+		/*}}}*/
+		/*Matice Numerics: {{{*/
+		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   GetViscosityDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon);
+		void   GetViscosity2dDerivativeEpsSquare(IssmDouble* pmu_prime, IssmDouble* pepsilon);
+		IssmDouble GetB();
+		IssmDouble GetBbar();
+		IssmDouble GetN();
+		bool   IsInput(int name);
+		/*}}}*/
+};
+
+#endif  /* _MATICE_H_ */
Index: /issm/trunk-jpl/src/c/classes/objects/Materials/Matpar.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Materials/Matpar.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Materials/Matpar.cpp	(revision 12822)
@@ -0,0 +1,361 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../include/include.h"
+#include "../../EnumDefinitions/EnumDefinitions.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){
+
+	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);
+	
+	iomodel->Constant(&this->hydro_CR,HydrologyCREnum);
+	iomodel->Constant(&this->kn,HydrologyKnEnum);
+	iomodel->Constant(&this->hydro_n,HydrologyNEnum);
+	iomodel->Constant(&this->hydro_p,HydrologyPEnum);
+	iomodel->Constant(&this->hydro_q,HydrologyQEnum);
+}
+/*}}}*/
+/*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);
+	return;
+}
+/*}}}*/
+/*FUNCTION Matpar::DeepEcho {{{*/
+void Matpar::DeepEcho(void){
+
+	this->Echo();
+}		
+/*}}}*/
+/*FUNCTION Matpar::Id {{{*/
+int    Matpar::Id(void){ return mid; }
+/*}}}*/
+/*FUNCTION Matpar::MyRank {{{*/
+int    Matpar::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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;
+		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::GetThermalConductivity {{{*/
+IssmDouble Matpar::GetThermalConductivity(){
+	return thermalconductivity;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetThermalExchangeVelocity {{{*/
+IssmDouble Matpar::GetThermalExchangeVelocity(){
+	return thermal_exchange_velocity;
+}
+/*}}}*/
+/*FUNCTION Matpar::GetKn {{{*/		 
+IssmDouble Matpar::GetKn(){			 
+	return 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::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;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Materials/Matpar.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Materials/Matpar.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Materials/Matpar.h	(revision 12822)
@@ -0,0 +1,99 @@
+/*!\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;
+
+		/*hydrology: */		 
+		IssmDouble  kn;			 
+		IssmDouble  hydro_p;		 
+		IssmDouble  hydro_q;		 
+		IssmDouble  hydro_CR;			 
+		IssmDouble  hydro_n; 
+
+	public:
+		Matpar();
+		Matpar(int matpar_id, IoModel* iomodel);
+		~Matpar();
+
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		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){_error2_("not implemented yet");};
+		/*}}}*/
+		/*Material virtual functions resolution: {{{*/
+		void   InputDuplicate(int original_enum,int new_enum){_error2_("not implemented yet");};
+		void   Configure(Elements* elements);
+		void   GetVectorFromInputs(Vector* vector,int input_enum){return;}
+		/*}}}*/
+		/*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 GetKn();
+		IssmDouble GetHydrologyP();
+		IssmDouble GetHydrologyQ();
+		IssmDouble GetHydrologyCR();
+		IssmDouble GetHydrologyN();
+		IssmDouble TMeltingPoint(IssmDouble pressure);
+		IssmDouble PureIceEnthalpy(IssmDouble pressure);
+		IssmDouble GetEnthalpyDiffusionParameter(IssmDouble enthalpy,IssmDouble pressure);
+		void   EnthalpyToThermal(IssmDouble* ptemperature,IssmDouble* pwaterfraction,IssmDouble enthalpy,IssmDouble pressure);
+		void   ThermalToEnthalpy(IssmDouble* penthalpy,IssmDouble temperature,IssmDouble waterfraction,IssmDouble pressure);
+		/*}}}*/
+
+};
+
+#endif  /* _MATPAR_H_ */
Index: /issm/trunk-jpl/src/c/classes/objects/Options/Option.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/Option.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/Option.cpp	(revision 12822)
@@ -0,0 +1,116 @@
+/*!\file Option.cpp
+ * \brief: implementation of the optionsobject abstract 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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../io/io.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION Option::Option(){{{*/
+Option::Option(){
+
+	name  =NULL;
+	numel =0;
+	ndims =0;
+	size  =NULL;
+
+}
+/*}}}*/
+/*FUNCTION Option::~Option(){{{*/
+Option::~Option(){
+
+	if(size) xDelete<int>(size);
+	if(name) xDelete<char>(name);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION Option::Echo {{{*/
+void  Option::Echo(){
+
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_("          name: \"" << name << "\"");
+	if(flag) _pprintLine_("         numel: " << numel);
+	if(flag) _pprintLine_("         ndims: " << ndims);
+	if(size){
+		StringFromSize(cstr,size,ndims);
+		if(flag) _pprintLine_("          size: " << cstr);
+	}
+	else if(flag) _pprintLine_("          size: [empty]");
+}
+/*}}}*/
+/*FUNCTION Option::DeepEcho() {{{*/
+void  Option::DeepEcho(){
+
+	char  indent[81]="";
+
+	Option::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION Option::DeepEcho(char* indent) {{{*/
+void  Option::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]");
+}
+/*}}}*/
+/*FUNCTION Option::Name {{{*/
+char* Option::Name(){
+
+	return(name);
+}
+/*}}}*/
+/*FUNCTION Option::NumEl {{{*/
+int   Option::NumEl(){
+
+	return(numel);
+}
+/*}}}*/
+/*FUNCTION Option::NDims {{{*/
+int   Option::NDims(){
+
+	return(ndims);
+}
+/*}}}*/
+/*FUNCTION Option::Size {{{*/
+int*  Option::Size(){
+
+	return(size);
+}
+/*}}}*/
+/*FUNCTION Option::Get {{{*/
+//void* Option::Get(){
+
+//	;
+
+//	return;
+//}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Options/Option.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/Option.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/Option.h	(revision 12822)
@@ -0,0 +1,55 @@
+/*! \file Option.h 
+ *  \brief: header file for option abstract object
+ */
+
+#ifndef _OPTIONOBJECT_H_
+#define _OPTIONOBJECT_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+
+#include "../Object.h"
+/*}}}*/
+
+class Option: public Object {
+
+	public:
+
+		char* name;
+		int   numel;
+		int   ndims;
+		int*  size;
+
+		/*Option constructors, destructors {{{*/
+		Option();
+		~Option();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		virtual void  Echo();
+		virtual void  DeepEcho();
+		virtual void  DeepEcho(char* indent);
+		int   Id(){_error2_("Not implemented yet");};
+		int   MyRank(){_error2_("Not implemented yet");};
+		int   ObjectEnum(){return OptionEnum;};
+		Object* copy(){_error2_("Not implemented yet");};
+		/*}}}*/
+
+		/*virtual functions: */
+		virtual char* Name()=0;
+		virtual int   NumEl()=0;
+		virtual int   NDims()=0;
+		virtual int*  Size()=0;
+		virtual void  Get(int* pvalue)=0;
+		virtual void  Get(IssmDouble* pvalue)=0;
+		virtual void  Get(bool* pvalue)=0;
+		virtual void  Get(char** pvalue)=0;
+		virtual void  Get(char*** ppvalue,int *pnumel)=0;
+		virtual void  Get(IssmDouble** pvalue,int *pnumel)=0;
+		virtual void  Get(Options** pvalue)=0;
+		virtual void  Get(Options*** ppvalue,int *pnumel)=0;
+
+};
+#endif  /* _OPTIONOBJECT_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionCell.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionCell.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionCell.cpp	(revision 12822)
@@ -0,0 +1,127 @@
+/*!\file OptionCell.cpp
+ * \brief: implementation of the optionscell 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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION OptionCell::OptionCell(){{{*/
+OptionCell::OptionCell(){
+
+	values    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION OptionCell::~OptionCell(){{{*/
+OptionCell::~OptionCell(){
+
+	if (values){
+		delete values;
+		values    =NULL;
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION OptionCell::Echo {{{*/
+void  OptionCell::Echo(){
+
+	char cstr[81];
+	bool flag     = true;
+
+	if(flag) _pprintLine_("OptionCell Echo:");
+	Option::Echo();
+
+	if (values && size) {
+		StringFromSize(cstr,size,ndims);
+		if(flag) _pprintLine_("        values: " << cstr << " " << "cell");
+	}
+	else if(flag) _pprintLine_("        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionCell::DeepEcho() {{{*/
+void  OptionCell::DeepEcho(){
+
+	char  indent[81]="";
+
+	OptionCell::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION OptionCell::DeepEcho(char* indent) {{{*/
+void  OptionCell::DeepEcho(char* indent){
+
+	int   i;
+	int*  dims;
+	char  indent2[81];
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "OptionCell DeepEcho:");
+	Option::DeepEcho(indent);
+
+	xMemCpy<char>(indent2,indent,(strlen(indent)+1));
+	strcat(indent2,"  ");
+
+	if (values->Size()) {
+		dims=xNew<int>(ndims);
+		for (i=0; i<values->Size(); i++) {
+			ColumnWiseDimsFromIndex(dims,i,size,ndims);
+			StringFromDims(cstr,dims,ndims);
+			if(flag) _pprintLine_(indent << "        values: -------- begin " << cstr << " --------");
+			((Option *)values->GetObjectByOffset(i))->DeepEcho(indent2);
+			if(flag) _pprintLine_(indent << "        values: --------  end  " << cstr << " --------");
+		}
+		xDelete<int>(dims);
+	}
+	else if(flag) _pprintLine_(indent << "        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionCell::Name {{{*/
+char* OptionCell::Name(){
+
+	return(Option::Name());
+}
+/*}}}*/
+/*FUNCTION OptionCell::NumEl {{{*/
+int   OptionCell::NumEl(){
+
+	return(Option::NumEl());
+}
+/*}}}*/
+/*FUNCTION OptionCell::NDims {{{*/
+int   OptionCell::NDims(){
+
+	return(Option::NDims());
+}
+/*}}}*/
+/*FUNCTION OptionCell::Size {{{*/
+int*  OptionCell::Size(){
+
+	return(Option::Size());
+}
+/*}}}*/
+/*FUNCTION OptionCell::Get(Options** pvalue) {{{*/
+void OptionCell::Get(Options** pvalue){
+
+	/*Assign output pointer*/
+	*pvalue=this->values;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionCell.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionCell.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionCell.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*! \file OptionCell.h 
+ *  \brief: header file for optioncell object
+ */
+
+#ifndef _OPTIONCELL_H_
+#define _OPTIONCELL_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+
+#include "./Option.h"
+/*}}}*/
+
+class OptionCell: public Option {
+
+	public:
+
+		Options* values;
+
+		/*OptionCell constructors, destructors {{{*/
+		OptionCell();
+		~OptionCell();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(char* indent);
+		int   Id(){_error2_("Not implemented yet");};
+		int   MyRank(){_error2_("Not implemented yet");};
+		int   ObjectEnum(){return OptionCellEnum;};
+		Object* copy(){_error2_("Not implemented yet");};
+		/*}}}*/
+
+		/*virtual functions: */
+		char* Name();
+		int   NumEl();
+		int   NDims();
+		int*  Size();
+		void  Get(int* pvalue){_error2_("An OptionCell object cannot return a int");};
+		void  Get(IssmDouble* pvalue){_error2_("An OptionCell object cannot return a IssmDouble");};
+		void  Get(bool* pvalue){  _error2_("An OptionCell object cannot return a bool");};
+		void  Get(char** pvalue){ _error2_("An OptionCell object cannot return a string");};
+		void  Get(char*** ppvalue,int *pnumel){ _error2_("An OptionCell object cannot return a string vec");};
+		void  Get(IssmDouble** pvalue,int *pnumel){ _error2_("An OptionCell object cannot return a IssmDouble vec");};
+		void  Get(Options** pvalue);
+		void  Get(Options*** ppvalue,int *pnumel){ _error2_("An OptionCell object cannot return an Options DataSet vec");};
+
+};
+#endif  /* _OPTIONCELL_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionChar.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionChar.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionChar.cpp	(revision 12822)
@@ -0,0 +1,176 @@
+/*!\file OptionChar.cpp
+ * \brief: implementation of the optionschar 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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION OptionChar::OptionChar(){{{*/
+OptionChar::OptionChar(){
+
+	values    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION OptionChar::~OptionChar(){{{*/
+OptionChar::~OptionChar(){
+
+	if (values) xDelete<char>(values);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION OptionChar::Echo {{{*/
+void  OptionChar::Echo(){
+
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_("OptionChar Echo:");
+	Option::Echo();
+
+	if (values && size) {
+//		if (numel == 1) {
+		if (1) {
+//			if(flag) _pprintLine_("        values: \"" << values[0] << "\"");
+			if(flag) _pprintLine_("        values: \"" << values << "\"");
+		}
+		else {
+			StringFromSize(cstr,size,ndims);
+			if(flag) _pprintLine_("        values: " << cstr << " " << "char");
+		}
+	}
+	else if(flag) _pprintLine_("        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionChar::DeepEcho() {{{*/
+void  OptionChar::DeepEcho(){
+
+	char  indent[81]="";
+
+	OptionChar::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION OptionChar::DeepEcho(char* indent) {{{*/
+void  OptionChar::DeepEcho(char* indent){
+
+	int   i,nstr,ipt=0;
+	int*  dims;
+	char  indent2[81];
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "OptionChar DeepEcho:");
+	Option::DeepEcho(indent);
+
+	xMemCpy<char>(indent2,indent,(strlen(indent)+1));
+	strcat(indent2,"  ");
+
+	if (values) {
+		if (ndims == 2 && size[0] == 1) {
+			if(flag) _pprintLine_(indent << "        values: \"" << values << "\"");
+		}
+		else {
+			nstr=size[0];
+			for (i=2; i<ndims; i++) nstr*=size[i];
+
+			dims=xNew<int>(ndims);
+			for (i=0; i<nstr; i++) {
+				RowWiseDimsFromIndex(dims,ipt,size,ndims);
+				StringFromDims(cstr,dims,ndims);
+				if(flag) _pprintLine_(indent << "        values" << cstr << ": \"" << size[1] << "*s\"");
+				ipt+=size[1];
+			}
+			xDelete<int>(dims);
+		}
+	}
+	else if(flag) _pprintLine_(indent << "        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionChar::Name {{{*/
+char* OptionChar::Name(){
+
+	return(Option::Name());
+}
+/*}}}*/
+/*FUNCTION OptionChar::NumEl {{{*/
+int   OptionChar::NumEl(){
+
+	return(Option::NumEl());
+}
+/*}}}*/
+/*FUNCTION OptionChar::NDims {{{*/
+int   OptionChar::NDims(){
+
+	return(Option::NDims());
+}
+/*}}}*/
+/*FUNCTION OptionChar::Size {{{*/
+int*  OptionChar::Size(){
+
+	return(Option::Size());
+}
+/*}}}*/
+/*FUNCTION OptionChar::Get(char** pvalue) {{{*/
+void OptionChar::Get(char** pvalue){
+
+	char* outstring=NULL;
+	int   stringsize;
+
+	stringsize=strlen(this->values)+1;
+
+	outstring=xNew<char>(stringsize);
+	xMemCpy<char>(outstring,this->values,stringsize);
+
+	*pvalue=outstring;
+}
+/*}}}*/
+/*FUNCTION OptionChar::Get(char*** ppvalue,int *pnumel) {{{*/
+void OptionChar::Get(char*** ppvalue,int *pnumel){
+
+	char* outstring=NULL;
+	int   stringsize;
+	int   i,nstr,ipt=0;
+
+	/*We should first check that the size is at least one*/
+	if(this->NumEl()<=0){
+		_error2_("option \"" << this->name << "\" is empty and cannot return a string vector");
+	}
+
+	/*Calculate the size and number of strings*/
+	stringsize=this->size[1]+1;
+	nstr=this->size[0];
+	for (i=2; i<this->ndims; i++) nstr*=this->size[i];
+
+	/*Break concatenated string into individual strings*/
+	*ppvalue=xNew<char*>(nstr);
+	for (i=0; i<nstr; i++) {
+		outstring=xNew<char>(stringsize);
+		xMemCpy<char>(outstring,&(this->values[ipt]),(stringsize-1));
+		outstring[stringsize-1]='\0';
+		(*ppvalue)[i]=outstring;
+		ipt+=stringsize-1;
+	}
+
+	/*Assign output pointer*/
+	if(numel) *pnumel=nstr;
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionChar.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionChar.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionChar.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*! \file OptionChar.h 
+ *  \brief: header file for optionchar object
+ */
+
+#ifndef _OPTIONCHAR_H_
+#define _OPTIONCHAR_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+
+#include "./Option.h"
+/*}}}*/
+
+class OptionChar: public Option {
+
+	public:
+
+		char* values;
+
+		/*OptionChar constructors, destructors {{{*/
+		OptionChar();
+		~OptionChar();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(char* indent);
+		int   Id(){_error2_("Not implemented yet");};
+		int   MyRank(){_error2_("Not implemented yet");};
+		int   ObjectEnum(){return OptionCharEnum;};
+		Object* copy(){_error2_("Not implemented yet");};
+		/*}}}*/
+
+		/*virtual functions: */
+		char* Name();
+		int   NumEl();
+		int   NDims();
+		int*  Size();
+		void  Get(int* pvalue){_error2_("An OptionChar object cannot return a int");};
+		void  Get(IssmDouble* pvalue){_error2_("An OptionChar object cannot return a IssmDouble");};
+		void  Get(bool* pvalue){  _error2_("An OptionChar object cannot return a bool");};
+		void  Get(char** pvalue);
+		void  Get(char*** ppvalue,int *pnumel);
+		void  Get(IssmDouble** pvalue,int *pnumel){ _error2_("An OptionChar object cannot return a IssmDouble vec");};
+		void  Get(Options** pvalue){ _error2_("An OptionChar object cannot return an Options DataSet");};
+		void  Get(Options*** ppvalue,int *pnumel){ _error2_("An OptionChar object cannot return an Options DataSet vec");};
+
+};
+#endif  /* _OPTIONCHAR_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionDouble.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionDouble.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionDouble.cpp	(revision 12822)
@@ -0,0 +1,162 @@
+/*!\file OptionDouble.cpp
+ * \brief: implementation of the optionsIssmDouble 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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION OptionDouble::OptionDouble(){{{*/
+OptionDouble::OptionDouble(){
+
+	values    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION OptionDouble::~OptionDouble(){{{*/
+OptionDouble::~OptionDouble(){
+
+	if (values) xDelete<IssmDouble>(values);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION OptionDouble::Echo {{{*/
+void  OptionDouble::Echo(){
+
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_("OptionDouble Echo:");
+	Option::Echo();
+
+	if (values && size) {
+		if(numel == 1) if(flag) _pprintLine_("        values: " << values[0]);
+		else {
+			StringFromSize(cstr,size,ndims);
+			if(flag) _pprintLine_("        values: " << cstr << " " << "IssmDouble");
+		}
+	}
+	else if(flag) _pprintLine_("        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionDouble::DeepEcho() {{{*/
+void  OptionDouble::DeepEcho(){
+
+	char  indent[81]="";
+
+	OptionDouble::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION OptionDouble::DeepEcho(char* indent) {{{*/
+void  OptionDouble::DeepEcho(char* indent){
+
+	int   i;
+	int*  dims;
+	char  indent2[81];
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "OptionDouble DeepEcho:");
+	Option::DeepEcho(indent);
+
+	xMemCpy<char>(indent2,indent,(strlen(indent)+1));
+	strcat(indent2,"  ");
+
+	if (values) {
+		dims=xNew<int>(ndims);
+		if(numel==1) if(flag) _pprintLine_(indent << "        values: " << values[0]);
+		else{
+			for (i=0; i<numel; i++) {
+				RowWiseDimsFromIndex(dims,i,size,ndims);
+				StringFromDims(cstr,dims,ndims);
+				if(flag) _pprintLine_(indent << "        values" << cstr << ": " << values[i]);
+			}
+		}
+		xDelete<int>(dims);
+	}
+	else if(flag) _pprintLine_(indent << "        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionDouble::Name {{{*/
+char* OptionDouble::Name(){
+
+	return(Option::Name());
+}
+/*}}}*/
+/*FUNCTION OptionDouble::NumEl {{{*/
+int   OptionDouble::NumEl(){
+
+	return(Option::NumEl());
+}
+/*}}}*/
+/*FUNCTION OptionDouble::NDims {{{*/
+int   OptionDouble::NDims(){
+
+	return(Option::NDims());
+}
+/*}}}*/
+/*FUNCTION OptionDouble::Size {{{*/
+int*  OptionDouble::Size(){
+
+	return(Option::Size());
+}
+/*}}}*/
+/*FUNCTION OptionDouble::Get(int* pvalue) {{{*/
+void OptionDouble::Get(int* pvalue){
+
+	/*We should first check that the size is one*/
+	if(this->NumEl()!=1){
+		_error2_("option \"" << this->name << "\" has " << this->NumEl() << " elements and cannot return a single int");
+	}
+
+	/*Assign output pointer*/
+	*pvalue=reCast<int>(values[0]);
+}
+/*}}}*/
+/*FUNCTION OptionDouble::Get(IssmDouble* pvalue) {{{*/
+void OptionDouble::Get(IssmDouble* pvalue){
+
+	/*We should first check that the size is one*/
+	if(this->NumEl()!=1){
+		_error2_("option \"" << this->name << "\" has " << this->NumEl() << " elements and cannot return a single IssmDouble");
+	}
+
+	/*Assign output pointer*/
+	*pvalue=this->values[0];
+}
+/*}}}*/
+/*FUNCTION OptionDouble::Get(IssmDouble** pvalue,int* numel) {{{*/
+void OptionDouble::Get(IssmDouble** pvalue,int* numel){
+
+	/*We should first check that the size is at least one*/
+	if(this->NumEl()<=0){
+		_error2_("option \"" << this->name << "\" is empty and cannot return a IssmDouble vector");
+	}
+
+	/*Copy vector*/
+	IssmDouble* outvalue=xNew<IssmDouble>(this->NumEl());
+	for(int i=0;i<this->NumEl();i++) outvalue[i]=this->values[i];
+
+	/*Assign output pointer*/
+	*pvalue=outvalue;
+	if(numel) *numel=this->NumEl();
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionDouble.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionDouble.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionDouble.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*! \file OptionDouble.h 
+ *  \brief: header file for optionIssmDouble object
+ */
+
+#ifndef _OPTIONDOUBLE_H_
+#define _OPTIONDOUBLE_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+
+#include "./Option.h"
+/*}}}*/
+
+class OptionDouble: public Option {
+
+	public:
+
+		IssmDouble* values;
+
+		/*OptionDouble constructors, destructors {{{*/
+		OptionDouble();
+		~OptionDouble();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(char* indent);
+		int   Id(){_error2_("Not implemented yet");};
+		int   MyRank(){_error2_("Not implemented yet");};
+		int   ObjectEnum(){return OptionDoubleEnum;};
+		Object* copy(){_error2_("Not implemented yet");};
+		/*}}}*/
+
+		/*virtual functions: */
+		char* Name();
+		int   NumEl();
+		int   NDims();
+		int*  Size();
+		void  Get(int* pvalue);
+		void  Get(IssmDouble* pvalue);
+		void  Get(bool* pvalue){  _error2_("An OptionDouble object cannot return a bool");};
+		void  Get(char** pvalue){ _error2_("An OptionDouble object cannot return a string");};
+		void  Get(char*** ppvalue,int *pnumel){ _error2_("An OptionDouble object cannot return a string vec");};
+		void  Get(IssmDouble** pvalue,int* pnumel);
+		void  Get(Options** pvalue){ _error2_("An OptionDouble object cannot return an Options DataSet");};
+		void  Get(Options*** ppvalue,int *pnumel){ _error2_("An OptionDouble object cannot return an Options DataSet vec");};
+
+};
+#endif  /* _OPTIONDOUBLE_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionLogical.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionLogical.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionLogical.cpp	(revision 12822)
@@ -0,0 +1,133 @@
+/*!\file OptionLogical.cpp
+ * \brief: implementation of the optionslogical 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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION OptionLogical::OptionLogical(){{{*/
+OptionLogical::OptionLogical(){
+
+	values    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION OptionLogical::~OptionLogical(){{{*/
+OptionLogical::~OptionLogical(){
+
+	if (values) xDelete<bool>(values);
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION OptionLogical::Echo {{{*/
+void  OptionLogical::Echo(){
+
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_("OptionLogical Echo:");
+	Option::Echo();
+
+	if (values && size) {
+		if(numel == 1) if(flag) _pprintLine_("        values: " << (values[0] ? "true" : "false"));
+		else{
+			StringFromSize(cstr,size,ndims);
+			if(flag) _pprintLine_("        values: " << cstr << " " << "logical");
+		}
+	}
+	else if(flag) _pprintLine_("        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionLogical::DeepEcho() {{{*/
+void  OptionLogical::DeepEcho(){
+
+	char  indent[81]="";
+
+	OptionLogical::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION OptionLogical::DeepEcho(char* indent) {{{*/
+void  OptionLogical::DeepEcho(char* indent){
+
+	int   i;
+	int*  dims;
+	char  indent2[81];
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "OptionLogical DeepEcho:");
+	Option::DeepEcho(indent);
+
+	xMemCpy<char>(indent2,indent,(strlen(indent)+1));
+	strcat(indent2,"  ");
+
+	if (values) {
+		if(numel==1) if(flag) _pprintLine_(indent << "        values: " << (values[0] ? "true" : "false"));
+		else{
+			dims=xNew<int>(ndims);
+			for (i=0; i<numel; i++) {
+				RowWiseDimsFromIndex(dims,i,size,ndims);
+				StringFromDims(cstr,dims,ndims);
+				if(flag) _pprintLine_(indent << "        values" << cstr << ": " << (values[i] ? "true" : "false"));
+			}
+			xDelete<int>(dims);
+		}
+	}
+	else if(flag) _pprintLine_(indent << "        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionLogical::Name {{{*/
+char* OptionLogical::Name(){
+
+	return(Option::Name());
+}
+/*}}}*/
+/*FUNCTION OptionLogical::NumEl {{{*/
+int   OptionLogical::NumEl(){
+
+	return(Option::NumEl());
+}
+/*}}}*/
+/*FUNCTION OptionLogical::NDims {{{*/
+int   OptionLogical::NDims(){
+
+	return(Option::NDims());
+}
+/*}}}*/
+/*FUNCTION OptionLogical::Size {{{*/
+int*  OptionLogical::Size(){
+
+	return(Option::Size());
+}
+/*}}}*/
+/*FUNCTION OptionLogical::Get(bool* pvalue) {{{*/
+void OptionLogical::Get(bool* pvalue){
+
+	/*We should first check that the size is one*/
+	if(this->NumEl()!=1){
+		_error2_("option \"" << this->name << "\" has " << this->NumEl() << " elements and cannot return a single bool");
+	}
+
+	/*Assign output pointer*/
+	*pvalue=this->values[0];
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionLogical.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionLogical.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionLogical.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*! \file OptionLogical.h 
+ *  \brief: header file for optionlogical object
+ */
+
+#ifndef _OPTIONLOGICAL_H_
+#define _OPTIONLOGICAL_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+
+#include "./Option.h"
+/*}}}*/
+
+class OptionLogical: public Option {
+
+	public:
+
+		bool* values;
+
+		/*OptionLogical constructors, destructors {{{*/
+		OptionLogical();
+		~OptionLogical();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(char* indent);
+		int   Id(){_error2_("Not implemented yet");};
+		int   MyRank(){_error2_("Not implemented yet");};
+		int   ObjectEnum(){return OptionLogicalEnum;};
+		Object* copy(){_error2_("Not implemented yet");};
+		/*}}}*/
+
+		/*virtual functions: */
+		char* Name();
+		int   NumEl();
+		int   NDims();
+		int*  Size();
+		void  Get(int* pvalue){_error2_("An OptionLogical object cannot return a int");};
+		void  Get(IssmDouble* pvalue){_error2_("An OptionLogical object cannot return a IssmDouble");};
+		void  Get(bool* pvalue);
+		void  Get(char** pvalue){ _error2_("An OptionLogical object cannot return a string");};
+		void  Get(char*** ppvalue,int *pnumel){ _error2_("An OptionLogical object cannot return a string vec");};
+		void  Get(IssmDouble** pvalue,int *pnumel){ _error2_("An OptionLogical object cannot return a IssmDouble vec");};
+		void  Get(Options** pvalue){ _error2_("An OptionLogical object cannot return an Options DataSet");};
+		void  Get(Options*** ppvalue,int *pnumel){ _error2_("An OptionLogical object cannot return an Options DataSet vec");};
+
+};
+#endif  /* _OPTIONLOGICAL_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionStruct.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionStruct.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionStruct.cpp	(revision 12822)
@@ -0,0 +1,153 @@
+/*!\file OptionStruct.cpp
+ * \brief: implementation of the optionsstruct 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 "../objects.h"
+#include "../../shared/shared.h"
+#include "../../io/io.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*Constructors/destructor/copy*/
+/*FUNCTION OptionStruct::OptionStruct(){{{*/
+OptionStruct::OptionStruct(){
+
+	values    =NULL;
+
+}
+/*}}}*/
+/*FUNCTION OptionStruct::~OptionStruct(){{{*/
+OptionStruct::~OptionStruct(){
+
+	int   i;
+
+	if(values){
+		for(i=0; i<numel; i++) {
+			delete values[i];
+			values[i] =NULL;
+		}
+		xDelete<Options*>(values);
+	}
+
+}
+/*}}}*/
+
+/*Other*/
+/*FUNCTION OptionStruct::Echo {{{*/
+void  OptionStruct::Echo(){
+
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_("OptionStruct Echo:");
+	Option::Echo();
+
+	if (values && size) {
+		StringFromSize(cstr,size,ndims);
+		if(flag) _pprintLine_("        values: " << cstr << " " << "struct");
+	}
+	else if(flag) _pprintLine_("        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionStruct::DeepEcho() {{{*/
+void  OptionStruct::DeepEcho(){
+
+	char  indent[81]="";
+
+	OptionStruct::DeepEcho(indent);
+
+	return;
+}
+/*}}}*/
+/*FUNCTION OptionStruct::DeepEcho(char* indent) {{{*/
+void  OptionStruct::DeepEcho(char* indent){
+
+	int   i,j;
+	int*  dims;
+	char  indent2[81];
+	char  cstr[81];
+	bool  flag=true;
+
+	if(flag) _pprintLine_(indent << "OptionStruct DeepEcho:");
+	Option::DeepEcho(indent);
+
+	xMemCpy<char>(indent2,indent,(strlen(indent)+1));
+	strcat(indent2,"  ");
+
+	if (values) {
+		dims=xNew<int>(ndims);
+		for (i=0; i<numel; i++) {
+			ColumnWiseDimsFromIndex(dims,i,size,ndims);
+			StringFromDims(cstr,dims,ndims);
+			if (values[i]->Size()){
+				if(flag) _pprintLine_(indent << "        values: -------- begin " << cstr << " --------");
+				for (j=0; j<values[i]->Size(); j++) ((Option *)values[i]->GetObjectByOffset(j))->DeepEcho(indent2);
+				if(flag) _pprintLine_(indent << "        values: --------  end  " << cstr << " --------");
+			}
+			else if(flag) _pprintLine_(indent << "        values: " << cstr << " [empty]");
+		}
+		xDelete<int>(dims);
+	}
+	else if(flag) _pprintLine_(indent << "        values: [empty]");
+}
+/*}}}*/
+/*FUNCTION OptionStruct::Name {{{*/
+char* OptionStruct::Name(){
+
+	return(Option::Name());
+}
+/*}}}*/
+/*FUNCTION OptionStruct::NumEl {{{*/
+int   OptionStruct::NumEl(){
+
+	return(Option::NumEl());
+}
+/*}}}*/
+/*FUNCTION OptionStruct::NDims {{{*/
+int   OptionStruct::NDims(){
+
+	return(Option::NDims());
+}
+/*}}}*/
+/*FUNCTION OptionStruct::Size {{{*/
+int*  OptionStruct::Size(){
+
+	return(Option::Size());
+}
+/*}}}*/
+/*FUNCTION OptionStruct::Get(Options** pvalue) {{{*/
+void OptionStruct::Get(Options** pvalue){
+
+	/*We should first check that the size is one*/
+	if(this->NumEl()!=1){
+		_error2_("option \"" << this->name << "\" has " << this->NumEl() << " elements and cannot return a single options dataset");
+	}
+
+	/*Assign output pointer*/
+	*pvalue=this->values[0];
+}
+/*}}}*/
+/*FUNCTION OptionStruct::Get(Options*** ppvalue,int* numel) {{{*/
+void OptionStruct::Get(Options*** ppvalue,int* numel){
+
+	/*We should first check that the size is at least one*/
+	if(this->NumEl()<=0){
+		_error2_("option \"" << this->name << "\" is empty and cannot return an options dataset vector");
+	}
+
+	/*Assign output pointer*/
+	*ppvalue=this->values;
+	if(numel) *numel=this->NumEl();
+}
+/*}}}*/
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionStruct.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionStruct.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionStruct.h	(revision 12822)
@@ -0,0 +1,52 @@
+/*! \file OptionStruct.h 
+ *  \brief: header file for optionstruct object
+ */
+
+#ifndef _OPTIONSTRUCT_H_
+#define _OPTIONSTRUCT_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+
+#include "./Option.h"
+/*}}}*/
+
+class OptionStruct: public Option {
+
+	public:
+
+		Options** values;
+
+		/*OptionStruct constructors, destructors {{{*/
+		OptionStruct();
+		~OptionStruct();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{*/
+		void  Echo();
+		void  DeepEcho();
+		void  DeepEcho(char* indent);
+		int   Id(){_error2_("Not implemented yet");};
+		int   MyRank(){_error2_("Not implemented yet");};
+		int   ObjectEnum(){return OptionStructEnum;};
+		Object* copy(){_error2_("Not implemented yet");};
+		/*}}}*/
+
+		/*virtual functions: */
+		char* Name();
+		int   NumEl();
+		int   NDims();
+		int*  Size();
+		void  Get(int* pvalue){_error2_("An OptionStruct object cannot return a int");};
+		void  Get(IssmDouble* pvalue){_error2_("An OptionStruct object cannot return a IssmDouble");};
+		void  Get(bool* pvalue){  _error2_("An OptionStruct object cannot return a bool");};
+		void  Get(char** pvalue){ _error2_("An OptionStruct object cannot return a string");};
+		void  Get(char*** ppvalue,int *pnumel){ _error2_("An OptionStruct object cannot return a string vec");};
+		void  Get(IssmDouble** pvalue,int *pnumel){ _error2_("An OptionStruct object cannot return a IssmDouble vec");};
+		void  Get(Options** pvalue);
+		void  Get(Options*** ppvalue,int *pnumel);
+
+};
+#endif  /* _OPTIONSTRUCT_H */
+
Index: /issm/trunk-jpl/src/c/classes/objects/Options/OptionUtilities.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionUtilities.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionUtilities.cpp	(revision 12822)
@@ -0,0 +1,114 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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) _error2_("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]) _error2_("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) _error2_("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]) _error2_("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/objects/Options/OptionUtilities.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Options/OptionUtilities.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Options/OptionUtilities.h	(revision 12822)
@@ -0,0 +1,24 @@
+/*! \file OptionUtilities.h 
+ *  \brief: header file for option object utilities
+ */
+
+#ifndef _OPTIONUTILITIES_H_
+#define _OPTIONUTILITIES_H_
+
+/*Headers:{{{*/
+#include "../../include/include.h"
+#include "../../shared/Exceptions/exceptions.h"
+#include "../../EnumDefinitions/EnumDefinitions.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/objects/Params/BoolParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/BoolParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/BoolParam.cpp	(revision 12822)
@@ -0,0 +1,89 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*BoolParam constructors and destructor*/
+/*FUNCTION BoolParam::BoolParam(){{{*/
+BoolParam::BoolParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION BoolParam::BoolParam(int enum_type,IssmBool value){{{*/
+BoolParam::BoolParam(int in_enum_type,IssmBool 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::MyRank{{{*/
+int    BoolParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/BoolParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/BoolParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/BoolParam.h	(revision 12822)
@@ -0,0 +1,77 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class BoolParam: public Param{
+
+	public:
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		IssmBool value;
+
+		/*BoolParam constructors, destructors: {{{*/
+		BoolParam();
+		BoolParam(int enum_type,IssmBool value);
+		~BoolParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){*pbool=value;}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot return a FILE");}
+
+		void  SetValue(bool boolean){this->value=boolean;}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold an int");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold an IssmPDouble");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a int array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << ") cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/DoubleMatArrayParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatArrayParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatArrayParam.cpp	(revision 12822)
@@ -0,0 +1,252 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DoubleMatArrayParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/DoubleMatArrayParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatArrayParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatArrayParam.h	(revision 12822)
@@ -0,0 +1,81 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims);
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << "cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a IssmDouble mat array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a int vec array");}
+		void  SetValue(int* intarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a int mat array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << "cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("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/objects/Params/DoubleMatParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatParam.cpp	(revision 12822)
@@ -0,0 +1,136 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DoubleMatParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){
+	_error2_("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/objects/Params/DoubleMatParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleMatParam.h	(revision 12822)
@@ -0,0 +1,80 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN);
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("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){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N);
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int vec array");}
+		void  SetValue(int* intarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");};
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/DoubleParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleParam.cpp	(revision 12822)
@@ -0,0 +1,116 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DoubleParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){
+	_error2_("Double param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return an integer");
+}
+/*}}}*/
+/*FUNCTION DoubleParam::GetParameterValue(bool* pbool){{{*/
+void DoubleParam::GetParameterValue(bool* pbool){
+	_error2_("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){
+	_error2_("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){
+	_error2_("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){
+	_error2_("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){
+	_error2_("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/objects/Params/DoubleParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleParam.h	(revision 12822)
@@ -0,0 +1,79 @@
+/*! \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 "../../include/include.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   MyRank();
+		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){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("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){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		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){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/DoubleTransientMatParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleTransientMatParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleTransientMatParam.cpp	(revision 12822)
@@ -0,0 +1,30 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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/objects/Params/DoubleTransientMatParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleTransientMatParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleTransientMatParam.h	(revision 12822)
@@ -0,0 +1,32 @@
+/*! \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 "../../include/include.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/objects/Params/DoubleVecParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleVecParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleVecParam.cpp	(revision 12822)
@@ -0,0 +1,150 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    DoubleVecParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){
+	_error2_("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/objects/Params/DoubleVecParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/DoubleVecParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/DoubleVecParam.h	(revision 12822)
@@ -0,0 +1,78 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param virtual functions definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM);
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");};
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("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){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M);
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");};
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/FileParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/FileParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/FileParam.cpp	(revision 12822)
@@ -0,0 +1,89 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    FileParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/FileParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/FileParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/FileParam.h	(revision 12822)
@@ -0,0 +1,78 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){  _error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("File param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){*pfid=value;};
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("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){_error2_("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/objects/Params/IntMatParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/IntMatParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/IntMatParam.cpp	(revision 12822)
@@ -0,0 +1,131 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    IntMatParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/IntMatParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/IntMatParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/IntMatParam.h	(revision 12822)
@@ -0,0 +1,80 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN);
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");};
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");};
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int vec array");};
+		void  SetValue(int* intarray,int M,int N);
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/IntParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/IntParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/IntParam.cpp	(revision 12822)
@@ -0,0 +1,89 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    IntParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/IntParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/IntParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/IntParam.h	(revision 12822)
@@ -0,0 +1,79 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){*pinteger=value;}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a bool");}
+		void  SetValue(int integer){this->value=integer;}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an int array");}
+		void  SetValue(int* intarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an int array");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/IntVecParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/IntVecParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/IntVecParam.cpp	(revision 12822)
@@ -0,0 +1,147 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    IntVecParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/IntVecParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/IntVecParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/IntVecParam.h	(revision 12822)
@@ -0,0 +1,79 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param virtual functions definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM);
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array (maybe in serial?)");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(int* intarray,int M);
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/MatrixParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/MatrixParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/MatrixParam.cpp	(revision 12822)
@@ -0,0 +1,117 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.h"
+/*}}}*/
+
+/*MatrixParam constructors and destructor*/
+/*FUNCTION MatrixParam::MatrixParam(){{{*/
+MatrixParam::MatrixParam(){
+	return;
+}
+/*}}}*/
+/*FUNCTION MatrixParam::MatrixParam(int enum_type,Matrix* value){{{*/
+MatrixParam::MatrixParam(int in_enum_type,Matrix* in_value){
+
+	enum_type=in_enum_type;
+	value=NULL;
+
+	if(in_value){
+		value=in_value->Duplicate();
+	}
+}
+/*}}}*/
+/*FUNCTION MatrixParam::~MatrixParam(){{{*/
+MatrixParam::~MatrixParam(){
+	xdelete(&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){
+
+	int i;
+	_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::MyRank{{{*/
+int    MatrixParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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** poutput){
+	Matrix* 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* matrix){
+	
+	/*avoid leak: */
+	xdelete(&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/objects/Params/MatrixParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/MatrixParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/MatrixParam.h	(revision 12822)
@@ -0,0 +1,79 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class MatrixParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		Matrix* value;
+
+	public:
+		/*MatrixParam constructors, destructors: {{{*/
+		MatrixParam();
+		MatrixParam(int enum_type,Matrix* value);
+		~MatrixParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a vec");}
+		void  GetParameterValue(Matrix** poutput);
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat);
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/Param.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/Param.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/Param.h	(revision 12822)
@@ -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** pvec)=0;
+		virtual void  GetParameterValue(Matrix** pmat)=0;
+		virtual void  GetParameterValue(FILE** pfid)=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* vec)=0;
+		virtual void  SetValue(Matrix* 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/objects/Params/StringArrayParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/StringArrayParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/StringArrayParam.cpp	(revision 12822)
@@ -0,0 +1,179 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    StringArrayParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/StringArrayParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/StringArrayParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/StringArrayParam.h	(revision 12822)
@@ -0,0 +1,80 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM);
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Vec param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M);
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/StringParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/StringParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/StringParam.cpp	(revision 12822)
@@ -0,0 +1,121 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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::MyRank{{{*/
+int    StringParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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/objects/Params/StringParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/StringParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/StringParam.h	(revision 12822)
@@ -0,0 +1,79 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring);
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Bool param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string);
+		void  SetValue(char** stringarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a int array");}
+		void  SetValue(Vector* vec){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/TransientParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/TransientParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/TransientParam.cpp	(revision 12822)
@@ -0,0 +1,151 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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){
+
+	int i,j;
+	
+	_printLine_("TransientParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	_printLine_("   size: " << this->N);
+	for(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::MyRank{{{*/
+int    TransientParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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){
+
+	double 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)_error2_("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/objects/Params/TransientParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/TransientParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/TransientParam.h	(revision 12822)
@@ -0,0 +1,80 @@
+/*! \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 "../../include/include.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   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time);
+		void  GetParameterValue(char** pstring){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM,int* pN){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Vector** pvec){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a Vec");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(FILE** pfid){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a IssmDouble vec array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M,int N){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a int vec array");}
+		void  SetValue(int* intarray,int M,int N){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a int mat array");};
+		void  SetValue(Vector* vec){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a Vec");}
+		void  SetValue(Matrix* mat){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("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/objects/Params/VectorParam.cpp
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/VectorParam.cpp	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/VectorParam.cpp	(revision 12822)
@@ -0,0 +1,121 @@
+/*!\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 <stdio.h>
+#include <string.h>
+#include "../objects.h"
+#include "../../EnumDefinitions/EnumDefinitions.h"
+#include "../../shared/shared.h"
+#include "../../Container/Container.h"
+#include "../../include/include.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* 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(){
+	xdelete(&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){
+
+	int i;
+	_printLine_("VectorParam:");
+	_printLine_("   enum: " << this->enum_type << " (" << EnumToStringx(this->enum_type) << ")");
+	value->Echo();
+}
+/*}}}*/
+/*FUNCTION VectorParam::Id{{{*/
+int    VectorParam::Id(void){ return -1; }
+/*}}}*/
+/*FUNCTION VectorParam::MyRank{{{*/
+int    VectorParam::MyRank(void){ 
+	extern int my_rank;
+	return my_rank; 
+}
+/*}}}*/
+/*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** poutput){
+	Vector*  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* vector){
+
+	/*avoid leak: */
+	xdelete(&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/objects/Params/VectorParam.h
===================================================================
--- /issm/trunk-jpl/src/c/classes/objects/Params/VectorParam.h	(revision 12822)
+++ /issm/trunk-jpl/src/c/classes/objects/Params/VectorParam.h	(revision 12822)
@@ -0,0 +1,79 @@
+/*! \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 "../../include/include.h"
+#include "../../shared/shared.h"
+/*}}}*/
+
+class VectorParam: public Param{
+
+	private: 
+		/*just hold 3 values for 3 vertices: */
+		int enum_type;
+		Vector* value;
+
+	public:
+		/*VectorParam constructors, destructors: {{{*/
+		VectorParam();
+		VectorParam(int enum_type,Vector* value);
+		~VectorParam();
+		/*}}}*/
+		/*Object virtual functions definitions:{{{ */
+		void  Echo();
+		void  DeepEcho();
+		int   Id(); 
+		int   MyRank();
+		int   ObjectEnum();
+		Object* copy();
+		/*}}}*/
+		/*Param vritual function definitions: {{{*/
+		int   InstanceEnum(){return enum_type;}
+		void  GetParameterValue(bool* pbool){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a bool");}
+		void  GetParameterValue(int* pinteger){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
+		void  GetParameterValue(int** pintarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(int** pintarray,int* pM,int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return an array of integers");}
+		void  GetParameterValue(IssmDouble* pIssmDouble){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble");}
+		void  GetParameterValue(IssmDouble* pdouble,IssmDouble time){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble for a given time");}
+		void  GetParameterValue(char** pstring){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string");}
+		void  GetParameterValue(char*** pstringarray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a string array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble** pIssmDoublearray,int* pM, int* pN){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a IssmDouble array");}
+		void  GetParameterValue(IssmDouble*** parray, int* pM,int** pmdims, int** pndims){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a matrix array");}
+		void  GetParameterValue(Matrix** pmat){_error2_("Param "<< EnumToStringx(enum_type) << " cannot return a Mat");}
+		void  GetParameterValue(Vector** poutput);
+		void  GetParameterValue(FILE** pfid){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot return a FILE");}
+
+		void  SetValue(bool boolean){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a boolean");}
+		void  SetValue(int integer){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold an integer");}
+		void  SetValue(IssmDouble scalar){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a scalar");}
+		void  SetValue(char* string){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a string");}
+		void  SetValue(char** stringarray,int M){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a string array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a IssmDouble array");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a IssmDouble array");}
+		void  SetValue(int* intarray,int M){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a int array");}
+		void  SetValue(int* pintarray,int M,int N){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a int array");}
+		void  SetValue(Vector* vec);
+		void  SetValue(Matrix* mat){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a Mat");}
+		void  SetValue(FILE* fid){_error2_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
+		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error2_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
+		void  UnitConversion(int direction_enum);
+
+		void GetParameterName(char**pname);
+
+		/*}}}*/
+};
+#endif  /* _VECTORPARAM_H */
Index: sm/trunk-jpl/src/c/objects/Gauss/GaussPenta.cpp
===================================================================
--- /issm/trunk-jpl/src/c/objects/Gauss/GaussPenta.cpp	(revision 12821)
+++ 	(revision )
@@ -1,406 +1,0 @@
-/*!\file GaussPenta.c
- * \brief: implementation of the GaussPenta object
- */
-
-/*Include files: {{{*/
-#include "./../objects.h"
-/*}}}*/
-
-/*GaussPenta constructors and destructors:*/
-/*FUNCTION GaussPenta::GaussPenta() {{{*/
-GaussPenta::GaussPenta(){
-
-	numgauss=-1;
-
-	weights=NULL;
-	coords1=NULL;
-	coords2=NULL;
-	coords3=NULL;
-	coords4=NULL;
-
-	weight=UNDEF;
-	coord1=UNDEF;
-	coord2=UNDEF;
-	coord3=UNDEF;
-	coord4=UNDEF;
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussPenta(int order_horiz,int order_vert) {{{*/
-GaussPenta::GaussPenta(int order_horiz,int order_vert){
-
-	/*Intermediaries*/
-	int     ighoriz,igvert;
-	int     numgauss_horiz;
-	int     numgauss_vert;
-	double *coords1_horiz = NULL;
-	double *coords2_horiz = NULL;
-	double *coords3_horiz = NULL;
-	double *weights_horiz  = NULL;
-	double *coords_vert = NULL;
-	double *weights_vert   = NULL;
-
-	/*Get gauss points*/
-	GaussLegendreTria(&numgauss_horiz,&coords1_horiz,&coords2_horiz,&coords3_horiz,&weights_horiz,order_horiz);
-	GaussLegendreLinear(&coords_vert,&weights_vert,order_vert);
-	numgauss_vert=order_vert;
-
-	/*Allocate GaussPenta fields*/
-	numgauss=numgauss_horiz*numgauss_vert;
-	coords1=xNew<double>(numgauss);
-	coords2=xNew<double>(numgauss);
-	coords3=xNew<double>(numgauss);
-	coords4=xNew<double>(numgauss);
-	weights=xNew<double>(numgauss);
-
-	/*Combine Horizontal and vertical points*/
-	for (ighoriz=0; ighoriz<numgauss_horiz; ighoriz++){
-		for (igvert=0; igvert<numgauss_vert; igvert++){
-			coords1[numgauss_vert*ighoriz+igvert]=coords1_horiz[ighoriz];
-			coords2[numgauss_vert*ighoriz+igvert]=coords2_horiz[ighoriz];
-			coords3[numgauss_vert*ighoriz+igvert]=coords3_horiz[ighoriz];
-			coords4[numgauss_vert*ighoriz+igvert]=coords_vert[igvert];
-			weights[numgauss_vert*ighoriz+igvert]=weights_horiz[ighoriz]*weights_vert[igvert];
-		}
-	}
-
-	/*Initialize static fields as undefinite*/
-	weight=UNDEF;
-	coord1=UNDEF;
-	coord2=UNDEF;
-	coord3=UNDEF;
-	coord4=UNDEF;
-
-	/*Clean up*/
-	xDelete<double>(coords1_horiz);
-	xDelete<double>(coords2_horiz);
-	xDelete<double>(coords3_horiz);
-	xDelete<double>(coords_vert);
-	xDelete<double>(weights_horiz);
-	xDelete<double>(weights_vert);
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussPenta(int index1, int index2, int order){{{*/
-GaussPenta::GaussPenta(int index1, int index2,int order){
-
-	/*Intermediaties*/
-	double *seg_coords  = NULL;
-	double *seg_weights = NULL;
-	int     i;
-
-	/*Get Segment gauss points*/
-	numgauss=order;
-	GaussLegendreLinear(&seg_coords,&seg_weights,numgauss);
-
-	/*Allocate GaussPenta fields*/
-	coords1=xNew<double>(numgauss);
-	coords2=xNew<double>(numgauss);
-	coords3=xNew<double>(numgauss);
-	coords4=xNew<double>(numgauss);
-	weights=xNew<double>(numgauss);
-
-	if(index1==0 && index2==3){
-		for(i=0;i<numgauss;i++) coords1[i]=1.0;
-		for(i=0;i<numgauss;i++) coords2[i]=0.0;
-		for(i=0;i<numgauss;i++) coords3[i]=0.0;
-		for(i=0;i<numgauss;i++) coords4[i]=seg_coords[i];
-		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
-	}
-	else if (index1==1 && index2==4){
-		for(i=0;i<numgauss;i++) coords1[i]=0.0;
-		for(i=0;i<numgauss;i++) coords2[i]=1.0;
-		for(i=0;i<numgauss;i++) coords3[i]=0.0;
-		for(i=0;i<numgauss;i++) coords4[i]=seg_coords[i];
-		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
-	}
-	else if (index1==2 && index2==5){
-		for(i=0;i<numgauss;i++) coords1[i]=0.0;
-		for(i=0;i<numgauss;i++) coords2[i]=0.0;
-		for(i=0;i<numgauss;i++) coords3[i]=1.0;
-		for(i=0;i<numgauss;i++) coords4[i]=seg_coords[i];
-		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
-	}
-	else{
-		_error2_("Penta not supported yet");
-	}
-
-	/*Initialize static fields as undefined*/
-	weight=UNDEF;
-	coord1=UNDEF;
-	coord2=UNDEF;
-	coord3=UNDEF;
-	coord4=UNDEF;
-
-	/*clean up*/
-	xDelete<double>(seg_coords);
-	xDelete<double>(seg_weights);
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussPenta(int index1, int index2, int index3, int order){{{*/
-GaussPenta::GaussPenta(int index1, int index2, int index3, int order){
-
-	/*Basal Tria*/
-	if(index1==0 && index2==1 && index3==2){
-
-		/*Get GaussTria*/
-		GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
-
-		/*compute z coordinate*/
-		coords4=xNew<double>(numgauss);
-		for(int i=0;i<numgauss;i++) coords4[i]=-1.0;
-	}
-	/*Upper surface Tria*/
-	else if(index1==3 && index2==4 && index3==5){
-
-		/*Get GaussTria*/
-		GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
-
-		/*compute z coordinate*/
-		coords4=xNew<double>(numgauss);
-		for(int i=0;i<numgauss;i++) coords4[i]=1.0;
-	}
-	else{
-		_error2_("Tria not supported yet");
-	}
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussPenta(int index1, int index2, int index3, int index4,int order_horiz,int order_vert){{{*/
-GaussPenta::GaussPenta(int index1, int index2, int index3, int index4,int order_horiz,int order_vert){
-
-	/*Intermediaties*/
-	double *seg_horiz_coords  = NULL;
-	double *seg_horiz_weights = NULL;
-	double *seg_vert_coords   = NULL;
-	double *seg_vert_weights  = NULL;
-	int     i,j;
-
-	/*get the gauss points using the product of two line rules*/
-	GaussLegendreLinear(&seg_horiz_coords,&seg_horiz_weights,order_horiz);
-	GaussLegendreLinear(&seg_vert_coords, &seg_vert_weights, order_vert);
-
-	/*Allocate GaussPenta fields*/
-	numgauss=order_horiz*order_vert;
-	coords1=xNew<double>(numgauss);
-	coords2=xNew<double>(numgauss);
-	coords3=xNew<double>(numgauss);
-	coords4=xNew<double>(numgauss);
-	weights=xNew<double>(numgauss);
-
-	/*Quads: get the gauss points using the product of two line rules  */
-	if(index1==0 && index2==1 && index3==4 && index4==3){
-		for(i=0;i<order_horiz;i++){
-			for(j=0;j<order_vert;j++){
-				coords1[i*order_vert+j]=  0.5*(1-seg_horiz_coords[i]);
-				coords2[i*order_vert+j]=1-0.5*(1-seg_horiz_coords[i]);
-				coords3[i*order_vert+j]=0.0;
-				coords4[i*order_vert+j]=seg_vert_coords[j];
-				weights[i*order_vert+j]=seg_horiz_weights[i]*seg_vert_weights[j];
-			}
-		}
-	}
-	else if(index1==1 && index2==2 && index3==5 && index4==4){
-		for(i=0;i<order_horiz;i++){
-			for(j=0;j<order_vert;j++){
-				coords1[i*order_vert+j]=0.0;
-				coords2[i*order_vert+j]=  0.5*(1-seg_horiz_coords[i]);
-				coords3[i*order_vert+j]=1-0.5*(1-seg_horiz_coords[i]);
-				coords4[i*order_vert+j]=seg_vert_coords[j];
-				weights[i*order_vert+j]=seg_horiz_weights[i]*seg_vert_weights[j];
-			}
-		}
-	}
-	else if(index1==2 && index2==0 && index3==3 && index4==5){
-		for(i=0;i<order_horiz;i++){
-			for(j=0;j<order_vert;j++){
-				coords1[i*order_vert+j]=1-0.5*(1-seg_horiz_coords[i]);
-				coords2[i*order_vert+j]=0.0;
-				coords3[i*order_vert+j]=  0.5*(1-seg_horiz_coords[i]);
-				coords4[i*order_vert+j]=seg_vert_coords[j];
-				weights[i*order_vert+j]=seg_horiz_weights[i]*seg_vert_weights[j];
-			}
-		}
-	}
-	else{
-		_error2_("Tria not supported yet (user provided indices " << index1 << " " << index2 << " " << index3 << " " << index4 << ")");
-	}
-
-	/*clean-up*/
-	xDelete<double>(seg_horiz_coords);
-	xDelete<double>(seg_horiz_weights);
-	xDelete<double>(seg_vert_coords);
-	xDelete<double>(seg_vert_weights);
-}
-/*}}}*/
-/*FUNCTION GaussPenta::~GaussPenta(){{{*/
-GaussPenta::~GaussPenta(){
-	xDelete<double>(weights);
-	xDelete<double>(coords1);
-	xDelete<double>(coords2);
-	xDelete<double>(coords3);
-	xDelete<double>(coords4);
-}
-/*}}}*/
-
-/*Methods*/
-/*FUNCTION GaussPenta::Echo{{{*/
-void GaussPenta::Echo(void){
-
-	_printLine_("GaussPenta:");
-	_printLine_("   numgauss: " << numgauss);
-
-	if (weights){
-	 _printString_("   weights = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << weights[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("weights = NULL");
-	if (coords1){
-	 _printString_("   coords1 = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords1[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("coords1 = NULL");
-	if (coords2){
-	 _printString_("   coords2 = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords2[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("coords2 = NULL");
-	if (coords3){
-	 _printString_("   coords3 = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords3[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("coords3 = NULL");
-	if (coords4){
-		_printString_("   coords4 = ["); 
-		for(int i=0;i<numgauss;i++) _printLine_(" " << coords4[i]);
-		_printLine_("]");
-	}
-	else _printLine_("coords4 = NULL");
-
-	_printLine_("   weight = " << weight);
-	_printLine_("   coord1 = " << coord1);
-	_printLine_("   coord2 = " << coord2);
-	_printLine_("   coord3 = " << coord3);
-	_printLine_("   coord4 = " << coord4);
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussCenter{{{*/
-void GaussPenta::GaussCenter(void){
-
-	/*update static arrays*/
-	coord1=ONETHIRD;
-	coord2=ONETHIRD;
-	coord3=ONETHIRD;
-	coord4=0.0;
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussPoint{{{*/
-void GaussPenta::GaussPoint(int ig){
-
-	/*Check input in debugging mode*/
-	 _assert_(ig>=0 && ig< numgauss);
-
-	 /*update static arrays*/
-	 weight=weights[ig];
-	 coord1=coords1[ig];
-	 coord2=coords2[ig];
-	 coord3=coords3[ig];
-	 coord4=coords4[ig];
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussVertex{{{*/
-void GaussPenta::GaussVertex(int iv){
-
-	/*in debugging mode: check that the default constructor has been called*/
-	_assert_(numgauss==-1);
-
-	/*update static arrays*/
-	switch(iv){
-		case 0:
-			coord1=1; coord2=0; coord3=0; coord4= -1;
-			break;
-		case 1:
-			coord1=0; coord2=1; coord3=0; coord4= -1;
-			break;
-		case 2:
-			coord1=0; coord2=0; coord3=1; coord4= -1;
-			break;
-		case 3:
-			coord1=1; coord2=0; coord3=0; coord4= +1;
-			break;
-		case 4:
-			coord1=0; coord2=1; coord3=0; coord4= +1;
-			break;
-		case 5:
-			coord1=0; coord2=0; coord3=1; coord4= +1;
-			break;
-		default:
-			_error2_("vertex index should be in [0 5]");
-
-	}
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::GaussFaceTria{{{*/
-void GaussPenta::GaussFaceTria(int index1, int index2, int index3, int order){
-
-	/*in debugging mode: check that the default constructor has been called*/
-	_assert_(numgauss==-1);
-
-	/*Basal Tria*/
-	if(index1==0 && index2==1 && index3==2){
-		GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
-		coords4=xNew<double>(numgauss);
-		for(int i=0;i<numgauss;i++) coords4[i]=-1.0;
-	}
-	else{
-		_error2_("Tria not supported yet");
-	}
-
-}
-/*}}}*/
-/*FUNCTION GaussPenta::begin{{{*/
-int GaussPenta::begin(void){
-
-	/*Check that this has been initialized*/
-	_assert_(numgauss>0);
-	_assert_(weights);
-	_assert_(coords1);
-	_assert_(coords2);
-	_assert_(coords3);
-	_assert_(coords4);
-
-	/*return first gauss index*/
-	return 0;
-}
-/*}}}*/
-/*FUNCTION GaussPenta::end{{{*/
-int GaussPenta::end(void){
-
-	/*Check that this has been initialized*/
-	_assert_(numgauss>0);
-	_assert_(weights);
-	_assert_(coords1);
-	_assert_(coords2);
-	_assert_(coords3);
-	_assert_(coords4);
-
-	/*return last gauss index +1*/
-	return numgauss;
-}
-/*}}}*/
-/*FUNCTION GaussPenta::SynchronizeGaussTria{{{*/
-void GaussPenta::SynchronizeGaussTria(GaussTria* gauss_tria){
-
-	gauss_tria->coord1=this->coord1;
-	gauss_tria->coord2=this->coord2;
-	gauss_tria->coord3=this->coord3;
-	gauss_tria->weight=UNDEF;
-}
-/*}}}*/
Index: sm/trunk-jpl/src/c/objects/Gauss/GaussPenta.h
===================================================================
--- /issm/trunk-jpl/src/c/objects/Gauss/GaussPenta.h	(revision 12821)
+++ 	(revision )
@@ -1,51 +1,0 @@
-/*!\file GaussPenta.h
- * \brief: header file for node object
- */
-
-#ifndef _GAUSSPENTA_H_
-#define _GAUSSPENTA_H_
-
-/*Headers:*/
-/*{{{*/
-#include "./../../shared/shared.h"
-class GaussTria;
-/*}}}*/
-
-class GaussPenta{
-
-	private:
-		int numgauss;
-		double* weights;
-		double* coords1;
-		double* coords2;
-		double* coords3;
-		double* coords4;
-
-	public:
-		double weight;
-		double coord1;
-		double coord2;
-		double coord3;
-		double coord4;
-		
-	public:
-
-		/*GaussPenta constructors, destructors*/
-		GaussPenta();
-		GaussPenta(int order_horiz,int order_vert);
-		GaussPenta(int index1, int index2,int order);
-		GaussPenta(int index1, int index2, int index3, int order);
-		GaussPenta(int index1, int index2, int index3, int index4,int order_horiz,int order_vert);
-		~GaussPenta();
-
-		/*Methods*/
-		int  begin(void);
-		int  end(void);
-		void Echo(void);
-		void GaussPoint(int ig);
-		void GaussVertex(int iv);
-		void GaussFaceTria(int index1, int index2, int index3, int order);
-		void GaussCenter(void);
-		void SynchronizeGaussTria(GaussTria* gauss_tria);
-};
-#endif
Index: sm/trunk-jpl/src/c/objects/Gauss/GaussTria.cpp
===================================================================
--- /issm/trunk-jpl/src/c/objects/Gauss/GaussTria.cpp	(revision 12821)
+++ 	(revision )
@@ -1,278 +1,0 @@
-/*!\file GaussTria.c
- * \brief: implementation of the GaussTria object
- */
-
-/*Include files: {{{*/
-#include "./../objects.h"
-/*}}}*/
-
-/*GaussTria constructors and destructors:*/
-/*FUNCTION GaussTria::GaussTria() {{{*/
-GaussTria::GaussTria(){
-
-	numgauss=-1;
-
-	weights=NULL;
-	coords1=NULL;
-	coords2=NULL;
-	coords3=NULL;
-
-	weight=UNDEF;
-	coord1=UNDEF;
-	coord2=UNDEF;
-	coord3=UNDEF;
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussTria(int order) {{{*/
-GaussTria::GaussTria(int order){
-
-	/*Get gauss points*/
-	GaussLegendreTria(&numgauss,&coords1,&coords2,&coords3,&weights,order);
-
-	/*Initialize static fields as undefinite*/
-	weight=UNDEF;
-	coord1=UNDEF;
-	coord2=UNDEF;
-	coord3=UNDEF;
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussTria(int index1,int index2,int order) {{{*/
-GaussTria::GaussTria(int index1,int index2,int order){
-
-	/*Intermediaties*/
-	IssmPDouble *seg_coords  = NULL;
-	IssmPDouble *seg_weights = NULL;
-	int     i,index3;
-
-	/*Get Segment gauss points*/
-	numgauss=order;
-	GaussLegendreLinear(&seg_coords,&seg_weights,numgauss);
-
-	/*Allocate GaussTria fields*/
-	coords1=xNew<IssmPDouble>(numgauss);
-	coords2=xNew<IssmPDouble>(numgauss);
-	coords3=xNew<IssmPDouble>(numgauss);
-	weights=xNew<IssmPDouble>(numgauss);
-
-	/*Reverse index1 and 2 if necessary*/
-	if (index1>index2){
-		index3=index1; index1=index2; index2=index3;
-		for(i=0;i<numgauss;i++) seg_coords[i]=-seg_coords[i];
-	}
-
-	/*Build Triangle Gauss point*/
-	if (index1==0 && index2==1){
-		for(i=0;i<numgauss;i++) coords1[i]=  0.5*(1-seg_coords[i]);
-		for(i=0;i<numgauss;i++) coords2[i]=1-0.5*(1.-seg_coords[i]);
-		for(i=0;i<numgauss;i++) coords3[i]=0;
-		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
-	}
-	else if (index1==0 && index2==2){
-		for(i=0;i<numgauss;i++) coords1[i]=  0.5*(1-seg_coords[i]);
-		for(i=0;i<numgauss;i++) coords2[i]= 0 ;
-		for(i=0;i<numgauss;i++) coords3[i]=1-0.5*(1.-seg_coords[i]);
-		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
-	}
-	else if (index1==1 && index2==2){
-		for(i=0;i<numgauss;i++) coords1[i]=0;
-		for(i=0;i<numgauss;i++) coords2[i]=  0.5*(1-seg_coords[i]);
-		for(i=0;i<numgauss;i++) coords3[i]=1-0.5*(1.-seg_coords[i]);
-		for(i=0;i<numgauss;i++) weights[i]=seg_weights[i];
-	}
-	else
-	 _error2_("The 2 indices provided are not supported yet (user provided " << index1 << " and " << index2 << ")");
-
-	/*Initialize static fields as undefined*/
-	weight=UNDEF;
-	coord1=UNDEF;
-	coord2=UNDEF;
-	coord3=UNDEF;
-
-	/*clean up*/
-	xDelete<double>(seg_coords);
-	xDelete<double>(seg_weights);
-}
-/*}}}*/
-/*FUNCTION GaussTria::~GaussTria(){{{*/
-GaussTria::~GaussTria(){
-	xDelete<IssmPDouble>(weights);
-	xDelete<IssmPDouble>(coords1);
-	xDelete<IssmPDouble>(coords2);
-	xDelete<IssmPDouble>(coords3);
-}
-/*}}}*/
-
-/*Methods*/
-/*FUNCTION GaussTria::Echo{{{*/
-void GaussTria::Echo(void){
-
-	_printLine_("GaussTria:");
-	_printLine_("   numgauss: " << numgauss);
-
-	if (weights){
-	 _printString_("   weights = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << weights[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("weights = NULL");
-	if (coords1){
-	 _printString_("   coords1 = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords1[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("coords1 = NULL");
-	if (coords2){
-	 _printString_("   coords2 = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords2[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("coords2 = NULL");
-	if (coords3){
-	 _printString_("   coords3 = ["); 
-	 for(int i=0;i<numgauss;i++) _printLine_(" " << coords3[i]);
-	 _printLine_("]");
-	}
-	else _printLine_("coords3 = NULL");
-
-	_printLine_("   weight = " << weight);
-	_printLine_("   coord1 = " << coord1);
-	_printLine_("   coord2 = " << coord2);
-	_printLine_("   coord3 = " << coord3);
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussCenter{{{*/
-void GaussTria::GaussCenter(void){
-
-	/*update static arrays*/
-	coord1=ONETHIRD;
-	coord2=ONETHIRD;
-	coord3=ONETHIRD;
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussEdgeCenter{{{*/
-void GaussTria::GaussEdgeCenter(int index1,int index2){
-
-	int     index3;
-
-	/*Reverse index1 and 2 if necessary*/
-	if (index1>index2){
-		index3=index1; index1=index2; index2=index3;
-	}
-
-	/*update static arrays*/
-	if (index1==0 && index2==1){
-		coord1=0.5;
-		coord2=0.5;
-		coord3=0.0;
-	}
-	else if (index1==0 && index2==2){
-		coord1=0.5;
-		coord2=0.0;
-		coord3=0.5;
-	}
-	else if (index1==1 && index2==2){
-		coord1=0.0;
-		coord2=0.5;
-		coord3=0.5;
-	}
-	else
-	 _error2_("The 2 indices provided are not supported yet (user provided " << index1 << " and " << index2 << ")");
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussPoint{{{*/
-void GaussTria::GaussPoint(int ig){
-
-	/*Check input in debugging mode*/
-	 _assert_(ig>=0 && ig< numgauss);
-
-	 /*update static arrays*/
-	 weight=weights[ig];
-	 coord1=coords1[ig];
-	 coord2=coords2[ig];
-	 coord3=coords3[ig];
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussFromCoords{{{*/
-void GaussTria::GaussFromCoords(IssmPDouble x,IssmPDouble y,IssmPDouble* xyz_list){
-
-	/*Intermediaries*/
-	IssmPDouble    area = 0;
-	IssmPDouble    x1,y1,x2,y2,x3,y3;
-
-	/*in debugging mode: check that the default constructor has been called*/
-	_assert_(numgauss==-1);
-
-	x1=*(xyz_list+3*0+0); y1=*(xyz_list+3*0+1);
-	x2=*(xyz_list+3*1+0); y2=*(xyz_list+3*1+1);
-	x3=*(xyz_list+3*2+0); y3=*(xyz_list+3*2+1);
-
-	area=(x2*y3 - y2*x3 + x1*y2 - y1*x2 + x3*y1 - y3*x1)/2;
-
-	/*Get first area coordinate = det(x-x3  x2-x3 ; y-y3   y2-y3)/area*/
-	coord1=((x-x3)*(y2-y3)-(x2-x3)*(y-y3))/area;
-
-	/*Get second area coordinate = det(x1-x3  x-x3 ; y1-y3   y-y3)/area*/
-	coord2=((x1-x3)*(y-y3)-(x-x3)*(y1-y3))/area;
-
-	/*Get third  area coordinate 1-area1-area2: */
-	coord3=1-coord1-coord2;
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::GaussVertex{{{*/
-void GaussTria::GaussVertex(int iv){
-
-	/*in debugging mode: check that the default constructor has been called*/
-	_assert_(numgauss==-1);
-
-	/*update static arrays*/
-	switch(iv){
-		case 0:
-			coord1=1; coord2=0; coord3=0;
-			break;
-		case 1:
-			coord1=0; coord2=1; coord3=0;
-			break;
-		case 2:
-			coord1=0; coord2=0; coord3=1;
-			break;
-		default:
-			_error2_("vertex index should be in [0 2]");
-
-	}
-
-}
-/*}}}*/
-/*FUNCTION GaussTria::begin{{{*/
-int GaussTria::begin(void){
-
-	/*Check that this has been initialized*/
-	_assert_(numgauss>0);
-	_assert_(weights);
-	_assert_(coords1);
-	_assert_(coords2);
-	_assert_(coords3);
-
-	/*return first gauss index*/
-	return 0;
-}
-/*}}}*/
-/*FUNCTION GaussTria::end{{{*/
-int GaussTria::end(void){
-
-	/*Check that this has been initialized*/
-	_assert_(numgauss>0);
-	_assert_(weights);
-	_assert_(coords1);
-	_assert_(coords2);
-	_assert_(coords3);
-
-	/*return last gauss index +1*/
-	return numgauss;
-}
-/*}}}*/
Index: sm/trunk-jpl/src/c/objects/Gauss/GaussTria.h
===================================================================
--- /issm/trunk-jpl/src/c/objects/Gauss/GaussTria.h	(revision 12821)
+++ 	(revision )
@@ -1,46 +1,0 @@
-/*!\file GaussTria.h
- * \brief: header file for node object
- */
-
-#ifndef _GAUSSTRIA_H_
-#define _GAUSSTRIA_H_
-
-/*Headers:*/
-/*{{{*/
-#include "./../../shared/shared.h"
-/*}}}*/
-
-class GaussTria{
-
-	private:
-		int numgauss;
-		IssmPDouble* weights;
-		IssmPDouble* coords1;
-		IssmPDouble* coords2;
-		IssmPDouble* coords3;
-
-	public:
-		IssmPDouble weight;
-		IssmPDouble coord1;
-		IssmPDouble coord2;
-		IssmPDouble coord3;
-		
-	public:
-
-		/*GaussTria constructors, destructors*/
-		GaussTria();
-		GaussTria(int order);
-		GaussTria(int index1,int index2,int order);
-		~GaussTria();
-
-		/*Methods*/
-		int  begin(void);
-		int  end(void);
-		void Echo(void);
-		void GaussFromCoords(IssmPDouble x1,IssmPDouble y1,IssmPDouble* xyz_list);
-		void GaussPoint(int ig);
-		void GaussVertex(int iv);
-		void GaussCenter(void);
-		void GaussEdgeCenter(int index1,int index2);
-};
-#endif  /* _GAUSSTRIA_H_ */
Index: sm/trunk-jpl/src/c/objects/IoModel.cpp
===================================================================
--- /issm/trunk-jpl/src/c/objects/IoModel.cpp	(revision 12821)
+++ 	(revision )
@@ -1,1250 +1,0 @@
-/*! \file IoModel.cpp
- * \brief  file containing the methods that will help in processing the input data coming 
- * into ISSM, from Matlab, or through a binary file opened for reading.
- */
-
-#ifdef HAVE_CONFIG_H
-	#include <config.h>
-#else
-#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
-#endif
-
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "./objects.h"
-#include "../io/io.h"
-#include "./Container/Parameters.h"
-#include "../shared/shared.h"
-#include "../io/io.h"
-#include "../include/include.h"
-
-/*FUNCTION IoModel::IoModel(){{{*/
-IoModel::IoModel(){
-	this->fid=NULL;
-	this->data=NULL;
-	this->constants=NULL;
-	
-	this->my_elements=NULL;
-	this->my_nodes=NULL;
-	this->my_vertices=NULL;
-	this->singlenodetoelementconnectivity=NULL;
-	this->numbernodetoelementconnectivity=NULL;
-	
-	this->nodecounter=0;
-	this->loadcounter=0;
-	this->constraintcounter=0;
-}
-/*}}}*/
-/*FUNCTION IoModel::IoModel(FILE*  iomodel_handle){{{*/
-IoModel::IoModel(FILE* iomodel_handle){
-	
-	/*First, keep track of the file handle: */
-	this->fid=iomodel_handle;
-
-	/*Check that Enums are Synchronized*/
-	this->CheckEnumSync();
-
-	/*Initialize and read constants:*/
-	this->constants=new Parameters();
-	this->FetchConstants(); /*this routine goes through the input file, and fetches bools, ints, IssmDoubles and strings only, nothing memory intensive*/
-
-	/*Initialize data: */
-	this->data=xNew<IssmDouble*>(MaximumNumberOfEnums);
-	for(int i=0;i<MaximumNumberOfEnums;i++) this->data[i]=NULL;
-	
-	/*Initialize permanent data: */
-	this->my_elements=NULL;
-	this->my_nodes=NULL;
-	this->my_vertices=NULL;
-	this->singlenodetoelementconnectivity=NULL;
-	this->numbernodetoelementconnectivity=NULL;
-	
-	this->nodecounter=0;
-	this->loadcounter=0;
-	this->constraintcounter=0;
-}
-/*}}}*/
-/*FUNCTION IoModel::~IoModel(){{{*/
-IoModel::~IoModel(){
-
-	if(this->constants) delete this->constants;
-
-	/*Some checks in debugging mode*/
-	#ifdef _ISSM_DEBUG_
-	if(this->data){
-		for(int i=0;i<MaximumNumberOfEnums;i++){
-			if(this->data[i]){
-				_pprintLine_("Info: previous pointer of " << EnumToStringx(i) << " has not been freed (DeleteData has not been called)");
-			}
-		}
-	}
-	#endif
-
-	xDelete<IssmDouble*>(this->data);
-	xDelete<bool>(this->my_elements);
-	xDelete<bool>(this->my_nodes);
-	xDelete<int>(this->my_vertices);
-	xDelete<int>(this->singlenodetoelementconnectivity);
-	xDelete<int>(this->numbernodetoelementconnectivity);
-}
-/*}}}*/
-
-/*FUNCTION IoModel::CheckEnumSync{{{*/
-void  IoModel::CheckEnumSync(void){
-
-	extern int my_rank;
-	int record_enum = 0;
-
-	/*Check that some fields have been allocated*/
-	_assert_(this->fid || my_rank);
-
-	/*Go find in the binary file, the position of the data we want to fetch: */
-	if(my_rank==0){ //cpu 0
-
-		/*First set FILE* position to the beginning of the file: */
-		fseek(this->fid,0,SEEK_SET);
-
-		/*Get first Enum*/
-		if(fread(&record_enum,sizeof(int),1,this->fid)==0){
-			_error2_("Marshalled file is empty");
-		}
-		else{
-			if(record_enum!=MaximumNumberOfEnums){
-				_printLine_("");
-				_printLine_("=========================================================================");
-				_printLine_(" Enums in marshalled file are not compatible with compiled code          ");
-				_printLine_("                                                                         ");
-				_printLine_("   * If you are running ISSM on a remote cluster:                        ");
-				_printLine_("     make sure that you are using the same version of ISSM on your local ");
-				_printLine_("     machine and remote cluster (you might need to run svn update)       ");
-				_printLine_("   * If you are running ISSM on your local machine:                      ");
-				_printLine_("     make sure that all the code is compiled (modules and executables)   ");
-				_printLine_("   * If you are a developer and just added a new Enum:                   ");
-				_printLine_("     you might need to run ./Synchronize.sh in src/c/EnumDefinitions     ");
-				_printLine_("     and recompile                                                       ");
-				_printLine_("=========================================================================");
-				_printLine_("");
-				_error2_("Enums not consistent (See error message above)");
-			}
-		}
-	}
-}
-/*}}}*/
-/*FUNCTION IoModel::Constant(bool* poutput,int constant_enum){{{*/
-void IoModel::Constant(bool* poutput,int constant_enum){
-
-	_assert_(constant_enum>=0);
-	_assert_(this->constants);
-
-	this->constants->FindParam(poutput,constant_enum);
-}
-/*}}}*/
-/*FUNCTION IoModel::Constant(int* poutput,int constant_enum){{{*/
-void IoModel::Constant(int* poutput,int constant_enum){
-
-	_assert_(constant_enum>=0);
-	_assert_(this->constants);
-
-	this->constants->FindParam(poutput,constant_enum);
-}
-/*}}}*/
-/*FUNCTION IoModel::Constant(IssmDouble* poutput,int constant_enum){{{*/
-void IoModel::Constant(IssmDouble* poutput,int constant_enum){
-
-	_assert_(constant_enum>=0);
-	_assert_(this->constants);
-
-	this->constants->FindParam(poutput,constant_enum);
-}
-/*}}}*/
-/*FUNCTION IoModel::Constant(char** poutput,int constant_enum){{{*/
-void IoModel::Constant(char** poutput,int constant_enum){
-
-	_assert_(constant_enum>=0);
-	_assert_(this->constants);
-
-	this->constants->FindParam(poutput,constant_enum);
-}
-/*}}}*/
-/*FUNCTION IoModel::CopyConstantObject{{{*/
-Param* IoModel::CopyConstantObject(int constant_enum){
-
-	_assert_(this->constants);
-
-	/*Find constant*/
-	Param* param=(Param*)this->constants->FindParamObject(constant_enum);
-	if(!param) _error2_("Constant " << EnumToStringx(constant_enum) << " not found in iomodel");
-
-	return (Param*)param->copy();
-}
-/*}}}*/
-/*FUNCTION IoModel::Data{{{*/
-IssmDouble* IoModel::Data(int data_enum){
-
-	_assert_(data_enum<MaximumNumberOfEnums);
-	_assert_(data_enum>=0);
-
-	return this->data[data_enum];
-}
-/*}}}*/
-/*FUNCTION IoModel::DeleteData{{{*/
-void  IoModel::DeleteData(int num,...){
-
-	va_list ap;
-	int     dataenum;
-	int     i;
-	DoubleMatParam* parameter=NULL;
-
-	/*Go through the entire list of enums and delete the corresponding data from the iomodel-data dataset: */
-
-	va_start(ap,num);
-	for(i = 0; i <num; i++){
-		dataenum=va_arg(ap, int);
-		_assert_(dataenum<MaximumNumberOfEnums);
-		xDelete<IssmDouble>(this->data[dataenum]);
-	}
-	va_end(ap);
-} /*}}}*/
-/*FUNCTION IoModel::FetchConstants{{{*/
-void  IoModel::FetchConstants(void){
-
-	extern int my_rank;
-	extern int num_procs;
-	
-	/*record descriptions; */
-	int record_enum;
-	int record_length;
-	int record_code; //1 to 7 number
-
-	/*records: */
-	int  booleanint=0;
-	int  integer=0;
-	IssmPDouble scalar=0;
-	char* string=NULL;
-	int   string_size;
-
-	/*Check that some fields have been allocated*/
-	_assert_(this->fid || my_rank);
-	_assert_(this->constants);
-
-	/*Go find in the binary file, the position of the data we want to fetch: */
-	if(my_rank==0){ //cpu 0{{{
-	
-		/*First set FILE* position to the beginning of the file: */
-		fseek(this->fid,0,SEEK_SET);
-
-		/*Now march through file looking for the correct data identifiers (bool,int,IssmDouble or string): */
-		for(;;){
-			if(fread(&record_enum,sizeof(int),1,this->fid)==0){
-
-				/*Ok, we have reached the end of the file. break: */
-				record_code=0; //0 means bailout
-				#ifdef _HAVE_MPI_
-				MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD);  /*tell others cpus we are bailing: */
-				#endif
-				break;
-			}
-			else{
-			
-				/* Read the record length and the data type code: */
-				fread(&record_length,sizeof(int),1,this->fid);
-				fread(&record_code,sizeof(int),1,this->fid);
-					
-				#ifdef _HAVE_MPI_
-				/*Tell other cpus what we are doing: */
-				MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD);  /*tell other cpus what we are going to do: */
-
-				/*Tell other cpus the name of the data, then branch according to the data type: */
-				MPI_Bcast(&record_enum,1,MPI_INT,0,MPI_COMM_WORLD);  
-				MPI_Bcast(&record_length,1,MPI_INT,0,MPI_COMM_WORLD);  
-				#endif
-				
-				switch(record_code){
-					case 1: 
-						/*Read the boolean and broadcast it to other cpus:*/
-						if(fread(&booleanint,sizeof(int),1,this->fid)!=1) _error2_("could not read boolean ");
-						#ifdef _HAVE_MPI_
-						MPI_Bcast(&booleanint,1,MPI_INT,0,MPI_COMM_WORLD); 
-						#endif
-
-						/*create BoolParam: */
-						this->constants->AddObject(new BoolParam(record_enum,(bool)booleanint)); //cast to boolean
-
-						break;
-					case 2:
-						/*Read the integer and broadcast it to other cpus:*/
-						if(fread(&integer,sizeof(int),1,this->fid)!=1) _error2_("could not read integer ");
-						#ifdef _HAVE_MPI_
-						MPI_Bcast(&integer,1,MPI_INT,0,MPI_COMM_WORLD); 
-						#endif
-
-						/*create IntParam: */
-						this->constants->AddObject(new IntParam(record_enum,integer));
-
-						break;
-					case 3:
-						/*Read the scalar and broadcast it to other cpus:*/
-						if(fread(&scalar,sizeof(IssmPDouble),1,this->fid)!=1) _error2_("could not read scalar ");
-						#ifdef _HAVE_MPI_
-						MPI_Bcast(&scalar,1,MPI_DOUBLE,0,MPI_COMM_WORLD); 
-						#endif
-
-						/*create DoubleParam: */
-						this->constants->AddObject(new DoubleParam(record_enum,scalar));
-
-						break;
-					case 4: 
-						/*We have to read a string from disk. First read the dimensions of the string, then the string: */
-						if(fread(&string_size,sizeof(int),1,this->fid)!=1) _error2_("could not read length of string ");
-						#ifdef _HAVE_MPI_
-						MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
-						#endif
-
-						if(string_size){
-							string=xNew<char>(string_size+1);
-							string[string_size]='\0';
-
-							/*Read string, then broadcast: */
-							if(fread(string,string_size*sizeof(char),1,this->fid)!=1)_error2_(" could not read string ");
-							#ifdef _HAVE_MPI_
-							MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
-							#endif
-						}
-						else{
-							string=xNew<char>(1);
-							string[0]='\0';
-						}
-						
-						/*Add string to parameters: */
-						this->constants->AddObject(new StringParam(record_enum,string));
-
-						/*Free string*/
-						xDelete<char>(string);
-
-						break;
-					case 5: 
-							/*We are not interested in this record, too memory intensive. Skip it: */
-							/*skip: */
-							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
-							fseek(fid,record_length,SEEK_CUR);
-							break;
-					case 6: 
-							/*We are not interested in this record, too memory intensive. Skip it: */
-							/*skip: */
-							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
-							fseek(fid,record_length,SEEK_CUR);
-							break;
-					case 7: 
-							/*We are not interested in this record, too memory intensive. Skip it: */
-							/*skip: */
-							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
-							fseek(fid,record_length,SEEK_CUR);
-							break;
-
-					case 8: 
-							/*We are not interested in this record, too memory intensive. Skip it: */
-							/*skip: */
-							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
-							fseek(fid,record_length,SEEK_CUR);
-							break;
-
-					case 9: 
-							/*We are not interested in this record, too memory intensive. Skip it: */
-							/*skip: */
-							fseek(fid,-sizeof(int),SEEK_CUR); //backtrak 1 integer
-							fseek(fid,record_length,SEEK_CUR);
-							break;
-
-					default: 
-						_error2_("unknown record type:" << record_code); 
-						break;;
-				}
-			}
-		}
-	} //}}}
-	#ifdef _HAVE_MPI_
-	else{ //cpu ~0 {{{
-		for(;;){ //wait on cpu 0
-			MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD);  /*get from cpu 0 what we are going to do: */
-			if(record_code==0){
-				break; //we are done, break from the loop
-			}
-			else{
-				MPI_Bcast(&record_enum,1,MPI_INT,0,MPI_COMM_WORLD);   //get from cpu 0 name of the data
-				MPI_Bcast(&record_length,1,MPI_INT,0,MPI_COMM_WORLD);  
-				switch(record_code){
-				case 1: 
-					/*boolean. get it from cpu 0 */
-					MPI_Bcast(&booleanint,1,MPI_INT,0,MPI_COMM_WORLD); 
-						
-					/*create BoolParam: */
-					this->constants->AddObject(new BoolParam(record_enum,(bool)booleanint)); //cast to a boolean
-					break;
-
-				case 2:
-					/*integer. get it from cpu 0 */
-					MPI_Bcast(&integer,1,MPI_INT,0,MPI_COMM_WORLD); 
-						
-					/*create IntParam: */
-					this->constants->AddObject(new IntParam(record_enum,integer));
-
-					break;
-				case 3:
-					/*scalar. get it from cpu 0 */
-					MPI_Bcast(&scalar,1,MPI_DOUBLE,0,MPI_COMM_WORLD); 
-						
-					/*create DoubleParam: */
-					this->constants->AddObject(new DoubleParam(record_enum,scalar));
-
-					break;
-				case 4: 
-					MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
-					if(string_size){
-						string=xNew<char>((string_size+1));
-						string[string_size]='\0';
-
-						/*Read string from cpu 0: */
-						MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
-					}
-					else{
-						string=xNew<char>(1);
-						string[0]='\0';
-					}
-					/*Add string to parameters: */
-					this->constants->AddObject(new StringParam(record_enum,string));
-
-					/*Free string*/
-					xDelete<char>(string);
-
-					break;
-				case 5: break; //do nothing. not interested in this type of data, which is memory intensive.
-				case 6: break; //do nothing. not interested in this type of data, which is memory intensive.
-				case 7: break; //do nothing. not interested in this type of data, which is memory intensive.
-				case 8: break; //do nothing. not interested in this type of data, which is memory intensive.
-				case 9: break; //do nothing. not interested in this type of data, which is memory intensive.
-
-				default: 
-					_error2_("unknown record type:" << record_code); 
-					break;;
-				}
-
-
-			}
-		}
-	} //}}}
-	#endif
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(bool*     pbool,int data_enum){{{*/
-void  IoModel::FetchData(bool* pboolean,int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-	
-
-	/*output: */
-	int   booleanint;
-	int   code;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,NULL,data_enum);
-
-	if(code!=1)_error2_("expecting a boolean for enum " << EnumToStringx(data_enum));
-	
-	/*We have to read a boolean from disk. */
-	if(my_rank==0){  
-		if(fread(&booleanint,sizeof(int),1,fid)!=1) _error2_("could not read boolean ");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&booleanint,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	/*cast to bool: */
-	/*Assign output pointers: */
-	*pboolean=(bool)booleanint;
-
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(int*      pinteger,int data_enum){{{*/
-void  IoModel::FetchData(int* pinteger,int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-
-	/*output: */
-	int   integer;
-	int   code;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,NULL,data_enum);
-	
-	if(code!=2)_error2_("expecting an integer for enum " << EnumToStringx(data_enum));
-	
-	/*We have to read a integer from disk. First read the dimensions of the integer, then the integer: */
-	if(my_rank==0){  
-		if(fread(&integer,sizeof(int),1,fid)!=1) _error2_("could not read integer ");
-	}
-
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&integer,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	/*Assign output pointers: */
-	*pinteger=integer;
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(IssmDouble*   pscalar,int data_enum){{{*/
-void  IoModel::FetchData(IssmDouble* pscalar,int data_enum){
-
-
-	extern int my_rank;
-	extern int num_procs;
-	
-
-	/*output: */
-	IssmPDouble   scalar;
-	int      code;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,NULL,data_enum);
-	
-	if(code!=3)_error2_("expecting a IssmDouble for enum " << EnumToStringx(data_enum));
-	
-	/*We have to read a scalar from disk. First read the dimensions of the scalar, then the scalar: */
-	if(my_rank==0){
-		if(fread(&scalar,sizeof(IssmPDouble),1,fid)!=1)_error2_("could not read scalar ");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&scalar,1,MPI_DOUBLE,0,MPI_COMM_WORLD); 
-	#endif
-
-	/*Assign output pointers: */
-	*pscalar=scalar;
-		 
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(char**    pstring,int data_enum){{{*/
-void  IoModel::FetchData(char** pstring,int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-	
-
-	/*output: */
-	char* string=NULL;
-	int   string_size;
-	int code=0;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,NULL,data_enum);
-	
-	if(code!=4)_error2_("expecting a string for enum " << EnumToStringx(data_enum));
-	
-	/*Now fetch: */
-	
-	/*We have to read a string from disk. First read the dimensions of the string, then the string: */
-	if(my_rank==0){  
-		if(fread(&string_size,sizeof(int),1,fid)!=1) _error2_("could not read length of string ");
-	}
-
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	/*Now allocate string: */
-	if(string_size){
-		string=xNew<char>((string_size+1));
-		string[string_size]='\0';
-
-		/*Read string on node 0, then broadcast: */
-		if(my_rank==0){  
-			if(fread(string,string_size*sizeof(char),1,fid)!=1)_error2_(" could not read string ");
-		}
-		#ifdef _HAVE_MPI_
-		MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
-		#endif
-	}
-	else{
-		string=xNew<char>(1);
-		string[0]='\0';
-	}
-
-
-	/*Assign output pointers: */
-	*pstring=string;
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(int**     pintegerematrix,int* pM,int* pN,int data_enum){{{*/
-void  IoModel::FetchData(int** pmatrix,int* pM,int* pN,int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-	int i,j;
-
-	/*output: */
-	int M,N;
-	IssmPDouble* matrix=NULL;
-	int*    integer_matrix=NULL;
-	int code=0;
-	int vector_type=0;
-	
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,&vector_type,data_enum);
-
-	if((code!=5) && (code!=6) && (code!=7))_error2_("expecting a IssmDouble, integer or boolean matrix for enum " << EnumToStringx(data_enum));
-	
-	/*Now fetch: */
-
-	/*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) _error2_("could not read number of rows for matrix ");
-	}
-
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&M,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	if(my_rank==0){  
-		if(fread(&N,sizeof(int),1,fid)!=1) _error2_("could not read number of columns for matrix ");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD);
-	#endif
-
-	/*Now allocate matrix: */
-	if(M*N){
-		matrix=xNew<IssmPDouble>(M*N);
-
-		/*Read matrix on node 0, then broadcast: */
-		if(my_rank==0){  
-			if(fread(matrix,M*N*sizeof(IssmPDouble),1,fid)!=1) _error2_("could not read matrix ");
-		}
-		
-		#ifdef _HAVE_MPI_
-		MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,MPI_COMM_WORLD); 
-		#endif
-	}
-
-	/*Now cast to integer: */
-	if(M*N){
-		integer_matrix=xNew<int>(M*N);
-		for (i=0;i<M;i++){
-			for (j=0;j<N;j++){
-				integer_matrix[i*N+j]=(int)matrix[i*N+j];
-			}
-		}
-	}
-	else{
-		integer_matrix=NULL;
-	}
-	/*Free ressources:*/
-	xDelete<IssmPDouble>(matrix);
-
-	/*Assign output pointers: */
-	*pmatrix=integer_matrix;
-	if (pM)*pM=M;
-	if (pN)*pN=N;
-
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(IssmDouble**  pIssmDoublematrix,int* pM,int* pN,int data_enum){{{*/
-void  IoModel::FetchData(IssmDouble** pmatrix,int* pM,int* pN,int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-
-	/*output: */
-	int M,N;
-	IssmPDouble* matrix=NULL;
-	int code=0;
-	int vector_type=0;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,&vector_type,data_enum);
-	if((code!=5) && (code!=6) && (code!=7))_error2_("expecting a IssmDouble, integer or boolean matrix for enum " << EnumToStringx(data_enum));
-	
-	/*Now fetch: */
-
-	/*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) _error2_("could not read number of rows for matrix ");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&M,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	if(my_rank==0){  
-		if(fread(&N,sizeof(int),1,fid)!=1) _error2_("could not read number of columns for matrix ");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	/*Now allocate matrix: */
-	if(M*N){
-		matrix=xNew<IssmPDouble>(M*N);
-
-		/*Read matrix on node 0, then broadcast: */
-		if(my_rank==0){  
-			if(fread(matrix,M*N*sizeof(IssmPDouble),1,fid)!=1) _error2_("could not read matrix ");
-		}
-		#ifdef _HAVE_MPI_
-		MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,MPI_COMM_WORLD); 
-		#endif
-	        *pmatrix=xNew<IssmDouble>(M*N);
-	        for (int i=0;i<M*N;++i) (*pmatrix)[i]=matrix[i];
-	        xDelete<IssmPDouble>(matrix);
-	}
-	else
-	  *pmatrix=NULL;
-	/*Assign output pointers: */
-	if (pM)*pM=M;
-	if (pN)*pN=N;
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(char***   pstrings,int* pnumstrings,int data_enum){{{*/
-void  IoModel::FetchData(char*** pstrings,int* pnumstrings,int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-	
-	int i;
-
-	/*output: */
-	int   numstrings=0;
-	char** strings=NULL;
-	
-	/*intermediary: */
-	char* string=NULL;
-	int   string_size;
-	int   code;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,NULL,data_enum);
-	
-	if(code!=9)_error2_("expecting a string array for enum " << EnumToStringx(data_enum));
-	
-	/*We have to read a bunch of strings from disk. First read the number of strings, and allocate: */
-	if(my_rank==0){  
-		if(fread(&numstrings,sizeof(int),1,fid)!=1) _error2_("could not read length of string array");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&numstrings,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	/*Now allocate string array: */
-	if(numstrings){
-		strings=xNew<char*>(numstrings);
-		for(i=0;i<numstrings;i++)strings[i]=NULL;
-
-		/*Go through strings, and read: */
-		for(i=0;i<numstrings;i++){
-			
-			if(my_rank==0){  
-				if(fread(&string_size,sizeof(int),1,fid)!=1) _error2_("could not read length of string ");
-			}
-			#ifdef _HAVE_MPI_
-			MPI_Bcast(&string_size,1,MPI_INT,0,MPI_COMM_WORLD); 
-			#endif
-			if(string_size){
-				string=xNew<char>((string_size+1));
-				string[string_size]='\0';
-
-				/*Read string on node 0, then broadcast: */
-				if(my_rank==0){  
-					if(fread(string,string_size*sizeof(char),1,fid)!=1)_error2_(" could not read string ");
-				}
-				#ifdef _HAVE_MPI_
-				MPI_Bcast(string,string_size,MPI_CHAR,0,MPI_COMM_WORLD); 
-				#endif
-			}
-			else{
-				string=xNew<char>(1);
-				string[0]='\0';
-			}
-
-			strings[i]=string;
-		}
-	}
-
-	/*Assign output pointers: */
-	*pstrings=strings;
-	*pnumstrings=numstrings;
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(IssmDouble*** pmatrices,int** pmdims,int** pndims, int* pM,int data_enum){{{*/
-void  IoModel::FetchData(IssmDouble*** pmatrices,int** pmdims,int** pndims, int* pnumrecords,int data_enum){
-
-	int i;
-
-	extern int my_rank;
-	extern int num_procs;
-
-	/*output: */
-	IssmDouble** matrices=NULL;
-	int*     mdims=NULL;
-	int*     ndims=NULL;
-	int      numrecords=0;
-
-	/*intermediary: */
-	int     M, N;
-	IssmPDouble *matrix = NULL;
-	int     code;
-	
-	/*Set file pointer to beginning of the data: */
-	fid=this->SetFilePointerToData(&code,NULL,data_enum);
-	if(code!=8)_error2_("expecting a IssmDouble mat array for enum " << EnumToStringx(data_enum));
-	
-	/*Now fetch: */
-	if(my_rank==0){  
-		if(fread(&numrecords,sizeof(int),1,fid)!=1) _error2_("could not read number of records in matrix array ");
-	}
-	#ifdef _HAVE_MPI_
-	MPI_Bcast(&numrecords,1,MPI_INT,0,MPI_COMM_WORLD); 
-	#endif
-
-	if(numrecords){
-
-		/*Allocate matrices :*/
-		matrices=xNew<IssmDouble*>(numrecords);
-		mdims=xNew<int>(numrecords);
-		ndims=xNew<int>(numrecords);
-
-		for(i=0;i<numrecords;i++){
-			matrices[i]=NULL;
-			mdims[i]=0;
-			ndims[i]=0;
-		}
-
-		/*Loop through records and fetch matrix: */
-		for(i=0;i<numrecords;i++){
-
-			if(my_rank==0){  
-				if(fread(&M,sizeof(int),1,fid)!=1) _error2_("could not read number of rows in " << i << "th matrix of matrix array");
-			}
-			#ifdef _HAVE_MPI_
-			MPI_Bcast(&M,1,MPI_INT,0,MPI_COMM_WORLD); 
-			#endif
-
-			if(my_rank==0){  
-				if(fread(&N,sizeof(int),1,fid)!=1) _error2_("could not read number of columns in " << i << "th matrix of matrix array");
-			}
-			#ifdef _HAVE_MPI_
-			MPI_Bcast(&N,1,MPI_INT,0,MPI_COMM_WORLD); 
-			#endif
-
-			/*Now allocate matrix: */
-			if(M*N){
-				matrix=xNew<IssmPDouble>(M*N);
-
-				/*Read matrix on node 0, then broadcast: */
-				if(my_rank==0){  
-					if(fread(matrix,M*N*sizeof(IssmPDouble),1,fid)!=1) _error2_("could not read matrix ");
-				}
-
-				#ifdef _HAVE_MPI_
-				MPI_Bcast(matrix,M*N,MPI_DOUBLE,0,MPI_COMM_WORLD); 
-				#endif
-				matrices[i]=xNew<IssmDouble>(M*N);
-				for (int j=0;j<M*N;++j) {matrices[i][j]=matrix[j];}
-				xDelete<IssmPDouble>(matrix);
-			}
-			else
-			  matrices[i]=NULL;
-			/*Assign: */
-			mdims[i]=M;
-			ndims[i]=N;
-		}
-	}
-
-	/*Assign output pointers: */
-	*pmatrices=matrices;
-	*pmdims=mdims;
-	*pndims=ndims;
-	*pnumrecords=numrecords;
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(Option**  poption,int data_enum){{{*/
-void  IoModel::FetchData(Option** poption,int index){
-
-	extern int my_rank;
-	extern int num_procs;
-
-	/*output: */
-	int     code;
-	Option *option      = NULL;
-	char   *name        = NULL;
-
-	/*First get option name*/
-	this->FetchData(&name,index);
-
-	/*Get option value*/
-	fid=this->SetFilePointerToData(&code,NULL,index+1);
-	switch(code){
-		case 3: {//IssmDouble
-			  IssmDouble *value = NULL;
-			  value=xNew<IssmDouble>(1);
-			  FetchData(value,index+1);
-			  option = new OptionDouble();
-			  ((OptionDouble*)option)->values = value;
-			  option->name  = name;
-			  option->numel = 1;
-			  option->ndims = 1;
-			  option->size  = NULL;
-			  break;
-			  }
-		case 4: {//char
-			  char* value = NULL;
-			  FetchData(&value,index+1);
-			  option = new OptionChar();
-			  ((OptionChar*)option)->values = value;
-			  option->name  = name;
-			  option->numel = 1;
-			  option->ndims = 1;
-			  option->size  = NULL;
-			  break;
-			  }
-		default:
-			  _error2_("Option of format " << code << " not supported yet");
-	}
-
-	/*Assign output pointers: */
-	*poption=option;
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchData(int num,...){{{*/
-void  IoModel::FetchData(int num,...){
-
-	va_list ap;
-	int     dataenum;
-	IssmDouble* matrix=NULL;
-	int     M,N;
-	int     i;
-
-	/*Go through the entire list of enums and fetch the corresponding data. Add it to the iomodel->data dataset. Everything
-	 *we fetch is a IssmDouble* : */
-	
-	va_start(ap,num);
-	for(i=0; i<num; i++){
-		
-		dataenum=va_arg(ap, int);
-
-		/*Some checks in debugging mode*/
-		/*{{{*/
-		#ifdef _ISSM_DEBUG_
-		_assert_(dataenum<MaximumNumberOfEnums);
-		if(this->data[dataenum]){
-			_error2_("Info: trying to fetch " << EnumToStringx(dataenum) << " but previous pointer has not been freed (DeleteData has not been called)");
-		}
-		#endif
-		/*}}}*/
-
-		/*Add to this->data: */
-		this->FetchData(&matrix,&M,&N,dataenum);
-		this->data[dataenum]=matrix;
-	}
-	va_end(ap);
-
-}
-/*}}}*/
-/*FUNCTION IoModel::FetchDataToInput{{{*/
-void IoModel::FetchDataToInput(Elements* elements,int vector_enum,int default_vector_enum,IssmDouble default_value){
-
-	/*intermediary: */
-	int     i;
-	bool    defaulting    = false;
-	bool    transient     = false;
-
-	FILE   *fid           = NULL;
-	int     code          = 0;
-	int     vector_layout = 0;
-	int     counter;
-	int     nods;
-	int     nel;
-	int     numberofelements;
-
-
-	/*variables being fetched: */
-	bool    boolean;
-	int     integer;
-	IssmDouble  scalar;
-	char   *string        = NULL;
-	IssmDouble *IssmDoublevector  = NULL;
-	int     M,N;
-
-	/*Fetch parameters: */
-	this->constants->FindParam(&numberofelements,MeshNumberofelementsEnum);
-
-	/*First of, find the record for the enum, and get code  of data type: */
-	fid=this->SetFilePointerToData(&code, &vector_layout,vector_enum);
-
-	switch(code){
-		case 1: //boolean constant.  {{{
-			this->FetchData(&boolean,vector_enum);
-
-			/*Add boolean constant input to all elements: */
-			counter=0;
-			for (i=0;i<numberofelements;i++){
-				if(this->my_elements[i]){
-					Element* element=(Element*)elements->GetObjectByOffset(counter);
-					element->InputCreate((IssmDouble)boolean,vector_enum,code);
-					counter++;
-				}
-			}
-			break; /*}}}*/
-		case 2: //integer constant.  {{{
-			this->FetchData(&integer,vector_enum);
-
-			/*Add integer constant input to all elements: */
-			counter=0;
-			for (i=0;i<numberofelements;i++){
-				if(this->my_elements[i]){
-					Element* element=(Element*)elements->GetObjectByOffset(counter);
-					element->InputCreate((IssmDouble)integer,vector_enum,code);
-					counter++;
-				}
-			}
-			break; /*}}}*/
-		case 3: //IssmDouble constant.  {{{
-			this->FetchData(&scalar,vector_enum);
-
-			/*Add IssmDouble constant input to all elements: */
-			counter=0;
-			for (i=0;i<numberofelements;i++){
-				if(this->my_elements[i]){
-					Element* element=(Element*)elements->GetObjectByOffset(counter);
-					element->InputCreate(scalar,vector_enum,code); 
-					counter++;
-				}
-			}
-			break; /*}}}*/
-		case 5: //boolean vector.  {{{
-
-			/*Fetch vector:*/
-			this->FetchData(&IssmDoublevector,&M,&N,vector_enum); //we still have a IssmDoublevector, because it might include times in transient mode
-			/*Check we got something, otherwise fetch default: */
-			if(IssmDoublevector){
-				defaulting=false;  //we are not defaulting, because  we do have a vector
-			}
-			else{
-				/*do we have a default enum to go fetch? */
-				if(default_vector_enum!=NoneEnum){
-					/*yes. fetch it: */
-					this->FetchData(&IssmDoublevector,&M,&N,default_vector_enum);
-					if(IssmDoublevector){
-						defaulting=false;  //we are not defaulting, because  we do have a vector
-					}
-					else{
-						/*even the default vector is non existent. we are defaulting to the default value: */
-						defaulting=true;
-					}
-				}
-				else{
-					/*we are left with the default value: */
-					defaulting=true;
-				}
-			}
-
-			/*Create inputs:*/
-			counter=0;
-			for (i=0;i<numberofelements;i++){
-				if(this->my_elements[i]){
-					Element* element=(Element*)elements->GetObjectByOffset(counter);
-					if(defaulting) element->InputCreate(default_value,vector_enum,code); 
-					else           element->InputCreate(IssmDoublevector,i,this,M,N,vector_layout,vector_enum,code);//we need i to index into elements.
-					counter++;
-				}
-			}
-			break; /*}}}*/
-		case 6: //int vector{{{
-
-			/*Fetch vector:*/
-			this->FetchData(&IssmDoublevector,&M,&N,vector_enum); //we still have a IssmDoublevector, because it might include times in transient mode
-			/*Check we got something, otherwise fetch default: */
-			if(IssmDoublevector){
-				defaulting=false;  //we are not defaulting, because  we do have a vector
-			}
-			else{
-				/*do we have a default enum to go fetch? */
-				if(default_vector_enum!=NoneEnum){
-					/*yes. fetch it: */
-					this->FetchData(&IssmDoublevector,&M,&N,default_vector_enum);
-					if(IssmDoublevector){
-						defaulting=false;  //we are not defaulting, because  we do have a vector
-					}
-					else{
-						/*even the default vector is non existent. we are defaulting to the default value: */
-						defaulting=true;
-					}
-				}
-				else{
-					/*we are left with the default value: */
-					defaulting=true;
-				}
-			}
-
-			/*Create inputs:*/
-			counter=0;
-			for (i=0;i<numberofelements;i++){
-				if(this->my_elements[i]){
-					Element* element=(Element*)elements->GetObjectByOffset(counter);
-					if(defaulting) element->InputCreate(default_value,vector_enum,code); 
-					else           element->InputCreate(IssmDoublevector,i,this,M,N,vector_layout,vector_enum,code);//we need i to index into elements.
-					counter++;
-				}
-			}
-			break; /*}}}*/
-		case 7: //IssmDouble vector{{{
-
-			/*Fetch vector:*/
-			this->FetchData(&IssmDoublevector,&M,&N,vector_enum);
-			/*Check we got something, otherwise fetch default: */
-			if(IssmDoublevector){
-				defaulting=false;  //we are not defaulting, because  we do have a vector
-			}
-			else{
-				/*do we have a default enum to go fetch? */
-				if(default_vector_enum!=NoneEnum){
-					/*yes. fetch it: */
-					this->FetchData(&IssmDoublevector,&M,&N,default_vector_enum);
-					if(IssmDoublevector){
-						defaulting=false;  //we are not defaulting, because  we do have a vector
-					}
-					else{
-						/*even the default vector is non existent. we are defaulting to the default value: */
-						defaulting=true;
-					}
-				}
-				else{
-					/*we are left with the default value: */
-					defaulting=true;
-				}
-			}
-
-			/*Create inputs:*/
-			counter=0;
-			for (i=0;i<numberofelements;i++){
-				if(this->my_elements[i]){
-					Element* element=(Element*)elements->GetObjectByOffset(counter);
-					if(defaulting) element->InputCreate(default_value,vector_enum,code); 
-					else           element->InputCreate(IssmDoublevector,i,this,M,N,vector_layout,vector_enum,code);//we need i to index into elements.
-					counter++;
-				}
-			}
-
-			break; /*}}}*/
-		default: /*{{{*/
-			_error2_("data code " << code << " not supported yet!");
-			break;
-			/*}}}*/
-	}
-	/*Free ressources:*/
-	xDelete<IssmDouble>(IssmDoublevector);
-	xDelete<char>(string);
-}
-/*FUNCTION IoModel::LastIndex{{{*/
-void IoModel::LastIndex(int *pindex){
-
-	extern int my_rank;
-	int        lastindex,index;
-	int        record_length;
-
-	/*Go find in the binary file, the position of the data we want to fetch: */
-	if(my_rank==0){
-
-		/*First set FILE* position to the beginning of the file: */
-		fseek(fid,0,SEEK_SET);
-
-		/*Now march through file looking for the correct data identifier: */
-		for(;;){
-			/*Read enum for this size of first string name: */
-			if(fread(&index,sizeof(int),1,fid)==0){
-				/*Ok, we have reached the end of the file. break: */
-				break;
-			}
-
-			/*read the record length, and use it to skip this record: */
-			fread(&record_length,sizeof(int),1,fid);
-			fseek(fid,record_length,SEEK_CUR);
-			lastindex=index;
-		}
-	}
-	/*Broadcast code and vector type: */
-#ifdef _HAVE_MPI_
-	MPI_Bcast(&lastindex,1,MPI_INT,0,MPI_COMM_WORLD); 
-#endif
-
-	/*Assign output pointers:*/
-	*pindex=lastindex;
-}
-/*FUNCTION IoModel::SetFilePointerToData{{{*/
-FILE* IoModel::SetFilePointerToData(int* pcode,int* pvector_type, int data_enum){
-
-	extern int my_rank;
-	extern int num_procs;
-
-	int found=0;
-	int record_enum;
-	int record_length;
-	int record_code; //1 to 7 number
-	int vector_type; //nodal or elementary
-
-	/*Go find in the binary file, the position of the data we want to fetch: */
-	if(my_rank==0){
-
-		/*First set FILE* position to the beginning of the file: */
-		fseek(fid,0,SEEK_SET);
-
-		/*Now march through file looking for the correct data identifier: */
-		for(;;){
-			/*Read enum for this size of first string name: */
-			if(fread(&record_enum,sizeof(int),1,fid)==0){
-				/*Ok, we have reached the end of the file. break: */
-				found=0;
-				break;
-			}
-
-			/*Is this the record sought for? : */
-			if (data_enum==record_enum){
-				/*Ok, we have found the correct string. Pass the record length, and read data type code: */
-				fseek(fid,sizeof(int),SEEK_CUR);
-				fread(&record_code,sizeof(int),1,fid);
-
-				/*if record_code points to a vector, get its type (nodal or elementary): */
-				if(5<=record_code && record_code<=7)fread(&vector_type,sizeof(int),1,fid);
-				found=1;
-				break;
-			}
-			else{
-				/*This is not the correct string, read the record length, and use it to skip this record: */
-				fread(&record_length,sizeof(int),1,fid);
-				/*skip: */
-				fseek(fid,record_length,SEEK_CUR);
-			}
-		}
-	}
-#ifdef _HAVE_MPI_
-	MPI_Bcast(&found,1,MPI_INT,0,MPI_COMM_WORLD); 
-	if(!found)_error2_("could not find data with name" << " " << EnumToStringx(data_enum) << " ");
-#endif
-
-	/*Broadcast code and vector type: */
-#ifdef _HAVE_MPI_
-	MPI_Bcast(&record_code,1,MPI_INT,0,MPI_COMM_WORLD); 
-	MPI_Bcast(&vector_type,1,MPI_INT,0,MPI_COMM_WORLD); 
-	if(record_code==5) MPI_Bcast(&vector_type,1,MPI_INT,0,MPI_COMM_WORLD); 
-#endif
-
-	/*Assign output pointers:*/
-	*pcode=record_code;
-	if(pvector_type)*pvector_type=vector_type;
-
-	return fid;
-}
-/*}}}*/
Index: sm/trunk-jpl/src/c/objects/IoModel.h
===================================================================
--- /issm/trunk-jpl/src/c/objects/IoModel.h	(revision 12821)
+++ 	(revision )
@@ -1,67 +1,0 @@
-/* \file IoModel.h
- * \brief  Header file defining the IoModel structure that will help in processing the input data coming 
- * into ISSM, from Matlab, or through a binary file opened for reading.
- * \sa IoModel.cpp
- */
-
-#ifndef _IOMODEL_H
-#define _IOMODEL_H
-
-#include "../include/include.h"
-#include "../EnumDefinitions/EnumDefinitions.h"
-
-class Elements;
-class Param;
-class Option;
-
-class IoModel {
-
-	private: 
-		IssmDouble **data;        //this dataset holds temporary data, memory intensive.
-		Parameters  *constants;   //this dataset holds all IssmDouble, int, bool and char *parameters read in from the input file.*
-
-	public:
-		/*This data needs to stay memory resident at all time, even if it's memory intensive: */
-		FILE *fid;         //pointer to input file
-		bool *my_elements;
-		bool *my_nodes;
-		int  *my_vertices;
-		int  *singlenodetoelementconnectivity;
-		int  *numbernodetoelementconnectivity;
-
-		/*Data to synchronize through low level object drivers: */
-		int nodecounter;         //keep track of how many nodes are being created in each analysis type
-		int loadcounter;         //keep track of how many loads are being created in each analysis type
-		int constraintcounter;   //keep track of how many constraints are being created in each analysis type
-
-		/*Methods*/
-		~IoModel();
-		IoModel();
-		IoModel(FILE* iomodel_handle);
-
-		/*Input/Output*/
-		void        CheckEnumSync(void);
-		void        Constant(bool *poutput,int constant_enum);
-		void        Constant(int *poutput,int constant_enum);
-		void        Constant(IssmDouble *poutput,int constant_enum);
-		void        Constant(char **poutput,int constant_enum);
-		Param      *CopyConstantObject(int constant_enum);
-		IssmDouble *Data(int dataenum);
-		void        DeleteData(int num,...);
-		void        FetchConstants(void);
-		void        FetchData(bool* pboolean,int data_enum);
-		void        FetchData(int* pinteger,int data_enum);
-		void        FetchData(IssmDouble* pscalar,int data_enum);
-		void        FetchData(char** pstring,int data_enum);
-		void        FetchData(int** pmatrix,int* pM,int* pN,int data_enum);
-		void        FetchData(IssmDouble**  pscalarmatrix,int* pM,int* pN,int data_enum);
-		void        FetchData(char***   pstringarray,int* pnumstrings,int data_enum);
-		void        FetchData(IssmDouble*** pmatrixarray,int** pmdims,int** pndims, int* pnumrecords,int data_enum);
-		void        FetchData(Option **poption,int data_enum);
-		void        FetchData(int num,...);
-		void        FetchDataToInput(Elements* elements,int vector_enum,int default_vector_enum=NoneEnum,IssmDouble default_value=0);
-		void        LastIndex(int *pindex);
-		FILE*       SetFilePointerToData(int* pcode,int* pvector_type, int data_enum);
-};
-
-#endif  /* _IOMODEL_H */
Index: sm/trunk-jpl/src/c/objects/OptArgs.h
===================================================================
--- /issm/trunk-jpl/src/c/objects/OptArgs.h	(revision 12821)
+++ 	(revision )
@@ -1,13 +1,0 @@
-/*!\file:  OptArgs.h
- * \brief place holder for optimization function arguments
- */ 
-
-#ifndef _OPTARGS_H_
-#define _OPTARGS_H_
-
-class Model;
-struct OptArgs{
-	FemModel* femmodel;
-};
-
-#endif
Index: sm/trunk-jpl/src/c/objects/OptPars.h
===================================================================
--- /issm/trunk-jpl/src/c/objects/OptPars.h	(revision 12821)
+++ 	(revision )
@@ -1,17 +1,0 @@
-/*!\file:  OptPars.h
- * \brief place holder for optimization parameters
- */ 
-
-#ifndef _OPTPARS_H_
-#define _OPTPARS_H_
-
-struct OptPars{
-
-	IssmDouble xmin;
-	IssmDouble xmax;
-	IssmDouble cm_jump;
-	int maxiter;
-
-};
-
-#endif
