#include"Assemble_Base.h"
#include"../function/BF.h"
#include"../function/Gauss.h"
#include"../common/define.h"
#include "../parser/mpParser.h"
#include"../Eigen/Sparse"
#include"../Eigen/Dense"

#include<cmath>

using namespace Eigen;

void OpticsFEM_2D_Scatter::Assemble_SBC()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();

	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	double* u, * v, * w, * wght;
	NbrGuassPoints = gauss.GetNbrGaussPoints(ONEDIM, LINE, BF_LINEFUNC * 2);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(ONEDIM, LINE, u, v, w, wght);

	//init of geo
	Vector3d* vertex = new Vector3d[5];
	Matrix3d Jac, InvJac;
	Vector3d normal;

	//init of basis function
	BF BF_Lagrange, BF_Nedelec;
	Vector3d* Et, ** Ez;
	BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);
	Et = new Vector3d[NbrGuassPoints];
	Ez = new Vector3d * [NbrGuassPoints];
	for (int i = 0; i < NbrGuassPoints; i++)
	{
		Ez[i] = new Vector3d[2];
	}

	//inite parser
	mup::ParserX p(mup::pckALL_COMPLEX);
	p.EnableAutoCreateVar(true);
	mup::Value xx, yy;
	p.DefineVar(_T("x"), mup::Variable(&xx));
	p.DefineVar(_T("y"), mup::Variable(&yy));
	Vector3cd* Einc;
	complex<double>* EincPhi;
	Einc = new Vector3cd[NbrGuassPoints];
	EincPhi = new complex<double>[NbrGuassPoints];

	//overloop of SBC
	int NbrSBC = _mPhy->GetNbrSBC();
	for (int n = 0; n < NbrSBC; n++)
	{
		//SBC data
		int SBCDomain = _mPhy->GetSBCDomain(n) + 1;
		int SBCType = _mPhy->GetSBCType(n);
		string Eincx, Eincy, Eincz;
		Vector3d kdir;
		if (SBCType == 1)
		{
			_mPhy->GetSBDir(n, kdir);
			_mPhy->GetEinc(n, Eincx, Eincy, Eincz);
		}
		VectorXi edgesIndex;
		_mMesh->GetEdgesIndexOfDomain(SBCDomain, edgesIndex);

		//overloop of edgesOfSBC
		for (int m = 0; m < edgesIndex.rows(); m++)
		{
			//edge data
			Vector2i coonOfEdges;
			_mMesh->GetCoonOfEdges(edgesIndex(m), coonOfEdges);
			int numEle = coonOfEdges(0);
			int numEdge = coonOfEdges(1);

			//coordinate of vertex,integration coordinate, and mapping
			int MappingIndex[3];
			int index[3];
			for (int i = 0; i < 3; i++)
				_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);
			if (numEdge == 0)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[1];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = 0.0;
				}

				index[0] = 1; index[1] = 2; index[2] = 1;
				MappingIndex[0] = _mMesh->GetTri(numEle, 0);
				MappingIndex[1] = _mMesh->GetTri(numEle, 1);
				MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 0) + _mMesh->GetNbrVertex();
			}
			else if (numEdge == 1)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = 0.0;
					w[i] = (u[i] + 1.0) / 2.0;
				}

				index[0] = 1; index[1] = 3; index[2] = 2;
				MappingIndex[0] = _mMesh->GetTri(numEle, 0);
				MappingIndex[1] = _mMesh->GetTri(numEle, 2);
				MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 1) + _mMesh->GetNbrVertex();
			}
			else if (numEdge == 2)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = (1.0 - u[i]) / 2.0;
				}

				index[0] = 2; index[1] = 3; index[2] = 3;
				MappingIndex[0] = _mMesh->GetTri(numEle, 1);
				MappingIndex[1] = _mMesh->GetTri(numEle, 2);
				MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 2) + _mMesh->GetNbrVertex();
			}

			//Jac
			Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
			Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
			Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
			InvJac = Jac.inverse();

			//integration coe
			double phi1 = vertex[4](1) - vertex[3](1);
			double phi2 = vertex[3](0) - vertex[4](0);
			double integCoe = 0;
			if (vertex[3](0)!= vertex[4](0))
			{
				integCoe = phi1 / phi2;
				integCoe = fabs(sqrtf(1 + integCoe * integCoe) * phi2 / 2.0);
			}
			else
			{
				integCoe = abs(phi1) / 2.0;
			}

			//normal
			_mMesh->GetNormOfEdges(_mMesh->GetDomainOfEdges(edgesIndex(m))-1, normal);

			//basis function
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				for (int j = 0; j < 2; j++)
				{
					BF_Lagrange.GetValueBF(index[j], v[i], w[i], 0.0, Ez[i][j]);
				}
				BF_Nedelec.GetValueBF(index[2], v[i], w[i], 0.0, Et[i]);
				Et[i] = InvJac * Et[i];
			}

			//material 
			double n = _mMatLib->GetN(_mMesh->GetDomainOfTri(numEle));
			complex<double> phySBC(0, k0 * n);

			//submatrix
			MatrixXcd Be;
			Be = MatrixXcd::Zero(2, 2);
			complex<double>Ae;
			for (int i = 0; i < 2; i++)
				for (int j = 0; j < 2; j++)
					for (int k = 0; k < NbrGuassPoints; k++)
					{
						Be(i, j) = Be(i, j) + wght[k] * integCoe * phySBC * (normal.cross(Ez[k][i])).dot(normal.cross(Ez[k][j]));
					}
			for (int k = 0; k < NbrGuassPoints; k++)
			{
				Ae = Ae + wght[k] * integCoe * phySBC * (normal.cross(Et[k])).dot(normal.cross(Et[k]));
			}

			//store in triple
			for (int i = 0; i < 2; i++)
				for (int j = 0; j < 2; j++)
				{
					_mTripleA_complex.push_back(Triplet<complex<double>>(MappingIndex[i], MappingIndex[j], Be(i, j)));
				}
			_mTripleA_complex.push_back(Triplet<complex<double>>(MappingIndex[2], MappingIndex[2], Ae));

			//inc
			if (SBCType == 1)
			{
				//Einc
				for (int i = 0; i < NbrGuassPoints; i++)
				{
					double tempX = Jac(0, 0) * v[i] + Jac(1, 0) * w[i] + vertex[0](0);
					double tempY = Jac(0, 1) * v[i] + Jac(1, 1) * w[i] + vertex[0](1);
					xx = Jac(0, 0) * v[i] + Jac(1, 0) * w[i] + vertex[0](0);
					yy = Jac(0, 1) * v[i] + Jac(1, 1) * w[i] + vertex[0](1);

					p.SetExpr(_T(Eincx));
					Einc[i](0).real(p.Eval().GetFloat());
					Einc[i](0).imag(p.Eval().GetImag());
					p.SetExpr(_T(Eincy));
					Einc[i](1).real(p.Eval().GetFloat());
					Einc[i](1).imag(p.Eval().GetImag());
					p.SetExpr(_T(Eincz));
					Einc[i](2).real(p.Eval().GetFloat());
					Einc[i](2).imag(p.Eval().GetImag());

					complex<double> phi(0, -k0 * n * (kdir(0) * tempX + kdir(1) * tempY));
					EincPhi[i] = exp(
						phi);
				}

				//submatrix
				complex<double> be[3];
				for (int k = 0; k < NbrGuassPoints; k++)
				{
					be[0] = be[0] + wght[k] * integCoe * phySBC * /* EincPhi[k]* */ Ez[k][0].dot(normal.cross(Einc[k].cross(normal - kdir)));
					be[1] = be[1] + wght[k] * integCoe * phySBC * /* EincPhi[k]* */ Ez[k][1].dot(normal.cross(Einc[k].cross(normal - kdir)));
					be[2] = be[2] + wght[k] * integCoe * phySBC * /* EincPhi[k]* */Et[k].dot(normal.cross(Einc[k].cross(normal - kdir)));
				}

				//store in vector
				for (int i = 0; i < 3; i++)
					_mB_complex(MappingIndex[i]) = _mB_complex(MappingIndex[i]) + be[i];

			}
		}
	}

	delete[] u, v, w, wght;

	delete[] vertex;

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		delete[] Ez[i];
	}
	delete[] Ez, Et, Einc, EincPhi;
}

