/*!\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(){{{1*/
DoubleInput::DoubleInput(){
	return;
}
/*}}}*/
/*FUNCTION DoubleInput::DoubleInput(double value){{{1*/
DoubleInput::DoubleInput(int in_enum_type,IssmDouble in_value){

	enum_type=in_enum_type;
	value=in_value;
}
/*}}}*/
/*FUNCTION DoubleInput::~DoubleInput(){{{1*/
DoubleInput::~DoubleInput(){
	return;
}
/*}}}*/

/*Object virtual functions definitions:*/
		/*FUNCTION DoubleInput::Echo {{{1*/
void DoubleInput::Echo(void){
	this->DeepEcho();
}
/*}}}*/
/*FUNCTION DoubleInput::DeepEcho{{{1*/
void DoubleInput::DeepEcho(void){

	printf("DoubleInput:\n");
	printf("   enum: %i (%s)\n",this->enum_type,EnumToStringx(this->enum_type));
	printf("   value: %g\n",this->value);
}
/*}}}*/
/*FUNCTION DoubleInput::Id{{{1*/
int    DoubleInput::Id(void){ return -1; }
/*}}}*/
/*FUNCTION DoubleInput::MyRank{{{1*/
int    DoubleInput::MyRank(void){ 
	extern int my_rank;
	return my_rank; 
}
/*}}}*/
#ifdef _SERIAL_
/*FUNCTION DoubleInput::Marshall{{{1*/
void  DoubleInput::Marshall(char** pmarshalled_dataset){

	char* marshalled_dataset=NULL;
	int   enum_value=0;

	/*recover marshalled_dataset: */
	marshalled_dataset=*pmarshalled_dataset;

	/*get enum value of DoubleInput: */
	enum_value=DoubleInputEnum;
	
	/*marshall enum: */
	memcpy(marshalled_dataset,&enum_value,sizeof(enum_value));marshalled_dataset+=sizeof(enum_value);
	
	/*marshall DoubleInput data: */
	memcpy(marshalled_dataset,&enum_type,sizeof(enum_type));marshalled_dataset+=sizeof(enum_type);
	memcpy(marshalled_dataset,&value,sizeof(value));marshalled_dataset+=sizeof(value);

	*pmarshalled_dataset=marshalled_dataset;
}
/*}}}*/
/*FUNCTION DoubleInput::MarshallSize{{{1*/
int   DoubleInput::MarshallSize(){
	
	return sizeof(value)+
		+sizeof(enum_type)+
		+sizeof(int); //sizeof(int) for enum value
}
/*}}}*/
/*FUNCTION DoubleInput::Demarshall{{{1*/
void  DoubleInput::Demarshall(char** pmarshalled_dataset){

	char* marshalled_dataset=NULL;
	int   i;

	/*recover marshalled_dataset: */
	marshalled_dataset=*pmarshalled_dataset;

	/*this time, no need to get enum type, the pointer directly points to the beginning of the 
	 *object data (thanks to DataSet::Demarshall):*/
	memcpy(&enum_type,marshalled_dataset,sizeof(enum_type));marshalled_dataset+=sizeof(enum_type);
	memcpy(&value,marshalled_dataset,sizeof(value));marshalled_dataset+=sizeof(value);

	/*return: */
	*pmarshalled_dataset=marshalled_dataset;
	return;
}
/*}}}*/
#endif
/*FUNCTION DoubleInput::ObjectEnum{{{1*/
int DoubleInput::ObjectEnum(void){

	return DoubleInputEnum;

}
/*}}}*/
/*FUNCTION DoubleInput::copy{{{1*/
Object* DoubleInput::copy() {
	
	return new DoubleInput(this->enum_type,this->value);

}
/*}}}*/
	
