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

/*
 * Power System Voltage Vector class source.
 */
#include "VoltageVector.h"


POWERFLOWER_NAMESPACE_BEGIN

POWERSYSTEM_NAMESPACE_USING


/////////////////////////////// PUBLIC ///////////////////////////////////////


//============================= LIFECYCLE ====================================


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::VoltageVector"
VoltageVector::VoltageVector(void) : mErr(0), mVa(PETSC_NULL), mVm(PETSC_NULL)
{
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Creating VoltageVector object.\n"); CHKERRV(mErr);
	}
}


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::VoltageVector"
VoltageVector::VoltageVector(const VoltageVector& rSource) : mErr(0), mVa(PETSC_NULL), mVm(PETSC_NULL)
{
	if (!PetscUtils::IsInitialized()) return;
	mErr = PetscInfo(PETSC_NULL, "Copy-creating VoltageVector object.\n"); CHKERRV(mErr);
	Copy_Private(rSource);
} // VoltageVector::VoltageVector


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::~VoltageVector"
VoltageVector::~VoltageVector(void)
{
	Clear();
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Destroying VoltageVector object.\n"); CHKERRV(mErr);
	}
} // VoltageVector::~VoltageVector


//============================= OPERATORS ====================================


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::operator="
VoltageVector& VoltageVector::operator=(const VoltageVector& rSource)
{
	if (PetscUtils::IsInitialized())
	{
		Copy_Private(rSource);
	}
	return *this;
} // VoltageVector::operator=


//============================= OPERATIONS ===================================


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::Clear"
void VoltageVector::Clear(void)
{
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Clearing VoltageVector object data.\n"); CHKERRV(mErr);
		if (mVa != PETSC_NULL) { mErr = VecDestroy(&mVa); mVa = PETSC_NULL; CHKERRV(mErr); }
		if (mVm != PETSC_NULL) { mErr = VecDestroy(&mVm); mVm = PETSC_NULL; CHKERRV(mErr); }
	}
	mErr = 0;
} // VoltageVector::Clear


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::Build"
bool VoltageVector::Build(const POWERSYSTEM_NAMESPACE_NAME::PowerSystem& rPowerSystem)
{
	if (!PetscUtils::IsInitialized()) return false;
 	mErr =  PetscInfo(PETSC_NULL, "Building voltage vector.\n"); CHKERRB(mErr);
	return Build_Private(rPowerSystem, false);
} // VoltageVector::Build


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::BuildFlat"
bool VoltageVector::BuildFlat(const POWERSYSTEM_NAMESPACE_NAME::PowerSystem& rPowerSystem)
{
	if (!PetscUtils::IsInitialized()) return false;
 	mErr =  PetscInfo(PETSC_NULL, "Building flat voltage vector.\n"); CHKERRB(mErr);
	return Build_Private(rPowerSystem, true);
} // VoltageVector::BuildFlat


//============================= ACCESS     ===================================


PetscUtils::ConstVec VoltageVector::GetAng(void) const { return mVa; }
PetscUtils::ConstVec VoltageVector::GetMag(void) const { return mVm; }


/////////////////////////////// PRIVATE    ///////////////////////////////////


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::Copy_Private"
bool VoltageVector::Copy_Private(const VoltageVector& rSource)
{
	// Copy voltage angle vector
	if (mVa != PETSC_NULL) { mErr = VecDestroy(&mVa); mVa = PETSC_NULL; CHKERRB(mErr); }
	mErr = VecDuplicate(rSource.mVa, &mVa); CHKERRB(mErr);
	mErr = VecCopy(rSource.mVa, mVa); CHKERRB(mErr);

	// Copy voltage magnitude vector
	if (mVm != PETSC_NULL) { mErr = VecDestroy(&mVm); mVm = PETSC_NULL; CHKERRB(mErr); }
	mErr = VecDuplicate(rSource.mVm, &mVm); CHKERRB(mErr);
	mErr = VecCopy(rSource.mVm, mVm); CHKERRB(mErr);

	return true;
} // VoltageVector::Copy_Private


#undef __FUNCT__
#define __FUNCT__ "VoltageVector::Build_Private"
bool VoltageVector::Build_Private(const POWERSYSTEM_NAMESPACE_NAME::PowerSystem& rPowerSystem, bool isFlat)
{
 	mErr =  PetscInfo(PETSC_NULL, "Creating and preallocating voltage vector.\n"); CHKERRB(mErr);

 	// Get the number of elements in the power vector
	PetscInt n = rPowerSystem.GetBusCount();
	if (n == 0) return false;

	if (mVa != PETSC_NULL) { mErr = VecDestroy(&mVa); mVa = PETSC_NULL; CHKERRB(mErr); }
	mErr = VecCreate(PETSC_COMM_WORLD, &mVa); CHKERRB(mErr);
	mErr = VecSetSizes(mVa, n, PETSC_DETERMINE); CHKERRB(mErr);
	mErr = VecSetType(mVa, VECSEQ); CHKERRB(mErr);

	if (mVm != PETSC_NULL) { mErr = VecDestroy(&mVm); mVm = PETSC_NULL; CHKERRB(mErr); }
	mErr = VecCreate(PETSC_COMM_WORLD, &mVm); CHKERRB(mErr);
	mErr = VecSetSizes(mVm, n, PETSC_DETERMINE); CHKERRB(mErr);
	mErr = VecSetType(mVm, VECSEQ); CHKERRB(mErr);

 	mErr =  PetscInfo(PETSC_NULL, "Setting voltage vector values.\n"); CHKERRB(mErr);

 	PetscScalar *pValsVa, *pValsVm;
	mErr = VecGetArray(mVa, &pValsVa); CHKERRB(mErr);
	mErr = VecGetArray(mVm, &pValsVm); CHKERRB(mErr);
	for (PetscInt i = 0; i < n; ++i)
	{
		const POWERSYSTEM_NAMESPACE_NAME::Bus* pBus = rPowerSystem.GetBus(i);
		if (pBus == NULL) return false;

		if (!isFlat) // Not flat voltage: set prescribed values
		{
			pValsVa[i] = rPowerSystem.GetBus(i)->GetVoltageAngle();
			pValsVm[i] = rPowerSystem.GetBus(i)->GetVoltageMagnitude();
		}
		else // Flat voltage vector: only set prescribed values that are not calculated in a power flow solver
		{
			if (pBus->IsLoadType())
			{	// Load: set flat values
				pValsVa[i] = 0;
				pValsVm[i] = 1;
			}
			else
			{	// Generator or slack: set prescribed magnitude
				pValsVa[i] = 0;
				pValsVm[i] = pBus->GetVoltageMagnitude();
				if (pBus->IsSlackType())
				{	// Slack: set prescribed reference angle
					pValsVa[i] = pBus->GetVoltageAngle();
				}
			}
		}
	}
	mErr = VecRestoreArray(mVa, &pValsVa); CHKERRB(mErr);
	mErr = VecRestoreArray(mVm, &pValsVm); CHKERRB(mErr);
	return true;
} // VoltageVector::Build_Private


Vec VoltageVector::GetAngPrivate(void) { return mVa; }
Vec VoltageVector::GetMagPrivate(void) { return mVm; }


POWERFLOWER_NAMESPACE_END
