Index: issm/trunk-jpl/src/c/classes/Params/BoolParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/BoolParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/BoolParam.h	(revision 27756)
@@ -72,5 +72,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/ControlParam.cpp
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/ControlParam.cpp	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/ControlParam.cpp	(revision 27756)
@@ -17,59 +17,25 @@
 }
 /*}}}*/
-ControlParam::ControlParam(IssmDouble* in_value, IssmDouble* in_minvalue, IssmDouble* in_maxvalue, IssmDouble* in_savedvalue, IssmDouble* in_gradient, int in_enum_type, int in_M){/*{{{*/
-
-	M=in_M;
-
-	if(M){
-		value=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(value,in_value,M);
-		
-		minvalue=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(minvalue,in_minvalue,M);
-		
-		maxvalue=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(maxvalue,in_maxvalue,M);
-		
-		savedvalue=NULL;
-		gradient=NULL;
-		
-	}
-	else{
-		value=NULL;
-		minvalue=NULL;
-		maxvalue=NULL;
-		savedvalue=NULL;
-		gradient=NULL;
-	}
-
-	enum_type=in_enum_type;
-}
-/*}}}*/
-ControlParam::ControlParam(IssmDouble* in_value, IssmDouble* in_minvalue, IssmDouble* in_maxvalue, int in_enum_type, int in_M){/*{{{*/
-
-	enum_type=in_enum_type;
-	M=in_M;
-
-	if(M){
-		value=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(value,in_value,M);
-		
-		minvalue=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(minvalue,in_minvalue,M);
-		
-		maxvalue=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(maxvalue,in_maxvalue,M);
-	
-		savedvalue=NULL;
-		gradient=xNewZeroInit<IssmDouble>(M);
-	}
-	else{
-		value=NULL;
-		minvalue=NULL;
-		maxvalue=NULL;
-		savedvalue=NULL;
-		gradient=NULL;
-	}
-
+ControlParam::ControlParam(IssmDouble* in_value, IssmDouble* in_minvalue, IssmDouble* in_maxvalue, int in_enum_type, int in_M,int in_N){/*{{{*/
+
+	this->enum_type=in_enum_type;
+	this->M=in_M;
+	this->N=in_N;
+
+	/*Sanity check, can't hurt*/
+	if(this->N<1) _error_("Parameter is empty");
+	if(this->M<1) _error_("Parameter is empty");
+	if(this->M>2) _error_("Cannot handle more than 2 rows (as a TransientParam)");
+
+	/*Assign value*/
+	this->value=xNew<IssmDouble>(M*N);
+	xMemCpy<IssmDouble>(value,in_value,M*N);
+
+	/*Assign other fields*/
+	this->minvalue=xNew<IssmDouble>(N);
+	xMemCpy<IssmDouble>(minvalue,in_minvalue,N);
+	this->maxvalue=xNew<IssmDouble>(N);
+	xMemCpy<IssmDouble>(maxvalue,in_maxvalue,N);
+	this->gradient=xNewZeroInit<IssmDouble>(N);
 }
 /*}}}*/
@@ -79,5 +45,4 @@
 	xDelete<IssmDouble>(maxvalue);
 	xDelete<IssmDouble>(gradient);
-	xDelete<IssmDouble>(savedvalue);
 	return;
 }
@@ -87,5 +52,25 @@
 Param* ControlParam::copy() {/*{{{*/
 
-	return new ControlParam(this->value,this->minvalue,this->maxvalue,this->savedvalue,this->gradient,this->enum_type,this->M);
+	ControlParam* output = new ControlParam();
+	output->enum_type=this->enum_type;
+	output->M=this->M;
+	output->N=this->N;
+	if(value){
+		output->value=xNew<IssmDouble>(this->M*this->N);
+		xMemCpy<IssmDouble>(output->value,this->value,this->M*this->N);
+	}
+	if(minvalue){
+		output->minvalue=xNew<IssmDouble>(this->N);
+		xMemCpy<IssmDouble>(output->minvalue,this->minvalue,this->N);
+	}
+	if(maxvalue){
+		output->maxvalue=xNew<IssmDouble>(this->N);
+		xMemCpy<IssmDouble>(output->maxvalue,this->maxvalue,this->N);
+	}
+	if(gradient){
+		output->gradient=xNew<IssmDouble>(this->N);
+		xMemCpy<IssmDouble>(output->gradient,this->gradient,this->N);
+	}
+	return output;
 
 }
@@ -97,5 +82,4 @@
 	for(int i=0;i<this->M;i++) _printf_(" "<< this->value[i]);
 	_printf_("]\n");