void OpticsFEM_2D_Scatter::Assemble_BELE()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();

	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	double* u, * v, * w, * wght;
	NbrGuassPoints = gauss.GetNbrGaussPoints(TWODIM, TRIANGLE, BF_LINEFUNC * 2);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(TWODIM, TRIANGLE, u, v, w, wght);

	//init of geo
	Vector3d* vertex = new Vector3d[5];
	Matrix3d Jac, InvJac, TJac, JacS;

	//init of basis function
	BF BF_Lagrange, BF_Curl_Lagrange, BF_Nedelec, BF_Curl_Nedelec;
	int sdof, vdof;
	Vector3d** Et, ** curlEt, ** Ez, ** curlEz;
	/*Vector3d** bEt, ** bcurlEt, ** bEz, ** bcurlEz;*/
	sdof = BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	BF_Curl_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_CURL_LAGRANGE, BF_LINEFUNC);
	vdof = BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);
	BF_Curl_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_CURL_NEDELEC, BF_LINEFUNC);
	Et = new Vector3d * [NbrGuassPoints];
	curlEt = new Vector3d * [NbrGuassPoints];
	Ez = new Vector3d * [NbrGuassPoints];
	curlEz = new Vector3d * [NbrGuassPoints];

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		Et[i] = new Vector3d[vdof];
		curlEt[i] = new Vector3d[vdof];
		Ez[i] = new Vector3d[sdof];
		curlEz[i] = new Vector3d[sdof];
	}

	//inite parser
	mup::ParserX p(mup::pckALL_COMPLEX);
	p.EnableAutoCreateVar(true);
	mup::Value xx, yy;
	p.DefineVar(_T("x"), mup::Variable(&xx));
	p.DefineVar(_T("y"), mup::Variable(&yy));
	Vector3cd* bEt, * bEz, * bcurlEt, * bcurlEz;
	bEt = new Vector3cd[NbrGuassPoints];
	bEz = new Vector3cd[NbrGuassPoints];
	bcurlEt = new Vector3cd[NbrGuassPoints];
	bcurlEz = new Vector3cd[NbrGuassPoints];

	string Ebx, Eby, Ebz;
	_mPhy->GetEb(Ebx, Eby, Ebz);

	string curlEbx, curlEby, curlEbz;
	_mPhy->GetCurlEb(curlEbx, curlEby, curlEbz);

	//loop over tri
	int NbrTri = _mMesh->GetNbrTri();
	for (int n = 0; n < NbrTri; n++)
	{
		int domain = _mMesh->GetDomainOfTri(n);
		Eigen::VectorXi BELE;
		_mPhy->GetBELE(BELE);
		if (std::find(BELE.begin(), BELE.end(), domain) == BELE.end())
		{
			continue;
		}

		//coordinate of vertex
		for (int i = 0; i < 3; i++)
			_mMesh->GetVertex(_mMesh->GetTri(n, i), vertex[i]);

		//Jac
		Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
		Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
		Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
		InvJac = Jac.inverse();
		JacS(0, 0) = InvJac(1, 1);  JacS(0, 1) = -InvJac(1, 0); JacS(0, 2) = 0.;
		JacS(1, 0) = -InvJac(0, 1); JacS(1, 1) = InvJac(0, 0);  JacS(1, 2) = 0.;
		JacS(2, 0) = 0.;			JacS(2, 1) = 0.;		    JacS(2, 2) = 1.;
		double DetJac = fabs(Jac.determinant());
		TJac = Jac.transpose() / Jac.determinant();

		//basis function
		for (int i = 0; i < NbrGuassPoints; i++)
		{
			for (int j = 0; j < sdof; j++)
			{
				BF_Lagrange.GetValueBF(j + 1, u[i], v[i], w[i], Ez[i][j]);
				BF_Curl_Lagrange.GetValueBF(j + 1, u[i], v[i], w[i], curlEz[i][j]);
				curlEz[i][j] = JacS * curlEz[i][j];
			}
			for (int j = 0; j < vdof; j++)
			{
				BF_Nedelec.GetValueBF(j + 1, u[i], v[i], w[i], Et[i][j]);
				Et[i][j] = InvJac * Et[i][j];
				BF_Curl_Nedelec.GetValueBF(j + 1, u[i], v[i], w[i], curlEt[i][j]);
				curlEt[i][j] = TJac * curlEt[i][j];
			}
		}

		//background field
		for (int i = 0; i < NbrGuassPoints; i++)
		{
			xx = vertex[0][0] + Jac(0, 0) * u[i] + Jac(1, 0) * v[i];
			yy = vertex[0][1] + Jac(0, 0) * u[i] + Jac(1, 1) * v[i];

			p.SetExpr(_T(Ebx));
			bEt[i](0).real(p.Eval().GetFloat());
			bEt[i](0).imag(p.Eval().GetImag());
			p.SetExpr(_T(Eby));
			bEt[i](1).real(p.Eval().GetFloat());
			bEt[i](1).imag(p.Eval().GetImag());
			p.SetExpr(_T(Ebz));
			bEz[i](2).real(p.Eval().GetFloat());
			bEz[i](2).imag(p.Eval().GetImag());

			p.SetExpr(_T(curlEbx));
			bcurlEz[i](0).real(p.Eval().GetFloat());
			bcurlEz[i](0).imag(p.Eval().GetImag());
			p.SetExpr(_T(curlEby));
			bcurlEz[i](1).real(p.Eval().GetFloat());
			bcurlEz[i](1).imag(p.Eval().GetImag());
			p.SetExpr(_T(curlEbz));
			bcurlEt[i](2).real(p.Eval().GetFloat());
			bcurlEt[i](2).imag(p.Eval().GetImag());

		}

		//material
		Matrix3cd epsr = _mMatLib->GetEpsr(domain);
		Matrix3cd Mur = _mMatLib->GetMur(domain);
		Matrix3cd invMur;
		invMur = Mur.inverse();

		//submatrix
		MatrixXcd St, Sz, Tt, Tz;
		St = MatrixXcd::Zero(vdof, vdof);
		Sz = MatrixXcd::Zero(sdof, sdof);
		Tt = MatrixXcd::Zero(vdof, vdof);
		Tz = MatrixXcd::Zero(sdof, sdof);

		for (int i = 0; i < sdof; i++)
			for (int k = 0; k < NbrGuassPoints; k++)
			{
				Sz(i, 0) = Sz(i, 0) + wght[k] * DetJac * curlEz[k][i].dot(invMur * bcurlEz[k]);
				Tz(i, 0) = Tz(i, 0) + wght[k] * DetJac * k0 * k0 * Ez[k][i].dot(epsr * bEz[k]);
			}
		for (int i = 0; i < vdof; i++)
			for (int k = 0; k < NbrGuassPoints; k++)
			{
				St(i, 0) = St(i, 0) + wght[k] * DetJac * curlEt[k][i].dot(invMur * bcurlEt[k]);
				Tt(i, 0) = Tt(i, 0) + wght[k] * DetJac * k0 * k0 * Et[k][i].dot(epsr * bEt[k]);
			}

		//Mapping
		VectorXi MappingIndexS = VectorXi::Zero(sdof);
		VectorXi MappingIndexV = VectorXi::Zero(vdof);

		for (int i = 0; i < 3; i++)
		{
			MappingIndexS(i) = _mMesh->GetTri(n, i);
			MappingIndexV(i) = _mMesh->GetEdgeOfTri(n, i) + _mMesh->GetNbrVertex();
			_mB_complex(MappingIndexS[i]) = _mB_complex(MappingIndexS[i]) + Tz(i, 0) - Sz(i, 0);
			_mB_complex(MappingIndexV[i]) = _mB_complex(MappingIndexV[i]) + Tt(i, 0) - St(i, 0);
		}
	}

	//Line
	//init of Gauss point
	NbrGuassPoints = gauss.GetNbrGaussPoints(ONEDIM, LINE, BF_LINEFUNC * 4);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(ONEDIM, LINE, u, v, w, wght);

	Eigen::VectorXi BELE;
	_mPhy->GetBELE(BELE);
	int NbrBELE = BELE.rows();
	//find PML index
	int NbrPML = _mPhy->GetNbrPML();
	Eigen::VectorXi PMLEdge = Eigen::VectorXi::Zero(NbrPML);
	for (int i = 0; i < NbrPML; i++)
		PMLEdge(i) = _mPhy->GetPMLEdge(i) + 1;
	Eigen::VectorXi edgeIndexOfPML, edgeNumOfPML;//edges索引 对应ELE索引
	_mMesh->GetIndexOfDomain2(PMLEdge, edgeIndexOfPML, edgeNumOfPML);

	//overloop of edgesOfBELE
	for (int m = 0; m < edgeNumOfPML.rows(); m++)
	{
		//edge data
		Vector2i coonOfEdges;
		_mMesh->GetCoonOfEdges(edgeIndexOfPML(m), coonOfEdges);
		int numEle = coonOfEdges(0);
		int numEdge = coonOfEdges(1);

		//coordinate of vertex,integration coordinate, and mapping
		int index[3];
		for (int i = 0; i < 3; i++)
			_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);
		if (numEdge == 0)
		{
			vertex[3] = vertex[0];
			vertex[4] = vertex[1];

			for (int i = 0; i < NbrGuassPoints; i++)
			{
				v[i] = (u[i] + 1.0) / 2.0;
				w[i] = 0.0;
			}
		}
		else if (numEdge == 1)
		{
			vertex[3] = vertex[0];
			vertex[4] = vertex[2];

			for (int i = 0; i < NbrGuassPoints; i++)
			{
				v[i] = 0.0;
				w[i] = (u[i] + 1.0) / 2.0;
			}
		}
		else if (numEdge == 2)
		{
			vertex[3] = vertex[1];
			vertex[4] = vertex[2];

			for (int i = 0; i < NbrGuassPoints; i++)
			{
				v[i] = (u[i] + 1.0) / 2.0;
				w[i] = (1.0 - u[i]) / 2.0;
			}
		}
		//Jac
		Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
		Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
		Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
		InvJac = Jac.inverse();
		//integration coe
		double phi1 = vertex[4](1) - vertex[3](1);
		double phi2 = vertex[3](0) - vertex[4](0);
		double integCoe = 0;
		if (vertex[3](0) != vertex[4](0))
		{
			integCoe = phi1 / phi2;
			integCoe = fabs(sqrtf(1 + integCoe * integCoe) * phi2 / 2.0);
		}
		else
		{
			integCoe = abs(phi1) / 2.0;
		}

		//normal
		Vector3d normal;
		int edge = _mMesh->GetDomainOfEdges(edgeNumOfPML(m));
		_mMesh->GetNormOfEdges(_mMesh->GetDomainOfEdges(edgeNumOfPML(m)) - 1, normal);


		if (normal.isZero())
		{
			normal[0] = (vertex[3](0) + vertex[4](0)) / 2 - normal[0];
			normal[1] = (vertex[3](1) + vertex[4](1)) / 2 - normal[1];
			normal[2] = 0;
			normal.normalize();
		}

		//basis function
		for (int i = 0; i < NbrGuassPoints; i++)
		{
			for (int j = 0; j < sdof; j++)
			{
				BF_Lagrange.GetValueBF(j + 1, v[i], w[i], 0.0, Ez[i][j]);

			}
			for (int j = 0; j < vdof; j++)
			{
				BF_Nedelec.GetValueBF(j + 1, v[i], w[i], 0.0, Et[i][j]);
				Et[i][j] = InvJac * Et[i][j];
			}
		}
		//back ground field
		for (int i = 0; i < NbrGuassPoints; i++)
		{
			xx = vertex[0][0] + Jac(0, 0) * v[i] + Jac(1, 0) * w[i];
			yy = vertex[0][1] + Jac(0, 0) * v[i] + Jac(1, 1) * w[i];

			p.SetExpr(_T(curlEbx));
			bcurlEz[i](0).real(p.Eval().GetFloat());
			bcurlEz[i](0).imag(p.Eval().GetImag());
			p.SetExpr(_T(curlEby));
			bcurlEz[i](1).real(p.Eval().GetFloat());
			bcurlEz[i](1).imag(p.Eval().GetImag());
			p.SetExpr(_T(curlEbz));
			bcurlEt[i](2).real(p.Eval().GetFloat());
			bcurlEt[i](2).imag(p.Eval().GetImag());
		}
		//submatrix
		MatrixXcd bz, bt;
		bz = MatrixXcd::Zero(3, 1);
		bt = MatrixXcd::Zero(3, 1);
		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < NbrGuassPoints; j++)
			{
				bz(i) = bz(i) - wght[j] * integCoe * Ez[j][i].dot(normal.cross(bcurlEz[j]));
				bt(i) = bt(i) - wght[j] * integCoe * Et[j][i].dot(normal.cross(bcurlEt[j]));
			}

		}
		//Mapping
		VectorXi MappingIndexS = VectorXi::Zero(sdof);
		VectorXi MappingIndexV = VectorXi::Zero(vdof);
		for (int i = 0; i < 3; i++)
		{
			MappingIndexS(i) = _mMesh->GetTri(numEle, i);
			MappingIndexV(i) = _mMesh->GetEdgeOfTri(numEle, i) + _mMesh->GetNbrVertex();
			_mB_complex(MappingIndexS[i]) = _mB_complex(MappingIndexS[i]) + bz(i);
			_mB_complex(MappingIndexV[i]) = _mB_complex(MappingIndexV[i]) + bt(i);
		}
	}

	delete[] u, v, w, wght;
	delete[] vertex;

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		delete[] Et[i], curlEt[i], Ez[i], curlEz[i];
	}
	delete[] Et, curlEt, Ez, curlEz, bEt, bcurlEt, bEz, bcurlEz;
}

