// 対角にパターンを追加
bool CZLinearSystem::AddPattern_Field(const unsigned int id_field, const CFieldWorld& world)
{
	if( !world.IsIdField(id_field) ) return false;
	const CField& field = world.GetField(id_field);
	unsigned int id_field_parent;
	{
		if( field.GetIDFieldParent() == 0 ){ id_field_parent = id_field; }
		else{ id_field_parent = field.GetIDFieldParent(); }
	}

	unsigned int nlen_value;
	{	// 複素数の場合は2で割る
		const unsigned int nlen = field.GetNLenValue();
		assert( nlen % 2 == 0 );
		nlen_value = nlen / 2;
	}

	int ESType2iLS[3];
	{	// Bubbleブロックを作る
		unsigned int id_na_val = field.GetNodeSegInNodeAry(BUBBLE).id_na_va;
		if( id_na_val != 0 ){
			assert( world.IsIdNA(id_na_val) );
			const CNodeAry& na = world.GetNA(id_na_val);
			CLinSysSeg seg;
			{
				seg.id_field = id_field_parent; seg.node_config = BUBBLE;
				seg.len=nlen_value; seg.nnode=na.Size();
			}
			ESType2iLS[2] = this->AddLinSysSeg(seg);
		}
		else{ ESType2iLS[2] = -1; }
	}
	{	// Edgeブロックを作る
		unsigned int id_na_val = field.GetNodeSegInNodeAry(EDGE).id_na_va;
		if( id_na_val != 0 ){
			assert( world.IsIdNA(id_na_val) );
			const CNodeAry& na = world.GetNA(id_na_val);
			CLinSysSeg seg;
			{
				seg.id_field = id_field_parent; seg.node_config = EDGE;
				seg.len=nlen_value; seg.nnode=na.Size();
			}
			ESType2iLS[1] = this->AddLinSysSeg(seg);
		}
		else{ ESType2iLS[1] = -1; }
	}
	{	// Cornerブロックを作る
		unsigned int id_na_val = field.GetNodeSegInNodeAry(CORNER).id_na_va;
		if( id_na_val != 0 ){
			assert( world.IsIdNA(id_na_val) );
			const CNodeAry& na = world.GetNA(id_na_val);
			CLinSysSeg seg;
			{
				seg.id_field = id_field_parent; seg.node_config = CORNER;
				seg.len=nlen_value; seg.nnode=na.Size();
			}
			ESType2iLS[0] = this->AddLinSysSeg(seg);
		}
		else{ ESType2iLS[0] = -1; }
	}
	////////////////////////////////
	const std::vector<unsigned int> aIdEA = field.GetAryIdEA();
	if( aIdEA.size() == 0 ){ // 剛体モードのための行列
		unsigned int ils0 = ESType2iLS[0];
		if( m_Matrix_Dia[ils0] == 0 ){
			m_Matrix_Dia[ils0] = new CZMatDia_BlkCrs(1, nlen_value);
		}
		return true;
	}

	for(unsigned int iiea=0;iiea<aIdEA.size();iiea++)
	{
		const unsigned int id_ea = aIdEA[iiea];
		const CElemAry& ea = world.GetEA(id_ea);
		// CORNER節点について
		if( field.GetIdElemSeg(id_ea,CORNER,true,world) != 0 ){
			assert( world.IsIdEA(id_ea) );
			const unsigned int id_es_c = field.GetIdElemSeg(id_ea,CORNER,true,world);
			assert( ea.IsSegID(id_es_c) );
			const unsigned int ils0 = ESType2iLS[0];
			this->AddMat_Dia(ils0, ea, id_es_c );			// cc行列を作る
			if( field.GetIdElemSeg(id_ea,BUBBLE,true,world) != 0 ){	// CORNER-BUBBLE
				const unsigned int id_es_b = field.GetIdElemSeg(id_ea,BUBBLE,true,world);
				assert( ea.IsSegID(id_es_b) );
				const unsigned int ils1 = ESType2iLS[2];
				Com::CIndexedArray crs;
				ea.MakePattern_FEM(id_es_c,id_es_b,crs);
				assert( crs.CheckValid() );
				this->AddMat_NonDia(ils0,ils1, crs);		// cb行列を作る
				const unsigned int nnode1 = m_aSeg[ils1].nnode;
				Com::CIndexedArray crs_inv;
				crs_inv.SetTranspose(nnode1,crs);
				this->AddMat_NonDia(ils1,ils0, crs_inv);	// bc行列を作る
			}
			if( field.GetIdElemSeg(id_ea,EDGE,true,world) != 0 ){	// CONRER-EDGE
				const unsigned int id_es_e = field.GetIdElemSeg(id_ea,EDGE,true,world);
				assert( ea.IsSegID(id_es_e) );
				const unsigned int ils1 = ESType2iLS[1];
				Com::CIndexedArray crs;
				ea.MakePattern_FEM(id_es_c,id_es_e,crs);
				assert( crs.CheckValid() );
				this->AddMat_NonDia(ils0,ils1, crs);		// ce行列を作る
				const unsigned int nnode1 = m_aSeg[ils1].nnode;
				Com::CIndexedArray crs_inv;
				crs_inv.SetTranspose(nnode1,crs);
				this->AddMat_NonDia(ils1,ils0, crs_inv);	// ec行列を作る
			}
		}
		// EDGE節点について
		if( field.GetIdElemSeg(id_ea,EDGE,true,world) != 0 ){
			const unsigned int id_es_e = field.GetIdElemSeg(id_ea,EDGE,true,world);
			assert( ea.IsSegID(id_es_e) );
			const unsigned int ils0 = ESType2iLS[1];
			this->AddMat_Dia(ils0, ea, id_es_e);			// ee行列を作る
			if( field.GetIdElemSeg(id_ea,BUBBLE,true,world) != 0 ){	// EDGE-BUBBLE
				const unsigned int id_es_b = field.GetIdElemSeg(id_ea,BUBBLE,true,world);
				assert( ea.IsSegID(id_es_b) );
				const unsigned int ils1 = ESType2iLS[2];
				Com::CIndexedArray crs;
				ea.MakePattern_FEM(id_es_e,id_es_b,crs);
				assert( crs.CheckValid() );
				this->AddMat_NonDia(ils0,ils1, crs);		// eb行列を作る
				const unsigned int nnode1 = m_aSeg[ils1].nnode;
				Com::CIndexedArray crs_inv;
				crs_inv.SetTranspose(nnode1,crs);
				this->AddMat_NonDia(ils1,ils0, crs_inv);	// be行列を作る
			}
		}
		// BUBBLE節点について
		if( field.GetIdElemSeg(id_ea,BUBBLE,true,world) != 0 ){
			const unsigned int id_es_b = field.GetIdElemSeg(id_ea,BUBBLE,true,world);
			assert( ea.IsSegID(id_es_b) );
			const unsigned int ils0 = ESType2iLS[2];
			this->AddMat_Dia(ils0, ea, id_es_b);
		}
	}
	return true;
}
static bool AddLinSys_AdvectionDiffusion_Static_P1P1(
		double myu, double source, 
		CLinearSystem_Field& ls, 
		const unsigned int id_field_val, const unsigned int id_field_velo, const CFieldWorld& world, 
		unsigned int id_ea )
{
//	std::cout << "Advection Diffusion Static 2D Triangle 3-point 1st order" << std::endl;

	assert( world.IsIdEA(id_ea) );
	const CElemAry& ea = world.GetEA(id_ea);
	assert( ea.ElemType() == TRI );

	if( !world.IsIdField(id_field_val) ) return false;
	const CField& val_field = world.GetField(id_field_val);

	if( !world.IsIdField(id_field_velo) ) return false;
	const CField& field_velo = world.GetField(id_field_velo);

	// 角節点の節点配列ID
	unsigned int id_na_c_co = val_field.GetNodeSegInNodeAry(CORNER).id_na_co;
	unsigned int id_ns_c_co = val_field.GetNodeSegInNodeAry(CORNER).id_ns_co;
	unsigned int id_na_c_val = val_field.GetNodeSegInNodeAry(CORNER).id_na_va;
	unsigned int id_ns_c_val = val_field.GetNodeSegInNodeAry(CORNER).id_ns_va;

	unsigned int id_na_c_velo = field_velo.GetNodeSegInNodeAry(CORNER).id_na_va;
	unsigned int id_ns_c_velo = field_velo.GetNodeSegInNodeAry(CORNER).id_ns_ve;
	assert( id_na_c_co != 0 && id_ns_c_co != 0 );
	assert( id_na_c_val != 0 && id_ns_c_val != 0 );
	assert( id_na_c_velo != 0 );
	assert( id_ns_c_velo != 0 );

	const unsigned int nno = 3;
	const unsigned int ndim = 2;

	const CElemAry::CElemSeg& es_c_val = field_velo.GetElemSeg(id_ea,CORNER,true,world);

	unsigned int no_c[nno];	// 要素節点の全体節点番号

	double value_c[nno];		// 要素節点の値
	double coord_c[nno][ndim];	// 要素節点の座標
	double velo_c[nno][ndim];
	
	double emat[nno][nno];	// 要素剛性行列
	double eres_c[nno];	// 要素節点等価内力、外力、残差ベクトル
				
	CMatDia_BlkCrs& mat_cc = ls.GetMatrix(  id_field_val,CORNER,world);
	CVector_Blk&    res_c  = ls.GetResidual(id_field_val,CORNER,world);

	const CNodeAry& na_c_val = world.GetNA(id_na_c_val);
	const CNodeAry::CNodeSeg& ns_c_val = na_c_val.GetSeg(id_ns_c_val);
	const CNodeAry& na_c_velo = world.GetNA(id_na_c_velo);
	const CNodeAry::CNodeSeg& ns_c_velo = na_c_velo.GetSeg(id_ns_c_velo);
	const CNodeAry& na_c_co = world.GetNA(id_na_c_co);
	const CNodeAry::CNodeSeg& ns_c_co = na_c_co.GetSeg(id_ns_c_co);

	for(unsigned int ielem=0;ielem<ea.Size();ielem++)
	{
		// 要素配列から要素セグメントの節点番号を取り出す
		es_c_val.GetNodes(ielem,no_c);
		// 節点の値を取って来る
		for(unsigned int inoes=0;inoes<nno;inoes++){
			ns_c_co.GetValue(no_c[inoes],coord_c[inoes]);
			ns_c_val.GetValue(no_c[inoes],&value_c[inoes]);
			ns_c_velo.GetValue(no_c[inoes],velo_c[inoes]);
		}

		////////////////////////////////////////////////////////////////

		// 面積を求める
		const double area = TriArea(coord_c[0],coord_c[1],coord_c[2]);
		// 形状関数の微分を求める			
		double dldx[nno][ndim];	// 形状関数のxy微分
		double const_term[nno];	// 形状関数の定数項
		TriDlDx(dldx,const_term,coord_c[0],coord_c[1],coord_c[2]);

		// 要素剛性行列を作る
		for(unsigned int ino=0;ino<nno;ino++){
		for(unsigned int jno=0;jno<nno;jno++){
			emat[ino][jno] = myu*area*(dldx[ino][0]*dldx[jno][0]+dldx[ino][1]*dldx[jno][1]);
		}
		}
		{
			const double dtmp1 = area*0.08333333333333333333333;
			for(unsigned int ino=0;ino<nno;ino++){
				const double dtmp_0 = dtmp1*(velo_c[0][0]+velo_c[1][0]+velo_c[2][0]+velo_c[ino][0]);
				const double dtmp_1 = dtmp1*(velo_c[0][1]+velo_c[1][1]+velo_c[2][1]+velo_c[ino][1]);
				for(unsigned int jno=0;jno<nno;jno++){
					emat[ino][jno] += dldx[jno][0]*dtmp_0+dldx[jno][1]*dtmp_1;
				}
			}
		}

		// Calc Stabilization Parameter
		double tau;
		{
			const double velo_ave[2] = { 
				(velo_c[0][0]+velo_c[1][0]+velo_c[2][0])/3.0, 
				(velo_c[0][1]+velo_c[1][1]+velo_c[2][1])/3.0 };
			const double norm_v = sqrt(velo_ave[0]*velo_ave[0]+velo_ave[1]*velo_ave[1]);
			const double velo_dir[2] = { velo_ave[0]/norm_v, velo_ave[1]/norm_v };
			// calc element length along the direction of velocity
			double h;
			{
				double dtmp1 = 0;
                for(unsigned int inode=0;inode<nno;inode++){
					dtmp1 += fabs(velo_dir[0]*dldx[inode][0]+velo_dir[1]*dldx[inode][1]);
				}
				h = 2.0/dtmp1;
			}
			// calc stabilization parameter
			if( myu > 1.0e-20 ){
				const double re_c = 0.5*norm_v*h/myu;	// 0.5*norm_v*h*rho/myu;
				if(  re_c < 3.0 ){ tau = h * 0.5 / norm_v * re_c / 3.0; }
				else{ tau = h * 0.5 / norm_v; }
			}
			else{ tau = h * 0.5 / norm_v; }
		}

		{
			double tmp_mat[ndim][ndim];
			for(unsigned int idim=0;idim<ndim;idim++){
			for(unsigned int jdim=0;jdim<ndim;jdim++){
				double dtmp1 = 0.0;
				for(unsigned int ino=0;ino<nno;ino++){
					for(unsigned int jno=0;jno<nno;jno++){
						dtmp1 += velo_c[ino][idim]*velo_c[jno][jdim];
					}
					dtmp1 += velo_c[ino][idim]*velo_c[ino][jdim];
				}
				tmp_mat[idim][jdim] = area*tau*dtmp1/12.0;
			}
			}
			for(unsigned int ino=0;ino<nno;ino++){
			for(unsigned int jno=0;jno<nno;jno++){
				double dtmp1 = 0.0;
				for(unsigned int idim=0;idim<ndim;idim++){
				for(unsigned int jdim=0;jdim<ndim;jdim++){
					dtmp1 += dldx[ino][idim]*dldx[jno][jdim]*tmp_mat[idim][jdim];
				}
				}
				emat[ino][jno] += dtmp1;
			}
			}
		}


		// 要素節点等価外力ベクトルを求める
		for(unsigned int ino=0;ino<nno;ino++){
			eres_c[ino] = source*area*0.3333333333333333333;
		}

		////////////////////////////////////////////////////////////////

		// 要素節点等価内力ベクトルを求める
		for(unsigned int ino=0;ino<nno;ino++){			
			for(unsigned int jno=0;jno<nno;jno++){
				eres_c[ino] -= emat[ino][jno]*value_c[jno];
			}	
		}
		// 要素剛性行列にマージする
		mat_cc.Mearge(nno,no_c,nno,no_c,1,&emat[0][0]);
		// 残差ベクトルにマージする
		for(unsigned int ino=0;ino<nno;ino++){
			res_c.AddValue( no_c[ino],0,eres_c[ino]);
		}
	}
	return true;
}