/*!\file Penta.c
 * \brief: implementation of the Penta 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 "./Penta.h"
#include <string.h>
#include "../EnumDefinitions/EnumDefinitions.h"
#include "../shared/shared.h"

Penta::Penta(){
	return;
}
Penta::Penta( int penta_id, int penta_mid, int penta_mparid, int penta_node_ids[6], double penta_h[6], double penta_s[6], double penta_b[6], double penta_k[6], int penta_friction_type, 
				double penta_p, double penta_q, int penta_shelf, int penta_onbed, int penta_onsurface, double penta_fit, double penta_meanvel,double penta_epsvel, 
				int penta_acceleration, int penta_collapse, double penta_melting[6], double penta_accumulation[6], double penta_geothermalflux[6], 
				int penta_artdiff, int penta_thermal_steadystate){
	
	int i;

	id = penta_id;
	mid = penta_mid; 
	mparid = penta_mparid; 

	for(i =0;i<6;i++){
		node_ids[i] = penta_node_ids[i]; 
		h[i] = penta_h[i]; 
		s[i] = penta_s[i]; 
		b[i] = penta_b[i]; 
		k[i] = penta_k[i]; 
		melting[i] = penta_melting[i]; 
		accumulation[i] = penta_accumulation[i] ;
		geothermalflux[i] = penta_geothermalflux[i]; 
	}

	friction_type = penta_friction_type; 
	p = penta_p; 
	q = penta_q; 
	shelf = penta_shelf; 
	onbed = penta_onbed; 
	onsurface = penta_onsurface; 
	fit = penta_fit; 
	meanvel = penta_meanvel;
	epsvel = penta_epsvel; 
	acceleration = penta_acceleration; 
	collapse = penta_collapse; 
	artdiff = penta_artdiff; 
	thermal_steadystate = penta_thermal_steadystate;

	return;
}

Penta::~Penta(){
	return;
}
void Penta::Echo(void){

	printf("Penta:\n");
	printf("   id: %i\n",id);
	printf("   mid: %i\n",mid);
	printf("   mparid: %i\n",mparid);

	printf("   nodes=[%i,%i,%i,%i,%i,%i]\n",node_ids[0],node_ids[1],node_ids[2],node_ids[3],node_ids[4],node_ids[5]);
	printf("   h=[%i,%i,%i,%i,%i,%i]\n",h[0],h[1],h[2],h[3],h[4],h[5]);
	printf("   s=[%i,%i,%i,%i,%i,%i]\n",s[0],s[1],s[2],s[3],s[4],s[5]);
	printf("   b=[%i,%i,%i,%i,%i,%i]\n",b[0],b[1],b[2],b[3],b[4],b[5]);
	printf("   k=[%i,%i,%i,%i,%i,%i]\n",k[0],k[1],k[2],k[3],k[4],k[5]);
	
	printf("   friction_type: %i\n",friction_type);
	printf("   p: %g\n",p);
	printf("   q: %g\n",q);
	printf("   shelf: %i\n",shelf);
	printf("   onbed: %i\n",onbed);
	printf("   onsurface: %i\n",onsurface);
	printf("   fit: %g\n",fit);
	printf("   meanvel: %g\n",meanvel);
	printf("   epsvel: %g\n",epsvel);
	printf("   acceleration: %i\n",acceleration);
	printf("   collapse: %i\n",collapse);
	
	printf("   melting=[%i,%i,%i,%i,%i,%i]\n",melting[0],melting[1],melting[2],melting[3],melting[4],melting[5]);
	printf("   accumulation=[%i,%i,%i,%i,%i,%i]\n",accumulation[0],accumulation[1],accumulation[2],accumulation[3],accumulation[4],accumulation[5]);
	printf("   geothermalflux=[%i,%i,%i,%i,%i,%i]\n",geothermalflux[0],geothermalflux[1],geothermalflux[2],geothermalflux[3],geothermalflux[4],geothermalflux[5]);
	printf("   artdiff: %i\n",artdiff);
	printf("   thermal_steadystate: %i\n",thermal_steadystate);
	return;
}

void  Penta::Marshall(char** pmarshalled_dataset){

	char* marshalled_dataset=NULL;
	int   enum_type=0;

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

	/*get enum type of Penta: */
	enum_type=PentaEnum();
	
	/*marshall enum: */
	memcpy(marshalled_dataset,&enum_type,sizeof(enum_type));marshalled_dataset+=sizeof(enum_type);
	
	/*marshall Penta data: */
	memcpy(marshalled_dataset,&id,sizeof(id));marshalled_dataset+=sizeof(id);
	memcpy(marshalled_dataset,&mid,sizeof(mid));marshalled_dataset+=sizeof(mid);
	memcpy(marshalled_dataset,&mparid,sizeof(mparid));marshalled_dataset+=sizeof(mparid);
	memcpy(marshalled_dataset,&node_ids,sizeof(node_ids));marshalled_dataset+=sizeof(node_ids);
	memcpy(marshalled_dataset,&h,sizeof(h));marshalled_dataset+=sizeof(h);
	memcpy(marshalled_dataset,&s,sizeof(s));marshalled_dataset+=sizeof(s);
	memcpy(marshalled_dataset,&b,sizeof(b));marshalled_dataset+=sizeof(b);
	memcpy(marshalled_dataset,&k,sizeof(k));marshalled_dataset+=sizeof(k);
	memcpy(marshalled_dataset,&friction_type,sizeof(friction_type));marshalled_dataset+=sizeof(friction_type);
	memcpy(marshalled_dataset,&p,sizeof(p));marshalled_dataset+=sizeof(p);
	memcpy(marshalled_dataset,&q,sizeof(q));marshalled_dataset+=sizeof(q);
	memcpy(marshalled_dataset,&shelf,sizeof(shelf));marshalled_dataset+=sizeof(shelf);
	memcpy(marshalled_dataset,&onbed,sizeof(onbed));marshalled_dataset+=sizeof(onbed);
	memcpy(marshalled_dataset,&onsurface,sizeof(onsurface));marshalled_dataset+=sizeof(onsurface);
	memcpy(marshalled_dataset,&fit,sizeof(fit));marshalled_dataset+=sizeof(fit);
	memcpy(marshalled_dataset,&meanvel,sizeof(meanvel));marshalled_dataset+=sizeof(meanvel);
	memcpy(marshalled_dataset,&epsvel,sizeof(epsvel));marshalled_dataset+=sizeof(epsvel);
	memcpy(marshalled_dataset,&acceleration,sizeof(acceleration));marshalled_dataset+=sizeof(acceleration);
	memcpy(marshalled_dataset,&collapse,sizeof(collapse));marshalled_dataset+=sizeof(collapse);
	memcpy(marshalled_dataset,&melting,sizeof(melting));marshalled_dataset+=sizeof(melting);
	memcpy(marshalled_dataset,&accumulation,sizeof(accumulation));marshalled_dataset+=sizeof(accumulation);
	memcpy(marshalled_dataset,&geothermalflux,sizeof(geothermalflux));marshalled_dataset+=sizeof(geothermalflux);
	memcpy(marshalled_dataset,&artdiff,sizeof(artdiff));marshalled_dataset+=sizeof(artdiff);
	memcpy(marshalled_dataset,&thermal_steadystate,sizeof(thermal_steadystate));marshalled_dataset+=sizeof(thermal_steadystate);
	
	*pmarshalled_dataset=marshalled_dataset;
	return;
}
		
