/*!\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(){{{1*/
TriaP1Input::TriaP1Input(){
	return;
}
/*}}}*/
/*FUNCTION TriaP1Input::TriaP1Input(int in_enum_type,double* values){{{1*/
TriaP1Input::TriaP1Input(int in_enum_type,double* 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(){{{1*/
TriaP1Input::~TriaP1Input(){
	return;
}
/*}}}*/

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

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

	char* marshalled_dataset=NULL;
	int   enum_value=0;

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

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

	*pmarshalled_dataset=marshalled_dataset;
}
/*}}}*/
/*FUNCTION TriaP1Input::MarshallSize{{{1*/
int   TriaP1Input::MarshallSize(){
	
	return sizeof(values)+
		+sizeof(enum_type)+
		+sizeof(int); //sizeof(int) for enum value
}
/*}}}*/
/*FUNCTION TriaP1Input::Demarshall{{{1*/
void  TriaP1Input::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(&values,marshalled_dataset,sizeof(values));marshalled_dataset+=sizeof(values);

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

	return TriaP1InputEnum;

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

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

	return this->enum_type;

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

	return new TriaP1ElementResult(this->enum_type,this->values,step,time);

}
/*}}}*/

/*Object functions*/
/*FUNCTION TriaP1Input::GetInputValue(double* pvalue,GaussTria* gauss){{{1*/
void TriaP1Input::GetInputValue(double* pvalue,GaussTria* gauss){

	/*Call TriaRef function*/
	TriaRef::GetInputValue(pvalue,&values[0],gauss);

}
/*}}}*/
/*FUNCTION TriaP1Input::GetInputDerivativeValue(double* p, double* xyz_list, GaussTria* gauss){{{1*/
void TriaP1Input::GetInputDerivativeValue(double* p, double* xyz_list, GaussTria* gauss){

	/*Call TriaRef function*/
	TriaRef::GetInputDerivativeValue(p,&values[0],xyz_list,gauss);
}
/*}}}*/
/*FUNCTION TriaP1Input::GetVxStrainRate2d{{{1*/
void TriaP1Input::GetVxStrainRate2d(double* epsilonvx,double* xyz_list, GaussTria* gauss){

	/*Intermediary*/
	int       i;
	const int numnodes=3;
	double B[3][NDOF2*numnodes];
	double 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{{{1*/
void TriaP1Input::GetVyStrainRate2d(double* epsilonvy,double* xyz_list, GaussTria* gauss){

	/*Intermediary*/
	int       i;
	const int numnodes=3;
	double B[3][NDOF2*numnodes];
	double 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{{{1*/
void TriaP1Input::ChangeEnum(int newenumtype){
	this->enum_type=newenumtype;
}
/*}}}*/
/*FUNCTION TriaP1Input::GetInputAverage{{{1*/
void TriaP1Input::GetInputAverage(double* pvalue){
	*pvalue=1./3.*(values[0]+values[1]+values[2]);
}
/*}}}*/

/*Intermediary*/
/*FUNCTION TriaP1Input::SquareMin{{{1*/
void TriaP1Input::SquareMin(double* psquaremin, bool process_units,Parameters* parameters){

	int i;
	const int numnodes=3;
	double valuescopy[numnodes];
	double 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{{{1*/
void TriaP1Input::ConstrainMin(double minimum){
	
	int i;
	const int numnodes=3;

	for(i=0;i<numnodes;i++) if (values[i]<minimum) values[i]=minimum;
}
/*}}}*/
/*FUNCTION TriaP1Input::InfinityNorm{{{1*/
double TriaP1Input::InfinityNorm(void){

	/*Output*/
	double 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{{{1*/
double TriaP1Input::Max(void){

	const int numnodes=3;
	double    max=values[0];

	for(int i=1;i<numnodes;i++){
		if(values[i]>max) max=values[i];
	}
	return max;
}
/*}}}*/
/*FUNCTION TriaP1Input::MaxAbs{{{1*/
double TriaP1Input::MaxAbs(void){

	const int numnodes=3;
	double    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{{{1*/
double TriaP1Input::Min(void){

	const int numnodes=3;
	double    min=values[0];

	for(int i=1;i<numnodes;i++){
		if(values[i]<min) min=values[i];
	}
	return min;
}
/*}}}*/
/*FUNCTION TriaP1Input::MinAbs{{{1*/
double TriaP1Input::MinAbs(void){

	const int numnodes=3;
	double    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{{{1*/
void TriaP1Input::Scale(double scale_factor){
	
	int i;
	const int numnodes=3;

	for(i=0;i<numnodes;i++)values[i]=values[i]*scale_factor;
}
/*}}}*/
/*FUNCTION TriaP1Input::ArtificialNoise{{{1*/
void TriaP1Input::ArtificialNoise(double min,double max){

	int i;
	const int numnodes=3;
	double noise;

	/*Compute random number between bounds:
	 * rand() outputs an integer in [0 RAND_MAX]
	 * (double)rand()/RAND_MAX is in [0 1]
	 */
	 noise=min+(max-min)*(double)rand()/RAND_MAX;

	for(i=0;i<numnodes;i++)values[i]=values[i]+noise;
}
/*}}}*/
/*FUNCTION TriaP1Input::AXPY{{{1*/
void TriaP1Input::AXPY(Input* xinput,double 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 :
			_error_("not implemented yet");
	}

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

	int i;
	const int numnodes=3;
		
	if(!isnan(cm_min)) for(i=0;i<numnodes;i++)if (this->values[i]<cm_min)this->values[i]=cm_min;
	if(!isnan(cm_max)) for(i=0;i<numnodes;i++)if (this->values[i]>cm_max)this->values[i]=cm_max;

}
/*}}}*/
/*FUNCTION TriaP1Input::GetVectorFromInputs{{{1*/
void TriaP1Input::GetVectorFromInputs(Vec vector,int* doflist){

	const int numvertices=3;
	VecSetValues(vector,numvertices,doflist,(const double*)this->values,INSERT_VALUES);

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

	*pvalues=this->values;
	if(pnum_values)*pnum_values=3;

}
/*}}}*/
/*FUNCTION TriaP1Input::PointwiseMin{{{1*/
Input* TriaP1Input::PointwiseMin(Input* inputB){

	/*Ouput*/
	TriaP1Input* outinput=NULL;

	/*Intermediaries*/
	int               i;
	TriaP1Input *xinputB     = NULL;
	int               B_numvalues;
	const int         numnodes    = 3;
	double            minvalues[numnodes];

	/*Check that inputB is of the same type*/
	if (inputB->ObjectEnum()!=TriaP1InputEnum) _error_("Operation not permitted because inputB is of type %s",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{{{1*/
Input* TriaP1Input::PointwiseMax(Input* inputB){

	/*Ouput*/
	TriaP1Input* outinput=NULL;

	/*Intermediaries*/
	int               i;
	TriaP1Input *xinputB     = NULL;
	int               B_numvalues;
	const int         numnodes    = 3;
	double            maxvalues[numnodes];

	/*Check that inputB is of the same type*/
	if (inputB->ObjectEnum()!=TriaP1InputEnum) _error_("Operation not permitted because inputB is of type %s",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{{{1*/
void TriaP1Input::Configure(Parameters* parameters){
	/*do nothing: */
}
/*}}}*/