void OpticsFEM_2D_Scatter::Assemble_MAG()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();

	//Line
	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	double* u, * v, * w, * wght;
	NbrGuassPoints = gauss.GetNbrGaussPoints(ONEDIM, LINE, BF_LINEFUNC * 4);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(ONEDIM, LINE, u, v, w, wght);

	//init of basis function
	Vector3d* vertex = new Vector3d[5];
	Matrix3d Jac, InvJac, TJac, JacS;

	//init of basis function
	BF BF_Lagrange, BF_Curl_Lagrange, BF_Nedelec, BF_Curl_Nedelec;
	Vector3d** Et, ** Ez;
	int sdof, vdof;
	Et = new Vector3d * [NbrGuassPoints];
	Ez = new Vector3d * [NbrGuassPoints];
	sdof = BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	vdof = BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		Et[i] = new Vector3d[vdof];
		Ez[i] = new Vector3d[sdof];
	}

	//inite parser
	mup::ParserX p(mup::pckALL_COMPLEX);
	p.EnableAutoCreateVar(true);
	mup::Value xx, yy;
	p.DefineVar(_T("x"), mup::Variable(&xx));
	p.DefineVar(_T("y"), mup::Variable(&yy));
	Vector3cd * bcurlEt, * bcurlEz;
	bcurlEt = new Vector3cd[NbrGuassPoints];
	bcurlEz = new Vector3cd[NbrGuassPoints];
	
	//find MAG index
	int NbrMAG = _mPhy->GetNbrMAG();
	string H0x, H0y, H0z;
	Eigen::VectorXi MAGDomain = Eigen::VectorXi::Zero(1);
	for (int n = 0; n < NbrMAG; n++)
	{
		_mPhy->GetH0(H0x, H0y, H0z, n);
		MAGDomain(0) = _mPhy->GetMAGDomain(n) + 1;
		Eigen::VectorXi edgeIndexOfMAG, edgeNumOfMAG;//edges索引 对应MAG索引
		_mMesh->GetIndexOfDomain2(MAGDomain, edgeIndexOfMAG, edgeNumOfMAG);

		//overloop of edgesOfMAG
		for (int m = 0; m < edgeNumOfMAG.rows(); m++)
		{
			//edge data
			Vector2i coonOfEdges;
			_mMesh->GetCoonOfEdges(edgeIndexOfMAG(m), coonOfEdges);
			int numEle = coonOfEdges(0);
			int numEdge = coonOfEdges(1);

			//coordinate of vertex,integration coordinate, and mapping
			int index[3];
			for (int i = 0; i < 3; i++)
				_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);
			if (numEdge == 0)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[1];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = 0.0;
				}
			}
			else if (numEdge == 1)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = 0.0;
					w[i] = (u[i] + 1.0) / 2.0;
				}
			}
			else if (numEdge == 2)
			{
				vertex[3] = vertex[1];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = (1.0 - u[i]) / 2.0;
				}
			}
			//Jac
			Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
			Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
			Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
			InvJac = Jac.inverse();
			//integration coe
			double phi1 = vertex[4](1) - vertex[3](1);
			double phi2 = vertex[3](0) - vertex[4](0);
			double integCoe = 0;
			if (vertex[3](0) != vertex[4](0))
			{
				integCoe = phi1 / phi2;
				integCoe = fabs(sqrtf(1 + integCoe * integCoe) * phi2 / 2.0);
			}
			else
			{
				integCoe = abs(phi1) / 2.0;
			}

			//normal
			Vector3d normal;
			int edge = _mMesh->GetDomainOfEdges(edgeNumOfMAG(m));
			_mMesh->GetNormOfEdges(_mMesh->GetDomainOfEdges(edgeNumOfMAG(m)) - 1, normal);

			if (normal.isZero())
			{
				normal[0] = (vertex[3](0) + vertex[4](0)) / 2 - normal[0];
				normal[1] = (vertex[3](1) + vertex[4](1)) / 2 - normal[1];
				normal[2] = 0;
				normal.normalize();
			}

			//basis function
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				for (int j = 0; j < sdof; j++)
				{
					BF_Lagrange.GetValueBF(j + 1, v[i], w[i], 0.0, Ez[i][j]);

				}
				for (int j = 0; j < vdof; j++)
				{
					BF_Nedelec.GetValueBF(j + 1, v[i], w[i], 0.0, Et[i][j]);
					Et[i][j] = InvJac * Et[i][j];
				}
			}
			//back ground field
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				xx = vertex[0][0] + Jac(0, 0) * v[i] + Jac(1, 0) * w[i];
				yy = vertex[0][1] + Jac(0, 1) * v[i] + Jac(1, 1) * w[i];

				p.SetExpr(_T(H0x));
				bcurlEz[i](0).real(p.Eval().GetFloat());
				bcurlEz[i](0).imag(p.Eval().GetImag());
				p.SetExpr(_T(H0y));
				bcurlEz[i](1).real(p.Eval().GetFloat());
				bcurlEz[i](1).imag(p.Eval().GetImag());
				p.SetExpr(_T(H0z));
				bcurlEt[i](2).real(p.Eval().GetFloat());
				bcurlEt[i](2).imag(p.Eval().GetImag());
			}
			//submatrix
			MatrixXcd bz, bt;
			bz = MatrixXcd::Zero(3, 1);
			bt = MatrixXcd::Zero(3, 1);
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < NbrGuassPoints; j++)
				{
					bz(i) = bz(i) - complex<double>(0.0, 1.0) * k0 * wght[j] * integCoe * Ez[j][i].dot(normal.cross(bcurlEz[j]));
					bt(i) = bt(i) - complex<double>(0.0, 1.0) * k0 * wght[j] * integCoe * Et[j][i].dot(normal.cross(bcurlEt[j]));
				}

			}
			//Mapping
			VectorXi MappingIndexS = VectorXi::Zero(sdof);
			VectorXi MappingIndexV = VectorXi::Zero(vdof);
			for (int i = 0; i < 3; i++)
			{
				MappingIndexS(i) = _mMesh->GetTri(numEle, i);
				MappingIndexV(i) = _mMesh->GetEdgeOfTri(numEle, i) + _mMesh->GetNbrVertex();
				_mB_complex(MappingIndexS[i]) = _mB_complex(MappingIndexS[i]) + bz(i);
				_mB_complex(MappingIndexV[i]) = _mB_complex(MappingIndexV[i]) + bt(i);
			}
		}
	}

	delete[] u, v, w, wght;
	delete[] vertex;

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		delete[] Et[i], Ez[i];
	}
	delete[] Et, Ez, bcurlEt, bcurlEz;
}

void OpticsFEM_2D_Scatter::Assemble_SCD()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();

	//Line
	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	double* u, * v, * w, * wght;
	NbrGuassPoints = gauss.GetNbrGaussPoints(ONEDIM, LINE, BF_LINEFUNC * 4);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(ONEDIM, LINE, u, v, w, wght);

	//init of basis function
	Vector3d* vertex = new Vector3d[5];
	Matrix3d Jac, InvJac, TJac, JacS;

	//init of basis function
	BF BF_Lagrange, BF_Curl_Lagrange, BF_Nedelec, BF_Curl_Nedelec;
	Vector3d** Et, ** Ez;
	int sdof, vdof;
	Et = new Vector3d * [NbrGuassPoints];
	Ez = new Vector3d * [NbrGuassPoints];
	sdof = BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	vdof = BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		Et[i] = new Vector3d[vdof];
		Ez[i] = new Vector3d[sdof];
	}

	//inite parser
	mup::ParserX p(mup::pckALL_COMPLEX);
	p.EnableAutoCreateVar(true);
	mup::Value xx, yy;
	p.DefineVar(_T("x"), mup::Variable(&xx));
	p.DefineVar(_T("y"), mup::Variable(&yy));
	Vector3cd* bEt, * bEz;
	bEt = new Vector3cd[NbrGuassPoints];
	bEz = new Vector3cd[NbrGuassPoints];

	//find SCD index
	int NbrSCD = _mPhy->GetNbrSCD();
	string J0x, J0y, J0z;
	Eigen::VectorXi SCDDomain = Eigen::VectorXi::Zero(1);
	for (int n = 0; n < NbrSCD; n++)
	{
		_mPhy->GetJ0(J0x, J0y, J0z, n);
		SCDDomain(0) = _mPhy->GetSCDDomain(n) + 1;
		Eigen::VectorXi edgeIndexOfSCD, edgeNumOfSCD;//edges索引 对应SCD索引
		_mMesh->GetIndexOfDomain2(SCDDomain, edgeIndexOfSCD, edgeNumOfSCD);
		//overloop of edgesOfSCD
		for (int m = 0; m < edgeNumOfSCD.rows(); m++)
		{
			//edge data
			Vector2i coonOfEdges;
			_mMesh->GetCoonOfEdges(edgeIndexOfSCD(m), coonOfEdges);
			int numEle = coonOfEdges(0);
			int numEdge = coonOfEdges(1);
			int index[3];
			for (int i = 0; i < 3; i++)
				_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);
			if (numEdge == 0)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[1];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = 0.0;
				}
			}
			else if (numEdge == 1)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = 0.0;
					w[i] = (u[i] + 1.0) / 2.0;
				}
			}
			else if (numEdge == 2)
			{
				vertex[3] = vertex[1];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = (1.0 - u[i]) / 2.0;
				}
			}
			//Jac
			Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
			Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
			Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
			InvJac = Jac.inverse();
			//integration coe
			double phi1 = vertex[4](1) - vertex[3](1);
			double phi2 = vertex[3](0) - vertex[4](0);
			double integCoe = 0;
			if (vertex[3](0) != vertex[4](0))
			{
				integCoe = phi1 / phi2;
				integCoe = fabs(sqrtf(1 + integCoe * integCoe) * phi2 / 2.0);
			}
			else
			{
				integCoe = abs(phi1) / 2.0;
			}

			//basis function
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				for (int j = 0; j < sdof; j++)
				{
					BF_Lagrange.GetValueBF(j + 1, v[i], w[i], 0.0, Ez[i][j]);

				}
				for (int j = 0; j < vdof; j++)
				{
					BF_Nedelec.GetValueBF(j + 1, v[i], w[i], 0.0, Et[i][j]);
					Et[i][j] = InvJac * Et[i][j];
				}
			}
			//back ground field
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				xx = vertex[0][0] + Jac(0, 0) * v[i] + Jac(1, 0) * w[i];
				yy = vertex[0][1] + Jac(0, 1) * v[i] + Jac(1, 1) * w[i];

				p.SetExpr(_T(J0x));
				bEt[i](0).real(p.Eval().GetFloat());
				bEt[i](0).imag(p.Eval().GetImag());
				p.SetExpr(_T(J0y));
				bEt[i](1).real(p.Eval().GetFloat());
				bEt[i](1).imag(p.Eval().GetImag());
				p.SetExpr(_T(J0z));
				bEz[i](2).real(p.Eval().GetFloat());
				bEz[i](2).imag(p.Eval().GetImag());
			}
			//submatrix
			MatrixXcd bz, bt;
			bz = MatrixXcd::Zero(3, 1);
			bt = MatrixXcd::Zero(3, 1);
			for (int i = 0; i < 3; i++)
			{
				for (int j = 0; j < NbrGuassPoints; j++)
				{
					bz(i) = bz(i) - complex<double>(0.0, 1.0) * sqrt(mu0 / epsilon0) * k0 * wght[j] * integCoe * Ez[j][i].dot(bEz[j]);
					bt(i) = bt(i) - complex<double>(0.0, 1.0) * sqrt(mu0 / epsilon0) * k0 * wght[j] * integCoe * Et[j][i].dot(bEt[j]);
				}

			}
			//Mapping
			VectorXi MappingIndexS = VectorXi::Zero(sdof);
			VectorXi MappingIndexV = VectorXi::Zero(vdof);
			for (int i = 0; i < 3; i++)
			{
				MappingIndexS(i) = _mMesh->GetTri(numEle, i);
				MappingIndexV(i) = _mMesh->GetEdgeOfTri(numEle, i) + _mMesh->GetNbrVertex();
				_mB_complex(MappingIndexS[i]) = _mB_complex(MappingIndexS[i]) + bz(i);
				_mB_complex(MappingIndexV[i]) = _mB_complex(MappingIndexV[i]) + bt(i);
			}
		}
	}
	delete[] u, v, w, wght;
	delete[] vertex;

	for (int i = 0; i < NbrGuassPoints; i++)
	{
		delete[] Et[i], Ez[i];
	}
	delete[] Et, Ez, bEt, bEz;
}

