// 対角にパターンを追加 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; }