/*
 * Copyright (C) 2008-2012 Delft University of Technology - All rights reserved.
 *
 * Author: Reijer Idema
 */

/**
 * @file NonLinearProblem.h
 * NonLinearProblem class header.
 */
#ifndef NonLinearSolver_NonLinearProblem_h
#define NonLinearSolver_NonLinearProblem_h

#include "../PetscUtils/PetscUtils.h"	// USES PetscUtils
#include "NonLinearSolver.def"

NONLINEARSOLVER_NAMESPACE_BEGIN

/**
 * %NonLinearProblem abstract base class.
 * Implements an abstract non-linear problem class.
 * Derived classes should implement
 * GetSolutionVector(), GetFunctionVector(), GetJacobianMatrix(),
 * CalculateFunctionVector(), and CalculateJacobianMatrix().
 */
class NonLinearProblem
{
public:
	virtual ~NonLinearProblem(void);

	/**
	 * Calculates the function vector.
	 * Called by NonLinearSolver::CalculateFunctionWrapper().
	 * @param[in] snes PETSc non-linear equation solver object.
	 * @param[in] pX current non-linear solution iterate.
	 * @param[in,out] pF function vector.
	 * @return non-zero error code on failure, 0 on success.
	 */
	virtual PetscErrorCode CalculateFunctionVector(SNES snes, Vec pX, Vec pF) = 0;

	/**
	 * Calculates the Jacobian matrix.
	 * Called by NonLinearSolver::CalculateJacobianWrapper().
	 * @param[in] snes PETSc non-linear equation solver object.
	 * @param[in] pX current non-linear solution iterate.
	 * @param[in,out] ppJ Jacobian matrix.
	 * @return non-zero error code on failure, 0 on success.
	 */
	virtual PetscErrorCode CalculateJacobianMatrix(SNES snes, Vec pX, Mat* ppJ) = 0;

	/**
	 * Gets the solution vector.
	 * Called by NonLinearSolver::Solve() to use the returned vector as iterate vector for SNESSolve().
	 * When calling NonLinearSolver::Solve() the returned vector should be the desired starting solution.
	 * After calling NonLinearSolver::Solve() the returned vector is the solution calculated by SNESSolve().
	 * @return solution vector.
	 */
	virtual Vec GetSolutionVector(void) = 0;

	/**
	 * Gets the function vector.
	 * Called by NonLinearSolver::Solve() to use the returned vector as function vector for SNESSetFunction().
	 * @return function vector.
	 */
	virtual Vec GetFunctionVector(void) = 0;

	/**
	 * Gets the Jacobian matrix.
	 * Called by NonLinearSolver::Solve() to use the returned matrix as Jacobian matrix for SNESSetJacobian().
	 * \warning Although SNESSetJacobian() only needs the location where the Jacobian matrix will be stored,
	 * the fully calculated matrix should be returned for some preconditioners to work properly.
	 * @return Jacobian matrix.
	 */
	virtual Mat GetJacobianMatrix(void) = 0;

	/**
	 * Checks whether the non-zero structure of the Jacobian matrix stayed the same in the latest calculation.
	 * \warning if unsure about the non-zero structure, keep the default implementation which always returns \c false.
	 * @return \c true if the same, \c false if changed.
	 */
	virtual bool IsJacobianMatrixStructureSame(void) const;
};

NONLINEARSOLVER_NAMESPACE_END

#endif // NonLinearSolver_NonLinearProblem_h