/*DoubleInput management*/
/*FUNCTION DoubleInput::InstanceEnum{{{1*/
int DoubleInput::InstanceEnum(void){

	return this->enum_type;

}
/*}}}*/
/*FUNCTION DoubleInput::SpawnTriaInput{{{1*/
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{{{1*/
ElementResult* DoubleInput::SpawnResult(int step, double time){

	return new DoubleElementResult(this->enum_type,this->value,step,time);

}
/*}}}*/

/*Object functions*/
/*FUNCTION DoubleInput::GetInputValue(bool* pvalue) {{{1*/
void DoubleInput::GetInputValue(bool* pvalue){
#ifdef _SERIAL_
	*pvalue=(bool)value;
#else
	_error_("Double input of enum %s cannot return a boolean",EnumToStringx(enum_type));
#endif

}
/*}}}*/
/*FUNCTION DoubleInput::GetInputValue(int* pvalue){{{1*/
void DoubleInput::GetInputValue(int* pvalue){
#ifdef _SERIAL_
	*pvalue=(int)value;
#else
	_error_("Double input of enum %i (%s) cannot return an integer",enum_type,EnumToStringx(enum_type));
#endif

}
/*}}}*/
/*FUNCTION DoubleInput::GetInputValue(double* pvalue){{{1*/
void DoubleInput::GetInputValue(double* pvalue){

	/*return value*/
	*pvalue=value;
}
/*}}}*/
/*FUNCTION DoubleInput::GetInputValue(double* pvalue,GaussTria* gauss){{{1*/
void DoubleInput::GetInputValue(double* pvalue,GaussTria* gauss){*pvalue=this->value;}
/*}}}*/
/*FUNCTION DoubleInput::GetInputValue(double* pvalue,GaussPenta* gauss){{{1*/
void DoubleInput::GetInputValue(double* pvalue,GaussPenta* gauss){*pvalue=this->value;}
/*}}}*/
/*FUNCTION DoubleInput::GetInputDerivativeValue(double* derivativevalues, double* xyz_list, GaussTria* gauss){{{1*/
void DoubleInput::GetInputDerivativeValue(double* derivativevalues, double* xyz_list, GaussTria* gauss){_error_(" not supported yet!");}
/*}}}*/
/*FUNCTION DoubleInput::GetInputDerivativeValue(double* derivativevalues, double* xyz_list, GaussPenta* gauss){{{1*/
void DoubleInput::GetInputDerivativeValue(double* derivativevalues, double* xyz_list, GaussPenta* gauss){_error_(" not supported yet!");}
/*}}}*/
/*FUNCTION DoubleInput::GetVxStrainRate2d(double* epsilonvx,double* xyz_list, GaussTria* gauss){{{1*/
void DoubleInput::GetVxStrainRate2d(double* epsilonvx,double* 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(double* epsilonvy,double* xyz_list, GaussTria* gauss){{{1*/
void DoubleInput::GetVyStrainRate2d(double* epsilonvy,double* 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(double* epsilonvx,double* xyz_list, GaussPenta* gauss){{{1*/
void DoubleInput::GetVxStrainRate3d(double* epsilonvx,double* 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(double* epsilonvy,double* xyz_list, GaussPenta* gauss){{{1*/
void DoubleInput::GetVyStrainRate3d(double* epsilonvy,double* 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(double* epsilonvz,double* xyz_list, GaussPenta* gauss){{{1*/
void DoubleInput::GetVzStrainRate3d(double* epsilonvz,double* 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(double* epsilonvx,double* xyz_list, GaussPenta* gauss){{{1*/
void DoubleInput::GetVxStrainRate3dPattyn(double* epsilonvx,double* 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(double* epsilonvy,double* xyz_list, GaussPenta* gauss){{{1*/
void DoubleInput::GetVyStrainRate3dPattyn(double* epsilonvy,double* 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{{{1*/
void DoubleInput::ChangeEnum(int newenumtype){
	this->enum_type=newenumtype;
}
/*}}}*/
/*FUNCTION DoubleInput::SquareMin{{{1*/
void DoubleInput::SquareMin(double* psquaremin, bool process_units,Parameters* parameters){

	/*square min of a double is the square of the double itself: */
	*psquaremin=pow(value,2);
}
/*}}}*/
/*FUNCTION DoubleInput::Scale{{{1*/
void DoubleInput::Scale(double scale_factor){
	value=value*scale_factor;
}
/*}}}*/
/*FUNCTION DoubleInput::ConstrainMin{{{1*/
void DoubleInput::ConstrainMin(double minimum){
	if (value<minimum) value=minimum;
}
/*}}}*/
/*FUNCTION DoubleInput::AXPY{{{1*/
void DoubleInput::AXPY(Input* xinput,double scalar){

	DoubleInput*  xdoubleinput=NULL;

	/*xinput is of the same type, so cast it: */
	xdoubleinput=(DoubleInput*)xinput;

	/*Carry out the AXPY operation depending on type:*/
	switch(xinput->ObjectEnum()){

		case DoubleInputEnum:
			this->value=this->value+scalar*xdoubleinput->value;
			return;

		default:
			_error_("not implemented yet");
	}

}
/*}}}*/
/*FUNCTION DoubleInput::Constrain{{{1*/
void DoubleInput::Constrain(double cm_min, double cm_max){

	if(!isnan(cm_min)) if (this->value<cm_min)this->value=cm_min;
	if(!isnan(cm_max)) if (this->value>cm_max)this->value=cm_max;

}
/*}}}*/
/*FUNCTION DoubleInput::Max{{{1*/
double DoubleInput::Max(void){
	return this->value;
}
/*}}}*/
/*FUNCTION DoubleInput::MaxAbs{{{1*/
double DoubleInput::MaxAbs(void){
	return fabs(this->value);
}
/*}}}*/
/*FUNCTION DoubleInput::Min{{{1*/
double DoubleInput::Min(void){
	return this->value;
}
/*}}}*/
/*FUNCTION DoubleInput::MinAbs{{{1*/
double DoubleInput::MinAbs(void){
	return fabs(this->value);
}
/*}}}*/
/*FUNCTION DoubleInput::GetVectorFromInputs{{{1*/
void DoubleInput::GetVectorFromInputs(Vec vector,int* doflist){

	_error_(" not supporte yet!");

}
/*}}}*/
/*FUNCTION DoubleInput::GetValuesPtr{{{1*/
void DoubleInput::GetValuesPtr(double** pvalues,int* pnum_values){

	_error_(" not supported yet!");

}
/*}}}*/
/*FUNCTION DoubleInput::GetInputAverage{{{1*/
void DoubleInput::GetInputAverage(double* pvalue){
	*pvalue=value;
}
/*}}}*/
/*FUNCTION DoubleInput::VerticallyIntegrate{{{1*/
void DoubleInput::VerticallyIntegrate(Input* thickness_input){

	/*Intermediaries*/
	double thickness_value;

	/*Check that input provided is a thickness*/
	if (thickness_input->InstanceEnum()!=ThicknessEnum) _error_("Input provided is not a Thickness (enum_type is %s)",EnumToStringx(thickness_input->InstanceEnum()));

	/*vertically integrate depending on type:*/
	switch(thickness_input->ObjectEnum()){

		case PentaP1InputEnum:
			thickness_input->GetInputAverage(&thickness_value);
			this->value=this->value*thickness_value;
			return;

		default:
			_error_("not implemented yet");
	}
}
/*}}}*/
/*FUNCTION DoubleInput::PointwiseDivide{{{1*/
Input* DoubleInput::PointwiseDivide(Input* inputB){

	/*Ouput*/
	DoubleInput* outinput=NULL;

	/*Intermediaries*/
	double       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{{{1*/
Input* DoubleInput::PointwiseMin(Input* input){

	/*Ouput*/
	DoubleInput* outinput=NULL;

	/*Intermediaries*/
	double       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{{{1*/
Input* DoubleInput::PointwiseMax(Input* input){

	/*Ouput*/
	DoubleInput* outinput=NULL;

	/*Intermediaries*/
	double       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{{{1*/
void DoubleInput::Configure(Parameters* parameters){
	/*do nothing: */
}
/*}}}*/
