#include"../common/define.h"
#include"Assemble_Base.h"

#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>


/*
2D_EigenMode
*/
void OpticsFEM_2D_EigenMode::Assemble()
{
	//判断矩阵虚实
	_mIsReal = _mMatLib->IsReal();
	if (_mIsReal)
	{
		if (_mPhy->GetNbrPML() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		for (int i = 0; i < _mPhy->GetNbrPBC(); i++)
		{
			if (_mPhy->GetPBCPhi(i).imag()!= 0.0)
			{
				_mIsReal = false;
				break;
			}
		}
	}

	//矩阵自由度 一阶基函数
	_mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();

	//波动方程
	this->Assemble_WaveEquation();

	if (_mIsReal)
	{
		_mA_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mDof, _mDof);
		_mB_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mDof, _mDof);
		_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
		_mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end());
	}
	else
	{
		_mA_complex = Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor>(_mDof, _mDof);
		_mB_complex = Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor>(_mDof, _mDof);
		_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());
		_mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end());
	}
	//完美电导体及周期边界条件处理
	if ((_mPhy->GetNbrPEC() + _mPhy->GetNbrPBC() > 0))
	{
		this->Assemble_PEC_PBC();

		if (_mIsReal)
		{
			_mA_real = (_mP_real.transpose() * _mA_real) * _mP_real;
			_mB_real = (_mP_real.transpose() * _mB_real) * _mP_real;
		}
		else
		{
			_mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex;
			_mB_complex = (_mP_complex.adjoint() * _mB_complex) * _mP_complex;
		}
	}
	else
	{
		if (_mIsReal)
		{
			_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mDof, _mDof);
			_mP_real.setIdentity();
		}
		else
		{
			_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mDof, _mDof);
			_mP_complex.setIdentity();
		}
	}
	//矩阵奇异性处理
	/*
	double k0 = 2 * Pi / _mSolver->GetLda0();
	double theta2 = k0 * k0 * _mSolver->GetSearchValue() * _mSolver->GetSearchValue();
	if (_mIsReal)
	{ 
		Eigen::SparseMatrix<double, Eigen::RowMajor> tempA = _mA_real;
		_mA_real = _mB_real;
		_mB_real = (1 / theta2) * tempA + _mB_real;
	}
	else
	{
		Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor> tempA = _mA_complex;
		_mA_complex = _mB_complex;
		_mB_complex = (1 / theta2) * tempA + _mB_complex;
	}
	*/
}

void OpticsFEM_2D_EigenMode::Run()
{
	double k0 = 2. * Pi / _mSolver->GetLda0();
	double search = -k0 * k0 * _mSolver->GetSearchValue() * _mSolver->GetSearchValue();
	if (_mIsReal)
	{
		_mSolver->GetRealFlag(_mIsReal);
		_mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real, search);
	}
	else
	{
		_mSolver->GetRealFlag(_mIsReal);
		_mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex, search);
	}
	_mSolver->Run(&_mX, &_mLambda);
}

void OpticsFEM_2D_EigenMode::Post(string file)
{
	_mPost->GetMesh(_mMesh);
	_mPost->GetSolver(_mSolver);
	_mPost->GetResult(&_mX, &_mLambda);
	_mPost->GetElectric();
	_mPost->OutputData(file);
}

/*
2D_EigenFreq
*/
void OpticsFEM_2D_EigenFreq::Assemble()
{
	//判断矩阵虚实
	_mIsReal = _mMatLib->IsReal();
	if (_mIsReal)
	{
		if (_mPhy->GetNbrPML() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		for (int i = 0; i < _mPhy->GetNbrPBC(); i++)
		{
			if (_mPhy->GetPBCPhi(i).imag()!= 0.0)
			{
				_mIsReal = false;
				break;
			}
		}
	}

	//波动方程
	this->Assemble_WaveEquation();

	//组装稀疏矩阵
	if (_mIsReal)
	{
		int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
		_mA_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(tempDof, tempDof);
		_mB_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(tempDof, tempDof);
		_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
		_mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end());
	}
	else
	{
		int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
		_mA_complex = Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor>(tempDof, tempDof);
		_mB_complex = Eigen::SparseMatrix<std::complex<double>, Eigen::RowMajor>(tempDof, tempDof);
		_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());
		_mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end());
	}

	//完美电导体及周期边界条件处理
	_mElectricType = _mSolver->GetElectricType();
	if ((_mPhy->GetNbrPEC() + _mPhy->GetNbrPBC() > 0))
	{
		this->Assemble_PEC_PBC();
	}
	else
	{
		//电场分量类型 0-Et 1-Ez 2-E
		if (_mIsReal)
		{
			std::vector<Eigen::Triplet<double>> tempTriple;
			if (_mElectricType == 0)
			{
				_mDof = _mMesh->GetNbrEdge();
				_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<double>(_mMesh->GetNbrVertex() + i, i, 1.));
				}
				_mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else if (_mElectricType == 1)
			{
				_mDof = _mMesh->GetNbrVertex();
				_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<double>(i, i, 1.));

				}
				_mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else
			{
				_mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
				_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mDof, _mDof);
				_mP_real.setIdentity();
			}

		}
		else
		{
			std::vector<Eigen::Triplet<complex<double>>> tempTriple;
			if (_mElectricType == 0)
			{
				_mDof = _mMesh->GetNbrEdge();
				_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					/*tempTriple.push_back(Eigen::Triplet<complex<double>>(_mMesh->GetNbrVertex() + i, _mMesh->GetNbrVertex() + i, 1.));*/
					tempTriple.push_back(Eigen::Triplet<complex<double>>(_mMesh->GetNbrVertex() + i, i, 1.));
				}
				_mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else if (_mElectricType == 1)
			{
				_mDof = _mMesh->GetNbrVertex();
				_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<complex<double>>(i, i, 1.));

				}
				_mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else
			{
				_mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
				_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mDof, _mDof);
				_mP_complex.setIdentity();
			}
		}

	}

	if (_mIsReal)
	{
		_mA_real = (_mP_real.transpose() * _mA_real) * _mP_real;
		_mB_real = (_mP_real.transpose() * _mB_real) * _mP_real;
	}
	else
	{
		_mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex;
		_mB_complex = (_mP_complex.adjoint() * _mB_complex) * _mP_complex;
	}
}

