/*
 * ModelCreateParameters.c:
 */

#undef __FUNCT__ 
#define __FUNCT__ "ModelCreateParameters"

#include "../DataSet/DataSet.h"
#include "../toolkits/toolkits.h"
#include "../EnumDefinitions/EnumDefinitions.h"
#include "../objects/objects.h"
#include "../shared/shared.h"
#include "./ModelProcessorx.h"

int ModelCreateParameters(DataSet** pparameters,Model* model,ConstDataHandle model_handle){
	
	int noerr=1;
	int i;
	
	DataSet* parameters = NULL;
	Param*   param = NULL;
	int      count=1;
	int      analysis_type;
	int      numberofdofspernode;

	double* fit=NULL;
	double* optscal=NULL;
	double* maxiter=NULL; 
	double* control_parameter=NULL;
	
	
	
	/*Initialize dataset: */
	parameters   = new DataSet(ParametersEnum());

	//Get analysis_type:
	analysis_type=AnalysisTypeAsEnum(model->analysis_type);
	
	count++;
	param= new Param(count,"analysis_type",INTEGER);
	param->SetInteger(analysis_type);
	parameters->AddObject(param);

	
	/*debug: */
	param= new Param(count,"debug",INTEGER);
	param->SetInteger(model->debug);
	parameters->AddObject(param);

	/*eps_rel: */
	count++;
	param= new Param(count,"eps_rel",DOUBLE);
	param->SetDouble(model->eps_rel);
	parameters->AddObject(param);

	/*eps_abs: */
	count++;
	param= new Param(count,"eps_abs",DOUBLE);
	param->SetDouble(model->eps_abs);
	parameters->AddObject(param);

	/*dt: */
	count++;
	param= new Param(count,"dt",DOUBLE);
	param->SetDouble(model->dt);
	parameters->AddObject(param);

	/*ndt: */
	count++;
	param= new Param(count,"ndt",DOUBLE);
	param->SetDouble(model->ndt);
	parameters->AddObject(param);

	/*penalty_offset: */
	count++;
	param= new Param(count,"penalty_offset",DOUBLE);
	param->SetDouble(model->penalty_offset);
	parameters->AddObject(param);

	/*sparsity: */
	count++;
	param= new Param(count,"sparsity",DOUBLE);
	param->SetDouble(model->sparsity);
	parameters->AddObject(param);

	/*lowmem: */
	count++;
	param= new Param(count,"lowmem",INTEGER);
	param->SetInteger(model->lowmem);
	parameters->AddObject(param);

	/*connectivity: */
	count++;
	param= new Param(count,"connectivity",INTEGER);
	param->SetInteger(model->connectivity);
	parameters->AddObject(param);

	/*beta: */
	count++;
	param= new Param(count,"beta",DOUBLE);
	param->SetDouble(model->beta);
	parameters->AddObject(param);

	/*meltingpoint: */
	count++;
	param= new Param(count,"meltingpoint",DOUBLE);
	param->SetDouble(model->meltingpoint);
	parameters->AddObject(param);

	/*latentheat: */
	count++;
	param= new Param(count,"latentheat",DOUBLE);
	param->SetDouble(model->latentheat);
	parameters->AddObject(param);

	/*heatcapacity: */
	count++;
	param= new Param(count,"heatcapacity",DOUBLE);
	param->SetDouble(model->heatcapacity);
	parameters->AddObject(param);

	/*penalty_melting: */
	count++;
	param= new Param(count,"penalty_melting",DOUBLE);
	param->SetDouble(model->penalty_melting);
	parameters->AddObject(param);

	/*min_thermal_constraints: */
	count++;
	param= new Param(count,"min_thermal_constraints",INTEGER);
	param->SetInteger(model->min_thermal_constraints);
	parameters->AddObject(param);

	/*waitonlock: */
	count++;
	param= new Param(count,"waitonlock",INTEGER);
	param->SetInteger(model->waitonlock);
	parameters->AddObject(param);

	/*solverstring: */
	count++;
	param= new Param(count,"solverstring",STRING);
	param->SetString(model->solverstring);
	parameters->AddObject(param);

	/*plot: */
	count++;
	param= new Param(count,"plot",INTEGER);
	param->SetInteger(model->plot);
	parameters->AddObject(param);

	/*numberofgrids: */
	count++;
	param= new Param(count,"numberofnodes",INTEGER);
	param->SetInteger(model->numberofnodes);
	parameters->AddObject(param);

	/*Deal with numberofdofspernode: */
	DistributeNumDofs(&numberofdofspernode,analysis_type);

	count++;
	param= new Param(count,"numberofdofspernode",INTEGER);
	param->SetInteger(numberofdofspernode);
	parameters->AddObject(param);

	/*All our datasets are already ordered by ids. Set presort flag so that later on, when sorting is requested on these 
	 * datasets, it will not be redone: */
	parameters->Presort();

	/*Deal with control parameters: */
	if (analysis_type==ControlAnalysisEnum()){

		/*control_type: */
		count++;
		param= new Param(count,"control_type",STRING);
		param->SetString(model->control_type);
		parameters->AddObject(param);


		/*nsteps: */
		count++;
		param= new Param(count,"nsteps",INTEGER);
		param->SetInteger(model->nsteps);
		parameters->AddObject(param);

		/*tolx: */
		count++;
		param= new Param(count,"tolx",DOUBLE);
		param->SetDouble(model->tolx);
		parameters->AddObject(param);

		/*mincontrolconstraint: */
		count++;
		param= new Param(count,"mincontrolconstraint",DOUBLE);
		param->SetDouble(model->mincontrolconstraint);
		parameters->AddObject(param);

		/*maxcontrolconstraint: */
		count++;
		param= new Param(count,"maxcontrolconstraint",DOUBLE);
		param->SetDouble(model->maxcontrolconstraint);
		parameters->AddObject(param);
		
		/*epsvel: */
		count++;
		param= new Param(count,"epsvel",DOUBLE);
		param->SetDouble(model->epsvel);
		parameters->AddObject(param);
		
		/*meanvel: */
		count++;
		param= new Param(count,"meanvel",DOUBLE);
		param->SetDouble(model->meanvel);
		parameters->AddObject(param);

		/*Now, recover fit, optscal and maxiter as vectors: */
		ModelFetchData((void**)&model->fit,NULL,NULL,model_handle,"fit","Matrix","Mat");
		ModelFetchData((void**)&model->optscal,NULL,NULL,model_handle,"optscal","Matrix","Mat");
		ModelFetchData((void**)&model->maxiter,NULL,NULL,model_handle,"maxiter","Matrix","Mat");
	
		count++;
		param= new Param(count,"fit",DOUBLEVEC);
		param->SetDoubleVec(model->fit,model->nsteps);
		parameters->AddObject(param);

		count++;
		param= new Param(count,"optscal",DOUBLEVEC);
		param->SetDoubleVec(model->optscal,model->nsteps);
		parameters->AddObject(param);

		count++;
		param= new Param(count,"maxiter",DOUBLEVEC);
		param->SetDoubleVec(model->maxiter,model->nsteps);
		parameters->AddObject(param);
	
		xfree((void**)&model->fit);
		xfree((void**)&model->optscal);
		xfree((void**)&model->maxiter);

		/*Get vx_obs, vy_obs, and the parameter value: */
		ModelFetchData((void**)&model->vx_obs,NULL,NULL,model_handle,"vx_obs","Matrix","Mat");
		ModelFetchData((void**)&model->vy_obs,NULL,NULL,model_handle,"vy_obs","Matrix","Mat");
		ModelFetchData((void**)&control_parameter,NULL,NULL,model_handle,model->control_type,"Matrix","Mat");

		for(i=0;i<model->numberofnodes;i++)model->vx_obs[i]=model->vx_obs[i]/model->yts;
		for(i=0;i<model->numberofnodes;i++)model->vy_obs[i]=model->vy_obs[i]/model->yts;

		count++;
		param= new Param(count,"vx_obs",DOUBLEVEC);
		param->SetDoubleVec(model->vx_obs,model->numberofnodes);
		parameters->AddObject(param);

		count++;
		param= new Param(count,"vy_obs",DOUBLEVEC);
		param->SetDoubleVec(model->vy_obs,model->numberofnodes);
		parameters->AddObject(param);

		count++;
		param= new Param(count,"control_parameter",DOUBLEVEC);
		param->SetDoubleVec(control_parameter,model->numberofnodes);
		parameters->AddObject(param);
		
		xfree((void**)&model->vx_obs);
		xfree((void**)&model->vy_obs);
		xfree((void**)&control_parameter);


	}

	/*Assign output pointer: */
	*pparameters=parameters;
}

	
