Canoe
Comprehensive Atmosphere N' Ocean Engine
partial_correction.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <iostream>
3 #include <vector>
4 
5 // Eigen
6 #include <Eigen/Core>
7 #include <Eigen/Dense>
8 
9 // canoe
10 #include <impl.hpp>
11 
12 // application
13 #include <application/application.hpp>
14 
15 // athena
16 #include <athena/eos/eos.hpp>
17 #include <athena/hydro/hydro.hpp>
18 #include <athena/mesh/mesh.hpp>
19 
20 // snap
21 #include "../thermodynamics/thermodynamics.hpp"
22 #include "flux_decomposition.hpp"
23 #include "forward_backward.hpp"
25 
27  AthenaArray<Real> const& w, Real dt) {
28  int is, ie, js, je, ks, ke;
29  int idn = 0, ivx = 1, ivy = 2, ivz = 3, ien = 4;
30 
31  MeshBlock const* pmb = pmy_block_;
32 
33  if (mydir_ == X1DIR) {
34  ks = pmb->ks, js = pmb->js, is = pmb->is;
35  ke = pmb->ke, je = pmb->je, ie = pmb->ie;
36  for (int n = 0; n < NHYDRO; ++n)
37  for (int k = ks; k <= ke; ++k)
38  for (int j = js; j <= je; ++j)
39  for (int i = is; i <= ie; ++i) du_(n, k, j, i) = du(n, k, j, i);
40  } else if (mydir_ == X2DIR) {
41  ks = pmb->is, js = pmb->ks, is = pmb->js;
42  ke = pmb->ie, je = pmb->ke, ie = pmb->je;
43  for (int n = 0; n < NHYDRO; ++n)
44  for (int k = ks; k <= ke; ++k)
45  for (int j = js; j <= je; ++j)
46  for (int i = is; i <= ie; ++i) du_(n, k, j, i) = du(n, j, i, k);
47  } else { // X3DIR
48  ks = pmb->js, js = pmb->is, is = pmb->ks;
49  ke = pmb->je, je = pmb->ie, ie = pmb->ke;
50  for (int n = 0; n < NHYDRO; ++n)
51  for (int k = ks; k <= ke; ++k)
52  for (int j = js; j <= je; ++j)
53  for (int i = is; i <= ie; ++i) du_(n, k, j, i) = du(n, i, k, j);
54  }
55 
56  // eigenvectors, eigenvalues, inverse matrix of eigenvectors.
57  Eigen::Matrix<Real, 5, 5> Rmat, Lambda, Rimat;
58 
59  // reduced diffusion matrix |A_{i-1/2}|, |A_{i+1/2}|
60  Eigen::Matrix<Real, 5, 5> Am, Ap, dfdq;
61  Eigen::Matrix<Real, 3, 2> Am1, Ap1;
62  Eigen::Matrix<Real, 3, 3> Am2, Ap2;
63  Eigen::Matrix<Real, 3, 1> sm, sp;
64  Eigen::Matrix<Real, 2, 1> dqm, dqp;
65 
66  Real prim[NHYDRO]; // Roe averaged primitive variables of cell i-1/2
67 
68  int nc = ie - is + 1 + 2 * NGHOST;
69  std::vector<Eigen::Matrix<Real, 3, 3>> a(nc), b(nc), c(nc);
70  std::vector<Eigen::Matrix<Real, 3, 1>> delta(nc);
71  std::vector<Eigen::Matrix<Real, 3, 2>> dfdq1(nc);
72  std::vector<Eigen::Matrix<Real, 3, 3>> dfdq2(nc);
73  std::vector<Eigen::Matrix<Real, 3, 1>> corr(nc);
74 
75  Real* gamma_m1 = new Real[nc];
76 
77  // 0. forcing and volume matrix
78  FindNeighbors();
79  // SynchronizeConserved(du_, ks, ke, js, je, is, ie);
80  // WaitToFinishSync(ks, ke, js, je, is, ie);
81 
82  Real gamma = pmy_block_->peos->GetGamma();
83  Real grav = pmy_block_->phydro->hsrc.GetG1();
84  Eigen::Matrix<Real, 3, 3> Phi, Dt, Bnd;
85  if (mydir_ == X1DIR) {
86  Phi << 0., 0., 0., grav, 0., 0., 0., grav, 0.;
87  } else {
88  Phi << 0., 0., 0., 0., 0., 0., 0., 0., 0.;
89  }
90 
91  Dt << 1. / dt, 0., 0., 0., 1. / dt, 0., 0., 0., 1. / dt;
92 
93  Bnd << 1., 0., 0., 0., -1., 0., 0., 0., 1.;
94 
95  Real wl[NHYDRO], wr[NHYDRO];
96  auto pthermo = Thermodynamics::GetInstance();
97 
98  for (int k = ks; k <= ke; ++k)
99  for (int j = js; j <= je; ++j) {
100  // calculate and save flux Jacobian matrix
101  for (int i = is - 2; i <= ie + 1; ++i) {
102  Real fsig = 1., feps = 1.;
103  CopyPrimitives(wl, wr, w, k, j, i, mydir_);
104  for (int n = 1; n <= NVAPOR; ++n) {
105  fsig += wr[n] * (pthermo->GetCvRatioMass(n) - 1.);
106  feps += wr[n] * (pthermo->GetInvMuRatio(n) - 1.);
107  }
108 
109  gamma_m1[i] = (gamma - 1.) * feps / fsig;
110  // FluxJacobian(dfdq1[i], dfdq2[i], gamma_m1[i], w, k, j, i);
111  FluxJacobian(dfdq, gamma_m1[i], wr, mydir_);
112  dfdq1[i] << dfdq(idn, ivy), dfdq(idn, ivz), dfdq(ivx, ivy),
113  dfdq(ivx, ivz), dfdq(ien, ivy), dfdq(ien, ivz);
114  dfdq2[i] << dfdq(idn, idn), dfdq(idn, ivx), dfdq(idn, ien),
115  dfdq(ivx, idn), dfdq(ivx, ivx), dfdq(ivx, ien), dfdq(ien, idn),
116  dfdq(ien, ivx), dfdq(ien, ien);
117  }
118 
119  // set up diffusion matrix and tridiagonal coefficients
120  // left edge
121  CopyPrimitives(wl, wr, w, k, j, is - 1, mydir_);
122  Real gm1 = 0.5 * (gamma_m1[is - 2] + gamma_m1[is - 1]);
123  RoeAverage(prim, gm1, wl, wr);
124  Real cs = pmy_block_->peos->SoundSpeed(prim);
125  Eigenvalue(Lambda, prim[IVX + mydir_], cs);
126  Eigenvector(Rmat, Rimat, prim, cs, gm1, mydir_);
127  Am = Rmat * Lambda * Rimat;
128  Am1 << Am(idn, ivy), Am(idn, ivz), Am(ivx, ivy), Am(ivx, ivz),
129  Am(ien, ivy), Am(ien, ivz);
130  Am2 << Am(idn, idn), Am(idn, ivx), Am(idn, ien), Am(ivx, idn),
131  Am(ivx, ivx), Am(ivx, ien), Am(ien, idn), Am(ien, ivx), Am(ien, ien);
132 
133  for (int i = is - 1; i <= ie; ++i) {
134  CopyPrimitives(wl, wr, w, k, j, i + 1, mydir_);
135  gm1 = 0.5 * (gamma_m1[i] + gamma_m1[i + 1]);
136  RoeAverage(prim, gm1, wl, wr);
137  Real cs = pmy_block_->peos->SoundSpeed(prim);
138  Eigenvalue(Lambda, prim[IVX + mydir_], cs);
139  Eigenvector(Rmat, Rimat, prim, cs, gm1, mydir_);
140  Ap = Rmat * Lambda * Rimat;
141  Ap1 << Ap(idn, ivy), Ap(idn, ivz), Ap(ivx, ivy), Ap(ivx, ivz),
142  Ap(ien, ivy), Ap(ien, ivz);
143  Ap2 << Ap(idn, idn), Ap(idn, ivx), Ap(idn, ien), Ap(ivx, idn),
144  Ap(ivx, ivx), Ap(ivx, ien), Ap(ien, idn), Ap(ien, ivx),
145  Ap(ien, ien);
146 
147  // set up diagonals a, b, c.
148  Real aleft, aright, vol;
149  Coordinates* pcoord = pmy_block_->pcoord;
150  if (mydir_ == X1DIR) {
151  aleft = pcoord->GetFace1Area(k, j, i);
152  aright = pcoord->GetFace1Area(k, j, i + 1);
153  vol = pcoord->GetCellVolume(k, j, i);
154  } else if (mydir_ == X2DIR) {
155  aleft = pcoord->GetFace2Area(j, i, k);
156  aright = pcoord->GetFace2Area(j, i + 1, k);
157  vol = pcoord->GetCellVolume(j, i, k);
158  } else { // X3DIR
159  aleft = pcoord->GetFace3Area(i, k, j);
160  aright = pcoord->GetFace3Area(i + 1, k, j);
161  vol = pcoord->GetCellVolume(i, k, j);
162  }
163  a[i] = (Am2 * aleft + Ap2 * aright + (aright - aleft) * dfdq2[i]) /
164  (2. * vol) +
165  Dt - Phi;
166  b[i] = -(Am2 + dfdq2[i - 1]) * aleft / (2. * vol);
167  c[i] = -(Ap2 - dfdq2[i + 1]) * aright / (2. * vol);
168 
169  // flux correction
170  // dqm << du_(IVX+(IVY-IVX+mydir_)%3,k,j,i ),
171  // du_(IVX+(IVZ-IVX+mydir_)%3,k,j,i ); dqp <<
172  // du_(IVX+(IVY-IVX+mydir_)%3,k,j,i+1),
173  // du_(IVX+(IVZ-IVX+mydir_)%3,k,j,i+1); sm = 0.5*((dfdq1[i-1] + Am1)*dqm
174  // + (dfdq1[i] - Am1)*dqp); sp = 0.5*((dfdq1[i] + Ap1)*dqm + (dfdq1[i+1]
175  // - Ap1)*dqp); corr[i] = (sp*aright - sm*aleft)/vol;
176  corr[i].setZero();
177 
178  // Shift one cell: i -> i+1
179  Am1 = Ap1;
180  Am2 = Ap2;
181  }
182 
183  // 5. fix boundary condition
184  if (first_block && !periodic_boundary) a[is] += b[is] * Bnd;
185  if (last_block && !periodic_boundary) a[ie] += c[ie] * Bnd;
186 
187  // 6. solve tridiagonal system using LU decomposition
188  if (periodic_boundary)
189  PeriodicForwardSweep(a, b, c, corr, dt, k, j, is, ie);
190  else
191  ForwardSweep(a, b, c, delta, corr, dt, k, j, is, ie);
192  }
193 
194  if (periodic_boundary)
195  PeriodicBackwardSubstitution(a, c, delta, ks, ke, js, je, is, ie);
196  else
197  BackwardSubstitution(a, delta, ks, ke, js, je, is, ie);
198 
199  if (mydir_ == X1DIR) {
200  for (int k = ks; k <= ke; ++k)
201  for (int j = js; j <= je; ++j)
202  for (int i = is; i <= ie; ++i) {
203  du(IDN, k, j, i) = du_(IDN, k, j, i);
204  du(IVX, k, j, i) = du_(IVX, k, j, i);
205  du(IEN, k, j, i) = du_(IEN, k, j, i);
206  }
207  } else if (mydir_ == X2DIR) {
208  for (int k = ks; k <= ke; ++k)
209  for (int j = js; j <= je; ++j)
210  for (int i = is; i <= ie; ++i) {
211  du(IDN, j, i, k) = du_(IDN, k, j, i);
212  du(IVY, j, i, k) = du_(IVY, k, j, i);
213  du(IEN, j, i, k) = du_(IEN, k, j, i);
214  }
215  } else { // X3DIR
216  for (int k = ks; k <= ke; ++k)
217  for (int j = js; j <= je; ++j)
218  for (int i = is; i <= ie; ++i) {
219  du(IDN, i, k, j) = du_(IDN, k, j, i);
220  du(IVZ, i, k, j) = du_(IVZ, k, j, i);
221  du(IEN, i, k, j) = du_(IEN, k, j, i);
222  }
223  }
224 
225  // pdebug->CheckConservation("du", du, is, ie, js, je, ks, ke);
226 
227  delete[] gamma_m1;
228 }
void ForwardSweep(std::vector< T1 > &a, std::vector< T1 > &b, std::vector< T1 > &c, std::vector< T2 > &delta, std::vector< T2 > &corr, Real dt, int k, int j, int il, int iu)
void PartialCorrection(AthenaArray< Real > &du, AthenaArray< Real > const &w, Real dt)
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 BackwardSubstitution(std::vector< T1 > &a, std::vector< T2 > &delta, int kl, int ku, int jl, int ju, 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)
MeshBlock const * pmy_block_
static Thermodynamics const * GetInstance()
Return a pointer to the one and only instance of Thermodynamics.
void Eigenvector(Eigen::DenseBase< Derived1 > &Rmat, Eigen::DenseBase< Derived2 > &Rimat, Real prim[], Real cs, Real gm1, CoordinateDirection dir)
void CopyPrimitives(Real wl[], Real wr[], AthenaArray< Real > const &w, int k, int j, int i, CoordinateDirection dir)
void FluxJacobian(Eigen::DenseBase< Derived1 > &dfdq, Real gm1, Real w[], CoordinateDirection dir)
void RoeAverage(Real prim[], Real gm1, Real wl[], Real wr[])
void Eigenvalue(Eigen::MatrixBase< Derived > &Lambda, Real u, Real cs)