MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/fem/equilibelem.h
Go to the documentation of this file.
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_EQUILIBELEM_H
00021 #define MECHSYS_FEM_EQUILIBELEM_H
00022 
00023 // MechSys
00024 #include <mechsys/fem/element.h>
00025 #include <mechsys/models/equilibstate.h>
00026 #include <mechsys/models/stressupdate.h>
00027 
00028 namespace FEM
00029 {
00030 
00031 class EquilibElem : public Element
00032 {
00033 public:
00034     // Static
00035     static size_t NCo; 
00036     static size_t NDu; 
00037 
00038     // Constructor & Destructor
00039     EquilibElem (int                  NDim,   
00040                  Mesh::Cell   const & Cell,   
00041                  Model        const * Mdl,    
00042                  Model        const * XMdl,   
00043                  SDPair       const & Prp,    
00044                  SDPair       const & Ini,    
00045                  Array<Node*> const & Nodes); 
00046     virtual ~EquilibElem () {}
00047 
00048     // Methods
00049     virtual void SetBCs      (size_t IdxEdgeOrFace, SDPair const & BCs, BCFuncs * BCF); 
00050     virtual void GetLoc      (Array<size_t> & Loc)                               const; 
00051     void         CalcK       (Mat_t & K)                                         const; 
00052     void         CalcM       (Mat_t & M)                                         const; 
00053     virtual void UpdateState (Vec_t const & dU, Vec_t * F_int=NULL)              const; 
00054     virtual void SetFint     (Vec_t * Fint=NULL)                                 const; 
00055     virtual void StateKeys   (Array<String> & Keys)                              const; 
00056     virtual void StateAtIP   (SDPair & KeysVals, int IdxIP)                      const; 
00057 
00058     // Internal methods
00059     void CalcB (Mat_t const & C, IntegPoint const & IP, Mat_t & B, double & detJ, double & Coef) const; 
00060     void CalcN (Mat_t const & C, IntegPoint const & IP, Mat_t & N, double & detJ, double & Coef) const; 
00061 
00062     // Methods for the Runge-Kutta method
00063     virtual size_t NIVs       ()                                                            const;
00064     virtual double GetIV      (size_t i)                                                    const;
00065     virtual void   SetIV      (size_t i, double Val);
00066     virtual void   CalcIVRate (double Time, Vec_t const & U, Vec_t const & V, Vec_t & Rate) const;
00067     virtual void   CorrectIVs ();
00068 
00069     // Constants
00070     double h;   
00071     double rho; 
00072 };
00073 
00074 size_t EquilibElem::NCo = 0;
00075 size_t EquilibElem::NDu = 0;
00076 
00077 
00079 
00080 
00081 inline EquilibElem::EquilibElem (int NDim, Mesh::Cell const & Cell, Model const * Mdl, Model const * XMdl, SDPair const & Prp, SDPair const & Ini, Array<Node*> const & Nodes)
00082     : Element(NDim,Cell,Mdl,XMdl,Prp,Ini,Nodes)
00083 {
00084     // check
00085     if (GE==NULL)  throw new Fatal("EquilibElem::EquilibElem: GE (geometry element) must be defined");
00086     if (Mdl==NULL) throw new Fatal("EquilibElem::EquilibElem: Model must be defined");
00087 
00088     // set constants of this class (just once)
00089     if (NDu==0)
00090     {
00091         NCo = 2*NDim;
00092         NDu = NDim*GE->NN;
00093     }
00094 
00095     // parameters/properties
00096     h   = (Prp.HasKey("h")   ? Prp("h")   : 1.0);
00097     rho = Mdl->Rho;//(Prp.HasKey("rho") ? Prp("rho") : 1.0);
00098     if (h<1.0e-8)   throw new Fatal("EquilibElem::EquilibElem: The thickness of the element must be greater than 1.0e-8. h=%g is invalid",h);
00099     if (rho<1.0e-8) throw new Fatal("EquilibElem::EquilibElem: 'rho' must be greater than zero (rho=%g is invalid)",rho);
00100 
00101     // allocate and initialize state at each IP
00102     for (size_t i=0; i<GE->NIP; ++i)
00103     {
00104         Sta.Push (new EquilibState(NDim));
00105         Mdl->InitIvs (Ini, Sta[i]);
00106     }
00107 
00108     // set initial values
00109     bool geosta = (Prp.HasKey("geosta") ? Prp("geosta")>0 : false);
00110     if (geosta)
00111     {
00112         double z_surf    = Prp("surf");
00113         double K0        = Prp("K0");
00114         bool   pos_pw    = (Prp.HasKey("pospw") ? Prp("pospw")>0 : false);
00115         bool   has_water = Prp.HasKey("water");
00116         double z_water   = 0;
00117         if (GTy==pse_t)          throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, geometry cannot be of 'plane-stress' (pse) type");
00118         if (!Prp.HasKey("K0"))   throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'K0' must be provided in 'Prp' dictionary");
00119         if (!Prp.HasKey("surf")) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'surf' must be provided in 'Prp' dictionary");
00120         if (has_water)
00121         {
00122             z_water = Prp("water");
00123             if (z_water>z_surf) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'water' must be smaller than or equal to 'surf'");
00124             // TODO: this last condition can be removed, but sv calculation in the next lines must be corrected
00125         }
00126         if (Mdl->GamW  <0.0) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'gamW' must be positive");
00127         if (Mdl->GamNat<0.0) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'gamNat' must be positive");
00128         if (Mdl->GamSat<0.0) throw new Fatal("EquilibElem::EquilibElem: For geostatic stresses, 'gamSat' must be positive");
00129         for (size_t i=0; i<GE->NIP; ++i)
00130         {
00131             // elevation of point
00132             Vec_t X;
00133             CoordsOfIP (i, X);
00134             double z = (NDim==2 ? X(1) : X(2));
00135             if (z>z_surf) throw new Fatal("EquilibElem::EquilibElem: 'surf' must be greater than any point in the domain.\n\tThere is a point [%g,%g,%g] above surf=%g.",X(0),X(1),(NDim==3?X(2):0.0),z_surf);
00136 
00137             // pore-water pressure and total vertical stress
00138             double pw = 0.0;
00139             double sv;
00140             if (has_water)
00141             {
00142                 double hw = z_water-z; // column of water
00143                 pw = (hw>0.0 ? Mdl->GamW*hw : (pos_pw ? 0.0 : Mdl->GamW*hw));
00144                 if (z>z_water) sv = (z_surf-z)*Mdl->GamNat;
00145                 else sv = (z_surf-z_water)*Mdl->GamNat + (z_water-z)*Mdl->GamSat;
00146             }
00147             else sv = (z_surf-z)*Mdl->GamNat;   
00148             sv *= (-1.0); // convert soil-mech. convention to classical mech. convention
00149 
00150             // vertical and horizontal effective stresses
00151             double sv_ = sv + pw;  // effective vertical stresss
00152             double sh_ = K0*sv_;   // effective horizontal stress
00153             double sh  = sh_ - pw; // total horizontal stress
00154 
00155             // set stress tensor with __total__ stresses
00156             Vec_t & sig = static_cast<EquilibState *>(Sta[i])->Sig;
00157             if (NDim==2) sig = sh, sv, sh, 0.0;
00158             else         sig = sh, sh, sv, 0.0,0.0,0.0;
00159         }
00160     }
00161 
00162     // set F in nodes due to initial stresses
00163     SetFint ();
00164 }
00165 
00166 inline void EquilibElem::SetBCs (size_t IdxEdgeOrFace, SDPair const & BCs, BCFuncs * BCF)
00167 {
00168     // deactivate/activate commands
00169     if (BCs.HasKey("deactivate"))
00170     {
00171         // check
00172         if (!Active) throw new Fatal("EquilibElem::SetBCs: 'deactivate' command failed: Element # %d is already inactive",Cell.ID);
00173 
00174         // calc force to be applied after removal of element
00175         double gra = (BCs.HasKey("gravity") ? BCs("gravity") : 0.0);
00176         double detJ, coef;
00177         Mat_t  C, B;
00178         Vec_t  Fi(NDu), Fb(NDu);
00179         set_to_zero (Fi);
00180         set_to_zero (Fb);
00181         CoordMatrix (C);
00182         size_t idx_grav = (NDim==2 ? 1 : 2);
00183         for (size_t i=0; i<GE->NIP; ++i)
00184         {
00185             // internal forces
00186             GE->Shape (GE->IPs[i].r, GE->IPs[i].s, GE->IPs[i].t);
00187             CalcB     (C, GE->IPs[i], B, detJ, coef);
00188             Vec_t const & sig = static_cast<EquilibState const *>(Sta[i])->Sig;
00189             Fi += (coef) * trans(B)*sig;
00190 
00191             // body forces
00192             for (size_t j=0; j<GE->NN; ++j) Fb(idx_grav+j*NDim) += -coef*GE->N(j)*rho*gra;
00193         }
00194 
00195         // set nodes
00196         for (size_t i=0; i<GE->NN; ++i)
00197         {
00198             // remove sharing information
00199             Con[i]->NShares--;
00200             if (Con[i]->NShares<0) throw new Fatal("EquilibElem::SetBCs: __internal_error__: 'deactivate' command failed: NShares==%d must be positive",Con[i]->NShares<0);
00201 
00202             // clear all values in node in case it becomes inactive
00203             if (Con[i]->NShares==0) Con[i]->Clear();
00204             else
00205             {
00206                 // set boundary conditions
00207                 Con[i]->AddToPF("fx", Fi(0+i*NDim) - Fb(0+i*NDim), BCF);
00208                 Con[i]->AddToPF("fy", Fi(1+i*NDim) - Fb(1+i*NDim), BCF);  if (NDim==3)
00209                 Con[i]->AddToPF("fz", Fi(2+i*NDim) - Fb(2+i*NDim), BCF);
00210             }
00211         }
00212 
00213         // clear state at IPs
00214         SDPair inis;
00215         inis.Set("zero",1.);
00216         for (size_t i=0; i<GE->NIP; ++i) Sta[i]->Init (inis, size(static_cast<EquilibState const *>(Sta[i])->Ivs));
00217 
00218         // deactivate element
00219         Active = false;
00220         return; // must return otherwise 'gravity' may be set in the following code
00221     }
00222     else if (BCs.HasKey("activate"))
00223     {
00224         // check
00225         if (Active) throw new Fatal("EquilibElem::SetBCs: 'activate' command failed: Element # %d is already active",Cell.ID);
00226 
00227         // add information to shares array in nodes
00228         for (size_t i=0; i<GE->NN; ++i) Con[i]->NShares++;
00229 
00230         // clear state at IPs
00231         SDPair inis;
00232         inis.Set("zero",1.);
00233         for (size_t i=0; i<GE->NIP; ++i) Sta[i]->Init (inis, size(static_cast<EquilibState const *>(Sta[i])->Ivs));
00234 
00235         // activate
00236         Active = true;
00237         // continue to set gravity
00238     }
00239 
00240     // check
00241     if (!Active) throw new Fatal("EquilibElem::SetBCs: Element %d is inactive",Cell.ID);
00242 
00243     bool has_bx  = BCs.HasKey("bx");  // x component of body force
00244     bool has_by  = BCs.HasKey("by");  // y component of body force
00245     bool has_bz  = BCs.HasKey("bz");  // z component of body force
00246     bool has_cbx = BCs.HasKey("cbx"); // centrifugal body force along x (in axisymmetric problems)
00247     bool has_qx  = BCs.HasKey("qx");  // x component of distributed loading
00248     bool has_qy  = BCs.HasKey("qy");  // y component of distributed loading
00249     bool has_qz  = BCs.HasKey("qz");  // z component of distributed loading
00250     bool has_qn  = BCs.HasKey("qn");  // normal distributed loading
00251     bool has_qt  = BCs.HasKey("qt");  // tangential distributed loading (2D only)
00252     bool has_ux  = BCs.HasKey("ux");  // x displacement
00253     bool has_uy  = BCs.HasKey("uy");  // y displacement
00254     bool has_uz  = BCs.HasKey("uz");  // z displacement
00255     bool has_sup = BCs.HasKey("incsup");  // inclined support
00256     bool has_gra = BCs.HasKey("gravity"); // gravity
00257 
00258     // force components specified
00259     if (has_bx || has_by || has_bz || has_cbx || has_gra ||
00260         has_qx || has_qy || has_qz || has_qn  || has_qt)
00261     {
00262         // body forces
00263         if (has_bx || has_by || has_bz || has_cbx || has_gra) // prescribed body forces
00264         {
00265             // matrix of coordinates of nodes
00266             Mat_t C;
00267             CoordMatrix (C);
00268             
00269             // loading
00270             double bx = (has_bx  ? BCs("bx")  : 0.0);
00271             double by = (has_by  ? BCs("by")  : 0.0);
00272             double bz = (has_bz  ? BCs("bz")  : 0.0);
00273                    bx = (has_cbx ? BCs("cbx") : bx );
00274             if (has_gra)
00275             {
00276                 if (NDim==2) by = -rho*BCs("gravity");
00277                 else         bz = -rho*BCs("gravity");
00278             }
00279 
00280             // set
00281             for (size_t i=0; i<GE->NIP; ++i)
00282             {
00283                 // geometric data
00284                 GE->Shape  (GE->IPs[i].r, GE->IPs[i].s, GE->IPs[i].t);
00285                 GE->Derivs (GE->IPs[i].r, GE->IPs[i].s, GE->IPs[i].t);
00286 
00287                 // Jacobian and its determinant
00288                 Mat_t J(GE->dNdR * C); // J = dNdR * C
00289                 double detJ = Det(J);
00290 
00291                 // coefficient used during integration
00292                 double coef = h*detJ*GE->IPs[i].w;
00293                 if (GTy==axs_t)
00294                 {
00295                     // calculate radius=x at this IP
00296                     double radius = 0.0;
00297                     for (size_t j=0; j<GE->NN; ++j) radius += GE->N(j)*Con[j]->Vert.C[0];
00298 
00299                     // correct coef
00300                     if (has_cbx) coef *= radius*radius;
00301                     else         coef *= radius;
00302                 }
00303 
00304                 // set boundary conditions
00305                 for (size_t j=0; j<GE->NN; ++j)
00306                 {
00307                     Con[j]->AddToPF("fx", coef*GE->N(j)*bx, BCF);
00308                     Con[j]->AddToPF("fy", coef*GE->N(j)*by, BCF);  if (NDim==3)
00309                     Con[j]->AddToPF("fz", coef*GE->N(j)*bz, BCF);
00310                 }
00311             }
00312         }
00313 
00314         // surface loading
00315         if (has_qx || has_qy || has_qz || has_qn  || has_qt)
00316         {
00317             // matrix of coordinates of edge/face
00318             Mat_t Cf;
00319             FCoordMatrix (IdxEdgeOrFace, Cf);
00320 
00321             // loading
00322             double qx = (has_qx ? BCs("qx") : 0.0);
00323             double qy = (has_qy ? BCs("qy") : 0.0);
00324             double qz = (has_qz ? BCs("qz") : 0.0);
00325             double qn = (has_qn ? BCs("qn") : 0.0);
00326             double qt = (has_qt ? BCs("qt") : 0.0);
00327 
00328             // set
00329             for (size_t i=0; i<GE->NFIP; ++i)
00330             {
00331                 // geometric data
00332                 GE->FaceShape  (GE->FIPs[i].r, GE->FIPs[i].s);
00333                 GE->FaceDerivs (GE->FIPs[i].r, GE->FIPs[i].s);
00334 
00335                 // face/edge Jacobian and its determinant
00336                 Mat_t J(GE->FdNdR * Cf);
00337 
00338                 // coefficient used during integration
00339                 double coef = h*GE->FIPs[i].w; // *detJ is not necessary since qx,qy,qz are already multiplied by detJ (due to normal)
00340 
00341                 if (GTy==axs_t)
00342                 {
00343                     // calculate radius=x at this FIP
00344                     double radius = 0.0;
00345                     for (size_t j=0; j<GE->NFN; ++j) radius += GE->FN(j)*Con[GE->FNode(IdxEdgeOrFace,j)]->Vert.C[0];
00346                     coef *= radius; // correct coef
00347                 }
00348 
00349                 // calculate qx, qy and qz from qn and qt
00350                 if (has_qn || has_qt)
00351                 {
00352                     // normal to edge/face
00353                     Vec_t n(NDim); // normal multiplied by detJ
00354                     if (NDim==2) n = J(0,1), -J(0,0);
00355                     else
00356                     {
00357                         // vectorial product
00358                         Vec_t a(3);  a = J(0,0), J(0,1), J(0,2);
00359                         Vec_t b(3);  b = J(1,0), J(1,1), J(1,2);
00360                         n = a(1)*b(2) - a(2)*b(1),
00361                             a(2)*b(0) - a(0)*b(2),
00362                             a(0)*b(1) - a(1)*b(0);
00363                     }
00364 
00365                     // loading
00366                     if (NDim==2)
00367                     {
00368                         qx = n(0)*qn - n(1)*qt;
00369                         qy = n(1)*qn + n(0)*qt;
00370                     }
00371                     else
00372                     {
00373                         qx = n(0)*qn;
00374                         qy = n(1)*qn;
00375                         qz = n(2)*qn;
00376                     }
00377                 }
00378 
00379                 // set boundary conditions
00380                 for (size_t j=0; j<GE->NFN; ++j)
00381                 {
00382                     size_t k = GE->FNode(IdxEdgeOrFace,j);
00383                     Con[k]->AddToPF("fx", coef*GE->FN(j)*qx, BCF);
00384                     Con[k]->AddToPF("fy", coef*GE->FN(j)*qy, BCF);  if (NDim==3)
00385                     Con[k]->AddToPF("fz", coef*GE->FN(j)*qz, BCF);
00386                 }
00387             }
00388         }
00389     }
00390 
00391     // prescribed displacements
00392     else if (has_ux || has_uy || has_uz || has_sup)
00393     {
00394         double ux = (has_ux ? BCs("ux") : 0.0);
00395         double uy = (has_uy ? BCs("uy") : 0.0);
00396         double uz = (has_uz ? BCs("uz") : 0.0);
00397         double alpha = (has_sup ? BCs("alpha") : 0.0);
00398         for (size_t j=0; j<GE->NFN; ++j)
00399         {
00400             size_t k = GE->FNode(IdxEdgeOrFace,j);
00401             if (has_ux) Con[k]->SetPU("ux", ux, BCF);
00402             if (has_uy) Con[k]->SetPU("uy", uy, BCF);
00403             if (has_uz) Con[k]->SetPU("uz", uz, BCF);
00404             if (has_sup) Con[k]->SetIncSup (alpha);
00405         }
00406     }
00407 }
00408 
00409 inline void EquilibElem::GetLoc (Array<size_t> & Loc) const
00410 {
00411     Loc.Resize (NDu);
00412     for (size_t i=0; i<GE->NN; ++i)
00413     {
00414         Loc[i*NDim+0] = Con[i]->Eq("ux");
00415         Loc[i*NDim+1] = Con[i]->Eq("uy");  if (NDim==3)
00416         Loc[i*NDim+2] = Con[i]->Eq("uz");
00417     }
00418 }
00419 
00420 inline void EquilibElem::CalcK (Mat_t & K) const
00421 {
00422     double detJ, coef;
00423     Mat_t C, D, B;
00424     K.change_dim (NDu, NDu);
00425     set_to_zero  (K);
00426     CoordMatrix  (C);
00427     for (size_t i=0; i<GE->NIP; ++i)
00428     {
00429         Mdl->Stiffness (Sta[i], D);
00430         CalcB (C, GE->IPs[i], B, detJ, coef);
00431         K += (coef) * trans(B)*D*B;
00432     }
00433 }
00434 
00435 inline void EquilibElem::CalcM (Mat_t & M) const
00436 {
00437     double detJ, coef;
00438     Mat_t  C, N;
00439     M.change_dim (NDu, NDu);
00440     set_to_zero  (M);
00441     CoordMatrix  (C);
00442     for (size_t i=0; i<GE->NIP; ++i)
00443     {
00444         CalcN (C, GE->IPs[i], N, detJ, coef);
00445         M += (rho*coef) * trans(N)*N;
00446     }
00447 }
00448 
00449 inline void EquilibElem::CalcB (Mat_t const & C, IntegPoint const & IP, Mat_t & B, double & detJ, double & Coef) const
00450 {
00451     // deriv of shape func w.r.t natural coordinates
00452     GE->Derivs (IP.r, IP.s, IP.t);
00453 
00454     // Jacobian and its determinant
00455     Mat_t J(GE->dNdR * C); // J = dNdR * C
00456     detJ = Det(J);
00457 
00458     // deriv of shape func w.r.t real coordinates
00459     Mat_t Ji;
00460     Inv (J, Ji);
00461     Mat_t dNdX(Ji * GE->dNdR); // dNdX = Inv(J) * dNdR
00462 
00463     // coefficient used during integration
00464     Coef = h*detJ*IP.w;
00465 
00466 
00467 
00468     //std::cout << "J = \n" << PrintMatrix(J);
00469     //std::cout << "dNdR = \n" << PrintMatrix(GE->dNdR);
00470     //std::cout << "C = \n" << PrintMatrix(C);
00471     //std::cout << "dNdX = \n" << PrintMatrix(dNdX);
00472     //printf("detJ = %g\n", detJ);
00473 
00474 
00475     // B matrix
00476     B.change_dim (NCo, NDu);
00477     set_to_zero  (B);
00478     if (NDim==2)
00479     {
00480         if (GTy==axs_t)
00481         {
00482             // shape functions
00483             GE->Shape (IP.r, IP.s, IP.t);
00484 
00485             // correct Coef
00486             double radius = 0.0; // radius=x at this IP
00487             for (size_t j=0; j<GE->NN; ++j) radius += GE->N(j)*Con[j]->Vert.C[0];
00488             Coef *= radius;
00489 
00490             // B matrix
00491             for (size_t i=0; i<GE->NN; ++i)
00492             {
00493                 B(0,0+i*NDim) = dNdX(0,i);
00494                 B(1,1+i*NDim) = dNdX(1,i);
00495                 B(2,0+i*NDim) = GE->N(i)/radius;
00496                 B(3,0+i*NDim) = dNdX(1,i)/sqrt(2.0);
00497                 B(3,1+i*NDim) = dNdX(0,i)/sqrt(2.0);
00498             }
00499             //std::cout << "B = \n" << PrintMatrix(B);
00500         }
00501         else // pse_t, psa_t
00502         {
00503             for (size_t i=0; i<GE->NN; ++i)
00504             {
00505                 B(0,0+i*NDim) = dNdX(0,i);
00506                 B(1,1+i*NDim) = dNdX(1,i);
00507                 B(3,0+i*NDim) = dNdX(1,i)/sqrt(2.0);
00508                 B(3,1+i*NDim) = dNdX(0,i)/sqrt(2.0);
00509             }
00510         }
00511     }
00512     else // 3D
00513     {
00514         for (size_t i=0; i<GE->NN; ++i)
00515         {
00516             B(0,0+i*NDim) = dNdX(0,i);
00517             B(1,1+i*NDim) = dNdX(1,i);
00518             B(2,2+i*NDim) = dNdX(2,i);
00519             B(3,0+i*NDim) = dNdX(1,i)/sqrt(2.0);   B(3,1+i*NDim) = dNdX(0,i)/sqrt(2.0);
00520             B(4,1+i*NDim) = dNdX(2,i)/sqrt(2.0);   B(4,2+i*NDim) = dNdX(1,i)/sqrt(2.0);
00521             B(5,2+i*NDim) = dNdX(0,i)/sqrt(2.0);   B(5,0+i*NDim) = dNdX(2,i)/sqrt(2.0);
00522         }
00523     }
00524 }
00525 
00526 inline void EquilibElem::CalcN (Mat_t const & C, IntegPoint const & IP, Mat_t & N, double & detJ, double & Coef) const
00527 {
00528     // deriv of shape func w.r.t natural coordinates
00529     GE->Shape  (IP.r, IP.s, IP.t);
00530     GE->Derivs (IP.r, IP.s, IP.t);
00531 
00532     // Jacobian and its determinant
00533     Mat_t J(GE->dNdR * C); // J = dNdR * C
00534     detJ = Det(J);
00535 
00536     // coefficient used during integration
00537     Coef = h*detJ*IP.w;
00538 
00539     // N matrix
00540     N.change_dim (NDim, NDu);
00541     set_to_zero  (N);
00542     if (GTy==axs_t)
00543     {
00544         double radius = 0.0; // radius=x at this IP
00545         for (size_t j=0; j<GE->NN; ++j) radius += GE->N(j)*Con[j]->Vert.C[0];
00546         Coef *= radius; // correct coef for axisymmetric problems
00547     }
00548     for (int    i=0; i<NDim;   ++i)
00549     for (size_t j=0; j<GE->NN; ++j)
00550         N(i,i+j*NDim) = GE->N(j);
00551 }
00552 
00553 inline void EquilibElem::UpdateState (Vec_t const & dU, Vec_t * F_int) const
00554 {
00555     // get location array
00556     Array<size_t> loc;
00557     GetLoc (loc);
00558 
00559     // element nodal displacements
00560     Vec_t dUe(NDu);
00561     for (size_t i=0; i<loc.Size(); ++i) dUe(i) = dU(loc[i]);
00562 
00563     // update state at each IP
00564     double detJ, coef;
00565     Mat_t  C, B;
00566     Vec_t  dFe(NDu), dsig(NCo), deps(NCo);
00567     set_to_zero (dFe);
00568     CoordMatrix (C);
00569     for (size_t i=0; i<GE->NIP; ++i)
00570     {
00571         // B matrix
00572         CalcB (C, GE->IPs[i], B, detJ, coef);
00573 
00574         // strain and stress increments
00575         deps = B * dUe;
00576         std::cout << "deps = " << PrintVector(deps);
00577         Mdl->SUp.Update (deps, Sta[i], dsig);
00578 
00579         // element nodal forces
00580         dFe += (coef) * trans(B)*dsig;
00581     }
00582 
00583     // add results to Fint (internal forces)
00584     if (F_int!=NULL) for (size_t i=0; i<loc.Size(); ++i) (*F_int)(loc[i]) += dFe(i);
00585 }
00586 
00587 inline void EquilibElem::SetFint (Vec_t * Fint) const
00588 {
00589     // element force
00590     double detJ, coef;
00591     Mat_t  C, B;
00592     Vec_t  Fe(NDu);
00593     CoordMatrix (C);
00594     set_to_zero (Fe);
00595     for (size_t i=0; i<GE->NIP; ++i)
00596     {
00597         CalcB (C, GE->IPs[i], B, detJ, coef);
00598         Vec_t const & sig = static_cast<EquilibState const *>(Sta[i])->Sig;
00599         Fe += (coef) * trans(B)*sig;
00600     }
00601 
00602     // set nodes
00603     if (Fint==NULL)
00604     {
00605         for (size_t i=0; i<GE->NN; ++i)
00606         {
00607             Con[i]->F("fx") += Fe(0+i*NDim);
00608             Con[i]->F("fy") += Fe(1+i*NDim);  if (NDim==3)
00609             Con[i]->F("fz") += Fe(2+i*NDim);
00610         }
00611     }
00612 
00613     // return Fint
00614     else
00615     {
00616         Array<size_t> loc;
00617         GetLoc (loc);
00618         for (size_t i=0; i<loc.Size(); ++i) (*Fint)(loc[i]) += Fe(i);
00619     }
00620 }
00621 
00622 inline void EquilibElem::StateKeys (Array<String> & Keys) const
00623 {
00624     Keys = EquilibState::Keys;
00625     for (size_t i=0; i<Mdl->NIvs; ++i) Keys.Push (Mdl->IvNames[i]);
00626 }
00627 
00628 inline void EquilibElem::StateAtIP (SDPair & KeysVals, int IdxIP) const
00629 {
00630     Vec_t const & sig = static_cast<EquilibState const *>(Sta[IdxIP])->Sig;
00631     Vec_t const & eps = static_cast<EquilibState const *>(Sta[IdxIP])->Eps;
00632     Vec_t const & ivs = static_cast<EquilibState const *>(Sta[IdxIP])->Ivs;
00633 
00634     if (NDim==2)
00635     {
00636         KeysVals.Set("sx sy sz sxy  ex ey ez exy  pcam qcam  ev ed",
00637                      sig(0), sig(1), sig(2), sig(3)/Util::SQ2,
00638                      eps(0), eps(1), eps(2), eps(3)/Util::SQ2,
00639                      Calc_pcam(sig), Calc_qcam(sig), Calc_ev(eps), Calc_ed(eps));
00640     }
00641     else
00642     {
00643         KeysVals.Set("sx sy sz sxy syz szx  ex ey ez exy eyz ezx  pcam qcam  ev ed",
00644                      sig(0), sig(1), sig(2), sig(3)/Util::SQ2, sig(4)/Util::SQ2, sig(5)/Util::SQ2,
00645                      eps(0), eps(1), eps(2), eps(3)/Util::SQ2, eps(4)/Util::SQ2, eps(5)/Util::SQ2,
00646                      Calc_pcam(sig), Calc_qcam(sig), Calc_ev(eps), Calc_ed(eps));
00647     }
00648     for (size_t k=0; k<Mdl->NIvs; ++k) KeysVals.Set(Mdl->IvNames[k].CStr(), ivs(k));
00649 }
00650 
00651 inline size_t EquilibElem::NIVs () const 
00652 {
00653     size_t niv = size(static_cast<EquilibState const*>(Sta[0])->Ivs);
00654     return (NCo+niv)*GE->NIP;
00655 }
00656 
00657 inline double EquilibElem::GetIV (size_t i) const 
00658 {
00659     size_t niv = size(static_cast<EquilibState const*>(Sta[0])->Ivs);
00660     size_t iip = static_cast<int>(i) / static_cast<int>(NCo+niv); // index of IP
00661     size_t ico = static_cast<int>(i) % static_cast<int>(NCo+niv); // index of component/iv
00662     if (ico<NCo) return static_cast<EquilibState const*>(Sta[iip])->Sig(ico);
00663     else         return static_cast<EquilibState const*>(Sta[iip])->Ivs(ico-NCo);
00664 }
00665 
00666 inline void EquilibElem::SetIV (size_t i, double Val) 
00667 {
00668     size_t niv = size(static_cast<EquilibState const*>(Sta[0])->Ivs);
00669     size_t iip = static_cast<int>(i) / static_cast<int>(NCo+niv); // index of IP
00670     size_t ico = static_cast<int>(i) % static_cast<int>(NCo+niv); // index of component
00671     if (ico<NCo) static_cast<EquilibState*>(Sta[iip])->Sig(ico)     = Val;
00672     else         static_cast<EquilibState*>(Sta[iip])->Ivs(ico-NCo) = Val;
00673 }
00674 
00675 inline void EquilibElem::CalcIVRate (double Time, Vec_t const & U, Vec_t const & V, Vec_t & Rate) const
00676 {
00677     // resize rate
00678     size_t niv = size(static_cast<EquilibState const*>(Sta[0])->Ivs);
00679     Rate.change_dim ((NCo+niv)*GE->NIP);
00680 
00681     // get location array
00682     Array<size_t> loc;
00683     GetLoc (loc);
00684 
00685     // element nodal velocities
00686     Vec_t Ve(NDu);
00687     for (size_t i=0; i<loc.Size(); ++i) Ve(i) = V(loc[i]);
00688 
00689     // calc dsigdt
00690     double detJ, coef;
00691     Mat_t  C, B, D;
00692     Vec_t  depsdt(NCo), dsigdt(NCo), divsdt(niv);
00693     CoordMatrix (C);
00694     for (size_t i=0; i<GE->NIP; ++i)
00695     {
00696         CalcB (C, GE->IPs[i], B, detJ, coef);
00697         depsdt = B * Ve;
00698         Mdl->Rate (Sta[i], depsdt,  dsigdt, divsdt);
00699         for (size_t j=0; j<NCo; ++j) Rate(    j+i*(NCo+niv)) = dsigdt(j);
00700         for (size_t j=0; j<niv; ++j) Rate(NCo+j+i*(NCo+niv)) = divsdt(j);
00701     }
00702 }
00703 
00704 inline void EquilibElem::CorrectIVs ()
00705 {
00706     if (Mdl->SUp.CDrift)
00707     {
00708         for (size_t i=0; i<GE->NIP; ++i) Mdl->CorrectDrift (Sta[i]);
00709     }
00710 }
00711 
00712 
00714 
00715 
00716 // Allocate a new element
00717 Element * EquilibElemMaker(int NDim, Mesh::Cell const & Cell, Model const * Mdl, Model const * XMdl, SDPair const & Prp, SDPair const & Ini, Array<Node*> const & Nodes) { return new EquilibElem(NDim,Cell,Mdl,XMdl,Prp,Ini,Nodes); }
00718 
00719 // Register element
00720 int EquilibElemRegister()
00721 {
00722     ElementFactory  ["Equilib"]   = EquilibElemMaker;
00723     ElementVarKeys  ["Equilib2D"] = std::make_pair ("ux uy",    "fx fy");
00724     ElementVarKeys  ["Equilib3D"] = std::make_pair ("ux uy uz", "fx fy fz");
00725     ElementExtraKeys["Equilib2D"] = Array<String>  ("activate", "deactivate", "grav", "qn", "qt");
00726     ElementExtraKeys["Equilib3D"] = Array<String>  ("activate", "deactivate", "grav", "qn");
00727     PROB.Set ("Equilib", (double)PROB.Keys.Size());
00728     return 0;
00729 }
00730 
00731 // Call register
00732 int __EquilibElem_dummy_int  = EquilibElemRegister();
00733 
00734 }; // namespace FEM
00735 
00736 #endif // MECHSYS_FEM_EQUILIBELEM
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines