Lagrangian Liquid Simulation
Master Thesis project on simulation of liquids using Lagrangian approach and SPH
src/Solver.cpp
Go to the documentation of this file.
00001 
00002 
00003 
00004 #include "Solver.h"
00005 #include "Configuration.h"
00006 #include "Integration.h"
00007 
00008 #include "boost/foreach.hpp"
00009 
00010 #include "ctime"
00011 
00012 Solver::Solver()
00013 {
00014     //create particles and initialise parameters
00015     Configuration::initialiseFluidSolver
00016             (
00017                 m_smoothingLength,
00018                 m_particleList,
00019                 m_hoseParticlePrototypeList,
00020                 m_hoseParticleList,
00021                 m_hoseCenter,
00022                 m_hoseVelocity,
00023                 m_drawHoseMarker,
00024                 m_hoseWaitUntilHitBoundary,
00025                 m_hoseWaitUntilHitRBD
00026            );
00027 
00028     //precompute kernel weight multipliers
00029     m_weightPoly = (315.0 / (64.0 * ngl::PI * pow(m_smoothingLength, 9)));
00030     m_weightPolyGradient = (-945.0 / (32.0 * ngl::PI * pow(m_smoothingLength, 9)));
00031     m_weightPolyLaplacian = (-945.0 / (32.0 * ngl::PI * pow(m_smoothingLength, 9)));
00032     m_weightPressureGradient = (-45.0 / (ngl::PI * pow(m_smoothingLength, 6)));
00033     m_weightViscosityLaplacian = (45.0 / (ngl::PI * pow(m_smoothingLength, 6)));
00034 
00035     //initialise parameters
00036     m_enableAutoFluid = true;
00037     m_currentHoseableFluid = 0;
00038 
00039     //create neighbouring structure
00040     m_neighbour = new Neighbour(m_particleList.size(), m_smoothingLength);
00041 
00042     m_iteration = 0;
00043 }
00044 
00045 Solver::~Solver()
00046 {
00047     //clean up
00048     std::cout << "Fluid Solver Cleanup" << std::endl;
00049 
00050     //delete objects
00051     delete m_neighbour;
00052 }
00053 
00054 void Solver::initialiseDrawing()
00055 {
00056     ngl::VBOPrimitives* prim = ngl::VBOPrimitives::instance();
00057 
00058     //create vbo for particle sphere
00059     prim->createVBOSphere("particleSphere", 0.17, 10);
00060 }
00061 
00062 ngl::Real Solver::WKernel_Poly(const ngl::Real _separationLength)
00063 {
00064     ngl::Real weight = m_weightPoly * (pow(pow(m_smoothingLength, 2) - pow(_separationLength, 2), 3));
00065 
00066     return weight;
00067 }
00068 
00069 ngl::Vector Solver::WKernel_Poly_Gradient(const ngl::Vector _separationVector)
00070 {
00071     ngl::Vector weight = 0;
00072     ngl::Real separationLength = _separationVector.length();
00073 
00074     weight = m_weightPolyGradient * _separationVector * pow(pow(m_smoothingLength, 2) - pow(separationLength, 2), 2);
00075 
00076     return weight;
00077 }
00078 
00079 ngl::Real Solver::WKernel_Poly_Laplacian(const ngl::Real _separationLength)
00080 {
00081     ngl::Real weight = m_weightPolyLaplacian * (pow(m_smoothingLength, 2) - pow(_separationLength, 2)) * ((3.0 * pow(m_smoothingLength, 2)) - (7.0 * pow(_separationLength, 2)));
00082 
00083     return weight;
00084 }
00085 
00086 ngl::Vector Solver::WKernel_Pressure_Gradient(const ngl::Vector _separationVector)
00087 {
00088     ngl::Vector weight = 0;
00089     ngl::Real separationLength = _separationVector.length();
00090 
00091     weight = m_weightPressureGradient * pow(m_smoothingLength - separationLength, 2) * normalise(_separationVector);
00092 
00093     return weight;
00094 }
00095 
00096 ngl::Real Solver::WKernel_Viscosity_Laplacian(const ngl::Real _separationLength)
00097 {
00098     ngl::Real weight = m_weightViscosityLaplacian * (m_smoothingLength - _separationLength);
00099 
00100     return weight;
00101 }
00102 
00103 ngl::Vector Solver::normalise(const ngl::Vector _vector)
00104 {
00105     ngl::Vector v = _vector;
00106     if (_vector.length() > 0.0001f) v.normalize();
00107 
00108     return v;
00109 }
00110 
00111 
00112 int Solver::getFluidIdFromName(const std::string _name)
00113 {
00114     //assume id to be of the first fluid
00115     int id = 0;
00116 
00117     //loop through hose prototype list
00118     for (int i = 0; i < m_hoseParticlePrototypeList.size(); i++)
00119     {
00120         //compare names
00121         if (m_hoseParticlePrototypeList[i].getName() == _name)
00122         {
00123             id = i;
00124             break;
00125         }
00126     }
00127 
00128     return id;
00129 }
00130 
00131 void Solver::injectParticles()
00132 {
00133     std::vector<FluidParticle> l;
00134 
00135     //get translate in hose center
00136     ngl::Vector translatedVector = m_hoseCenter - m_hoseInitialCenter;
00137 
00138     //get prototype particle from hose prototype list
00139     FluidParticle prototypeParticle = m_hoseParticlePrototypeList[m_currentHoseableFluid];
00140 
00141     //loop through hose particles and add particles to solver particle list
00142     for (int i = 0; i < m_hoseParticleList.size(); i++)
00143     {
00144         //create particle from prototype particle
00145         FluidParticle p(prototypeParticle);
00146 
00147         //set id of new particle
00148         p.setId(Configuration::s_nextParticleId++);
00149 
00150         //set position of new particle = hose particle(i) + translatedVector
00151         p.setPosition(m_hoseParticleList[i].getPosition() + translatedVector);
00152 
00153         //set velocity of new particle
00154         p.setVelocity(m_hoseVelocity);
00155 
00156         //set wait until first hit properties
00157         p.setWaitUntilFirstHitBoundary(m_hoseWaitUntilHitBoundary);
00158         p.setWaitUntilFirstHitRBD(m_hoseWaitUntilHitRBD);
00159 
00160         //add new particle to particle list
00161         m_particleList.push_back(p);
00162     }
00163 
00164     std::cout << "Hose for fluid : " << m_currentHoseableFluid << "\tnew particle count : " << m_particleList.size() << "\n";
00165 
00166     //reinitialise neighbour structure due to new particles being added
00167     m_neighbour->reInitialise(m_particleList.size(), m_smoothingLength);
00168 }
00169 
00170 void Solver::updateFluid
00171                 (
00172                     Environment* io_environment,
00173                     Integration* _integration
00174                 )
00175 {
00176     //clear neighbour map
00177     m_neighbour->clearHashmap();
00178 
00179 #pragma omp parallel
00180 {
00181     //refresh neighbour list
00182     m_neighbour->refreshHashmap(m_particleList);
00183 }
00184 
00185 #pragma omp parallel
00186 {
00187 #pragma omp for schedule(dynamic, 50)
00188     //density-pressure calculations
00189     for (int i = 0; i < m_particleList.size(); ++i)
00190     {
00191         //get neighbours of current particle
00192         std::vector<FluidParticle> neighbourList = m_neighbour->determineNeighbours(m_particleList[i].getPosition());
00193 
00194         //calculate density and pressure
00195         ngl::Real density = 0.0;
00196         for (int j = 0; j < neighbourList.size(); j++)
00197         {
00198             //accumulate density
00199             density += neighbourList[j].getMass() * WKernel_Poly((m_particleList[i].getPosition() - neighbourList[j].getPosition()).length());
00200         }
00201         m_particleList[i].setDensity(density);
00202 
00203         //calculate pressure
00204         m_particleList[i].calculatePressure();
00205     }
00206 
00207 #pragma omp for schedule(dynamic, 50)
00208     //force calculations
00209     for (int i = 0; i < m_particleList.size(); ++i)
00210     {
00211         //reset net forces accumulate
00212         m_particleList[i].resetForce();
00213 
00214         //get neighbours of current particle
00215         std::vector<FluidParticle> neighbourList = m_neighbour->determineNeighbours(m_particleList[i].getPosition());
00216 
00217         //calculate internal forces of current particle
00218         ngl::Real massPerDensity = 0;
00219         ngl::Vector separationVector = 0;
00220         ngl::Real separationLength = 0.0;
00221 
00222         ngl::Vector pressure = 0;
00223         ngl::Vector viscosity = 0;
00224 
00225         ngl::Vector surfaceGradient = 0;
00226         ngl::Real surfaceLaplacian = 0;
00227 
00228         ngl::Vector surfaceTensionGradient = 0;
00229         ngl::Real surfaceTensionLaplacian = 0;
00230         ngl::Vector interfaceTensionGradient = 0;
00231         ngl::Real interfaceTensionLaplacian = 0;
00232 
00233         //apply fluid rules if enabled
00234         if (m_particleList[i].fluidRulesEnabled())
00235         {
00236             for (int j = 0; j < neighbourList.size(); j++)
00237             {
00238                 //get neighbour
00239                 FluidParticle neighbour = neighbourList[j];
00240 
00241                 //pre-calculate some repetitive values
00242                 massPerDensity = neighbour.getMass() / neighbour.getDensity();
00243                 separationVector = m_particleList[i].getPosition() - neighbour.getPosition();
00244                 separationLength = separationVector.length();
00245 
00246                 //add in pressure and viscosity force only for neighbours, not the current particle itself
00247                 if (neighbour.getId() != m_particleList[i].getId())
00248                 {
00249                     //accumulate pressure force component
00250                     pressure = pressure +
00251                                (
00252                                        ((m_particleList[i].getPressure() / pow(m_particleList[i].getDensity(), 2)) + (neighbour.getPressure() / pow(neighbour.getDensity(), 2))) *
00253                                        neighbour.getMass() *
00254                                        WKernel_Pressure_Gradient(separationVector)
00255                                        );
00256 
00257                     //accumulate viscous force component
00258                     viscosity = viscosity +
00259                                 (
00260                                         /*((currentParticle.getViscosityConstant() + neighbour.getViscosityConstant()) / 2.0) **/
00261                                         massPerDensity *
00262                                         (neighbour.getVelocity() - m_particleList[i].getVelocity()) *
00263                                         WKernel_Viscosity_Laplacian(separationLength)
00264                                         );
00265                 }
00266 
00267                 //accumulate surface tension-interface force component
00268                 surfaceGradient = WKernel_Poly_Gradient(separationVector);
00269                 surfaceLaplacian = WKernel_Poly_Laplacian(separationLength);
00270 
00271                 //accumulate surface gradient
00272                 surfaceTensionGradient = surfaceTensionGradient +
00273                                          (
00274                                                  massPerDensity *
00275                                                  m_particleList[i].getSurfaceColorCoefficient() *
00276                                                  surfaceGradient
00277                                                  );
00278 
00279                 //accumulate surface laplacian
00280                 surfaceTensionLaplacian = surfaceTensionLaplacian +
00281                                           (
00282                                                   massPerDensity *
00283                                                   m_particleList[i].getSurfaceColorCoefficient() *
00284                                                   surfaceLaplacian
00285                                                   );
00286 
00287                 //accumulate interface gradient
00288                 interfaceTensionGradient = surfaceTensionGradient +
00289                                            (
00290                                                    massPerDensity *
00291                                                    m_particleList[i].getInterfaceColorCoefficient() *
00292                                                    surfaceGradient
00293                                                    );
00294 
00295                 //accumulate interface laplacian
00296                 interfaceTensionLaplacian = surfaceTensionLaplacian +
00297                                             (
00298                                                     massPerDensity *
00299                                                     m_particleList[i].getInterfaceColorCoefficient() *
00300                                                     surfaceLaplacian
00301                                                     );
00302 
00303             }
00304         }
00305 
00306         //calculate pressure force
00307         m_particleList[i].setPressureForce(-1.0 * m_particleList[i].getDensity() * pressure);
00308 
00309         //calculate viscosity force
00310         m_particleList[i].setViscosityForce(viscosity * m_particleList[i].getViscosityConstant());
00311 
00312         //calculate surface tension force
00313         m_particleList[i].setSurfaceTensionForce(0.0);
00314         if (surfaceTensionGradient.length() > m_particleList[i].getSurfaceTensionThreshold())
00315         {
00316             m_particleList[i].setSurfaceTensionForce(-1.0 * m_particleList[i].getSurfaceTensionCoefficient() * normalise(surfaceTensionGradient) * surfaceTensionLaplacian);
00317         }
00318 
00319         //calculate interface tension force
00320         m_particleList[i].setInterfaceTensionForce(0.0);
00321         if (interfaceTensionGradient.length() > m_particleList[i].getInterfaceTensionThreshold())
00322         {
00323             m_particleList[i].setInterfaceTensionForce(-1.0 * m_particleList[i].getInterfaceTensionCoefficient() * normalise(interfaceTensionGradient) * interfaceTensionLaplacian);
00324         }
00325 
00326         //calculate gravity force (=density * g)
00327         m_particleList[i].setGravityForce(new ngl::Vector(0, m_particleList[i].getDensity() * Configuration::s_accelerationOfFreeFall, 0));
00328 
00329         //calculate acceleration (= force / mass)
00330         m_particleList[i].accumulateNetForce(m_particleList[i].getPressureForce());
00331         m_particleList[i].accumulateNetForce(m_particleList[i].getViscosityForce());
00332         m_particleList[i].accumulateNetForce(m_particleList[i].getSurfaceTensionForce());
00333         m_particleList[i].accumulateNetForce(m_particleList[i].getInterfaceTensionForce());
00334         m_particleList[i].accumulateNetForce(m_particleList[i].getGravityForce());
00335         m_particleList[i].updateAcceleration(m_particleList[i].getNetForce() / m_particleList[i].getDensity());
00336     }
00337 
00338 #pragma omp for schedule(dynamic, 50)
00339     //fluid integration and movement
00340     for (int i = 0; i < m_particleList.size(); ++i)
00341     {
00342         if (m_particleList[i].getMoveable())
00343         {
00344             //determine next (position, velocity) of particle
00345             _integration->integrateNext(m_particleList[i]);
00346         }
00347     }
00348 
00349 #pragma omp single
00350     //obstacles movement
00351     io_environment->updateObstacles(_integration);
00352 
00353 #pragma omp for schedule(dynamic, 50)
00354     //collision check and resolution for fluid particles
00355     for (int i = 0; i < m_particleList.size(); ++i)
00356     {
00357         //check and resolve collision against obstacles and boundary
00358         bool hitBoundary = false; bool hitRBD = false;
00359         io_environment->checkAndResolveCollision(m_particleList[i], hitBoundary, hitRBD, false);
00360 
00361         //update first time hit issues
00362         m_particleList[i].updateHitForTheFirstTime(hitBoundary, hitRBD);
00363     }
00364 }
00365 
00366 //    //increment iteration counter
00367 //    iteration++;
00368 //    std::cout << iteration << "\n";
00369 
00370 //    if ((iteration % 1001) == 0)
00371 //    {
00372 //        time_t now; time(&now);
00373 //        printf("%s\n", ctime(&now));
00374 //    }
00375 }
00376 
00377 void Solver::render
00378                 (
00379                     ngl::TransformStack _txStack,
00380                     ShaderLibrary* io_sman,
00381                     const std::string _shader
00382                 )
00383 {
00384     ngl::VBOPrimitives* prim = ngl::VBOPrimitives::instance();
00385 
00386     _txStack.pushTransform();
00387     {
00388         for (int i = 0; i < m_particleList.size(); ++i)
00389         {
00390             _txStack.getCurrentTransform().setPosition(m_particleList[i].getPosition().m_x, m_particleList[i].getPosition().m_y, m_particleList[i].getPosition().m_z);
00391 
00392             //pass vertex info to shader
00393             io_sman->updateModel(_shader, _txStack.getCurrAndGlobal().getMatrix(), false);
00394 
00395             //pass color info to shader
00396             io_sman->updateColor(_shader, m_particleList[i].getColour(), false);
00397 
00398             prim->draw("particleSphere");
00399         }
00400     }
00401     _txStack.popTransform();
00402 }
00403 
00404 std::vector<std::vector<ngl::Vector> > Solver::getPositionList()
00405 {
00406     std::vector<std::vector<ngl::Vector> > positionList;
00407 
00408     //loop through the prototype list that contains 1 particle prototype for each fluid
00409     for (int i = 0; i < m_hoseParticlePrototypeList.size(); ++i)
00410     {
00411         //get name
00412         std::string name = m_hoseParticlePrototypeList[i].getName();
00413         std::vector<ngl::Vector> list;
00414         list.reserve(m_particleList.size());
00415 
00416         //loop through particle list
00417         for (int j = 0; j < m_particleList.size(); ++j)
00418         {
00419             //search for particles having this name
00420             if (m_particleList[j].getName() == name)
00421             {
00422                 //add this particle's position to list
00423                 list.push_back(m_particleList[j].getPosition());
00424             }
00425         }
00426 
00427         //add this fluid's position list to the big list
00428         positionList.push_back(list);
00429     }
00430 
00431     return positionList;
00432 }
00433 
00434 std::vector<std::string> Solver::getNameList()
00435 {
00436     std::vector<std::string> list;
00437     list.reserve(m_hoseParticlePrototypeList.size());
00438 
00439     for (int i = 0; i < m_hoseParticlePrototypeList.size(); ++i) list.push_back(m_hoseParticlePrototypeList[i].getName());
00440 
00441     return list;
00442 }
00443 
00444 void Solver::updateRestDensityForFluid
00445                 (
00446                     const int _fluidId,
00447                     const ngl::Real _restDensity
00448                 )
00449 {
00450     //loop for particles of the concerned fluid
00451     for (int i = 0; i < m_particleList.size(); ++i)
00452     {
00453         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00454         {
00455             //found particles of the concerned fluid -> update it
00456             m_particleList[i].setMaterialRestDensity(_restDensity);
00457         }
00458     }
00459 
00460     m_hoseParticlePrototypeList[_fluidId].setMaterialRestDensity(_restDensity);
00461 }
00462 
00463 void Solver::updateGasConstantForFluid
00464                 (
00465                     const int _fluidId,
00466                     const ngl::Real _gasConstant
00467                 )
00468 {
00469     //loop for particles of the concerned fluid
00470     for (int i = 0; i < m_particleList.size(); ++i)
00471     {
00472         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00473         {
00474             //found particles of the concerned fluid -> update it
00475             m_particleList[i].setGasConstant(_gasConstant);
00476         }
00477     }
00478 
00479     m_hoseParticlePrototypeList[_fluidId].setGasConstant(_gasConstant);
00480 }
00481 
00482 void Solver::updateViscosityConstantForFluid
00483                 (
00484                     const int _fluidId,
00485                     const ngl::Real _viscosityConstant
00486                 )
00487 {
00488     //loop for particles of the concerned fluid
00489     for (int i = 0; i < m_particleList.size(); ++i)
00490     {
00491         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00492         {
00493             //found particles of the concerned fluid -> update it
00494             m_particleList[i].setViscosityConstant(_viscosityConstant);
00495         }
00496     }
00497 
00498     m_hoseParticlePrototypeList[_fluidId].setViscosityConstant(_viscosityConstant);
00499 }
00500 
00501 void Solver::updateSurfaceCoefficientForFluid
00502                 (
00503                     const int _fluidId,
00504                     const ngl::Real _coefficient
00505                 )
00506 {
00507     //loop for particles of the concerned fluid
00508     for (int i = 0; i < m_particleList.size(); ++i)
00509     {
00510         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00511         {
00512             //found particles of the concerned fluid -> update it
00513             m_particleList[i].setSurfaceTensionCoefficient(_coefficient);
00514         }
00515     }
00516 
00517     m_hoseParticlePrototypeList[_fluidId].setSurfaceTensionCoefficient(_coefficient);
00518 }
00519 
00520 void Solver::updateSurfaceThresholdForFluid
00521                 (
00522                     const int _fluidId,
00523                     const ngl::Real _threshold
00524                 )
00525 {
00526     //loop for particles of the concerned fluid
00527     for (int i = 0; i < m_particleList.size(); ++i)
00528     {
00529         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00530         {
00531             //found particles of the concerned fluid -> update it
00532             m_particleList[i].setSurfaceTensionThreshold(_threshold);
00533         }
00534     }
00535 
00536     m_hoseParticlePrototypeList[_fluidId].setSurfaceTensionThreshold(_threshold);
00537 }
00538 
00539 void Solver::updateInterfaceCoefficientForFluid
00540                 (
00541                     const int _fluidId,
00542                     const ngl::Real _coefficient
00543                 )
00544 {
00545     //loop for particles of the concerned fluid
00546     for (int i = 0; i < m_particleList.size(); ++i)
00547     {
00548         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00549         {
00550             //found particles of the concerned fluid -> update it
00551             m_particleList[i].setInterfaceTensionCoefficient(_coefficient);
00552         }
00553     }
00554 
00555     m_hoseParticlePrototypeList[_fluidId].setInterfaceTensionCoefficient(_coefficient);
00556 }
00557 
00558 void Solver::updateInterfaceThresholdForFluid
00559                 (
00560                     const int _fluidId,
00561                     const ngl::Real _threshold
00562                 )
00563 {
00564     //loop for particles of the concerned fluid
00565     for (int i = 0; i < m_particleList.size(); ++i)
00566     {
00567         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00568         {
00569             //found particles of the concerned fluid -> update it
00570             m_particleList[i].setInterfaceTensionThreshold(_threshold);
00571         }
00572     }
00573 
00574     m_hoseParticlePrototypeList[_fluidId].setInterfaceTensionThreshold(_threshold);
00575 }
00576 
00577 void Solver::updateInterfaceColorForFluid
00578                 (
00579                     const int _fluidId,
00580                     const ngl::Real _color
00581                 )
00582 {
00583     //loop for particles of the concerned fluid
00584     for (int i = 0; i < m_particleList.size(); ++i)
00585     {
00586         if (getFluidIdFromName(m_particleList[i].getName()) == _fluidId)
00587         {
00588             //found particles of the concerned fluid -> update it
00589             m_particleList[i].setInterfaceColorCoefficient(_color);
00590         }
00591     }
00592 
00593     m_hoseParticlePrototypeList[_fluidId].setInterfaceColorCoefficient(_color);
00594 }
00595 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator