|
2 | 2 |
|
3 | 3 | #include "../smoother.h" |
4 | 4 |
|
| 5 | +// The smoother implements the coupled circle-radial smoothing procedure. |
| 6 | +// It performs iterative updates on different parts of the grid based |
| 7 | +// on the circle/radial section of the grid and black/white line coloring. |
| 8 | +// |
| 9 | +// The smoother solves linear systems of the form: |
| 10 | +// A_sc * u_sc = f_sc − A_sc^ortho * u_sc^ortho |
| 11 | +// where: |
| 12 | +// - s in {Circle, Radial} denotes the smoother section type, |
| 13 | +// - c in {Black, White} denotes the coloring (even/odd line sub-system). |
| 14 | +// |
| 15 | +// The update sequence is as follows: |
| 16 | +// 1. Black-Circle update (u_bc): |
| 17 | +// A_bc * u_bc = f_bc − A_bc^ortho * u_bc^ortho |
| 18 | +// 2. White-Circle update (u_wc): |
| 19 | +// A_wc * u_wc = f_wc − A_wc^ortho * u_wc^ortho |
| 20 | +// 3. Black-Radial update (u_br): |
| 21 | +// A_br * u_br = f_br − A_br^ortho * u_br^ortho |
| 22 | +// 4. White-Radial update (u_wr): |
| 23 | +// A_wr * u_wr = f_wr − A_wr^ortho * u_wr^ortho |
| 24 | +// |
| 25 | +// Algorithm details: |
| 26 | +// - 'rhs' corresponds to the f vector, 'x' stores the final solution, |
| 27 | +// and 'temp' is used for temporary storage during updates. |
| 28 | +// - First, temp is updated with f_sc − A_sc^ortho * u_sc^ortho. |
| 29 | +// - The system is then solved in-place in temp, and the results |
| 30 | +// are copied back to x. |
| 31 | +// - Using 'temp' isn't strictly necessary as all updates could be performed in place in 'x'. |
| 32 | +// - The stencil is applied using the A-Give method. |
| 33 | +// |
| 34 | +// Solver and matrix structure: |
| 35 | +// - The matrix A_sc is block tridiagonal due to the smoother-based |
| 36 | +// grid indexing, which allows efficient line-wise factorization. |
| 37 | +// - The inner boundary requires special handling because it |
| 38 | +// contains an additional across-origin coupling, making it |
| 39 | +// non-tridiagonal; therefore, a more general solver is used there. |
| 40 | +// When using the MUMPS solver, the matrix is assembled in COO format. |
| 41 | +// When using the in-house solver, the matrix is stored in CSR format. |
| 42 | +// - Circular line matrices are cyclic tridiagonal due to angular |
| 43 | +// periodicity, whereas radial line matrices are strictly tridiagonal. |
| 44 | +// - Dirichlet boundary contributions in radial matrices are shifted |
| 45 | +// into the right-hand side to make A_sc symmetric. |
| 46 | + |
5 | 47 | class SmootherGive : public Smoother |
6 | 48 | { |
7 | 49 | public: |
| 50 | + // Constructs the coupled circle-radial smoother. |
| 51 | + // Builds the A_sc smoother matrices and prepares the solvers. |
8 | 52 | explicit SmootherGive(const PolarGrid& grid, const LevelCache& level_cache, const DomainGeometry& domain_geometry, |
9 | 53 | const DensityProfileCoefficients& density_profile_coefficients, bool DirBC_Interior, |
10 | 54 | int num_omp_threads); |
| 55 | + |
| 56 | + // If MUMPS is enabled, this cleans up the inner boundary solver. |
11 | 57 | ~SmootherGive() override; |
12 | 58 |
|
| 59 | + // Performs one full coupled smoothing sweep: |
| 60 | + // BC -> WC -> BR -> WR |
| 61 | + // Parallel implementation using OpenMP: |
| 62 | + // Scedule every 2nd/4th line in parallel to avoid race conditions arising from the A-Give distribution. |
| 63 | + // Sceduling every 3rd line in parallel would also be possible, but is less natural for the 2 coloring. |
13 | 64 | void smoothing(Vector<double> x, ConstVector<double> rhs, Vector<double> temp) override; |
14 | 65 |
|
15 | 66 | private: |
16 | | - void smoothingSequential(Vector<double> x, ConstVector<double> rhs, Vector<double> temp); |
17 | | - void smoothingForLoop(Vector<double> x, ConstVector<double> rhs, Vector<double> temp); |
18 | | - |
19 | | - // The A_sc matrix on i_r = 0 is defined through the COO/CSR matrix |
20 | | - // 'inner_boundary_circle_matrix_' due to the across-origin treatment. |
21 | | - // It isn't tridiagonal and thus it requires a more advanced solver. |
22 | | - // Note that circle_tridiagonal_solver_[0] is thus unused! |
23 | | - // Additionally 'circle_tridiagonal_solver_[index]' will refer to the circular line i_r = index and |
24 | | - // 'radial_tridiagonal_solver_[index] will refer to the radial line i_theta = index. |
| 67 | + /* ------------------- */ |
| 68 | + /* Tridiagonal solvers */ |
| 69 | + /* ------------------- */ |
| 70 | + |
| 71 | + // Batched solver for cyclic-tridiagonal circle line A_sc matrices. |
| 72 | + BatchedTridiagonalSolver<double> circle_tridiagonal_solver_; |
| 73 | + |
| 74 | + // Batched solver for tridiagonal radial circle line A_sc matrices. |
| 75 | + BatchedTridiagonalSolver<double> radial_tridiagonal_solver_; |
| 76 | + |
| 77 | + // The A_sc matrix on i_r = 0 (inner circle) is NOT tridiagonal because |
| 78 | + // it potentially includes across-origin coupling. Therefore, it is assembled |
| 79 | + // into a sparse matrix and solved using a general-purpose sparse solver. |
| 80 | + // When using the MUMPS solver, the matrix is assembled in COO format. |
| 81 | + // When using the in-house solver, the matrix is stored in CSR format. |
25 | 82 | #ifdef GMGPOLAR_USE_MUMPS |
26 | 83 | using MatrixType = SparseMatrixCOO<double>; |
27 | 84 | DMUMPS_STRUC_C inner_boundary_mumps_solver_; |
28 | 85 | #else |
29 | 86 | using MatrixType = SparseMatrixCSR<double>; |
30 | 87 | SparseLUSolver<double> inner_boundary_lu_solver_; |
31 | 88 | #endif |
| 89 | + // Sparse matrix for the non-tridiagonal inner boundary circle block. |
32 | 90 | MatrixType inner_boundary_circle_matrix_; |
33 | 91 |
|
34 | | - std::vector<SymmetricTridiagonalSolver<double>> circle_tridiagonal_solver_; |
35 | | - std::vector<SymmetricTridiagonalSolver<double>> radial_tridiagonal_solver_; |
| 92 | + // Note: |
| 93 | + // - circle_tridiagonal_solver_[batch=0] is unused. Use the COO/CSR matrix instead. |
| 94 | + // - circle_tridiagonal_solver_[batch=i_r] solves circle line i_r. |
| 95 | + // - radial_tridiagonal_solver_[batch=i_theta] solves radial line i_theta. |
| 96 | + |
| 97 | + /* ------------------- */ |
| 98 | + /* Stencil definitions */ |
| 99 | + /* ------------------- */ |
| 100 | + |
| 101 | + // Stencils encode neighborhood connectivity for A_sc matrix assembly. |
| 102 | + // It is only used in the construction of COO/CSR matrices. |
| 103 | + // Thus it is only used for the interior boundary matrix and not needed for the tridiagonal matrices. |
| 104 | + // The Stencil class stores the offset for each position. |
| 105 | + // - Non-zero matrix indicesare obtained via `ptr + offset` |
| 106 | + // - A offset value of `-1` means the position is not included in the stencil pattern. |
| 107 | + // - Other values (0, 1, 2, ..., stencil_size - 1) correspond to valid stencil indices. |
36 | 108 |
|
37 | 109 | // clang-format off |
38 | 110 | const Stencil stencil_DB_ = { |
39 | 111 | -1, -1, -1, |
40 | 112 | -1, 0, -1, |
41 | 113 | -1, -1, -1 |
42 | 114 | }; |
43 | | - /* Circle Stencils */ |
44 | | - const Stencil circle_stencil_interior_ = { |
45 | | - -1, 2, -1, |
46 | | - -1, 0, -1, |
47 | | - -1, 1, -1 |
48 | | - }; |
49 | 115 | const Stencil circle_stencil_across_origin_ = { |
50 | 116 | -1, 3, -1, |
51 | 117 | 1, 0, -1, |
52 | 118 | -1, 2, -1 |
53 | 119 | }; |
54 | | - /* Radial Stencils */ |
55 | | - const Stencil radial_stencil_interior_ = { |
56 | | - -1, -1, -1, |
57 | | - 1, 0, 2, |
58 | | - -1, -1, -1 |
59 | | - }; |
60 | | - const Stencil radial_stencil_next_outer_DB_ = { |
61 | | - -1, -1, -1, |
62 | | - 1, 0, -1, |
63 | | - -1, -1, -1 |
64 | | - }; |
65 | | - const Stencil radial_stencil_next_circular_smoothing_ = { |
66 | | - -1, -1, -1, |
67 | | - -1, 0, 1, |
68 | | - -1, -1, -1 |
69 | | - }; |
| 120 | + |
70 | 121 | // clang-format on |
71 | 122 |
|
72 | | - const Stencil& getStencil(int i_r) const; |
73 | | - int getNonZeroCountCircleAsc(const int i_r) const; |
74 | | - int getNonZeroCountRadialAsc(const int i_theta) const; |
| 123 | + // Select correct stencil depending on the grid position. |
| 124 | + const Stencil& getStencil(int i_r) const; /* Only i_r = 0 implemented */ |
| 125 | + // Number of nonzero A_sc entries. |
| 126 | + int getNonZeroCountCircleAsc(int i_r) const; /* Only i_r = 0 implemented */ |
| 127 | + // Obtain a ptr to index into COO matrices. |
| 128 | + // It accumulates all stencil sizes within a line up to, but excluding the current node. |
| 129 | + int getCircleAscIndex(int i_r, int i_theta) const; /* Only i_r = 0 implemented */ |
75 | 130 |
|
76 | | - int getCircleAscIndex(const int i_r, const int i_theta) const; |
77 | | - int getRadialAscIndex(const int i_r, const int i_theta) const; |
| 131 | + /* --------------- */ |
| 132 | + /* Matrix assembly */ |
| 133 | + /* --------------- */ |
78 | 134 |
|
| 135 | + // Build all A_sc matrices for circle and radial smoothers. |
79 | 136 | void buildAscMatrices(); |
80 | | - void buildAscCircleSection(const int i_r); |
81 | | - void buildAscRadialSection(const int i_theta); |
| 137 | + // Build A_sc matrix block for a single circular line. |
| 138 | + void buildAscCircleSection(int i_r); |
| 139 | + // Build A_sc matrix block for a single radial line. |
| 140 | + void buildAscRadialSection(int i_theta); |
| 141 | + // Build A_sc for a specific node (i_r, i_theta) |
| 142 | + void nodeBuildAscGive(int i_r, int i_theta, const PolarGrid& grid, bool DirBC_Interior, |
| 143 | + MatrixType& inner_boundary_circle_matrix, |
| 144 | + BatchedTridiagonalSolver<double>& circle_tridiagonal_solver, |
| 145 | + BatchedTridiagonalSolver<double>& radial_tridiagonal_solver, double arr, double att, |
| 146 | + double art, double detDF, double coeff_beta); |
| 147 | + |
| 148 | + /* ---------------------- */ |
| 149 | + /* Orthogonal application */ |
| 150 | + /* ---------------------- */ |
82 | 151 |
|
83 | | - void applyAscOrthoCircleSection(const int i_r, const SmootherColor smoother_color, ConstVector<double> x, |
| 152 | + // Compute temp = f_sc − A_sc^ortho * u_sc^ortho (precomputed right-hand side) |
| 153 | + // where x = u_sc and rhs = f_sc |
| 154 | + void applyAscOrthoCircleSection(int i_r, const SmootherColor smoother_color, ConstVector<double> x, |
84 | 155 | ConstVector<double> rhs, Vector<double> temp); |
85 | | - void applyAscOrthoRadialSection(const int i_theta, const SmootherColor smoother_color, ConstVector<double> x, |
| 156 | + void applyAscOrthoRadialSection(int i_theta, const SmootherColor smoother_color, ConstVector<double> x, |
86 | 157 | ConstVector<double> rhs, Vector<double> temp); |
87 | 158 |
|
88 | | - void solveCircleSection(const int i_r, Vector<double> x, Vector<double> temp, Vector<double> solver_storage_1, |
89 | | - Vector<double> solver_storage_2); |
90 | | - void solveRadialSection(const int i_theta, Vector<double> x, Vector<double> temp, Vector<double> solver_storage); |
| 159 | + /* ----------------- */ |
| 160 | + /* Line-wise solvers */ |
| 161 | + /* ----------------- */ |
91 | 162 |
|
| 163 | + // Solve the linear system: |
| 164 | + // A_sc * u_sc = f_sc − A_sc^ortho * u_sc^ortho |
| 165 | + // Parameter mapping: |
| 166 | + // x = u_sc (solution vector for section s and color c) |
| 167 | + // temp = f_sc − A_sc^ortho * u_sc^ortho (precomputed right-hand side) |
| 168 | + // where: |
| 169 | + // s in {Circle, Radial} denotes the smoother section type, |
| 170 | + // c in {Black, White} denotes the line coloring. |
| 171 | + void solveBlackCircleSection(Vector<double> x, Vector<double> temp); |
| 172 | + void solveWhiteCircleSection(Vector<double> x, Vector<double> temp); |
| 173 | + void solveBlackRadialSection(Vector<double> x, Vector<double> temp); |
| 174 | + void solveWhiteRadialSection(Vector<double> x, Vector<double> temp); |
| 175 | + |
| 176 | + /* ----------------------------------- */ |
| 177 | + /* Initialize and destroy MUMPS solver */ |
| 178 | + /* ----------------------------------- */ |
92 | 179 | #ifdef GMGPOLAR_USE_MUMPS |
| 180 | + // Initialize sparse MUMPS solver with assembled COO matrix. |
93 | 181 | void initializeMumpsSolver(DMUMPS_STRUC_C& mumps_solver, SparseMatrixCOO<double>& solver_matrix); |
| 182 | + // Release MUMPS internal memory and MPI structures. |
94 | 183 | void finalizeMumpsSolver(DMUMPS_STRUC_C& mumps_solver); |
95 | 184 | #endif |
96 | | - |
97 | | - void nodeBuildSmootherGive(int i_r, int i_theta, const PolarGrid& grid, bool DirBC_Interior, |
98 | | - MatrixType& inner_boundary_circle_matrix, |
99 | | - std::vector<SymmetricTridiagonalSolver<double>>& circle_tridiagonal_solver, |
100 | | - std::vector<SymmetricTridiagonalSolver<double>>& radial_tridiagonal_solver, double arr, |
101 | | - double att, double art, double detDF, double coeff_beta); |
102 | 185 | }; |
0 commit comments