int   Penta::MarshallSize(){

	return sizeof(id)+sizeof(mid)+sizeof(mparid)+sizeof(node_ids)+sizeof(h)+sizeof(s)+sizeof(b)+sizeof(k)+sizeof(friction_type)+sizeof(p)+sizeof(q)+sizeof(shelf)+sizeof(onbed)+sizeof(onsurface)+sizeof(fit)+sizeof(meanvel)+sizeof(epsvel)+sizeof(acceleration)+sizeof(collapse)+sizeof(melting)+sizeof(accumulation)+sizeof(geothermalflux)+sizeof(artdiff)+sizeof(thermal_steadystate) +sizeof(int); //sizeof(int) for enum type
}

char* Penta::GetName(void){
	return "penta";
}

void  Penta::Demarshall(char** pmarshalled_dataset){

	char* marshalled_dataset=NULL;

	/*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(&id,marshalled_dataset,sizeof(id));marshalled_dataset+=sizeof(id);
	memcpy(&mid,marshalled_dataset,sizeof(mid));marshalled_dataset+=sizeof(mid);
	memcpy(&mparid,marshalled_dataset,sizeof(mparid));marshalled_dataset+=sizeof(mparid);
	memcpy(&node_ids,marshalled_dataset,sizeof(node_ids));marshalled_dataset+=sizeof(node_ids);
	memcpy(&h,marshalled_dataset,sizeof(h));marshalled_dataset+=sizeof(h);
	memcpy(&s,marshalled_dataset,sizeof(s));marshalled_dataset+=sizeof(s);
	memcpy(&b,marshalled_dataset,sizeof(b));marshalled_dataset+=sizeof(b);
	memcpy(&k,marshalled_dataset,sizeof(k));marshalled_dataset+=sizeof(k);
	memcpy(&friction_type,marshalled_dataset,sizeof(friction_type));marshalled_dataset+=sizeof(friction_type);
	memcpy(&p,marshalled_dataset,sizeof(p));marshalled_dataset+=sizeof(p);
	memcpy(&q,marshalled_dataset,sizeof(q));marshalled_dataset+=sizeof(q);
	memcpy(&shelf,marshalled_dataset,sizeof(shelf));marshalled_dataset+=sizeof(shelf);
	memcpy(&onbed,marshalled_dataset,sizeof(onbed));marshalled_dataset+=sizeof(onbed);
	memcpy(&onsurface,marshalled_dataset,sizeof(onsurface));marshalled_dataset+=sizeof(onsurface);
	memcpy(&fit,marshalled_dataset,sizeof(fit));marshalled_dataset+=sizeof(fit);
	memcpy(&meanvel,marshalled_dataset,sizeof(meanvel));marshalled_dataset+=sizeof(meanvel);
	memcpy(&epsvel,marshalled_dataset,sizeof(epsvel));marshalled_dataset+=sizeof(epsvel);
	memcpy(&acceleration,marshalled_dataset,sizeof(acceleration));marshalled_dataset+=sizeof(acceleration);
	memcpy(&collapse,marshalled_dataset,sizeof(collapse));marshalled_dataset+=sizeof(collapse);
	memcpy(&melting,marshalled_dataset,sizeof(melting));marshalled_dataset+=sizeof(melting);
	memcpy(&accumulation,marshalled_dataset,sizeof(accumulation));marshalled_dataset+=sizeof(accumulation);
	memcpy(&geothermalflux,marshalled_dataset,sizeof(geothermalflux));marshalled_dataset+=sizeof(geothermalflux);
	memcpy(&artdiff,marshalled_dataset,sizeof(artdiff));marshalled_dataset+=sizeof(artdiff);
	memcpy(&thermal_steadystate,marshalled_dataset,sizeof(thermal_steadystate));marshalled_dataset+=sizeof(thermal_steadystate);

	/*return: */
	*pmarshalled_dataset=marshalled_dataset;
	return;
}
int Penta::Enum(void){

	return PentaEnum();

}
int    Penta::GetId(void){ return id; }

