Skip to content

Commit e677840

Browse files
authored
Improved variational pressure projection (#89)
* Fix bug on the boundary condition solver * Use better fraction calculation based on Christopher Batty's Fluid3D code
1 parent ce3990a commit e677840

4 files changed

Lines changed: 206 additions & 98 deletions

File tree

3RD_PARTY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,3 +397,7 @@ The above copyright notice and this permission notice shall be included in all c
397397

398398
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
399399

400+
---
401+
402+
Jet uses portion of Fluid3D by Christopher Batty.
403+
Original code from: https://github.com/christopherbatty/Fluid3D

include/jet/detail/level_set_utils-inl.h

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
// I am making my contributions/submissions to this project solely in my
44
// personal capacity and am not conveying any rights to any intellectual
55
// property of any third parties.
6+
//
7+
// Function fractionInside is originally from Christopher Batty's code:
8+
//
9+
// http://www.cs.ubc.ca/labs/imager/tr/2007/Batty_VariationalFluids/
10+
//
11+
// and
12+
//
13+
// https://github.com/christopherbatty/Fluid3D
614

715
#ifndef INCLUDE_JET_DETAIL_LEVEL_SET_UTILS_INL_H_
816
#define INCLUDE_JET_DETAIL_LEVEL_SET_UTILS_INL_H_
917

10-
// Function fractionInside is from
11-
// http://www.cs.ubc.ca/labs/imager/tr/2007/Batty_VariationalFluids/
12-
1318
#include <jet/constants.h>
1419
#include <cmath>
1520

@@ -28,9 +33,8 @@ inline T smearedHeavisideSdf(T phi) {
2833
if (phi < -1.5) {
2934
return 0;
3035
} else {
31-
return 0.5f
32-
+ phi / 3.0
33-
+ 0.5f * invPi<T>() * std::sin(pi<T>() * phi / 1.5);
36+
return 0.5f + phi / 3.0 +
37+
0.5f * invPi<T>() * std::sin(pi<T>() * phi / 1.5);
3438
}
3539
}
3640
}
@@ -40,8 +44,7 @@ inline T smearedDeltaSdf(T phi) {
4044
if (std::fabs(phi) > 1.5) {
4145
return 0;
4246
} else {
43-
return 1.0 / 3.0
44-
+ 1.0/3.0 * std::cos(pi<T>() * phi / 1.5);
47+
return 1.0 / 3.0 + 1.0 / 3.0 * std::cos(pi<T>() * phi / 1.5);
4548
}
4649
}
4750

@@ -58,6 +61,91 @@ T fractionInsideSdf(T phi0, T phi1) {
5861
}
5962
}
6063

