![]() |
MechSys
1.0
Computing library for simulations in continuum and discrete mechanics
|
00001 /************************************************************************ 00002 * MechSys - Open Library for Mechanical Systems * 00003 * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand * 00004 * Copyright (C) 2009 Sergio Galindo * 00005 * * 00006 * This program is free software: you can redistribute it and/or modify * 00007 * it under the terms of the GNU General Public License as published by * 00008 * the Free Software Foundation, either version 3 of the License, or * 00009 * any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License * 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> * 00018 ************************************************************************/ 00019 00020 #ifndef MECHSYS_FEM_FLOWELEM_H 00021 #define MECHSYS_FEM_FLOWELEM_H 00022 00023 // Std Lib 00024 #include <map> 00025 00026 // MechSys 00027 #include <mechsys/fem/element.h> 00028 #include <mechsys/models/flowstate.h> 00029 #include <mechsys/models/flowupdate.h> 00030 00031 namespace FEM 00032 { 00033 00034 class FlowElem : public Element 00035 { 00036 public: 00037 // Constructor 00038 FlowElem (int NDim, 00039 Mesh::Cell const & Cell, 00040 Model const * Mdl, 00041 Model const * XMdl, 00042 SDPair const & Prp, 00043 SDPair const & Ini, 00044 Array<Node*> const & Nodes); 00045 00046 // Methods 00047 void SetBCs (size_t IdxEdgeOrFace, SDPair const & BCs, BCFuncs * BCF); 00048 void ClrBCs (); 00049 void GetLoc (Array<size_t> & Loc) const; 00050 void CalcK (Mat_t & K) const; 00051 void CalcM (Mat_t & M) const; 00052 void UpdateState (Vec_t const & dU, Vec_t * F_int=NULL) const; 00053 void StateKeys (Array<String> & Keys) const; 00054 void StateAtIP (SDPair & KeysVals, int IdxIP) const; 00055 00056 // Internal methods 00057 void Interp (Mat_t const & C, IntegPoint const & IP, Mat_t & B, Mat_t & N, double & detJ, double & Coef) const; 00058 00059 // Data 00060 bool HasConv; // Has convection ? 00061 bool HasPer; // Hsa convection along perimeter ? (line elements only) 00062 std::map<int,double> Bry2h; // Map: boundary (edge/face) ID ==> to convection coefficient (h) 00063 double rho; // Coefficient for mass matrix 00064 double hPer; // h*Perimeter (if HasPer==true) (line elements only) 00065 double A; // cross-sectional area (line elements only) 00066 }; 00067 00068 00070 00071 00072 inline FlowElem::FlowElem (int NDim, Mesh::Cell const & Cell, Model const * Mdl, Model const * XMdl, SDPair const & Prp, SDPair const & Ini, Array<Node*> const & Nodes) 00073 : Element(NDim,Cell,Mdl,XMdl,Prp,Ini,Nodes), HasConv(false), HasPer(false), rho(1.0), hPer(0.0), A(1.0) 00074 { 00075 // check 00076 if (GE==NULL) throw new Fatal("FlowElem::FlowElem: GE (geometry element) must be defined"); 00077 if (Mdl==NULL) throw new Fatal("FlowElem::FlowElem: Model must be defined"); 00078 00079 // check GTy 00080 if (NDim==2 && GTy==d2d_t) { /*OK*/ } 00081 else if (NDim==3 && GTy==d3d_t) { /*OK*/ } 00082 else throw new Fatal("FlowElem::FlowElem: For NDim=%d, geometry type (GTy) must be equal to 'd%dd'. GTy=%s is invalid",NDim,NDim,GTypeToStr(GTy).CStr()); 00083 00084 // properties 00085 if (Prp.HasKey("rho")) rho = Prp("rho"); 00086 if (Prp.HasKey("A")) A = Prp("A"); 00087 00088 // allocate and initialize state at each IP 00089 for (size_t i=0; i<GE->NIP; ++i) 00090 { 00091 Sta.Push (new FlowState(NDim)); 00092 Mdl->InitIvs (Ini, Sta[i]); 00093 } 00094 } 00095 00096 inline void FlowElem::SetBCs (size_t IdxEdgeOrFace, SDPair const & BCs, BCFuncs * BCF) 00097 { 00098 bool has_s = BCs.HasKey("s"); // source term 00099 bool has_H = BCs.HasKey("hh"); // potential 00100 bool has_flux = BCs.HasKey("flux"); // flux 00101 bool has_conv = BCs.HasKey("conv"); // convection 00102 bool has_per = BCs.HasKey("per"); // perimeter (length) in which convection is applied (line element only) 00103 00104 if (has_s || has_flux || has_conv) 00105 { 00106 // source term 00107 if (has_s) 00108 { 00109 double detJ, coef; 00110 double s = BCs("s"); 00111 Mat_t C; 00112 CoordMatrix (C); 00113 for (size_t i=0; i<GE->NIP; ++i) 00114 { 00115 CalcShape (C, GE->IPs[i], detJ, coef); 00116 for (size_t j=0; j<GE->NN; ++j) 00117 { 00118 Con[j]->AddToPF("qq", s*coef*GE->N(j), BCF); 00119 } 00120 } 00121 } 00122 00123 // flux 00124 if (has_flux) 00125 { 00126 double qn = BCs("flux"); 00127 double detJ, coef; 00128 Mat_t FC; 00129 FCoordMatrix (IdxEdgeOrFace, FC); 00130 for (size_t i=0; i<GE->NFIP; ++i) 00131 { 00132 CalcFaceShape (FC, GE->FIPs[i], detJ, coef); 00133 for (size_t j=0; j<GE->NFN; ++j) 00134 { 00135 size_t k = GE->FNode(IdxEdgeOrFace,j); 00136 Con[k]->AddToPF("qq", coef*GE->FN(j)*qn, BCF); 00137 } 00138 } 00139 } 00140 00141 // convection 00142 else if (has_conv) 00143 { 00144 // data 00145 double h = BCs("h"); // convection coefficient 00146 double Tinf = BCs("Tinf"); // temperature of surrounding environment 00147 00148 // convection along perimeter 00149 if (has_per) 00150 { 00151 hPer = h * BCs("per"); 00152 HasPer = true; 00153 if (GE->NN==2) 00154 { 00155 Vec3_t dl(Con[1]->Vert.C - Con[0]->Vert.C); 00156 double l = norm(dl); 00157 Con[0]->AddToPF("qq", hPer*l*Tinf/2.0, BCF); 00158 Con[1]->AddToPF("qq", hPer*l*Tinf/2.0, BCF); 00159 } 00160 else throw new Fatal("FlowElem::SetBCs: per (perimiter) must be used for convection in Line elments only"); 00161 } 00162 00163 // convection at boundaries 00164 else 00165 { 00166 Bry2h[IdxEdgeOrFace] = h; // Map: bry => h 00167 HasConv = true; // has convection 00168 } 00169 00170 // add to pF 00171 double detJ, coef; 00172 Mat_t FC; 00173 FCoordMatrix (IdxEdgeOrFace, FC); 00174 for (size_t i=0; i<GE->NFIP; ++i) 00175 { 00176 CalcFaceShape (FC, GE->FIPs[i], detJ, coef); 00177 for (size_t j=0; j<GE->NFN; ++j) 00178 { 00179 size_t k = GE->FNode(IdxEdgeOrFace,j); 00180 Con[k]->AddToPF("qq", coef*GE->FN(j)*h*Tinf, BCF); 00181 } 00182 } 00183 } 00184 } 00185 00186 // potential 00187 else if (has_H) 00188 { 00189 double H = BCs("hh"); 00190 for (size_t j=0; j<GE->NFN; ++j) 00191 { 00192 size_t k = GE->FNode(IdxEdgeOrFace,j); 00193 Con[k]->SetPU("hh", H, BCF); 00194 } 00195 } 00196 } 00197 00198 inline void FlowElem::ClrBCs () 00199 { 00200 HasConv = false; 00201 Bry2h.clear(); 00202 } 00203 00204 inline void FlowElem::GetLoc (Array<size_t> & Loc) const 00205 { 00206 Loc.Resize (GE->NN); 00207 for (size_t i=0; i<GE->NN; ++i) Loc[i] = Con[i]->Eq("hh"); 00208 } 00209 00210 inline void FlowElem::CalcK (Mat_t & K) const 00211 { 00212 double detJ, coef; 00213 Mat_t C, D, B, N; 00214 int nrows = Con.Size(); // number of rows in local K matrix 00215 K.change_dim (nrows,nrows); 00216 set_to_zero (K); 00217 CoordMatrix (C); 00218 for (size_t i=0; i<GE->NIP; ++i) 00219 { 00220 Mdl->Stiffness (Sta[i], D); 00221 Interp (C, GE->IPs[i], B, N, detJ, coef); 00222 Mat_t BtDB(trans(B)*D*B); 00223 K += (A*coef) * BtDB; 00224 00225 // convection along perimeter (line elements) 00226 if (HasPer) 00227 { 00228 CalcShape (C, GE->IPs[i], detJ, coef); 00229 Mat_t NtN(trans(N)*N); 00230 K += (hPer*coef) * NtN; 00231 } 00232 } 00233 00234 // convection at boundaries 00235 if (HasConv) 00236 { 00237 for (std::map<int,double>::const_iterator p=Bry2h.begin(); p!=Bry2h.end(); ++p) 00238 { 00239 int idx_bry = p->first; 00240 double h = p->second; 00241 00242 // add to K 00243 Mat_t FC; 00244 FCoordMatrix (idx_bry, FC); 00245 for (size_t i=0; i<GE->NFIP; ++i) 00246 { 00247 CalcFaceShape (FC, GE->FIPs[i], detJ, coef); 00248 for (size_t j=0; j<GE->NFN; ++j) 00249 { 00250 int row = GE->FNode(idx_bry,j); 00251 for (size_t k=0; k<GE->NFN; ++k) 00252 { 00253 int col = GE->FNode(idx_bry,k); 00254 K(row,col) += h*coef * GE->FN(j)*GE->FN(k); 00255 } 00256 } 00257 } 00258 } 00259 } 00260 } 00261 00262 inline void FlowElem::CalcM (Mat_t & M) const 00263 { 00264 double detJ, coef; 00265 Mat_t C; 00266 int nrows = Con.Size(); // number of rows in local K matrix 00267 M.change_dim (nrows,nrows); 00268 set_to_zero (M); 00269 CoordMatrix (C); 00270 for (size_t i=0; i<GE->NIP; ++i) 00271 { 00272 CalcShape (C, GE->IPs[i], detJ, coef); 00273 for (size_t j=0; j<GE->NN; ++j) 00274 { 00275 for (size_t k=0; k<GE->NN; ++k) 00276 { 00277 M(j,k) += (A*rho*coef)*GE->N(j)*GE->N(k); 00278 } 00279 } 00280 } 00281 } 00282 00283 inline void FlowElem::Interp (Mat_t const & C, IntegPoint const & IP, Mat_t & B, Mat_t & N, double & detJ, double & Coef) const 00284 { 00285 // deriv of shape func w.r.t natural coordinates 00286 GE->Shape (IP.r, IP.s, IP.t); 00287 GE->Derivs (IP.r, IP.s, IP.t); 00288 00289 // Jacobian and its determinant 00290 Mat_t J(GE->dNdR * C); // J = dNdR * C 00291 detJ = Det(J); 00292 00293 // deriv of shape func w.r.t real coordinates 00294 Mat_t Ji; 00295 Inv (J, Ji); 00296 00297 // coefficient used during integration 00298 Coef = detJ*IP.w; 00299 00300 // B matrix 00301 int nrows = Con.Size(); // number of rows in local K matrix 00302 B.change_dim (NDim,nrows); 00303 B = Ji * GE->dNdR; // B = dNdX = Inv(J) * dNdR 00304 00305 // N matrix 00306 N.change_dim (1,nrows); 00307 for (size_t j=0; j<GE->NN; ++j) N(0,j) = GE->N(j); 00308 } 00309 00310 inline void FlowElem::UpdateState (Vec_t const & dU, Vec_t * F_int) const 00311 { 00312 // get location array 00313 Array<size_t> loc; 00314 GetLoc (loc); 00315 00316 // element nodal potential 00317 int nrows = Con.Size(); // number of rows in local K matrix 00318 Vec_t dUe(nrows); 00319 for (size_t i=0; i<loc.Size(); ++i) dUe(i) = dU(loc[i]); 00320 00321 // update state at each IP 00322 FlowUpdate fu(Mdl); 00323 double detJ, coef; 00324 Mat_t C, B, N; 00325 Vec_t dFe(nrows), dvel(NDim), dgra(NDim); 00326 set_to_zero (dFe); 00327 CoordMatrix (C); 00328 for (size_t i=0; i<GE->NIP; ++i) 00329 { 00330 // B matrix 00331 Interp (C, GE->IPs[i], B, N, detJ, coef); 00332 00333 // velocity and gradient increments 00334 dgra = B * dUe; 00335 fu.Update (dgra, Sta[i], dvel); 00336 00337 // element nodal forces 00338 Vec_t Btdvel(trans(B)*dvel); 00339 dFe -= (A*coef) * (Btdvel); // '-=' because dvel is -k*dgra 00340 00341 // convection along perimeter (line elements) 00342 if (HasPer) 00343 { 00344 Mat_t NtN(trans(N)*N); 00345 dFe += (hPer*coef) * NtN * dUe; 00346 } 00347 } 00348 00349 // add contribution to dFe due to convection term 00350 if (HasConv) 00351 { 00352 for (std::map<int,double>::const_iterator p=Bry2h.begin(); p!=Bry2h.end(); ++p) 00353 { 00354 int idx_bry = p->first; 00355 double h = p->second; 00356 00357 // add to dFe 00358 Mat_t FC; 00359 FCoordMatrix (idx_bry, FC); 00360 for (size_t i=0; i<GE->NFIP; ++i) 00361 { 00362 CalcFaceShape (FC, GE->FIPs[i], detJ, coef); 00363 for (size_t j=0; j<GE->NFN; ++j) 00364 { 00365 int row = GE->FNode(idx_bry,j); 00366 for (size_t k=0; k<GE->NFN; ++k) 00367 { 00368 int col = GE->FNode(idx_bry,k); 00369 dFe(row) += h*coef * GE->FN(j)*GE->FN(k) * dUe(col); 00370 } 00371 } 00372 } 00373 } 00374 } 00375 00376 // add results to Fint (internal forces) 00377 if (F_int!=NULL) for (size_t i=0; i<loc.Size(); ++i) (*F_int)(loc[i]) += dFe(i); 00378 } 00379 00380 inline void FlowElem::StateKeys (Array<String> & Keys) const 00381 { 00382 Keys.Resize (2*NDim + Mdl->NIvs); 00383 size_t k=0; 00384 Keys[k++] = "vx"; 00385 Keys[k++] = "vy"; 00386 if (NDim==3) 00387 { 00388 Keys[k++] = "vz"; 00389 } 00390 Keys[k++] = "gx"; 00391 Keys[k++] = "gy"; 00392 if (NDim==3) 00393 { 00394 Keys[k++] = "gz"; 00395 } 00396 for (size_t i=0; i<Mdl->NIvs; ++i) Keys[k++] = Mdl->IvNames[i]; 00397 } 00398 00399 inline void FlowElem::StateAtIP (SDPair & KeysVals, int IdxIP) const 00400 { 00401 Vec_t const & vel = static_cast<FlowState const *>(Sta[IdxIP])->Vel; 00402 Vec_t const & gra = static_cast<FlowState const *>(Sta[IdxIP])->Gra; 00403 00404 if (NDim==2) 00405 { 00406 KeysVals.Set("vx vy gx gy", 00407 vel(0), vel(1), 00408 gra(0), gra(1)); 00409 } 00410 else 00411 { 00412 KeysVals.Set("vx vy vz gx gy gz", 00413 vel(0), vel(1), vel(2), 00414 gra(0), gra(1), gra(2)); 00415 } 00416 } 00417 00418 00420 00421 00422 // Allocate a new element 00423 Element * FlowElemMaker(int NDim, Mesh::Cell const & Cell, Model const * Mdl, Model const * XMdl, SDPair const & Prp, SDPair const & Ini, Array<Node*> const & Nodes) { return new FlowElem(NDim,Cell,Mdl,XMdl,Prp,Ini,Nodes); } 00424 00425 // Register element 00426 int FlowElemRegister() 00427 { 00428 ElementFactory ["Flow"] = FlowElemMaker; 00429 ElementVarKeys ["Flow2D"] = std::make_pair ("hh", "qq"); 00430 ElementVarKeys ["Flow3D"] = std::make_pair ("hh", "qq"); 00431 ElementExtraKeys["Flow2D"] = Array<String> ("flux", "conv"); 00432 ElementExtraKeys["Flow3D"] = Array<String> ("flux", "conv"); 00433 PROB.Set ("Flow", (double)PROB.Keys.Size()); 00434 return 0; 00435 } 00436 00437 // Call register 00438 int __FlowElem_dummy_int = FlowElemRegister(); 00439 00440 }; // namespace FEM 00441 00442 #endif // MECHSYS_FEM_FLOWELEM