void FunctionCMP_2P2C<T1, T2>::output(const NumLib::TimeStep &/*time*/)
{
	// update data for output
	Ogs6FemData* femData = Ogs6FemData::getInstance();
	this->_msh_id = this->_problem->getDiscreteSystem()->getMesh()->getID();
	// set the new output
	// we have 2 primary variables
	OutputVariableInfo var1("MEAN_PRESSURE", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _P);
	femData->outController.setOutput(var1.name, var1);
	OutputVariableInfo var2("MOLAR_FRACTION", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _X);
	femData->outController.setOutput(var2.name, var2);
	// and 8 secondary variables
	// add all seconary variables as well. 
	OutputVariableInfo var_Sec_1("Capillary Pressure", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _PC);
	femData->outController.setOutput(var_Sec_1.name, var_Sec_1);
	OutputVariableInfo var_Sec_2("Liquid_Phase_Pressure", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _PL);
	femData->outController.setOutput(var_Sec_2.name, var_Sec_2);
	OutputVariableInfo var_Sec_3("Gas_Phase_Pressure", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _PG);
	femData->outController.setOutput(var_Sec_3.name, var_Sec_3);
	OutputVariableInfo var_Sec_4("Molar_Fraction_Light_component_Liquid_Phase", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _X_m);
	femData->outController.setOutput(var_Sec_4.name, var_Sec_4);
	OutputVariableInfo var_Sec_5("Molar_Fraction_Light_component_Gas_Phase", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _X_M);
	femData->outController.setOutput(var_Sec_5.name, var_Sec_5);
	OutputVariableInfo var_Sec_6("Molar_Density_Gas_Phase", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _NG);
	femData->outController.setOutput(var_Sec_6.name, var_Sec_6);
	OutputVariableInfo var_Sec_7("Molar_Density_Liquid_Phase", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _NL);
	femData->outController.setOutput(var_Sec_7.name, var_Sec_7);
	OutputVariableInfo var_Sec_8("Saturation", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _S);
	femData->outController.setOutput(var_Sec_8.name, var_Sec_8);
}
void FunctionCMP_NonIso_LocalNCPForm<T1, T2>::output(const NumLib::TimeStep &/*time*/)
{
	
	//update data for output
	Ogs6FemData* femData = Ogs6FemData::getInstance();
	this->_msh_id = this->_problem->getDiscreteSystem()->getMesh()->getID();
	// set the new output
	// we have 2 primary variables
	OutputVariableInfo var1("MEAN_PRESSURE", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _P);
	femData->outController.setOutput(var1.name, var1);
	OutputVariableInfo var2("TOTAL_MASS_DENSITY", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _X);
	femData->outController.setOutput(var2.name, var2);
	OutputVariableInfo var3("TEMPERATURE", _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _T);
	femData->outController.setOutput(var3.name, var3);
	// and 8 secondary variables
	// add all seconary variables as well. 
	//we have several secondary variables the values of which are defined on each elements
	
	OutputVariableInfo var_Sec_1("Saturation", _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _S);
	femData->outController.setOutput(var_Sec_1.name, var_Sec_1);

	OutputVariableInfo var_Sec_3("Gas_Pressure", _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _PG);
	femData->outController.setOutput(var_Sec_3.name, var_Sec_3);

	OutputVariableInfo var_Sec_4("Capillary_Pressure", _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _PC);
	femData->outController.setOutput(var_Sec_4.name, var_Sec_4);

	OutputVariableInfo var_Sec_6("Mass_Density_G_H", _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _rho_G_h);
	femData->outController.setOutput(var_Sec_6.name, var_Sec_6);

	OutputVariableInfo var_Sec_7("Mass_Density_G_W", _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _rho_G_w);
	femData->outController.setOutput(var_Sec_7.name, var_Sec_7);

}
bool FunctionCMP_NonIsoTotalMassEXPForm<T1, T2>::initialize(const BaseLib::Options &option)
{

	Ogs6FemData* femData = Ogs6FemData::getInstance();
	_msh_id = option.getOptionAsNum<size_t>("MeshID");
	size_t time_id = option.getOptionAsNum<int>("TimeGroupID");
	NumLib::ITimeStepFunction* tim = femData->list_tim[time_id];

	//mesh and FE objects
	MeshLib::IMesh* msh = femData->list_mesh[_msh_id];
	// get the number of elements 
	size_t n_ele = msh->getNumberOfElements();
	size_t n_nodes = msh->getNumberOfNodes();
	MyDiscreteSystem* dis = 0;
	dis = DiscreteLib::DiscreteSystemContainerPerMesh::getInstance()->createObject<MyDiscreteSystem>(msh);
	_feObjects = new FemLib::LagrangeFeObjectContainer(msh);
	
	// set names of the output parameters
	this->setOutputParameterName(0, "MEAN_PRESSURE");
	this->setOutputParameterName(1, "TOTAL_MASS_DENSITY");
	this->setOutputParameterName(2, "TEMPERATURE");

	this->setOutputParameterName(3, "Saturation");
	this->setOutputParameterName(4, "Liquid_Pressure");
	this->setOutputParameterName(5, "Gas_Pressure");
	this->setOutputParameterName(6, "Capillary_Pressure");
	this->setOutputParameterName(7, "Mass_Density_L_H");
	this->setOutputParameterName(8, "Mass_Density_G_H");
	this->setOutputParameterName(9, "Mass_Density_G_W");
	// also secondary variables
	// TODO: set seconary variable names also as output parameters

	// create the MyCMPPressureForm problem
	_problem = new MyCMPNonIsoTotalMassEXPFormProblemType(dis);
	_problem->setTimeSteppingFunction(*tim);  // applying the time stepping function
	
	// creating mean pressure vector
	MyVariableCMPNonIsoTotalMassEXPForm* mean_pressure = _problem->addVariable("MEAN_PRESSURE");
	FemVariableBuilder var_builder;
	var_builder.doit("MEAN_PRESSURE", option, msh, femData->geo, femData->geo_unique_name, _feObjects, mean_pressure);
	SolutionLib::FemIC* femIC = _problem->getVariable(0)->getIC();
	_P = new MyNodalFunctionScalar();
	if (femIC)
	{
		// FemIC vector is not empty
		_P->initialize(*dis, _problem->getVariable(0)->getCurrentOrder(), 0.0);
		femIC->setup(*_P);
	}
	else
	{
		// FemIC vector is empty
		// initialize the vector with zeros
		_P->initialize(*dis, _problem->getVariable(0)->getCurrentOrder(), 0.0);
	}

	// creating molar fraction

	MyVariableCMPNonIsoTotalMassEXPForm* total_mass_density = _problem->addVariable("TOTAL_MASS_DENSITY");
	var_builder.doit("TOTAL_MASS_DENSITY", option, msh, femData->geo, femData->geo_unique_name, _feObjects, total_mass_density);
	femIC = _problem->getVariable(1)->getIC();
	_X = new MyNodalFunctionScalar();
	if (femIC)
	{
		// FemIC vector is not empty
		_X->initialize(*dis, _problem->getVariable(1)->getCurrentOrder(), 0.0);
		femIC->setup(*_X);
	}
	else
	{
		// FemIC vector is empty
		// initialize the vector with zeros
		_X->initialize(*dis, _problem->getVariable(1)->getCurrentOrder(), 0.0);
	}


	MyVariableCMPNonIsoTotalMassEXPForm* temperature = _problem->addVariable("TEMPERATURE");
	var_builder.doit("TEMPERATURE", option, msh, femData->geo, femData->geo_unique_name, _feObjects, temperature);
	femIC = _problem->getVariable(2)->getIC();
	_T = new MyNodalFunctionScalar();
	if (femIC)
	{
		// FemIC vector is not empty
		_T->initialize(*dis, _problem->getVariable(2)->getCurrentOrder(), 0.0);
		femIC->setup(*_T);
	}
	else
	{
		// FemIC vector is empty
		// initialize the vector with zeros
		_T->initialize(*dis, _problem->getVariable(2)->getCurrentOrder(), 0.0);
	}
	// initialize the local EOS problem
	//_LP_EOS = new LocalProblem_EOS_TotalMassEXPForm();
	//ogsChem::LocalVector _output1;
	//_output1 = ogsChem::LocalVector::Zero(_LP_EOS->N);
	_S = new MyIntegrationPointFunctionVector();
	_S->initialize(dis);
	_PL = new MyIntegrationPointFunctionVector();
	_PL->initialize(dis);
	_PG = new  MyIntegrationPointFunctionVector();
	_PG->initialize(dis);
	_PC = new MyIntegrationPointFunctionVector();
	_PC->initialize(dis);
	_rho_L_h = new MyIntegrationPointFunctionVector();
	_rho_L_h->initialize(dis);
	_rho_G_h = new MyIntegrationPointFunctionVector();
	_rho_G_h->initialize(dis);
	_rho_G_w = new  MyIntegrationPointFunctionVector();
	_rho_G_w->initialize(dis);
	MathLib::LocalVector tmp = MathLib::LocalVector::Zero(1);

	for (size_t ele_id = 0; ele_id < n_ele; ele_id++)
	{
		MeshLib::IElement *e = msh->getElement(ele_id);
		const std::size_t node_ele = e->getNumberOfNodes();//
		_S->setNumberOfIntegationPoints(ele_id, node_ele);
		_PL->setNumberOfIntegationPoints(ele_id, node_ele);
		_PC->setNumberOfIntegationPoints(ele_id, node_ele);
		_rho_G_h->setNumberOfIntegationPoints(ele_id, node_ele);
		_rho_G_w->setNumberOfIntegationPoints(ele_id, node_ele);
		for (size_t jj = 0; jj < node_ele; jj++)
		{
			_S->setIntegrationPointValue(ele_id, jj, tmp);
			_PL->setIntegrationPointValue(ele_id, jj, tmp);
			_PC->setIntegrationPointValue(ele_id, jj, tmp);
			_rho_G_h->setIntegrationPointValue(ele_id, jj, tmp);
			_rho_G_w->setIntegrationPointValue(ele_id, jj, tmp);
		}
	}
	
	_mat_secDer = new MyNodalFunctionMatrix();// define a matrix to store all the derivatives of the secondary variables 
	MathLib::LocalMatrix tmp_mat = MathLib::LocalMatrix::Zero(3, 2); //the size I will modify later
	_mat_secDer->initialize(*dis, FemLib::PolynomialOrder::Linear, tmp_mat);
	/**
	* initialize the vector of tempVar
	*/
	
	_vec_tempVar = new MyNodalFunctionVector();
	MathLib::LocalVector tmp_vec = MathLib::LocalVector::Zero(2);
	_vec_tempVar->initialize(*dis, FemLib::PolynomialOrder::Linear, tmp_vec);


	//initialize the local M matrix and K matrix
	for (size_t index = 0; index < n_ele; index++)
	{
		MathLib::LocalMatrix test1 = MathLib::LocalMatrix::Zero(6, 6);
		_elem_M_matrix.push_back(test1);
		MathLib::LocalMatrix test2 = MathLib::LocalMatrix::Zero(6, 6);
		_elem_K_matrix.push_back(test2);
	}
	
	// linear assemblers
	MyNonLinearAssemblerType* nonlin_assembler = new MyNonLinearAssemblerType(_feObjects, this, msh->getGeometricProperty()->getCoordinateSystem());
	MyNonLinearResidualAssemblerType* non_linear_r_assembler = new MyNonLinearResidualAssemblerType(_feObjects, this, msh->getGeometricProperty()->getCoordinateSystem());
	MyNonLinearJacobianAssemblerType* non_linear_j_assembler = new MyNonLinearJacobianAssemblerType(_feObjects, this, msh->getGeometricProperty()->getCoordinateSystem());

	// define nonlinear problem
	_non_linear_problem = new MyNonLinearCMPNonIsoTotalMassEXPFormProblemType(dis);
	_non_linear_eqs = _non_linear_problem->createEquation();
	_non_linear_eqs->initialize(nonlin_assembler, non_linear_r_assembler, non_linear_j_assembler);
	_non_linear_problem->setTimeSteppingFunction(*tim);
	_non_linear_problem->addVariable("MEAN_PRESSURE");
	_non_linear_problem->addVariable("TOTAL_MASS_DENSITY");
	_non_linear_problem->addVariable("TEMPERATURE");

	SolutionLib::FemIC* P_ic = new SolutionLib::FemIC(msh);
	P_ic->addDistribution(femData->geo->getDomainObj(), new NumLib::TXFunctionDirect<double>(_P->getDiscreteData()));
	var_builder.doit("MEAN_PRESSURE", option, msh, femData->geo, femData->geo_unique_name, _feObjects, _non_linear_problem->getVariable(0));
	_non_linear_problem->getVariable(0)->setIC(P_ic);

	SolutionLib::FemIC* X_ic = new SolutionLib::FemIC(msh);
	X_ic->addDistribution(femData->geo->getDomainObj(), new NumLib::TXFunctionDirect<double>(_X->getDiscreteData()));
	var_builder.doit("TOTAL_MASS_DENSITY", option, msh, femData->geo, femData->geo_unique_name, _feObjects, _non_linear_problem->getVariable(1));
	_non_linear_problem->getVariable(1)->setIC(X_ic);

	SolutionLib::FemIC* T_ic = new SolutionLib::FemIC(msh);
	T_ic->addDistribution(femData->geo->getDomainObj(), new NumLib::TXFunctionDirect<double>(_T->getDiscreteData()));
	var_builder.doit("TEMPERATURE", option, msh, femData->geo, femData->geo_unique_name, _feObjects, _non_linear_problem->getVariable(2));
	_non_linear_problem->getVariable(2)->setIC(T_ic);
	// set up non-linear solution
	myNRIterator = new MyNRIterationStepInitializer(non_linear_r_assembler, non_linear_j_assembler);
	myNSolverFactory = new MyDiscreteNonlinearSolverFactory(myNRIterator);
	this->_non_linear_solution = new MyNonLinearSolutionType(dis, this->_non_linear_problem, myNSolverFactory);
	this->_non_linear_solution->getDofEquationIdTable()->setNumberingType(DiscreteLib::DofNumberingType::BY_POINT);  // global order
	this->_non_linear_solution->getDofEquationIdTable()->setLocalNumberingType(DiscreteLib::DofNumberingType::BY_VARIABLE);  // local order
	const BaseLib::Options* optNum = option.getSubGroup("Numerics");

	// linear solver
	MyLinearSolver* linear_solver = this->_non_linear_solution->getLinearEquationSolver();
	linear_solver->setOption(*optNum);
	// set nonlinear solver options
	this->_non_linear_solution->getNonlinearSolver()->setOption(*optNum);
    // set theta
    if (!optNum->hasOption("TimeTheta"))
    {
        ERR("Time theta setting not found!!!");
        exit(1);
    }
    else
    {
        double tmp_theta(optNum->getOptionAsNum<double>("TimeTheta"));
        non_linear_j_assembler->setTheta(tmp_theta);
        non_linear_r_assembler->setTheta(tmp_theta);
        _non_linear_eqs->getLinearAssembler()->setTheta(tmp_theta);
    }



	// get the nonlinear solution dof manager
	this->_nl_sol_dofManager = this->_non_linear_solution->getDofEquationIdTable();
	// set up solution
	_solution = new MyCMPNonIsoTotalMassEXPFormSolution(dis, _problem, _non_linear_solution, this);
	/**
	*Calculate the secondary variables on each node
	*/
	this->calc_nodal_eos_sys(0.0);
	

	// set initial output parameter
	OutputVariableInfo var1(this->getOutputParameterName(0), _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _P);
	femData->outController.setOutput(var1.name, var1);
	OutputVariableInfo var2(this->getOutputParameterName(1), _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _X);
	femData->outController.setOutput(var2.name, var2);
	OutputVariableInfo var3(this->getOutputParameterName(2), _msh_id, OutputVariableInfo::Node, OutputVariableInfo::Real, 1, _T);
	femData->outController.setOutput(var3.name, var3);
	// 
	OutputVariableInfo var_Sec_1(this->getOutputParameterName(3), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _S);
	femData->outController.setOutput(var_Sec_1.name, var_Sec_1);

	OutputVariableInfo var_Sec_2(this->getOutputParameterName(4), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _PL);
	femData->outController.setOutput(var_Sec_2.name, var_Sec_2);

	OutputVariableInfo var_Sec_3(this->getOutputParameterName(5), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _PG);
	femData->outController.setOutput(var_Sec_3.name, var_Sec_3);

	OutputVariableInfo var_Sec_4(this->getOutputParameterName(6), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _PC);
	femData->outController.setOutput(var_Sec_4.name, var_Sec_4);
	
	OutputVariableInfo var_Sec_5(this->getOutputParameterName(7), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _rho_L_h);
	femData->outController.setOutput(var_Sec_5.name, var_Sec_5);

	OutputVariableInfo var_Sec_6(this->getOutputParameterName(8), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _rho_G_h);
	femData->outController.setOutput(var_Sec_6.name, var_Sec_6);

	OutputVariableInfo var_Sec_7(this->getOutputParameterName(9), _msh_id, OutputVariableInfo::Element, OutputVariableInfo::Real, 1, _rho_G_w);
	femData->outController.setOutput(var_Sec_7.name, var_Sec_7);
	return true;
}