Grid3D.cpp

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 #include <iostream>
00026 #include <sofa/component/behaviormodel/eulerianfluid/Grid3D.h>
00027 #include <cstring>
00028 
00029 namespace sofa
00030 {
00031 
00032 namespace component
00033 {
00034 
00035 namespace behaviormodel
00036 {
00037 
00038 namespace eulerianfluid
00039 {
00040 
00041 const unsigned long* Grid3D::obstacles = NULL;
00042 
00043 #define LEVELSET_MARGIN 0.01f
00044 
00045 // For loop macros
00046 
00047 #define FOR_ALL_CELLS(grid,cmd)                 \
00048 {                                               \
00049   int ind = index(0,0,0);                       \
00050   for (int z=0;z<nz;z++)                        \
00051     for (int y=0;y<ny;y++)                      \
00052       for (int x=0;x<nx;x++,ind+=index(1,0,0))  \
00053       {                                         \
00054     cmd;                                    \
00055       }                                         \
00056 }
00057 
00058 #define FOR_READ_INNER_CELLS(cmd)               \
00059 {                                               \
00060   int ind = index(1,1,1);                       \
00061   for (int z=1;z<nz-1;z++,ind+=index(0,2,0))    \
00062     for (int y=1;y<ny-1;y++,ind+=index(2,0,0))  \
00063       for (int x=1;x<nx-1;x++,ind+=index(1,0,0))\
00064       {                                         \
00065     cmd;                                    \
00066       }                                         \
00067 }
00068 
00069 #define FOR_INNER_CELLS(grid,cmd)               \
00070 {                                               \
00071   int ind = index(1,1,1);                       \
00072   for (int z=1;z<nz-1;z++,ind+=index(0,2,0))    \
00073     for (int y=1;y<ny-1;y++,ind+=index(2,0,0))  \
00074       for (int x=1;x<nx-1;x++,ind+=index(1,0,0))\
00075       {                                         \
00076     cmd;                                    \
00077       }                                         \
00078 }
00079 
00080 // Surface cells  are inner  cells and borders  between a  fluid inner
00081 // cell and an empty out cell (right or bottom side)
00082 
00083 #define FOR_SURFACE_CELLS(grid,cmd)             \
00084 {                                               \
00085   int ind = index(1,1,1);                       \
00086   for (int z=1;z<nz-1;z++,ind+=index(0,2,0))    \
00087     for (int y=1;y<ny-1;y++,ind+=index(2,0,0))  \
00088       for (int x=1;x<nx-1;x++,ind+=index(1,0,0))\
00089       {                                         \
00090     cmd;                                    \
00091       }                                         \
00092 }
00093 
00094 Grid3D::Grid3D()
00095 : nx(0), ny(0), nz(0), nxny(0), ncell(0),
00096   fdata(NULL), pressure(NULL), levelset(NULL),
00097   t(0), tend(60),
00098   max_pressure(0.0),
00099   gravity(0,-5,0),
00100   fmm_status(NULL),
00101   fmm_heap(NULL),
00102   fmm_heap_size(0)
00103 {
00104   bcell.u.clear();
00105   bcell.type=-1;
00106 }
00107 
00108 Grid3D::~Grid3D()
00109 {
00110   if (fdata!=NULL) delete[] fdata;
00111   if (pressure!=NULL) delete[] pressure;
00112   if (levelset!=NULL) delete[] levelset;
00113   if (fmm_status!=NULL) delete[] fmm_status;
00114   if (fmm_heap!=NULL) delete[] fmm_heap;
00115 }
00116 
00117 void Grid3D::clear(int _nx, int _ny, int _nz)
00118 {
00119     t = 0;
00120     tend = 40;
00121     
00122     int old_ncell=ncell;
00123     nx=_nx; ny=_ny; nz=_nz;
00124     nxny = nx*ny; ncell = nxny*nz;
00125     
00126     if (ncell != old_ncell)
00127     {
00128         if (fdata!=NULL) delete[] fdata;
00129         if (ncell>0)  fdata = new Cell[ncell];
00130         else          fdata = NULL;
00131         if (pressure!=NULL) delete[] pressure;
00132         if (ncell>0)  pressure = new real[ncell];
00133         else          pressure = NULL;
00134         if (levelset!=NULL) delete[] levelset;
00135         if (ncell>0)  levelset = new real[ncell];
00136         else          levelset = NULL;
00137         if (fmm_status!=NULL) delete[] fmm_status;
00138         if (ncell>0)  fmm_status = new int[ncell];
00139         else          fmm_status = NULL;
00140         if (fmm_heap!=NULL) delete[] fmm_heap;
00141         if (ncell>0)  fmm_heap = new int[ncell];
00142         else          fmm_heap = NULL;
00143     }
00144     if (ncell>0)
00145         memset(fdata,0,ncell*sizeof(Cell));
00146     if (ncell>0)
00147         memset(pressure,0,ncell*sizeof(real));
00148     if (ncell>0)
00149         memset(levelset,0,ncell*sizeof(real));
00150 }
00151 
00152 void Grid3D::seed(real height)
00153 {
00154     //seed(vec3(0,0,0), vec3(nx,height,nz));
00155     FOR_ALL_CELLS(fdata,
00156     {
00157         real d = y - height;
00158         levelset[ind] = d;
00159     });
00160 }
00161 
00162 void Grid3D::seed(real height, vec3 normal)
00163 {
00164     normal.normalize();
00165     FOR_ALL_CELLS(fdata,
00166     {
00167         real d = vec3((real)x,(real)y,(real)z)*normal - height;
00168         levelset[ind] = d;
00169     });
00170 }
00171 
00172 void Grid3D::seed(vec3 p0, vec3 p1, vec3 velocity)
00173 {
00174     if (p0[0]<0.5f) p0[0]=0.5f;
00175     if (p0[1]<0.5f) p0[1]=0.5f;
00176     if (p0[2]<0.5f) p0[2]=0.5f;
00177     if (p1[0]>nx-1.5f) p1[0]=nx-1.5f;
00178     if (p1[1]>ny-1.5f) p1[1]=ny-1.5f;
00179     if (p1[2]>nz-1.5f) p1[2]=nz-1.5f;
00180     if (p0[0]>=p1[0]) return;
00181     if (p0[1]>=p1[1]) return;
00182     if (p0[2]>=p1[2]) return;
00183     std::cout << "p0="<<p0<<" p1="<<p1<<std::endl;
00184     vec3 center = (p0+p1)*0.5f;
00185     vec3 dim = (p1-p0)*0.5f;
00186     FOR_ALL_CELLS(fdata,
00187     {
00188         vec3 v ((real)x,(real)y,(real)z);
00189         v -= center;
00190         v[0] = rabs(v[0]) - dim[0];
00191         v[1] = rabs(v[1]) - dim[1];
00192         v[2] = rabs(v[2]) - dim[2];
00193         real d;
00194         if (v[0] <= 0 && v[1] <= 0 && v[2] <= 0)
00195         {
00196             d = rmax(v[0],rmax(v[1],v[2]));
00197             fdata[ind].u = velocity;
00198         }
00199         else
00200         {
00201             if (v[0] < 0) v[0] = 0;
00202             if (v[1] < 0) v[1] = 0;
00203             if (v[2] < 0) v[2] = 0;
00204             d = v.norm();
00205         }
00206         levelset[ind] = d;
00207     });
00208 }
00209 
00210 void Grid3D::step(Grid3D* prev, Grid3D* temp, real dt, real diff)
00211 {
00212     t = prev->t+dt;
00213     tend = prev->tend;
00214     //std::cout << "STEP\n";
00215     
00216     //clear(prev->nx, prev->ny, prev->nz);
00217     //temp->clear(prev->nx, prev->ny, prev->nz);
00218     
00219     step_init(prev, temp, dt, diff);      // init fluid obstacles
00220     //step_particles(prev, temp, dt, diff); // init particles
00221     //step_levelset(prev, temp, dt, diff); // advance levelset
00222     step_forces(prev, temp, dt, diff);    // init fluid u with prev u, particles and gravity
00223     step_surface(prev, temp, dt, diff);   // calc fluid u at air/fluid surfaces
00224     step_advect(prev, temp, dt, diff);    // advance fluid u to temp u
00225     step_diffuse(prev, temp, dt, diff);   // calc diffusion of temp u to fluid u
00226     step_project(prev, temp, dt, diff);   // calc pressure and project fluid u to divergent free field. use temp as temporary scalar fields
00227     step_levelset(prev, temp, dt, diff); // advance levelset
00228     
00229     // And that should be it!
00230     
00231     //std::cout << "STEP: Done!\n";
00232 }
00233 
00236 
00237 void Grid3D::step_init(const Grid3D* prev, Grid3D* /*temp*/, real /*dt*/, real /*diff*/)
00238 {
00239     //std::cout << "STEP: Obstacles\n";
00240     // Currently: only borders are obstacle
00241 
00242     int bsize = 1;
00243     //  int x0 = nx/2-2;
00244     //  int x1 = x0+4;
00245     //  int y0 = ny/2-2;
00246     //  int y1 = y0+4;
00247     
00248     const unsigned char* obs = (const unsigned char*)obstacles;
00249     int lnsize = (nx+7)/8;
00250     int plsize = lnsize*ny;
00251     
00252     //memset(fdata,0,ncell*sizeof(Cell));
00253     
00254     FOR_ALL_CELLS(fdata,
00255     {
00256         //levelset[ind] = 5;
00257         levelset[ind] = prev->levelset[ind];
00258         if (x<bsize || y<bsize || z<bsize || x>=nx-bsize || y>=ny-bsize || z>=nz-bsize
00259         //    || (x>=x0 && x<x1 && y>=y0 && y<y1)
00260             || (obs!=NULL && ((obs[(z)*plsize+(y)*lnsize+((x)>>3)])&(1<<((x)&7))))
00261             ) // || z==nz-1)
00262         {
00263             fdata[ind].type = PART_WALL;
00264         }
00265         else
00266         {
00267             if (levelset[ind] < LEVELSET_MARGIN)
00268                 fdata[ind].type = PART_FULL;
00269             else
00270                 fdata[ind].type = PART_EMPTY;
00271         }
00272     });
00273 }
00274 
00277 
00278 #define RMAX 1e10
00279 
00280 void Grid3D::step_levelset(Grid3D* prev, Grid3D* temp, real dt, real /*diff*/)
00281 {
00282 //    std::cout << "STEP: levelset\n";
00283 
00284     // advect levelset into temp
00285     
00286     // Modified Eulerian / Midpoint method
00287     // Carlson Thesis page 22
00288 
00289     FOR_INNER_CELLS(levelset,
00290     {
00291         //if (prev->fdata[ind].type != PART_WALL && rabs(prev->levelset[ind]) < 5)
00292         if (rabs(prev->levelset[ind]) < 5)
00293         {
00294             vec3 xn ( (real)x, (real)y, (real)z );
00295             //vec3 un = prev->interp(xn);
00296             vec3 un = interp(xn);
00297             vec3 xn1 = xn - un*dt; // xn1_2 at this time
00298 
00299             // TODO: Check if xn1_2 is not in empty cell
00300             //un = (un + prev->interp(xn1))*0.5;
00301             un = (un + interp(xn1))*0.5;
00302             xn1 = xn - un*dt;
00303             
00304             temp->levelset[ind] = prev->getlevelset(xn1);
00305         }
00306         else
00307             temp->levelset[ind] = prev->levelset[ind];
00308     });
00309 
00310     // fill border levelset using neighbors
00311 
00312     FOR_ALL_CELLS(fmm_status,
00313     {
00314         fmm_status[ind] = FMM_FAR;
00315         if (fdata[ind].type == PART_WALL)
00316         {
00317             // find a neighbor cell
00318             real phi = 0;
00319             int n = 0;
00320             for (int dz=-1;dz<=1;dz++)
00321                 if ((unsigned)(z+dz)<(unsigned)nz)
00322                     for (int dy=-1;dy<=1;dy++)
00323                         if ((unsigned)(y+dy)<(unsigned)ny)
00324                             for (int dx=-1;dx<=1;dx++)
00325                                 if ((unsigned)(x+dx)<(unsigned)nx)
00326                                 {
00327                                     int ind2 = ind+index(dx,dy,dz);
00328                                     if (fdata[ind2].type != PART_WALL)
00329                                     {
00330                                         phi += temp->levelset[ind2];
00331                                         ++n;
00332                                     }
00333                                 }
00334             temp->levelset[ind] = phi/n;
00335         }
00336     });
00337     
00338     // Levelset Reinitilization using Fast Marching Method
00339     //TODO do not reinit at every steps
00340     
00341     fmm_heap_size = 0;
00342     const int cmax[3] = { nx-1, ny-1, nz-1 };
00343     const int dind[3] = { 1, nx, nxny };
00344 
00345     // Compute all known points
00346     FOR_ALL_CELLS(fdata,
00347     {
00348         int c[3]; c[0] = x; c[1] = y; c[2] = z;
00349         bool known = false;
00350         real phi0 = temp->levelset[ind];
00351         real inv_dist2 = 0;
00352         for (int dim = 0; dim < 3; dim++)
00353         {
00354             real dist = RMAX;
00355             bool border = false;
00356             if (c[dim]>0)
00357             {
00358                 real phi1 = temp->levelset[ind-dind[dim]];
00359                 if (phi1*phi0 < 0)
00360                 {
00361                     dist = phi0/(phi0-phi1);
00362                     border = true;
00363                 }
00364             }
00365             if (c[dim]<cmax[dim])
00366             {
00367                 real phi1 = temp->levelset[ind+dind[dim]];
00368                 if (phi1*phi0 < 0)
00369                 {
00370                     real d = phi0/(phi0-phi1);
00371                     if (d < dist) dist = d;
00372                     border = true;
00373                 }
00374             }
00375             if (border)
00376             {
00377                 known = true;
00378                 inv_dist2 += 1 / (dist*dist);
00379             }
00380         }
00381         if (known)
00382         {
00383             //real phi = 1 / sqrt(inv_dist2);
00384             real phi = rabs(phi0);
00385             levelset[ind] = phi;
00386             fmm_status[ind] = FMM_KNOWN;
00387         }
00388         else
00389         {
00390             levelset[ind] = 5; //RMAX;
00391             fmm_status[ind] = FMM_FAR;
00392         }
00393     });
00394 
00395     // Update known points neighbors
00396     FOR_ALL_CELLS(fdata,
00397     {
00398         if (fmm_status[ind] == FMM_KNOWN)
00399         {
00400             int c[3]; c[0] = x; c[1] = y; c[2] = z;
00401             real phi1 = levelset[ind];
00402             phi1+=1;
00403             for (int dim = 0; dim < 3; dim++)
00404             {
00405                 if (c[dim]>0)
00406                 {
00407                     int ind2 = ind-dind[dim];
00408                     if (fmm_status[ind2] >= FMM_FAR)
00409                     {
00410                         real phi2 = levelset[ind2];
00411                         if ((phi1) < (phi2))
00412                         {
00413                             levelset[ind2] = phi1;
00414                             fmm_push(ind2); // create or update the corresponding entry in the heap
00415                         }
00416                     }
00417                 }
00418                 if (c[dim]<cmax[dim])
00419                 {
00420                     int ind2 = ind+dind[dim];
00421                     if (fmm_status[ind2] >= FMM_FAR)
00422                     {
00423                         real phi2 = levelset[ind2];
00424                         if ((phi1) < (phi2))
00425                         {
00426                             levelset[ind2] = phi1;
00427                             fmm_push(ind2); // create or update the corresponding entry in the heap
00428                         }
00429                     }
00430                 }
00431             }
00432         }
00433     });
00434     
00435     while (fmm_heap_size > 0)
00436     {
00437         int ind = fmm_pop();
00438         real phi1 = levelset[ind]+1;
00439         if ((phi1) >= 5) break;
00440         int c[3] = { ind % nx, (ind / nx) % ny, ind / nxny };
00441         for (int dim = 0; dim < 3; dim++)
00442         {
00443             if (c[dim]>0)
00444             {
00445                 int ind2 = ind-dind[dim];
00446                 if (fmm_status[ind2] >= FMM_FAR)
00447                 {
00448                     real phi2 = levelset[ind2];
00449                     if ((phi1) < (phi2))
00450                     {
00451                         levelset[ind2] = phi1;
00452                         fmm_push(ind2); // create or update the corresponding entry in the heap
00453                     }
00454                 }
00455             }
00456             if (c[dim]<cmax[dim])
00457             {
00458                 int ind2 = ind+dind[dim];
00459                 if (fmm_status[ind2] >= FMM_FAR)
00460                 {
00461                     real phi2 = levelset[ind2];
00462                     if ((phi1) < (phi2))
00463                     {
00464                         levelset[ind2] = phi1;
00465                         fmm_push(ind2); // create or update the corresponding entry in the heap
00466                     }
00467                 }
00468             }
00469         }
00470     }
00471 
00472     FOR_ALL_CELLS(levelset,
00473     {
00474         if(temp->levelset[ind] < 0)
00475         {
00476             levelset[ind] = -levelset[ind];
00477         }
00478         if (levelset[ind] < LEVELSET_MARGIN)
00479     {
00480       if (fdata[ind].type == PART_EMPTY)
00481             fdata[ind].type = PART_FULL;
00482     }
00483         else
00484         {
00485             if (fdata[ind].type == PART_FULL)
00486                 fdata[ind].type = PART_EMPTY;
00487         }
00488     });
00489 }
00490 
00491 inline void Grid3D::fmm_swap(int entry1, int entry2)
00492 {
00493     int ind1 = fmm_heap[entry1];
00494     int ind2 = fmm_heap[entry2];
00495     fmm_heap[entry1] = ind2;
00496     fmm_heap[entry2] = ind1;
00497     fmm_status[ind1] = entry2 + FMM_FRONT0;
00498     fmm_status[ind2] = entry1 + FMM_FRONT0;
00499 }
00500 
00501 int Grid3D::fmm_pop()
00502 {
00503     int res = fmm_heap[0];
00504 #ifdef FMM_VERBOSE
00505     std::cout << "fmm_pop -> <"<<(res%nx)<<','<<((res/nx)%ny)<<','<<(res/nxny)<<">="<<levelset[res]<<std::endl;
00506 #endif
00507     --fmm_heap_size;
00508     if (fmm_heap_size>0)
00509     {
00510         fmm_swap(0, fmm_heap_size);
00511         int i=0;
00512         real phi = (levelset[fmm_heap[i]]);
00513         while (i*2+1 < fmm_heap_size)
00514         {
00515             real phi1 = (levelset[fmm_heap[i*2+1]]);
00516             if (i*2+2 < fmm_heap_size)
00517             {
00518                 real phi2 = (levelset[fmm_heap[i*2+2]]);
00519                 if (phi1 < phi)
00520                 {
00521                     if (phi1 < phi2)
00522                     {
00523                         fmm_swap(i, i*2+1);
00524                         i = i*2+1;
00525                     }
00526                     else
00527                     {
00528                         fmm_swap(i, i*2+2);
00529                         i = i*2+2;
00530                     }
00531                 }
00532                 else if (phi2 < phi)
00533                 {
00534                     fmm_swap(i, i*2+2);
00535                     i = i*2+2;
00536                 }
00537                 else break;
00538             }
00539             else if (phi1 < phi)
00540             {
00541                 fmm_swap(i, i*2+1);
00542                 i = i*2+1;
00543             }
00544             else break;
00545         }
00546     }
00547 #ifdef FMM_VERBOSE
00548     std::cout << "fmm_heap = [";
00549     for (int i=0;i<fmm_heap_size;i++)
00550         std::cout << " <"<<(fmm_heap[i]%nx)<<','<<((fmm_heap[i]/nx)%ny)<<','<<(fmm_heap[i]/nxny)<<">="<<levelset[fmm_heap[i]];
00551     std::cout << std::endl;
00552 #endif
00553     fmm_status[res] = FMM_KNOWN;
00554     return res;
00555 }
00556 
00557 void Grid3D::fmm_push(int index)
00558 {
00559     real phi = (levelset[index]);
00560     int i;
00561     if (fmm_status[index] >= FMM_FRONT0)
00562     {
00563         i = fmm_status[index] - FMM_FRONT0;
00564 #ifdef FMM_VERBOSE
00565         std::cout << "fmm update <"<<(index%nx)<<','<<((index/nx)%ny)<<','<<(index/nxny)<<">="<<levelset[index]<<" from entry "<<i<<std::endl;
00566 #endif
00567         while (i>0 && phi < (levelset[fmm_heap[(i-1)/2]]))
00568         {
00569             fmm_swap(i,(i-1)/2);
00570             i = (i-1)/2;
00571         }
00572         while (i*2+1 < fmm_heap_size)
00573         {
00574             real phi1 = (levelset[fmm_heap[i*2+1]]);
00575             if (i*2+2 < fmm_heap_size)
00576             {
00577                 real phi2 = (levelset[fmm_heap[i*2+2]]);
00578                 if (phi1 < phi)
00579                 {
00580                     if (phi1 < phi2)
00581                     {
00582                         fmm_swap(i, i*2+1);
00583                         i = i*2+1;
00584                     }
00585                     else
00586                     {
00587                         fmm_swap(i, i*2+2);
00588                         i = i*2+2;
00589                     }
00590                 }
00591                 else if (phi2 < phi)
00592                 {
00593                     fmm_swap(i, i*2+2);
00594                     i = i*2+2;
00595                 }
00596                 else break;
00597             }
00598             else if (phi1 < phi)
00599             {
00600                 fmm_swap(i, i*2+1);
00601                 i = i*2+1;
00602             }
00603             else break;
00604         }
00605     }
00606     else
00607     {
00608 #ifdef FMM_VERBOSE
00609         std::cout << "fmm push <"<<(index%nx)<<','<<((index/nx)%ny)<<','<<(index/nxny)<<">="<<levelset[index]<<std::endl;
00610 #endif
00611         i = fmm_heap_size;
00612         ++fmm_heap_size;
00613         fmm_heap[i] = index;
00614         fmm_status[index] = i;
00615         while (i>0 && phi < (levelset[fmm_heap[(i-1)/2]]))
00616         {
00617             fmm_swap(i,(i-1)/2);
00618             i = (i-1)/2;
00619         }
00620     }
00621 #ifdef FMM_VERBOSE
00622     std::cout << "fmm_heap = [";
00623     for (int i=0;i<fmm_heap_size;i++)
00624         std::cout << " <"<<(fmm_heap[i]%nx)<<','<<((fmm_heap[i]/nx)%ny)<<','<<(fmm_heap[i]/nxny)<<">="<<levelset[fmm_heap[i]];
00625     std::cout << std::endl;
00626 #endif
00627 }
00628 
00633 
00634 void Grid3D::step_forces(const Grid3D* prev, Grid3D* /*temp*/, real dt, real /*diff*/, real /*scale*/)
00635 {
00636     //  std::cout << "STEP: Boundary and Forces\n";
00637     // Solid immovable obstacles set all velocity inside and touching them to 0
00638     // (free-slip condition)
00639     // Carlson Thesis page 23
00640     
00641     //vec3 f(0,0,-9.81*dt/scale);
00642     vec3 f = gravity * dt; //(0,-5*dt,0);
00643     
00644     FOR_INNER_CELLS(fdata,
00645     {
00646         vec3 u = f;
00647         int p0 = fdata[ind].type;
00648         if (p0 < 0)
00649         u.clear();
00650         else
00651         { // not an obstacle
00652             int p1;
00653             // X Axis
00654             p1 = fdata[ind+index(-1,0,0)].type;
00655             if (p1>=0 && p0+p1>0) // this face is now in the fluid
00656             {
00657                 //if (prev->fdata[ind].type>0 && prev->fdata[ind+index(-1,0,0)].type>0)
00658                 u[0] += prev->fdata[ind].u[0]; // was in the fluid in previous step
00659                 //else // find the best velocity from particles
00660                 //  u[0] += find_velocity<0>(x,y,z,ind,ind+index(-1,0,0),prev,temp);
00661             }
00662             else //if (p1<0)
00663                 u[0] = 0; // Obstacle
00664             // Y Axis
00665             p1 = fdata[ind+index(0,-1,0)].type;
00666             if (p1>=0 && p0+p1>0) // this face is now in the fluid
00667             {
00668                 //if (prev->fdata[ind].type>0 && prev->fdata[ind+index(0,-1,0)].type>0)
00669                 u[1] += prev->fdata[ind].u[1]; // was in the fluid in previous step
00670                 //else // find the best velocity from particles
00671                 //  u[1] += find_velocity<1>(x,y,z,ind,ind+index(0,-1,0),prev,temp);
00672             }
00673             else //if (p1<0)
00674                 u[1] = 0; // Obstacle
00675             // Z Axis
00676             p1 = fdata[ind+index(0,0,-1)].type;
00677             if (p1>=0 && p0+p1>0) // this face is now in the fluid
00678             {
00679                 //if (prev->fdata[ind].type>0 && prev->fdata[ind+index(0,0,-1)].type>0)
00680                 u[2] += prev->fdata[ind].u[2]; // was in the fluid in previous step
00681                 //else // find the best velocity from particles
00682                 //  u[2] += find_velocity<2>(x,y,z,ind,ind+index(0,0,-1),prev,temp);
00683             }
00684             else //if (p1<0)
00685                 u[2] = 0; // Obstacle
00686         }
00687         fdata[ind].u = u;
00688     });
00689     
00690     //std::cout << "t="<<t<<" tend="<<tend<<std::endl;
00691     
00692     if (t > 0 && t < tend)
00693     {
00694         float f = 2*t;
00695         srand(*(const unsigned int*)(const void*)&f);
00696         vec3 v(4,0,-4);
00697         int cx = 1*nz/4; //-Gx0;
00698         int cy = 3*ny/4; //-Gx0;
00699         int cz = 3*nz/4; //-Gz0;
00700         real r = nz/8.0f;
00701         if (t < 1) r *= t;
00702         else if (t>tend-1) r*= tend-t;
00703         int ir = rceil(r)+5;
00704         //real r2=r*r;
00705     
00706         //real cr = (t+0)/3; cr = rabs(cr-rnear(cr))*2;
00707         //real cg = (t+1)/3; cg = rabs(cg-rnear(cg))*2;
00708         //real cb = (t+2)/3; cb = rabs(cb-rnear(cb))*2;
00709         //real cr = (t+2.5)/3; cr = rmax(0.0f,rabs(cr-rnear(cr))*3-0.5f);
00710         //real cg = (t    )/3; cg = rmin(1.0f,rabs(cg-rnear(cg))*3);
00711         //real cb = 1;
00712     
00713         for (int z=cz-ir;z<=cz+ir;z++)
00714             if ((unsigned)z<(unsigned)nz)
00715                 for (int y=cy-ir;y<=cy+ir;y++)
00716                     if ((unsigned)y<(unsigned)ny)
00717                         for (int x=cx-ir;x<=cx+ir;x++)
00718                         {
00719                             real d = sqrtf((real)((z-cz)*(z-cz)+(y-cy)*(y-cy)+(x-cx)*(x-cx))) - r;
00720                             int ind = index(x,y,z);
00721                             if (d < LEVELSET_MARGIN)
00722                             {
00723                                 fdata[ind].u = v;
00724                                 if (fdata[ind].type == PART_EMPTY)
00725                                     fdata[ind].type = PART_FULL;
00726                             }
00727                             if (d < levelset[ind])
00728                                 levelset[ind] = d;
00729                         }
00730     }
00731 }
00732 
00735 
00736 void Grid3D::step_surface(const Grid3D* /*prev*/, Grid3D* /*temp*/, real /*dt*/, real /*diff*/)
00737 {
00738     //  std::cout << "STEP: Surfaces\n";
00739     // Boundary conditions are not trivial...
00740     // Carlson Thesis page 24-28
00741     
00742     enum {
00743         FACE_X0=1<<0,
00744         FACE_X1=1<<1,
00745         FACE_Y0=1<<2,
00746         FACE_Y1=1<<3,
00747         FACE_Z0=1<<4,
00748         FACE_Z1=1<<5,
00749     };
00750     
00751     FOR_SURFACE_CELLS(fdata,
00752     {
00753         if (fdata[ind].type>0)
00754         {
00755             // get face air bitmask
00756             int mask = 0;
00757             if (fdata[ind+index(-1,0,0)].type==0) mask|=FACE_X0;
00758             if (fdata[ind+index( 1,0,0)].type==0) mask|=FACE_X1;
00759             if (fdata[ind+index(0,-1,0)].type==0) mask|=FACE_Y0;
00760             if (fdata[ind+index(0, 1,0)].type==0) mask|=FACE_Y1;
00761             if (fdata[ind+index(0,0,-1)].type==0) mask|=FACE_Z0;
00762             if (fdata[ind+index(0,0, 1)].type==0) mask|=FACE_Z1;
00763             if (mask!=0)
00764             {
00765                 real& x0 = fdata[ind].u[0];
00766                 real& y0 = fdata[ind].u[1];
00767                 real& z0 = fdata[ind].u[2];
00768                 real& x1 = fdata[ind+index( 1,0,0)].u[0];
00769                 real& y1 = fdata[ind+index(0, 1,0)].u[1];
00770                 real& z1 = fdata[ind+index(0,0, 1)].u[2];
00771                 real r;
00772                 // Continuity condition: x1-x0+y1-y0+z1-z0 = 0
00773                 switch (mask)
00774                 { // 63 cases...
00775                     
00776                     // 1 face: add the other values
00777                     case FACE_X0: x0 = x1   +y1-y0+z1-z0; break;
00778                     case FACE_X1: x1 = x0   +y0-y1+z0-z1; break;
00779                     case FACE_Y0: y0 = x1-x0+y1   +z1-z0; break;
00780                     case FACE_Y1: y1 = x0-x1+y0   +z0-z1; break;
00781                     case FACE_Z0: z0 = x1-x0+y1-y0+z1   ; break;
00782                     case FACE_Z1: z1 = x0-x1+y0-y1+z0   ; break;
00783             
00784                     // 2 faces: weaker condition x1=x0 y1=y0 z1=z0
00785                     // opposite faces -> do nothing
00786                     case FACE_X0|FACE_X1: break;
00787                     case FACE_Y0|FACE_Y1: break;
00788                     case FACE_Z0|FACE_Z1: break;
00789                     // other cases: copy opposite value and add half the difference of the remaining two faces
00790                     case FACE_X0|FACE_Y0: r = (z1-z0)*0.5f;  x0 = x1+r;  y0 = y1+r; break;
00791                     case FACE_X0|FACE_Y1: r = (z1-z0)*0.5f;  x0 = x1+r;  y1 = y0-r; break;
00792                     case FACE_X0|FACE_Z0: r = (y1-y0)*0.5f;  x0 = x1+r;  z0 = z1+r; break;
00793                     case FACE_X0|FACE_Z1: r = (y1-y0)*0.5f;  x0 = x1+r;  z1 = z0-r; break;
00794                     case FACE_X1|FACE_Y0: r = (z1-z0)*0.5f;  x1 = x0-r;  y0 = y1+r; break;
00795                     case FACE_X1|FACE_Y1: r = (z1-z0)*0.5f;  x1 = x0-r;  y1 = y0-r; break;
00796                     case FACE_X1|FACE_Z0: r = (y1-y0)*0.5f;  x1 = x0-r;  z0 = z1+r; break;
00797                     case FACE_X1|FACE_Z1: r = (y1-y0)*0.5f;  x1 = x0-r;  z1 = z0-r; break;
00798                     case FACE_Y0|FACE_Z0: r = (x1-x0)*0.5f;  y0 = y1+r;  z0 = z1+r; break;
00799                     case FACE_Y0|FACE_Z1: r = (x1-x0)*0.5f;  y0 = y1+r;  z1 = z0-r; break;
00800                     case FACE_Y1|FACE_Z0: r = (x1-x0)*0.5f;  y1 = y0-r;  z0 = z1+r; break;
00801                     case FACE_Y1|FACE_Z1: r = (x1-x0)*0.5f;  y1 = y0-r;  z1 = z0-r; break;
00802                     
00803                     // 3 faces with no opposite face: copy other 3 values
00804                     case FACE_X0|FACE_Y0|FACE_Z0: x0 = x1;  y0 = y1;  z0 = z1; break;
00805                     case FACE_X1|FACE_Y0|FACE_Z0: x1 = x0;  y0 = y1;  z0 = z1; break;
00806                     case FACE_X0|FACE_Y1|FACE_Z0: x0 = x1;  y1 = y0;  z0 = z1; break;
00807                     case FACE_X1|FACE_Y1|FACE_Z0: x1 = x0;  y1 = y0;  z0 = z1; break;
00808                     case FACE_X0|FACE_Y0|FACE_Z1: x0 = x1;  y0 = y1;  z1 = z0; break;
00809                     case FACE_X1|FACE_Y0|FACE_Z1: x1 = x0;  y0 = y1;  z1 = z0; break;
00810                     case FACE_X0|FACE_Y1|FACE_Z1: x0 = x1;  y1 = y0;  z1 = z0; break;
00811                     case FACE_X1|FACE_Y1|FACE_Z1: x1 = x0;  y1 = y0;  z1 = z0; break;
00812                     // 3 faces with one opposite pair: ignore the pair and resolve the remaining one
00813                     case FACE_X0|FACE_Y0|FACE_Y1: x0 = x1   +y1-y0+z1-z0; break;
00814                     case FACE_X0|FACE_Z0|FACE_Z1: x0 = x1   +y1-y0+z1-z0; break;
00815                     case FACE_X1|FACE_Y0|FACE_Y1: x1 = x0   +y0-y1+z0-z1; break;
00816                     case FACE_X1|FACE_Z0|FACE_Z1: x1 = x0   +y0-y1+z0-z1; break;
00817                     case FACE_Y0|FACE_X0|FACE_X1: y0 = x1-x0+y1   +z1-z0; break;
00818                     case FACE_Y0|FACE_Z0|FACE_Z1: y0 = x1-x0+y1   +z1-z0; break;
00819                     case FACE_Y1|FACE_X0|FACE_X1: y1 = x0-x1+y0   +z0-z1; break;
00820                     case FACE_Y1|FACE_Z0|FACE_Z1: y1 = x0-x1+y0   +z0-z1; break;
00821                     case FACE_Z0|FACE_Y0|FACE_Y1: z0 = x1-x0+y1-y0+z1   ; break;
00822                     case FACE_Z0|FACE_X0|FACE_X1: z0 = x1-x0+y1-y0+z1   ; break;
00823                     case FACE_Z1|FACE_Y0|FACE_Y1: z1 = x0-x1+y0-y1+z0   ; break;
00824                     case FACE_Z1|FACE_X0|FACE_X1: z1 = x0-x1+y0-y1+z0   ; break;
00825                     
00826                     // 4 faces opposing each other: add a quarter of the difference of the remaining two faces
00827                     case FACE_X0|FACE_X1|FACE_Y0|FACE_Y1: r = ( z1-z0)*0.25f;  x0 = r;  x1 = -r;  y0 = r;  y1 = -r; break;
00828                     case FACE_X0|FACE_X1|FACE_Z0|FACE_Z1: r = ( z1-z0)*0.25f;  x0 = r;  x1 = -r;  z0 = r;  z1 = -r; break;
00829                     case FACE_Y0|FACE_Y1|FACE_Z0|FACE_Z1: r = ( z1-z0)*0.25f;  y0 = r;  y1 = -r;  y0 = r;  y1 = -r; break;
00830                     // other cases: copy opposite values to the two faces not opposing each other split the difference of the remaining faces
00831                     case FACE_X0|FACE_X1|FACE_Y0|FACE_Z0: y0 = y1; z0 = z1;  r = ( y1+z1)*0.5f;  x0 = r; x1 = r; break;
00832                     case FACE_X0|FACE_X1|FACE_Y1|FACE_Z0: y1 = y0; z0 = z1;  r = (-y0+z1)*0.5f;  x0 = r; x1 = r; break;
00833                     case FACE_X0|FACE_X1|FACE_Y0|FACE_Z1: y0 = y1; z1 = z0;  r = ( y1-z0)*0.5f;  x0 = r; x1 = r; break;
00834                     case FACE_X0|FACE_X1|FACE_Y1|FACE_Z1: y1 = y0; z1 = z0;  r = (-y0-z0)*0.5f;  x0 = r; x1 = r; break;
00835                     case FACE_Y0|FACE_Y1|FACE_X0|FACE_Z0: x0 = x1; z0 = z1;  r = ( x1+z1)*0.5f;  y0 = r; y1 = r; break;
00836                     case FACE_Y0|FACE_Y1|FACE_X1|FACE_Z0: x1 = x0; z0 = z1;  r = (-x0+z1)*0.5f;  y0 = r; y1 = r; break;
00837                     case FACE_Y0|FACE_Y1|FACE_X0|FACE_Z1: x0 = x1; z1 = z0;  r = ( x1-z0)*0.5f;  y0 = r; y1 = r; break;
00838                     case FACE_Y0|FACE_Y1|FACE_X1|FACE_Z1: x1 = x0; z1 = z0;  r = (-x0-z0)*0.5f;  y0 = r; y1 = r; break;
00839                     case FACE_Z0|FACE_Z1|FACE_Y0|FACE_X0: y0 = y1; x0 = x1;  r = ( y1+x1)*0.5f;  z0 = r; z1 = r; break;
00840                     case FACE_Z0|FACE_Z1|FACE_Y1|FACE_X0: y1 = y0; x0 = x1;  r = (-y0+x1)*0.5f;  z0 = r; z1 = r; break;
00841                     case FACE_Z0|FACE_Z1|FACE_Y0|FACE_X1: y0 = y1; x1 = x0;  r = ( y1-x0)*0.5f;  z0 = r; z1 = r; break;
00842                     case FACE_Z0|FACE_Z1|FACE_Y1|FACE_X1: y1 = y0; x1 = x0;  r = (-y0-x0)*0.5f;  z0 = r; z1 = r; break;
00843                     
00844                     // 5 faces: solve for the face with no opposite face
00845                     case         FACE_X1|FACE_Y0|FACE_Y1|FACE_Z0|FACE_Z1: x0 = x1   +y1-y0+z1-z0; break;
00846                     case FACE_X0|        FACE_Y0|FACE_Y1|FACE_Z0|FACE_Z1: x1 = x0   +y0-y1+z0-z1; break;
00847                     case FACE_X0|FACE_X1|        FACE_Y1|FACE_Z0|FACE_Z1: y0 = x1-x0+y1   +z1-z0; break;
00848                     case FACE_X0|FACE_X1|FACE_Y0|        FACE_Z0|FACE_Z1: y1 = x0-x1+y0   +z0-z1; break;
00849                     case FACE_X0|FACE_X1|FACE_Y0|FACE_Y1|        FACE_Z1: z0 = x1-x0+y1-y0+z1   ; break;
00850                     case FACE_X0|FACE_X1|FACE_Y0|FACE_Y1|FACE_Z0        : z1 = x0-x1+y0-y1+z0   ; break;
00851                     
00852                     // 6 faces: can't do anything
00853                     case FACE_X0|FACE_X1|FACE_Y0|FACE_Y1|FACE_Z0|FACE_Z1: break;
00854                     
00855                     // Done!
00856                 }
00857             }
00858         }
00859     });
00860 }
00861 
00864 
00865   // This is the real fluid simulation...
00866 
00867 void Grid3D::step_advect(const Grid3D* /*prev*/, Grid3D* temp, real dt, real /*diff*/)
00868 {
00869     //  std::cout << "STEP: Fluid Advection\n";
00870     
00871     // Calculate advection using a semi-lagrangian technique
00872     // Stam
00873     
00874     // not much optimized for now...
00875     
00876     memset(temp->fdata,0,temp->ncell*sizeof(Cell));
00877     
00878     FOR_INNER_CELLS(temp->fdata,
00879     {
00880         // X Axis
00881         vec3 px( x-0.5f - dt*(fdata[ind].u[0]),
00882                  y      - dt*0.25f*(fdata[ind].u[1]+fdata[ind+index(-1,0,0)].u[1]+fdata[ind+index(0,1,0)].u[1]+fdata[ind+index(-1,1,0)].u[1]),
00883                  z      - dt*(fdata[ind].u[2]+fdata[ind+index(-1,0,0)].u[2]+fdata[ind+index(0,0,1)].u[2]+fdata[ind+index(-1,0,1)].u[2]));
00884         temp->fdata[ind].u[0] = interp<0>(px);
00885         // Y Axis
00886         vec3 py( x      - dt*0.25f*(fdata[ind].u[0]+fdata[ind+index(0,-1,0)].u[0]+fdata[ind+index(1,0,0)].u[0]+fdata[ind+index(1,-1,0)].u[0]),
00887                  y-0.5f - dt*(fdata[ind].u[1]),
00888                  z      - dt*(fdata[ind].u[2]+fdata[ind+index(0,-1,0)].u[2]+fdata[ind+index(0,0,1)].u[2]+fdata[ind+index(0,-1,1)].u[2]));
00889         temp->fdata[ind].u[1] = interp<1>(py);
00890         // Z Axis
00891         vec3 pz( x      - dt*(fdata[ind].u[0]+fdata[ind+index(0,0,-1)].u[0]+fdata[ind+index(1,0,0)].u[0]+fdata[ind+index(1,0,-1)].u[0]),
00892                  y      - dt*0.25f*(fdata[ind].u[1]+fdata[ind+index(0,0,-1)].u[1]+fdata[ind+index(0,1,0)].u[1]+fdata[ind+index(0,1,-1)].u[1]),
00893                  z-0.5f - dt*(fdata[ind].u[2]));
00894         temp->fdata[ind].u[2] = interp<2>(pz);
00895     });
00896     // Result is now is temp
00897 }
00898 
00899 
00900 void Grid3D::step_diffuse(const Grid3D* /*prev*/, Grid3D* temp, real /*dt*/, real diff)
00901 {
00902     //  std::cout << "STEP: Fluid Diffusion\n";
00903     // Calculate diffusion back to here
00904     // TODO: Check boundary conditions
00905     
00906     if (diff==0.0f)
00907     {
00908         for (int ind=0;ind<ncell;ind++)
00909             fdata[ind].u = temp->fdata[ind].u;
00910         return;
00911     }
00912     
00913     real a = diff;
00914     real inv_c = 1.0f / (1.0001f + 6*a);
00915     
00916     FOR_INNER_CELLS(fdata,
00917     {
00918         fdata[ind].u = (temp->fdata[ind].u +
00919                        (temp->fdata[ind+index(-1,0,0)].u+temp->fdata[ind+index(1,0,0)].u+
00920                         temp->fdata[ind+index(0,-1,0)].u+temp->fdata[ind+index(0,1,0)].u+
00921                         temp->fdata[ind+index(0,0,-1)].u+temp->fdata[ind+index(0,0,1)].u
00922                        )*a)*inv_c;
00923     });
00924 }
00925 
00926 
00927 void Grid3D::step_project(const Grid3D* prev, Grid3D* temp, real dt, real /*diff*/)
00928 {
00929     //  std::cout << "STEP: Fluid Projection\n";
00930     
00931     // Finally calculate projection to divergence free velocity
00932     
00933     // u_new = u~ - dt/P Dp where P = fluid density and p = pressure, Dp = (dp/dx,dp/dy,dp/dz)
00934     // D.u_new = 0  =>  -dxDp = -P/dt dxD.u~
00935     //   where  -dxDp = 6p(i,j,k)-p(i-1,j,k)-p(i,j-1,k)-p(i,j,k-1)-p(i+1,j,k)-p(i,j+1,k)-p(i,j,k+1)
00936     //     and  -P/dt dxD.u~ = -P/dt dx ( u~(i+1,j,k) - u~(i,j,k) + v~(i,j+1,k) - v~(i,j,k) + w~(i,j,k+1) - w~(i,j,k) )
00937     // Ap = b where A is a diagonal matrix plus neighbour coefficients at -1
00938     
00939     memset(temp->fdata,0,temp->ncell*sizeof(Cell));
00940     memset(temp->pressure,0,temp->ncell*sizeof(real));
00941     
00942     real* diag = (real*)temp->fdata;
00943     real* b = diag+ncell;
00944     real* r = b+ncell;
00945     real* g = r+ncell;
00946     real* q = temp->pressure;
00947     
00948     real a = -1.0f/dt;
00949     
00950     double b_norm2 = 0.0;
00951     
00952     //  int nbdiag[7]={0,0,0,0,0,0,0};
00953     
00954     FOR_INNER_CELLS(diag,
00955     {
00956         if (fdata[ind].type>0)
00957         {
00958             real d = 6; // count air/fluid neighbours
00959             d -= ((unsigned int)fdata[ind+index(-1,0,0)].type)>>31;
00960             d -= ((unsigned int)fdata[ind+index(0,-1,0)].type)>>31;
00961             d -= ((unsigned int)fdata[ind+index(0,0,-1)].type)>>31;
00962             d -= ((unsigned int)fdata[ind+index( 1,0,0)].type)>>31;
00963             d -= ((unsigned int)fdata[ind+index(0, 1,0)].type)>>31;
00964             d -= ((unsigned int)fdata[ind+index(0,0, 1)].type)>>31;
00965             //  nbdiag[(int)d]++;
00966             diag[ind] = d;
00967         }
00968     });
00969     
00970     FOR_INNER_CELLS(b,
00971     {
00972         if (fdata[ind].type>0)
00973         {
00974             real bi = a*(fdata[ind+index(1,0,0)].u[0]-fdata[ind].u[0] + fdata[ind+index(0,1,0)].u[1]-fdata[ind].u[1] + fdata[ind+index(0,0,1)].u[2]-fdata[ind].u[2]);
00975             b[ind] = bi;
00976             b_norm2 += bi*bi;
00977         }
00978     });
00979     
00980     //  std::cout << "Proc"<<Grank<<" local b2="<<b_norm2<<std::endl;
00981     //reduceAll(1,&b_norm2);
00982     //  std::cout << "Proc"<<Grank<<" global b2="<<b_norm2<<std::endl;
00983     
00984     FOR_ALL_CELLS(pressure,
00985     {
00986         if (fdata[ind].type>0)
00987             pressure[ind] = prev->pressure[ind]; // use previous pressure as initial estimate
00988         else pressure[ind] = 0;
00989     });
00990     
00991     //  std::cout << "STEP: Pressure diag";
00992     //  for (int i=0;i<7;i++) std::cout << ' ' << nbdiag[i];
00993     //  std::cout << '\n';
00994     
00995     double err = 0.0;
00996     
00997     // r = b - Ax
00998     FOR_INNER_CELLS(r,
00999     {
01000         if (diag[ind] != 0)
01001         {
01002             r[ind] = b[ind] - (diag[ind]*pressure[ind]
01003                               -pressure[ind+index(-1,0,0)]-pressure[ind+index(0,-1,0)]-pressure[ind+index(0,0,-1)]
01004                               -pressure[ind+index( 1,0,0)]-pressure[ind+index(0, 1,0)]-pressure[ind+index(0,0, 1)]);
01005         }
01006     });
01007     
01008     FOR_ALL_CELLS(g,
01009     {
01010         g[ind] = r[ind]; // first direction is r
01011     });
01012     
01013     double min_err = 0.000001f*b_norm2;
01014     
01015     int step;
01016     for (step=0;step<100;step++)
01017     {
01018         double err_old = err;
01019         err = 0.0;
01020         FOR_READ_INNER_CELLS(
01021         {
01022         err += r[ind]*r[ind];
01023         });
01024         
01025         if (err<=min_err) break;
01026         if (step>0)
01027         {
01028             real beta = (real)(err/err_old);
01029             // g = g*beta + r
01030             FOR_ALL_CELLS(g,
01031             {
01032                 g[ind] = g[ind]*beta + r[ind];
01033             });
01034         }
01035         double g_q = 0.0;
01036         // q = Ag
01037         FOR_INNER_CELLS(q,
01038         {
01039             if (diag[ind] != 0)
01040             {
01041                 real Ag = (diag[ind]*g[ind]
01042                           -g[ind+index(-1,0,0)]-g[ind+index(0,-1,0)]-g[ind+index(0,0,-1)]
01043                           -g[ind+index( 1,0,0)]-g[ind+index(0, 1,0)]-g[ind+index(0,0, 1)]); 
01044                 q[ind] = Ag;
01045                 g_q += g[ind]*Ag;
01046             }
01047         });
01048         
01049         real alpha = (real)(err/g_q);
01050         
01051         FOR_ALL_CELLS(pressure,
01052         {
01053             pressure[ind] += alpha*g[ind];
01054             r[ind] -= alpha*q[ind];
01055         });
01056     }
01057 
01058     std::cout << "STEP: CG iteration "<<step<<" error(d) "<<sqrt(err/b_norm2)<<"\n";
01059     
01060     // Now apply pressure back to velocity
01061     a = dt;
01062     
01063     real max_speed = 0.5f/dt;
01064     
01065     //max_pressure = 0.0;
01066     max_pressure = prev->max_pressure;
01067     
01068     FOR_INNER_CELLS(fdata,
01069     {
01070         if (fdata[ind].type>=PART_EMPTY)
01071         {
01072             if (fdata[ind+index(-1,0,0)].type>=PART_EMPTY)
01073             {
01074                 fdata[ind].u[0] -= a*(pressure[ind] - pressure[ind+index(-1,0,0)]);
01075                 // safety check
01076                 if (fdata[ind].u[0] >  max_speed) fdata[ind].u[0] =  max_speed;
01077                 else if (fdata[ind].u[0] < -max_speed) fdata[ind].u[0] = -max_speed;
01078             }
01079             if (fdata[ind+index(0,-1,0)].type>=PART_EMPTY)
01080             {
01081                 fdata[ind].u[1] -= a*(pressure[ind] - pressure[ind+index(0,-1,0)]);
01082                 if (fdata[ind].u[1] >  max_speed) fdata[ind].u[1] =  max_speed;
01083                 else if (fdata[ind].u[1] < -max_speed) fdata[ind].u[1] = -max_speed;
01084             }
01085             if (fdata[ind+index(0,0,-1)].type>=PART_EMPTY)
01086             {
01087                 fdata[ind].u[2] -= a*(pressure[ind] - pressure[ind+index(0,0,-1)]);
01088                 if (fdata[ind].u[2] >  max_speed) fdata[ind].u[2] =  max_speed;
01089                 else if (fdata[ind].u[2] < -max_speed) fdata[ind].u[2] = -max_speed;
01090             }
01091         }
01092     });
01093     
01094     //  std::cout << "STEP: max pressure "<<max_pressure<<'\n';
01095 }
01096 
01097 } // namespace eulerianfluid
01098 
01099 } // namespace behaviormodel
01100 
01101 } // namespace component
01102 
01103 } // namespace sofa
01104 

Generated on Sun Nov 23 02:29:31 2008 for Sofa by  doxygen 1.5.7.1