void OpticsFEM_2D_Scatter::Assemble_MPD()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();
	Eigen::MatrixXd  m;
	Eigen::VectorXi MPD;
	_mPhy->GetMPD(MPD);
	_mPhy->GetMPDData(m);
	
	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	double* u, * v, * w, * wght;
	NbrGuassPoints = gauss.GetNbrGaussPoints(TWODIM, TRIANGLE, BF_LINEFUNC * 4);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(TWODIM, TRIANGLE, u, v, w, wght);

	//init of geo
	Vector3d* vertex = new Vector3d[3];
	Matrix3d Jac, InvJac, TJac, JacS;

	double xx, yy;
	Vector3cd* bEt, * bEz;
	bEt = new Vector3cd[NbrGuassPoints];
	bEz = new Vector3cd[NbrGuassPoints];

	
	//init of basis function
	BF BF_Lagrange, BF_Curl_Lagrange, BF_Nedelec, BF_Curl_Nedelec;
	int sdof, vdof;
	Vector3d** curlEt, ** curlEz;
	sdof = BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	BF_Curl_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_CURL_LAGRANGE, BF_LINEFUNC);
	vdof = BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);
	BF_Curl_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_CURL_NEDELEC, BF_LINEFUNC);
	curlEt = new Vector3d * [NbrGuassPoints];
	curlEz = new Vector3d * [NbrGuassPoints];
	for (int i = 0; i < NbrGuassPoints; i++)
	{
		curlEt[i] = new Vector3d[vdof];
		curlEz[i] = new Vector3d[sdof];
	}
	//loop over tri
	int NbrTri = _mMesh->GetNbrTri();
	int NbrMPD = MPD.size();
	int num = 0;
	for (int i = 0; i < NbrMPD; i++)
	{
		for (int n = 0; n < NbrTri; n++)
		{
			bool  found = false;
			for (int j = 0; j < 3; j++)
			{

				if (MPD[i] == _mMesh->GetTri(n, j))
				{
					found = true;
					break;
				}
			}

			if (found) {
				//coordinate of vertex
				num = num + 1;
				for (int j = 0; j < 3; j++)
					_mMesh->GetVertex(_mMesh->GetTri(n, j), vertex[j]);

				//Jac
				Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
				Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
				Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
				InvJac = Jac.inverse();
				JacS(0, 0) = InvJac(1, 1);  JacS(0, 1) = -InvJac(1, 0); JacS(0, 2) = 0.;
				JacS(1, 0) = -InvJac(0, 1); JacS(1, 1) = InvJac(0, 0);  JacS(1, 2) = 0.;
				JacS(2, 0) = 0.;			JacS(2, 1) = 0.;		    JacS(2, 2) = 1.;
				double DetJac = fabs(Jac.determinant());
				TJac = Jac.transpose() / Jac.determinant();

				//basis function
				for (int j = 0; j < NbrGuassPoints; j++)
				{
					for (int k = 0; k < sdof; k++)
					{
						BF_Curl_Lagrange.GetValueBF(k + 1, u[j], v[j], w[j], curlEz[j][k]);
						curlEz[j][k] = JacS * curlEz[j][k];
					}
					for (int k = 0; k < vdof; k++)
					{
						BF_Curl_Nedelec.GetValueBF(k + 1, u[j], v[j], w[j], curlEt[j][k]);
						curlEt[j][k] = TJac * curlEt[j][k];
					}
				}

				//submatrix
				Eigen::Vector3d m_current = m.row(i);
				MatrixXcd Tt, Tz;
				Tt = MatrixXcd::Zero(vdof, 1);
				Tz = MatrixXcd::Zero(sdof, 1);
				for (int j = 0; j < sdof; j++)
					for (int k = 0; k < NbrGuassPoints; k++)
					{
						Tz(j) = Tz(j) + complex<double>(0.0, -1.0) * sqrt(mu0 / epsilon0) * k0 * wght[k] * DetJac * curlEz[k][j].dot(m_current);
					}
				for (int j = 0; j < vdof; j++)
					for (int k = 0; k < NbrGuassPoints; k++)
					{
						Tt(j) = Tt(j) + complex<double>(0.0, -1.0) * sqrt(mu0 / epsilon0) * k0 * wght[k] * DetJac * curlEt[k][j].dot(m_current);
					}

				//Mapping
				VectorXi MappingIndexS = VectorXi::Zero(sdof);
				VectorXi MappingIndexV = VectorXi::Zero(vdof);
				for (int j = 0; j < 3; j++)
				{
					MappingIndexS(j) = _mMesh->GetTri(n, j);
					MappingIndexV(j) = _mMesh->GetEdgeOfTri(n, j) + _mMesh->GetNbrVertex();
					_mB_complex(MappingIndexS[j]) = _mB_complex(MappingIndexS[j]) + Tz(j);
					_mB_complex(MappingIndexV[j]) = _mB_complex(MappingIndexV[j]) + Tt(j);
				}
			}
		}		
	}
	delete[] u, v, w, wght;
	delete[] vertex;		
	for (int i = 0; i < NbrGuassPoints; i++)
	{
		delete[] curlEt[i], curlEz[i];
	}
	delete[] bEt, bEz;
	
}

void OpticsFEM_2D_Scatter::Assemble_EPD()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();
	Eigen::MatrixXd  p;
	Eigen::VectorXi EPD;
	_mPhy->GetEPD(EPD);
	_mPhy->GetEPDData(p);

	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	double* u, * v, * w, * wght;
	NbrGuassPoints = gauss.GetNbrGaussPoints(TWODIM, TRIANGLE, BF_LINEFUNC * 4);
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(TWODIM, TRIANGLE, u, v, w, wght);

	//init of geo
	Vector3d* vertex = new Vector3d[3];
	Matrix3d Jac, InvJac, TJac, JacS;

	double xx, yy;
	Vector3cd* bEt, * bEz;
	bEt = new Vector3cd[NbrGuassPoints];
	bEz = new Vector3cd[NbrGuassPoints];


	//init of basis function
	BF BF_Lagrange, BF_Curl_Lagrange, BF_Nedelec, BF_Curl_Nedelec;
	int sdof, vdof;
	Vector3d** Et, ** Ez;
	sdof = BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	BF_Curl_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_CURL_LAGRANGE, BF_LINEFUNC);
	vdof = BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);
	BF_Curl_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_CURL_NEDELEC, BF_LINEFUNC);
	Et = new Vector3d * [NbrGuassPoints];
	Ez = new Vector3d * [NbrGuassPoints];
	for (int i = 0; i < NbrGuassPoints; i++)
	{
		Et[i] = new Vector3d[vdof];
		Ez[i] = new Vector3d[sdof];
	}
	//loop over tri
	int NbrTri = _mMesh->GetNbrTri();
	int NbrEPD = EPD.size();
	int num = 0;
	for (int i = 0; i < NbrEPD; i++)
	{
		for (int n = 0; n < NbrTri; n++)
		{
			bool  found = false;
			for (int j = 0; j < 3; j++)
			{

				if (EPD[i] == _mMesh->GetTri(n, j))
				{
					found = true;
					break;
				}
			}

			if (found) {
				//coordinate of vertex
				num = num + 1;
				for (int j = 0; j < 3; j++)
					_mMesh->GetVertex(_mMesh->GetTri(n, j), vertex[j]);

				//Jac
				Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
				Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
				Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
				InvJac = Jac.inverse();
				JacS(0, 0) = InvJac(1, 1);  JacS(0, 1) = -InvJac(1, 0); JacS(0, 2) = 0.;
				JacS(1, 0) = -InvJac(0, 1); JacS(1, 1) = InvJac(0, 0);  JacS(1, 2) = 0.;
				JacS(2, 0) = 0.;			JacS(2, 1) = 0.;		    JacS(2, 2) = 1.;
				double DetJac = fabs(Jac.determinant());
				TJac = Jac.transpose() / Jac.determinant();

				//basis function
				for (int j = 0; j < NbrGuassPoints; j++)
				{
					for (int k = 0; k < sdof; k++)
					{
						BF_Lagrange.GetValueBF(k + 1, u[j], v[j], w[j], Ez[j][k]);
					}
					for (int k = 0; k < vdof; k++)
					{
						BF_Nedelec.GetValueBF(k + 1, u[j], v[j], w[j], Et[j][k]);
						Et[j][k] = InvJac * Et[j][k];
					}
				}

				//submatrix
				Eigen::Vector3d p_current = p.row(i);
				MatrixXcd Tt, Tz;
				Tt = MatrixXcd::Zero(vdof, 1);
				Tz = MatrixXcd::Zero(sdof, 1);
				for (int j = 0; j < sdof; j++)
					for (int k = 0; k < NbrGuassPoints; k++)
					{
						Tz(j) = Tz(j) + complex<double>(0.0, -1.0) * sqrt(mu0/epsilon0) * k0 * wght[k] * DetJac * Ez[k][j].dot(p_current);
					}
				for (int j = 0; j < vdof; j++)
					for (int k = 0; k < NbrGuassPoints; k++)
					{
						Tt(j) = Tt(j) + complex<double>(0.0, -1.0) * sqrt(mu0 / epsilon0) * k0 * wght[k] * DetJac * Et[k][j].dot(p_current);
					}
				//Mapping
				VectorXi MappingIndexS = VectorXi::Zero(sdof);
				VectorXi MappingIndexV = VectorXi::Zero(vdof);
				for (int j = 0; j < 3; j++)
				{
					MappingIndexS(j) = _mMesh->GetTri(n, j);
					MappingIndexV(j) = _mMesh->GetEdgeOfTri(n, j) + _mMesh->GetNbrVertex();
					_mB_complex(MappingIndexS[j]) = _mB_complex(MappingIndexS[j]) + Tz(j);
					_mB_complex(MappingIndexV[j]) = _mB_complex(MappingIndexV[j]) + Tt(j);
				}
			}
		}
	}
	delete[] u, v, w, wght;
	delete[] vertex;
	for (int i = 0; i < NbrGuassPoints; i++)
	{
		delete[] Et[i], Ez[i];
	}
	delete[] bEt, bEz;

}

