MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/fem/solvers/uwpsolver.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_UWPSOLVER_H
00021 #define MECHSYS_FEM_UWPSOLVER_H
00022 
00023 // MechSys
00024 #include <mechsys/fem/solver.h>
00025 #include <mechsys/fem/uwpelem.h>
00026 
00027 using std::cout;
00028 using std::endl;
00029 
00030 namespace FEM
00031 {
00032 
00033 class UWPSolver : public Solver
00034 {
00035 public:
00036     // Constructor
00037     UWPSolver (Domain & Dom, SDPair const & Flags, pOutFun OutFun=NULL, void * OutDat=NULL,
00038                                                    pOutFun DbgFun=NULL, void * DbgDat=NULL); 
00039 
00040     // Methods
00041     String Name       () const { return "UWPSolver"; }
00042     void   Initialize ();
00043     void   Assemble   (double Time, Vec_t const & V, Vec_t const & Ww, Vec_t const & Pw);
00044     void   RKFunc     (double Time, Vec_t const & V, Vec_t const & Ww, Vec_t const & Pw);
00045     void   Solve      (double tf, double dt, double dtOut, char const * FileKey=NULL); 
00046 
00047     // Data
00048     Array<long>                   pEqU, pEqW, pEqP;   
00049     Array<bool>                   pU,   pW,   pP;     
00050     Vec_t                         U, V, Ww, Pw;       
00051     Vec_t                         V_fe, Ww_fe, Pw_fe; 
00052     Vec_t                         V_me, Ww_me, Pw_me; 
00053     Vec_t                         V_er, Ww_er, Pw_er; 
00054     Vec_t                         DV,   DWw,   DPw;   
00055     Vec_t                         Rv, Rww;            
00056     Vec_t                         dVdt, dWwdt, dPwdt; 
00057     Vec_t                         f, fw, hw, cw, ew;  
00058     Sparse::Triplet<double,int>   M, Mb, Mw, Hw;      
00059     bool                          WithInfo;           
00060     double                        STOL, mMin, mMax, dTini, dTlast;
00061     size_t                        MaxSS;
00062 };
00063 
00064 
00066 
00067 
00068 inline UWPSolver::UWPSolver (Domain & Dom, SDPair const & Flags, pOutFun OutFun, void * OutDat, pOutFun DbgFun, void * DbgDat)
00069     : Solver (Dom, Flags, OutFun, OutDat, DbgFun, DbgDat), WithInfo(true),
00070       STOL(1.0e-2), mMin(0.2), mMax(2.0), dTini(0.01), dTlast(-1.0), MaxSS(2000)
00071 {
00072 }
00073 
00074 inline void UWPSolver::Initialize ()
00075 {
00076     // assign equation numbers
00077     size_t NEqU = 0;
00078     size_t NEqW = 0;
00079     size_t NEqP = 0;
00080     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00081     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00082     {
00083         if (Dom.ActNods[i]->UKey(j)=="wwx" || Dom.ActNods[i]->UKey(j)=="wwy" || Dom.ActNods[i]->UKey(j)=="wwz")
00084         {
00085             Dom.ActNods[i]->Eq(j) = NEqW;
00086             NEqW++;
00087         }
00088         else if (Dom.ActNods[i]->UKey(j)=="pw")
00089         {
00090             Dom.ActNods[i]->Eq(j) = NEqP;
00091             NEqP++;
00092         }
00093         else
00094         {
00095             Dom.ActNods[i]->Eq(j) = NEqU;
00096             NEqU++;
00097         }
00098     }
00099 
00100     // prescribed equations
00101     pEqU.Resize(0);  pU.Resize(NEqU);  pU.SetValues(false);
00102     pEqW.Resize(0);  pW.Resize(NEqW);  pW.SetValues(false);
00103     pEqP.Resize(0);  pP.Resize(NEqP);  pP.SetValues(false);
00104     for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
00105     {
00106         Node const * nod = Dom.NodsWithPU[i];
00107         for (size_t j=0; j<nod->NPU(); ++j)
00108         {
00109             int eq = nod->EqPU(j);
00110             if (nod->PUKey(j)=="wwx" || nod->PUKey(j)=="wwy" || nod->PUKey(j)=="wwz") { pEqW.Push(eq);  pW[eq]=true; }
00111             else if (nod->PUKey(j)=="pw")                                             { pEqP.Push(eq);  pP[eq]=true; }
00112             else                                                                      { pEqU.Push(eq);  pU[eq]=true; }
00113         }
00114     }
00115     //cout << "pEqU = " << pEqU << endl;
00116     //cout << "pEqW = " << pEqW << endl;
00117     //cout << "pEqP = " << pEqP << endl;
00118 
00119     // find total number of non-zero entries, including duplicates
00120     size_t Mb_size = 0;
00121     size_t Mw_size = 0;
00122     size_t Hw_size = 0;
00123     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00124     {
00125         if (Dom.ActEles[k]->IsUWP)
00126         {
00127             Dom.ActEles[k]->GetLoc ();
00128             for (size_t i=0; i<UWPElem::LocU .Size(); ++i)
00129             for (size_t j=0; j<UWPElem::LocU .Size(); ++j) Mb_size++;
00130             for (size_t i=0; i<UWPElem::LocWw.Size(); ++i)
00131             for (size_t j=0; j<UWPElem::LocWw.Size(); ++j) Mw_size++;
00132             for (size_t i=0; i<UWPElem::LocPw.Size(); ++i)
00133             for (size_t j=0; j<UWPElem::LocPw.Size(); ++j) Hw_size++;
00134         }
00135         else throw new Fatal("UWPElem::Initialize: this method does not work with elements that are not UWP yet");
00136     }
00137 
00138     // resize vectors and matrices
00139     U     . change_dim (NEqU);
00140     V     . change_dim (NEqU);
00141     Ww    . change_dim (NEqW);
00142     Pw    . change_dim (NEqP);
00143     V_fe  . change_dim (NEqU);
00144     Ww_fe . change_dim (NEqW);
00145     Pw_fe . change_dim (NEqP);
00146     V_me  . change_dim (NEqU);
00147     Ww_me . change_dim (NEqW);
00148     Pw_me . change_dim (NEqP);
00149     V_er  . change_dim (NEqU);
00150     Ww_er . change_dim (NEqW);
00151     Pw_er . change_dim (NEqP);
00152     DV    . change_dim (NEqU);
00153     DWw   . change_dim (NEqW);
00154     DPw   . change_dim (NEqP);
00155     Rv    . change_dim (NEqU);
00156     Rww   . change_dim (NEqW);
00157     dVdt  . change_dim (NEqU);
00158     dWwdt . change_dim (NEqW);
00159     dPwdt . change_dim (NEqP);
00160     f     . change_dim (NEqU);
00161     fw    . change_dim (NEqW);
00162     hw    . change_dim (NEqW);
00163     cw    . change_dim (NEqU);
00164     ew    . change_dim (NEqP);
00165     M     . AllocSpace (NEqU,NEqU,Mb_size);
00166     Mb    . AllocSpace (NEqU,NEqU,Mb_size);
00167     Mw    . AllocSpace (NEqW,NEqW,Mw_size);
00168     Hw    . AllocSpace (NEqP,NEqP,Hw_size);
00169 
00170     // set initial values (from previous stage)
00171     for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00172     for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00173     {
00174         if (Dom.ActNods[i]->UKey(j)=="wwx" || Dom.ActNods[i]->UKey(j)=="wwy" || Dom.ActNods[i]->UKey(j)=="wwz")
00175         {
00176             Ww(Dom.ActNods[i]->Eq(j)) = Dom.ActNods[i]->U(j);
00177         }
00178         else if (Dom.ActNods[i]->UKey(j)=="pw")
00179         {
00180             Pw(Dom.ActNods[i]->Eq(j)) = Dom.ActNods[i]->U(j);
00181         }
00182         else
00183         {
00184             U(Dom.ActNods[i]->Eq(j)) = Dom.ActNods[i]->U(j);
00185             V(Dom.ActNods[i]->Eq(j)) = Dom.ActNods[i]->V(j);
00186         }
00187     }
00188 }
00189 
00190 inline void UWPSolver::Assemble (double Time, Vec_t const & TheV, Vec_t const & TheWw, Vec_t const & ThePw)
00191 {
00192     M .ResetTop ();
00193     Mb.ResetTop ();
00194     Mw.ResetTop ();
00195     Hw.ResetTop ();
00196     set_to_zero (f);
00197     set_to_zero (fw);
00198     set_to_zero (hw);
00199     set_to_zero (cw);
00200     set_to_zero (ew);
00201     for (size_t k=0; k<Dom.ActEles.Size(); ++k)
00202     {
00203         if (Dom.ActEles[k]->IsUWP)
00204         {
00205             Dom.ActEles[k]->GetLoc  ();
00206             Dom.ActEles[k]->ElemEqs (Time, TheV, TheWw, ThePw);
00207 
00208             for (size_t i=0; i<UWPElem::LocU .Size(); ++i)
00209             {
00210                 f (UWPElem::LocU[i]) += UWPElem::f (i);
00211                 cw(UWPElem::LocU[i]) += UWPElem::cw(i);
00212                 for (size_t j=0; j<UWPElem::LocU.Size(); ++j)
00213                 {
00214                     M.PushEntry (UWPElem::LocU[i], UWPElem::LocU[j], UWPElem::M(i,j));
00215                     //if (!pU[UWPElem::LocU[i]] && !pU[UWPElem::LocU[j]]) Mb.PushEntry (UWPElem::LocU[i], UWPElem::LocU[j], UWPElem::M(i,j) - UWPElem::Mw(i,j));
00216                     Mb.PushEntry (UWPElem::LocU[i], UWPElem::LocU[j], UWPElem::M(i,j) - UWPElem::Mw(i,j));
00217                 }
00218             }
00219 
00220             for (size_t i=0; i<UWPElem::LocWw.Size(); ++i)
00221             {
00222                 fw(UWPElem::LocWw[i]) += UWPElem::fw(i);
00223                 hw(UWPElem::LocWw[i]) += UWPElem::hw(i);
00224                 for (size_t j=0; j<UWPElem::LocWw.Size(); ++j)
00225                 {
00226                     //if (!pW[UWPElem::LocWw[i]] && !pW[UWPElem::LocWw[j]]) Mw.PushEntry (UWPElem::LocWw[i], UWPElem::LocWw[j], UWPElem::Mw(i,j));
00227                     Mw.PushEntry (UWPElem::LocWw[i], UWPElem::LocWw[j], UWPElem::Mw(i,j));
00228                 }
00229             }
00230 
00231             for (size_t i=0; i<UWPElem::LocPw.Size(); ++i)
00232             {
00233                 ew(UWPElem::LocPw[i]) += UWPElem::ew(i);
00234                 for (size_t j=0; j<UWPElem::LocPw.Size(); ++j)
00235                 {
00236                     //if (!pP[UWPElem::LocPw[i]] && !pP[UWPElem::LocPw[j]]) Hw.PushEntry (UWPElem::LocPw[i], UWPElem::LocPw[j], UWPElem::Hw(i,j));
00237                     Hw.PushEntry (UWPElem::LocPw[i], UWPElem::LocPw[j], UWPElem::Hw(i,j));
00238                 }
00239             }
00240 
00241             //cout << "M  = \n" << PrintMatrix(UWPElem::M);
00242             //cout << "Mw = \n" << PrintMatrix(UWPElem::Mw);
00243             //cout << "Hw = \n" << PrintMatrix(UWPElem::Hw);
00244             //cout << "f  = \n" << PrintVector(UWPElem::f);
00245             //cout << "fw = \n" << PrintVector(UWPElem::fw);
00246             //cout << "hw = \n" << PrintVector(UWPElem::hw);
00247             //cout << "cw = \n" << PrintVector(UWPElem::cw);
00248             //cout << "ew = \n" << PrintVector(UWPElem::ew);
00249         }
00250         else
00251         {
00252             throw new Fatal("UWPElem::Assembly: this method does not work with elements that are not u-w-p yet");
00253             Array<size_t> loc;
00254             Mat_t         M;
00255             Dom.ActEles[k]->GetLoc (loc);
00256             Dom.ActEles[k]->CalcM  (M);
00257         }
00258     }
00259 
00260     //for (size_t i=0; i<pEqU.Size(); ++i) Mb.PushEntry (pEqU[i],pEqU[i], 1.0);
00261     //for (size_t i=0; i<pEqW.Size(); ++i) Mw.PushEntry (pEqW[i],pEqW[i], 1.0);
00262     //for (size_t i=0; i<pEqP.Size(); ++i) Hw.PushEntry (pEqP[i],pEqP[i], 1.0);
00263 
00264     /*
00265     M .WriteSMAT("M");
00266     Mb.WriteSMAT("Mb");
00267     Mw.WriteSMAT("Mw");
00268     Hw.WriteSMAT("Hw");
00269     Sparse::Matrix<double,int> sM(M), sMb(Mb), sMw(Mw), sHw(Hw);
00270     Mat_t Mmat, Mbmat, Mwmat, Hwmat, Mi, Mbi, Mwi, Hwi;
00271     sM .GetDense (Mmat);
00272     sMb.GetDense (Mbmat);
00273     sMw.GetDense (Mwmat);
00274     sHw.GetDense (Hwmat);
00275     cout << "M  = \n"       << PrintMatrix(Mmat,  "%10.5f");
00276     cout << "Mb = \n"       << PrintMatrix(Mbmat, "%10.5f");
00277     cout << "Mw = \n"       << PrintMatrix(Mwmat, "%10.5f");
00278     cout << "Hw = \n"       << PrintMatrix(Hwmat, "%10.5f");
00279     Inv (Mmat,  Mi);
00280     Inv (Mbmat, Mbi);
00281     Inv (Mwmat, Mwi);
00282     Inv (Hwmat, Hwi);
00283     cout << "Inv(M)   = \n" << PrintMatrix(Mi,  "%10.5f");
00284     cout << "Inv(Mbi) = \n" << PrintMatrix(Mbi, "%10.5f");
00285     cout << "Inv(Mw)  = \n" << PrintMatrix(Mwi, "%10.5f");
00286     cout << "Inv(Hw)  = \n" << PrintMatrix(Hwi, "%10.1f");
00287     cout << "det(M)  = "    << UMFPACK::Det (sM)  << endl;
00288     cout << "det(Mb) = "    << UMFPACK::Det (sMb) << endl;
00289     cout << "det(Mw) = "    << UMFPACK::Det (sMw) << endl;
00290     cout << "det(Hw) = "    << UMFPACK::Det (sHw) << endl;
00291     */
00292 }
00293 
00294 inline void UWPSolver::RKFunc (double Time, Vec_t const & TheV, Vec_t const & TheWw, Vec_t const & ThePw)
00295 {
00296     Assemble (Time, TheV, TheWw, ThePw);
00297 
00298     Rv  = f + hw - fw;
00299     Rww = f - cw;
00300 
00301     /*
00302     cout << "f     = " << PrintVector(f,      "%10.5f");
00303     cout << "fw    = " << PrintVector(fw,     "%10.5f");
00304     cout << "hw    = " << PrintVector(hw,     "%10.5f");
00305     cout << "cw    = " << PrintVector(cw,     "%10.5f");
00306     cout << "ew    = " << PrintVector(ew,     "%10.5f");
00307     cout << "Rv    = " << PrintVector(Rv,     "%10.5f");
00308     cout << "Rww   = " << PrintVector(Rww,    "%10.5f");
00309     */
00310 
00311     UMFPACK::Solve  (Mb, Rv,    dVdt);  // dVdt  = inv(Mb)*Rv
00312 
00313     for (size_t i=0; i<pEqU.Size(); ++i) dVdt(pEqU[i]) = 0.0;
00314 
00315     Sparse::SubMult (M,  dVdt,  Rww);   // Rww  -= M*dVdt
00316     UMFPACK::Solve  (Mw, Rww,   dWwdt); // dWwdt = inv(Mw)*Rww
00317 
00318     for (size_t i=0; i<pEqW.Size(); ++i) dWwdt(pEqW[i]) = 0.0;
00319 
00320     UMFPACK::Solve  (Hw, ew,    dPwdt); // dPwdt = inv(Hw)*ew
00321 
00322     // set prescribed U, V and A
00323     for (size_t i=0; i<Dom.NodsWithPU.Size(); ++i)
00324     {
00325         Node * const nod = Dom.NodsWithPU[i];
00326         for (size_t j=0; j<nod->NPU(); ++j)
00327         {
00328             if (nod->PUKey(j)=="pw")
00329             {
00330                 int eq = nod->EqPU(j);
00331                 dPwdt(eq) = nod->PV(j, Time);
00332             }
00333         }
00334     }
00335 
00336     /*
00337     cout << "Rv   (after) = " << PrintVector(Rv,     "%10.5f");
00338     cout << "Rww  (after) = " << PrintVector(Rww,    "%10.5f");
00339     cout << "dVdt  = "        << PrintVector(dVdt,   "%10.5f");
00340     cout << "dWwdt = "        << PrintVector(dWwdt,  "%10.5f");
00341     cout << "dPwdt = "        << PrintVector(dPwdt,  "%10.5f");
00342     cout << "V     = "        << PrintVector(V,      "%10.5f");
00343     cout << "Ww    = "        << PrintVector(Ww,     "%10.5f");
00344     cout << "Pw    = "        << PrintVector(Pw,     "%10.5f") << "\n";
00345     */
00346 }
00347 
00348 inline void UWPSolver::Solve (double tf, double, double dtOut, char const * FileKey)
00349 {
00350     // info
00351     Util::Stopwatch stopwatch(WithInfo);
00352 
00353     // initialize global matrices and vectors
00354     Initialize ();
00355 
00356     // output initial state
00357     printf ("\n%s--- Stage solution --- u-w-p Solver -- Runge-Kutta --------------------------%s\n",TERM_CLR1,TERM_RST);
00358     printf ("%s%10s  %4s%s\n",TERM_CLR2,"Time","NSS",TERM_RST);
00359     printf ("%10.6f  %4d\n",Dom.Time,0);
00360     if (Dom.IdxOut==0)
00361     {
00362         Dom.OutResults (FileKey);
00363         if (OutFun!=NULL) (*OutFun) (this, OutDat);
00364         if (DbgFun!=NULL) (*DbgFun) (this, DbgDat);
00365     }
00366 
00367     // time for output
00368     double tout = Dom.Time + dtOut;
00369     while (Dom.Time<tf)
00370     {
00371         // update to tout
00372         size_t stp = 0;
00373         double T   = 0.0;
00374         double dT  = (dTlast>0.0 ? dTlast : dTini);
00375         double Dt  = tout - Dom.Time;
00376         for (stp=0; stp<MaxSS; ++stp)
00377         {
00378             // exit
00379             if (T>=1.0) break;
00380 
00381             // time increment
00382             double dt = dT*Dt;
00383 
00384             // FE state
00385             RKFunc (Dom.Time, V, Ww, Pw);
00386             //DU    = V     * dt;
00387             DV    = dVdt  * dt;
00388             DWw   = dWwdt * dt;
00389             DPw   = dPwdt * dt;
00390             //U_fe  = U  + DU;
00391             V_fe  = V  + DV;
00392             Ww_fe = Ww + DWw;
00393             Pw_fe = Pw + DPw;
00394             for (size_t k=0; k<Dom.ActEles.Size(); ++k) Dom.ActEles[k]->Update (0, V, dPwdt, dt); // should update U here as well (because of large displacements shape functions)
00395 
00396             // ME State
00397             RKFunc (Dom.Time+dt, V_fe, Ww_fe, Pw_fe);
00398             V_me  = V  + 0.5*DV  + (0.5*dt)*dVdt;
00399             Ww_me = Ww + 0.5*DWw + (0.5*dt)*dWwdt;
00400             Pw_me = Pw + 0.5*DPw + (0.5*dt)*dPwdt;
00401             for (size_t k=0; k<Dom.ActEles.Size(); ++k) Dom.ActEles[k]->Update (1, V_fe, dPwdt, dt);
00402 
00403             // error estimate
00404             V_er  = V_me  - V_fe;
00405             Ww_er = Ww_me - Ww_fe;
00406             Pw_er = Pw_me - Pw_fe;
00407             double V_error  = Norm(V_er)  / (1.0+Norm(V_me));
00408             double Ww_error = Norm(Ww_er) / (1.0+Norm(Ww_me));
00409             double Pw_error = Norm(Pw_er) / (1.0+Norm(Pw_me));
00410             double error    = Util::Max (V_error, Ww_error, Pw_error);
00411 
00412             // step multiplier
00413             double m = (error>0.0 ? 0.9*sqrt(STOL/error) : mMax);
00414 
00415             //cout << "error = " << error << ", elems_error = " << elems_error << endl;
00416             //cout << "error = " << error << endl;
00417             //break;
00418 
00419             // update
00420             if (error<STOL)
00421             {
00422                 T        += dT;
00423                 Dom.Time += dt;
00424                 U        += V_me*dt;
00425                 V         = V_me;
00426                 Ww        = Ww_me;
00427                 Pw        = Pw_me;
00428                 if (m>mMax) m = mMax;
00429             }
00430             else
00431             {
00432                 for (size_t k=0; k<Dom.ActEles.Size(); ++k) Dom.ActEles[k]->Restore ();
00433                 if (m<mMin) m = mMin;
00434             }
00435             dT = m * dT;
00436             if (dT>1.0-T) dT = 1.0-T;
00437             else dTlast = dT;
00438         }
00439         if (stp==MaxSS) throw new Fatal("UWPSolver::Solve: Runge-Kutta (2nd order / ME) did not converge after %zd substeps",stp);
00440 
00441         // update nodes to tout
00442         for (size_t i=0; i<Dom.ActNods.Size();     ++i)
00443         for (size_t j=0; j<Dom.ActNods[i]->NDOF(); ++j)
00444         {
00445             if (Dom.ActNods[i]->UKey(j)=="wwx" || Dom.ActNods[i]->UKey(j)=="wwy" || Dom.ActNods[i]->UKey(j)=="wwz")
00446             {
00447                 Dom.ActNods[i]->U(j) = Ww(Dom.ActNods[i]->Eq(j));
00448             }
00449             else if (Dom.ActNods[i]->UKey(j)=="pw")
00450             {
00451                 Dom.ActNods[i]->U(j) = Pw(Dom.ActNods[i]->Eq(j));
00452             }
00453             else
00454             {
00455                 Dom.ActNods[i]->U(j) = U(Dom.ActNods[i]->Eq(j));
00456                 Dom.ActNods[i]->V(j) = V(Dom.ActNods[i]->Eq(j));
00457             }
00458         }
00459         
00460         // output
00461         printf ("%10.6f  %4zd\n",Dom.Time,stp);
00462         Dom.OutResults (FileKey);
00463         if (OutFun!=NULL) (*OutFun) (this, OutDat);
00464 
00465         // next tout
00466         tout = Dom.Time + dtOut;
00467     }
00468 }
00469 
00470 
00472 
00473 
00474 Solver * UWPSolverMaker(Domain & Dom, SDPair const & Flags, Solver::pOutFun OutFun, void * OutDat, Solver::pOutFun DbgFun, void * DbgDat)
00475 {
00476     return new UWPSolver (Dom, Flags, OutFun, OutDat, DbgFun, DbgDat);
00477 }
00478 
00479 int UWPSolverRegister()
00480 {
00481     SolverFactory["UWPSolver"] = UWPSolverMaker;
00482     return 0;
00483 }
00484 
00485 int __UWPSolver_dummy_int  = UWPSolverRegister();
00486 
00487 };
00488 
00489 #endif // MECHSYS_FEM_UWPSOLVER_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines