Lagrangian Liquid Simulation
Master Thesis project on simulation of liquids using Lagrangian approach and SPH
|
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