/*!\file: CreateParameters.cpp
 * \brief general driver for creating parameters dataset
 */ 

#ifdef HAVE_CONFIG_H
	#include <config.h>
#else
#error "Cannot compile with HAVE_CONFIG_H symbol! run configure first!"
#endif


#include "../../Container/Container.h"
#include "../../toolkits/toolkits.h"
#include "../../EnumDefinitions/EnumDefinitions.h"
#include "../../classes/objects/objects.h"
#include "../../shared/shared.h"
#include "../MeshPartitionx/MeshPartitionx.h"
#include "../../io/io.h"
#include "./ModelProcessorx.h"

void CreateParameters(Parameters** pparameters,IoModel* iomodel,const int solution_type,int analysis_type,int analysis_counter){
	
	int         i;
	int         numoutputs;
	Parameters *parameters       = NULL;
	IssmDouble *requestedoutputs = NULL;
	bool        isdelta18o;

	if(*pparameters)return; //do not create parameters twice!

	/*Initialize dataset: */
	parameters = new Parameters();
		
	/*Copy some constants from iomodel */
	parameters->AddObject(iomodel->CopyConstantObject(MeshDimensionEnum));
	parameters->AddObject(iomodel->CopyConstantObject(FlowequationIshutterEnum));
	parameters->AddObject(iomodel->CopyConstantObject(FlowequationIsmacayealpattynEnum));
	parameters->AddObject(iomodel->CopyConstantObject(FlowequationIsstokesEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SettingsOutputFrequencyEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticRestolEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticReltolEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticAbstolEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticIsnewtonEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticMaxiterEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SteadystateReltolEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SteadystateMaxiterEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ConstantsYtsEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TimesteppingStartTimeEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TimesteppingFinalTimeEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TimesteppingTimeAdaptEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TimesteppingTimeStepEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TimesteppingCflCoefficientEnum));
	parameters->AddObject(iomodel->CopyConstantObject(PrognosticHydrostaticAdjustmentEnum));
	parameters->AddObject(iomodel->CopyConstantObject(PrognosticStabilizationEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticPenaltyFactorEnum));
	parameters->AddObject(iomodel->CopyConstantObject(PrognosticMinThicknessEnum));
	parameters->AddObject(iomodel->CopyConstantObject(PrognosticPenaltyFactorEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ThermalPenaltyFactorEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SettingsLowmemEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DebugProfilingEnum));
	parameters->AddObject(iomodel->CopyConstantObject(MeshAverageVertexConnectivityEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ConstantsReferencetemperatureEnum));
	parameters->AddObject(iomodel->CopyConstantObject(BalancethicknessStabilizationEnum));
	parameters->AddObject(iomodel->CopyConstantObject(HydrologyStabilizationEnum));
	parameters->AddObject(iomodel->CopyConstantObject(GroundinglineMeltingRateEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ThermalMaxiterEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ThermalStabilizationEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ThermalPenaltyThresholdEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ThermalPenaltyLockEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticRiftPenaltyThresholdEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticStokesreconditioningEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticShelfDampeningEnum));
	parameters->AddObject(iomodel->CopyConstantObject(DiagnosticViscosityOvershootEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SettingsWaitonlockEnum));
	parameters->AddObject(iomodel->CopyConstantObject(MeshNumberofelementsEnum));
	parameters->AddObject(iomodel->CopyConstantObject(MeshNumberofverticesEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SettingsIoGatherEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SettingsResultsAsPatchesEnum));
	parameters->AddObject(iomodel->CopyConstantObject(GroundinglineMigrationEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TransientIsdiagnosticEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TransientIsprognosticEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TransientIsthermalEnum));
	parameters->AddObject(iomodel->CopyConstantObject(TransientIsgroundinglineEnum));
	parameters->AddObject(iomodel->CopyConstantObject(ThermalIsenthalpyEnum));
	parameters->AddObject(iomodel->CopyConstantObject(MaterialsRheologyLawEnum));
	parameters->AddObject(iomodel->CopyConstantObject(AutodiffIsautodiffEnum));
	parameters->AddObject(iomodel->CopyConstantObject(AutodiffForwardEnum));
	parameters->AddObject(iomodel->CopyConstantObject(AutodiffReverseEnum));
	parameters->AddObject(iomodel->CopyConstantObject(QmuIsdakotaEnum));
	parameters->AddObject(iomodel->CopyConstantObject(InversionIscontrolEnum));
	parameters->AddObject(iomodel->CopyConstantObject(InversionTaoEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SurfaceforcingsIspddEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SurfaceforcingsIsdelta18oEnum));
	parameters->AddObject(iomodel->CopyConstantObject(SurfaceforcingsIssmbgradientsEnum));

	iomodel->Constant(&isdelta18o,SurfaceforcingsIsdelta18oEnum);
	if(isdelta18o){
		IssmDouble *temp = NULL;
		IssmDouble  yts;
		int         N,M;

		iomodel->Constant(&yts,ConstantsYtsEnum);

		iomodel->FetchData(&temp,&N,&M,SurfaceforcingsDelta18oEnum); _assert_(N==2);
		for(i=0;i<M;i++) temp[M+i]=yts*temp[M+i];
		parameters->AddObject(new TransientParam(SurfaceforcingsDelta18oEnum,&temp[0],&temp[M],M));
		xDelete<IssmDouble>(temp);

		iomodel->FetchData(&temp,&N,&M,SurfaceforcingsDelta18oSurfaceEnum); _assert_(N==2);
		for(i=0;i<M;i++) temp[M+i]=yts*temp[M+i];
		parameters->AddObject(new TransientParam(SurfaceforcingsDelta18oSurfaceEnum,&temp[0],&temp[M],M));
		xDelete<IssmDouble>(temp);
	}

	/*some parameters that did not come with the iomodel: */
	parameters->AddObject(new IntParam(SolutionTypeEnum,solution_type));
	parameters->AddObject(new IntParam(AnalysisTypeEnum,analysis_type));
	parameters->AddObject(new IntParam(AnalysisCounterEnum,analysis_counter));
	parameters->AddObject(new DoubleParam(TimeEnum,0.0));  //start at time 0 by default for all solutions FIXME: to be deleted
	parameters->AddObject(new IntParam(StepEnum,1));  //start at time 0 by default for all solutions FIXME: to be deleted

	/*By default, save all results*/
	parameters->AddObject(new BoolParam(SaveResultsEnum,true));

	/*Requested outputs*/
	iomodel->FetchData(&requestedoutputs,&numoutputs,NULL,DiagnosticRequestedOutputsEnum);
	parameters->AddObject(new IntParam(DiagnosticNumRequestedOutputsEnum,numoutputs));
	if(numoutputs)parameters->AddObject(new IntVecParam(DiagnosticRequestedOutputsEnum,requestedoutputs,numoutputs));
	xDelete<IssmDouble>(requestedoutputs);
	iomodel->FetchData(&requestedoutputs,&numoutputs,NULL,TransientRequestedOutputsEnum);
	parameters->AddObject(new IntParam(TransientNumRequestedOutputsEnum,numoutputs));
	if(numoutputs)parameters->AddObject(new IntVecParam(TransientRequestedOutputsEnum,requestedoutputs,numoutputs));
	xDelete<IssmDouble>(requestedoutputs);
	iomodel->FetchData(&requestedoutputs,&numoutputs,NULL,SteadystateRequestedOutputsEnum);
	parameters->AddObject(new IntParam(SteadystateNumRequestedOutputsEnum,numoutputs));
	if(numoutputs)parameters->AddObject(new IntVecParam(SteadystateRequestedOutputsEnum,requestedoutputs,numoutputs));
	xDelete<IssmDouble>(requestedoutputs);
	
	/*Before returning, create parameters in case we are running Qmu or control types runs: */
	#ifdef _HAVE_CONTROL_
	CreateParametersControl(&parameters,iomodel,solution_type,analysis_type);
	#endif

	#ifdef _HAVE_DAKOTA_
	CreateParametersDakota(&parameters,iomodel,solution_type,analysis_type);
	#endif

	/*Go through all parameters, and convert units to SI: */
	parameters->UnitConversion(ExtToIuEnum);

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