/*!\file:  issm.cpp
 * \brief: ISSM main parallel program
 */ 

#include "../issm.h"
#include "../include/globals.h"

int main(int argc,char **argv){

	/*I/O: */
	FILE *output_fid       = NULL;
	FILE *petscoptionsfid  = NULL;
	bool  waitonlock       = false;
	bool  dakota_analysis,control_analysis,tao_analysis;

	/*FemModel: */
	FemModel *femmodel = NULL;

	/*configuration: */
	void (*solutioncore)(FemModel*)=NULL; //core solution function pointer
	int* analyses=NULL;
	int  numanalyses;
	int  solution_type;

	/*File names*/
	char *lockfilename   = NULL;
	char *binfilename    = NULL;
	char *outbinfilename = NULL;
	char *petscfilename  = NULL;

	/*time*/
	double   start, finish;
	double   start_core, finish_core;
	double   start_init, finish_init;
	int      ierr;

	ISSMBOOT();

	/*Initialize environments: Petsc, MPI, etc...: */
	#ifdef _HAVE_PETSC_
	ierr=PetscInitialize(&argc,&argv,(char*)0,"");  
	if(ierr) _error_("Could not initialize Petsc");
	#else
	#ifdef _HAVE_MPI_
	MPI_Init(&argc,&argv);
	#endif
	#endif

	#ifdef _HAVE_MPI_
	MPI_Barrier(MPI_COMM_WORLD); start=MPI_Wtime();
	#else
	start=(double)clock();
	#endif

	/*Size and rank: */
	#ifdef _HAVE_MPI_
	MPI_Comm_rank(MPI_COMM_WORLD,&my_rank);  
	MPI_Comm_size(MPI_COMM_WORLD,&num_procs); 
	#endif

	/*First process inputs*/
	_printf_(true,"\n");
	_printf_(true,"Ice Sheet System Model (%s) version %s\n",PACKAGE_NAME,PACKAGE_VERSION);
	_printf_(true,"(website: %s contact: %s)\n",PACKAGE_URL,PACKAGE_BUGREPORT);
	_printf_(true,"\n");
	ProcessArguments(&solution_type,&binfilename,&outbinfilename,&petscfilename,&lockfilename,argc,argv);

	/*out of solution_type, figure out types of analyses needed in the femmodel: */
	AnalysisConfiguration(&analyses,&numanalyses,solution_type);
	
	/*Create femmodel, using input file: */
	#ifdef _HAVE_MPI_
	MPI_Barrier(MPI_COMM_WORLD); start_init=MPI_Wtime();
	#else
	start_init=(double)clock();
	#endif
	femmodel=new FemModel(binfilename,outbinfilename,solution_type,analyses,numanalyses);
	
	/*get type of solution we are going to run: */
	CorePointerFromSolutionEnum(&solutioncore,femmodel->parameters,solution_type);

	/*Open output file once for all*/
	output_fid=pfopen(outbinfilename,"wb");
	femmodel->parameters->SetParam(output_fid,OutputFilePointerEnum);

	/*add petsc options to parameters: */
	petscoptionsfid=pfopen(petscfilename,"r");
	ParsePetscOptionsx(femmodel->parameters,petscoptionsfid);
	pfclose(petscoptionsfid,petscfilename);

	/*get parameters: */
	femmodel->parameters->FindParam(&waitonlock,SettingsWaitonlockEnum);
	femmodel->parameters->FindParam(&dakota_analysis,QmuIsdakotaEnum);
	femmodel->parameters->FindParam(&control_analysis,InversionIscontrolEnum);
	femmodel->parameters->FindParam(&tao_analysis,InversionTaoEnum);
	#ifdef _HAVE_MPI_
	MPI_Barrier(MPI_COMM_WORLD); finish_init=MPI_Wtime();
	#else
	finish_init=(double)clock();
	#endif

	_printf_(true,"call computational core:\n");
	#ifdef _HAVE_MPI_
	MPI_Barrier(MPI_COMM_WORLD); start_core=MPI_Wtime( );
	#else
	start_core=(double)clock();
	#endif
	
	if(dakota_analysis){
		#ifdef _HAVE_DAKOTA_
		Dakotax(femmodel);
		#else
		_error_("ISSM was not compiled with dakota support, cannot carry out dakota analysis!");
		#endif
	}
	else if(control_analysis){
		#ifdef _HAVE_CONTROL_
		if(tao_analysis)
		 controltao_core(femmodel);
		else
		 control_core(femmodel);
		#else
		_error_("ISSM was not compiled with control support, cannot carry out dakota analysis!");
		#endif
	}
	else{
		solutioncore(femmodel);
	}
	#ifdef _HAVE_MPI_
	MPI_Barrier(MPI_COMM_WORLD); finish_core=MPI_Wtime( );
	#else
	finish_core=(double)clock();
	#endif
	
	_printf_(true,"write results to disk:\n");
	OutputResultsx(femmodel->elements, femmodel->nodes, femmodel->vertices, femmodel->loads, femmodel->materials, femmodel->parameters,femmodel->results);

	/*Close output and petsc options file and write lock file if requested*/
	pfclose(output_fid,lockfilename);
	if (waitonlock>0){
		_printf_(true,"write lock file:\n");
		WriteLockFile(lockfilename);
	}

	/*Free ressources */
	xfree((void**)&analyses);
	xfree((void**)&lockfilename);
	xfree((void**)&binfilename);
	xfree((void**)&outbinfilename);
	xfree((void**)&petscfilename);
	delete femmodel;

	/*Get finish time and close*/
	#ifdef _HAVE_MPI_
	MPI_Barrier(MPI_COMM_WORLD); finish = MPI_Wtime( );
	_printf_(true,"\n   %-34s %f seconds  \n","FemModel initialization elapsed time:",finish_init-start_init);
	_printf_(true,"   %-34s %f seconds  \n","Core solution elapsed time:",finish_core-start_core);
	_printf_(true,"\n   %s %i hrs %i min %i sec\n\n","Total elapsed time:",int((finish-start)/3600),int(int(finish-start)%3600/60),int(finish-start)%60);
	#else
	finish=(double)clock();
	_printf_(true,"\n   %-34s %f seconds  \n","FemModel initialization elapsed time:",(finish_init-start_init)/CLOCKS_PER_SEC);
	_printf_(true,"   %-34s %f seconds  \n","Core solution elapsed time:",(finish_core-start_core)/CLOCKS_PER_SEC);
	_printf_(true,"\n   %s %i hrs %i min %i sec\n\n","Total elapsed time:",int((finish-start)/3600/CLOCKS_PER_SEC),int(int((finish-start)/CLOCKS_PER_SEC)%3600/60),(int(finish-start)/CLOCKS_PER_SEC)%60);
	#endif
	
		
	
	#ifdef _HAVE_PETSC_
	_printf_(true,"closing MPI and Petsc\n");
	PetscFinalize(); 
	#else
	#ifdef _HAVE_MPI_
	_printf_(true,"closing MPI and Petsc\n");
	MPI_Finalize();
	#endif
	#endif
	
	/*end module: */
	ISSMEND();

	return 0; //unix success return;
}
