1 
2 
3 // DO NOT EDIT !
4 // This file is generated using the MantaFlow preprocessor (prep generate).
5 
6 /******************************************************************************
7  *
8  * MantaFlow fluid solver framework
9  * Copyright 2011 Tobias Pfaff, Nils Thuerey
10  *
11  * This program is free software, distributed under the terms of the
12  * Apache License, Version 2.0
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Fast marching and extrapolation
16  *
17  ******************************************************************************/
18 
19 #include "fastmarch.h"
20 #include "levelset.h"
21 #include "kernel.h"
22 #include <algorithm>
23 
24 using namespace std;
25 
26 namespace Manta {
27 
28 template<class COMP, int TDIR>
FastMarch(const FlagGrid & flags,Grid<int> & fmFlags,Grid<Real> & levelset,Real maxTime,MACGrid * velTransport)29 FastMarch<COMP, TDIR>::FastMarch(const FlagGrid &flags,
30                                  Grid<int> &fmFlags,
31                                  Grid<Real> &levelset,
32                                  Real maxTime,
33                                  MACGrid *velTransport)
34     : mLevelset(levelset), mFlags(flags), mFmFlags(fmFlags)
35 {
36   if (velTransport)
37     mVelTransport.initMarching(velTransport, &flags);
38 
39   mMaxTime = maxTime * TDIR;
40 }
41 
42 // helper for individual components to calculateDistance
43 template<class COMP, int TDIR>
44 template<int C>
calcWeights(int & okcnt,int & invcnt,Real * v,const Vec3i & idx)45 Real FastMarch<COMP, TDIR>::calcWeights(int &okcnt, int &invcnt, Real *v, const Vec3i &idx)
46 {
47   Real val = 0.;
48   Vec3i idxPlus(idx), idxMinus(idx);
49   idxPlus[C]++;
50   idxMinus[C]--;
51 
52   mWeights[C * 2] = mWeights[C * 2 + 1] = 0.;
53   if (mFmFlags(idxPlus) == FlagInited) {
54     // somewhat arbitrary - choose +1 value over -1 ...
55     val = mLevelset(idxPlus);
56     v[okcnt] = val;
57     okcnt++;
58     mWeights[C * 2] = 1.;
59   }
60   else if (mFmFlags(idxMinus) == FlagInited) {
61     val = mLevelset(idxMinus);
62     v[okcnt] = val;
63     okcnt++;
64     mWeights[C * 2 + 1] = 1.;
65   }
66   else {
67     invcnt++;
68   }
69   return val;
70 }
71 
72 template<class COMP, int TDIR>
calculateDistance(const Vec3i & idx)73 inline Real FastMarch<COMP, TDIR>::calculateDistance(const Vec3i &idx)
74 {
75   // int invflag = 0;
76   int invcnt = 0;
77   Real v[3];
78   int okcnt = 0;
79 
80   Real aVal = calcWeights<0>(okcnt, invcnt, v, idx);
81   Real bVal = calcWeights<1>(okcnt, invcnt, v, idx);
82   Real cVal = 0.;
83   if (mLevelset.is3D())
84     cVal = calcWeights<2>(okcnt, invcnt, v, idx);
85   else {
86     invcnt++;
87     mWeights[4] = mWeights[5] = 0.;
88   }
89 
90   Real ret = InvalidTime();
91   switch (invcnt) {
92     case 0: {
93       // take all values
94       const Real ca = v[0], cb = v[1], cc = v[2];
95       const Real csqrt = max(0.,
96                              -2. * (ca * ca + cb * cb - cb * cc + cc * cc - ca * (cb + cc)) + 3);
97       // clamp to make sure the sqrt is valid
98       ret = 0.333333 * (ca + cb + cc + TDIR * sqrt(csqrt));
99 
100       // weights needed for transport (transpTouch)
101       mWeights[0] *= fabs(ret - ca);
102       mWeights[1] *= fabs(ret - ca);
103       mWeights[2] *= fabs(ret - cb);
104       mWeights[3] *= fabs(ret - cb);
105       mWeights[4] *= fabs(ret - cc);
106       mWeights[5] *= fabs(ret - cc);
107 
108       Real norm = 0.0;  // try to force normalization
109       for (int i = 0; i < 6; i++) {
110         norm += mWeights[i];
111       }
112       norm = 1.0 / norm;
113       for (int i = 0; i < 6; i++) {
114         mWeights[i] *= norm;
115       }
116 
117     } break;
118     case 1: {
119       // take just the 2 ok values
120       // t=0.5*( a+b+ (2*g*g-(b-a)*(b-a))^0.5)
121       const Real csqrt = max(0., 2. - (v[1] - v[0]) * (v[1] - v[0]));
122       // clamp to make sure the sqrt is valid
123       ret = 0.5 * (v[0] + v[1] + TDIR * sqrt(csqrt));
124 
125       // weights needed for transport (transpTouch)
126       mWeights[0] *= fabs(ret - aVal);
127       mWeights[1] *= fabs(ret - aVal);
128       mWeights[2] *= fabs(ret - bVal);
129       mWeights[3] *= fabs(ret - bVal);
130       mWeights[4] *= fabs(ret - cVal);
131       mWeights[5] *= fabs(ret - cVal);
132 
133       Real norm = 0.0;  // try to force normalization
134       for (int i = 0; i < 6; i++) {
135         norm += mWeights[i];
136       }
137       norm = 1.0 / norm;
138       for (int i = 0; i < 6; i++) {
139         mWeights[i] *= norm;
140       }
141       // */
142 
143     } break;
144     case 2: {
145       // just use the one remaining value
146       ret = v[0] + (Real)(TDIR);  // direction = +- 1
147     } break;
148     default:
149       errMsg("FastMarch :: Invalid invcnt");
150       break;
151   }
152   return ret;
153 }
154 
155 template<class COMP, int TDIR>
addToList(const Vec3i & p,const Vec3i & src)156 void FastMarch<COMP, TDIR>::addToList(const Vec3i &p, const Vec3i &src)
157 {
158   if (!mLevelset.isInBounds(p, 1))
159     return;
160   const IndexInt idx = mLevelset.index(p);
161 
162   // already known value, value alreay set to valid value? skip cell...
163   if (mFmFlags[idx] == FlagInited)
164     return;
165 
166   // discard by source time now , TODO do instead before calling all addtolists?
167   Real srct = mLevelset(src);
168   if (COMP::compare(srct, mMaxTime))
169     return;
170 
171   Real ttime = calculateDistance(p);
172 
173   // remove old entry if larger
174   bool found = false;
175 
176   Real oldt = mLevelset[idx];
177   if (mFmFlags[idx] == FlagIsOnHeap) {
178     found = true;
179     // is old time better?
180     if (COMP::compare(ttime, oldt))
181       return;
182   }
183 
184   // update field
185   mFmFlags[idx] = FlagIsOnHeap;
186   mLevelset[idx] = ttime;
187   // debug info std::cout<<"set "<< idx <<","<< ttime <<"\n";
188 
189   if (mVelTransport.isInitialized())
190     mVelTransport.transpTouch(p.x, p.y, p.z, mWeights, ttime);
191 
192   // the following adds entries to the heap of active cells
193   // current: (!found) , previous: always add, might lead to duplicate
194   //     entries, but the earlier will be handled earlier, the second one will skip to the
195   //     FlagInited check above
196   if (!found) {
197     // add list entry with source value
198     COMP entry;
199     entry.p = p;
200     entry.time = mLevelset[idx];
201 
202     mHeap.push(entry);
203     // debug info std::cout<<"push "<< entry.p <<","<< entry.time <<"\n";
204   }
205 }
206 
207 //! Enforce delta_phi = 0 on boundaries
208 
209 struct SetLevelsetBoundaries : public KernelBase {
SetLevelsetBoundariesManta::SetLevelsetBoundaries210   SetLevelsetBoundaries(Grid<Real> &phi) : KernelBase(&phi, 0), phi(phi)
211   {
212     runMessage();
213     run();
214   }
opManta::SetLevelsetBoundaries215   inline void op(int i, int j, int k, Grid<Real> &phi)
216   {
217     if (i == 0)
218       phi(i, j, k) = phi(1, j, k);
219     if (i == maxX - 1)
220       phi(i, j, k) = phi(i - 1, j, k);
221 
222     if (j == 0)
223       phi(i, j, k) = phi(i, 1, k);
224     if (j == maxY - 1)
225       phi(i, j, k) = phi(i, j - 1, k);
226 
227     if (phi.is3D()) {
228       if (k == 0)
229         phi(i, j, k) = phi(i, j, 1);
230       if (k == maxZ - 1)
231         phi(i, j, k) = phi(i, j, k - 1);
232     }
233   }
getArg0Manta::SetLevelsetBoundaries234   inline Grid<Real> &getArg0()
235   {
236     return phi;
237   }
238   typedef Grid<Real> type0;
runMessageManta::SetLevelsetBoundaries239   void runMessage()
240   {
241     debMsg("Executing kernel SetLevelsetBoundaries ", 3);
242     debMsg("Kernel range"
243                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
244            4);
245   };
runManta::SetLevelsetBoundaries246   void run()
247   {
248     const int _maxX = maxX;
249     const int _maxY = maxY;
250     for (int k = minZ; k < maxZ; k++)
251       for (int j = 0; j < _maxY; j++)
252         for (int i = 0; i < _maxX; i++)
253           op(i, j, k, phi);
254   }
255   Grid<Real> &phi;
256 };
257 
258 /*****************************************************************************/
259 //! Walk...
performMarching()260 template<class COMP, int TDIR> void FastMarch<COMP, TDIR>::performMarching()
261 {
262   mReheapVal = 0.0;
263   while (mHeap.size() > 0) {
264 
265     const COMP &ce = mHeap.top();
266     Vec3i p = ce.p;
267     mFmFlags(p) = FlagInited;
268     mHeap.pop();
269     // debug info std::cout<<"pop "<< ce.p <<","<< ce.time <<"\n";
270 
271     addToList(Vec3i(p.x - 1, p.y, p.z), p);
272     addToList(Vec3i(p.x + 1, p.y, p.z), p);
273     addToList(Vec3i(p.x, p.y - 1, p.z), p);
274     addToList(Vec3i(p.x, p.y + 1, p.z), p);
275     if (mLevelset.is3D()) {
276       addToList(Vec3i(p.x, p.y, p.z - 1), p);
277       addToList(Vec3i(p.x, p.y, p.z + 1), p);
278     }
279   }
280 
281   // set boundary for plain array
282   SetLevelsetBoundaries setls(mLevelset);
283   setls.getArg0();  // get rid of compiler warning...
284 }
285 
286 // explicit instantiation
287 template class FastMarch<FmHeapEntryIn, -1>;
288 template class FastMarch<FmHeapEntryOut, +1>;
289 
290 /*****************************************************************************/
291 // simpler extrapolation functions (primarily for FLIP)
292 
293 struct knExtrapolateMACSimple : public KernelBase {
knExtrapolateMACSimpleManta::knExtrapolateMACSimple294   knExtrapolateMACSimple(MACGrid &vel, int distance, Grid<int> &tmp, const int d, const int c)
295       : KernelBase(&vel, 1), vel(vel), distance(distance), tmp(tmp), d(d), c(c)
296   {
297     runMessage();
298     run();
299   }
opManta::knExtrapolateMACSimple300   inline void op(int i,
301                  int j,
302                  int k,
303                  MACGrid &vel,
304                  int distance,
305                  Grid<int> &tmp,
306                  const int d,
307                  const int c) const
308   {
309     static const Vec3i nb[6] = {Vec3i(1, 0, 0),
310                                 Vec3i(-1, 0, 0),
311                                 Vec3i(0, 1, 0),
312                                 Vec3i(0, -1, 0),
313                                 Vec3i(0, 0, 1),
314                                 Vec3i(0, 0, -1)};
315     const int dim = (vel.is3D() ? 3 : 2);
316 
317     if (tmp(i, j, k) != 0)
318       return;
319 
320     // copy from initialized neighbors
321     Vec3i p(i, j, k);
322     int nbs = 0;
323     Real avgVel = 0.;
324     for (int n = 0; n < 2 * dim; ++n) {
325       if (tmp(p + nb[n]) == d) {
326         // vel(p)[c] = (c+1.)*0.1;
327         avgVel += vel(p + nb[n])[c];
328         nbs++;
329       }
330     }
331 
332     if (nbs > 0) {
333       tmp(p) = d + 1;
334       vel(p)[c] = avgVel / nbs;
335     }
336   }
getArg0Manta::knExtrapolateMACSimple337   inline MACGrid &getArg0()
338   {
339     return vel;
340   }
341   typedef MACGrid type0;
getArg1Manta::knExtrapolateMACSimple342   inline int &getArg1()
343   {
344     return distance;
345   }
346   typedef int type1;
getArg2Manta::knExtrapolateMACSimple347   inline Grid<int> &getArg2()
348   {
349     return tmp;
350   }
351   typedef Grid<int> type2;
getArg3Manta::knExtrapolateMACSimple352   inline const int &getArg3()
353   {
354     return d;
355   }
356   typedef int type3;
getArg4Manta::knExtrapolateMACSimple357   inline const int &getArg4()
358   {
359     return c;
360   }
361   typedef int type4;
runMessageManta::knExtrapolateMACSimple362   void runMessage()
363   {
364     debMsg("Executing kernel knExtrapolateMACSimple ", 3);
365     debMsg("Kernel range"
366                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
367            4);
368   };
operator ()Manta::knExtrapolateMACSimple369   void operator()(const tbb::blocked_range<IndexInt> &__r) const
370   {
371     const int _maxX = maxX;
372     const int _maxY = maxY;
373     if (maxZ > 1) {
374       for (int k = __r.begin(); k != (int)__r.end(); k++)
375         for (int j = 1; j < _maxY; j++)
376           for (int i = 1; i < _maxX; i++)
377             op(i, j, k, vel, distance, tmp, d, c);
378     }
379     else {
380       const int k = 0;
381       for (int j = __r.begin(); j != (int)__r.end(); j++)
382         for (int i = 1; i < _maxX; i++)
383           op(i, j, k, vel, distance, tmp, d, c);
384     }
385   }
runManta::knExtrapolateMACSimple386   void run()
387   {
388     if (maxZ > 1)
389       tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
390     else
391       tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
392   }
393   MACGrid &vel;
394   int distance;
395   Grid<int> &tmp;
396   const int d;
397   const int c;
398 };
399 //! copy velocity into domain side, note - don't read & write same grid, hence velTmp copy
400 
401 struct knExtrapolateIntoBnd : public KernelBase {
knExtrapolateIntoBndManta::knExtrapolateIntoBnd402   knExtrapolateIntoBnd(FlagGrid &flags, MACGrid &vel, const MACGrid &velTmp)
403       : KernelBase(&flags, 0), flags(flags), vel(vel), velTmp(velTmp)
404   {
405     runMessage();
406     run();
407   }
opManta::knExtrapolateIntoBnd408   inline void op(int i, int j, int k, FlagGrid &flags, MACGrid &vel, const MACGrid &velTmp) const
409   {
410     int c = 0;
411     Vec3 v(0, 0, 0);
412     const bool isObs = flags.isObstacle(i, j, k);
413     if (i == 0) {
414       v = velTmp(i + 1, j, k);
415       if (isObs && v[0] < 0.)
416         v[0] = 0.;
417       c++;
418     }
419     else if (i == (flags.getSizeX() - 1)) {
420       v = velTmp(i - 1, j, k);
421       if (isObs && v[0] > 0.)
422         v[0] = 0.;
423       c++;
424     }
425     if (j == 0) {
426       v = velTmp(i, j + 1, k);
427       if (isObs && v[1] < 0.)
428         v[1] = 0.;
429       c++;
430     }
431     else if (j == (flags.getSizeY() - 1)) {
432       v = velTmp(i, j - 1, k);
433       if (isObs && v[1] > 0.)
434         v[1] = 0.;
435       c++;
436     }
437     if (flags.is3D()) {
438       if (k == 0) {
439         v = velTmp(i, j, k + 1);
440         if (isObs && v[2] < 0.)
441           v[2] = 0.;
442         c++;
443       }
444       else if (k == (flags.getSizeZ() - 1)) {
445         v = velTmp(i, j, k - 1);
446         if (isObs && v[2] > 0.)
447           v[2] = 0.;
448         c++;
449       }
450     }
451     if (c > 0) {
452       vel(i, j, k) = v / (Real)c;
453     }
454   }
getArg0Manta::knExtrapolateIntoBnd455   inline FlagGrid &getArg0()
456   {
457     return flags;
458   }
459   typedef FlagGrid type0;
getArg1Manta::knExtrapolateIntoBnd460   inline MACGrid &getArg1()
461   {
462     return vel;
463   }
464   typedef MACGrid type1;
getArg2Manta::knExtrapolateIntoBnd465   inline const MACGrid &getArg2()
466   {
467     return velTmp;
468   }
469   typedef MACGrid type2;
runMessageManta::knExtrapolateIntoBnd470   void runMessage()
471   {
472     debMsg("Executing kernel knExtrapolateIntoBnd ", 3);
473     debMsg("Kernel range"
474                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
475            4);
476   };
operator ()Manta::knExtrapolateIntoBnd477   void operator()(const tbb::blocked_range<IndexInt> &__r) const
478   {
479     const int _maxX = maxX;
480     const int _maxY = maxY;
481     if (maxZ > 1) {
482       for (int k = __r.begin(); k != (int)__r.end(); k++)
483         for (int j = 0; j < _maxY; j++)
484           for (int i = 0; i < _maxX; i++)
485             op(i, j, k, flags, vel, velTmp);
486     }
487     else {
488       const int k = 0;
489       for (int j = __r.begin(); j != (int)__r.end(); j++)
490         for (int i = 0; i < _maxX; i++)
491           op(i, j, k, flags, vel, velTmp);
492     }
493   }
runManta::knExtrapolateIntoBnd494   void run()
495   {
496     if (maxZ > 1)
497       tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
498     else
499       tbb::parallel_for(tbb::blocked_range<IndexInt>(0, maxY), *this);
500   }
501   FlagGrid &flags;
502   MACGrid &vel;
503   const MACGrid &velTmp;
504 };
505 
506 // todo - use getGradient instead?
getNormal(const Grid<Real> & data,int i,int j,int k)507 inline Vec3 getNormal(const Grid<Real> &data, int i, int j, int k)
508 {
509   if (i > data.getSizeX() - 2)
510     i = data.getSizeX() - 2;
511   if (i < 1)
512     i = 1;
513   if (j > data.getSizeY() - 2)
514     j = data.getSizeY() - 2;
515   if (j < 1)
516     j = 1;
517 
518   int kd = 1;
519   if (data.is3D()) {
520     if (k > data.getSizeZ() - 2)
521       k = data.getSizeZ() - 2;
522     if (k < 1)
523       k = 1;
524   }
525   else {
526     kd = 0;
527   }
528 
529   return Vec3(data(i + 1, j, k) - data(i - 1, j, k),
530               data(i, j + 1, k) - data(i, j - 1, k),
531               data(i, j, k + kd) - data(i, j, k - kd));
532 }
533 
534 struct knUnprojectNormalComp : public KernelBase {
knUnprojectNormalCompManta::knUnprojectNormalComp535   knUnprojectNormalComp(FlagGrid &flags, MACGrid &vel, Grid<Real> &phi, Real maxDist)
536       : KernelBase(&flags, 1), flags(flags), vel(vel), phi(phi), maxDist(maxDist)
537   {
538     runMessage();
539     run();
540   }
opManta::knUnprojectNormalComp541   inline void op(
542       int i, int j, int k, FlagGrid &flags, MACGrid &vel, Grid<Real> &phi, Real maxDist) const
543   {
544     // apply inside, within range near obstacle surface
545     if (phi(i, j, k) > 0. || phi(i, j, k) < -maxDist)
546       return;
547 
548     Vec3 n = getNormal(phi, i, j, k);
549     Vec3 v = vel(i, j, k);
550     if (dot(n, v) < 0.) {
551       normalize(n);
552       Real l = dot(n, v);
553       vel(i, j, k) -= n * l;
554     }
555   }
getArg0Manta::knUnprojectNormalComp556   inline FlagGrid &getArg0()
557   {
558     return flags;
559   }
560   typedef FlagGrid type0;
getArg1Manta::knUnprojectNormalComp561   inline MACGrid &getArg1()
562   {
563     return vel;
564   }
565   typedef MACGrid type1;
getArg2Manta::knUnprojectNormalComp566   inline Grid<Real> &getArg2()
567   {
568     return phi;
569   }
570   typedef Grid<Real> type2;
getArg3Manta::knUnprojectNormalComp571   inline Real &getArg3()
572   {
573     return maxDist;
574   }
575   typedef Real type3;
runMessageManta::knUnprojectNormalComp576   void runMessage()
577   {
578     debMsg("Executing kernel knUnprojectNormalComp ", 3);
579     debMsg("Kernel range"
580                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
581            4);
582   };
operator ()Manta::knUnprojectNormalComp583   void operator()(const tbb::blocked_range<IndexInt> &__r) const
584   {
585     const int _maxX = maxX;
586     const int _maxY = maxY;
587     if (maxZ > 1) {
588       for (int k = __r.begin(); k != (int)__r.end(); k++)
589         for (int j = 1; j < _maxY; j++)
590           for (int i = 1; i < _maxX; i++)
591             op(i, j, k, flags, vel, phi, maxDist);
592     }
593     else {
594       const int k = 0;
595       for (int j = __r.begin(); j != (int)__r.end(); j++)
596         for (int i = 1; i < _maxX; i++)
597           op(i, j, k, flags, vel, phi, maxDist);
598     }
599   }
runManta::knUnprojectNormalComp600   void run()
601   {
602     if (maxZ > 1)
603       tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
604     else
605       tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
606   }
607   FlagGrid &flags;
608   MACGrid &vel;
609   Grid<Real> &phi;
610   Real maxDist;
611 };
612 // a simple extrapolation step , used for cases where there's no levelset
613 // (note, less accurate than fast marching extrapolation.)
614 // into obstacle is a special mode for second order obstable boundaries (extrapolating
615 // only fluid velocities, not those at obstacles)
616 
extrapolateMACSimple(FlagGrid & flags,MACGrid & vel,int distance=4,LevelsetGrid * phiObs=NULL,bool intoObs=false)617 void extrapolateMACSimple(FlagGrid &flags,
618                           MACGrid &vel,
619                           int distance = 4,
620                           LevelsetGrid *phiObs = NULL,
621                           bool intoObs = false)
622 {
623   Grid<int> tmp(flags.getParent());
624   int dim = (flags.is3D() ? 3 : 2);
625 
626   for (int c = 0; c < dim; ++c) {
627     Vec3i dir = 0;
628     dir[c] = 1;
629     tmp.clear();
630 
631     // remove all fluid cells (not touching obstacles)
632     FOR_IJK_BND(flags, 1)
633     {
634       Vec3i p(i, j, k);
635       bool mark = false;
636       if (!intoObs) {
637         if (flags.isFluid(p) || flags.isFluid(p - dir))
638           mark = true;
639       }
640       else {
641         if ((flags.isFluid(p) || flags.isFluid(p - dir)) && (!flags.isObstacle(p)) &&
642             (!flags.isObstacle(p - dir)))
643           mark = true;
644       }
645 
646       if (mark)
647         tmp(p) = 1;
648     }
649 
650     // extrapolate for distance
651     for (int d = 1; d < 1 + distance; ++d) {
652       knExtrapolateMACSimple(vel, distance, tmp, d, c);
653     }  // d
654   }
655 
656   if (phiObs) {
657     knUnprojectNormalComp(flags, vel, *phiObs, distance);
658   }
659 
660   // copy tangential values into sides of domain
661   MACGrid velTmp(flags.getParent());
662   velTmp.copyFrom(vel);
663   knExtrapolateIntoBnd(flags, vel, velTmp);
664 }
_W_0(PyObject * _self,PyObject * _linargs,PyObject * _kwds)665 static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
666 {
667   try {
668     PbArgs _args(_linargs, _kwds);
669     FluidSolver *parent = _args.obtainParent();
670     bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
671     pbPreparePlugin(parent, "extrapolateMACSimple", !noTiming);
672     PyObject *_retval = 0;
673     {
674       ArgLocker _lock;
675       FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
676       MACGrid &vel = *_args.getPtr<MACGrid>("vel", 1, &_lock);
677       int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
678       LevelsetGrid *phiObs = _args.getPtrOpt<LevelsetGrid>("phiObs", 3, NULL, &_lock);
679       bool intoObs = _args.getOpt<bool>("intoObs", 4, false, &_lock);
680       _retval = getPyNone();
681       extrapolateMACSimple(flags, vel, distance, phiObs, intoObs);
682       _args.check();
683     }
684     pbFinalizePlugin(parent, "extrapolateMACSimple", !noTiming);
685     return _retval;
686   }
687   catch (std::exception &e) {
688     pbSetError("extrapolateMACSimple", e.what());
689     return 0;
690   }
691 }
692 static const Pb::Register _RP_extrapolateMACSimple("", "extrapolateMACSimple", _W_0);
693 extern "C" {
PbRegister_extrapolateMACSimple()694 void PbRegister_extrapolateMACSimple()
695 {
696   KEEP_UNUSED(_RP_extrapolateMACSimple);
697 }
698 }
699 
700 struct knExtrapolateMACFromWeight : public KernelBase {
knExtrapolateMACFromWeightManta::knExtrapolateMACFromWeight701   knExtrapolateMACFromWeight(
702       MACGrid &vel, Grid<Vec3> &weight, int distance, const int d, const int c)
703       : KernelBase(&vel, 1), vel(vel), weight(weight), distance(distance), d(d), c(c)
704   {
705     runMessage();
706     run();
707   }
opManta::knExtrapolateMACFromWeight708   inline void op(int i,
709                  int j,
710                  int k,
711                  MACGrid &vel,
712                  Grid<Vec3> &weight,
713                  int distance,
714                  const int d,
715                  const int c) const
716   {
717     static const Vec3i nb[6] = {Vec3i(1, 0, 0),
718                                 Vec3i(-1, 0, 0),
719                                 Vec3i(0, 1, 0),
720                                 Vec3i(0, -1, 0),
721                                 Vec3i(0, 0, 1),
722                                 Vec3i(0, 0, -1)};
723     const int dim = (vel.is3D() ? 3 : 2);
724 
725     if (weight(i, j, k)[c] != 0)
726       return;
727 
728     // copy from initialized neighbors
729     Vec3i p(i, j, k);
730     int nbs = 0;
731     Real avgVel = 0.;
732     for (int n = 0; n < 2 * dim; ++n) {
733       if (weight(p + nb[n])[c] == d) {
734         avgVel += vel(p + nb[n])[c];
735         nbs++;
736       }
737     }
738 
739     if (nbs > 0) {
740       weight(p)[c] = d + 1;
741       vel(p)[c] = avgVel / nbs;
742     }
743   }
getArg0Manta::knExtrapolateMACFromWeight744   inline MACGrid &getArg0()
745   {
746     return vel;
747   }
748   typedef MACGrid type0;
getArg1Manta::knExtrapolateMACFromWeight749   inline Grid<Vec3> &getArg1()
750   {
751     return weight;
752   }
753   typedef Grid<Vec3> type1;
getArg2Manta::knExtrapolateMACFromWeight754   inline int &getArg2()
755   {
756     return distance;
757   }
758   typedef int type2;
getArg3Manta::knExtrapolateMACFromWeight759   inline const int &getArg3()
760   {
761     return d;
762   }
763   typedef int type3;
getArg4Manta::knExtrapolateMACFromWeight764   inline const int &getArg4()
765   {
766     return c;
767   }
768   typedef int type4;
runMessageManta::knExtrapolateMACFromWeight769   void runMessage()
770   {
771     debMsg("Executing kernel knExtrapolateMACFromWeight ", 3);
772     debMsg("Kernel range"
773                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
774            4);
775   };
operator ()Manta::knExtrapolateMACFromWeight776   void operator()(const tbb::blocked_range<IndexInt> &__r) const
777   {
778     const int _maxX = maxX;
779     const int _maxY = maxY;
780     if (maxZ > 1) {
781       for (int k = __r.begin(); k != (int)__r.end(); k++)
782         for (int j = 1; j < _maxY; j++)
783           for (int i = 1; i < _maxX; i++)
784             op(i, j, k, vel, weight, distance, d, c);
785     }
786     else {
787       const int k = 0;
788       for (int j = __r.begin(); j != (int)__r.end(); j++)
789         for (int i = 1; i < _maxX; i++)
790           op(i, j, k, vel, weight, distance, d, c);
791     }
792   }
runManta::knExtrapolateMACFromWeight793   void run()
794   {
795     if (maxZ > 1)
796       tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
797     else
798       tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
799   }
800   MACGrid &vel;
801   Grid<Vec3> &weight;
802   int distance;
803   const int d;
804   const int c;
805 };
806 
807 // same as extrapolateMACSimple, but uses weight vec3 grid instead of flags to check
808 // for valid values (to be used in combination with mapPartsToMAC)
809 // note - the weight grid values are destroyed! the function is necessary due to discrepancies
810 // between velocity mapping on surface-levelset / fluid-flag creation. With this
811 // extrapolation we make sure the fluid region is covered by initial velocities
812 
extrapolateMACFromWeight(MACGrid & vel,Grid<Vec3> & weight,int distance=2)813 void extrapolateMACFromWeight(MACGrid &vel, Grid<Vec3> &weight, int distance = 2)
814 {
815   const int dim = (vel.is3D() ? 3 : 2);
816 
817   for (int c = 0; c < dim; ++c) {
818     Vec3i dir = 0;
819     dir[c] = 1;
820 
821     // reset weight values to 0 (uninitialized), and 1 (initialized inner values)
822     FOR_IJK_BND(vel, 1)
823     {
824       Vec3i p(i, j, k);
825       if (weight(p)[c] > 0.)
826         weight(p)[c] = 1.0;
827     }
828 
829     // extrapolate for distance
830     for (int d = 1; d < 1 + distance; ++d) {
831       knExtrapolateMACFromWeight(vel, weight, distance, d, c);
832     }  // d
833   }
834 }
_W_1(PyObject * _self,PyObject * _linargs,PyObject * _kwds)835 static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
836 {
837   try {
838     PbArgs _args(_linargs, _kwds);
839     FluidSolver *parent = _args.obtainParent();
840     bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
841     pbPreparePlugin(parent, "extrapolateMACFromWeight", !noTiming);
842     PyObject *_retval = 0;
843     {
844       ArgLocker _lock;
845       MACGrid &vel = *_args.getPtr<MACGrid>("vel", 0, &_lock);
846       Grid<Vec3> &weight = *_args.getPtr<Grid<Vec3>>("weight", 1, &_lock);
847       int distance = _args.getOpt<int>("distance", 2, 2, &_lock);
848       _retval = getPyNone();
849       extrapolateMACFromWeight(vel, weight, distance);
850       _args.check();
851     }
852     pbFinalizePlugin(parent, "extrapolateMACFromWeight", !noTiming);
853     return _retval;
854   }
855   catch (std::exception &e) {
856     pbSetError("extrapolateMACFromWeight", e.what());
857     return 0;
858   }
859 }
860 static const Pb::Register _RP_extrapolateMACFromWeight("", "extrapolateMACFromWeight", _W_1);
861 extern "C" {
PbRegister_extrapolateMACFromWeight()862 void PbRegister_extrapolateMACFromWeight()
863 {
864   KEEP_UNUSED(_RP_extrapolateMACFromWeight);
865 }
866 }
867 
868 // simple extrapolation functions for levelsets
869 
870 static const Vec3i nb[6] = {Vec3i(1, 0, 0),
871                             Vec3i(-1, 0, 0),
872                             Vec3i(0, 1, 0),
873                             Vec3i(0, -1, 0),
874                             Vec3i(0, 0, 1),
875                             Vec3i(0, 0, -1)};
876 
877 template<class S> struct knExtrapolateLsSimple : public KernelBase {
knExtrapolateLsSimpleManta::knExtrapolateLsSimple878   knExtrapolateLsSimple(Grid<S> &val, int distance, Grid<int> &tmp, const int d, S direction)
879       : KernelBase(&val, 1), val(val), distance(distance), tmp(tmp), d(d), direction(direction)
880   {
881     runMessage();
882     run();
883   }
opManta::knExtrapolateLsSimple884   inline void op(int i,
885                  int j,
886                  int k,
887                  Grid<S> &val,
888                  int distance,
889                  Grid<int> &tmp,
890                  const int d,
891                  S direction) const
892   {
893     const int dim = (val.is3D() ? 3 : 2);
894     if (tmp(i, j, k) != 0)
895       return;
896 
897     // copy from initialized neighbors
898     Vec3i p(i, j, k);
899     int nbs = 0;
900     S avg(0.);
901     for (int n = 0; n < 2 * dim; ++n) {
902       if (tmp(p + nb[n]) == d) {
903         avg += val(p + nb[n]);
904         nbs++;
905       }
906     }
907 
908     if (nbs > 0) {
909       tmp(p) = d + 1;
910       val(p) = avg / nbs + direction;
911     }
912   }
getArg0Manta::knExtrapolateLsSimple913   inline Grid<S> &getArg0()
914   {
915     return val;
916   }
917   typedef Grid<S> type0;
getArg1Manta::knExtrapolateLsSimple918   inline int &getArg1()
919   {
920     return distance;
921   }
922   typedef int type1;
getArg2Manta::knExtrapolateLsSimple923   inline Grid<int> &getArg2()
924   {
925     return tmp;
926   }
927   typedef Grid<int> type2;
getArg3Manta::knExtrapolateLsSimple928   inline const int &getArg3()
929   {
930     return d;
931   }
932   typedef int type3;
getArg4Manta::knExtrapolateLsSimple933   inline S &getArg4()
934   {
935     return direction;
936   }
937   typedef S type4;
runMessageManta::knExtrapolateLsSimple938   void runMessage()
939   {
940     debMsg("Executing kernel knExtrapolateLsSimple ", 3);
941     debMsg("Kernel range"
942                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
943            4);
944   };
operator ()Manta::knExtrapolateLsSimple945   void operator()(const tbb::blocked_range<IndexInt> &__r) const
946   {
947     const int _maxX = maxX;
948     const int _maxY = maxY;
949     if (maxZ > 1) {
950       for (int k = __r.begin(); k != (int)__r.end(); k++)
951         for (int j = 1; j < _maxY; j++)
952           for (int i = 1; i < _maxX; i++)
953             op(i, j, k, val, distance, tmp, d, direction);
954     }
955     else {
956       const int k = 0;
957       for (int j = __r.begin(); j != (int)__r.end(); j++)
958         for (int i = 1; i < _maxX; i++)
959           op(i, j, k, val, distance, tmp, d, direction);
960     }
961   }
runManta::knExtrapolateLsSimple962   void run()
963   {
964     if (maxZ > 1)
965       tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
966     else
967       tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
968   }
969   Grid<S> &val;
970   int distance;
971   Grid<int> &tmp;
972   const int d;
973   S direction;
974 };
975 
976 template<class S> struct knSetRemaining : public KernelBase {
knSetRemainingManta::knSetRemaining977   knSetRemaining(Grid<S> &phi, Grid<int> &tmp, S distance)
978       : KernelBase(&phi, 1), phi(phi), tmp(tmp), distance(distance)
979   {
980     runMessage();
981     run();
982   }
opManta::knSetRemaining983   inline void op(int i, int j, int k, Grid<S> &phi, Grid<int> &tmp, S distance) const
984   {
985     if (tmp(i, j, k) != 0)
986       return;
987     phi(i, j, k) = distance;
988   }
getArg0Manta::knSetRemaining989   inline Grid<S> &getArg0()
990   {
991     return phi;
992   }
993   typedef Grid<S> type0;
getArg1Manta::knSetRemaining994   inline Grid<int> &getArg1()
995   {
996     return tmp;
997   }
998   typedef Grid<int> type1;
getArg2Manta::knSetRemaining999   inline S &getArg2()
1000   {
1001     return distance;
1002   }
1003   typedef S type2;
runMessageManta::knSetRemaining1004   void runMessage()
1005   {
1006     debMsg("Executing kernel knSetRemaining ", 3);
1007     debMsg("Kernel range"
1008                << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
1009            4);
1010   };
operator ()Manta::knSetRemaining1011   void operator()(const tbb::blocked_range<IndexInt> &__r) const
1012   {
1013     const int _maxX = maxX;
1014     const int _maxY = maxY;
1015     if (maxZ > 1) {
1016       for (int k = __r.begin(); k != (int)__r.end(); k++)
1017         for (int j = 1; j < _maxY; j++)
1018           for (int i = 1; i < _maxX; i++)
1019             op(i, j, k, phi, tmp, distance);
1020     }
1021     else {
1022       const int k = 0;
1023       for (int j = __r.begin(); j != (int)__r.end(); j++)
1024         for (int i = 1; i < _maxX; i++)
1025           op(i, j, k, phi, tmp, distance);
1026     }
1027   }
runManta::knSetRemaining1028   void run()
1029   {
1030     if (maxZ > 1)
1031       tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
1032     else
1033       tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
1034   }
1035   Grid<S> &phi;
1036   Grid<int> &tmp;
1037   S distance;
1038 };
1039 
extrapolateLsSimple(Grid<Real> & phi,int distance=4,bool inside=false)1040 void extrapolateLsSimple(Grid<Real> &phi, int distance = 4, bool inside = false)
1041 {
1042   Grid<int> tmp(phi.getParent());
1043   tmp.clear();
1044   const int dim = (phi.is3D() ? 3 : 2);
1045 
1046   // by default, march outside
1047   Real direction = 1.;
1048   if (!inside) {
1049     // mark all inside
1050     FOR_IJK_BND(phi, 1)
1051     {
1052       if (phi(i, j, k) < 0.) {
1053         tmp(i, j, k) = 1;
1054       }
1055     }
1056   }
1057   else {
1058     direction = -1.;
1059     FOR_IJK_BND(phi, 1)
1060     {
1061       if (phi(i, j, k) > 0.) {
1062         tmp(i, j, k) = 1;
1063       }
1064     }
1065   }
1066   // + first layer around
1067   FOR_IJK_BND(phi, 1)
1068   {
1069     Vec3i p(i, j, k);
1070     if (tmp(p))
1071       continue;
1072     for (int n = 0; n < 2 * dim; ++n) {
1073       if (tmp(p + nb[n]) == 1) {
1074         tmp(i, j, k) = 2;
1075         n = 2 * dim;
1076       }
1077     }
1078   }
1079 
1080   // extrapolate for distance
1081   for (int d = 2; d < 1 + distance; ++d) {
1082     knExtrapolateLsSimple<Real>(phi, distance, tmp, d, direction);
1083   }
1084 
1085   // set all remaining cells to max
1086   knSetRemaining<Real>(phi, tmp, Real(direction * (distance + 2)));
1087 }
_W_2(PyObject * _self,PyObject * _linargs,PyObject * _kwds)1088 static PyObject *_W_2(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
1089 {
1090   try {
1091     PbArgs _args(_linargs, _kwds);
1092     FluidSolver *parent = _args.obtainParent();
1093     bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
1094     pbPreparePlugin(parent, "extrapolateLsSimple", !noTiming);
1095     PyObject *_retval = 0;
1096     {
1097       ArgLocker _lock;
1098       Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 0, &_lock);
1099       int distance = _args.getOpt<int>("distance", 1, 4, &_lock);
1100       bool inside = _args.getOpt<bool>("inside", 2, false, &_lock);
1101       _retval = getPyNone();
1102       extrapolateLsSimple(phi, distance, inside);
1103       _args.check();
1104     }
1105     pbFinalizePlugin(parent, "extrapolateLsSimple", !noTiming);
1106     return _retval;
1107   }
1108   catch (std::exception &e) {
1109     pbSetError("extrapolateLsSimple", e.what());
1110     return 0;
1111   }
1112 }
1113 static const Pb::Register _RP_extrapolateLsSimple("", "extrapolateLsSimple", _W_2);
1114 extern "C" {
PbRegister_extrapolateLsSimple()1115 void PbRegister_extrapolateLsSimple()
1116 {
1117   KEEP_UNUSED(_RP_extrapolateLsSimple);
1118 }
1119 }
1120 
1121 // extrapolate centered vec3 values from marked fluid cells
1122 
extrapolateVec3Simple(Grid<Vec3> & vel,Grid<Real> & phi,int distance=4,bool inside=false)1123 void extrapolateVec3Simple(Grid<Vec3> &vel, Grid<Real> &phi, int distance = 4, bool inside = false)
1124 {
1125   Grid<int> tmp(vel.getParent());
1126   tmp.clear();
1127   const int dim = (vel.is3D() ? 3 : 2);
1128 
1129   // mark initial cells, by default, march outside
1130   if (!inside) {
1131     // mark all inside
1132     FOR_IJK_BND(phi, 1)
1133     {
1134       if (phi(i, j, k) < 0.) {
1135         tmp(i, j, k) = 1;
1136       }
1137     }
1138   }
1139   else {
1140     FOR_IJK_BND(phi, 1)
1141     {
1142       if (phi(i, j, k) > 0.) {
1143         tmp(i, j, k) = 1;
1144       }
1145     }
1146   }
1147   // + first layer next to initial cells
1148   FOR_IJK_BND(vel, 1)
1149   {
1150     Vec3i p(i, j, k);
1151     if (tmp(p))
1152       continue;
1153     for (int n = 0; n < 2 * dim; ++n) {
1154       if (tmp(p + nb[n]) == 1) {
1155         tmp(i, j, k) = 2;
1156         n = 2 * dim;
1157       }
1158     }
1159   }
1160 
1161   for (int d = 2; d < 1 + distance; ++d) {
1162     knExtrapolateLsSimple<Vec3>(vel, distance, tmp, d, Vec3(0.));
1163   }
1164   knSetRemaining<Vec3>(vel, tmp, Vec3(0.));
1165 }
_W_3(PyObject * _self,PyObject * _linargs,PyObject * _kwds)1166 static PyObject *_W_3(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
1167 {
1168   try {
1169     PbArgs _args(_linargs, _kwds);
1170     FluidSolver *parent = _args.obtainParent();
1171     bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
1172     pbPreparePlugin(parent, "extrapolateVec3Simple", !noTiming);
1173     PyObject *_retval = 0;
1174     {
1175       ArgLocker _lock;
1176       Grid<Vec3> &vel = *_args.getPtr<Grid<Vec3>>("vel", 0, &_lock);
1177       Grid<Real> &phi = *_args.getPtr<Grid<Real>>("phi", 1, &_lock);
1178       int distance = _args.getOpt<int>("distance", 2, 4, &_lock);
1179       bool inside = _args.getOpt<bool>("inside", 3, false, &_lock);
1180       _retval = getPyNone();
1181       extrapolateVec3Simple(vel, phi, distance, inside);
1182       _args.check();
1183     }
1184     pbFinalizePlugin(parent, "extrapolateVec3Simple", !noTiming);
1185     return _retval;
1186   }
1187   catch (std::exception &e) {
1188     pbSetError("extrapolateVec3Simple", e.what());
1189     return 0;
1190   }
1191 }
1192 static const Pb::Register _RP_extrapolateVec3Simple("", "extrapolateVec3Simple", _W_3);
1193 extern "C" {
PbRegister_extrapolateVec3Simple()1194 void PbRegister_extrapolateVec3Simple()
1195 {
1196   KEEP_UNUSED(_RP_extrapolateVec3Simple);
1197 }
1198 }
1199 
1200 }  // namespace Manta
1201