void OpticsFEM_2D_EigenFreq::Run()
{
	double k0 = 2. * Pi / (c_const / _mSolver->GetSearchValue());
	double search = k0 * k0;
	if (_mIsReal)
	{
		_mSolver->GetRealFlag(_mIsReal);
		_mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real, search);
	}
	else
	{
		_mSolver->GetRealFlag(_mIsReal);
		_mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex, search);
	}
	_mSolver->Run(&_mX, &_mLambda);
}

void OpticsFEM_2D_EigenFreq::Post(string file)
{
	_mPost->GetMesh(_mMesh);
	_mPost->GetSolver(_mSolver);
	_mPost->GetResult(&_mX, &_mLambda);
	_mPost->GetElectric();
	_mPost->OutputData(file);
}

/*
2D_Scatter
*/
void OpticsFEM_2D_Scatter::Assemble()
{
	_mIsReal = _mMatLib->IsReal();
	if (_mIsReal)
	{
		if (_mPhy->GetNbrPML() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		if (_mPhy->GetNbrSBC() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		/*for (int i = 0; i < _mPhy->GetNbrElE(); i++)
		{
			Eigen::Vector3cd E0;
			_mPhy->GetE0(i, E0);
			for (int j = 0; j < 3; j++)
			{
				if (E0(j).imag() != 0)
				{
					_mIsReal = false;
				}
			}
		}*/
	}
	if (_mIsReal)
	{
		for (int i = 0; i < _mPhy->GetNbrPBC(); i++)
		{
			if (_mPhy->GetPBCPhi(i).imag()!= 0.0)
			{
				_mIsReal = false;
				break;
			}
		}
	}
	if (_mIsReal)
	{
		if (_mPhy->GetBeamState() != 0)
			_mIsReal = false;
	}

	//波动方程组装
	this->Assemble_WaveEquation();

	if (_mIsReal)
	{
		int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
		_mB_real = Eigen::VectorXd::Zero(tempDof);
	}
	else
	{
		int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
		_mB_complex = Eigen::VectorXcd::Zero(tempDof);
	}

	//SBC
	if (_mPhy->GetNbrSBC() > 0)
		this->Assemble_SBC();

	//BELE
	if (_mPhy->GetNbrBELE())
		this->Assemble_BELE();
		
	if (_mIsReal)
	{
		int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
		_mA_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(tempDof, tempDof);
		_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
	}
	else
	{
		int tempDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
		_mA_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(tempDof, tempDof);
		_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());
	}

	//MAG
	if (_mPhy->GetNbrMAG())
		this->Assemble_MAG();

	//SCD
	if (_mPhy->GetNbrSCD())
		this->Assemble_SCD();

	//MPD
	if (_mPhy->GetNbrMPD())
		this->Assemble_MPD();

	//EPD
	if (_mPhy->GetNbrEPD())
		this->Assemble_EPD();

	//PEC+ELE
	this->Assemble_PEC_ELE();

	//PBC
	if (_mPhy->GetNbrPBC() > 0)
	{
		this->Assemble_PBC();
	}
	else
	{
		if (_mIsReal)
		{
			std::vector<Eigen::Triplet<double>> tempTriple;
			if (_mSolver->GetElectricType() == 0)
			{
				_mDof = _mMesh->GetNbrEdge();
				_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<double>(_mMesh->GetNbrVertex() + i, i, 1.));
				}
				_mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else if (_mSolver->GetElectricType() == 1)
			{
				_mDof = _mMesh->GetNbrVertex();
				_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<double>(i, i, 1.));

				}
				_mP_real.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else
			{
				_mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
				_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(_mDof, _mDof);
				_mP_real.setIdentity();
			}

		}
		else
		{
			std::vector<Eigen::Triplet<complex<double>>> tempTriple;
			if (_mSolver->GetElectricType() == 0)
			{
				_mDof = _mMesh->GetNbrEdge();
				_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<complex<double>>(_mMesh->GetNbrVertex() + i, i, 1.));
				}
				_mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else if (_mSolver->GetElectricType() == 1)
			{
				_mDof = _mMesh->GetNbrVertex();
				_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mMesh->GetNbrVertex() + _mMesh->GetNbrEdge(), _mDof);
				for (int i = 0; i < _mDof; i++)
				{
					tempTriple.push_back(Eigen::Triplet<complex<double>>(i, i, 1.));

				}
				_mP_complex.setFromTriplets(tempTriple.begin(), tempTriple.end());
			}
			else
			{
				_mDof = _mMesh->GetNbrVertex() + _mMesh->GetNbrEdge();
				_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(_mDof, _mDof);
				_mP_complex.setIdentity();
			}
		}
	}
	if (_mIsReal)
	{
		_mA_real = (_mP_real.transpose() * _mA_real) * _mP_real;
		_mB_real = _mP_real.transpose() * _mB_real;
	}
	else
	{
		_mA_complex = (_mP_complex.adjoint() * _mA_complex) * _mP_complex;
		_mB_complex = _mP_complex.adjoint() * _mB_complex;
	}

}

