SPHFluidForceField.inl

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This library is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU Lesser General Public License as published by    *
00007 * the Free Software Foundation; either version 2.1 of the License, or (at     *
00008 * your option) any later version.                                             *
00009 *                                                                             *
00010 * This library is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License *
00013 * for more details.                                                           *
00014 *                                                                             *
00015 * You should have received a copy of the GNU Lesser General Public License    *
00016 * along with this library; if not, write to the Free Software Foundation,     *
00017 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.          *
00018 *******************************************************************************
00019 *                               SOFA :: Modules                               *
00020 *                                                                             *
00021 * Authors: The SOFA Team and external contributors (see Authors.txt)          *
00022 *                                                                             *
00023 * Contact information: contact@sofa-framework.org                             *
00024 ******************************************************************************/
00025 #ifndef SOFA_COMPONENT_FORCEFIELD_SPHFLUIDFORCEFIELD_INL
00026 #define SOFA_COMPONENT_FORCEFIELD_SPHFLUIDFORCEFIELD_INL
00027 
00028 #include <sofa/component/forcefield/SPHFluidForceField.h>
00029 #include <sofa/component/container/SpatialGridContainer.inl>
00030 #include <sofa/helper/system/config.h>
00031 #include <sofa/helper/gl/template.h>
00032 #include <math.h>
00033 #include <iostream>
00034 
00035 using std::cerr;
00036 using std::endl;
00037 
00038 namespace sofa
00039 {
00040 
00041 namespace component
00042 {
00043 
00044 namespace forcefield
00045 {
00046 
00047 template<class DataTypes>
00048 SPHFluidForceField<DataTypes>::SPHFluidForceField()
00049 : particleRadius   (initData(&particleRadius   ,Real(1)     , "radius", "Radius of a Particle")), 
00050   particleMass     (initData(&particleMass     ,Real(1)     , "mass", "Mass of a Particle")), 
00051   pressureStiffness(initData(&pressureStiffness,Real(100)   , "pressure", "Pressure")), 
00052   density0         (initData(&density0         ,Real(1)     , "density", "Density")), 
00053   viscosity        (initData(&viscosity        ,Real(0.001f), "viscosity", "Viscosity")), 
00054   surfaceTension   (initData(&surfaceTension   ,Real(0)     , "surfaceTension", "Surface Tension")), 
00055   grid(NULL)
00056 {
00057 }
00058 
00059 
00060 template<class DataTypes>
00061 void SPHFluidForceField<DataTypes>::init()
00062 {
00063     this->Inherit::init();
00064     this->getContext()->get(grid); //new Grid(particleRadius.getValue());
00065     if (grid==NULL)
00066         std::cout << "WARNING: SpatialGridContainer not found by SPHFluidForceField, slow O(n2) method will be used !!!" << std::endl;
00067     int n = (*this->mstate->getX()).size();
00068     particles.resize(n);
00069     for (int i=0;i<n;i++)
00070     {
00071         particles[i].neighbors.clear();
00072 #ifdef SOFA_DEBUG_SPATIALGRIDCONTAINER
00073         particles[i].neighbors2.clear();
00074 #endif
00075         particles[i].density = density0.getValue();
00076         particles[i].pressure = 0;
00077         particles[i].normal.clear();
00078         particles[i].curvature = 0;
00079     }
00080 }
00081 
00082 template<class DataTypes>
00083 void SPHFluidForceField<DataTypes>::addForce(VecDeriv& f, const VecCoord& x, const VecDeriv& v)
00084 {
00085     const Real h = particleRadius.getValue();
00086     const Real h2 = h*h;
00087     const Real m = particleMass.getValue();
00088     const Real m2 = m*m;
00089     const Real k = pressureStiffness.getValue();
00090     const Real d0 = density0.getValue();
00091     const Vec3d localg = this->getContext()->getLocalGravity();
00092     Deriv g;
00093     DataTypes::set ( g, localg[0], localg[1], localg[2]);
00094     //const Deriv mg = g * mass;
00095     const int n = x.size();
00096 
00097     // Precompute constants for smoothing kernels
00098     const Real     CWd =     constWd(h);
00099     //const Real CgradWd = constGradWd(h);
00100     //const Real  ClaplacianWd =  constLaplacianWd(h);
00101     //const Real     CWp =     constWp(h);
00102     const Real CgradWp = constGradWp(h);
00103     //const Real  ClaplacianWp =  constLaplacianWp(h);
00104     //const Real     CWv =     constWv(h);
00105     //const Real CgradWv = constGradWv(h);
00106     const Real  ClaplacianWv =  constLaplacianWv(h);
00107     //const Real     CWc =     constWc(h);
00108     const Real CgradWc = constGradWc(h);
00109     const Real  ClaplacianWc =  constLaplacianWc(h);
00110 
00111     // Initialization
00112     f.resize(n);
00113     dforces.clear();
00114     particles.resize(n);
00115     for (int i=0;i<n;i++)
00116     {
00117         particles[i].neighbors.clear();
00118 #ifdef SOFA_DEBUG_SPATIALGRIDCONTAINER
00119         particles[i].neighbors2.clear();
00120 #endif
00121         particles[i].density = 0;
00122         particles[i].pressure = 0;
00123         particles[i].normal.clear();
00124         particles[i].curvature = 0;
00125     }
00126 
00127     // First compute the neighbors
00128     // This is an O(n2) step, except if a hash-grid is used to optimize it
00129     if (grid == NULL)
00130     {
00131         for (int i=0;i<n;i++)
00132         {
00133             const Coord& ri = x[i];
00134             for (int j=i+1;j<n;j++)
00135             {
00136                 const Coord& rj = x[j];
00137                 Real r2 = (rj-ri).norm2();
00138                 if (r2 < h2)
00139                 {
00140                     Real r_h = (Real)sqrt(r2/h2);
00141                     particles[i].neighbors.push_back(std::make_pair(j,r_h));
00142                     //particles[j].neighbors.push_back(std::make_pair(i,r_h));
00143                 }
00144             }
00145         }
00146     }
00147     else
00148     {
00149         grid->updateGrid(x);
00150         grid->findNeighbors(this, h);
00151 #ifdef SOFA_DEBUG_SPATIALGRIDCONTAINER
00152         // Check grid
00153         for (int i=0;i<n;i++)
00154         {
00155             const Coord& ri = x[i];
00156             for (int j=i+1;j<n;j++)
00157             {
00158                 const Coord& rj = x[j];
00159                 Real r2 = (rj-ri).norm2();
00160                 if (r2 < h2)
00161                 {
00162                     Real r_h = (Real)sqrt(r2/h2);
00163                     particles[i].neighbors2.push_back(std::make_pair(j,r_h));
00164                 }
00165             }
00166         }
00167         for (int i=0;i<n;i++)
00168         {
00169             if (particles[i].neighbors.size() != particles[i].neighbors2.size())
00170             {
00171                 std::cerr << "particle "<<i<<" "<< x[i] <<" : "<<particles[i].neighbors.size()<<" neighbors on grid, "<< particles[i].neighbors2.size() << " neighbors on bruteforce.\n";
00172                 std::cerr << "grid-only neighbors:";
00173                 for (unsigned int j=0;j<particles[i].neighbors.size();j++)
00174                 {
00175                     int index = particles[i].neighbors[j].first;
00176                     unsigned int j2 = 0;
00177                     while (j2 < particles[i].neighbors2.size() && particles[i].neighbors2[j2].first != index)
00178                         ++j2;
00179                     if (j2 == particles[i].neighbors2.size())
00180                         std::cerr << " "<< x[index] << "<"<< particles[i].neighbors[j].first<<","<<particles[i].neighbors[j].second<<">";
00181                 }
00182                 std::cerr << "\n";
00183                 std::cerr << "bruteforce-only neighbors:";
00184                 for (unsigned int j=0;j<particles[i].neighbors2.size();j++)
00185                 {
00186                     int index = particles[i].neighbors2[j].first;
00187                     unsigned int j2 = 0;
00188                     while (j2 < particles[i].neighbors.size() && particles[i].neighbors[j2].first != index)
00189                         ++j2;
00190                     if (j2 == particles[i].neighbors.size())
00191                         std::cerr << " "<< x[index] << "<"<< particles[i].neighbors2[j].first<<","<<particles[i].neighbors2[j].second<<">";
00192                 }
00193                 std::cerr << "\n";
00194             }
00195         }
00196 #endif
00197     }
00198 
00199     // Compute density and pressure
00200     for (int i=0;i<n;i++)
00201     {
00202         Particle& Pi = particles[i];
00203         Real density = Pi.density;
00204         density += m*Wd(0,CWd); // density from current particle
00205         Deriv n;
00206         for (typename std::vector< std::pair<int,Real> >::const_iterator it = Pi.neighbors.begin(); it != Pi.neighbors.end(); ++it)
00207         {
00208             const int j = it->first;
00209             const Real r_h = it->second;
00210             Particle& Pj = particles[j];
00211             Real d = m*Wd(r_h,CWd);
00212             density += d;
00213             Pj.density += d;
00214         }
00215         Pi.density = density;
00216         Pi.pressure = k*(density - d0);
00217     }
00218 
00219     // Compute surface normal and curvature
00220     if (surfaceTension.getValue() > 0)
00221     {
00222         for (int i=0;i<n;i++)
00223         {
00224             Particle& Pi = particles[i];
00225             for (typename std::vector< std::pair<int,Real> >::const_iterator it = Pi.neighbors.begin(); it != Pi.neighbors.end(); ++it)
00226             {
00227                 const int j = it->first;
00228                 const Real r_h = it->second;
00229                 Particle& Pj = particles[j];
00230                 Deriv n = gradWc(x[i]-x[j],r_h,CgradWc) * (m / Pj.density - m / Pi.density);
00231                 Pi.normal += n;
00232                 Pj.normal -= n;
00233                 Real c = laplacianWc(r_h,ClaplacianWc) * (m / Pj.density - m / Pi.density);
00234                 Pi.curvature += c;
00235                 Pj.curvature -= c;
00236             }
00237         }
00238     }
00239 
00240     // Compute the forces
00241     for (int i=0;i<n;i++)
00242     {
00243         Particle& Pi = particles[i];
00244 
00245         // Gravity
00246         //f[i] += g*(m*Pi.density);
00247 
00248         for (typename std::vector< std::pair<int,Real> >::const_iterator it = Pi.neighbors.begin(); it != Pi.neighbors.end(); ++it)
00249         {
00250             const int j = it->first;
00251             const Real r_h = it->second;
00252             Particle& Pj = particles[j];
00253             // Pressure
00254             Deriv fpressure = gradWp(x[i]-x[j],r_h,CgradWp) * ( - m2 * (Pi.pressure / (Pi.density*Pi.density) + Pj.pressure / (Pj.density*Pj.density)) );
00255             f[i] += fpressure;
00256             f[j] -= fpressure;
00257     
00258             // Viscosity
00259             Deriv fviscosity = ( v[j] - v[i] ) * ( m2 * viscosity.getValue() / (Pi.density * Pj.density) * laplacianWv(r_h,ClaplacianWv) );
00260             f[i] += fviscosity;
00261             f[j] -= fviscosity;
00262         }
00263 
00264         if (surfaceTension.getValue() > 0)
00265         {
00266             Real n = Pi.normal.norm();
00267             if (n > 0.000001)
00268             {
00269                 Deriv fsurface = Pi.normal * ( - m * surfaceTension.getValue() * Pi.curvature / n );
00270                 f[i] += fsurface;
00271             }
00272         }
00273     }
00274 }
00275 
00276 template<class DataTypes>
00277 void SPHFluidForceField<DataTypes>::addDForce(VecDeriv& f1,  const VecDeriv& dx1)
00278 {
00279     const VecCoord& p1 = *this->mstate->getX();
00280     f1.resize(dx1.size());
00281     for (unsigned int i=0; i<this->dforces.size(); i++)
00282     {
00283         const DForce& df = this->dforces[i];
00284         const unsigned int ia = df.a;
00285         const unsigned int ib = df.b;
00286         const Deriv u = p1[ib]-p1[ia];
00287         const Deriv du = dx1[ib]-dx1[ia];
00288         const Deriv dforce = u * (df.df * (du*u)); 
00289         f1[ia] += dforce;
00290         f1[ib] -= dforce;
00291     }
00292 }
00293 
00294     template <class DataTypes> 
00295     double SPHFluidForceField<DataTypes>::getPotentialEnergy(const VecCoord&)
00296 {
00297     cerr<<"SPHFluidForceField::getPotentialEnergy-not-implemented !!!"<<endl;
00298     return 0;
00299 }
00300 
00301 
00302 template<class DataTypes>
00303 void SPHFluidForceField<DataTypes>::draw()
00304 {
00305     if (!getContext()->getShowForceFields()) return;
00306     //if (grid != NULL)
00307     //  grid->draw();
00308     const VecCoord& x = *this->mstate->getX();
00309     glDisable(GL_LIGHTING);
00310     glEnable(GL_BLEND);
00311     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00312     glDepthMask(0);
00313     glColor3f(0,1,1);
00314     glLineWidth(1);
00315     glBegin(GL_LINES);
00316     for (unsigned int i=0;i<particles.size();i++)
00317     {
00318         Particle& Pi = particles[i];
00319 #ifdef SOFA_DEBUG_SPATIALGRIDCONTAINER
00320         // Check grid
00321         if (Pi.neighbors.size() != Pi.neighbors2.size())
00322         {
00323             glColor4f(1,0,0,1);
00324             for (unsigned int j=0;j<Pi.neighbors.size();j++)
00325             {
00326                 int index = Pi.neighbors[j].first;
00327                 unsigned int j2 = 0;
00328                 while (j2 < Pi.neighbors2.size() && Pi.neighbors2[j2].first != index)
00329                     ++j2;
00330                 if (j2 == Pi.neighbors2.size())
00331                 {
00332                     helper::gl::glVertexT(x[i]);
00333                     helper::gl::glVertexT(x[index]);
00334                 }
00335             }
00336             glColor4f(1,0,1,1);
00337             for (unsigned int j=0;j<Pi.neighbors2.size();j++)
00338             {
00339                 int index = Pi.neighbors2[j].first;
00340                 unsigned int j2 = 0;
00341                 while (j2 < Pi.neighbors.size() && Pi.neighbors[j2].first != index)
00342                     ++j2;
00343                 if (j2 == Pi.neighbors.size())
00344                 {
00345                     helper::gl::glVertexT(x[i]);
00346                     helper::gl::glVertexT(x[index]);
00347                 }
00348             }
00349         }
00350 #else
00351         for (typename std::vector< std::pair<int,Real> >::const_iterator it = Pi.neighbors.begin(); it != Pi.neighbors.end(); ++it)
00352         {
00353             const int j = it->first;
00354             const float r_h = (float)it->second;
00355             float f = r_h*2;
00356             if (f < 1)
00357             {
00358                 glColor4f(0,1-f,f,1-r_h);
00359             }
00360             else
00361             {
00362                 glColor4f(f-1,0,2-f,1-r_h);
00363             }
00364             helper::gl::glVertexT(x[i]);
00365             helper::gl::glVertexT(x[j]);
00366         }
00367 #endif
00368     }
00369     glEnd();
00370     glDisable(GL_BLEND);
00371     glDepthMask(1);
00372     glPointSize(5);
00373     glBegin(GL_POINTS);
00374     for (unsigned int i=0;i<particles.size();i++)
00375     {
00376         Particle& Pi = particles[i];
00377         float f = (float)(Pi.density / density0.getValue());
00378         f = 1+10*(f-1);
00379         if (f < 1)
00380         {
00381             glColor3f(0,1-f,f);
00382         }
00383         else
00384         {
00385             glColor3f(f-1,0,2-f);
00386         }
00387         helper::gl::glVertexT(x[i]);
00388     }
00389     glEnd();
00390     glPointSize(1);
00391 }
00392 
00393 } // namespace forcefield
00394 
00395 } // namespace component
00396 
00397 } // namespace sofa
00398 
00399 #endif

Generated on Sun Nov 23 03:07:38 2008 for Sofa by  doxygen 1.5.7.1