REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_MaskedAverageDown.H
Go to the documentation of this file.
1#ifndef REMORA_MASKED_AVERAGE_DOWN_H_
2#define REMORA_MASKED_AVERAGE_DOWN_H_
3
4#include <AMReX_Algorithm.H>
5#include <AMReX_Array4.H>
6#include <AMReX_IntVect.H>
7#include <AMReX_REAL.H>
8
9/**
10 * Two-way nesting's fine-to-coarse update, weighted by the land/sea mask.
11 *
12 * Ported from ROMS fine2coarse2d/fine2coarse3d in Nonlinear/nesting.F, the AreaAvg = .FALSE.
13 * branch that every call site there uses:
14 *
15 * num = sum of (fine value * fine mask) over the fine points under the coarse one
16 * den = sum of min(1, fine mask) over the same
17 * crse = num/den * coarse mask
18 *
19 * Dividing by the count of wet fine points rather than by how many there are means a coarse
20 * point only partly covered by water takes the mean of that water, not a value diluted toward
21 * zero by land. That is not conservative; ROMS makes the same trade deliberately. The coarse
22 * mask has the final say on wet or dry.
23 *
24 * Where every fine point is wet these have to reproduce amrex_avgdown and amrex_avgdown_faces
25 * bit for bit, or every existing multilevel answer moves in its last bit.
26 */
28
29/** Cell-centered fields: every fine cell under the coarse one. The mask is 2D, read at k=0. */
31void avgdown_masked (int i, int j, int k, int n,
32 amrex::Array4<amrex::Real> const& crse,
33 amrex::Array4<amrex::Real const> const& fine,
34 amrex::Array4<amrex::Real const> const& fmsk,
35 amrex::Array4<amrex::Real const> const& cmsk,
36 int ccomp, int fcomp, amrex::IntVect const& ratio) noexcept
37{
38 using amrex::Real;
39 const int facx = ratio[0];
40 const int facy = ratio[1];
41 const int facz = ratio[2];
42 const int ii = i*facx;
43 const int jj = j*facy;
44 const int kk = k*facz;
45
46 Real num = Real(0.0);
47 Real den = Real(0.0);
48 // AMReX's loop order, and the mask multiplying the value before it is accumulated rather
49 // than after (x * 1.0 == x), are what make the all-wet case bit-identical to amrex_avgdown.
50 for (int kref = 0; kref < facz; ++kref) {
51 for (int jref = 0; jref < facy; ++jref) {
52 for (int iref = 0; iref < facx; ++iref) {
53 const Real m = amrex::min(Real(1.0), fmsk(ii+iref,jj+jref,0));
54 num += fine(ii+iref,jj+jref,kk+kref,n+fcomp) * m;
55 den += m;
56 }}}
57
58 // Multiplication by the reciprocal, not num/den: this is AMReX's volfrac, and dividing
59 // would differ in the last bit. den == 0 under a wet coarse point cannot happen once
60 // check_mask_consistency passes, so write zero rather than diagnose it from a kernel.
61 crse(i,j,k,n+ccomp) = (den > Real(0.0))
62 ? num * (Real(1.0)/den) * cmsk(i,j,0)
63 : Real(0.0);
64}
65
66/** Face-centered fields: only the fine faces in the coarse face's own plane, the stencil
67 * amrex_avgdown_faces uses, so "wet" means the flow really does cross here. */
69void avgdown_faces_masked (int i, int j, int k, int n,
70 amrex::Array4<amrex::Real> const& crse,
71 amrex::Array4<amrex::Real const> const& fine,
72 amrex::Array4<amrex::Real const> const& fmsk,
73 amrex::Array4<amrex::Real const> const& cmsk,
74 int ccomp, int fcomp, amrex::IntVect const& ratio, int idir) noexcept
75{
76 using amrex::Real;
77 const int facx = ratio[0];
78 const int facy = ratio[1];
79 const int facz = ratio[2];
80 const int ii = i*facx;
81 const int jj = j*facy;
82 const int kk = k*facz;
83
84 Real num = Real(0.0);
85 Real den = Real(0.0);
86
87 if (idir == 0) {
88 for (int kref = 0; kref < facz; ++kref) {
89 for (int jref = 0; jref < facy; ++jref) {
90 const Real m = amrex::min(Real(1.0), fmsk(ii,jj+jref,0));
91 num += fine(ii,jj+jref,kk+kref,n+fcomp) * m;
92 den += m;
93 }}
94 } else if (idir == 1) {
95 for (int kref = 0; kref < facz; ++kref) {
96 for (int iref = 0; iref < facx; ++iref) {
97 const Real m = amrex::min(Real(1.0), fmsk(ii+iref,jj,0));
98 num += fine(ii+iref,jj,kk+kref,n+fcomp) * m;
99 den += m;
100 }}
101 } else {
102 for (int jref = 0; jref < facy; ++jref) {
103 for (int iref = 0; iref < facx; ++iref) {
104 const Real m = amrex::min(Real(1.0), fmsk(ii+iref,jj+jref,0));
105 num += fine(ii+iref,jj+jref,kk,n+fcomp) * m;
106 den += m;
107 }}
108 }
109
110 // As in avgdown_masked: reciprocal rather than divide, and zero when nothing is wet.
111 crse(i,j,k,n+ccomp) = (den > Real(0.0))
112 ? num * (Real(1.0)/den) * cmsk(i,j,0)
113 : Real(0.0);
114}
115
116} // namespace REMORAMaskedAvgDown
117
118#endif
mf_h setVal(geomdata.ProbHi(2))
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void avgdown_faces_masked(int i, int j, int k, int n, amrex::Array4< amrex::Real > const &crse, amrex::Array4< amrex::Real const > const &fine, amrex::Array4< amrex::Real const > const &fmsk, amrex::Array4< amrex::Real const > const &cmsk, int ccomp, int fcomp, amrex::IntVect const &ratio, int idir) noexcept
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void avgdown_masked(int i, int j, int k, int n, amrex::Array4< amrex::Real > const &crse, amrex::Array4< amrex::Real const > const &fine, amrex::Array4< amrex::Real const > const &fmsk, amrex::Array4< amrex::Real const > const &cmsk, int ccomp, int fcomp, amrex::IntVect const &ratio) noexcept