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

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

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

	/*MPI: */
	extern int my_rank;
	extern int num_procs;

	/*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;

	MODULEBOOT();

	#if !defined(_PARALLEL_) || (defined(_PARALLEL_) && !defined(_HAVE_PETSC_))
	_error_(" parallel executable was compiled without support of parallel libraries!");
	#endif

	/*Initialize Petsc and get start time*/
	int ierr=PetscInitialize(&argc,&argv,(char*)0,"");  
	if(ierr) _error_("Could not initialize Petsc");
	MPI_Barrier(MPI_COMM_WORLD); start=MPI_Wtime();

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

	/*First process inputs*/
	_printf_(true,"Launching solution sequence\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: */
	MPI_Barrier(MPI_COMM_WORLD); start_init=MPI_Wtime();
	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);
	MPI_Barrier(MPI_COMM_WORLD); finish_init=MPI_Wtime();

	_printf_(true,"call computational core:\n");
	MPI_Barrier(MPI_COMM_WORLD); start_core=MPI_Wtime( );
	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);
	}
	MPI_Barrier(MPI_COMM_WORLD); finish_core=MPI_Wtime( );

	_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*/
	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);
	_printf_(true,"closing MPI and Petsc\n");
	PetscFinalize(); 
	
	/*end module: */
	MODULEEND();

	return 0; //unix success return;
}