void OpticsFEM_2D_Scatter::Assemble_PEC_ELE()
{
	//find PEC index
	int NbrPEC = _mPhy->GetNbrPEC();
	Eigen::VectorXi PECDomain = Eigen::VectorXi::Zero(NbrPEC);
	for (int i = 0; i < NbrPEC; i++)
		PECDomain(i) = _mPhy->GetPECDomain(i) + 1;
	Eigen::VectorXi nodeIndexOfPEC, edgeIndexOfPEC;
	_mMesh->GetIndexOfDomain(PECDomain, nodeIndexOfPEC, edgeIndexOfPEC);

	//find ELE index
	int NbrELE = _mPhy->GetNbrElE();
	Eigen::VectorXi ELEDomain = Eigen::VectorXi::Zero(NbrELE);
	for (int i = 0; i < NbrELE; i++)
		ELEDomain(i) = _mPhy->GetELEDomain(i) + 1;
	Eigen::VectorXi edgeIndexOfELE, edgeNumOfELE;//edges索引 对应ELE索引
	_mMesh->GetIndexOfDomain2(ELEDomain, edgeIndexOfELE, edgeNumOfELE);

	
	//init BCIndex BCValue
	int NbrBC = edgeIndexOfPEC.rows() + nodeIndexOfPEC.rows() + edgeNumOfELE.rows() * 3; //两边+一顶点
	Eigen::VectorXi BCIndex = Eigen::VectorXi::Zero(NbrBC);// 1:3 ELE  4:6 PEC
	Eigen::VectorXcd BCValue = Eigen::VectorXcd::Zero(NbrBC);

	//init of geo
	Vector3d* vertex = new Vector3d[5];

	//inite parser
	mup::ParserX p(mup::pckALL_COMPLEX);
	p.EnableAutoCreateVar(true);
	mup::Value xx, yy, zz;
	p.DefineVar(_T("x"), mup::Variable(&xx));
	p.DefineVar(_T("y"), mup::Variable(&yy));
	p.DefineVar(_T("z"), mup::Variable(&zz));
	Vector3cd E0;

	//overloop edge of ELE
	int bcOffset = 0;
	int NbrVertex = _mMesh->GetNbrVertex();
	for (int m = 0; m < NbrELE; m++)
	{
		Eigen::VectorXi ELEDomain = Eigen::VectorXi::Zero(NbrELE);
		ELEDomain(0) = _mPhy->GetELEDomain(m) + 1;
		Eigen::VectorXi edgeIndexOfELE, currentEdgeNum;//edges索引 对应ELE索引
		_mMesh->GetIndexOfDomain2(ELEDomain, edgeIndexOfELE, currentEdgeNum);
		string E0x, E0y, E0z;
		_mPhy->GetE0(E0x, E0y, E0z,m);
		for (int n = 0; n <currentEdgeNum.rows(); n++)
		{
			//edge data
			Eigen::Vector2i coonOfEdges;
			_mMesh->GetCoonOfEdges(edgeIndexOfELE(n), coonOfEdges);
			int numEle = coonOfEdges(0);
			int numEdge = coonOfEdges(1);

			for (int i = 0; i < 3; i++)
				_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);

			Eigen::Vector3d ee = Eigen::Vector3d::Zero();
			
			if (numEdge == 0)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[1];
				ee(0) = vertex[1](0) - vertex[0](0);
				ee(1) = vertex[1](1) - vertex[0](1);

				BCIndex(n + bcOffset)= _mMesh->GetTri(numEle, 0);
				BCIndex(n + bcOffset + edgeNumOfELE.rows()) = _mMesh->GetTri(numEle, 1);
				BCIndex(n + bcOffset + edgeNumOfELE.rows() * 2) = _mMesh->GetEdgeOfTri(numEle, 0) + NbrVertex;
			}
			else if (numEdge == 1)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];
				ee(0) = vertex[2](0) - vertex[0](0);
				ee(1) = vertex[2](1) - vertex[0](1);

				BCIndex(n + bcOffset) = _mMesh->GetTri(numEle, 0);
				BCIndex(n + bcOffset + edgeNumOfELE.rows()) = _mMesh->GetTri(numEle, 2);
				BCIndex(n + bcOffset + edgeNumOfELE.rows() * 2) = _mMesh->GetEdgeOfTri(numEle, 1) + NbrVertex;
			}
			else if (numEdge == 2)
			{
				vertex[3] = vertex[1];
				vertex[4] = vertex[2];
				ee(0) = vertex[2](0) - vertex[1](0);
				ee(1) = vertex[2](1) - vertex[1](1);

				BCIndex(n + bcOffset) = _mMesh->GetTri(numEle, 1);
				BCIndex(n + bcOffset + edgeNumOfELE.rows()) = _mMesh->GetTri(numEle, 2);
				BCIndex(n + bcOffset + edgeNumOfELE.rows() * 2) = _mMesh->GetEdgeOfTri(numEle, 2) + NbrVertex;
			}
			xx = (vertex[3](0) + vertex[4](0)) / 2;
			yy = (vertex[3](1) + vertex[4](1)) / 2;
			if (_mPhy->GetNbrBELE())
			{
				string Ebx, Eby, Ebz;
				string ExFunc, EyFunc, EzFunc;
				_mPhy->GetEb(Ebx, Eby, Ebz);
				ExFunc = E0x + "-" + Ebx;
				EyFunc = E0y + "-" + Eby;
				EzFunc = E0z + "-" + Ebz;
				p.SetExpr(_T(ExFunc));
				E0(0).real(p.Eval().GetFloat());
				E0(0).imag(p.Eval().GetImag());
				p.SetExpr(_T(EyFunc));
				E0(1).real(p.Eval().GetFloat());
				E0(1).imag(p.Eval().GetImag());

				xx = vertex[3](0); yy = vertex[4](0);
				p.SetExpr(_T(EzFunc));
				E0(2).real(p.Eval().GetFloat());
				E0(2).imag(p.Eval().GetImag());
				BCValue(n + bcOffset) = E0(2);

				xx = vertex[4](0); yy = vertex[5](0);
				p.SetExpr(_T(EzFunc));
				E0(2).real(p.Eval().GetFloat());
				E0(2).imag(p.Eval().GetImag());
				BCValue(n + bcOffset + edgeNumOfELE.rows()) = E0(2);
			}
			else
			{
				p.SetExpr(_T(E0x));
				E0(0).real(p.Eval().GetFloat());
				E0(0).imag(p.Eval().GetImag());
				p.SetExpr(_T(E0y));
				E0(1).real(p.Eval().GetFloat());
				E0(1).imag(p.Eval().GetImag());

				xx = vertex[3](0); yy = vertex[4](0);
				p.SetExpr(_T(E0z));
				E0(2).real(p.Eval().GetFloat());
				E0(2).imag(p.Eval().GetImag());
				BCValue(n + bcOffset) = E0(2);

				xx = vertex[4](0); yy = vertex[5](0);
				p.SetExpr(_T(E0z));
				E0(2).real(p.Eval().GetFloat());
				E0(2).imag(p.Eval().GetImag());
				BCValue(n + bcOffset + edgeNumOfELE.rows()) = E0(2);
			}

			BCValue(n + bcOffset + edgeNumOfELE.rows() * 2) = E0.dot(ee);
		}
		bcOffset += currentEdgeNum.rows();
	}
	delete[] vertex;

	
	//store PEC data
	for (int i = 0; i < nodeIndexOfPEC.rows(); i++)
	{
		BCIndex(i + bcOffset * 3) = nodeIndexOfPEC(i);
		BCValue(i + bcOffset * 3) = 0.;
	}
	for (int i = 0; i < edgeIndexOfPEC.rows(); i++)
	{
		BCIndex(i + bcOffset * 3 + nodeIndexOfPEC.rows()) = edgeIndexOfPEC(i) + NbrVertex;
		BCValue(i + bcOffset * 3 + nodeIndexOfPEC.rows()) = 0.;
	}

	//排序
	Eigen::VectorXi tempIndex = Eigen::VectorXi::Zero(NbrBC);
	for (int i = 0; i < NbrBC; i++)
		tempIndex(i) = i;
	QuickSort(BCIndex, tempIndex, 0, NbrBC - 1);
	
	//去重
	Unique(BCIndex, tempIndex);
	Eigen::VectorXcd tempValue = Eigen::VectorXcd::Zero(BCIndex.rows());
	for (int i = 0; i < BCIndex.rows(); i++)
		tempValue(i) = BCValue(tempIndex(i));
	BCValue = tempValue;

	
	//处理
	if (_mIsReal)
	{
		Eigen::VectorXd tempValue;
		for (int i = 0; i < BCValue.rows(); i++)
		{
			tempValue = Eigen::VectorXd::Zero(_mA_real.rows());
			tempValue(BCIndex(i)) = 1.;
			_mB_real = _mB_real - _mA_real * tempValue * BCValue(i).real();
		}
		
		Eigen::SparseMatrix<double, Eigen::RowMajor> P(_mA_real.rows(), _mA_real.rows());
		std::vector<Eigen::Triplet<double>> tempTriple;
		int num = 0;
		for (int i = 0; i < _mA_real.rows(); i++)
		{
			if (num < BCIndex.rows())
			{
				if (i == BCIndex(num))
					num++;
				else
					tempTriple.push_back(Eigen::Triplet<double>(i, i, 1.));
			}
			else
				tempTriple.push_back(Eigen::Triplet<double>(i, i, 1.));
		}
		P.setFromTriplets(tempTriple.begin(), tempTriple.end());
		_mA_real = P * _mA_real * P;
		
		P.setZero();
		tempTriple.clear();
		
		for (int i = 0; i < BCIndex.rows(); i++)
		{
			tempTriple.push_back(Eigen::Triplet<double>(BCIndex(i), BCIndex(i), 1.));
			_mB_real(BCIndex(i)) = BCValue(i).real();
		}
		P.setFromTriplets(tempTriple.begin(), tempTriple.end());
		_mA_real = _mA_real + P;
		
	}
	else
	{
		Eigen::VectorXcd tempValue;
		for (int i = 0; i < BCValue.rows(); i++)
		{
			tempValue = Eigen::VectorXcd::Zero(_mA_complex.rows());
			tempValue(BCIndex(i)) = 1;
			_mB_complex = _mB_complex - _mA_complex * tempValue * BCValue(i);
		}

		Eigen::SparseMatrix<complex<double>, Eigen::RowMajor> P(_mA_complex.rows(), _mA_complex.rows());
		std::vector<Eigen::Triplet<complex<double>>> tempTriple;
		int num = 0;
		for (int i = 0; i < _mA_complex.rows(); i++)
		{
			if (num < BCIndex.rows())
			{
				if (i == BCIndex(num))
					num++;
				else
					tempTriple.push_back(Eigen::Triplet<complex<double>>(i, i, 1.));
			}
			else
				tempTriple.push_back(Eigen::Triplet<complex<double>>(i, i, 1.));
		}
		P.setFromTriplets(tempTriple.begin(), tempTriple.end());
		_mA_complex = P * _mA_complex * P;

		P.setZero();
		tempTriple.clear();
		for (int i = 0; i < BCIndex.rows(); i++)
		{
			tempTriple.push_back(Eigen::Triplet<complex<double>>(BCIndex(i), BCIndex(i), 1.));
			_mB_complex(BCIndex(i)) = BCValue(i);
		}
		P.setFromTriplets(tempTriple.begin(), tempTriple.end());
		_mA_complex = _mA_complex + P;
	}
	
}

