00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <iostream>
00026 #include <sofa/component/behaviormodel/eulerianfluid/Grid2D.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* Grid2D::obstacles = NULL;
00042
00043
00044
00045 #define FOR_ALL_CELLS(grid,cmd) \
00046 { \
00047 int ind = index(0,0); \
00048 for (int y=0;y<ny;y++) \
00049 for (int x=0;x<nx;x++,ind+=index(1,0)) \
00050 { \
00051 cmd; \
00052 } \
00053 }
00054
00055 #define FOR_READ_INNER_CELLS(cmd) \
00056 { \
00057 int ind = index(1,1); \
00058 for (int y=1;y<ny-1;y++,ind+=index(2,0)) \
00059 for (int x=1;x<nx-1;x++,ind+=index(1,0))\
00060 { \
00061 cmd; \
00062 } \
00063 }
00064
00065 #define FOR_INNER_CELLS(grid,cmd) \
00066 { \
00067 int ind = index(1,1); \
00068 for (int y=1;y<ny-1;y++,ind+=index(2,0)) \
00069 for (int x=1;x<nx-1;x++,ind+=index(1,0))\
00070 { \
00071 cmd; \
00072 } \
00073 }
00074
00075
00076
00077
00078 #define FOR_SURFACE_CELLS(grid,cmd) \
00079 { \
00080 int ind = index(1,1); \
00081 for (int y=1;y<ny-1;y++,ind+=index(2,0)) \
00082 for (int x=1;x<nx-1;x++,ind+=index(1,0))\
00083 { \
00084 cmd; \
00085 } \
00086 }
00087
00088 Grid2D::Grid2D()
00089 : nx(0), ny(0), ncell(0),
00090 fdata(NULL), pressure(NULL), levelset(NULL),
00091 t(0), tend(60),
00092 max_pressure(0.0),
00093 fmm_status(NULL),
00094 fmm_heap(NULL),
00095 fmm_heap_size(0)
00096 {
00097 bcell.u.clear();
00098 bcell.type=-1;
00099 }
00100
00101 Grid2D::~Grid2D()
00102 {
00103 if (fdata!=NULL) delete[] fdata;
00104 if (pressure!=NULL) delete[] pressure;
00105 if (levelset!=NULL) delete[] levelset;
00106 if (fmm_status!=NULL) delete[] fmm_status;
00107 if (fmm_heap!=NULL) delete[] fmm_heap;
00108 }
00109
00110 void Grid2D::clear(int _nx, int _ny)
00111 {
00112 t = 0;
00113 tend = 40;
00114
00115 int old_ncell=ncell;
00116 nx=_nx; ny=_ny;
00117 ncell = nx*ny;
00118
00119 if (ncell != old_ncell)
00120 {
00121 if (fdata!=NULL) delete[] fdata;
00122 if (ncell>0) fdata = new Cell[ncell];
00123 else fdata = NULL;
00124 if (pressure!=NULL) delete[] pressure;
00125 if (ncell>0) pressure = new real[ncell];
00126 else pressure = NULL;
00127 if (levelset!=NULL) delete[] levelset;
00128 if (ncell>0) levelset = new real[ncell];
00129 else levelset = NULL;
00130 if (fmm_status!=NULL) delete[] fmm_status;
00131 if (ncell>0) fmm_status = new int[ncell];
00132 else fmm_status = NULL;
00133 if (fmm_heap!=NULL) delete[] fmm_heap;
00134 if (ncell>0) fmm_heap = new int[ncell];
00135 else fmm_heap = NULL;
00136 }
00137 if (ncell>0)
00138 memset(fdata,0,ncell*sizeof(Cell));
00139 if (ncell>0)
00140 memset(pressure,0,ncell*sizeof(real));
00141 if (ncell>0)
00142 memset(levelset,0,ncell*sizeof(real));
00143 }
00144
00145 void Grid2D::seed(real height)
00146 {
00147
00148 FOR_ALL_CELLS(fdata,
00149 {
00150 real d = y - height;
00151 levelset[ind] = d;
00152 });
00153 }
00154
00155 void Grid2D::seed(real height, vec2 normal)
00156 {
00157 normal.normalize();
00158 FOR_ALL_CELLS(fdata,
00159 {
00160 real d = vec2((real)x,(real)y)*normal - height;
00161 levelset[ind] = d;
00162 });
00163 }
00164
00165 void Grid2D::seed(vec2 p0, vec2 p1, vec2 velocity)
00166 {
00167 if (p0[0]<0.5f) p0[0]=0.5f;
00168 if (p0[1]<0.5f) p0[1]=0.5f;
00169 if (p1[0]>nx-1.5f) p1[0]=nx-1.5f;
00170 if (p1[1]>ny-1.5f) p1[1]=ny-1.5f;
00171 if (p0[0]>=p1[0]) return;
00172 if (p0[1]>=p1[1]) return;
00173 std::cout << "p0="<<p0<<" p1="<<p1<<std::endl;
00174 vec2 center = (p0+p1)*0.5f;
00175 vec2 dim = (p1-p0)*0.5f;
00176 FOR_ALL_CELLS(fdata,
00177 {
00178 vec2 v ((real)x,(real)y);
00179 v -= center;
00180 v[0] = rabs(v[0]) - dim[0];
00181 v[1] = rabs(v[1]) - dim[1];
00182 real d;
00183 if (v[0] <= 0 && v[1] <= 0)
00184 {
00185 d = rmax(v[0],v[1]);
00186 fdata[ind].u = velocity;
00187 }
00188 else
00189 {
00190 if (v[0] < 0) v[0] = 0;
00191 if (v[1] < 0) v[1] = 0;
00192 d = v.norm();
00193 }
00194 levelset[ind] = d;
00195 });
00196 }
00197
00198 void Grid2D::step(Grid2D* prev, Grid2D* temp, real dt, real diff)
00199 {
00200 t = prev->t+dt;
00201 tend = prev->tend;
00202
00203
00204
00205
00206
00207 step_init(prev, temp, dt, diff);
00208
00209 step_levelset(prev, temp, dt, diff);
00210 step_forces(prev, temp, dt, diff);
00211 step_surface(prev, temp, dt, diff);
00212 step_advect(prev, temp, dt, diff);
00213 step_diffuse(prev, temp, dt, diff);
00214 step_project(prev, temp, dt, diff);
00215
00216
00217
00218
00219 }
00220
00223
00224 void Grid2D::step_init(const Grid2D* , Grid2D* , real , real )
00225 {
00226
00227
00228
00229 int bsize = 1;
00230
00231
00232
00233
00234
00235 const unsigned char* obs = (const unsigned char*)obstacles;
00236 int lnsize = (nx+7)/8;
00237
00238
00239
00240 FOR_ALL_CELLS(fdata,
00241 {
00242 if (x<bsize || y<bsize || x>=nx-bsize || y>=ny-bsize
00243
00244 || (obs!=NULL && ((obs[(y)*lnsize+((x)>>3)])&(1<<((x)&7))))
00245 )
00246 {
00247 fdata[ind].type = PART_WALL;
00248 }
00249 else
00250 {
00251 fdata[ind].type = PART_EMPTY;
00252 }
00253 levelset[ind] = 5;
00254 });
00255 }
00256
00259
00260 #define RMAX 1e10
00261
00262 void Grid2D::step_levelset(Grid2D* prev, Grid2D* temp, real dt, real )
00263 {
00264
00265
00266
00267
00268
00269
00270
00271 FOR_INNER_CELLS(levelset,
00272 {
00273
00274 if (rabs(prev->levelset[ind]) < 5)
00275 {
00276 vec2 xn ( (real)x, (real)y );
00277 vec2 un = prev->interp(xn);
00278 vec2 xn1 = xn - un*dt;
00279
00280
00281 un = (un + prev->interp(xn1))*0.5;
00282 xn1 = xn - un*dt;
00283
00284 temp->levelset[ind] = prev->getlevelset(xn1);
00285 }
00286 else
00287 temp->levelset[ind] = prev->levelset[ind];
00288 });
00289
00290
00291
00292 FOR_ALL_CELLS(fmm_status,
00293 {
00294 fmm_status[ind] = FMM_FAR;
00295 if (fdata[ind].type == PART_WALL)
00296 {
00297
00298 real phi = 0;
00299 int n = 0;
00300 for (int dy=-1;dy<=1;dy++)
00301 if ((unsigned)(y+dy)<(unsigned)ny)
00302 for (int dx=-1;dx<=1;dx++)
00303 if ((unsigned)(x+dx)<(unsigned)nx)
00304 {
00305 int ind2 = ind+index(dx,dy);
00306 if (fdata[ind2].type != PART_WALL)
00307 {
00308 phi += temp->levelset[ind2];
00309 ++n;
00310 }
00311 }
00312 temp->levelset[ind] = phi/n;
00313 }
00314 });
00315
00316
00317
00318
00319 fmm_heap_size = 0;
00320 const int cmax[2] = { nx-1, ny-1 };
00321 const int dind[2] = { 1, nx };
00322
00323
00324 FOR_ALL_CELLS(fdata,
00325 {
00326 int c[2]; c[0] = x; c[1] = y;
00327 bool known = false;
00328 real phi0 = temp->levelset[ind];
00329 real inv_dist2 = 0;
00330 for (int dim = 0; dim < 2; dim++)
00331 {
00332 real dist = RMAX;
00333 bool border = false;
00334 if (c[dim]>0)
00335 {
00336 real phi1 = temp->levelset[ind-dind[dim]];
00337 if (phi1*phi0 < 0)
00338 {
00339 dist = phi0/(phi0-phi1);
00340 border = true;
00341 }
00342 }
00343 if (c[dim]<cmax[dim])
00344 {
00345 real phi1 = temp->levelset[ind+dind[dim]];
00346 if (phi1*phi0 < 0)
00347 {
00348 real d = phi0/(phi0-phi1);
00349 if (d < dist) dist = d;
00350 border = true;
00351 }
00352 }
00353 if (border)
00354 {
00355 known = true;
00356 inv_dist2 += 1 / (dist*dist);
00357 }
00358 }
00359 if (known)
00360 {
00361
00362 real phi = rabs(phi0);
00363 levelset[ind] = phi;
00364 fmm_status[ind] = FMM_KNOWN;
00365 }
00366 else
00367 {
00368 levelset[ind] = 5;
00369 fmm_status[ind] = FMM_FAR;
00370 }
00371 });
00372
00373
00374 FOR_ALL_CELLS(fdata,
00375 {
00376 if (fmm_status[ind] == FMM_KNOWN)
00377 {
00378 int c[2]; c[0] = x; c[1] = y;
00379 real phi1 = levelset[ind];
00380 phi1+=1;
00381 for (int dim = 0; dim < 2; dim++)
00382 {
00383 if (c[dim]>0)
00384 {
00385 int ind2 = ind-dind[dim];
00386 if (fmm_status[ind2] >= FMM_FAR)
00387 {
00388 real phi2 = levelset[ind2];
00389 if ((phi1) < (phi2))
00390 {
00391 levelset[ind2] = phi1;
00392 fmm_push(ind2);
00393 }
00394 }
00395 }
00396 if (c[dim]<cmax[dim])
00397 {
00398 int ind2 = ind+dind[dim];
00399 if (fmm_status[ind2] >= FMM_FAR)
00400 {
00401 real phi2 = levelset[ind2];
00402 if ((phi1) < (phi2))
00403 {
00404 levelset[ind2] = phi1;
00405 fmm_push(ind2);
00406 }
00407 }
00408 }
00409 }
00410 }
00411 });
00412
00413 while (fmm_heap_size > 0)
00414 {
00415 int ind = fmm_pop();
00416 real phi1 = levelset[ind]+1;
00417 if ((phi1) >= 5) break;
00418 int c[2] = { ind % nx, (ind / nx) };
00419 for (int dim = 0; dim < 2; dim++)
00420 {
00421 if (c[dim]>0)
00422 {
00423 int ind2 = ind-dind[dim];
00424 if (fmm_status[ind2] >= FMM_FAR)
00425 {
00426 real phi2 = levelset[ind2];
00427 if ((phi1) < (phi2))
00428 {
00429 levelset[ind2] = phi1;
00430 fmm_push(ind2);
00431 }
00432 }
00433 }
00434 if (c[dim]<cmax[dim])
00435 {
00436 int ind2 = ind+dind[dim];
00437 if (fmm_status[ind2] >= FMM_FAR)
00438 {
00439 real phi2 = levelset[ind2];
00440 if ((phi1) < (phi2))
00441 {
00442 levelset[ind2] = phi1;
00443 fmm_push(ind2);
00444 }
00445 }
00446 }
00447 }
00448 }
00449
00450 FOR_ALL_CELLS(levelset,
00451 {
00452 if(temp->levelset[ind] < 0)
00453 {
00454 levelset[ind] = -levelset[ind];
00455 if (fdata[ind].type == PART_EMPTY)
00456 fdata[ind].type = PART_FULL;
00457 }
00458 });
00459 }
00460
00461 inline void Grid2D::fmm_swap(int entry1, int entry2)
00462 {
00463 int ind1 = fmm_heap[entry1];
00464 int ind2 = fmm_heap[entry2];
00465 fmm_heap[entry1] = ind2;
00466 fmm_heap[entry2] = ind1;
00467 fmm_status[ind1] = entry2 + FMM_FRONT0;
00468 fmm_status[ind2] = entry1 + FMM_FRONT0;
00469 }
00470
00471 int Grid2D::fmm_pop()
00472 {
00473 int res = fmm_heap[0];
00474 #ifdef FMM_VERBOSE
00475 std::cout << "fmm_pop -> <"<<(res%nx)<<','<<((res/nx)%ny)<<','<<(res/nxny)<<">="<<levelset[res]<<std::endl;
00476 #endif
00477 --fmm_heap_size;
00478 if (fmm_heap_size>0)
00479 {
00480 fmm_swap(0, fmm_heap_size);
00481 int i=0;
00482 real phi = (levelset[fmm_heap[i]]);
00483 while (i*2+1 < fmm_heap_size)
00484 {
00485 real phi1 = (levelset[fmm_heap[i*2+1]]);
00486 if (i*2+2 < fmm_heap_size)
00487 {
00488 real phi2 = (levelset[fmm_heap[i*2+2]]);
00489 if (phi1 < phi)
00490 {
00491 if (phi1 < phi2)
00492 {
00493 fmm_swap(i, i*2+1);
00494 i = i*2+1;
00495 }
00496 else
00497 {
00498 fmm_swap(i, i*2+2);
00499 i = i*2+2;
00500 }
00501 }
00502 else if (phi2 < phi)
00503 {
00504 fmm_swap(i, i*2+2);
00505 i = i*2+2;
00506 }
00507 else break;
00508 }
00509 else if (phi1 < phi)
00510 {
00511 fmm_swap(i, i*2+1);
00512 i = i*2+1;
00513 }
00514 else break;
00515 }
00516 }
00517 #ifdef FMM_VERBOSE
00518 std::cout << "fmm_heap = [";
00519 for (int i=0;i<fmm_heap_size;i++)
00520 std::cout << " <"<<(fmm_heap[i]%nx)<<','<<((fmm_heap[i]/nx)%ny)<<','<<(fmm_heap[i]/nxny)<<">="<<levelset[fmm_heap[i]];
00521 std::cout << std::endl;
00522 #endif
00523 fmm_status[res] = FMM_KNOWN;
00524 return res;
00525 }
00526
00527 void Grid2D::fmm_push(int index)
00528 {
00529 real phi = (levelset[index]);
00530 int i;
00531 if (fmm_status[index] >= FMM_FRONT0)
00532 {
00533 i = fmm_status[index] - FMM_FRONT0;
00534 #ifdef FMM_VERBOSE
00535 std::cout << "fmm update <"<<(index%nx)<<','<<((index/nx)%ny)<<','<<(index/nxny)<<">="<<levelset[index]<<" from entry "<<i<<std::endl;
00536 #endif
00537 while (i>0 && phi < (levelset[fmm_heap[(i-1)/2]]))
00538 {
00539 fmm_swap(i,(i-1)/2);
00540 i = (i-1)/2;
00541 }
00542 while (i*2+1 < fmm_heap_size)
00543 {
00544 real phi1 = (levelset[fmm_heap[i*2+1]]);
00545 if (i*2+2 < fmm_heap_size)
00546 {
00547 real phi2 = (levelset[fmm_heap[i*2+2]]);
00548 if (phi1 < phi)
00549 {
00550 if (phi1 < phi2)
00551 {
00552 fmm_swap(i, i*2+1);
00553 i = i*2+1;
00554 }
00555 else
00556 {
00557 fmm_swap(i, i*2+2);
00558 i = i*2+2;
00559 }
00560 }
00561 else if (phi2 < phi)
00562 {
00563 fmm_swap(i, i*2+2);
00564 i = i*2+2;
00565 }
00566 else break;
00567 }
00568 else if (phi1 < phi)
00569 {
00570 fmm_swap(i, i*2+1);
00571 i = i*2+1;
00572 }
00573 else break;
00574 }
00575 }
00576 else
00577 {
00578 #ifdef FMM_VERBOSE
00579 std::cout << "fmm push <"<<(index%nx)<<','<<((index/nx)%ny)<<','<<(index/nxny)<<">="<<levelset[index]<<std::endl;
00580 #endif
00581 i = fmm_heap_size;
00582 ++fmm_heap_size;
00583 fmm_heap[i] = index;
00584 fmm_status[index] = i;
00585 while (i>0 && phi < (levelset[fmm_heap[(i-1)/2]]))
00586 {
00587 fmm_swap(i,(i-1)/2);
00588 i = (i-1)/2;
00589 }
00590 }
00591 #ifdef FMM_VERBOSE
00592 std::cout << "fmm_heap = [";
00593 for (int i=0;i<fmm_heap_size;i++)
00594 std::cout << " <"<<(fmm_heap[i]%nx)<<','<<((fmm_heap[i]/nx)%ny)<<','<<(fmm_heap[i]/nxny)<<">="<<levelset[fmm_heap[i]];
00595 std::cout << std::endl;
00596 #endif
00597 }
00598
00603
00604 void Grid2D::step_forces(const Grid2D* prev, Grid2D* , real dt, real , real )
00605 {
00606
00607
00608
00609
00610
00611
00612 vec2 f(0,-5*dt);
00613
00614 FOR_INNER_CELLS(fdata,
00615 {
00616 vec2 u = f;
00617 int p0 = fdata[ind].type;
00618 if (p0 < 0)
00619 u.clear();
00620 else
00621 {
00622 int p1;
00623
00624 p1 = fdata[ind+index(-1,0)].type;
00625 if (p1>=0 && p0+p1>0)
00626 {
00627 u[0] += prev->fdata[ind].u[0];
00628 }
00629 else
00630 u[0] = 0;
00631
00632 p1 = fdata[ind+index(0,-1)].type;
00633 if (p1>=0 && p0+p1>0)
00634 {
00635 u[1] += prev->fdata[ind].u[1];
00636 }
00637 else
00638 u[1] = 0;
00639 }
00640 fdata[ind].u = u;
00641 });
00642
00643
00644
00645 if (t > 0 && t < tend)
00646 {
00647 float f = 2*t;
00648 srand(*(const unsigned int*)(const void*)&f);
00649 vec2 v(4,0);
00650 int cx = 1*ny/4;
00651 int cy = 3*ny/4;
00652 real r = ny/8.0f;
00653 if (t < 1) r *= t;
00654 else if (t>tend-1) r*= tend-t;
00655 int ir = rceil(r)+5;
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 for (int y=cy-ir;y<=cy+ir;y++)
00666 if ((unsigned)y<(unsigned)ny)
00667 for (int x=cx-ir;x<=cx+ir;x++)
00668 {
00669 real d = sqrtf((real)((y-cy)*(y-cy)+(x-cx)*(x-cx))) - r;
00670 int ind = index(x,y);
00671 if (d < 0)
00672 {
00673 fdata[ind].u = v;
00674 if (fdata[ind].type == PART_EMPTY)
00675 fdata[ind].type = PART_FULL;
00676 }
00677 if (d < levelset[ind])
00678 levelset[ind] = d;
00679 }
00680 }
00681 }
00682
00685
00686 void Grid2D::step_surface(const Grid2D* , Grid2D* , real , real )
00687 {
00688
00689
00690
00691
00692 enum {
00693 FACE_X0=1<<0,
00694 FACE_X1=1<<1,
00695 FACE_Y0=1<<2,
00696 FACE_Y1=1<<3,
00697 };
00698
00699 FOR_SURFACE_CELLS(fdata,
00700 {
00701 if (fdata[ind].type>0)
00702 {
00703
00704 int mask = 0;
00705 if (fdata[ind+index(-1,0)].type==0) mask|=FACE_X0;
00706 if (fdata[ind+index( 1,0)].type==0) mask|=FACE_X1;
00707 if (fdata[ind+index(0,-1)].type==0) mask|=FACE_Y0;
00708 if (fdata[ind+index(0, 1)].type==0) mask|=FACE_Y1;
00709 if (mask!=0)
00710 {
00711 real& x0 = fdata[ind].u[0];
00712 real& y0 = fdata[ind].u[1];
00713 real& x1 = fdata[ind+index( 1,0)].u[0];
00714 real& y1 = fdata[ind+index(0, 1)].u[1];
00715
00716 switch (mask)
00717 {
00718
00719
00720 case FACE_X0: x0 = x1 +y1-y0; break;
00721 case FACE_X1: x1 = x0 +y0-y1; break;
00722 case FACE_Y0: y0 = x1-x0+y1 ; break;
00723 case FACE_Y1: y1 = x0-x1+y0 ; break;
00724
00725
00726
00727 case FACE_X0|FACE_X1: break;
00728 case FACE_Y0|FACE_Y1: break;
00729
00730 case FACE_X0|FACE_Y0: x0 = x1; y0 = y1; break;
00731 case FACE_X0|FACE_Y1: x0 = x1; y1 = y0; break;
00732 case FACE_X1|FACE_Y0: x1 = x0; y0 = y1; break;
00733 case FACE_X1|FACE_Y1: x1 = x0; y1 = y0; break;
00734
00735
00736 case FACE_X0|FACE_Y0|FACE_Y1: x0 = x1 +y1-y0; break;
00737 case FACE_X1|FACE_Y0|FACE_Y1: x1 = x0 +y0-y1; break;
00738 case FACE_Y0|FACE_X0|FACE_X1: y0 = x1-x0+y1 ; break;
00739 case FACE_Y1|FACE_X0|FACE_X1: y1 = x0-x1+y0 ; break;
00740
00741
00742 case FACE_X0|FACE_X1|FACE_Y0|FACE_Y1: break;
00743
00744
00745 }
00746 }
00747 }
00748 });
00749 }
00750
00753
00754
00755
00756 void Grid2D::step_advect(const Grid2D* , Grid2D* temp, real dt, real )
00757 {
00758
00759
00760
00761
00762
00763
00764
00765 memset(temp->fdata,0,temp->ncell*sizeof(Cell));
00766
00767 FOR_INNER_CELLS(temp->fdata,
00768 {
00769
00770 vec2 px( x-0.5f - dt*(fdata[ind].u[0]),
00771 y - dt*0.25f*(fdata[ind].u[1]+fdata[ind+index(-1,0)].u[1]+fdata[ind+index(0,1)].u[1]+fdata[ind+index(-1,1)].u[1]));
00772 temp->fdata[ind].u[0] = interp<0>(px);
00773
00774 vec2 py( x - dt*0.25f*(fdata[ind].u[0]+fdata[ind+index(0,-1)].u[0]+fdata[ind+index(1,0)].u[0]+fdata[ind+index(1,-1)].u[0]),
00775 y-0.5f - dt*(fdata[ind].u[1]));
00776 temp->fdata[ind].u[1] = interp<1>(py);
00777 });
00778
00779 }
00780
00781
00782 void Grid2D::step_diffuse(const Grid2D* , Grid2D* temp, real , real diff)
00783 {
00784
00785
00786
00787
00788 if (diff==0.0f)
00789 {
00790 for (int ind=0;ind<ncell;ind++)
00791 fdata[ind].u = temp->fdata[ind].u;
00792 return;
00793 }
00794
00795 real a = diff;
00796 real inv_c = 1.0f / (1.0001f + 4*a);
00797
00798 FOR_INNER_CELLS(fdata,
00799 {
00800 fdata[ind].u = (temp->fdata[ind].u +
00801 (temp->fdata[ind+index(-1,0)].u+temp->fdata[ind+index(1,0)].u+
00802 temp->fdata[ind+index(0,-1)].u+temp->fdata[ind+index(0,1)].u
00803 )*a)*inv_c;
00804 });
00805 }
00806
00807
00808 void Grid2D::step_project(const Grid2D* prev, Grid2D* temp, real dt, real )
00809 {
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820 memset(temp->fdata,0,temp->ncell*sizeof(Cell));
00821 memset(temp->pressure,0,temp->ncell*sizeof(real));
00822
00823 real* diag = (real*)temp->fdata;
00824 real* b = diag+ncell;
00825 real* r = b+ncell;
00826 real* g = r+ncell;
00827 real* q = temp->pressure;
00828
00829 real a = -1.0f/dt;
00830
00831 real b_norm2 = 0.0;
00832
00833
00834
00835 FOR_INNER_CELLS(diag,
00836 {
00837 if (fdata[ind].type>0)
00838 {
00839 real d = 4;
00840 d -= ((unsigned int)fdata[ind+index(-1,0)].type)>>31;
00841 d -= ((unsigned int)fdata[ind+index(0,-1)].type)>>31;
00842 d -= ((unsigned int)fdata[ind+index( 1,0)].type)>>31;
00843 d -= ((unsigned int)fdata[ind+index(0, 1)].type)>>31;
00844
00845 diag[ind] = d;
00846 }
00847 });
00848
00849 FOR_INNER_CELLS(b,
00850 {
00851 if (fdata[ind].type>0)
00852 {
00853 real bi = a*(fdata[ind+index(1,0)].u[0]-fdata[ind].u[0] + fdata[ind+index(0,1)].u[1]-fdata[ind].u[1]);
00854 b[ind] = bi;
00855 b_norm2 += bi*bi;
00856 }
00857 });
00858
00859
00860
00861
00862
00863 FOR_ALL_CELLS(pressure,
00864 {
00865 if (fdata[ind].type>0)
00866 pressure[ind] = prev->pressure[ind];
00867 else pressure[ind] = 0;
00868 });
00869
00870
00871
00872
00873
00874 real err = 0.0;
00875
00876
00877 FOR_INNER_CELLS(r,
00878 {
00879 if (diag[ind] != 0)
00880 {
00881 r[ind] = b[ind] - (diag[ind]*pressure[ind]
00882 -pressure[ind+index(-1,0)]-pressure[ind+index(0,-1)]
00883 -pressure[ind+index( 1,0)]-pressure[ind+index(0, 1)]);
00884 }
00885 });
00886
00887 FOR_ALL_CELLS(g,
00888 {
00889 g[ind] = r[ind];
00890 });
00891
00892 real min_err = 0.0001f*b_norm2;
00893
00894 int step;
00895 for (step=0;step<100;step++)
00896 {
00897 real err_old = err;
00898 err = 0.0f;
00899 FOR_READ_INNER_CELLS(
00900 {
00901 err += r[ind]*r[ind];
00902 });
00903
00904 if (err<=min_err) break;
00905 if (step>0)
00906 {
00907 real beta = err/err_old;
00908
00909 FOR_ALL_CELLS(g,
00910 {
00911 g[ind] = g[ind]*beta + r[ind];
00912 });
00913 }
00914 real g_q = 0.0;
00915
00916 FOR_INNER_CELLS(q,
00917 {
00918 if (diag[ind] != 0)
00919 {
00920 real Ag = (diag[ind]*g[ind]
00921 -g[ind+index(-1,0)]-g[ind+index(0,-1)]
00922 -g[ind+index( 1,0)]-g[ind+index(0, 1)]);
00923 q[ind] = Ag;
00924 g_q += g[ind]*Ag;
00925 }
00926 });
00927
00928 real alpha = err/g_q;
00929
00930 FOR_ALL_CELLS(pressure,
00931 {
00932 pressure[ind] += alpha*g[ind];
00933 r[ind] -= alpha*q[ind];
00934 });
00935 }
00936
00937
00938
00939
00940 a = dt;
00941
00942 real max_speed = 0.5f/dt;
00943
00944
00945 max_pressure = prev->max_pressure;
00946
00947 FOR_INNER_CELLS(fdata,
00948 {
00949 if (fdata[ind].type>=PART_EMPTY)
00950 {
00951 if (fdata[ind+index(-1,0)].type>=PART_EMPTY)
00952 {
00953 fdata[ind].u[0] -= a*(pressure[ind] - pressure[ind+index(-1,0)]);
00954
00955 if (fdata[ind].u[0] > max_speed) fdata[ind].u[0] = max_speed;
00956 else if (fdata[ind].u[0] < -max_speed) fdata[ind].u[0] = -max_speed;
00957 }
00958 if (fdata[ind+index(0,-1)].type>=PART_EMPTY)
00959 {
00960 fdata[ind].u[1] -= a*(pressure[ind] - pressure[ind+index(0,-1)]);
00961 if (fdata[ind].u[1] > max_speed) fdata[ind].u[1] = max_speed;
00962 else if (fdata[ind].u[1] < -max_speed) fdata[ind].u[1] = -max_speed;
00963 }
00964 }
00965 });
00966
00967
00968 }
00969
00970 }
00971
00972 }
00973
00974 }
00975
00976 }
00977