/*!\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: */
}
/*}}}*/
