#module imports
from fielddisplay import fielddisplay

class inversion:
	#properties
	def __init__(self):
		# {{{ Properties
		self.iscontrol                   = 0
		self.tao                         = 0
		self.incomplete_adjoint          = 0
		self.control_parameters          = float('NaN')
		self.nsteps                      = 0
		self.maxiter_per_step            = float('NaN')
		self.cost_functions              = float('NaN')
		self.cost_functions_coefficients = float('NaN')
		self.gradient_scaling            = float('NaN')
		self.cost_function_threshold     = 0
		self.min_parameters              = float('NaN')
		self.max_parameters              = float('NaN')
		self.step_threshold              = float('NaN')
		self.gradient_only               = 0
		self.vx_obs                      = float('NaN')
		self.vy_obs                      = float('NaN')
		self.vz_obs                      = float('NaN')
		self.vel_obs                     = float('NaN')
		self.thickness_obs               = float('NaN')
		#}}}
	def __repr__(obj):
		# {{{ Display
		string='\n   Inversion parameters:'
		string="%s\n%s"%(string,fielddisplay(obj,'iscontrol','is inversion activated?'))
		string="%s\n%s"%(string,fielddisplay(obj,'incomplete_adjoint','do we assume linear viscosity?'))
		string="%s\n%s"%(string,fielddisplay(obj,'control_parameters','parameter where inverse control is carried out; ex: {''FrictionCoefficient''}, or {''MaterialsRheologyBbar''}'))
		string="%s\n%s"%(string,fielddisplay(obj,'nsteps','number of optimization searches'))
		string="%s\n%s"%(string,fielddisplay(obj,'cost_functions','indicate the type of response for each optimization step'))
		string="%s\n%s"%(string,fielddisplay(obj,'cost_functions_coefficients','cost_functions_coefficients applied to the misfit of each vertex and for each control_parameter'))
		string="%s\n%s"%(string,fielddisplay(obj,'cost_function_threshold','misfit convergence criterion. Default is 1%, NaN if not applied'))
		string="%s\n%s"%(string,fielddisplay(obj,'maxiter_per_step','maximum iterations during each optimization step'))
		string="%s\n%s"%(string,fielddisplay(obj,'gradient_scaling','scaling factor on gradient direction during optimization, for each optimization step'))
		string="%s\n%s"%(string,fielddisplay(obj,'step_threshold','decrease threshold for misfit, default is 30%'))
		string="%s\n%s"%(string,fielddisplay(obj,'min_parameters','absolute minimum acceptable value of the inversed parameter on each vertex'))
		string="%s\n%s"%(string,fielddisplay(obj,'max_parameters','absolute maximum acceptable value of the inversed parameter on each vertex'))
		string="%s\n%s"%(string,fielddisplay(obj,'gradient_only','stop control method solution at gradient'))
		string="%s\n%s"%(string,fielddisplay(obj,'vx_obs','observed velocity x component [m/a]'))
		string="%s\n%s"%(string,fielddisplay(obj,'vy_obs','observed velocity y component [m/a]'))
		string="%s\n%s"%(string,fielddisplay(obj,'vel_obs','observed velocity magnitude [m/a]'))
		string="%s\n%s"%(string,fielddisplay(obj,'thickness_obs','observed thickness [m]'))
		string="%s\n%s"%(string,'Available cost functions:')
		string="%s\n%s"%(string,'   101: SurfaceAbsVelMisfit')
		string="%s\n%s"%(string,'   102: SurfaceRelVelMisfit')
		string="%s\n%s"%(string,'   103: SurfaceLogVelMisfit')
		string="%s\n%s"%(string,'   104: SurfaceLogVxVyMisfit')
		string="%s\n%s"%(string,'   105: SurfaceAverageVelMisfit')
		string="%s\n%s"%(string,'   201: ThicknessAbsMisfit')
		string="%s\n%s"%(string,'   501: DragCoefficientAbsGradient')
		string="%s\n%s"%(string,'   502: RheologyBbarAbsGradient')
		string="%s\n%s"%(string,'   503: ThicknessAbsGradient')
		return string
		#}}}

	def setdefaultparameters(obj):
		# {{{setdefaultparameters
		
		#default is incomplete adjoint for now
		obj.incomplete_adjoint=1

		#parameter to be inferred by control methods (only
		#drag and B are supported yet)
		obj.control_parameters=['FrictionCoefficient']

		#number of steps in the control methods
		obj.nsteps=20

		#maximum number of iteration in the optimization algorithm for
		#each step
		obj.maxiter_per_step=20*ones(obj.nsteps)

		#the inversed parameter is updated as follows:
		#new_par=old_par + gradient_scaling(n)*C*gradient with C in [0 1];
		#usually the gradient_scaling must be of the order of magnitude of the 
		#inversed parameter (10^8 for B, 50 for drag) and can be decreased
		#after the first iterations
		obj.gradient_scaling=50*ones(obj.nsteps)

		#several responses can be used:
		obj.cost_functions=101*ones(obj.nsteps)

		#step_threshold is used to speed up control method. When
		#misfit(1)/misfit(0) < obj.step_threshold, we go directly to
		#the next step
		obj.step_threshold=.7*ones(obj.nsteps) #30 per cent decrement

		#stop control solution at the gradient computation and return it? 
		obj.gradient_only=0

		#cost_function_threshold is a criteria to stop the control methods.
		#if J[n]-J[n-1]/J[n] < criteria, the control run stops
		#NaN if not applied
		obj.cost_function_threshold=NaN #not activated 

		return obj
		#}}}


