REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_rho_eos.cpp
Go to the documentation of this file.
1#include <REMORA.H>
2
3using namespace amrex;
4
5/**
6 * @param[in ] bx box for calculation
7 * @param[in ] state state holds temp, salt
8 * @param[ out] rho density
9 * @param[ out] rhoA vertically-averaged density
10 * @param[ out] rhoS density perturbation
11 * @param[ out] bvf Brunt-Vaisala frequency
12 * @param[ out] alpha thermal expansion coefficient
13 * @param[ out] beta saline contraction coefficient
14 * @param[in ] Hz vertical cell height
15 * @param[in ] z_r z coordinates at rho points
16 * @param[in ] z_w z coordinates at w points
17 * @param[in ] h bathymetry
18 * @param[in ] mskr land-sea mask on rho points
19 * @param[in ] N number of vertical levels
20 */
21void
22REMORA::rho_eos (const Box& bx,
23 const Array4<Real const>& state,
24 const Array4<Real >& rho,
25 const Array4<Real >& rhoA,
26 const Array4<Real >& rhoS,
27 const Array4<Real >& bvf,
28 const Array4<Real >& alpha,
29 const Array4<Real >& beta,
30 const Array4<Real const>& Hz,
31 const Array4<Real const>& z_w,
32 const Array4<Real const>& z_r,
33 const Array4<Real const>& h,
34 const Array4<Real const>& mskr,
35 const int N)
36{
38 lin_eos(bx, state, rho, rhoA, rhoS, bvf, Hz, z_w, z_r, h, mskr, N);
40 nonlin_eos(bx, state, rho, rhoA, rhoS, bvf, alpha, beta, Hz, z_w, z_r, h, mskr, N);
41 } else {
42 Abort("Unknown EOS type in rho_eos");
43 }
44}
45
46/**
47 * @param[in ] bx box for calculation
48 * @param[in ] state state holds temp, salt
49 * @param[ out] rho density
50 * @param[ out] rhoA vertically-averaged density
51 * @param[ out] rhoS density perturbation
52 * @param[ out] bvf Brunt-Vaisala frequency
53 * @param[in ] Hz vertical cell height
54 * @param[in ] z_r z coordinates at rho points
55 * @param[in ] z_w z coordinates at w points
56 * @param[in ] h bathymetry
57 * @param[in ] mskr land-sea mask on rho points
58 * @param[in ] N number of vertical levels
59 */
60void
61REMORA::lin_eos (const Box& bx,
62 const Array4<Real const>& state,
63 const Array4<Real >& rho,
64 const Array4<Real >& rhoA,
65 const Array4<Real >& rhoS,
66 const Array4<Real >& bvf,
67 const Array4<Real const>& Hz,
68 const Array4<Real const>& z_w,
69 const Array4<Real const>& z_r,
70 const Array4<Real const>& h,
71 const Array4<Real const>& mskr,
72 const int N)
73{
74//
75 AMREX_ASSERT(bx.smallEnd(2) == 0 && bx.bigEnd(2) == N);
76//
77//=======================================================================
78// Linear equation of state.
79//=======================================================================
80//
81//
82//-----------------------------------------------------------------------
83// Compute "in situ" density anomaly (kg/m3 - 1000) using the linear
84// equation of state.
85//-----------------------------------------------------------------------
86//
87 Real R0 = solverChoice.R0;
88 Real S0 = solverChoice.S0;
89 Real T0 = solverChoice.T0;
90 Real Tcoef = solverChoice.Tcoef;
91 Real Scoef = solverChoice.Scoef;
92
93 ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
94 {
95 rho(i,j,k) = (R0 - R0*Tcoef*(state(i,j,k,Temp_comp)-T0)
96 + R0*Scoef*(state(i,j,k,Salt_comp)-S0)
97 - 1000.0_rt) * mskr(i,j,0);
98 });
99
100//
101//-----------------------------------------------------------------------
102// Compute vertical averaged density (rhoA) and density perturbation
103// used (rhoS) in barotropic pressure gradient.
104//-----------------------------------------------------------------------
105//
106 Real cff2 =1.0_rt/solverChoice.rho0;
107
108 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int )
109 {
110 Real cff0 = rho(i,j,N)*Hz(i,j,N);
111 rhoS(i,j,0) = 0.5_rt*cff0*Hz(i,j,N);
112 rhoA(i,j,0) = cff0;
113
114 for (int k = 1; k <= N; ++k) {
115 Real cff1=rho(i,j,N-k)*Hz(i,j,N-k);
116 rhoS(i,j,0) += Hz(i,j,N-k)*(rhoA(i,j,0)+0.5_rt*cff1);
117 rhoA(i,j,0) += cff1;
118 }
119
120 Real cff11 =1.0_rt/(z_w(i,j,N+1)+h(i,j,0,0));
121
122 rhoA(i,j,0) *= cff2*cff11;
123
124 rhoS(i,j,0) *= 2.0_rt*cff11*cff11*cff2;
125 });
126
127 // Compute Brunt-Vaisala frequency (1/s2)
128 Real gorho0 = g / solverChoice.rho0;
129 // Really want enclosed nodes or something similar
130 Box box_w = bx;
131 box_w.surroundingNodes(2);
132 box_w.grow(IntVect(0,0,-1));
133
134 ParallelFor(box_w, [=] AMREX_GPU_DEVICE (int i, int j, int k)
135 {
136 bvf(i,j,k) = -gorho0 * (rho(i,j,k)-rho(i,j,k-1)) / (z_r(i,j,k)-z_r(i,j,k-1));
137 });
138}
139
140/**
141 * @param[in ] bx box for calculation
142 * @param[in ] state state holds temp, salt
143 * @param[ out] rho density
144 * @param[ out] rhoA vertically-averaged density
145 * @param[ out] rhoS density perturbation
146 * @param[ out] bvf Brunt-Vaisala frequency
147 * @param[ out] alpha thermal expansion coefficient
148 * @param[ out] beta saline contraction coefficient
149 * @param[in ] Hz vertical cell height
150 * @param[in ] z_r z coordinates at rho points
151 * @param[in ] z_w z coordinates at w points
152 * @param[in ] h bathymetry
153 * @param[in ] mskr land-sea mask on rho points
154 * @param[in ] N number of vertical levels
155 */
156void
157REMORA::nonlin_eos (const Box& bx,
158 const Array4<Real const>& state,
159 const Array4<Real >& rho,
160 const Array4<Real >& rhoA,
161 const Array4<Real >& rhoS,
162 const Array4<Real >& bvf,
163 const Array4<Real >& alpha,
164 const Array4<Real >& beta,
165 const Array4<Real const>& Hz,
166 const Array4<Real const>& z_w,
167 const Array4<Real const>& z_r,
168 const Array4<Real const>& h,
169 const Array4<Real const>& mskr,
170 const int N)
171{
172//
173 AMREX_ASSERT(bx.smallEnd(2) == 0 && bx.bigEnd(2) == N);
174
175 FArrayBox fab_den1 (bx,1,amrex::The_Async_Arena()); auto den1 = fab_den1.array();
176 FArrayBox fab_den (bx,1,amrex::The_Async_Arena()); auto den = fab_den.array();
177 FArrayBox fab_bulk (bx,1,amrex::The_Async_Arena()); auto bulk = fab_bulk.array();
178 FArrayBox fab_bulk0(bx,1,amrex::The_Async_Arena()); auto bulk0 = fab_bulk0.array();
179 FArrayBox fab_bulk1(bx,1,amrex::The_Async_Arena()); auto bulk1 = fab_bulk1.array();
180 FArrayBox fab_bulk2(bx,1,amrex::The_Async_Arena()); auto bulk2 = fab_bulk2.array();
181 FArrayBox fab_DbulkDT(bx,1,amrex::The_Async_Arena()); auto DbulkDT = fab_DbulkDT.array();
182 FArrayBox fab_Dden1DT(bx,1,amrex::The_Async_Arena()); auto Dden1DT = fab_Dden1DT.array();
183 FArrayBox fab_DbulkDS(bx,1,amrex::The_Async_Arena()); auto DbulkDS = fab_DbulkDS.array();
184 FArrayBox fab_Dden1DS(bx,1,amrex::The_Async_Arena()); auto Dden1DS = fab_Dden1DS.array();
185
187//
188//=======================================================================
189// Non-linear equation of state.
190//=======================================================================
191 ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k)
192 {
193 Real Tt = std::max(-2.5_rt, state(i,j,k,Temp_comp));
194 Tt = std::min(40.0_rt, Tt);
195 Real Ts = std::max(0.0_rt, state(i,j,k,Salt_comp));
196 Ts = std::min(100.0_rt, Ts);
197 Real sqrtTs = std::sqrt(Ts);
198
199 Real Tp = z_r(i,j,k);
200 Real Tpr10 = 0.1_rt*Tp;
201
202 Real C0 = Q00+Tt*(Q01+Tt*(Q02+Tt*(Q03+Tt*(Q04+Tt*Q05))));
203 Real C1 = U00+Tt*(U01+Tt*(U02+Tt*(U03+Tt*U04)));
204 Real C2 = V00+Tt*(V01+Tt*V02);
205
206 if (bulk_fluxes) {
207 Real dCdT0=Q01+Tt*(2.0_rt*Q02+Tt*(3.0_rt*Q03+Tt*(4.0_rt*Q04+
208 Tt*5.0_rt*Q05)));
209 Real dCdT1=U01+Tt*(2.0_rt*U02+Tt*(3.0_rt*U03+Tt*4.0_rt*U04));
210 Real dCdT2=V01+Tt*2.0_rt*V02;
211 // Compute d(den1)/d(S) and d(den1)/d(T) derivatives used in the
212 // computation of thermal expansion and saline contraction
213 // coefficients.
214
215 Dden1DS(i,j,k)=C1+1.5_rt*C2*sqrtTs+2.0_rt*W00*Ts;
216 Dden1DT(i,j,k)=dCdT0+Ts*(dCdT1+sqrtTs*dCdT2);
217 }
218
219 den1(i,j,k) = C0 + Ts*(C1+sqrtTs*C2+Ts*W00);
220
221 //-----------------------------------------------------------------------
222 // Compute secant bulk modulus.
223 //-----------------------------------------------------------------------
224 Real C3=A00+Tt*(A01+Tt*(A02+Tt*(A03+Tt*A04)));
225 Real C4=B00+Tt*(B01+Tt*(B02+Tt*B03));
226 Real C5=D00+Tt*(D01+Tt*D02);
227 Real C6=E00+Tt*(E01+Tt*(E02+Tt*E03));
228 Real C7=F00+Tt*(F01+Tt*F02);
229 Real C8=G01+Tt*(G02+Tt*G03);
230 Real C9=H00+Tt*(H01+Tt*H02);
231
232 bulk0(i,j,k)=C3+Ts*(C4+sqrtTs*C5);
233 bulk1(i,j,k)=C6+Ts*(C7+sqrtTs*G00);
234 bulk2(i,j,k)=C8+Ts*C9;
235 bulk (i,j,k)=bulk0(i,j,k)-Tp*(bulk1(i,j,k)-Tp*bulk2(i,j,k));
236
237 Real cff = 1.0_rt / (bulk(i,j,k) + Tpr10);
238 den(i,j,k) = (den1(i,j,k)*bulk(i,j,k)*cff - 1000.0_rt) * mskr(i,j,0);
239 // This line may need to move once bluk fluxes are added
240 rho(i,j,k) = den(i,j,k);
241
242 if (bulk_fluxes) {
243 Real dCdT3=A01+Tt*(2.0_rt*A02+Tt*(3.0_rt*A03+Tt*4.0_rt*A04));
244 Real dCdT4=B01+Tt*(2.0_rt*B02+Tt*3.0_rt*B03);
245 Real dCdT5=D01+Tt*2.0_rt*D02;
246 Real dCdT6=E01+Tt*(2.0_rt*E02+Tt*3.0_rt*E03);
247 Real dCdT7=F01+Tt*2.0_rt*F02;
248 Real dCdT8=G02+Tt*2.0_rt*G03;
249 Real dCdT9=H01+Tt*2.0_rt*H02;
250
251 DbulkDS(i,j,k)=C4+sqrtTs*1.5_rt*C5-
252 Tp*(C7+sqrtTs*1.5_rt*G00-Tp*C9);
253 DbulkDT(i,j,k)=dCdT3+Ts*(dCdT4+sqrtTs*dCdT5)-
254 Tp*(dCdT6+Ts*dCdT7-
255 Tp*(dCdT8+Ts*dCdT9));
256 }
257 });
258
259//
260//-----------------------------------------------------------------------
261// Compute vertical averaged density (rhoA) and density perturbation
262// used (rhoS) in barotropic pressure gradient.
263//-----------------------------------------------------------------------
264//
265 Real cff_rho =1.0_rt/solverChoice.rho0;
266
267 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int )
268 {
269 Real cff0 = den(i,j,N)*Hz(i,j,N);
270 rhoS(i,j,0) = 0.5_rt*cff0*Hz(i,j,N);
271 rhoA(i,j,0) = cff0;
272
273 for (int k = 1; k <= N; ++k) {
274 Real cff1=den(i,j,N-k)*Hz(i,j,N-k);
275 rhoS(i,j,0) += Hz(i,j,N-k)*(rhoA(i,j,0)+0.5_rt*cff1);
276 rhoA(i,j,0) += cff1;
277 }
278 Real cff11 =1.0_rt/(z_w(i,j,N+1)+h(i,j,0,0));
279 rhoA(i,j,0) *= cff_rho*cff11;
280 rhoS(i,j,0) *= 2.0_rt*cff11*cff11*cff_rho;
281 });
282
283 // Compute Brunt-Vaisala frequency (1/s2)
284 Box bxD = bx; bxD.makeSlab(2,0);
285
286 ParallelFor(bxD, [=] AMREX_GPU_DEVICE (int i, int j, int )
287 {
288 bvf(i,j,0) = 0.0_rt;
289 bvf(i,j,N+1) = 0.0_rt;
290 for (int k=0; k<=N-1; k++) {
291 Real bulk_up = bulk0(i,j,k+1) - (z_w(i,j,k+1) * (bulk1(i,j,k+1) - bulk2(i,j,k+1)*z_w(i,j,k+1)));
292 Real bulk_dn = bulk0(i,j,k ) - (z_w(i,j,k+1) * (bulk1(i,j,k ) - bulk2(i,j,k )*z_w(i,j,k+1)));
293 Real cff1 = 1.0_rt / (bulk_up + 0.1_rt * z_w(i,j,k+1));
294 Real cff2 = 1.0_rt / (bulk_dn + 0.1_rt * z_w(i,j,k+1));
295 Real den_up = cff1 * (den1(i,j,k+1) * bulk_up);
296 Real den_dn = cff2 * (den1(i,j,k ) * bulk_dn);
297 bvf(i,j,k+1) = -g * (den_up - den_dn) / (0.5_rt * (den_up+den_dn) * (z_r(i,j,k+1) - z_r(i,j,k)));
298 }
299 });
300
302 ParallelFor(bxD, [=] AMREX_GPU_DEVICE (int i, int j, int )
303 {
304 Real Tp = z_r(i,j,N);
305 Real Tpr10 = 0.1_rt*Tp;
306
307 // Compute thermal expansion and saline contraction coefficients
308 Real cff = bulk(i,j,N) + Tpr10;
309 Real cff1 = Tpr10 * den1(i,j,N);
310 Real cff2 = bulk(i,j,N) * cff;
311 Real wrk = (den(i,j,N) + 1000.0_rt) * cff * cff;
312 Real Tcof = -(DbulkDT(i,j,N) * cff1 + Dden1DT(i,j,N) * cff2);
313 Real Scof = (DbulkDS(i,j,N) * cff1 + Dden1DS(i,j,N) * cff2);
314 alpha(i,j,0) = Tcof / wrk;
315 beta(i,j,0) = Scof / wrk;
316 });
317 }
318}
constexpr amrex::Real A01
constexpr amrex::Real U01
constexpr amrex::Real E02
constexpr amrex::Real W00
constexpr amrex::Real E03
constexpr amrex::Real H00
constexpr amrex::Real Q04
constexpr amrex::Real V02
constexpr amrex::Real B02
constexpr amrex::Real U03
constexpr amrex::Real H01
constexpr amrex::Real G00
constexpr amrex::Real D02
constexpr amrex::Real A04
constexpr amrex::Real B00
constexpr amrex::Real A02
constexpr amrex::Real B01
constexpr amrex::Real F01
constexpr amrex::Real g
constexpr amrex::Real Q00
constexpr amrex::Real G01
constexpr amrex::Real G03
constexpr amrex::Real Q02
constexpr amrex::Real H02
constexpr amrex::Real Q01
constexpr amrex::Real Q03
constexpr amrex::Real U04
constexpr amrex::Real F00
constexpr amrex::Real B03
constexpr amrex::Real E00
constexpr amrex::Real Q05
constexpr amrex::Real G02
constexpr amrex::Real V00
constexpr amrex::Real U02
constexpr amrex::Real F02
constexpr amrex::Real E01
constexpr amrex::Real U00
constexpr amrex::Real A00
constexpr amrex::Real V01
constexpr amrex::Real A03
constexpr amrex::Real D01
constexpr amrex::Real D00
#define Temp_comp
#define Salt_comp
void rho_eos(const amrex::Box &bx, const amrex::Array4< amrex::Real const > &state, const amrex::Array4< amrex::Real > &rho, const amrex::Array4< amrex::Real > &rhoA, const amrex::Array4< amrex::Real > &rhoS, const amrex::Array4< amrex::Real > &bvf, const amrex::Array4< amrex::Real > &alpha, const amrex::Array4< amrex::Real > &beta, const amrex::Array4< amrex::Real const > &Hz, const amrex::Array4< amrex::Real const > &z_w, const amrex::Array4< amrex::Real const > &z_r, const amrex::Array4< amrex::Real const > &h, const amrex::Array4< amrex::Real const > &mskr, const int N)
Wrapper around equation of state calculation.
void lin_eos(const amrex::Box &bx, const amrex::Array4< amrex::Real const > &state, const amrex::Array4< amrex::Real > &rho, const amrex::Array4< amrex::Real > &rhoA, const amrex::Array4< amrex::Real > &rhoS, const amrex::Array4< amrex::Real > &bvf, const amrex::Array4< amrex::Real const > &Hz, const amrex::Array4< amrex::Real const > &z_w, const amrex::Array4< amrex::Real const > &z_r, const amrex::Array4< amrex::Real const > &h, const amrex::Array4< amrex::Real const > &mskr, const int N)
Calculate density and related quantities from linear equation of state.
void bulk_fluxes(int lev, amrex::MultiFab *mf_cons, amrex::MultiFab *mf_uwind, amrex::MultiFab *mf_vwind, amrex::MultiFab *mf_evap, amrex::MultiFab *mf_sustr, amrex::MultiFab *mf_svstr, amrex::MultiFab *mf_stflux, amrex::MultiFab *mf_lrflx, amrex::MultiFab *mf_lhflx, amrex::MultiFab *mf_shflx, const int N)
Calculate bulk temperature, salinity, wind fluxes.
static SolverChoice solverChoice
Container for algorithmic choices.
Definition REMORA.H:1221
void nonlin_eos(const amrex::Box &bx, const amrex::Array4< amrex::Real const > &state, const amrex::Array4< amrex::Real > &rho, const amrex::Array4< amrex::Real > &rhoA, const amrex::Array4< amrex::Real > &rhoS, const amrex::Array4< amrex::Real > &bvf, const amrex::Array4< amrex::Real > &alpha, const amrex::Array4< amrex::Real > &beta, const amrex::Array4< amrex::Real const > &Hz, const amrex::Array4< amrex::Real const > &z_w, const amrex::Array4< amrex::Real const > &z_r, const amrex::Array4< amrex::Real const > &h, const amrex::Array4< amrex::Real const > &mskr, const int N)
Calculate density and related quantities from nonlinear equation of state.
amrex::Real Tcoef
amrex::Real Scoef