/*
 * FemModel.h: 
 */

#ifndef _FEMMODEL_H_
#define _FEMMODEL_H_

/*Headers:*/
/*{{{*/
#include "./objects/Object.h"
#include "../toolkits/toolkits.h"
class DataSet;
class Parameters;
class NodeSets;
class Nodes;
class Vertices;
class Results;
class Constraints;
class Loads;
class Materials;
class Profiler;
class Elements;
/*}}}*/

class FemModel {

	/*no private members, as we need access to these datasets quite often!:*/

	public:

		int          nummodels;
		int          solution_type;
		int         *analysis_type_list;   //list of analyses this femmodel is going to carry out
		int          analysis_counter;     //counter into analysis_type_list

		Profiler*    profiler;             //keep time, cpu and mem statistics while we are running.

		Elements    *elements;             //elements (one set for all analyses)
		Nodes       *nodes;                //one set of nodes
		Vertices    *vertices;             //one set of vertices
		Constraints *constraints;          //one set of constraints. each constraint knows which analysis_type it handles
		Loads       *loads;                //one set of constraints. each constraint knows which analysis_type it handles
		Materials   *materials;            //one set of materials, for each element
		Parameters  *parameters;           //one set of parameters, independent of the analysis_type
		Results     *results;              //results that cannot be fit into the elements 
		COMM        comm;                  //communicator for this particular model

		/*constructors, destructors: */
		FemModel(char* filename);
		FemModel(int argc,char** argv,COMM comm_init);
		FemModel(char* rootpath, char* inputfilename, char* outputfilename, char* petscfilename, char* lockfilename, const int solution_type,const int* analyses,const int nummodels);
		~FemModel();

		/*Methods:*/
		void AllocateSystemMatrices(Matrix<IssmDouble>** pKff,Matrix<IssmDouble>** pKfs,Vector<IssmDouble>** pdf,Vector<IssmDouble>** ppf);
		void CreateJacobianMatrixx(Matrix<IssmDouble>** pJff,IssmDouble kmax);
		void Echo();
		void InitFromFiles(char* rootpath, char* inputfilename, char* outputfilename, char* petscfilename, char* lockfilename, const int solution_type,const int* analyses,const int nummodels);
		void MatrixNonzeros(int** pd_nnz,int** po_nnz,int set1enum,int set2enum);
		void Solve(void);
		void OutputResults(void);
		void SetStaticComm();
		void SetCurrentConfiguration(int configuration_type);
		void SetCurrentConfiguration(int configuration_type,int analysis_type);

		/*Modules*/ 
		#ifdef _HAVE_RESPONSES_
		void MassFluxx(IssmDouble* presponse,bool process_units);
		void MaxAbsVxx(IssmDouble* presponse,bool process_units);
		void MaxAbsVyx(IssmDouble* presponse,bool process_units);
		void MaxAbsVzx(IssmDouble* presponse,bool process_units);
		void MaxVelx(IssmDouble* presponse,bool process_units);
		void MaxVxx(IssmDouble* presponse,bool process_units);
		void MaxVyx(IssmDouble* presponse,bool process_units);
		void MaxVzx(IssmDouble* presponse,bool process_units);
		void MinVelx(IssmDouble* presponse,bool process_units);
		void MinVxx(IssmDouble* presponse,bool process_units);
		void MinVyx(IssmDouble* presponse,bool process_units);
		void MinVzx(IssmDouble* presponse,bool process_units);
		void TotalSmbx(IssmDouble* pSmb,bool process_units);
		void IceVolumex(IssmDouble* pV,bool process_units);
		void ElementResponsex(IssmDouble* presponse,int response_enum,bool process_units);
		#endif
		#ifdef  _HAVE_DAKOTA_
		void DakotaResponsesx(double* d_responses,char** responses_descriptors,int numresponsedescriptors,int d_numresponses);
		#endif
		void RequestedOutputsx(int* requested_outputs, int numoutputs);
		void RequestedDependentsx(void);
		void Responsex(IssmDouble* presponse,int response_descriptor_enum,bool process_units,int weight_index);
		void Responsex(IssmDouble* presponse,const char* response_descriptor,bool process_units,int weight_index);
		#ifdef _HAVE_CONTROL_
		void CostFunctionx( IssmDouble* pJ);
		void ThicknessAbsGradientx( IssmDouble* pJ, bool process_units,int weight_index);
		#endif
		void SystemMatricesx(Matrix<IssmDouble>** pKff, Matrix<IssmDouble>** pKfs, Vector<IssmDouble>** ppf, Vector<IssmDouble>** pdf, IssmDouble* pkmax);
		void TimeAdaptx(IssmDouble* pdt);
		void UpdateConstraintsx(void);
		int  UpdateVertexPositionsx(void);
};

#endif
