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

/**
 * @file PowerFlowProblem.h
 * PowerFlowProblem class header.
 */
#ifndef PowerFlower_PowerFlowProblem_h
#define PowerFlower_PowerFlowProblem_h

#include "../PetscUtils/PetscUtils.h"				// USES PetscUtils
#include "../NonLinearSolver/NonLinearProblem.h"	// ISA NonLinearProblem
#include "EquationMap.h"							// HASA EquationMap
#include "VoltageVector.h"							// HASA VoltageVector
#include "PowerFlower.def"

POWERFLOWER_NAMESPACE_BEGIN

// FORWARD DECLARATIONS
class LogEvents;
class PowerSystemExt;
class PowerVector;
class AdmittanceMatrix;

/**
 * Power flow problem class.
 * Implements the non-linear power flow problem.
 */
class PowerFlowProblem : public NONLINEARSOLVER_NAMESPACE_NAME::NonLinearProblem
{
public:
	// LIFECYCLE
	PowerFlowProblem(void);
	PowerFlowProblem(const LogEvents* pLogEvents);
	~PowerFlowProblem(void);

	// OPERATIONS

	/**
	 * Clears the power flow problem object data.
	 */
	void Clear(void);

	/**
	 * Sets the power system on which the power flow problem is based.
	 * Power vector, and admittance matrix should be properly calculated in the power system,
	 * before setting the power system in the power flow problem.
	 * The initial solution is set to a flat start voltage vector.
	 * Any change to the power system object will invalidate the power flow problem object.
	 * @param rPowerSystem power system on which the power flow problem is based.
	 * @return \c true on success, \c false otherwise.
	 */
	bool SetPowerSystem(const PowerSystemExt& rPowerSystem);

	/**
	 * Updates the power system on which the power flow problem is based.
	 * The initial solution is set to a flat start voltage vector.
	 * Any change to the power system object will invalidate the power flow problem object.
	 * \warning Only use if the power system has the same bus and branch structure as the currently set power system.
	 * @param rPowerSystem power system with the same bus and branch structure as the system on which the power flow problem is currently based.
	 * @return \c true on success, \c false otherwise.
	 */
	bool UpdatePowerSystem(const PowerSystemExt& rPowerSystem);  // :TODO: hasSameBusses, hasSameBranches?

	/**
	 * Sets the initial solution of the power flow problem.
	 * @param rVoltageVector voltage vector to use as initial solution.
	 * @return \c true on success, \c false otherwise.
	 */
	bool SetInitialSolution(const VoltageVector& rVoltageVector);

	PetscErrorCode CalculateFunctionVector(SNES snes, Vec pX, Vec pF);
	PetscErrorCode CalculateJacobianMatrix(SNES snes, Vec pX, Mat* ppJ);

	// ACCESS
	Vec GetSolutionVector(void);
	Vec GetFunctionVector(void);
	Mat GetJacobianMatrix(void);
	bool IsJacobianMatrixStructureSame(void) const;

	/**
	 * Gets the voltage vector.
	 * The voltage vector is updated every time the solution vector is updated,
	 * which is when the mismatch vector and Jacobian matrix are calculated.
	 * Thus the voltage vector always reflects the current solution of the power flow problem.
	 * @return voltage vector.
	 */
	const VoltageVector* GetVoltageVector(void) const;

private:
	/**
	 * Creates the Jacobian system.
	 * Allocates memory for the initial solution vector, mismatch vector, and Jacobian matrix.
	 * Also calculates and sets the proper nonzero structure for the Jacobian matrix.
	 * @return \c true on success, \c false otherwise.
	 */
	bool CreateJacobianSystem(void);

	/**
	 * Updates the Jacobian system.
	 * Resets the not-owned pointers to the owned pointers, and calculates the initial solution vector, mismatch vector, and Jacobian matrix.
	 * Creates the Jacobian system if it was not yet created.
	 * @return \c true on success, \c false otherwise.
	 */
	bool UpdateJacobianSystem(void);

	/**
	 * Destroys the Jacobian system.
	 * Frees the memory of the solution vector, mismatch vector, and Jacobian matrix.
	 * @return \c true on success, \c false otherwise.
	 */
	bool DestroyJacobianSystem(void);

	/**
	 * Builds the structure of the solution vector.
	 * Sets the vector dimension and allocates the memory.
	 * @return \c true on success, \c false otherwise.
	 */
	bool BuildSolutionVectorStructure(void);

	/**
	 * Builds the structure of the mismatch vector.
	 * Sets the vector dimension and allocates the memory.
	 * @return \c true on success, \c false otherwise.
	 */
	bool BuildMismatchVectorStructure(void);

	/**
	 * Builds the structure of the Jacobian matrix.
	 * Sets the matrix dimensions and non-zero structure, and allocates the memory.
	 * @return \c true on success, \c false otherwise.
	 */
	bool BuildJacobianMatrixStructure(void);

	/**
	 * Calculates the voltage vector using the solution vector.
	 * @return \c true on success, \c false otherwise.
	 */
	bool CalculateVoltage(void);

	/**
	 * Calculates the solution vector using the voltage vector.
	 * @return \c true on success, \c false otherwise.
	 */
	bool CalculateSolution(void);

	/**
	 * Calculates mismatch vector and Jacobian matrix.
	 * Calculates the mismatch vector and Jacobian matrix values
	 * using the equation map, voltage vector, power vector, and admittance matrix.
	 * @return \c true on success, \c false otherwise.
	 */
	bool CalculateMismatchAndJacobian(void);

	PetscErrorCode mErr;	///< PETSc error code of the latest error (0 if there were no errors).
	const LogEvents* mpLogEvents;	///< PETSc log events.

	PetscInt mBusCount;		///< Number of busses in the power system, also number of rows in the admittance matrix.
	PetscInt mEqCount;		///< Number of equations in the power flow problem, also number of rows in the Jacobian matrix.
	PetscInt mMaxNnz;		///< Maximum number of nonzeros on a single row in the Jacobian.

	EquationMap mEqMap;							///< Mapping from bus index to equation index.
	VoltageVector mVoltageVector;				///< Voltage phasor vector.
	const PowerVector* mpPowerVector;			///< Injected power vector.
	const AdmittanceMatrix* mpAdmittanceMatrix;	///< Admittance matrix.

	Vec mpOwnedX;	///< Solution vector provided to PETSc SNES (owned).
	Vec mpOwnedF;	///< Mismatch vector provided to PETSc SNES (owned).
	Mat mpOwnedJ;	///< Jacobian matrix provided to PETSc SNES (owned).

	Vec mpX;		///< Solution vector as provided by PETSc SNES (not owned).
	Vec mpF;		///< Mismatch vector as provided by PETSc SNES (not owned).
	Mat mpJ;		///< Jacobian matrix as provided by PETSc SNES (not owned).

	bool mIsCalculated;		///< \c true if mismatch and Jacobian have been calculated for the current solution, \c false otherwise.
	bool mIsPrecalculated;	///< \c true if mismatch and Jacobian have been calculated for the current initial solution and CalculateFunctionVector() has not yet been called, \c false otherwise.
	bool mIsStructureSame;	///< \c false after BuildJacobianMatrixStructure(), \c true after CalculateMismatchAndJacobian().
};

POWERFLOWER_NAMESPACE_END

#endif // PowerFlower_PowerFlowProblem_h