64+
template <typename T>
65+
void cycleArray(T* arr, int size) {
66+
T t = arr[0];
67+
for (int i = 0; i < size - 1; ++i) arr[i] = arr[i + 1];
68+
arr[size - 1] = t;
69+
}
70+
71+
template <typename T>
72+
T fractionInside(T phiBottomLeft, T phiBottomRight, T phiTopLeft,
73+
T phiTopRight) {
74+
int inside_count = (phiBottomLeft < 0 ? 1 : 0) + (phiTopLeft < 0 ? 1 : 0) +
75+
(phiBottomRight < 0 ? 1 : 0) + (phiTopRight < 0 ? 1 : 0);
76+
T list[] = {phiBottomLeft, phiBottomRight, phiTopRight, phiTopLeft};
77+
78+
if (inside_count == 4) {
79+
return 1;
80+
} else if (inside_count == 3) {
81+
// rotate until the positive value is in the first position
82+
while (list[0] < 0) {
83+
cycleArray(list, 4);
84+
}
85+
86+
// Work out the area of the exterior triangle
87+
T side0 = 1 - fractionInsideSdf(list[0], list[3]);
88+
T side1 = 1 - fractionInsideSdf(list[0], list[1]);
89+
return 1 - 0.5f * side0 * side1;
90+
} else if (inside_count == 2) {
91+
// rotate until a negative value is in the first position, and the next
92+
// negative is in either slot 1 or 2.
93+
while (list[0] >= 0 || !(list[1] < 0 || list[2] < 0)) {
94+
cycleArray(list, 4);
95+
}
96+
97+
if (list[1] < 0) { // the matching signs are adjacent
98+
T side_left = fractionInsideSdf(list[0], list[3]);
99+
T side_right = fractionInsideSdf(list[1], list[2]);
100+
return 0.5f * (side_left + side_right);
101+
} else { // matching signs are diagonally opposite
102+
// determine the centre point's sign to disambiguate this case
103+
T middle_point = 0.25f * (list[0] + list[1] + list[2] + list[3]);
104+
if (middle_point < 0) {
105+
T area = 0;
106+
107+
// first triangle (top left)
108+
T side1 = 1 - fractionInsideSdf(list[0], list[3]);
109+
T side3 = 1 - fractionInsideSdf(list[2], list[3]);
110+
111+
area += 0.5f * side1 * side3;
112+
113+
// second triangle (top right)
114+
T side2 = 1 - fractionInsideSdf(list[2], list[1]);
115+
T side0 = 1 - fractionInsideSdf(list[0], list[1]);
116+
area += 0.5f * side0 * side2;
117+
118+
return 1 - area;
119+
} else {
120+
T area = 0;
121+
122+
// first triangle (bottom left)
123+
T side0 = fractionInsideSdf(list[0], list[1]);
124+
T side1 = fractionInsideSdf(list[0], list[3]);
125+
area += 0.5f * side0 * side1;
126+
127+
// second triangle (top right)
128+
T side2 = fractionInsideSdf(list[2], list[1]);
129+
T side3 = fractionInsideSdf(list[2], list[3]);
130+
area += 0.5f * side2 * side3;
131+
return area;
132+
}
133+
}
134+
} else if (inside_count == 1) {
135+
// rotate until the negative value is in the first position
136+
while (list[0] >= 0) {
137+
cycleArray(list, 4);
138+
}
139+
140+
// Work out the area of the interior triangle, and subtract from 1.
141+
T side0 = fractionInsideSdf(list[0], list[3]);
142+
T side1 = fractionInsideSdf(list[0], list[1]);
143+
return 0.5f * side0 * side1;
144+
} else {
145+
return 0;
146+
}
147+
}
148+
61149
template <typename T>
62150
T distanceToZeroLevelSet(T phi0, T phi1) {
63151
if (std::fabs(phi0) + std::fabs(phi1) > kEpsilonD) {

include/jet/level_set_utils.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,27 @@ T smearedDeltaSdf(T phi);
8080
template <typename T>
8181
T fractionInsideSdf(T phi0, T phi1);
8282

83+
//!
84+
//! \brief Returns the fraction occupied by the implicit surface.
85+
//!
86+
//! Given four signed distance values (square corners), determine what fraction
87+
//! of the square is "inside". The original implementation can be found from
88+
//! Christopher Batty's variational fluid code at
89+
//! https://github.com/christopherbatty/Fluid3D.
90+
//!
91+
//! \tparam T Value type.
92+
//!
93+
//! \param phiBottomLeft The level set value on the bottom-left corner.
94+
//! \param phiBottomRight The level set value on the bottom-right corner.
95+
//! \param phiTopLeft The level set value on the top-left corner.
96+
//! \param phiTopRight The level set value on the top-right corner.
97+
//!
98+
//! \return The fraction occupied by the implicit surface.
99+
//!
100+
template <typename T>
101+
T fractionInside(T phiBottomLeft, T phiBottomRight, T phiTopLeft,
102+
T phiTopRight);
103+
83104
} // namespace jet
84105

85106
#include "detail/level_set_utils-inl.h"

0 commit comments

Comments
 (0)