void OpticsFEM_2D_Scatter::Assemble_PBC()
{
	//find PBC index
	Eigen::VectorXi srcNodeIndex, dstNodeIndex, srcEdgeIndex, dstEdgeIndex;
	Eigen::VectorXcd nodePhi, edgePhi, PBCData;
	Eigen::MatrixXi PBC;
	PBC = Eigen::MatrixXi::Zero(_mPhy->GetNbrPBC(), 2);
	PBCData = Eigen::VectorXcd::Zero(_mPhy->GetNbrPBC());
	for (int i = 0; i < _mPhy->GetNbrPBC(); i++)
	{
		PBC(i, 0) = _mPhy->GetSrcDomain(i);
		PBC(i, 1) = _mPhy->GetDstDomain(i);
		PBCData(i) = _mPhy->GetPBCPhi(i);
	}
	_mMesh->GetIndexOfPBC(PBC, PBCData, srcNodeIndex, dstNodeIndex, nodePhi, srcEdgeIndex, dstEdgeIndex, edgePhi);

	//行 1:DOF
	//列 1：(DOF-NbrPEC-NbrDst)
	int NbrVertex = _mMesh->GetNbrVertex();
	int NbrDstIndex = dstNodeIndex.rows() + dstEdgeIndex.rows();

	Eigen::VectorXi dstIndex = Eigen::VectorXi::Zero(NbrDstIndex);
	Eigen::VectorXi srcIndex = Eigen::VectorXi::Zero(NbrDstIndex);
	Eigen::VectorXcd IndexPhi = Eigen::VectorXcd::Zero(NbrDstIndex);

	for (int i = 0; i < dstNodeIndex.rows(); i++)
	{
		dstIndex(i) = dstNodeIndex(i);
		srcIndex(i) = srcNodeIndex(i);
		IndexPhi(i) = nodePhi(i);
	}
	for (int i = 0; i < dstEdgeIndex.rows(); i++)
	{
		int num = dstNodeIndex.rows();
		dstIndex(i + num) = dstEdgeIndex(i) + NbrVertex;
		srcIndex(i + num) = srcEdgeIndex(i) + NbrVertex;
		IndexPhi(i + num) = edgePhi(i);
	}
	//排序
	Eigen::VectorXi tempIndex = Eigen::VectorXi::Zero(NbrDstIndex);
	for (int i = 0; i < NbrDstIndex; i++)
		tempIndex(i) = i;
	QuickSort(dstIndex, tempIndex, 0, NbrDstIndex - 1);

	//去重
	Unique(dstIndex, tempIndex);
	Eigen::VectorXcd tempIndexPhi = Eigen::VectorXcd::Zero(dstIndex.rows());
	Eigen::VectorXi tempSrcIndex = Eigen::VectorXi::Zero(dstIndex.rows());
	for (int i = 0; i < dstIndex.rows(); i++)
	{
		tempIndexPhi(i) = IndexPhi(tempIndex(i));
		tempSrcIndex(i) = srcIndex(tempIndex(i));
	}
	IndexPhi = tempIndexPhi;
	srcIndex = tempSrcIndex;

	//不同数目
	int dof = _mMesh->GetNbrEdge() + _mMesh->GetNbrVertex();
	int vdof = _mMesh->GetNbrEdge();
	int sdof = _mMesh->GetNbrVertex();

	//P矩阵
	int num = 0;
	if (_mIsReal)
	{
		std::vector<Eigen::Triplet<double>> temp_P;
		for (int i = 0; i < dof; i++) // 
		{
			temp_P.push_back(Eigen::Triplet<double>(i, i, 1));
			if (num < dstIndex.size()) //处理PBC
			{
				if (i == dstIndex(num))
				{
					temp_P.push_back(Eigen::Triplet<double>(dstIndex(num), srcIndex(num), IndexPhi(num).real()));
					num++;
				}
			}
		}
		/*临时P矩阵排序*/
		std::sort(temp_P.begin(), temp_P.end(),
			[](const Eigen::Triplet<double>& a, const Eigen::Triplet<double>& b)
			{
				return a.col() < b.col();
			});


		/*删除dstIndex对应列*/
		std::vector<Eigen::Triplet<double>> tripleP_real;
		num = 0;// 用于跟踪新矩阵的列索引
		int	DeleteIndex = 0;
		for (int i = 0; i < dof; i++)
		{
			DeleteIndex = 0;
			for (int j = 0; j < dstIndex.rows(); j++)
			{
				if (i == dstIndex[j])
				{
					DeleteIndex = 1;
				}
			}
			if (DeleteIndex != 1)
			{
				for (const auto& triplet : temp_P)
				{
					if (triplet.col() == i)
					{
						tripleP_real.push_back(Eigen::Triplet<double>(triplet.row(), triplet.col() - num, triplet.value()));
					}
				}
			}
			for (int j = 0; j < dstIndex.rows(); j++)
			{
				if (i == dstIndex[j])
				{
					num = num + 1;
				}
			}

		}
		_mP_real = Eigen::SparseMatrix<double, Eigen::RowMajor>(dof, dof - dstIndex.rows());
		_mP_real.setFromTriplets(tripleP_real.begin(), tripleP_real.end());

	}
	else
	{
		std::vector<Eigen::Triplet<complex<double>>> temp_P_complex;
		for (int i = 0; i < dof; i++) // 
		{
			temp_P_complex.push_back(Eigen::Triplet<complex<double>>(i, i, 1));
			if (num < dstIndex.size()) //处理PEC或PBC
			{
				if (i == dstIndex(num))
				{
					temp_P_complex.push_back(Eigen::Triplet<complex<double>>(dstIndex(num), srcIndex(num), IndexPhi(num)));
					num++;
				}
			}
		}
		/*临时P矩阵排序*/
		std::sort(temp_P_complex.begin(), temp_P_complex.end(),
			[](const Eigen::Triplet<complex<double>>& a, const Eigen::Triplet<complex<double>>& b)
			{
				return a.col() < b.col();
			});


		/*删除dstIndex对应列*/
		std::vector<Eigen::Triplet<complex<double>>> tripleP_complex;
		num = 0;// 用于跟踪新矩阵的列索引
		int	DeleteIndex = 0;
		for (int i = 0; i < dof; i++)
		{
			DeleteIndex = 0;
			for (int j = 0; j < dstIndex.rows(); j++)
			{
				if (i == dstIndex[j])
				{
					DeleteIndex = 1;
				}
			}
			if (DeleteIndex != 1)
			{
				for (const auto& triplet : temp_P_complex)
				{
					if (triplet.col() == i)
					{
						tripleP_complex.push_back(Eigen::Triplet<complex<double>>(triplet.row(), triplet.col() - num, triplet.value()));
					}
				}
			}
			for (int j = 0; j < dstIndex.rows(); j++)
			{
				if (i == dstIndex[j])
				{
					num = num + 1;
				}
			}

		}
		_mP_complex = Eigen::SparseMatrix<complex<double>, Eigen::RowMajor>(dof, dof - dstIndex.rows());
		_mP_complex.setFromTriplets(tripleP_complex.begin(), tripleP_complex.end());;
	}
}

