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> φ
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> φ
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> φ
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