/*!\file:  gradient_core.cpp
 * \brief compute inverse method gradient direction.
 */ 

#include "./cores.h"
#include "../toolkits/toolkits.h"
#include "../classes/classes.h"
#include "../shared/shared.h"
#include "../modules/modules.h"
#include "../solutionsequences/solutionsequences.h"

void gradient_core(FemModel* femmodel,int step,bool orthogonalize){ 

	/*Intermediaries*/
	IssmDouble  norm_inf;
	IssmDouble *norm_list    = NULL;
	Vector<IssmDouble>*     new_gradient = NULL;
	Vector<IssmDouble>*     gradient     = NULL;
	Vector<IssmDouble>*     old_gradient = NULL;

	/*Compute gradient*/
	if(VerboseControl()) _printf0_("   compute cost function gradient\n");
	Gradjx(&gradient,&norm_list,femmodel->elements,femmodel->nodes, femmodel->vertices,femmodel->loads, femmodel->materials,femmodel->parameters);

	if (orthogonalize){
		if(VerboseControl()) _printf0_("   orthogonalization\n");
		ControlInputGetGradientx(&old_gradient,femmodel->elements,femmodel->nodes, femmodel->vertices,femmodel->loads, femmodel->materials,femmodel->parameters);
		Orthx(&new_gradient,gradient,old_gradient); delete old_gradient; delete gradient;
	}
	else{ 
		new_gradient=gradient;
	}

	/*Check that gradient is clean*/
	norm_inf=new_gradient->Norm(NORM_INF);
	if(norm_inf<=0)    _error_("||∂J/∂α||∞ = 0    gradient norm is zero");
	if(xIsNan<IssmDouble>(norm_inf))_error_("||∂J/∂α||∞ = NaN  gradient norm is NaN");

	/*plug back into inputs: */
	ControlInputSetGradientx(femmodel->elements,femmodel->nodes,femmodel->vertices,femmodel->loads,femmodel->materials,femmodel->parameters,new_gradient);
	delete new_gradient;

	/*Scale Gradients*/
	ControlInputScaleGradientx(femmodel->elements,femmodel->nodes,femmodel->vertices,femmodel->loads,femmodel->materials,femmodel->parameters,norm_list,step);

	/*Clean up and return*/
	xDelete<IssmDouble>(norm_list);
}