void OpticsFEM_2D_Scatter::Assemble_Port()
{
	//physic
	double k0 = 2 * Pi / _mSolver->GetLda0();

	//init of Gauss point
	Gauss gauss;
	int NbrGuassPoints;
	NbrGuassPoints = gauss.GetNbrGaussPoints(ONEDIM, LINE, BF_LINEFUNC * 4);
	double* u, * v, * w, * wght;
	u = new double[NbrGuassPoints];
	v = new double[NbrGuassPoints];
	w = new double[NbrGuassPoints];
	wght = new double[NbrGuassPoints];
	gauss.GetGaussPoints(ONEDIM, LINE, u, v, w, wght);
	//init of geo
	Vector3d* vertex = new Vector3d[5];
	Matrix3d Jac, InvJac;
	Vector3d normal;

	//init of basis function
	BF BF_Lagrange, BF_Nedelec;
	Vector3d* Et, ** Ez;
	BF_Lagrange.GetNbrBF(TWODIM, TRIANGLE, BF_LAGRANGE, BF_LINEFUNC);
	BF_Nedelec.GetNbrBF(TWODIM, TRIANGLE, BF_NEDELEC, BF_LINEFUNC);
	Et = new Vector3d[NbrGuassPoints];
	Ez = new Vector3d * [NbrGuassPoints];
	for (int i = 0; i < NbrGuassPoints; i++)
	{
		Ez[i] = new Vector3d[2];
	}

	//inite parser
	mup::ParserX p(mup::pckALL_COMPLEX);
	p.EnableAutoCreateVar(true);
	mup::Value xx, yy;
	p.DefineVar(_T("x"), mup::Variable(&xx));
	p.DefineVar(_T("y"), mup::Variable(&yy));
	Vector3cd* N0, * N2, * curlN0, * curlN1, * curlN2;
	N0 = new Vector3cd[NbrGuassPoints];
	N2 = new Vector3cd[NbrGuassPoints];
	curlN0 = new Vector3cd[NbrGuassPoints];
	curlN1 = new Vector3cd[NbrGuassPoints];
	curlN2 = new Vector3cd[NbrGuassPoints];

	int NbrPortinc = _mPhy->GetNbrPortinc();
	for (int n = 0; n < NbrPortinc; n++)
	{
		int PortincDomain = _mPhy->GetPortincDomain(n) + 1;
		Eigen::VectorXi edgesIndex;
		_mMesh->GetEdgesIndexOfDomain(PortincDomain, edgesIndex);
		string Eincx, Eincy, Eincz, Eoutx, Eouty, Eoutz, EincCurlx, EincCurly, EincCurlz, EoutCurlx, EoutCurly, EoutCurlz;
		_mPhy->GetPortEinc(Eincx, Eincy, Eincz);
		_mPhy->GetPortEout(Eoutx, Eouty, Eoutz);
		_mPhy->GetPortEincCurl(EincCurlx, EincCurly, EincCurlz);
		_mPhy->GetPortEoutCurl(EoutCurlx, EoutCurly, EoutCurlz);
		//overloop of edgesOfPortinc
		for (int m = 0; m < edgesIndex.rows(); m++)
		{
			// edge data
			Vector2i coonOfEdges;
			_mMesh->GetCoonOfEdges(edgesIndex(m), coonOfEdges);
			int numEle = coonOfEdges(0);
			int numEdge = coonOfEdges(1);

			//coordinate of vertex,integration coordinate, and mapping
			int MappingIndex[3];
			int index[3];
			for (int i = 0; i < 3; i++)
				_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);
			if (numEdge == 0)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[1];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = 0.0;
				}

				index[0] = 1; index[1] = 2; index[2] = 1;
				MappingIndex[0] = _mMesh->GetTri(numEle, 0);
				MappingIndex[1] = _mMesh->GetTri(numEle, 1);
				MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 0) + _mMesh->GetNbrVertex();
			}
			else if (numEdge == 1)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = 0.0;
					w[i] = (u[i] + 1.0) / 2.0;
				}

				index[0] = 1; index[1] = 3; index[2] = 2;
				MappingIndex[0] = _mMesh->GetTri(numEle, 0);
				MappingIndex[1] = _mMesh->GetTri(numEle, 2);
				MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 1) + _mMesh->GetNbrVertex();
			}
			else if (numEdge == 2)
			{
				vertex[3] = vertex[0];
				vertex[4] = vertex[2];

				for (int i = 0; i < NbrGuassPoints; i++)
				{
					v[i] = (u[i] + 1.0) / 2.0;
					w[i] = (1.0 - u[i]) / 2.0;
				}

				index[0] = 2; index[1] = 3; index[2] = 3;
				MappingIndex[0] = _mMesh->GetTri(numEle, 1);
				MappingIndex[1] = _mMesh->GetTri(numEle, 2);
				MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 2) + _mMesh->GetNbrVertex();
			}

			//Jac
			Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
			Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
			Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
			InvJac = Jac.inverse();

			//integration coe
			double phi1 = vertex[4](1) - vertex[3](1);
			double phi2 = vertex[3](0) - vertex[4](0);
			double integCoe = 0;
			if (vertex[3](0) != vertex[4](0))
			{
				integCoe = phi1 / phi2;
				integCoe = fabs(sqrtf(1 + integCoe * integCoe) * phi2 / 2.0);
			}
			else
			{
				integCoe = abs(phi1) / 2.0;
			}

			//normal
			_mMesh->GetNormOfEdges(_mMesh->GetDomainOfEdges(edgesIndex(m)) - 1, normal);

			//basis function
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				for (int j = 0; j < 2; j++)
				{
					BF_Lagrange.GetValueBF(index[j], v[i], w[i], 0.0, Ez[i][j]);
				}
				BF_Nedelec.GetValueBF(index[2], v[i], w[i], 0.0, Et[i]);
				Et[i] = InvJac * Et[i];
			}
			for (int i = 0; i < NbrGuassPoints; i++)
			{
				double tempX = Jac(0, 0) * v[i] + Jac(1, 0) * w[i] + vertex[0](0);
				double tempY = Jac(0, 1) * v[i] + Jac(1, 1) * w[i] + vertex[0](1);
				xx = Jac(0, 0) * v[i] + Jac(1, 0) * w[i] + vertex[0](0);
				yy = Jac(0, 1) * v[i] + Jac(1, 1) * w[i] + vertex[0](1);
				//入射场N0
				p.SetExpr(_T(Eincx));
				N0[i](0).real(p.Eval().GetFloat());
				N0[i](0).imag(p.Eval().GetImag());
				p.SetExpr(_T(Eincy));
				N0[i](1).real(p.Eval().GetFloat());
				N0[i](1).imag(p.Eval().GetImag());
				p.SetExpr(_T(Eincz));
				N0[i](2).real(p.Eval().GetFloat());
				N0[i](2).imag(p.Eval().GetImag());

				//出射场N2
				p.SetExpr(_T(Eoutx));
				N2[i](0).real(p.Eval().GetFloat());
				N2[i](0).imag(p.Eval().GetImag());
				p.SetExpr(_T(Eincy));
				N0[i](1).real(p.Eval().GetFloat());
				N0[i](1).imag(p.Eval().GetImag());
				p.SetExpr(_T(Eincz));
				N0[i](2).real(p.Eval().GetFloat());
				N0[i](2).imag(p.Eval().GetImag());

				//入射场N0旋度
				p.SetExpr(_T(EincCurlx));
				curlN0[i](0).real(p.Eval().GetFloat());
				curlN0[i](0).imag(p.Eval().GetImag());
				p.SetExpr(_T(EincCurly));
				curlN0[i](1).real(p.Eval().GetFloat());
				curlN0[i](1).imag(p.Eval().GetImag());
				p.SetExpr(_T(EincCurlz));
				curlN0[i](2).real(p.Eval().GetFloat());
				curlN0[i](2).imag(p.Eval().GetImag());

				//入射场N1旋度
				curlN1[i](0) = std::conj(curlN0[i](0));
				curlN1[i](1) = std::conj(curlN0[i](1));
				curlN1[i](2) = std::conj(curlN0[i](2));
				//出射场N2
				p.SetExpr(_T(EoutCurlx));
				curlN2[i](0).real(p.Eval().GetFloat());
				curlN2[i](0).imag(p.Eval().GetImag());
				p.SetExpr(_T(EoutCurly));
				curlN2[i](1).real(p.Eval().GetFloat());
				curlN2[i](1).imag(p.Eval().GetImag());
				p.SetExpr(_T(EoutCurlz));
				curlN2[i](2).real(p.Eval().GetFloat());
				curlN2[i](2).imag(p.Eval().GetImag());
			}

			//material 
			int domain = _mMesh->GetDomainOfTri(n);
			Matrix3cd epsr = _mMatLib->GetEpsr(domain);
			Matrix3cd refra = epsr.cwiseSqrt();

			//submatrix
			MatrixXcd Se1, Ge1, be1;
			Se1 = MatrixXcd::Zero(2, 1);
			Ge1 = MatrixXcd::Zero(2, 1);
			be1 = MatrixXcd::Zero(2, 1);
			complex<double>Se2, Ge2, be2;
			for (int i = 0; i < 2; i++)
			{
				for (int k = 0; k < NbrGuassPoints; k++)
				{
					be1(i, 0) = be1(i, 0) + wght[k] * integCoe * Ez[k][i].dot(curlN0[k].cross(refra * normal));
					Se1(i, 0) = Se1(i, 0) + wght[k] * integCoe * Ez[k][i].dot(curlN1[k].cross(refra * normal));
					Ge1(i, 0) = Ge1(i, 0) + wght[k] * integCoe * N0[k].dot(normal.cross(Ez[k][i].cross(normal)));
				}
			}
			for (int k = 0; k < NbrGuassPoints; k++)
			{
				be2 = be2 + wght[k] * integCoe * Et[k].dot(curlN0[k].cross(refra * normal));
				Se2 = Se2 + wght[k] * integCoe * Et[k].dot(curlN1[k].cross(refra * normal));
				Ge2 = Ge2 + wght[k] * integCoe * N0[k].dot(normal.cross(Et[k].cross(normal)));
				P1 = P1 + wght[k] * integCoe * N0[k].dot(normal.cross(N0[k].cross(normal)));
				b1 = b1 + wght[k] * integCoe * N0[k].dot(normal.cross(N0[k].cross(normal)));
			}
			//组装矩阵
			for (int i = 0; i < 2; i++)
			{
				_mPort_B_complex(MappingIndex[i]) = _mPort_B_complex(MappingIndex[i]) - be1(i, 0);
				_mS_complex(MappingIndex[i]) = _mS_complex(MappingIndex[i]) + Se1(i, 0);
				_mG1_complex(MappingIndex[i]) = _mG1_complex(MappingIndex[i]) + Ge1(i, 0);
			}
			_mPort_B_complex(MappingIndex[2]) = _mPort_B_complex(MappingIndex[2]) - be2;
			_mS_complex(MappingIndex[2]) = _mS_complex(MappingIndex[2]) + Se2;
			_mG1_complex(MappingIndex[2]) = _mG1_complex(MappingIndex[2]) + Ge2;


			//出射端口
			int PortoutDomain = _mPhy->GetPortoutDomain(n) + 1;
			Eigen::VectorXi edgesIndex;
			_mMesh->GetEdgesIndexOfDomain(PortoutDomain, edgesIndex);
			for (int m = 0; m < edgesIndex.rows(); m++)
			{
				// edge data
				Vector2i coonOfEdges;
				_mMesh->GetCoonOfEdges(edgesIndex(m), coonOfEdges);
				int numEle = coonOfEdges(0);
				int numEdge = coonOfEdges(1);

				//coordinate of vertex,integration coordinate, and mapping
				int MappingIndex[3];
				int index[3];
				for (int i = 0; i < 3; i++)
					_mMesh->GetVertex(_mMesh->GetTri(numEle, i), vertex[i]);
				if (numEdge == 0)
				{
					vertex[3] = vertex[0];
					vertex[4] = vertex[1];

					for (int i = 0; i < NbrGuassPoints; i++)
					{
						v[i] = (u[i] + 1.0) / 2.0;
						w[i] = 0.0;
					}

					index[0] = 1; index[1] = 2; index[2] = 1;
					MappingIndex[0] = _mMesh->GetTri(numEle, 0);
					MappingIndex[1] = _mMesh->GetTri(numEle, 1);
					MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 0) + _mMesh->GetNbrVertex();
				}
				else if (numEdge == 1)
				{
					vertex[3] = vertex[0];
					vertex[4] = vertex[2];

					for (int i = 0; i < NbrGuassPoints; i++)
					{
						v[i] = 0.0;
						w[i] = (u[i] + 1.0) / 2.0;
					}

					index[0] = 1; index[1] = 3; index[2] = 2;
					MappingIndex[0] = _mMesh->GetTri(numEle, 0);
					MappingIndex[1] = _mMesh->GetTri(numEle, 2);
					MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 1) + _mMesh->GetNbrVertex();
				}
				else if (numEdge == 2)
				{
					vertex[3] = vertex[0];
					vertex[4] = vertex[2];

					for (int i = 0; i < NbrGuassPoints; i++)
					{
						v[i] = (u[i] + 1.0) / 2.0;
						w[i] = (1.0 - u[i]) / 2.0;
					}

					index[0] = 2; index[1] = 3; index[2] = 3;
					MappingIndex[0] = _mMesh->GetTri(numEle, 1);
					MappingIndex[1] = _mMesh->GetTri(numEle, 2);
					MappingIndex[2] = _mMesh->GetEdgeOfTri(numEle, 2) + _mMesh->GetNbrVertex();
				}

				//Jac
				Jac(0, 0) = vertex[1](0) - vertex[0](0); Jac(0, 1) = vertex[1](1) - vertex[0](1); Jac(0, 2) = 0.;
				Jac(1, 0) = vertex[2](0) - vertex[0](0); Jac(1, 1) = vertex[2](1) - vertex[0](1); Jac(1, 2) = 0.;
				Jac(2, 0) = 0.;			Jac(2, 1) = 0.;			Jac(2, 2) = 1.;
				InvJac = Jac.inverse();

				//integration coe
				double phi1 = vertex[4](1) - vertex[3](1);
				double phi2 = vertex[3](0) - vertex[4](0);
				double integCoe = 0;
				if (vertex[3](0) != vertex[4](0))
				{
					integCoe = phi1 / phi2;
					integCoe = fabs(sqrtf(1 + integCoe * integCoe) * phi2 / 2.0);
				}
				else
				{
					integCoe = abs(phi1) / 2.0;
				}

				//normal
				_mMesh->GetNormOfEdges(_mMesh->GetDomainOfEdges(edgesIndex(m)) - 1, normal);

				//basis function
				for (int i = 0; i < NbrGuassPoints; i++)
				{
					for (int j = 0; j < 2; j++)
					{
						BF_Lagrange.GetValueBF(index[j], v[i], w[i], 0.0, Ez[i][j]);
					}
					BF_Nedelec.GetValueBF(index[2], v[i], w[i], 0.0, Et[i]);
					Et[i] = InvJac * Et[i];
				}
				for (int i = 0; i < NbrGuassPoints; i++)
				{
					double tempX = Jac(0, 0) * v[i] + Jac(1, 0) * w[i] + vertex[0](0);
					double tempY = Jac(0, 1) * v[i] + Jac(1, 1) * w[i] + vertex[0](1);
					xx = Jac(0, 0) * v[i] + Jac(1, 0) * w[i] + vertex[0](0);
					yy = Jac(0, 1) * v[i] + Jac(1, 1) * w[i] + vertex[0](1);
					//入射场N0
					p.SetExpr(_T(Eincx));
					N0[i](0).real(p.Eval().GetFloat());
					N0[i](0).imag(p.Eval().GetImag());
					p.SetExpr(_T(Eincy));
					N0[i](1).real(p.Eval().GetFloat());
					N0[i](1).imag(p.Eval().GetImag());
					p.SetExpr(_T(Eincz));
					N0[i](2).real(p.Eval().GetFloat());
					N0[i](2).imag(p.Eval().GetImag());

					//出射场N2
					p.SetExpr(_T(Eoutx));
					N2[i](0).real(p.Eval().GetFloat());
					N2[i](0).imag(p.Eval().GetImag());
					p.SetExpr(_T(Eouty));
					N2[i](1).real(p.Eval().GetFloat());
					N2[i](1).imag(p.Eval().GetImag());
					p.SetExpr(_T(Eoutz));
					N2[i](2).real(p.Eval().GetFloat());
					N2[i](2).imag(p.Eval().GetImag());

					//入射场N0旋度
					p.SetExpr(_T(EincCurlx));
					curlN0[i](0).real(p.Eval().GetFloat());
					curlN0[i](0).imag(p.Eval().GetImag());
					p.SetExpr(_T(EincCurly));
					curlN0[i](1).real(p.Eval().GetFloat());
					curlN0[i](1).imag(p.Eval().GetImag());
					p.SetExpr(_T(EincCurlz));
					curlN0[i](2).real(p.Eval().GetFloat());
					curlN0[i](2).imag(p.Eval().GetImag());

					//入射场N1旋度
					curlN1[i](0) = std::conj(curlN0[i](0));
					curlN1[i](1) = std::conj(curlN0[i](1));
					curlN1[i](2) = std::conj(curlN0[i](2));
					//出射场N2
					p.SetExpr(_T(EoutCurlx));
					curlN2[i](0).real(p.Eval().GetFloat());
					curlN2[i](0).imag(p.Eval().GetImag());
					p.SetExpr(_T(EoutCurly));
					curlN2[i](1).real(p.Eval().GetFloat());
					curlN2[i](1).imag(p.Eval().GetImag());
					p.SetExpr(_T(EoutCurlz));
					curlN2[i](2).real(p.Eval().GetFloat());
					curlN2[i](2).imag(p.Eval().GetImag());
				}

				//material 
				int domain = _mMesh->GetDomainOfTri(n);
				Matrix3cd epsr = _mMatLib->GetEpsr(domain);
				Matrix3cd refra = epsr.cwiseSqrt();

				//submatrix
				MatrixXcd Te1, Ge1;
				Te1 = MatrixXcd::Zero(2, 1);
				Ge1 = MatrixXcd::Zero(2, 1);
				complex<double>P2;
				for (int i = 0; i < 2; i++)
				{
					for (int k = 0; k < NbrGuassPoints; k++)
					{
						Te1(i, 0) = Te1(i, 0) + wght[k] * integCoe * Ez[k][i].dot(curlN2[k].cross(refra * normal));
						Ge1(i, 0) = Ge1(i, 0) + wght[k] * integCoe * N2[k].dot(normal.cross(Ez[k][i].cross(normal)));
						P2 = P2 + wght[k] * integCoe * N2[k].dot(normal.cross(N2[k].cross(normal)));
					}
				}
				complex<double>Te2, Ge2;
				for (int k = 0; k < NbrGuassPoints; k++)
				{
					Te2 = Te2 + wght[k] * integCoe * Et[k].dot(curlN2[k].cross(refra * normal));
					Ge2 = Ge2 + wght[k] * integCoe * N2[k].dot(normal.cross(Et[k].cross(normal)));
				}

				//组装矩阵
				for (int i = 0; i < 2; i++)
				{
					_mT_complex(MappingIndex[i]) = _mT_complex(MappingIndex[i]) + Te1(i, 0);
					_mG2_complex(MappingIndex[i]) = _mG2_complex(MappingIndex[i]) + Ge1(i, 0);
				}
				_mT_complex(MappingIndex[2]) = _mT_complex(MappingIndex[2]) + Te2;
				_mG2_complex(MappingIndex[2]) = _mG2_complex(MappingIndex[2]) + Ge2;
			}
		}
	}

	_mS_complex = _mP_complex.adjoint() * _mS_complex;
	_mT_complex = _mP_complex.adjoint() * _mT_complex;
	_mG1_complex = _mP_complex.adjoint() * _mG1_complex;
	_mG2_complex = _mP_complex.adjoint() * _mG2_complex;

	for (const auto& triplet : _mTripleA_complex)
	{
		_mTriplePort_A_complex.push_back(Triplet<complex<double>>(triplet.row(), triplet.col(), triplet.value()));
		/*std::cout << "col: " << triplet.col()  << "row: " << triplet.row() << ", Value: " << triplet.value() << std::endl;*/
	}
	for (int k = 0; k < _mA_complex.outerSize(); k++)
	{
		for (Eigen::SparseMatrix<complex<double>, RowMajor>::InnerIterator it(_mA_complex, k); it; ++it)
		{
			_mTriplePort_A_complex.push_back(Triplet<complex<double>>(it.row(), it.col(), it.value()));
		}
	}
	for (int i = 0; i < _mS_complex.size(); i++) {
		_mTriplePort_A_complex.push_back(Triplet<complex<double>>(i, _mDof, _mS_complex[i]));
	}
	for (int i = 0; i < _mT_complex.size(); i++) {
		_mTriplePort_A_complex.push_back(Triplet<complex<double>>(i, _mDof + 1, _mT_complex[i]));
	}
	for (int i = 0; i < _mG1_complex.size(); i++) {
		_mTriplePort_A_complex.push_back(Triplet<complex<double>>(_mDof, i, _mG1_complex[i]));
	}
	for (int i = 0; i < _mG2_complex.size(); i++) {
		_mTriplePort_A_complex.push_back(Triplet<complex<double>>(_mDof + 1, i, _mG2_complex[i]));
	}
	_mTriplePort_A_complex.push_back(Triplet<complex<double>>(_mDof, _mDof, -P1));
	_mTriplePort_A_complex.push_back(Triplet<complex<double>>(_mDof + 1, _mDof + 1, -P2));


	_mPort_B_complex(_mDof) = b1;
	for (int k = 0; k < _mP_complex.outerSize(); k++)
	{
		for (Eigen::SparseMatrix<complex<double>, RowMajor>::InnerIterator it(_mP_complex, k); it; ++it)
		{
			_mPort_P_complex.coeffRef(it.row(), it.col()) = it.value();
		}
	}
}