RealVector HyperbolicEquationUpwindRHSFunction::evalF(Real time, RealVector& y, IntegerVector& ref){

	Real dx = (xL - x0) / Nx;
	Integer elem_ref = ref.sum();
	RealVector F(elem_ref);
	F.fill(0.0);

	Integer idx = 0;

	if (ref(0) == 1){
		F(idx) = bc_func->getValue(time);
		idx += 1;
	}
	for (Integer i = 1; i <= Nx-2; ++i){
		if (ref(i) == 1){
			Real yi = y(i);
			Real a = flux_func->evalFderivative(time,yi);
			if ( a > 0.0 ){
				Real yi_prec = y(i-1);
				F(idx) = 1.0/dx  * ( flux_func->evalF(time,yi_prec) - flux_func->evalF(time,yi) );
			}
			else{
				Real yi_succ = y(i+1);
				F(idx) = 1.0/dx  * ( flux_func->evalF(time,yi) - flux_func->evalF(time,yi_succ) );
			}
			idx += 1;
		}
	}

	return F;
}
RealMatrixSparse HyperbolicEquationUpwindRHSFunction::evaldFdY(Real time, RealVector& y,IntegerVector& ref){

	// this is not the exact Jacobian!

		Integer y_size = y.size();
		Integer elem_ref = ref.sum();
		RealMatrixSparse J(elem_ref,elem_ref);


		Integer col = 0;
		Real epsi = 1.e-3;
		Real iepsi = 1.0 / 1.e-3;
		RealVector F = evalF(time,y,ref);

		for (Integer j = 0; j < y_size; ++j){
			if(ref(j) == 1){
				RealVector yd = y;
				yd(j) = yd(j) + epsi;

				RealVector Fd = evalF(time,yd,ref);

				for(Integer i=0; i< Fd.size(); i++){
					J.insert(i,col) = (Fd[i] - F[i]) * iepsi;
				}
				col = col + 1;
			}
		}

		return J;
}
RealVector HyperbolicEquationRusanovFlux::evalF(Real time, RealVector& y, IntegerVector& ref){

	Real dx = (xL - x0) / Nx;
	Integer elem_ref = ref.sum();
	RealVector F(elem_ref);
	F.fill(0.0);

	Integer idx = 0;

	if (ref(0) == 1){
		Integer i=0;
		Real y0 = bc_func->getValue(time); 
		Real yi_succ = y(i+1);

		Real f_deriv_i = fabs(flux_func-> evalFderivative(time,y0));
		Real f_deriv_isucc = fabs(flux_func-> evalFderivative(time,yi_succ));

		Real f_prev =  flux_func->evalF(time,y0);
		Real f_succ =  0.5*(flux_func->evalF(time,y0) + flux_func->evalF(time,yi_succ) - ( std::max( f_deriv_i, f_deriv_isucc))*(yi_succ-y0));

		F(0) = - 1.0/dx  * (f_succ - f_prev );
		idx += 1;
	}
	for (Integer i = 1; i < Nx-1; ++i){
		if (ref(i) == 1){

			//! We use a finite volume method with Rusanov flux

			Real yi = y(i);
			Real yi_succ = y(i+1);
			Real yi_prev = y(i-1);

			Real f_deriv_i = fabs(flux_func-> evalFderivative(time,yi));
			Real f_deriv_isucc = fabs(flux_func-> evalFderivative(time,yi_succ));
			Real f_deriv_iprev = fabs(flux_func-> evalFderivative(time,yi_prev));

			Real f_prev =  0.5*(flux_func->evalF(time,yi_prev) + flux_func->evalF(time,yi) - (std::max( f_deriv_i, f_deriv_iprev))*(yi-yi_prev));
			Real f_succ =  0.5*(flux_func->evalF(time,yi) + flux_func->evalF(time,yi_succ) - ( std::max( f_deriv_i, f_deriv_isucc))*(yi_succ-yi));

			F(idx) = - 1.0/dx  * (f_succ - f_prev );
			idx += 1;
		}
	}

	if(ref(Nx-1)==1){
		Real yn = y(Nx-1);
		Real yi_prev = y(Nx-2);

		Real f_deriv_i = fabs(flux_func-> evalFderivative(time,yn));
		Real f_deriv_iprev = fabs(flux_func-> evalFderivative(time,yi_prev));

		Real f_prev =  0.5*(flux_func->evalF(time,yi_prev) + flux_func->evalF(time,yn) - (std::max( f_deriv_i, f_deriv_iprev))*(yn-yi_prev));
		Real f_succ =  flux_func->evalF(time,yn);

		F(idx) = - 1.0/dx  * (f_succ - f_prev );
	}
	return F;
}
int GenerateNumbComponentsRestabFile::ComponentsRestab( std::vector<std::unique_ptr<ISolverData>>&& vect_solution){
	DataCube datacube;

			///====================================
			/// Set Description
			///====================================

			{
				IndexDescription index;

				index.label = "timeStep";
				index.name  = "iTimeStep";

				datacube.list_of_index_description.add(index);
			}

			{
				Restab::VariableDescription var;

				var.label = "number_of_components";

				datacube.list_of_variable_description.add(var);
			}

			///====================================
			/// Add Step Values
			///====================================

			MapInteger step_index_values;
			MapReal step_var_values;

			Integer num_solution = vect_solution.size();

			//!Steps

			for(Integer i = 1; i < num_solution; i++){

				step_index_values.clear();
				step_var_values.clear();

				step_index_values.insert(KeyInteger("timeStep",i));

				IntegerVector ref = vect_solution[i]->getNumbComponentsSolve();
				Integer numb_comp = ref.sum();

				step_var_values.insert(KeyReal("number_of_components" ,numb_comp));

				datacube.table_of_index_values.add(step_index_values);
				datacube.table_of_variable_values.add(step_var_values);
			}
				///======================================
				/// Write Results
				///======================================

				String filename = "Componentsresult";

				//! Description

				String filenameDesc = filename + ".restab.desc";

				String text_desc = datacube.toStringDescription();
				//std::cout << text_desc << "\n";

				datacube.writeDescription(filenameDesc);

				//! Data

				String filenameData = filename + ".restab";

				String text_data = datacube.toStringData();
				//std::cout << text_data << "\n";

				datacube.writeData(filenameData);

				//======================================


			return 0;
}