/*\file Inputs.cpp
 * \brief: Implementation of the Inputs class, derived from DataSet class.
 */

/*Headers: {{{*/
#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif

#include "./Input2.h"
#include "./Inputs2.h"

#include "./BoolInput2.h"
#include "./IntInput2.h"
#include "./ElementInput2.h"
#include "./SegInput2.h"
#include "./TriaInput2.h"
#include "./PentaInput2.h"
#include "./TransientInput2.h"
#include "./ControlInput2.h"
#include "./DatasetInput2.h"
#include "./ArrayInput2.h"
using namespace std;
/*}}}*/

/*Object constructors and destructor*/
Inputs2::Inputs2(void){/*{{{*/

	this->numberofelements_local = 0;
	this->numberofvertices_local = 0;

	/*Initialize pointers*/
	for(int i=0;i<NUMINPUTS;i++) this->inputs[i] = NULL;
}
/*}}}*/
Inputs2::Inputs2(int nbe,int nbv){/*{{{*/

	this->numberofelements_local = nbe;
	this->numberofvertices_local = nbv;

	/*Initialize pointers*/
	for(int i=0;i<NUMINPUTS;i++) this->inputs[i] = NULL;
}
/*}}}*/
Inputs2::~Inputs2(){/*{{{*/
	for(int i=0;i<NUMINPUTS;i++){
		if(this->inputs[i]) delete this->inputs[i];
	}
	return;
}
/*}}}*/

Inputs2* Inputs2::Copy(void){/*{{{*/

	Inputs2* output = new Inputs2(this->numberofelements_local,this->numberofvertices_local);

	for(int i=0;i<NUMINPUTS;i++){
		if(this->inputs[i]) output->inputs[i]=this->inputs[i]->copy();
	}

	return output;
}/*}}}*/
void Inputs2::DeepEcho(void){/*{{{*/
	for(int i=0;i<NUMINPUTS;i++) {
		if(this->inputs[i]) this->inputs[i]->DeepEcho();
	}
	return;
}
/*}}}*/
void Inputs2::Echo(void){/*{{{*/
	_printf_("Inputs Echo:\n");
	for(int i=0;i<NUMINPUTS;i++) {
		if(this->inputs[i]) _printf_(setw(25)<<EnumToStringx(i+InputsSTARTEnum+1)<<": set as "<<EnumToStringx(this->inputs[i]->ObjectEnum())<<"\n");
	}
	return;
}
/*}}}*/
void Inputs2::Marshall(char** pmarshalled_data, int* pmarshalled_data_size, int marshall_direction){/*{{{*/

	int obj_enum=-1;
	int num_inputs2=0;
	int index;

	MARSHALLING_ENUM(Inputs2Enum);

	if(marshall_direction==MARSHALLING_FORWARD || marshall_direction==MARSHALLING_SIZE){

		/*Marshall num_inputs2 first*/
		for(int i=0;i<NUMINPUTS;i++){
			if(this->inputs[i]) num_inputs2++;
		}
		MARSHALLING(num_inputs2);

		/*Marshall Parameters one by one now*/
		for(int i=0;i<NUMINPUTS;i++){
			if(this->inputs[i]){
				obj_enum = this->inputs[i]->ObjectEnum();
				MARSHALLING(i);
				MARSHALLING(obj_enum);
				this->inputs[i]->Marshall(pmarshalled_data,pmarshalled_data_size,marshall_direction);
			}
		}
	}
	else{

		/*Get number of inputs2 marshalled*/
		MARSHALLING(num_inputs2);

		/*Recover input2eters one by one*/
		for(int i=0;i<num_inputs2;i++){

			/*Recover enum of object first: */
			MARSHALLING(index);
			MARSHALLING(obj_enum);

			if(obj_enum==BoolInput2Enum){
				BoolInput2* boolinput2=new BoolInput2();
				boolinput2->Marshall(pmarshalled_data,pmarshalled_data_size,marshall_direction);
				this->inputs[index]=boolinput2;
			}
			else if(obj_enum==IntInput2Enum){
				IntInput2* intinput2=new IntInput2();
				intinput2->Marshall(pmarshalled_data,pmarshalled_data_size,marshall_direction);
				this->inputs[index]=intinput2;
			}
			else if(obj_enum==TriaInput2Enum){
				TriaInput2* triainput2=new TriaInput2();
				triainput2->Marshall(pmarshalled_data,pmarshalled_data_size,marshall_direction);
				this->inputs[index]=triainput2;
			}
			else if(obj_enum==PentaInput2Enum){
				PentaInput2* pentainput2=new PentaInput2();
				pentainput2->Marshall(pmarshalled_data,pmarshalled_data_size,marshall_direction);
				this->inputs[index]=pentainput2;
			}
			else{
				_error_("input "<<EnumToStringx(obj_enum)<<" not supported");
			}
		}
	}
}
/*}}}*/

