REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_Tagging.cpp
Go to the documentation of this file.
1#include <REMORA.H>
2#include <REMORA_Derive.H>
3
4using namespace amrex;
5
6/**
7 * Function to tag cells for refinement -- this overrides the pure virtual function in AmrCore
8 *
9 * @param[in] levc level of refinement (0 is coarsest level)
10 * @param[out] tags array of tagged cells
11 * @param[in] time current time
12 * @param[in] ngrow number of grow cells
13*/
14void
15REMORA::ErrorEst (int levc, TagBoxArray& tags, Real time, int /*ngrow*/)
16{
17 const int clearval = TagBox::CLEAR;
18 const int tagval = TagBox::SET;
19
20 //
21 // This mf must have ghost cells because we may take differences between adjacent values
22 //
23 std::unique_ptr<MultiFab> mf = std::make_unique<MultiFab>(grids[levc], dmap[levc], 1, 1);
24
25 for (int j=0; j < ref_tags.size(); ++j)
26 {
27 if (ref_tags[j].Field() == "tracer" || ref_tags[j].Field() == "temp" ||
28 ref_tags[j].Field() == "salt") {
30 0,true,false);
31 }
32 // This allows dynamic refinement based on the value of the tracer
33 if (ref_tags[j].Field() == "tracer")
34 {
35 MultiFab::Copy(*mf,*cons_new[levc],Tracer_comp,0,1,1);
36 } else if (ref_tags[j].Field() == "temp") {
37 MultiFab::Copy(*mf,*cons_new[levc],Temp_comp,0,1,1);
38 } else if (ref_tags[j].Field() == "salt") {
39 MultiFab::Copy(*mf,*cons_new[levc],Salt_comp,0,1,1);
40 } else if (ref_tags[j].Field() == "x_velocity") {
41 FillPatch(levc, time, *xvel_new[levc], xvel_new, xvel_bc(), BdyVars::u,0,true,true);
42 MultiFab::Copy(*mf,*xvel_new[levc],0,0,1,1);
43 } else if (ref_tags[j].Field() == "y_velocity") {
44 FillPatch(levc, time, *yvel_new[levc], yvel_new, yvel_bc(), BdyVars::v,0,true,true);
45 MultiFab::Copy(*mf,*yvel_new[levc],0,0,1,1);
46 } else if (ref_tags[j].Field() == "z_velocity") {
47 FillPatch(levc, time, *zvel_new[levc], zvel_new, zvel_bc(), BdyVars::null,0,true,true);
48 MultiFab::Copy(*mf,*zvel_new[levc],0,0,1,1);
49 } else if (ref_tags[j].Field() == "vorticity") {
50 MultiFab mf_cc_vel(grids[levc],dmap[levc],3,1);
51 average_face_to_cellcenter(mf_cc_vel,0,
52 Array<const MultiFab*,3>{xvel_new[levc],
53 yvel_new[levc],
54 zvel_new[levc]});
55 // Impose bc's at domain boundaries at all levels
56 FillBdyCCVels(levc, mf_cc_vel);
57
58#ifdef _OPENMP
59#pragma omp parallel if (Gpu::notInLaunchRegion())
60#endif
61 for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
62 {
63 const Box& bx = mfi.tilebox();
64 auto& dfab = (*mf)[mfi];
65 auto& sfab = mf_cc_vel[mfi];
66 auto pm = vec_pm[levc]->const_array(mfi);
67 auto pn = vec_pn[levc]->const_array(mfi);
68 auto maskr = vec_mskr[levc]->const_array(mfi);
69 derived::remora_dervort(bx, dfab, 0, 1, sfab, pm, pn, maskr, Geom(levc), time, nullptr, levc);
70 } // mfi
71
72 mf->FillBoundary(geom[levc].periodicity());
73 //
74 // TODO: we may need to fill physical boundaries here before tagging criteria are imposed
75 //
76
77 } else if (ref_tags[j].Field() == "mask") {
78 MultiFab::Copy(*mf,*vec_mskr3d[levc],0,0,1,IntVect(1,1,0));
79#ifdef REMORA_USE_PARTICLES
80 } else {
81 //
82 // This allows dynamic refinement based on the number of particles per cell
83 //
84 // Note that we must count all the particles in levels both at and above the current,
85 // since otherwise, e.g., if the particles are all at level 1, counting particles at
86 // level 0 will not trigger refinement when regridding so level 1 will disappear,
87 // then come back at the next regridding
88 //
89 const auto& particles_namelist( particleData.getNames() );
90 mf->setVal(zero);
91 for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
92 {
93 std::string tmp_string(particles_namelist[i]+"_count");
94 IntVect rr = IntVect::TheUnitVector();
95 if (ref_tags[j].Field() == tmp_string) {
96 for (int lev = levc; lev <= finest_level; lev++)
97 {
98 MultiFab temp_dat(grids[lev], dmap[lev], 1, 0); temp_dat.setVal(0);
99 particleData[particles_namelist[i]]->IncrementWithTotal(temp_dat, lev);
100
101 MultiFab temp_dat_crse(grids[levc], dmap[levc], 1, 0); temp_dat_crse.setVal(0);
102
103 if (lev == levc) {
104 MultiFab::Copy(*mf, temp_dat, 0, 0, 1, 0);
105 } else {
106 for (int d = 0; d < AMREX_SPACEDIM; d++) {
107 rr[d] *= ref_ratio[levc][d];
108 }
109 average_down(temp_dat, temp_dat_crse, 0, 1, rr);
110 MultiFab::Add(*mf, temp_dat_crse, 0, 0, 1, 0);
111 }
112 }
113 }
114 }
115
116
117#endif
118 }
119
120 ref_tags[j](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
121 }
122
123 // Promote any tagged cell to a full local z-column.
124 for (MFIter mfi(tags, TilingIfNotGPU()); mfi.isValid(); ++mfi)
125 {
126 const Box& bx = mfi.validbox();
127 auto const& tag = tags.array(mfi);
128
129 const int klo = bx.smallEnd(2);
130 const int khi = bx.bigEnd(2);
131
132 amrex::ParallelFor(makeSlab(bx, 2, 0),
133 [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
134 {
135 bool refine_col = false;
136 for (int k = klo; k <= khi; ++k) {
137 refine_col = refine_col || (tag(i,j,k) != TagBox::CLEAR);
138 }
139
140 if (refine_col) {
141 for (int k = klo; k <= khi; ++k) {
142 tag(i,j,k) = TagBox::SET;
143 }
144 }
145 });
146 }
147}
148
149/**
150 * Function to define the refinement criteria based on user input
151*/
152void
154{
155 if (max_level > 0)
156 {
157 ParmParse pp(pp_prefix);
158 Vector<std::string> refinement_indicators;
159 pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
160 for (int i=0; i<refinement_indicators.size(); ++i)
161 {
162 std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
163
164 ParmParse ppr(ref_prefix);
165 RealBox realbox;
166 int lev_for_box;
167
168 int num_real_lo = ppr.countval("in_box_lo");
169 int num_indx_lo = ppr.countval("in_box_lo_indices");
170 int num_indx_lo_crse = ppr.countval("in_box_lo_indices_crse");
171
172 int num_real_hi = ppr.countval("in_box_hi");
173 int num_indx_hi = ppr.countval("in_box_hi_indices");
174 int num_indx_hi_crse = ppr.countval("in_box_hi_indices_crse");
175
176 AMREX_ALWAYS_ASSERT( (num_real_lo == num_real_hi) && (num_real_lo == 0 || num_real_lo >= 2) );
177 AMREX_ALWAYS_ASSERT( (num_indx_lo == num_indx_hi) && (num_indx_lo == 0 || num_indx_lo >= 2) );
178 AMREX_ALWAYS_ASSERT( (num_indx_lo_crse == num_indx_hi_crse) && (num_indx_lo_crse == 0 || num_indx_lo_crse >= 2) );
179
180 // Problem low and high (in real not index space) are the same at all levels
181 if ( !((num_real_lo >= AMREX_SPACEDIM-1 && num_indx_lo == 0 && num_indx_lo_crse == 0) ||
182 (num_indx_lo >= AMREX_SPACEDIM-1 && num_real_lo == 0 && num_indx_lo_crse == 0) ||
183 (num_indx_lo == 0 && num_real_lo == 0 && num_indx_lo_crse == 0) ||
184 (num_indx_lo_crse >= AMREX_SPACEDIM-1 && num_real_lo == 0 && num_indx_lo == 0)
185 ) )
186 {
187 amrex::Abort("Must only specify box for refinement using real OR index space with fine/coarse grid indices");
188 }
189
190 if (num_real_lo > 0) {
191 std::vector<Real> box_lo(3), box_hi(3);
192 ppr.get("max_level",lev_for_box);
193 if (lev_for_box > 0 && lev_for_box <= max_level)
194 {
195 ppr.getarr("in_box_lo",box_lo,0,2);
196 ppr.getarr("in_box_hi",box_hi,0,2);
197 box_lo[2] = geom[0].ProbLo(2);
198 box_hi[2] = geom[0].ProbHi(2);
199 realbox = RealBox(&(box_lo[0]),&(box_hi[0]));
200
201 amrex::Print() << "Reading " << realbox << " at level " << lev_for_box << std::endl;
202 num_boxes_at_level[lev_for_box] += 1;
203
204 const auto* dx = geom[lev_for_box].CellSize();
205 const Real* plo = geom[lev_for_box].ProbLo();
206
207 int ilo = static_cast<int>((box_lo[0] - plo[0])/dx[0]);
208 int jlo = static_cast<int>((box_lo[1] - plo[1])/dx[1]);
209 int klo = static_cast<int>((box_lo[2] - plo[2])/dx[2]);
210 int ihi = static_cast<int>((box_hi[0] - plo[0])/dx[0]-1);
211 int jhi = static_cast<int>((box_hi[1] - plo[1])/dx[1]-1);
212 int khi = static_cast<int>((box_hi[2] - plo[2])/dx[2]-1);
213
214 Box bx_old(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
215
216 int mod_ilo = ilo%ref_ratio[lev_for_box-1][0];
217 int mod_jlo = jlo%ref_ratio[lev_for_box-1][1];
218
219 int mod_ihi = (ihi+1)%ref_ratio[lev_for_box-1][0];
220 int mod_jhi = (jhi+1)%ref_ratio[lev_for_box-1][1];
221
222 if (mod_ilo != 0) {
223 ilo -= mod_ilo;
224 }
225 if (mod_jlo != 0) {
226 jlo -= mod_jlo;
227 }
228 if (mod_ihi != 0) {
229 ihi += ref_ratio[lev_for_box-1][0] - mod_ihi;
230 }
231 if (mod_jhi != 0) {
232 jhi += ref_ratio[lev_for_box-1][1] - mod_jhi;
233 }
234 Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
235 if (mod_ilo !=0 || mod_jlo !=0 || mod_ihi != 0 || mod_jhi != 0) {
236 amrex::Print() << "Fine box on level " << lev_for_box << " adjusted from " << bx_old << " to " << bx << " to make it valid for refinement." << std::endl;
237 }
238 boxes_at_level[lev_for_box].push_back(bx);
239 amrex::Print() << "Saving in 'boxes at level' as " << bx << std::endl;
240 } // lev
241
242 } else if (num_indx_lo > 0) {
243
244 std::vector<int> box_lo(3), box_hi(3);
245 ppr.get("max_level",lev_for_box);
246 if (lev_for_box > 0 && lev_for_box <= max_level)
247 {
248 if (n_error_buf[0] != IntVect::TheZeroVector()) {
249 amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
250 }
251
252 ppr.getarr("in_box_lo_indices",box_lo,0,num_indx_lo);
253 ppr.getarr("in_box_hi_indices",box_hi,0,num_indx_hi);
254
255 if (num_indx_lo < AMREX_SPACEDIM) {
256 box_lo[2] = geom[lev_for_box].Domain().smallEnd(2);
257 box_hi[2] = geom[lev_for_box].Domain().bigEnd(2);
258 }
259
260 Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
261 const Box& domain = geom[lev_for_box].Domain();
262
263 if (!domain.contains(bx)) {
264 amrex::Print() << "\n";
265 amrex::Print() << "Box specified is " << bx << std::endl;
266 amrex::Print() << "But domain at level is " << domain << std::endl;
267 amrex::Error("Specified box doesn't fit in the domain");
268 }
269
270 const auto* dx = geom[lev_for_box].CellSize();
271 const Real* plo = geom[lev_for_box].ProbLo();
272 realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
273 plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
274
275 Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
276 num_boxes_at_level[lev_for_box] += 1;
277
278 if(box_lo[0]%ref_ratio[lev_for_box-1][0] != 0){
279 amrex::Print()<< "Requested ilo in x-direction : " << box_lo[0] << std::endl;
280 amrex::Print() << "ilo = " << box_lo[0] << " is not divisible by ref_ratio in x direction = " <<
281 ref_ratio[lev_for_box-1][0] << std::endl;
282 amrex::Error("Adjust in_box_lo_indices in x-direction to be divisible by ref_ratio and try again");
283 }
284 if((box_hi[0]+1)%ref_ratio[lev_for_box-1][0] != 0){
285 amrex::Print()<< "Requested ihi in x-direction : " << box_hi[0] << std::endl;
286 amrex::Print() << "ihi+1 = " << box_hi[0]+1 << " is not divisible by ref_ratio in x direction = " <<
287 ref_ratio[lev_for_box-1][0] << std::endl;
288 amrex::Error("Adjust in_box_hi_indices in x-direction to be divisible by ref_ratio and try again");
289 }
290 if(box_lo[1]%ref_ratio[lev_for_box-1][1] != 0){
291 amrex::Print()<< "Requested jlo in y-direction : " << box_lo[1] << std::endl;
292 amrex::Print() << "jlo = " << box_lo[1] << " is not divisible by ref_ratio in y direction = " <<
293 ref_ratio[lev_for_box-1][1] << std::endl;
294 amrex::Error("Adjust in_box_lo_indices in y-direction to be divisible by ref_ratio and try again");
295 }
296 if((box_hi[1]+1)%ref_ratio[lev_for_box-1][1] != 0){
297 amrex::Print()<< "Requested jhi in y-direction : " << box_hi[1] << std::endl;
298 amrex::Print() << "jhi+1 = " << box_hi[1]+1 << " is not divisible by ref_ratio in y direction = " <<
299 ref_ratio[lev_for_box-1][1] << std::endl;
300 amrex::Error("Adjust in_box_hi_indices in y-direction to be divisible by ref_ratio and try again");
301 }
302 if(box_lo[2]%ref_ratio[lev_for_box-1][2] != 0){
303 amrex::Print()<< "Requested klo in z-direction : " << box_lo[2] << std::endl;
304 amrex::Print() << "klo = " << box_lo[2] << " is not divisible by ref_ratio in z direction = " <<
305 ref_ratio[lev_for_box-1][2] << std::endl;
306 amrex::Error("Adjust in_box_lo_indices in z-direction to be divisible by ref_ratio and try again");
307 }
308 if((box_hi[2]+1)%ref_ratio[lev_for_box-1][2] != 0){
309 amrex::Print()<< "Requested khi in z-direction : " << box_hi[2] << std::endl;
310 amrex::Print() << "khi+1 = " << box_hi[2]+1 << " is not divisible by ref_ratio in z direction = " <<
311 ref_ratio[lev_for_box-1][2] << std::endl;
312 amrex::Error("Adjust in_box_hi_indices in z-direction to be divisible by ref_ratio and try again");
313 }
314
315 boxes_at_level[lev_for_box].push_back(bx);
316 Print() << "Saving in 'boxes at level' as " << bx << std::endl;
317 } // lev
318
319 } else if (num_indx_lo_crse > 0) {
320
321 std::vector<int> box_lo(3), box_hi(3);
322 ppr.get("max_level",lev_for_box);
323 if (lev_for_box > 0 && lev_for_box <= max_level)
324 {
325 if (n_error_buf[0] != IntVect::TheZeroVector()) {
326 amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
327 }
328
329 ppr.getarr("in_box_lo_indices_crse",box_lo,0,num_indx_lo_crse);
330 ppr.getarr("in_box_hi_indices_crse",box_hi,0,num_indx_hi_crse);
331
332 if (num_indx_lo_crse < AMREX_SPACEDIM) {
333 box_lo[2] = geom[lev_for_box-1].Domain().smallEnd(2);
334 box_hi[2] = geom[lev_for_box-1].Domain().bigEnd(2);
335 }
336
337 Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
338
339 if (!geom[lev_for_box-1].Domain().contains(bx)) {
340 amrex::Print() << "\n";
341 amrex::Print() << "(Coarse) Box specified is " << bx << std::endl;
342 amrex::Print() << "But (coarse) domain at level is " << geom[lev_for_box-1].Domain() << std::endl;
343 amrex::Error("Specified box doesn't fit in the domain");
344 }
345
346 bx.refine(ref_ratio[lev_for_box-1]);
347
348 const auto* dx = geom[lev_for_box-1].CellSize();
349
350 const Real* plo = geom[lev_for_box].ProbLo();
351 realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
352 plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
353
354 Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
355 num_boxes_at_level[lev_for_box] += 1;
356
357 boxes_at_level[lev_for_box].push_back(bx);
358 Print() << "Saving in 'boxes at level' as " << bx << std::endl;
359 } // lev
360 }
361
362 AMRErrorTagInfo info;
363
364 if (realbox.ok()) {
365 info.SetRealBox(realbox);
366 }
367 if (ppr.countval("start_time") > 0) {
368 Real ref_min_time; ppr.get("start_time",ref_min_time);
369 info.SetMinTime(ref_min_time);
370 }
371 if (ppr.countval("end_time") > 0) {
372 Real ref_max_time; ppr.get("end_time",ref_max_time);
373 info.SetMaxTime(ref_max_time);
374 }
375 if (ppr.countval("max_level") > 0) {
376 int ref_max_level; ppr.get("max_level",ref_max_level);
377 info.SetMaxLevel(ref_max_level);
378 }
379
380 if (ppr.countval("value_greater")) {
381 int num_val = ppr.countval("value_greater");
382 Vector<Real> value(num_val);
383 ppr.getarr("value_greater",value,0,num_val);
384 std::string field; ppr.get("field_name",field);
385 ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
386 }
387 else if (ppr.countval("value_less")) {
388 int num_val = ppr.countval("value_less");
389 Vector<Real> value(num_val);
390 ppr.getarr("value_less",value,0,num_val);
391 std::string field; ppr.get("field_name",field);
392 ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
393 }
394 else if (ppr.countval("adjacent_difference_greater")) {
395 int num_val = ppr.countval("adjacent_difference_greater");
396 Vector<Real> value(num_val);
397 ppr.getarr("adjacent_difference_greater",value,0,num_val);
398 std::string field; ppr.get("field_name",field);
399 ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
400 }
401 else if (realbox.ok())
402 {
403 ref_tags.push_back(AMRErrorTag(info));
404 } else {
405 Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
406 }
407 } // loop over criteria
408 {
409 // Untag anywhere we have masks
410 AMRErrorTagInfo info;
411 info.SetDerefine(1);
412 Real value = Real(0.5);
413 ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,"mask",info));
414 }
415 {
416 // Also untag at mask-water boundaries
417 AMRErrorTagInfo info;
418 info.SetDerefine(1);
419 Real value = Real(0.5);
420 ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,"mask",info));
421 }
422 } // if max_level > 0
423}
constexpr amrex::Real zero
#define Temp_comp
#define Tracer_comp
#define Salt_comp
AMREX_ALWAYS_ASSERT(!NSPeriodic||!EWPeriodic)
int zvel_bc() const noexcept
Definition REMORA.H:1249
int xvel_bc() const noexcept
Definition REMORA.H:1247
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pm
horizontal scaling factor: 1 / dx (2D)
Definition REMORA.H:550
amrex::Vector< amrex::MultiFab * > cons_new
multilevel data container for current step's scalar data: temperature, salinity, passive tracer
Definition REMORA.H:368
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskr
land/sea mask at cell centers (2D)
Definition REMORA.H:539
int yvel_bc() const noexcept
Definition REMORA.H:1248
amrex::Vector< amrex::MultiFab * > zvel_new
multilevel data container for current step's z velocities (largely unused; W stored separately)
Definition REMORA.H:374
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
the boxes specified at each level by tagging criteria
Definition REMORA.H:1466
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Holds info for dynamically generated tagging criteria.
Definition REMORA.H:1718
amrex::Vector< amrex::MultiFab * > yvel_new
multilevel data container for current step's y velocities (v in ROMS)
Definition REMORA.H:372
amrex::Vector< int > num_boxes_at_level
how many boxes specified at each level by tagging criteria
Definition REMORA.H:1462
amrex::Vector< amrex::MultiFab * > xvel_new
multilevel data container for current step's x velocities (u in ROMS)
Definition REMORA.H:370
void refinement_criteria_setup()
Set refinement criteria.
virtual void ErrorEst(int lev, amrex::TagBoxArray &tags, amrex::Real time, int ngrow) override
Tag cells for refinement.
void FillBdyCCVels(int lev, amrex::MultiFab &mf_cc_vel)
Fill the physical boundary conditions for cell-centered velocity (diagnostic only)
std::string pp_prefix
default prefix for input file parameters
Definition REMORA.H:356
void FillPatch(int lev, amrex::Real time, amrex::MultiFab &mf_to_be_filled, amrex::Vector< amrex::MultiFab * > const &mfs, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const bool fill_set=false, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab())
Fill a new MultiFab by copying in phi from valid region and filling ghost cells.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pn
horizontal scaling factor: 1 / dy (2D)
Definition REMORA.H:552
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskr3d
land/sea mask at cell centers, copied to all z levels (3D)
Definition REMORA.H:547
static constexpr int cons_bc
void remora_dervort(const amrex::Box &bx, amrex::FArrayBox &derfab, int dcomp, int ncomp, const amrex::FArrayBox &datfab, const amrex::Array4< const amrex::Real > &pm, const amrex::Array4< const amrex::Real > &pn, const amrex::Array4< const amrex::Real > &, const amrex::Geometry &, amrex::Real, const int *, const int)