-	if (savedvalue) _printf_("---savedvalue: " << this->savedvalue << "\n");
 	if (minvalue) _printf_("---minvalue: ");
 	for(int i=0;i<this->M;i++) _printf_(" "<< this->minvalue[i]);
@@ -119,9 +103,9 @@
 	marshallhandle->call(this->enum_type);
 	marshallhandle->call(this->M);
-	marshallhandle->call(this->value,this->M);
-	marshallhandle->call(this->minvalue,this->M);
-	marshallhandle->call(this->maxvalue,this->M);
-	marshallhandle->call(this->savedvalue,this->M);
-	marshallhandle->call(this->gradient,this->M);
+	marshallhandle->call(this->N);
+	marshallhandle->call(this->value,this->M*this->N);
+	marshallhandle->call(this->minvalue,this->N);
+	marshallhandle->call(this->maxvalue,this->N);
+	marshallhandle->call(this->gradient,this->N);
 
 }
@@ -134,22 +118,19 @@
 /*}}}*/
 
-void  ControlParam::GetParameterValue(IssmDouble** poutput,int* pM, const char* data){/*{{{*/
-
-	IssmDouble* output=xNew<IssmDouble>(M);
+void  ControlParam::GetParameterValue(IssmDouble** poutput,int* pN, const char* data){/*{{{*/
+
+	IssmDouble* output=xNew<IssmDouble>(N);
 	
 	if(strcmp(data,"value")==0){
-		xMemCpy<IssmDouble>(output,value,M);
-	}
-	else if(strcmp(data,"savedvalues")==0){
-		xMemCpy<IssmDouble>(output,savedvalue,M);
+		xMemCpy<IssmDouble>(output,value,N);
 	}
 	else if (strcmp(data,"lowerbound")==0){
-		xMemCpy<IssmDouble>(output,minvalue,M);
+		xMemCpy<IssmDouble>(output,minvalue,N);
 	}
 	else if (strcmp(data,"upperbound")==0){
-		xMemCpy<IssmDouble>(output,maxvalue,M);
+		xMemCpy<IssmDouble>(output,maxvalue,N);
 	}
 	else if (strcmp(data,"gradient")==0){
-		xMemCpy<IssmDouble>(output,gradient,M);
+		xMemCpy<IssmDouble>(output,gradient,N);
 	}
 	else{
@@ -158,5 +139,5 @@
 	
 	/*Assign output pointers:*/
-	if(pM) *pM=M;
+	if(pN) *pN=N;
 	*poutput=output;
 }
@@ -164,60 +145,97 @@
 void  ControlParam::GetParameterValue(IssmDouble* poutput){/*{{{*/
 
-	xMemCpy<IssmDouble>(poutput,value,M);
-	
+	/*Copy entire vector if M==1, or first row if M==2*/
+	if(M==1){
+		xMemCpy<IssmDouble>(poutput,value,N);
+		return;
+	}
+
+	_error_("STOP");
+
 }
 /*}}}*/
 void  ControlParam::GetParameterValue(IssmDouble* poutput, IssmDouble time){/*{{{*/
 
+	if(M==1){
+		*poutput = value[0];
+		return;
+	}
+
+	IssmDouble *timesteps = &this->value[1*this->N+0];
+	IssmDouble output;
+	bool       found;
+
+	/*Ok, we have the time, go through the timesteps, and figure out which interval we 
+	 *fall within. Then interpolate the values on this interval: */
+	if(time<timesteps[0]){
+		/*get values for the first time: */
+		output=this->value[0];
+		found=true;
+	}
+	else if(time>timesteps[this->N-1]){
+		/*get values for the last time: */
+		output=this->value[this->N-1];
+		found=true;
+	}
+	else{
+		/*Find which interval we fall within: */
+		for(int i=0;i<this->N;i++){
+			if(time==timesteps[i]){
+				/*We are right on one step time: */
+				output=this->value[i];
+				found=true;
+				break; //we are done with the time interpolation.
+			}
+			else{
+				if(timesteps[i]<time && time<timesteps[i+1]){
+					/*ok, we have the interval ]i:i+1[. Interpolate linearly for now: */
+					IssmDouble deltat=timesteps[i+1]-timesteps[i];
+					IssmDouble alpha=(time-timesteps[i])/deltat;
+					output=(1.0-alpha)*this->value[i] + alpha*this->value[i+1];
+					found=true;
+					break;
+				}
+				else continue; //keep looking on the next interval
+			}
+		}
+	}
+	if(!found)_error_("did not find time interval on which to interpolate values");
+	//_printf_("for time = "<<time/31536000.<<" yr, melt = "<<output*31536000.<<" m/yr\n");
+
+	*poutput=output;
+}
+/*}}}*/
+void  ControlParam::GetParameterValue(IssmDouble** poutput, int* pN){/*{{{*/
+
+	/*This method should be specific to VectorParams, only one tow required*/
+	_assert_(N>0);
 	_assert_(M==1);
-	*poutput = value[0];
-
-}
-/*}}}*/
-void  ControlParam::GetParameterValue(IssmDouble** poutput, int* pM){/*{{{*/
-
-	IssmDouble* output=NULL;
-
-	if(M){
-		output=xNew<IssmDouble>(M);
-		xMemCpy<IssmDouble>(output,value,M);
-	}
+	IssmDouble* output=xNew<IssmDouble>(N);
+	xMemCpy<IssmDouble>(output,value,N);
 	
 	/*Assign output pointers:*/
-	if(pM) *pM=M;
+	if(pN) *pN=N;
 	*poutput=output;
-	
-}
-/*}}}*/
-void  ControlParam::SetValue(IssmDouble* poutput, int in_M){/*{{{*/
-
-	/*avoid leak: */
-	xDelete<IssmDouble>(this->value);
-	
-	this->value=xNew<IssmDouble>(in_M);
-	xMemCpy<IssmDouble>(this->value,poutput,in_M);
-
-	this->M=in_M;
-}
-/*}}}*/
-void  ControlParam::SetGradient(IssmDouble* poutput, int in_M){/*{{{*/
-
-	_assert_(in_M==this->M);
-
-	/*avoid leak: */
-	xDelete<IssmDouble>(this->gradient);
-	
-	this->gradient=xNew<IssmDouble>(in_M);
-	xMemCpy<IssmDouble>(this->gradient,poutput,in_M);
-
-	this->M=in_M;
-}
-/*}}}*/
-void  ControlParam::GetVectorFromControl(Vector<IssmDouble>* vector,int control_index,int N,const char* data,int offset){/*{{{*/
+}
+/*}}}*/
+void  ControlParam::SetValue(IssmDouble* poutput,int in_M, int in_N){/*{{{*/
+
+	_assert_(in_N==this->N);
+	_assert_(in_M==1);
+	xMemCpy<IssmDouble>(this->value,poutput,in_N);
+}
+/*}}}*/
+void  ControlParam::SetGradient(IssmDouble* poutput,int in_M, int in_N){/*{{{*/
+
+	_assert_(in_M==1);
+	xMemCpy<IssmDouble>(this->gradient,poutput,in_N);
+}
+/*}}}*/
+void  ControlParam::GetVectorFromControl(Vector<IssmDouble>* vector,int control_index,int in_N,const char* data,int offset){/*{{{*/
 
 	/*Get list of ids for this element and this control*/
-	_assert_(N==this->M); //FIXME
-	int* idlist = xNew<int>(this->M);
-	for(int i=0;i<this->M;i++) idlist[i] = offset+i;
+	_assert_(in_N==this->N);
+	int* idlist = xNew<int>(this->N);
+	for(int i=0;i<this->N;i++) idlist[i] = offset+i;
 
 	/*Get data*/
@@ -226,5 +244,5 @@
 
 	/*Enter data in vector*/
-	vector->SetValues(this->M,idlist,values,INS_VAL);
+	vector->SetValues(this->N,idlist,values,INS_VAL);
 
 	/*Clean up*/
Index: issm/trunk-jpl/src/c/classes/Params/ControlParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/ControlParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/ControlParam.h	(revision 27756)
@@ -21,17 +21,15 @@
 
 	private: 
-		IssmDouble* value;
+		IssmDouble* value;   //Can either be a VecParam or a TransientParam
 		IssmDouble* minvalue;
 		IssmDouble* maxvalue;
-		IssmDouble* savedvalue;
 		IssmDouble* gradient; 
 		int         enum_type;
-		int         M;
+		int         M,N;
 
 	public:
 		/*ControlParam constructors, destructors: {{{*/
 		ControlParam();
-		ControlParam(IssmDouble* in_value, IssmDouble* in_minvalue, IssmDouble* in_maxvalue, IssmDouble* in_savedvalue, IssmDouble* in_gradient, int in_enum_type, int in_M);
-		ControlParam(IssmDouble* in_value, IssmDouble* in_minvalue, IssmDouble* in_maxvalue, int in_enum_type, int in_M);
+		ControlParam(IssmDouble* in_value, IssmDouble* in_minvalue, IssmDouble* in_maxvalue, int in_enum_type, int in_M, int in_N);
 		~ControlParam();
 		/*}}}*/
@@ -70,6 +68,6 @@
 		void  SetValue(char** stringarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a string array");}
 		void  SetValue(IssmDouble* IssmDoublearray){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a scalar");}
-		void  SetValue(IssmDouble* IssmDoublearray,int M);
-		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a IssmDouble mat array");}
+		void  SetValue(IssmDouble* IssmDoublearray,int M){_error_("not implemented");}
+		void  SetValue(IssmDouble* pIssmDoublearray,int M,int N);
 		void  SetValue(int* intarray,int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot return an integer");}
 		void  SetValue(int* pintarray,int M,int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a int mat array");}
@@ -78,5 +76,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M);
+		void  SetGradient(IssmDouble* poutput, int M, int N);
 		void  GetVectorFromControl(Vector<IssmDouble>* vector,int control_index,int N,const char* data,int offset);
 		/*}}}*/
Index: issm/trunk-jpl/src/c/classes/Params/DataSetParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/DataSetParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/DataSetParam.h	(revision 27756)
@@ -74,5 +74,5 @@
 		void  SetValue(DataSet* dataset);
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("DataSet param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/DoubleMatArrayParam.h	(revision 27756)
@@ -75,5 +75,5 @@
 		void  SetValue(FILE* fid){_error_("Bool param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array);
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/DoubleMatParam.h	(revision 27756)
@@ -74,5 +74,5 @@
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
 		void  SetEnum(int enum_in){this->enum_type = enum_in;};
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 		/*DoubleMatParam specific routines:{{{*/
Index: issm/trunk-jpl/src/c/classes/Params/DoubleParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/DoubleParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/DoubleParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/DoubleVecParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 		/*DoubleVecParam specific routines:{{{*/
Index: issm/trunk-jpl/src/c/classes/Params/FileParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/FileParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/FileParam.h	(revision 27756)
@@ -72,5 +72,5 @@
 		void  SetValue(FILE* fid){_error_("File param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("File param of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/GenericParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/GenericParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/GenericParam.h	(revision 27756)
@@ -99,5 +99,5 @@
                 void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold a FILE");}
                 void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an array of matrices");}
-					 void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an IssmDouble");};
+					 void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(myEnumVal) << " cannot hold an IssmDouble");};
 
                 /*}}}*/
Index: issm/trunk-jpl/src/c/classes/Params/IntMatParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/IntMatParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/IntMatParam.h	(revision 27756)
@@ -74,5 +74,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/IntParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/IntParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/IntParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/IntVecParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/IntVecParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/IntVecParam.h	(revision 27756)
@@ -74,5 +74,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/MatrixParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/MatrixParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/MatrixParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/Param.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/Param.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/Param.h	(revision 27756)
@@ -65,5 +65,5 @@
 		virtual void  SetValue(FILE* fid)=0;
 		virtual void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array)=0;
-		virtual void  SetGradient(IssmDouble* poutput, int M)=0;
+		virtual void  SetGradient(IssmDouble* poutput, int M, int N)=0;
 		virtual void  GetVectorFromControl(Vector<IssmDouble>* vector,int control_index,int N,const char* data,int offset){_error_("not implemented yet");};
 };
Index: issm/trunk-jpl/src/c/classes/Params/Parameters.cpp
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/Parameters.cpp	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/Parameters.cpp	(revision 27756)
@@ -655,5 +655,5 @@
 	param=xDynamicCast<Param*>(this->FindParamObject(enum_type));
 
-	if(param) param->SetValue(&vector[offset], M);
+	if(param) param->SetValue(&vector[offset], M, N);
 	else _error_("Param "<< EnumToStringx(enum_type) << " cannot setValue");
 }
@@ -665,18 +665,6 @@
 	param=xDynamicCast<Param*>(this->FindParamObject(enum_type));
 
-	if(param) param->SetGradient(&vector[offset], M);
+	if(param) param->SetGradient(&vector[offset], M, N);
 	else _error_("Param "<< EnumToStringx(enum_type) << " cannot setValue");
-}
-/*}}}*/
-void   Parameters::ControlParamSetGradient(IssmDouble* IssmDoublearray, int M, int enum_type){/*{{{*/
-
-	Param* param=NULL;
-
-	/*first, figure out if the param has already been created: */
-	param=xDynamicCast<Param*>(this->FindParamObject(enum_type));
-	if(param) param->SetGradient(IssmDoublearray,M); //already exists, just set it.
-	else _error_("Param "<< EnumToStringx(enum_type) << " cannot setValue");
-
-	 //this->AddObject(new ControlParam(enum_type,IssmDoublearray,M,N)); //just add the new parameter.
 }
 /*}}}*/
Index: issm/trunk-jpl/src/c/classes/Params/Parameters.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/Parameters.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/Parameters.h	(revision 27756)
@@ -76,5 +76,4 @@
 		void  SetControlFromVector(IssmDouble* array, int enum_type, int M, int N, int offset);
 		void  SetGradientFromVector(IssmDouble* array, int enum_type, int M, int N, int offset);
-		void  ControlParamSetGradient(IssmDouble* IssmDoublearray, int M, int enum_type);
 		void  GetVectorFromControl(Vector<IssmDouble>* vector,int control_enum,int control_index,int N,const char* data,int offset);
 		Param* FindParamObject(int enum_type);
Index: issm/trunk-jpl/src/c/classes/Params/StringArrayParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/StringArrayParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/StringArrayParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/StringParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/StringParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/StringParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/TransientArrayParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/TransientArrayParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/TransientArrayParam.h	(revision 27756)
@@ -78,5 +78,5 @@
 		void  SetValue(FILE* fid){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/TransientParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/TransientParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/TransientParam.h	(revision 27756)
@@ -76,5 +76,5 @@
 		void  SetValue(FILE* fid){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Parameter " <<EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/classes/Params/VectorParam.h
===================================================================
--- issm/trunk-jpl/src/c/classes/Params/VectorParam.h	(revision 27755)
+++ issm/trunk-jpl/src/c/classes/Params/VectorParam.h	(revision 27756)
@@ -73,5 +73,5 @@
 		void  SetValue(FILE* fid){_error_("Vector of enum " << enum_type << " (" << EnumToStringx(enum_type) << ") cannot hold a FILE");}
 		void  SetValue(IssmDouble** array, int M, int* mdim_array, int* ndim_array){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an array of matrices");}
-		void  SetGradient(IssmDouble* poutput, int M){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
+		void  SetGradient(IssmDouble* poutput, int M, int N){_error_("Param "<< EnumToStringx(enum_type) << " cannot hold an IssmDouble");};
 		/*}}}*/
 };
Index: issm/trunk-jpl/src/c/cores/controladm1qn3_core.cpp
===================================================================
--- issm/trunk-jpl/src/c/cores/controladm1qn3_core.cpp	(revision 27755)
+++ issm/trunk-jpl/src/c/cores/controladm1qn3_core.cpp	(revision 27756)
@@ -662,6 +662,6 @@
 	}
 	else{
+		//FIXME: merge with code above?
 		femmodel->results->AddObject(new GenericExternalResult<IssmPDouble*>(femmodel->results->Size()+1,JEnum,mystruct.Jlist,(*mystruct.i),mystruct.N,0,0));
-
 		femmodel->OutputControlsx(&femmodel->results);
 	}
Index: issm/trunk-jpl/src/c/modules/ModelProcessorx/Control/UpdateElementsAndMaterialsControl.cpp
===================================================================
--- issm/trunk-jpl/src/c/modules/ModelProcessorx/Control/UpdateElementsAndMaterialsControl.cpp	(revision 27755)
+++ issm/trunk-jpl/src/c/modules/ModelProcessorx/Control/UpdateElementsAndMaterialsControl.cpp	(revision 27756)
@@ -117,4 +117,5 @@
 	for(int i=0;i<num_controls;i++){
 		control = control_enums[i];
+		if(!IsInputEnum(control)) _error_("Only inputs can be parameters except if you use AD");
 		scale   = 1.;
 
@@ -264,7 +265,10 @@
 				}
 			}
-			if(N!=1) M_all[i]=M-1;
 
 			if(IsInputEnum(input_enum)){
+
+				/*remove last row if time series*/
+				if(N!=1) M_all[i]=M-1;
+
 				if(M_all[i]==iomodel->numberofvertices){
 					Interp_all[i] = P1Enum;
@@ -284,7 +288,11 @@
 			else if(IsParamEnum(input_enum)){
 				//_error_("not supported yet");
-				Interp_all[i] = P0Enum;
-				parameters->AddObject(new ControlParam(independent,independents_min,independents_max,input_enum,M_all[i]));
-
+				Interp_all[i] = DummyEnum; //Placeholder
+				parameters->AddObject(new ControlParam(independent,independents_min,independents_max,input_enum,M_all[i],N_all[i]));
+
+				if(M!=1){
+					_assert_(M==2); //TransientParam
+					M_all[i]=M-1;
+				}
 			}
 			xDelete<IssmDouble>(independent);