void Inputs2::AddInput(Input2* newinput){/*{{{*/

	/*Get Enum from Param*/
	_assert_(newinput);
	int input_enum = newinput->InstanceEnum();

	/*Get index in array*/
	#ifdef _ISSM_DEBUG_
	if(input_enum<=InputsSTARTEnum) _error_("Cannot add input: Enum "<<EnumToStringx(input_enum)<<" should appear after InputsSTARTEnum");
	if(input_enum>=InputsENDEnum)   _error_("Cannot add input: Enum "<<EnumToStringx(input_enum)<<" should appear before InputsENDEnum");
	#endif
	int index = input_enum - InputsSTARTEnum -1;

	/*Delete input if it already exists*/
	if(this->inputs[index]){
		delete this->inputs[index];
		this->inputs[index] = NULL;
	}

	/*Add input to array*/
	this->inputs[index] = newinput;
}
/*}}}*/
void Inputs2::ChangeEnum(int oldenumtype,int newenumtype){/*{{{*/

	/*Get indices from enums*/
	int index_old = EnumToIndex(oldenumtype);
	int index_new = EnumToIndex(newenumtype);

	/*Delete input if it already exists*/
	if(this->inputs[index_new]) delete this->inputs[index_new];

	/*Make sure that old one exists*/
	if(!this->inputs[index_old]){
		_error_("Input "<<EnumToStringx(oldenumtype)<<" not found");
	}

	/*Replace Enums*/
	this->inputs[index_old]->ChangeEnum(newenumtype);
	this->inputs[index_new] = this->inputs[index_old];
	this->inputs[index_old] = NULL;
}/*}}}*/
void Inputs2::Configure(Parameters* parameters){/*{{{*/
	for(int i=0;i<NUMINPUTS;i++){
		if(this->inputs[i]) this->inputs[i]->Configure(parameters);
	}
}
/*}}}*/
int  Inputs2::DeleteInput(int input_enum){/*{{{*/

	int index = EnumToIndex(input_enum);
	if(this->inputs[index]){
		delete this->inputs[index];
		this->inputs[index] = NULL;
	}

	return 1;
}
/*}}}*/
void Inputs2::DuplicateInput(int original_enum,int new_enum){/*{{{*/

	_assert_(this);

	/*Get indices from enums*/
	int index_ori = EnumToIndex(original_enum);
	int index_new = EnumToIndex(new_enum);

	/*Delete input if it already exists*/
	if(this->inputs[index_new]) delete this->inputs[index_new];

	/*Make sure that old one exists*/
	if(!this->inputs[index_ori]){
		_error_("Input "<<EnumToStringx(original_enum)<<" not found");
	}

	/*Make a copy*/
	Input2* copy=this->inputs[index_ori]->copy();

	/*Add copy*/
	this->inputs[index_new] = copy;
}
/*}}}*/
int  Inputs2::EnumToIndex(int enum_in){/*{{{*/

	_assert_(this);

	/*Make sure this parameter is at the right place*/
	#ifdef _ISSM_DEBUG_
	if(enum_in<=InputsSTARTEnum){
		//int* temp = xNew<int>(3);
		_error_("Enum "<<EnumToStringx(enum_in)<<" should appear after InputsSTARTEnum");
	}
	if(enum_in>=InputsENDEnum){
		_error_("Enum "<<EnumToStringx(enum_in)<<" should appear before InputsENDEnum");
	}
	#endif
	return enum_in - InputsSTARTEnum -1;
}/*}}}*/
bool Inputs2::Exist(int enum_in){/*{{{*/

	_assert_(this);

	int index = EnumToIndex(enum_in);
	if(this->inputs[index]) return true;
	return false;
}
/*}}}*/
int Inputs2::GetInputObjectEnum(int enum_in){/*{{{*/

	_assert_(this);

	int index = EnumToIndex(enum_in);
	if(!this->inputs[index]) _error_("Input "<<EnumToStringx(enum_in)<<" not found");
	return this->inputs[index]->ObjectEnum();
}
/*}}}*/
void Inputs2::GetInputsInterpolations(int* pnuminputs,int** pinterpolations,int** pinputenums){/*{{{*/

	/*First count number of inputs*/
	int count = 0;
	for(int i=0;i<NUMINPUTS;i++){
		if(this->inputs[i]) count++;
	}
	int numinputs = count;

	/*Allocate output*/
	int* interpolations = xNew<int>(count);
	int* enumlist       = xNew<int>(count);

	/*Go through all inputs and assign interpolation in vector*/
	count = 0;
	for(int i=0;i<NUMINPUTS;i++){

		Input2* input=this->inputs[i];
		if(!input) continue;

		enumlist[count] = i+InputsSTARTEnum+1;
		switch(input->ObjectEnum()){
			case BoolInput2Enum:
			case IntInput2Enum:
				interpolations[count] = input->ObjectEnum();
				break;
			case TriaInput2Enum:
				interpolations[count] = input->GetResultInterpolation();
				break;
			default:
				_error_("Input "<<EnumToStringx(input->ObjectEnum())<<" not supported yet");
		}
		count++;
	}
	_assert_(count == numinputs);

	/*Return pointer*/
	*pnuminputs = numinputs;
	*pinterpolations = interpolations;
	*pinputenums = enumlist;

}/*}}}*/
SegInput2* Inputs2::GetSegInput(int enum_in){/*{{{*/

	_assert_(this);

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	return input->GetSegInput();
}/*}}}*/
TriaInput2* Inputs2::GetTriaInput(int enum_in){/*{{{*/

	_assert_(this);

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	return input->GetTriaInput();
}/*}}}*/
TriaInput2* Inputs2::GetTriaInput(int enum_in,IssmDouble time){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	if(input->ObjectEnum()==TransientInput2Enum){
		return xDynamicCast<TransientInput2*>(input)->GetTriaInput(time);
	}
	else{
		return input->GetTriaInput();
	}
}/*}}}*/
TriaInput2* Inputs2::GetTriaInput(int enum_in,IssmDouble start_time,IssmDouble end_time){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	if(input->ObjectEnum()==TransientInput2Enum){
		return xDynamicCast<TransientInput2*>(input)->GetTriaInput(start_time,end_time);
	}
	else{
		_error_("Input "<<EnumToStringx(enum_in)<<" is not an TransientInput2");
	}
}/*}}}*/
PentaInput2* Inputs2::GetPentaInput(int enum_in){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	return input->GetPentaInput();
}/*}}}*/
PentaInput2* Inputs2::GetPentaInput(int enum_in,IssmDouble time){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	if(input->ObjectEnum()==TransientInput2Enum){
		return xDynamicCast<TransientInput2*>(input)->GetPentaInput(time);
	}
	else{
		return input->GetPentaInput();
	}
}/*}}}*/
TransientInput2* Inputs2::GetTransientInput(int enum_in){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;

	if(input->ObjectEnum() != TransientInput2Enum){
		_error_("Input "<<EnumToStringx(enum_in)<<" is not an TransientInput2");
	}

	/*Cast and return*/
	TransientInput2* output = xDynamicCast<TransientInput2*>(input);
	return output;
}/*}}}*/
ElementInput2* Inputs2::GetControlInput2Data(int enum_in,const char* data){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;
	if(input->ObjectEnum() != ControlInput2Enum){
		_error_("Input "<<EnumToStringx(enum_in)<<" is not an ControlInput2");
	}

	/*Cast and return*/
	return xDynamicCast<ControlInput2*>(input)->GetInput2(data);
}/*}}}*/
DatasetInput2* Inputs2::GetDatasetInput2(int enum_in){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;
	if(input->ObjectEnum() != DatasetInput2Enum){
		_error_("Input "<<EnumToStringx(enum_in)<<" is not an DatasetInput2");
	}

	/*Cast and return*/
	return xDynamicCast<DatasetInput2*>(input);
}/*}}}*/
ControlInput2* Inputs2::GetControlInput2(int enum_in){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Check that it has the right format*/
	Input2* input = this->inputs[id];
	if(!input) return NULL;
	if(input->ObjectEnum() != ControlInput2Enum){
		_error_("Input "<<EnumToStringx(enum_in)<<" is not an ControlInput2");
	}

	/*Cast and return*/
	return xDynamicCast<ControlInput2*>(input);
}/*}}}*/
void Inputs2::GetArray(int enum_in,int row,IssmDouble** pvalues,int* pN){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=ArrayInput2Enum) _error_(EnumToStringx(this->inputs[id]->ObjectEnum())<<" cannot return an array");
	}
	else{
		_error_("Input "<<EnumToStringx(enum_in)<<" not found");
	}

	/*Set input*/
	ArrayInput2* input = xDynamicCast<ArrayInput2*>(this->inputs[id]);
	input->GetArray(row,pvalues,pN);
}/*}}}*/
void Inputs2::GetInputValue(bool* pvalue,int enum_in,int index){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=BoolInput2Enum) _error_(EnumToStringx(this->inputs[id]->ObjectEnum())<<" cannot return a bool");
	}
	else{
		_error_("Input "<<EnumToStringx(enum_in)<<" not found");
	}

	/*Set input*/
	BoolInput2* input = xDynamicCast<BoolInput2*>(this->inputs[id]);
	input->GetInput(pvalue,index);
}/*}}}*/
void Inputs2::GetInputValue(int* pvalue,int enum_in,int index){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=IntInput2Enum) _error_(EnumToStringx(this->inputs[id]->ObjectEnum())<<" cannot return a int");
	}
	else{
		int* temp = xNew<int>(3);
		_error_("Input "<<EnumToStringx(enum_in)<<" not found");
	}

	/*Set input*/
	IntInput2* input = xDynamicCast<IntInput2*>(this->inputs[id]);
	input->GetInput(pvalue,index);
}/*}}}*/
void Inputs2::ResultInterpolation(int* pinterpolation,int* pnodesperelement,int* parray_size, int output_enum){/*{{{*/

	/*Get input */
	int     index = EnumToIndex(output_enum);
	Input2* input = this->inputs[index];

	/*Check that it is found*/
	if(!input){
		_error_("Input "<<EnumToStringx(output_enum)<<" not found and cannot be added to model results");
	}

	/*Assign output pointer*/
	*pinterpolation   = input->GetResultInterpolation();
	*pnodesperelement = input->GetResultNumberOfNodes();
	*parray_size      = input->GetResultArraySize();
}/*}}}*/
void Inputs2::SetInput(int enum_in,int index,bool value){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=BoolInput2Enum) _error_("cannot add a bool to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new BoolInput2(this->numberofelements_local);
	}

	/*Set input*/
	BoolInput2* input = xDynamicCast<BoolInput2*>(this->inputs[id]);
	input->SetInput(index,value);
}/*}}}*/
void Inputs2::SetInput(int enum_in,int index,int value){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=IntInput2Enum) _error_("cannot add an int to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new IntInput2(this->numberofelements_local);
	}

	/*Set input*/
	IntInput2* input = xDynamicCast<IntInput2*>(this->inputs[id]);
	input->SetInput(index,value);
}/*}}}*/
void Inputs2::SetArrayInput(int enum_in,int row,IssmDouble* values,int numlayers){/*{{{*/

	bool recreate = false;

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=ArrayInput2Enum){
			delete this->inputs[id];
			recreate = true;
		}
	}
	else{
		recreate = true;
	}

	if(recreate){
		this->inputs[id] = new ArrayInput2(this->numberofelements_local);
	}

	/*Set input*/
	ArrayInput2* input = xDynamicCast<ArrayInput2*>(this->inputs[id]);
	input->SetInput(row,numlayers,values);
}/*}}}*/
TransientInput2* Inputs2::SetDatasetTransientInput(int enum_in,int dataset_id,IssmDouble* times,int numtimes){/*{{{*/

	bool recreate = false;
	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=DatasetInput2Enum){
			delete this->inputs[id];
			recreate = true;
		}
	}
	else{
		recreate = true;
	}

	if(recreate){
		this->inputs[id] = new DatasetInput2(this->numberofelements_local,this->numberofvertices_local);
	}

	/*Get Dataset Input now*/
	DatasetInput2* input = xDynamicCast<DatasetInput2*>(this->inputs[id]);

	/*Create and return transient input*/
	return input->SetTransientInput(dataset_id,times,numtimes);
}/*}}}*/
void Inputs2::SetTransientInput(int enum_in,IssmDouble* times,int numtimes){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		/*Input already there, make sure it is the right type*/
		if(this->inputs[id]->ObjectEnum()!=TransientInput2Enum){
			_error_("cannot add a TransientInput to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
		}
	}
	else{
		this->inputs[id] = new TransientInput2(enum_in,this->numberofelements_local,this->numberofvertices_local,times,numtimes);
	}
}/*}}}*/
void Inputs2::SetTriaControlInput(int enum_in,int layout,int interpolation,int control_id,int numindices,int* indices,IssmDouble* values,IssmDouble* values_min,IssmDouble* values_max){/*{{{*/

	bool recreate = false;
	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=ControlInput2Enum){
			delete this->inputs[id];
			recreate = true;
		}
	}
	else{
		recreate = true;
	}

	if(recreate){
		this->inputs[id] = new ControlInput2(this->numberofelements_local,this->numberofvertices_local,layout,interpolation,control_id);
	}

	/*Set input*/
	ControlInput2* input = xDynamicCast<ControlInput2*>(this->inputs[id]);
	input->SetControl(interpolation,numindices,indices,values,values_min,values_max);
}/*}}}*/
void Inputs2::SetTriaControlInputGradient(int enum_in,int interpolation,int numindices,int* indices,IssmDouble* values){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(!this->inputs[id]) _error_("could not find Input "<<EnumToStringx(enum_in));
	if( this->inputs[id]->ObjectEnum()!=ControlInput2Enum) _error_("Input "<<EnumToStringx(enum_in)<<" is not a ControlInput2");

	/*Set input*/
	ControlInput2* input = xDynamicCast<ControlInput2*>(this->inputs[id]);
	input->SetGradient(interpolation,numindices,indices,values);
}/*}}}*/
void Inputs2::SetTriaControlInputGradient(int enum_in,int interpolation,int numindices,int* indices,IssmDouble* values,int n){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(!this->inputs[id]) _error_("could not find Input "<<EnumToStringx(enum_in));
	if( this->inputs[id]->ObjectEnum()!=ControlInput2Enum) _error_("Input "<<EnumToStringx(enum_in)<<" is not a ControlInput2");

	/*Set input*/
	ControlInput2* input = xDynamicCast<ControlInput2*>(this->inputs[id]);
	input->SetGradient(interpolation,numindices,indices,values,n);
}/*}}}*/
void Inputs2::SetTriaDatasetInput(int enum_in,int id_in,int interpolation,int numindices,int* indices,IssmDouble* values){/*{{{*/

	bool recreate = false;
	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=DatasetInput2Enum){
			delete this->inputs[id];
			recreate = true;
		}
	}
	else{
		recreate = true;
	}

	if(recreate){
		this->inputs[id] = new DatasetInput2(this->numberofelements_local,this->numberofvertices_local);
	}

	/*Set input*/
	DatasetInput2* input = xDynamicCast<DatasetInput2*>(this->inputs[id]);
	input->SetTriaInput(id_in,P1Enum,numindices,indices,values);
}/*}}}*/
void Inputs2::SetTriaInput(int enum_in,int interpolation,int row,IssmDouble value){/*{{{*/

	/*This one only supports P0 and P1 because it assumes col=0*/
	_assert_(interpolation==P0Enum || interpolation==P1Enum);

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=TriaInput2Enum) _error_("cannot add a bool to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new TriaInput2(this->numberofelements_local,this->numberofvertices_local,interpolation);
	}

	/*Set input*/
	TriaInput2* input = xDynamicCast<TriaInput2*>(this->inputs[id]);
	input->SetInput(interpolation,row,value);
}/*}}}*/
void Inputs2::SetTriaInput(int enum_in,int interpolation,int numindices,int* indices,IssmDouble* values){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=TriaInput2Enum){
			_error_("cannot add Element values to a "<<EnumToStringx(this->inputs[id]->ObjectEnum())<<" while trying to set "<<EnumToStringx(enum_in));
		}
	}
	else{
		this->inputs[id] = new TriaInput2(this->numberofelements_local,this->numberofvertices_local,interpolation);
	}

	/*Set input*/
	TriaInput2* input = xDynamicCast<TriaInput2*>(this->inputs[id]);
	input->SetInput(interpolation,numindices,indices,values);
}/*}}}*/
void Inputs2::SetTriaInput(int enum_in,int interpolation,int row,int numindices,IssmDouble* values){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=TriaInput2Enum) _error_("cannot add Element values to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new TriaInput2(this->numberofelements_local,this->numberofvertices_local,interpolation);
	}

	/*Set input*/
	TriaInput2* input = xDynamicCast<TriaInput2*>(this->inputs[id]);
	input->SetInput(interpolation,row,numindices,values);
}/*}}}*/
void Inputs2::SetPentaControlInput(int enum_in,int layout,int interpolation,int control_id,int numindices,int* indices,IssmDouble* values,IssmDouble* values_min,IssmDouble* values_max){/*{{{*/

	bool recreate = false;
	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=ControlInput2Enum){
			delete this->inputs[id];
			recreate = true;
		}
	}
	else{
		recreate = true;
	}

	if(recreate){
		this->inputs[id] = new ControlInput2(this->numberofelements_local,this->numberofvertices_local,layout,interpolation,control_id);
	}

	/*Set input*/
	ControlInput2* input = xDynamicCast<ControlInput2*>(this->inputs[id]);
	input->SetControl(interpolation,numindices,indices,values,values_min,values_max);
}/*}}}*/
void Inputs2::SetPentaControlInputGradient(int enum_in,int interpolation,int numindices,int* indices,IssmDouble* values){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(!this->inputs[id]) _error_("could not find Input "<<EnumToStringx(enum_in));
	if( this->inputs[id]->ObjectEnum()!=ControlInput2Enum) _error_("Input "<<EnumToStringx(enum_in)<<" is not a ControlInput2");

	/*Set input*/
	ControlInput2* input = xDynamicCast<ControlInput2*>(this->inputs[id]);
	input->SetGradient(interpolation,numindices,indices,values);
}/*}}}*/
void Inputs2::SetPentaDatasetInput(int enum_in,int id_in,int interpolation,int numindices,int* indices,IssmDouble* values){/*{{{*/

	bool recreate = false;
	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=DatasetInput2Enum){
			delete this->inputs[id];
			recreate = true;
		}
	}
	else{
		recreate = true;
	}

	if(recreate){
		this->inputs[id] = new DatasetInput2(this->numberofelements_local,this->numberofvertices_local);
	}

	/*Set input*/
	DatasetInput2* input = xDynamicCast<DatasetInput2*>(this->inputs[id]);
	input->SetPentaInput(id_in,P1Enum,numindices,indices,values);
}/*}}}*/
void Inputs2::SetPentaInput(int enum_in,int interpolation,int row,IssmDouble value){/*{{{*/

	/*This one only supports P0 and P1 because it assumes col=0*/
	_assert_(interpolation==P0Enum || interpolation==P1Enum);

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=PentaInput2Enum) _error_("cannot add a bool to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new PentaInput2(this->numberofelements_local,this->numberofvertices_local,interpolation);
	}

	/*Set input*/
	PentaInput2* input = xDynamicCast<PentaInput2*>(this->inputs[id]);
	input->SetInput(interpolation,row,value);
}/*}}}*/
void Inputs2::SetPentaInput(int enum_in,int interpolation,int numindices,int* indices,IssmDouble* values){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=PentaInput2Enum) _error_("cannot add Element values to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new PentaInput2(this->numberofelements_local,this->numberofvertices_local,interpolation);
	}

	/*Set input*/
	PentaInput2* input = xDynamicCast<PentaInput2*>(this->inputs[id]);
	input->SetInput(interpolation,numindices,indices,values);
}/*}}}*/
void Inputs2::SetPentaInput(int enum_in,int interpolation,int row,int numindices,IssmDouble* values){/*{{{*/

	/*Get input id*/
	int id = EnumToIndex(enum_in);

	/*Create it if necessary*/
	if(this->inputs[id]){
		if(this->inputs[id]->ObjectEnum()!=PentaInput2Enum) _error_("cannot add Element values to a "<<EnumToStringx(this->inputs[id]->ObjectEnum()));
	}
	else{
		this->inputs[id] = new PentaInput2(this->numberofelements_local,this->numberofvertices_local,interpolation);
	}

	/*Set input*/
	PentaInput2* input = xDynamicCast<PentaInput2*>(this->inputs[id]);
	input->SetInput(interpolation,row,numindices,values);
}/*}}}*/
