Skip to content

Commit 087efb7

Browse files
authored
Multigrid Linear System Solver (#104)
This revision includes: * Successive Over-Relaxation (SOR) method implementation * Red-black Gauss-Seidel method implementation * Multigrid (MG) method implementation (Issue #17) * Multigrid Preconditioned Conjugate Gradient (MGPCG) method implementation (Issue #17) * Python bindings for all the new APIs for the new solvers above
1 parent eba14ba commit 087efb7

64 files changed

Lines changed: 3905 additions & 852 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

include/jet/detail/cg-inl.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ void pcg(
3434
BlasType::set(0, q);
3535
BlasType::set(0, s);
3636

37-
M->build(A);
38-
3937
// r = b - Ax
4038
BlasType::residual(A, *x, b, r);
4139

@@ -90,7 +88,9 @@ void pcg(
9088
}
9189

9290
*lastNumberOfIterations = iter;
93-
*lastResidualNorm = std::sqrt(sigmaNew);
91+
92+
// std::fabs(sigmaNew) - Workaround for negative zero
93+
*lastResidualNorm = std::sqrt(std::fabs(sigmaNew));
9494
}
9595

9696
template <typename BlasType>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright (c) 2017 Doyub Kim
2+
//
3+
// I am making my contributions/submissions to this project solely in my
4+
// personal capacity and am not conveying any rights to any intellectual
5+
// property of any third parties.
6+
7+
#ifndef INCLUDE_JET_FDM_MG_LINEAR_SYSTEM2_INL_H_
8+
#define INCLUDE_JET_FDM_MG_LINEAR_SYSTEM2_INL_H_
9+
10+
#include <jet/fdm_mg_linear_system2.h>
11+
12+
namespace jet {
13+
14+
template <typename T>
15+
void FdmMgUtils2::resizeArrayWithCoarsest(const Size2& coarsestResolution,
16+
size_t numberOfLevels,
17+
std::vector<Array2<T>>* levels) {
18+
numberOfLevels = std::max(numberOfLevels, kOneSize);
19+
20+
levels->resize(numberOfLevels);
21+
22+
// Level 0 is the finest level, thus takes coarsestResolution ^
23+
// numberOfLevels.
24+
// Level numberOfLevels - 1 is the coarsest, taking coarsestResolution.
25+
Size2 res = coarsestResolution;
26+
for (size_t level = 0; level < numberOfLevels; ++level) {
27+
(*levels)[numberOfLevels - level - 1].resize(res);
28+
res.x = res.x << 1;
29+
res.y = res.y << 1;
30+
}
31+
}
32+
33+
template <typename T>
34+
void FdmMgUtils2::resizeArrayWithFinest(const Size2& finestResolution,
35+
size_t maxNumberOfLevels,
36+
std::vector<Array2<T>>* levels) {
37+
Size2 res = finestResolution;
38+
size_t i = 1;
39+
for (; i < maxNumberOfLevels; ++i) {
40+
if (res.x % 2 == 0 && res.y % 2 == 0) {
41+
res.x = res.x >> 1;
42+
res.y = res.y >> 1;
43+
} else {
44+
break;
45+
}
46+
}
47+
resizeArrayWithCoarsest(res, i, levels);
48+
}
49+
50+
} // namespace jet
51+
52+
#endif // INCLUDE_JET_FDM_MG_LINEAR_SYSTEM2_INL_H_
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2017 Doyub Kim
2+
//
3+
// I am making my contributions/submissions to this project solely in my
4+
// personal capacity and am not conveying any rights to any intellectual
5+
// property of any third parties.
6+
7+
#ifndef INCLUDE_JET_FDM_MG_LINEAR_SYSTEM3_INL_H_
8+
#define INCLUDE_JET_FDM_MG_LINEAR_SYSTEM3_INL_H_
9+
10+
#include <jet/fdm_mg_linear_system3.h>
11+
12+
namespace jet {
13+
14+
template <typename T>
15+
void FdmMgUtils3::resizeArrayWithCoarsest(const Size3& coarsestResolution,
16+
size_t numberOfLevels,
17+
std::vector<Array3<T>>* levels) {
18+
numberOfLevels = std::max(numberOfLevels, kOneSize);
19+
20+
levels->resize(numberOfLevels);
21+
22+
// Level 0 is the finest level, thus takes coarsestResolution ^
23+
// numberOfLevels.
24+
// Level numberOfLevels - 1 is the coarsest, taking coarsestResolution.
25+
Size3 res = coarsestResolution;
26+
for (size_t level = 0; level < numberOfLevels; ++level) {
27+
(*levels)[numberOfLevels - level - 1].resize(res);
28+
res.x = res.x << 1;
29+
res.y = res.y << 1;
30+
res.z = res.z << 1;
31+
}
32+
}
33+
34+
template <typename T>
35+
void FdmMgUtils3::resizeArrayWithFinest(const Size3& finestResolution,
36+
size_t maxNumberOfLevels,
37+
std::vector<Array3<T>>* levels) {
38+
Size3 res = finestResolution;
39+
size_t i = 1;
40+
for (; i < maxNumberOfLevels; ++i) {
41+
if (res.x % 2 == 0 && res.y % 2 == 0 && res.z % 2 == 0) {
42+
res.x = res.x >> 1;
43+
res.y = res.y >> 1;
44+
res.z = res.z >> 1;
45+
} else {
46+
break;
47+
}
48+
}
49+
resizeArrayWithCoarsest(res, i, levels);
50+
}
51+
52+
} // namespace jet
53+
54+
#endif // INCLUDE_JET_FDM_MG_LINEAR_SYSTEM3_INL_H_

include/jet/detail/math_utils-inl.h

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ inline T max3(T x, T y, T z) {
3838
return std::max(std::max(x, y), z);
3939
}
4040

41-
//! Returns minimum among n-elements.
4241
template <typename T>
4342
inline T minn(const T* x, size_t n) {
4443
T m = x[0];
@@ -48,7 +47,6 @@ inline T minn(const T* x, size_t n) {
4847
return m;
4948
}
5049

51-
//! Returns maximum among n-elements.
5250
template <typename T>
5351
inline T maxn(const T* x, size_t n) {
5452
T m = x[0];
@@ -68,7 +66,6 @@ inline T absmax(T x, T y) {
6866
return (x*x > y*y) ? x : y;
6967
}
7068

71-
//! Returns absolute minimum among n-elements.
7269
template <typename T>
7370
inline T absminn(const T* x, size_t n) {
7471
T m = x[0];
@@ -78,7 +75,6 @@ inline T absminn(const T* x, size_t n) {
7875
return m;
7976
}
8077

81-
//! Returns absolute maximum among n-elements.
8278
template <typename T>
8379
inline T absmaxn(const T* x, size_t n) {
8480
T m = x[0];
@@ -88,6 +84,34 @@ inline T absmaxn(const T* x, size_t n) {
8884
return m;
8985
}
9086

87+
template <typename T>
88+
inline size_t argmin2(T x, T y) {
89+
return (x < y) ? 0 : 1;
90+
}
91+
92+
template <typename T>
93+
inline size_t argmax2(T x, T y) {
94+
return (x > y) ? 0 : 1;
95+
}
96+
97+
template <typename T>
98+
inline size_t argmin3(T x, T y, T z) {
99+
if (x < y) {
100+
return (x < z) ? 0 : 2;
101+
} else {
102+
return (y < z) ? 1 : 2;
103+
}
104+
}
105+
106+
template <typename T>
107+
inline size_t argmax3(T x, T y, T z) {
108+
if (x > y) {
109+
return (x > z) ? 0 : 2;
110+
} else {
111+
return (y > z) ? 1 : 2;
112+
}
113+
}
114+
91115
template <typename T>
92116
inline T square(T x) {
93117
return x * x;

include/jet/detail/mg-inl.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ MgResult mgVCycle(const MgMatrix<BlasType>& A, MgParameters<BlasType> params,
2323
&((*x)[currentLevel]), &((*buffer)[currentLevel]));
2424

2525
// 2) if currentLevel is the coarsest grid, goto 5)
26-
if (currentLevel < params.maxNumberOfLevels - 1) {
26+
if (currentLevel < A.levels.size() - 1) {
2727
auto r = buffer;
2828
BlasType::residual(A[currentLevel], (*x)[currentLevel],
2929
(*b)[currentLevel], &(*r)[currentLevel]);
@@ -80,6 +80,16 @@ typename BlasType::MatrixType& MgMatrix<BlasType>::operator[](size_t i) {
8080
return levels[i];
8181
}
8282

83+
template <typename BlasType>
84+
const typename BlasType::MatrixType& MgMatrix<BlasType>::finest() const {
85+
return levels.front();
86+
}
87+
88+
template <typename BlasType>
89+
typename BlasType::MatrixType& MgMatrix<BlasType>::finest() {
90+
return levels.front();
91+
}
92+
8393
template <typename BlasType>
8494
const typename BlasType::VectorType& MgVector<BlasType>::operator[](
8595
size_t i) const {
@@ -91,6 +101,16 @@ typename BlasType::VectorType& MgVector<BlasType>::operator[](size_t i) {
91101
return levels[i];
92102
}
93103

104+
template <typename BlasType>
105+
const typename BlasType::VectorType& MgVector<BlasType>::finest() const {
106+
return levels.front();
107+
}
108+
109+
template <typename BlasType>
110+
typename BlasType::VectorType& MgVector<BlasType>::finest() {
111+
return levels.front();
112+
}
113+
94114
template <typename BlasType>
95115
MgResult mgVCycle(const MgMatrix<BlasType>& A, MgParameters<BlasType> params,
96116
MgVector<BlasType>* x, MgVector<BlasType>* b,

include/jet/detail/parallel-inl.h

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,26 +158,80 @@ void parallelFor(IndexType start, IndexType end, const Function& func,
158158
}
159159
}
160160

161+
template <typename IndexType, typename Function>
162+
void parallelRangeFor(IndexType start, IndexType end, const Function& func,
163+
ExecutionPolicy policy) {
164+
if (start > end) {
165+
return;
166+
}
167+
168+
// Estimate number of threads in the pool
169+
static const unsigned int numThreadsHint =
170+
std::thread::hardware_concurrency();
171+
const unsigned int numThreads =
172+
(policy == ExecutionPolicy::kParallel)
173+
? (numThreadsHint == 0u ? 8u : numThreadsHint)
174+
: 1;
175+
176+
// Size of a slice for the range functions
177+
IndexType n = end - start + 1;
178+
IndexType slice =
179+
(IndexType)std::round(n / static_cast<double>(numThreads));
180+
slice = std::max(slice, IndexType(1));
181+
182+
// Create pool and launch jobs
183+
std::vector<std::thread> pool;
184+
pool.reserve(numThreads);
185+
IndexType i1 = start;
186+
IndexType i2 = std::min(start + slice, end);
187+
for (unsigned int i = 0; i + 1 < numThreads && i1 < end; ++i) {
188+
pool.emplace_back(func, i1, i2);
189+
i1 = i2;
190+
i2 = std::min(i2 + slice, end);
191+
}
192+
if (i1 < end) {
193+
pool.emplace_back(func, i1, end);
194+
}
195+
196+
// Wait for jobs to finish
197+
for (std::thread& t : pool) {
198+
if (t.joinable()) {
199+
t.join();
200+
}
201+
}
202+
}
203+
161204
template <typename IndexType, typename Function>
162205
void parallelFor(IndexType beginIndexX, IndexType endIndexX,
163206
IndexType beginIndexY, IndexType endIndexY,
164207
const Function& function, ExecutionPolicy policy) {
165208
parallelFor(beginIndexY, endIndexY,
166-
[&](size_t j) {
209+
[&](IndexType j) {
167210
for (IndexType i = beginIndexX; i < endIndexX; ++i) {
168211
function(i, j);
169212
}
170213
},
171214
policy);
172215
}
173216

217+
template <typename IndexType, typename Function>
218+
void parallelRangeFor(IndexType beginIndexX, IndexType endIndexX,
219+
IndexType beginIndexY, IndexType endIndexY,
220+
const Function& function, ExecutionPolicy policy) {
221+
parallelRangeFor(beginIndexY, endIndexY,
222+
[&](IndexType jBegin, IndexType jEnd) {
223+
function(beginIndexX, endIndexX, jBegin, jEnd);
224+
},
225+
policy);
226+
}
227+
174228
template <typename IndexType, typename Function>
175229
void parallelFor(IndexType beginIndexX, IndexType endIndexX,
176230
IndexType beginIndexY, IndexType endIndexY,
177231
IndexType beginIndexZ, IndexType endIndexZ,
178232
const Function& function, ExecutionPolicy policy) {
179233
parallelFor(beginIndexZ, endIndexZ,
180-
[&](size_t k) {
234+
[&](IndexType k) {
181235
for (IndexType j = beginIndexY; j < endIndexY; ++j) {
182236
for (IndexType i = beginIndexX; i < endIndexX; ++i) {
183237
function(i, j, k);
@@ -187,6 +241,19 @@ void parallelFor(IndexType beginIndexX, IndexType endIndexX,
187241
policy);
188242
}
189243

244+
template <typename IndexType, typename Function>
245+
void parallelRangeFor(IndexType beginIndexX, IndexType endIndexX,
246+
IndexType beginIndexY, IndexType endIndexY,
247+
IndexType beginIndexZ, IndexType endIndexZ,
248+
const Function& function, ExecutionPolicy policy) {
249+
parallelRangeFor(beginIndexZ, endIndexZ,
250+
[&](IndexType kBegin, IndexType kEnd) {
251+
function(beginIndexX, endIndexX, beginIndexY,
252+
endIndexY, kBegin, kEnd);
253+
},
254+
policy);
255+
}
256+
190257
template <typename IndexType, typename Value, typename Function,
191258
typename Reduce>
192259
Value parallelReduce(IndexType start, IndexType end, const Value& identity,

include/jet/fdm_gauss_seidel_solver2.h

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ namespace jet {
1616
class FdmGaussSeidelSolver2 final : public FdmLinearSystemSolver2 {
1717
public:
1818
//! Constructs the solver with given parameters.
19-
FdmGaussSeidelSolver2(
20-
unsigned int maxNumberOfIterations,
21-
unsigned int residualCheckInterval,
22-
double tolerance);
19+
FdmGaussSeidelSolver2(unsigned int maxNumberOfIterations,
20+
unsigned int residualCheckInterval, double tolerance,
21+
double sorFactor = 1.0,
22+
bool useRedBlackOrdering = false);
2323

2424
//! Solves the given linear system.
2525
bool solve(FdmLinearSystem2* system) override;
@@ -36,16 +36,30 @@ class FdmGaussSeidelSolver2 final : public FdmLinearSystemSolver2 {
3636
//! Returns the last residual after the Gauss-Seidel iterations.
3737
double lastResidual() const;
3838

39+
//! Returns the SOR (Successive Over Relaxation) factor.
40+
double sorFactor() const;
41+
42+
//! Returns true if red-black ordering is enabled.
43+
bool useRedBlackOrdering() const;
44+
45+
//! Performs single natural Gauss-Seidel relaxation step.
46+
static void relax(const FdmMatrix2& A, const FdmVector2& b,
47+
double sorFactor, FdmVector2* x);
48+
49+
//! Performs single Red-Black Gauss-Seidel relaxation step.
50+
static void relaxRedBlack(const FdmMatrix2& A, const FdmVector2& b,
51+
double sorFactor, FdmVector2* x);
52+
3953
private:
4054
unsigned int _maxNumberOfIterations;
4155
unsigned int _lastNumberOfIterations;
4256
unsigned int _residualCheckInterval;
4357
double _tolerance;
4458
double _lastResidual;
59+
double _sorFactor;
60+
bool _useRedBlackOrdering;
4561

4662
FdmVector2 _residual;
47-
48-
void relax(FdmLinearSystem2* system);
4963
};
5064

5165
//! Shared pointer type for the FdmGaussSeidelSolver2.

0 commit comments

Comments
 (0)