Canoe
Comprehensive Atmosphere N' Ocean Engine
full_correction.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <iostream>
3 #include <vector>
4 
5 // canoe
6 #include <configure.hpp>
7 #include <impl.hpp>
8 
9 // Eigen
10 #include <Eigen/Core>
11 #include <Eigen/Dense>
12 
13 // climath
14 #include <climath/core.h>
15 
16 // athena
17 #include <athena/eos/eos.hpp>
18 #include <athena/hydro/hydro.hpp>
19 #include <athena/mesh/mesh.hpp>
20 
21 // application
22 #include <application/application.hpp>
23 
24 // snap
25 #include "../thermodynamics/thermodynamics.hpp"
26 #include "flux_decomposition.hpp"
27 #include "forward_backward.hpp"
28 #include "implicit_solver.hpp"
30 // #include "forcing_jacobians.hpp"
31 
33  AthenaArray<Real> const& w, Real dt) {
34  MeshBlock const* pmb = pmy_block_;
35  int is, ie, js, je, ks, ke;
36  int idn = 0, ivx = 1, ivy = 2, ivz = 3, ien = 4;
37  if (mydir_ == X1DIR) {
38  ks = pmb->ks, js = pmb->js, is = pmb->is;
39  ke = pmb->ke, je = pmb->je, ie = pmb->ie;
40  for (int n = 0; n < NHYDRO; ++n)
41  for (int k = ks; k <= ke; ++k)
42  for (int j = js; j <= je; ++j)
43  for (int i = is; i <= ie; ++i) du_(n, k, j, i) = du(n, k, j, i);
44  } else if (mydir_ == X2DIR) {
45  ks = pmb->is, js = pmb->ks, is = pmb->js;
46  ke = pmb->ie, je = pmb->ke, ie = pmb->je;
47  for (int n = 0; n < NHYDRO; ++n)
48  for (int k = ks; k <= ke; ++k)
49  for (int j = js; j <= je; ++j)
50  for (int i = is; i <= ie; ++i) du_(n, k, j, i) = du(n, j, i, k);
51  } else { // X3DIR
52  ks = pmb->js, js = pmb->is, is = pmb->ks;
53  ke = pmb->je, je = pmb->ie, ie = pmb->ke;
54  for (int n = 0; n < NHYDRO; ++n)
55  for (int k = ks; k <= ke; ++k)
56  for (int j = js; j <= je; ++j)
57  for (int i = is; i <= ie; ++i) du_(n, k, j, i) = du(n, i, k, j);
58  }
59 
60  // eigenvectors, eigenvalues, inverse matrix of eigenvectors.
61  Eigen::Matrix<Real, 5, 5> Rmat, Lambda, Rimat;
62 
63  // reduced diffusion matrix |A_{i-1/2}|, |A_{i+1/2}|
64  Eigen::Matrix<Real, 5, 5> Am, Ap;
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, 5, 1>> rhs(nc);
70  std::vector<Eigen::Matrix<Real, 5, 5>> a(nc), b(nc), c(nc);
71  std::vector<Eigen::Matrix<Real, 5, 1>> delta(nc);
72  std::vector<Eigen::Matrix<Real, 5, 5>> dfdq(nc);
73  std::vector<Eigen::Matrix<Real, 5, 1>> corr(nc); // place holder
74 
75  // 0. forcing and volume matrix
76  FindNeighbors();
77 
78  Real gamma = pmy_block_->peos->GetGamma();
79  Eigen::Matrix<Real, 5, 5> Phi, Dt, Bnds, Bnde, tmp;
80 
81  Dt.setIdentity();
82  Dt *= 1. / dt;
83 
84  Bnds.setIdentity();
85  Bnds(ivx, ivx) = -1;
86  if (pole_at_bot) Bnds(ivy, ivy) = -1;
87 
88  Bnde.setIdentity();
89  Bnde(ivx, ivx) = -1;
90  if (pole_at_top) Bnde(ivy, ivy) = -1;
91 
92  Real* gamma_m1 = new Real[nc];
93 
94  Real wl[NHYDRO], wr[NHYDRO];
95  auto pthermo = Thermodynamics::GetInstance();
96 
97  for (int k = ks; k <= ke; ++k)
98  for (int j = js; j <= je; ++j) {
99  // 3. calculate and save flux Jacobian matrix
100  for (int i = is - 2; i <= ie + 1; ++i) {
101  Real fsig = 1., feps = 1.;
102  CopyPrimitives(wl, wr, w, k, j, i, mydir_);
103  for (int n = 1; n <= NVAPOR; ++n) {
104  fsig += w(n, k, j, i) * (pthermo->GetCvRatioMass(n) - 1.);
105  feps += w(n, k, j, i) * (pthermo->GetInvMuRatio(n) - 1.);
106  }
107 
108  gamma_m1[i] = (gamma - 1.) * feps / fsig;
109  FluxJacobian(dfdq[i], gamma_m1[i], wr, mydir_);
110  } // 5. set up diffusion matrix and tridiagonal coefficients
111  // left edge
112  CopyPrimitives(wl, wr, w, k, j, is - 1, mydir_);
113  Real gm1 = 0.5 * (gamma_m1[is - 2] + gamma_m1[is - 1]);
114  RoeAverage(prim, gm1, wl, wr);
115  Real cs = pmy_block_->peos->SoundSpeed(prim);
116  Eigenvalue(Lambda, prim[IVX + mydir_], cs);
117  Eigenvector(Rmat, Rimat, prim, cs, gm1, mydir_);
118  Am = Rmat * Lambda * Rimat;
119 
120  Coordinates* pcoord = pmy_block_->pcoord;
121  for (int i = is - 1; i <= ie; ++i) {
122  CopyPrimitives(wl, wr, w, k, j, i + 1, mydir_);
123  // right edge
124  gm1 = 0.5 * (gamma_m1[i] + gamma_m1[i + 1]);
125  RoeAverage(prim, gm1, wl, wr);
126  Real cs = pmy_block_->peos->SoundSpeed(prim);
127  Eigenvalue(Lambda, prim[IVX + mydir_], cs);
128  Eigenvector(Rmat, Rimat, prim, cs, gm1, mydir_);
129  Ap = Rmat * Lambda * Rimat;
130 
131  // set up diagonals a, b, c, and Jacobian of the forcing function
132  Real aleft, aright, vol;
133  if (mydir_ == X1DIR) {
134  aleft = pcoord->GetFace1Area(k, j, i);
135  aright = pcoord->GetFace1Area(k, j, i + 1);
136  vol = pcoord->GetCellVolume(k, j, i);
137  // JACOBIAN_FUNCTION(Phi,wl,k,j,i);
138  // memcpy(jacobian_[k][j][i], Phi.data(), Phi.size()*sizeof(Real));
139  } else if (mydir_ == X2DIR) {
140  aleft = pcoord->GetFace2Area(j, i, k);
141  aright = pcoord->GetFace2Area(j, i + 1, k);
142  vol = pcoord->GetCellVolume(j, i, k);
143  Phi.setZero();
144  // JACOBIAN_FUNCTION(Phi,wl,j,i,k);
145  // tmp = p3_*Phi*p2_;
146  // memcpy(jacobian_[j][i][k], tmp.data(), tmp.size()*sizeof(Real));
147  } else { // X3DIR
148  aleft = pcoord->GetFace3Area(i, k, j);
149  aright = pcoord->GetFace3Area(i + 1, k, j);
150  vol = pcoord->GetCellVolume(i, k, j);
151  Phi.setZero();
152  // JACOBIAN_FUNCTION(Phi,wl,i,k,j);
153  // tmp = p2_*Phi*p3_;
154  // memcpy(jacobian_[i][k][j], tmp.data(), tmp.size()*sizeof(Real));
155  }
156 
157  a[i] = (Am * aleft + Ap * aright + (aright - aleft) * dfdq[i]) /
158  (2. * vol) +
159  Dt - Phi;
160  b[i] = -(Am + dfdq[i - 1]) * aleft / (2. * vol);
161  c[i] = -(Ap - dfdq[i + 1]) * aright / (2. * vol);
162 
163  // Shift one cell: i -> i+1
164  Am = Ap;
165  }
166 
167  // 5. fix boundary condition
168  if (first_block && !periodic_boundary) a[is] += b[is] * Bnds;
169 
170  if (last_block && !periodic_boundary) a[ie] += c[ie] * Bnde;
171 
172  // 6. solve tridiagonal system
173  if (periodic_boundary)
174  PeriodicForwardSweep(a, b, c, corr, dt, k, j, is, ie);
175  else
176  ForwardSweep(a, b, c, delta, corr, dt, k, j, is, ie);
177  }
178 
179  if (periodic_boundary)
180  PeriodicBackwardSubstitution(a, c, delta, ks, ke, js, je, is, ie);
181  else
182  BackwardSubstitution(a, delta, ks, ke, js, je, is, ie);
183 
184  if (mydir_ == X1DIR) {
185  for (int k = ks; k <= ke; ++k)
186  for (int j = js; j <= je; ++j)
187  for (int i = is; i <= ie; ++i) {
188  du(IDN, k, j, i) = du_(IDN, k, j, i);
189  for (int n = IVX; n < NHYDRO; ++n) du(n, k, j, i) = du_(n, k, j, i);
190  }
191  } else if (mydir_ == X2DIR) {
192  for (int k = ks; k <= ke; ++k)
193  for (int j = js; j <= je; ++j)
194  for (int i = is; i <= ie; ++i) {
195  du(IDN, j, i, k) = du_(IDN, k, j, i);
196  for (int n = IVX; n < NHYDRO; ++n) du(n, j, i, k) = du_(n, k, j, i);
197  }
198  } else { // X3DIR
199  for (int k = ks; k <= ke; ++k)
200  for (int j = js; j <= je; ++j)
201  for (int i = is; i <= ie; ++i) {
202  du(IDN, i, k, j) = du_(IDN, k, j, i);
203  for (int n = IVX; n < NHYDRO; ++n) du(n, i, k, j) = du_(n, k, j, i);
204  }
205  }
206 
207  // pdebug->CheckConservation("du", du, is, ie, js, je, ks, ke);
208 
209  delete[] gamma_m1;
210 }
void FullCorrection(AthenaArray< Real > &du, AthenaArray< Real > const &w, Real dt)
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)
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)