void OpticsFEM_2D_Scatter::Run()
{
	if (_mIsReal)
	{
		_mSolver->GetRealFlag(_mIsReal);
		_mSolver->SetParam(&_mA_real, &_mB_real, &_mP_real);
	}
	else
	{
		_mSolver->GetRealFlag(_mIsReal);
		_mSolver->SetParam(&_mA_complex, &_mB_complex, &_mP_complex);
	}
	_mSolver->Run(&_mX);
}

void OpticsFEM_2D_Scatter::Post(string file)
{
	_mPost->GetMesh(_mMesh);
	_mPost->GetSolver(_mSolver);
	_mPost->GetPhy(_mPhy);
	_mPost->GetResult(&_mX);
	_mPost->GetElectric();
	_mPost->OutputData(file);
}

/*
3D_EigenFreq
*/
void OpticsFEM_3D_EigenFreq::Assemble()
{
	_mIsReal = _mMatLib->IsReal();
	if (_mIsReal)
	{
		for (int i = 0; i < _mPhy->GetNbrPBC(); i++)
		{
			if (_mPhy->GetPBCPhi(i).imag()!= 0.0)
			{
				_mIsReal = false;
				break;
			}
		}
	}

	this->Assemble_WaveEquation();

	if (_mIsReal)
	{
		_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
		_mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end());
	}
	else
	{
		_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());
		_mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end());
	}

	if ((_mPhy->GetNbrPEC() + _mPhy->GetNbrPBC() > 0))
	{
		this->Assemble_PEC_PBC();
	}

}

/*
3D_Scatter
*/
void OpticsFEM_3D_Scatter::Assemble()
{
	_mIsReal = _mMatLib->IsReal();
	if (_mIsReal)
	{
		if (_mPhy->GetNbrPML() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		if (_mPhy->GetNbrSBC() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		/*for (int i = 0; i < _mPhy->GetNbrElE(); i++)
		{
			Eigen::Vector3cd E0;
			_mPhy->GetE0(i, E0);
			for (int j = 0; j < 3; j++)
			{
				if (E0(j).imag() != 0)
				{
					_mIsReal = false;
				}
			}
		}*/
	}
	if (_mIsReal)
	{
		for (int i = 0; i < _mPhy->GetNbrPBC(); i++)
		{
			if (_mPhy->GetPBCPhi(i).imag()!= 0.0)
			{
				_mIsReal = false;
				break;
			}
		}
	}

	this->Assemble_WaveEquation();

	//SBC
	this->Assemble_SBC();

	//BELE

	//Port (n+m)*(n+m)

	if (_mIsReal)
		_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
	else
		_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());

	//PEC+ELE
	this->Assemble_PEC_ELE();

	//PBC
}

/*
3D_Scatter2 
prism
*/
void OpticsFEM_3D_Scatter2::Assemble()
{
	_mIsReal = _mMatLib->IsReal();
	if (_mIsReal)
	{
		if (_mPhy->GetNbrPML() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		if (_mPhy->GetNbrSBC() > 0)
			_mIsReal = false;
	}
	if (_mIsReal)
	{
		/*for (int i = 0; i < _mPhy->GetNbrElE(); i++)
		{
			Eigen::Vector3cd E0;
			_mPhy->GetE0(i, E0);
			for (int j = 0; j < 3; j++)
			{
				if (E0(j).imag() != 0)
				{
					_mIsReal = false;
				}
			}
		}*/
	}

	this->Assemble_WaveEquation();

	//SBC
	//this->Assemble_SBC();

	//Port (n+m)*(n+m)
	//this->Assemble_PortBC();


	if (_mIsReal)
		_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
	else
		_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());

	//PEC+ELE
	//this->Assemble_PEC_ELE();
}
