40 Vector<int> source_indices, owners;
41 const auto& source_ba = state.boxArray();
42 const auto& source_owners = state.DistributionMap().ProcessorMap();
43 for (
int b = 0; b < source_ba.size(); ++b) {
44 const Box bx = source_ba[b] & region;
45 if (!bx.ok()) {
continue; }
47 source_indices.push_back(b);
48 owners.push_back(source_owners[b]);
50 if (boxes.isEmpty()) {
return {}; }
51 const BoxArray ba(boxes);
52 const DistributionMapping dm(owners);
54 MultiFab samples(ba, dm, 5, IntVect(0,0,1));
56 const int klo = geometry.Domain().smallEnd(2);
57 const auto dx = geometry.CellSizeArray();
58 auto ground = perturbation_ground(z_nd, samples, geometry);
59 for (MFIter mfi(samples); mfi.isValid(); ++mfi) {
60 const int src = source_indices[mfi.index()];
61 const auto ua =
xvel.const_array(src);
62 const auto va =
yvel.const_array(src);
63 const auto cc = z_cc ? z_cc->const_array(src) : Array4<const Real>{};
64 const auto nd = z_nd ? z_nd->const_array(src) : Array4<const Real>{};
65 const auto ga = ground ? ground->const_array(mfi) : Array4<const Real>{};
66 const auto a = samples.array(mfi);
67 ParallelFor(mfi.validbox(), [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept {
73 ga(i,j+1,
klo) + ga(i+1,j+1,
klo));
74 zlo =
fourth*(nd(i,j,k) + nd(i+1,j,k) +
75 nd(i,j+1,k) + nd(i+1,j+1,k)) - zs;
76 zhi =
fourth*(nd(i,j,k+1) + nd(i+1,j,k+1) +
77 nd(i,j+1,k+1) + nd(i+1,j+1,k+1)) - zs;
78 z = cc ? cc(i,j,k) - zs :
myhalf*(zlo+zhi);
80 a(i,j,k,0) =
myhalf*(ua(i,j,k)+ua(i+1,j,k));
81 a(i,j,k,1) =
myhalf*(va(i,j,k)+va(i,j+1,k));
87 samples.FillBoundary(geometry.periodicity());
90 for (MFIter mfi(samples); mfi.isValid(); ++mfi) {
91 const auto a = samples.const_array(mfi);
92 ReduceOps<ReduceOpSum, ReduceOpSum, ReduceOpSum> op;
93 ReduceData<Real, Real, Real> data(op);
94 using Tuple =
typename decltype(data)::Type;
95 op.eval(mfi.validbox(), data, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k) noexcept -> Tuple {
96 const Real z = a(i,j,k,2);
97 const Real znext = a(i,j,k+1,2);
102 u += weight*(a(i,j,k+1,0)-u);
103 v += weight*(a(i,j,k+1,1)-v);
112 const auto values = data.value(op);
113 sums[0] += amrex::get<0>(values);
114 sums[1] += amrex::get<1>(values);
115 sums[2] += amrex::get<2>(values);
117 ParallelAllReduce::Sum(sums, 3, ParallelContext::CommunicatorSub());
118 Box footprint = region;
119 footprint.setRange(2,
klo);
120 if (sums[2] !=
Real(footprint.numPts()) || sums[2] ==
zero) {
124 const Real min_height = samples.min(2);
125 const Real max_height = samples.max(2);
126 Print() <<
"Automatic perturbation wind sampling: region=" << region
127 <<
" target_height_agl=" <<
height_agl <<
" m"
128 <<
" samples=" << sums[2]
129 <<
" expected_columns=" << footprint.numPts()
130 <<
" cell_height_agl_min=" << min_height <<
" m"
131 <<
" cell_height_agl_max=" << max_height <<
" m"
132 <<
" source_boxes=" << ba.size() <<
"\n";
135 const Real u = sums[0]/sums[2];
136 const Real v = sums[1]/sums[2];
137 if (!std::isfinite(u) || !std::isfinite(v)) {
138 Abort(
"Automatic perturbations: non-finite wind at the CPM sampling height");
constexpr amrex::Real bogus_large_value
Definition: ERF_Constants.H:19
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
const int klo
Definition: ERF_InitCustomPert_KE.H:9
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:42
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ xvel
Definition: ERF_IndexDefines.H:255
@ yvel
Definition: ERF_IndexDefines.H:256
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real height_agl(amrex::Real z, amrex::Real z_sfc) noexcept
Definition: ERF_ShocGpuUtils.H:50