int    Penta::MyRank(void){ 
	extern int my_rank;
	return my_rank; 
}

#undef __FUNCT__ 
#define __FUNCT__ "Penta::Configure"
void  Penta::Configure(void* loads,void* nodes,void* materials){

	throw ErrorException(__FUNCT__," not supported yet!");

}
#undef __FUNCT__ 
#define __FUNCT__ "Penta::CreateKMatrix"

void  Penta::CreateKMatrix(Mat Kgg,ParameterInputs* inputs,int analysis_type){

	throw ErrorException(__FUNCT__," not supported yet!");

}

#undef __FUNCT__ 
#define __FUNCT__ "Penta::CreatePVector"
void  Penta::CreatePVector(Vec pg, ParameterInputs* inputs, int analysis_type){
	
	throw ErrorException(__FUNCT__," not supported yet!");

}
#undef __FUNCT__ 
#define __FUNCT__ "Penta::UpdateFromInputs"
void  Penta::UpdateFromInputs(ParameterInputs* inputs){
	
	throw ErrorException(__FUNCT__," not supported yet!");

}

Matpar* Penta::GetMatPar(){
	return matpar;
}

int   Penta::GetShelf(){
	return shelf;
}


void  Penta::GetNodes(Node** pnodes){
	int i;
	for(i=0;i<6;i++){
		pnodes[i]=nodes[i];
	}
}
		
int Penta::GetOnBed(){
	return onbed;
}

void          Penta::GetThicknessList(double* thickness_list){

	int i;
	for(i=0;i<6;i++)thickness_list[i]=h[i];
}
void          Penta::GetBedList(double* bed_list){
	
	int i;
	for(i=0;i<6;i++)bed_list[i]=b[i];

}

Object* Penta::copy() {
	return new Penta(*this); 
}

#undef __FUNCT__ 
#define __FUNCT__ "Penta::Du"
void  Penta::Du(Vec du_g,double* u_g,double* u_g_obs,ParameterInputs* inputs,int analysis_type){
	
	throw ErrorException(__FUNCT__," not supported yet!");


}

#undef __FUNCT__ 
#define __FUNCT__ "Penta::Gradj"
void  Penta::Gradj(Vec grad_g,double* u_g,double* lambda_g,ParameterInputs* inputs,int analysis_type,char* control_type){
	throw ErrorException(__FUNCT__," not supported yet!");
}
#undef __FUNCT__ 
#define __FUNCT__ "Penta::GradjDrag"
void  Penta::GradjDrag(Vec grad_g,double* u_g,double* lambda_g,ParameterInputs* inputs,int analysis_type){
	throw ErrorException(__FUNCT__," not supported yet!");
}
#undef __FUNCT__ 
#define __FUNCT__ "Penta::GradjB"
void  Penta::GradjB(Vec grad_g,double* u_g,double* lambda_g,ParameterInputs* inputs,int analysis_type){
	throw ErrorException(__FUNCT__," not supported yet!");
}
        
#undef __FUNCT__ 
#define __FUNCT__ "Penta::Misfit"
double Penta::Misfit(double* u_g,double* u_g_obs,ParameterInputs* inputs,int analysis_type){
	throw ErrorException(__FUNCT__," not supported yet!");
}
