Canoe
Comprehensive Atmosphere N' Ocean Engine
periodic_forward_backward.hpp
Go to the documentation of this file.
1 #ifndef SRC_SNAP_IMPLICIT_PERIODIC_FORWARD_BACKWARD_HPP_
2 #define SRC_SNAP_IMPLICIT_PERIODIC_FORWARD_BACKWARD_HPP_
3 
4 // C/C++ headers
5 #include <vector>
6 
7 // Eigen headers
8 #include <Eigen/Core>
9 #include <Eigen/Dense>
10 
11 // Athena++ headers
12 #include "communication.hpp"
13 
14 template <typename T1, typename T2>
15 void ImplicitSolver::PeriodicForwardSweep(std::vector<T1> &diag,
16  std::vector<T1> &diagL,
17  std::vector<T1> &diagU,
18  std::vector<T2> &corr, Real dt, int k,
19  int j, int il, int iu) {
20  T1 sum_beta_gamma, phi;
21  T2 rhs, sum_beta_zeta;
22  std::vector<T1> beta(diag.size()), gamma(diag.size());
23  std::vector<T1> ainv(diag.size());
24  std::vector<T2> zeta(diag.size());
25 
26  // start periodic linear system solver, ref: El-Mikkawy (2005).
27  // step 1: compute alpha, beta, gamma, delta from is to ie-1.
28  // -1
29  // alpha[1] = a[1], gamma[1] = U, beta[1] = L*alpha[1]
30 
31  // diag -> d
32  // diagU -> a
33  // diagL -> b
34  // alpha -> c
35  // gamma -> v
36  // beta -> h
37  // zeta -> k
38 
39  if (T2::RowsAtCompileTime == 3) { // partial matrix
40  rhs(0) = du_(IDN, k, j, il);
41  for (int n = 1; n <= NVAPOR; ++n) rhs(0) += du_(n, k, j, il);
42  rhs(0) /= dt;
43  rhs(1) = du_(IVX + mydir_, k, j, il) / dt;
44  rhs(2) = du_(IEN, k, j, il) / dt;
45  rhs -= corr[il];
46  } else { // full matrix
47  rhs(0) = du_(IDN, k, j, il);
48  for (int n = 1; n <= NVAPOR; ++n) rhs(0) += du_(n, k, j, il);
49  rhs(0) /= dt;
50  rhs(1) = du_(IVX + mydir_, k, j, il) / dt;
51  rhs(2) = du_(IVX + (IVY - IVX + mydir_) % 3, k, j, il) / dt;
52  rhs(3) = du_(IVX + (IVZ - IVX + mydir_) % 3, k, j, il) / dt;
53  rhs(4) = du_(IEN, k, j, il) / dt;
54  // if (pmy_hydro->implicit_done != nullptr) {
55  // pmy_hydro->implicit_done->LoadForcingJacobian(phi,k,j,il,mydir_);
56  // rhs -= dt*phi*rhs;
57  // }
58  }
59 
60  // if (last_block)
61  // SendBuffer(diagU[iu], k, j, tblock);
62  // if (first_block)
63  // RecvBuffer(diagU[il-1], k, j, bblock);
64 
65  if (first_block) {
66  // c[1] = d[1]
67  ainv[il] = diag[il].inverse().eval();
68  // v[1] = t (upper corner)
69  gamma[il] = diagL[il];
70  // -1
71  // h[1] = s*c[1] (lower corner)
72  beta[il] = diagU[il - 1] * ainv[il];
73  // r[1] = k[1]
74  zeta[il] = rhs;
75  sum_beta_gamma.setZero();
76  sum_beta_zeta.setZero();
77  } else {
78  RecvBuffer(ainv[il - 1], gamma[il - 1], beta[il - 1], zeta[il - 1],
79  sum_beta_gamma, sum_beta_zeta, k, j, bblock);
80  // -1
81  // c[il] = d[il] - b[il]*c[il-1]*a[il-1]
82  ainv[il] = diag[il] - diagL[il] * ainv[il - 1] * diagU[il - 1];
83  ainv[il] = ainv[il].inverse().eval();
84  // -1
85  // v[il] = -b[il]*c[il-1]*v[il-1]
86  gamma[il] = -diagL[il] * ainv[il - 1] * gamma[il - 1];
87  // -1
88  // h[il] = -h[il-1]*a[il-1]*c[il]
89  beta[il] = -beta[il - 1] * diagU[il - 1] * ainv[il];
90  // -1
91  // r[il] = k[il] - b[il]*c[il]*r[il-1]
92  zeta[il] = rhs - diagL[il] * ainv[il - 1] * zeta[il - 1];
93  }
94 
95  for (int i = il + 1; i <= iu; ++i) {
96  if (T2::RowsAtCompileTime == 3) { // partial matrix
97  rhs(0) = du_(IDN, k, j, i);
98  for (int n = 1; n <= NVAPOR; ++n) rhs(0) += du_(n, k, j, i);
99  rhs(0) /= dt;
100  rhs(1) = du_(IVX + mydir_, k, j, i) / dt;
101  rhs(2) = du_(IEN, k, j, i) / dt;
102  rhs -= corr[i];
103  } else {
104  rhs(0) = du_(IDN, k, j, i);
105  for (int n = 1; n <= NVAPOR; ++n) rhs(0) += du_(n, k, j, i);
106  rhs(0) /= dt;
107  rhs(1) = du_(IVX + mydir_, k, j, i) / dt;
108  rhs(2) = du_(IVX + (IVY - IVX + mydir_) % 3, k, j, i) / dt;
109  rhs(3) = du_(IVX + (IVZ - IVX + mydir_) % 3, k, j, i) / dt;
110  rhs(4) = du_(IEN, k, j, i) / dt;
111  // if (pmy_hydro->implicit_done != nullptr) {
112  // pmy_hydro->implicit_done->LoadForcingJacobian(phi,k,j,i,mydir_);
113  // rhs -= dt*phi*rhs;
114  // }
115  }
116 
117  // -1
118  // c[i] = d[i] - b[i]*c[i-1]*a[i-1]
119  ainv[i] = diag[i] - diagL[i] * ainv[i - 1] * diagU[i - 1];
120  ainv[i] = ainv[i].inverse().eval();
121  // -1
122  // v[i] = -b[i]*c[i-1]*v[i-1]
123  gamma[i] = -diagL[i] * ainv[i - 1] * gamma[i - 1];
124  // -1
125  // h[i] = -h[i-1]*a[i-1]*c[i]
126  beta[i] = -beta[i - 1] * diagU[i - 1] * ainv[i];
127  // -1
128  // r[i] = k[i] - b[i]*c[i]*r[i-1]
129  zeta[i] = rhs - diagL[i] * ainv[i - 1] * zeta[i - 1];
130  }
131 
132  if (last_block) { // I'm the last block
133  // -1
134  // v[n-1] = a[n-1] - b[n-1]*c[n-2]*v[n-2];
135  gamma[iu - 1] =
136  diagU[iu - 1] - diagL[iu - 1] * ainv[iu - 2] * gamma[iu - 2];
137  // -1
138  // h[n-1] = (b[n] - h[n-2]*a[n-2])*c[n-1]
139  beta[iu - 1] = (diagL[iu] - beta[iu - 2] * diagU[iu - 2]) * ainv[iu - 1];
140  for (int i = il; i < iu; ++i) {
141  // h[i]*v[i]
142  sum_beta_gamma += beta[i] * gamma[i];
143  // h[i]*r[i]
144  sum_beta_zeta += beta[i] * zeta[i];
145  }
146  // n-1
147  // c[n] = d[n] - Sum {h[i]*v[i]}
148  // i=1
149  ainv[iu] = diag[iu] - sum_beta_gamma;
150  ainv[iu] = ainv[iu].inverse().eval();
151  // n-1
152  // r[n] = k[n] - Sum {h[i]*r[i]}
153  // i=1
154  zeta[iu] = rhs - sum_beta_zeta;
155  } else {
156  for (int i = il; i <= iu; ++i) {
157  // h[i]*v[i]
158  sum_beta_gamma += beta[i] * gamma[i];
159  // h[i]*r[i]
160  sum_beta_zeta += beta[i] * zeta[i];
161  }
162  SendBuffer(ainv[iu], gamma[iu], beta[iu], zeta[iu], sum_beta_gamma,
163  sum_beta_zeta, k, j, tblock);
164  }
165 
166  SaveCoefficients(ainv, gamma, zeta, diagU, k, j, il, iu);
167 }
168 
169 // delta -> x
170 // zeta -> r
171 // alpha -> c
172 // diagU -> a
173 // gamma -> v
174 
175 template <typename T1, typename T2>
177  std::vector<T1> &diagU,
178  std::vector<T2> &delta,
179  int kl, int ku, int jl,
180  int ju, int il, int iu) {
181  T2 delta_last;
182  std::vector<T1> gamma(diagU.size());
183  std::vector<T2> zeta(diagU.size());
184 
185  for (int k = kl; k <= ku; ++k)
186  for (int j = jl; j <= ju; ++j) {
187  LoadCoefficients(ainv, gamma, zeta, diagU, k, j, il, iu);
188  if (last_block) { // I'm the last block
189  // a[n-1] = 0
190  diagU[iu - 1].setZero();
191  // -1
192  // x[n] = c[n]*r[n]
193  delta[iu] = ainv[iu] * zeta[iu];
194  delta_last = delta[iu];
195  } else {
196  RecvBuffer(delta[iu + 1], delta_last, k, j, tblock);
197  delta[iu] = ainv[iu] * (zeta[iu] - diagU[iu] * delta[iu + 1] -
198  gamma[iu] * delta_last);
199  }
200 
201  // backward substitution
202  for (int i = iu - 1; i >= il; --i)
203  // -1
204  // x[i] = c[i]*(r[i] - a[i]*x[i+1] - v[i]*x[n])
205  delta[i] = ainv[i] *
206  (zeta[i] - diagU[i] * delta[i + 1] - gamma[i] * delta_last);
207 
208  // update conserved variables
209  for (int i = il; i <= iu; ++i) {
210  if (T2::RowsAtCompileTime == 3) { // partial matrix
211  du_(IDN, k, j, i) = delta[i](0);
212  du_(IVX + mydir_, k, j, i) = delta[i](1);
213  du_(IEN, k, j, i) = delta[i](2);
214  } else { // full matrix
215  du_(IDN, k, j, i) = delta[i](0);
216  du_(IVX + mydir_, k, j, i) = delta[i](1);
217  du_(IVX + (IVY - IVX + mydir_) % 3, k, j, i) = delta[i](2);
218  du_(IVX + (IVZ - IVX + mydir_) % 3, k, j, i) = delta[i](3);
219  du_(IEN, k, j, i) = delta[i](4);
220  }
221  for (int n = 1; n <= NVAPOR; ++n) du_(IDN, k, j, i) -= du_(n, k, j, i);
222  }
223 
224  if (!first_block) SendBuffer(delta[il], delta_last, k, j, bblock);
225  }
226 
227 #ifdef MPI_PARALLEL
228  MPI_Status status;
229 
230  if (!last_block && (tblock.snb.rank != Globals::my_rank)) {
231  for (int k = kl; k <= ku; ++k)
232  for (int j = jl; j <= ju; ++j) MPI_Wait(&req_send_data6_[k][j], &status);
233  }
234 
235  if (!first_block && (bblock.snb.rank != Globals::my_rank)) {
236  for (int k = kl; k <= ku; ++k)
237  for (int j = jl; j <= ju; ++j) MPI_Wait(&req_send_data2_[k][j], &status);
238  }
239 #endif
240 }
241 
242 #endif // SRC_SNAP_IMPLICIT_PERIODIC_FORWARD_BACKWARD_HPP_
NeighborBlock bblock
void RecvBuffer(T &a, int k, int j, NeighborBlock nb)
NeighborBlock tblock
CoordinateDirection mydir_
void PeriodicBackwardSubstitution(std::vector< T1 > &a, std::vector< T1 > &c, std::vector< T2 > &delta, int kl, int ku, int jl, int ju, int il, int iu)
void LoadCoefficients(std::vector< T1 > &a, std::vector< T2 > &b, int k, int j, int il, int iu)
AthenaArray< Real > du_
void PeriodicForwardSweep(std::vector< T1 > &a, std::vector< T1 > &b, std::vector< T1 > &c, std::vector< T2 > &corr, Real dt, int k, int j, int il, int iu)
void SaveCoefficients(std::vector< T1 > &a, std::vector< T2 > &b, int k, int j, int il, int iu)
void SendBuffer(T const &a, int k, int j, NeighborBlock nb)