REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA_NCTimeSeriesBoundary.cpp
Go to the documentation of this file.
2#include "REMORA_NCFile.H"
3
4#include "AMReX_ParallelDescriptor.H"
5
6#include <string>
7
8#ifdef REMORA_USE_NETCDF
9/**
10 * @param[in ] a_lev level at which we will store the data
11 * @param[in ] a_geom Vector of Geometry objects at all levels
12 * @param[in ] a_file_name vector of file name(s) to read from
13 * @param[in ] a_field_name name of field to read in
14 * @param[in ] a_time_name name of time variable in NetCDF file
15 * @param[in ] a_index_type nodality of data field
16 * @param[in ] a_var_need_data array over boundaries of flags that indicate whether we need data for the variable
17 * @param[in ] a_is2d Whether the variable we're working with is 2D
18 * @param[in ] a_rx refinement ratio in x relative to level 0
19 * @param[in ] a_ry refinement ratio in y relative to level 0
20 */
21NCTimeSeriesBoundary::NCTimeSeriesBoundary (int a_lev, const amrex::Vector<amrex::Geometry> a_geom,
22 const amrex::Vector<std::string>& a_file_names, const std::string a_field_name,
23 const std::string a_time_name,
24 const amrex::IntVect a_index_type,
25 const amrex::GpuArray<bool, AMREX_SPACEDIM*2>& a_var_need_data,
26 bool a_is2d, int a_rx, int a_ry)
27{
28 m_lev = a_lev;
29 m_geom = a_geom;
30 file_names.assign(a_file_names.begin(), a_file_names.end());
33 domain = a_geom[a_lev].Domain();
35 // Copied, not aliased: the caller's array (REMORA::phys_bc_need_data) is an
36 // amrex::Vector element, whose address is not stable across a resize.
38 is2d = a_is2d;
39 m_rx = a_rx;
40 m_ry = a_ry;
41}
42
44{
45 // Initialize Fabs
46 amrex::Arena* Arena_Used = amrex::The_Arena();
47#ifdef AMREX_USE_GPU
48 Arena_Used = amrex::The_Pinned_Arena();
49#endif
50
51 // open file
52 // Only announce the variables that will really be read. A series is constructed for
53 // every boundary variable, but most of them typically sit on a local boundary
54 // condition and never touch the file.
55 bool any_side_needs_data = false;
56 for (int ori = 0; ori < AMREX_SPACEDIM*2; ++ori) {
58 }
60 amrex::Print() << "Setting up boundary data for " << field_name << " coming from NetCDF file " << std::endl;
61 }
62
63 // The time field can have any number of names, depending on the field.
64 // If not specified in input file (time_name.empty()) then set it by default
65 if (time_name.empty())
66 {
67 time_name = "ocean_time";
68 }
69
70 int ioproc = amrex::ParallelDescriptor::IOProcessorNumber();
71 for (int ifile = 0; ifile < file_names.size(); ifile++) {
72 std::string file_name = file_names[ifile];
73 // Check units of time stamps; should be days, if unit attribute exists.
74 // If it does not, print a warning and assume days
76 amrex::ParallelDescriptor::Bcast(&has_units,1,ioproc);
77 if (has_units) {
78 std::string unit_str = ReadNetCDFVarAttrStr(file_name, time_name, "units"); // works on proc 0
79 if (amrex::ParallelDescriptor::IOProcessor())
80 {
81 if (unit_str.find("days") == std::string::npos) {
82 amrex::Print() << "Units of ocean_time given as: " << unit_str << std::endl;
83 amrex::Abort("Units must be in days.");
84 }
85 }
86 } else {
87 amrex::Warning("Units attribute not found on time variable " + time_name + ". Assuming days");
88 }
89 // get times and put in array
91 amrex::Vector<RARRAY> array_ts(1);
92 ReadNetCDFFile(file_name, {time_name}, array_ts); // filled only on proc 0
93 if (amrex::ParallelDescriptor::IOProcessor())
94 {
95 int ntimes_io = array_ts[0].get_vshape()[0];
96 for (int nt(0); nt < ntimes_io; nt++)
97 {
98 // Convert ocean time from days to seconds
99 bry_times.push_back((*(array_ts[0].get_data() + nt)) * amrex::Real(60.0) * amrex::Real(60.0) * amrex::Real(24.0));
100 file_for_time.push_back(ifile);
101 file_itime_offset.push_back(nt);
102 }
103 }
104 }
105
106 int ntimes = bry_times.size();
107 // Only do checks on IO processor since bry_times isn't populated on other ranks yet
108 if (amrex::ParallelDescriptor::IOProcessor()) {
109 AMREX_ASSERT(std::is_sorted(bry_times.begin(), bry_times.end()));
110 if (ntimes <= 1) {
111 amrex::Error("Time series of boundary data must be given at at least two times");
112 }
113 }
114 amrex::ParallelDescriptor::Bcast(&ntimes,1,ioproc);
115 if (!(amrex::ParallelDescriptor::IOProcessor())) {
116 bry_times.resize(ntimes);
117 file_for_time.resize(ntimes);
119 }
120 amrex::ParallelDescriptor::Bcast(bry_times.data(), bry_times.size(), ioproc);
121 amrex::ParallelDescriptor::Bcast(file_for_time.data(), file_for_time.size(), ioproc);
122 amrex::ParallelDescriptor::Bcast(file_itime_offset.data(), file_itime_offset.size(), ioproc);
123
124 const auto& lo = domain.loVect();
125 const auto& hi = domain.hiVect();
126
127 amrex::Box xlo_bx(amrex::IntVect(lo[0]+index_type[0]-1, lo[1]+index_type[1]-1, lo[2]),
128 amrex::IntVect(lo[0]+index_type[0]-1, hi[1]+1 , hi[2]), index_type);
129 amrex::Box xhi_bx(amrex::IntVect(hi[0]+1 , lo[1]+index_type[1]-1, lo[2]),
130 amrex::IntVect(hi[0]+1 , hi[1]+1 , hi[2]), index_type);
131 amrex::Box ylo_bx(amrex::IntVect(lo[0]+index_type[0]-1, lo[1]+index_type[1]-1, lo[2]),
132 amrex::IntVect(hi[0]+1 , lo[1]+index_type[1]-1, hi[2]), index_type);
133 amrex::Box yhi_bx(amrex::IntVect(lo[0]+index_type[0]-1, hi[1]+1 , lo[2]),
134 amrex::IntVect(hi[0]+1 , hi[1]+1 , hi[2]), index_type);
135 if (is2d) {
136 xlo_bx.makeSlab(2,0);
137 xhi_bx.makeSlab(2,0);
138 ylo_bx.makeSlab(2,0);
139 yhi_bx.makeSlab(2,0);
140 }
141
142 // amrex::Print() << xlo_bx << " " << xhi_bx << " " << ylo_bx << " " << yhi_bx << std::endl;
143
144 xlo_dat_before = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
145 xhi_dat_before = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
146 ylo_dat_before = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
147 yhi_dat_before = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
148
149 xlo_dat_after = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
150 xhi_dat_after = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
151 ylo_dat_after = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
152 yhi_dat_after = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
153
154 xlo_dat_interp = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
155 xhi_dat_interp = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
156 ylo_dat_interp = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
157 yhi_dat_interp = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
158
159 // dummy initialization
160 i_time_before = -100;
161
162 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::low)] == true) {
163 nc_var_names.push_back(field_name + "_west");
164 }
165 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::high)] == true) {
166 nc_var_names.push_back(field_name + "_east");
167 }
168 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::low)] == true) {
169 nc_var_names.push_back(field_name + "_south");
170 }
171 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::high)] == true) {
172 nc_var_names.push_back(field_name + "_north");
173 }
174
175 // Nothing to check for a variable that reads no boundary data at all, and skipping
176 // keeps a run with many tracers from opening the file once per inert tracer
177 if (nc_var_names.empty()) {
178 return;
179 }
180
181 // Fail early and by name. read_in_at_time dereferences each variable unconditionally,
182 // so a file that is missing e.g. NO3_west would otherwise fail deep inside the reader
183 // with nothing to say which variable, which file, or which input asked for it.
184 for (const auto& file_name : file_names) {
186 std::string msg = "Boundary file " + file_name + " does not contain all of:";
187 for (const auto& var_name : nc_var_names) {
188 msg += " " + var_name;
189 }
190 msg += ". The boundary condition requested for " + field_name +
191 " reads from file (clamped, chapman, flather, or orlanski_rad_nudg)."
192 " Either add the missing variable(s) to the file, or give " + field_name +
193 " a boundary condition that needs no file data, such as outflow.";
194 amrex::Abort(msg);
195 }
196 }
197}
198
199/**
200 * @param time time to interpolate to
201 */
203{
204 // Nothing in the file for this variable, so there is nothing to read or
205 // interpolate. Returning here also keeps the reader from announcing that it is
206 // reading a variable the file does not contain: the caller updates every tracer
207 // in one sweep, and most of them are typically on a local boundary condition.
208 if (nc_var_names.empty()) {
209 return;
210 }
211
212 // Initialize Fabs
213 amrex::Arena* Arena_Used = amrex::The_Arena();
214#ifdef AMREX_USE_GPU
215 Arena_Used = amrex::The_Pinned_Arena();
216#endif
217
218 // Figure out time index:
220 AMREX_ASSERT(time <= bry_times[bry_times.size()-1]);
222 for (int nt=0; nt < bry_times.size()-1; nt++) {
223 if ((bry_times[nt] <= time) and (bry_times[nt+1] >= time)) {
224 i_time_before = nt;
226 time_after = bry_times[nt+1];
227 break;
228 }
229 }
230
231 int i_time_after = i_time_before + 1;
232
233 amrex::FArrayBox crse_xlo_dat;
234 amrex::FArrayBox crse_xhi_dat;
235 amrex::FArrayBox crse_ylo_dat;
236 amrex::FArrayBox crse_yhi_dat;
237
238 if (m_lev > 0) {
239 const auto& crse_lo = m_geom[0].Domain().loVect();
240 const auto& crse_hi = m_geom[0].Domain().hiVect();
241
242 amrex::Box crse_xlo_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_lo[1]+index_type[1]-1, crse_lo[2]),
243 amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_hi[1]+1 , crse_hi[2]), index_type);
244 amrex::Box crse_xhi_bx(amrex::IntVect(crse_hi[0]+1 , crse_lo[1]+index_type[1]-1, crse_lo[2]),
245 amrex::IntVect(crse_hi[0]+1 , crse_hi[1]+1 , crse_hi[2]), index_type);
246 amrex::Box crse_ylo_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_lo[1]+index_type[1]-1, crse_lo[2]),
247 amrex::IntVect(crse_hi[0]+1 , crse_lo[1]+index_type[1]-1, crse_hi[2]), index_type);
248 amrex::Box crse_yhi_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_hi[1]+1 , crse_lo[2]),
249 amrex::IntVect(crse_hi[0]+1 , crse_hi[1]+1 , crse_hi[2]), index_type);
250 if (is2d) {
251 crse_xlo_bx.makeSlab(2,0);
252 crse_xhi_bx.makeSlab(2,0);
253 crse_ylo_bx.makeSlab(2,0);
254 crse_yhi_bx.makeSlab(2,0);
255 }
256
257 crse_xlo_dat = amrex::FArrayBox(crse_xlo_bx, 1, Arena_Used);
258 crse_xhi_dat = amrex::FArrayBox(crse_xhi_bx, 1, Arena_Used);
259 crse_ylo_dat = amrex::FArrayBox(crse_ylo_bx, 1, Arena_Used);
260 crse_yhi_dat = amrex::FArrayBox(crse_yhi_bx, 1, Arena_Used);
261 }
262
263 if (i_time_before_old + 1 == i_time_before) {
264 // swap multifabs so we only have to read in one MultiFab
265 std::swap(xlo_dat_before, xlo_dat_after);
266 std::swap(xhi_dat_before, xhi_dat_after);
267 std::swap(ylo_dat_before, ylo_dat_after);
268 std::swap(yhi_dat_before, yhi_dat_after);
269
270 amrex::Print() << "Reading in " << field_name << " at (after) time " << i_time_after << std::endl;
271
272 if (m_lev == 0) {
274 } else {
275
277
282
283 // The_Pinned_Arena is not stream-ordered, so wait for interp_fab's
284 // kernels before these fabs are freed at return
285 amrex::Gpu::streamSynchronize();
286
287 }
288
289 } else if (i_time_before_old != i_time_before) {
290
291
292 if (m_lev == 0) {
293 amrex::Print() << "Reading in " << field_name << " at (before) time " << i_time_before << std::endl;
295 amrex::Print() << "Reading in " << field_name << " at (after) time " << i_time_after << std::endl;
297 } else {
298
299 amrex::Print() << "Reading in " << field_name << " at (before) time " << i_time_before << std::endl;
300
302
307
308 amrex::Print() << "Reading in " << field_name << " at time " << i_time_after << std::endl;
309
311
316
317 // The_Pinned_Arena is not stream-ordered, so wait for interp_fab's
318 // kernels before these fabs are freed at return
319 amrex::Gpu::streamSynchronize();
320 } // lev
321 } // i_time
322
323 amrex::Real dt = time_after - time_before;
324 amrex::Real time_before_copy = time_before;
325
326 amrex::Array4<amrex::Real> xlo_interp_arr = xlo_dat_interp.array();
327 amrex::Array4<amrex::Real> xhi_interp_arr = xhi_dat_interp.array();
328 amrex::Array4<amrex::Real> ylo_interp_arr = ylo_dat_interp.array();
329 amrex::Array4<amrex::Real> yhi_interp_arr = yhi_dat_interp.array();
330
331 amrex::Array4<amrex::Real> xlo_before_arr = xlo_dat_before.array();
332 amrex::Array4<amrex::Real> xhi_before_arr = xhi_dat_before.array();
333 amrex::Array4<amrex::Real> ylo_before_arr = ylo_dat_before.array();
334 amrex::Array4<amrex::Real> yhi_before_arr = yhi_dat_before.array();
335
336 amrex::Array4<amrex::Real> xlo_after_arr = xlo_dat_after.array();
337 amrex::Array4<amrex::Real> xhi_after_arr = xhi_dat_after.array();
338 amrex::Array4<amrex::Real> ylo_after_arr = ylo_dat_after.array();
339 amrex::Array4<amrex::Real> yhi_after_arr = yhi_dat_after.array();
340
341 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::low)] == true) {
342 amrex::ParallelFor(xlo_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
343 {
345 });
346 }
347
348 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::high)] == true) {
349 amrex::ParallelFor(xhi_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
350 {
352 });
353 }
354
355 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::low)] == true) {
356 amrex::ParallelFor(ylo_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
357 {
359 });
360 }
361
362 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::high)] == true) {
363 amrex::ParallelFor(yhi_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
364 {
366 });
367 }
368}
369
370/**
371 * @param[inout] fab_xlo fab to store xlo boundary data into
372 * @param[inout] fab_xhi fab to store xhi boundary data into
373 * @param[inout] fab_ylo fab to store ylo boundary data into
374 * @param[inout] fab_yhi fab to store yhi boundary data into
375 * @param[in ] itime index of time step to read from file
376 */
378 amrex::FArrayBox& fab_xhi,
379 amrex::FArrayBox& fab_ylo,
380 amrex::FArrayBox& fab_yhi,
381 int itime) {
382 // The host writes below land in pinned fabs that queued kernels may still be
383 // reading in place, so drain the stream first
384 amrex::Gpu::streamSynchronize();
385
387 amrex::Vector<RARRAY> arrays(nc_var_names.size());
388
389 amrex::Print() << "Actually reading in " << field_name << " at time " << bry_times[itime] << std::endl;
390 std::string nc_bdry_file = file_names[file_for_time[itime]];
392 ReadNetCDFFile(nc_bdry_file, nc_var_names, arrays, true, itime_offset); // does work on proc 0 only
393
394 for (int iv=0; iv < nc_var_names.size(); iv++) {
395 if (amrex::ParallelDescriptor::IOProcessor())
396 {
397 std::string last4 = nc_var_names[iv].substr(nc_var_names[iv].size()-4, 4);
398 std::string last5 = nc_var_names[iv].substr(nc_var_names[iv].size()-5, 5);
399 int nx, ny, nz, n_plane;
400 int i, j, k, ioff, joff;
401 if (last4 == "west") {
402 amrex::Box my_box = fab_xlo.box();
403 if (is2d) {
404 nz = 1;
405 ny = arrays[iv].get_vshape()[1];
406 } else {
407 nz = arrays[iv].get_vshape()[1];
408 ny = arrays[iv].get_vshape()[2];
409 }
410 n_plane = ny * nz;
412
413 i = my_box.smallEnd()[0];
414 joff = my_box.smallEnd()[1];
415
416 amrex::Array4<amrex::Real> fab_arr = fab_xlo.array();
417
418 for (int n(0); n < n_plane; n++) {
419 k = n / ny;
420 j = n - (k * ny);
421 fab_arr(i, j+joff, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
422 }
423 } else if (last4 == "east") {
424 amrex::Box my_box = fab_xhi.box();
425 if (is2d) {
426 nz = 1;
427 ny = arrays[iv].get_vshape()[1];
428 } else {
429 nz = arrays[iv].get_vshape()[1];
430 ny = arrays[iv].get_vshape()[2];
431 }
432 n_plane = ny * nz;
434
435 i = my_box.smallEnd()[0];
436 joff = my_box.smallEnd()[1];
437
438 amrex::Array4<amrex::Real> fab_arr = fab_xhi.array();
439 for (int n(0); n < n_plane; n++) {
440 k = n / ny;
441 j = n - (k * ny);
442 fab_arr(i, j+joff, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
443 }
444 } else if (last5 == "south") {
445 amrex::Box my_box = fab_ylo.box();
446 if (is2d) {
447 nz = 1;
448 nx = arrays[iv].get_vshape()[1];
449 } else {
450 nz = arrays[iv].get_vshape()[1];
451 nx = arrays[iv].get_vshape()[2];
452 }
453 n_plane = nx * nz;
455
456 j = my_box.smallEnd()[1];
457 ioff = my_box.smallEnd()[0];
458
459 amrex::Array4<amrex::Real> fab_arr = fab_ylo.array();
460 for (int n(0); n < n_plane; n++) {
461 k = n / nx;
462 i = n - (k * nx);
463 fab_arr(i+ioff, j, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
464 }
465 } else if (last5 == "north") {
466 amrex::Box my_box = fab_yhi.box();
467 if (is2d) {
468 nz = 1;
469 nx = arrays[iv].get_vshape()[1];
470 } else {
471 nz = arrays[iv].get_vshape()[1];
472 nx = arrays[iv].get_vshape()[2];
473 }
474 n_plane = nx * nz;
476
477 j = my_box.smallEnd()[1];
478 ioff = my_box.smallEnd()[0];
479
480 amrex::Array4<amrex::Real> fab_arr = fab_yhi.array();
481 for (int n(0); n < n_plane; n++) {
482 k = n / nx;
483 i = n - (k * nx);
484 fab_arr(i+ioff, j, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
485 }
486 }
487 }
488 }
489
490 amrex::ParallelDescriptor::Barrier();
491
492 // When an FArrayBox is built, space is allocated on every rank. However, we only
493 // filled the data in these FABs on the IOProcessor. So here we broadcast
494 // the data to every rank.
495 int ioproc = amrex::ParallelDescriptor::IOProcessorNumber(); // I/O rank
496 amrex::ParallelDescriptor::Bcast(fab_xlo.dataPtr(),fab_xlo.box().numPts(),ioproc);
497 amrex::ParallelDescriptor::Bcast(fab_xhi.dataPtr(),fab_xhi.box().numPts(),ioproc);
498 amrex::ParallelDescriptor::Bcast(fab_ylo.dataPtr(),fab_ylo.box().numPts(),ioproc);
499 amrex::ParallelDescriptor::Bcast(fab_yhi.dataPtr(),fab_yhi.box().numPts(),ioproc);
500
501 amrex::Print() << "DONE reading in " << field_name << " at time " << bry_times[itime] << std::endl;
502}
503
504/**
505 * @param[in ] dat_crse fab of coarse data to interpolate from
506 * @param[ out] dat_fine fab of fine data to interpoalte to
507 */
508void NCTimeSeriesBoundary::interp_fab(amrex::FArrayBox& dat_crse, amrex::FArrayBox& dat_fine)
509{
510 amrex::Array4<amrex::Real> crse_arr = dat_crse.array();
511 amrex::Array4<amrex::Real> fine_arr = dat_fine.array();
512
513 const auto& bhi = ubound(dat_crse.box());
514
515 int rx = m_rx;
516 int ry = m_ry;
517
518 amrex::Real xfac = one / static_cast<amrex::Real>(rx);
519 amrex::Real yfac = one / static_cast<amrex::Real>(ry);
520
521 // Doing box on x-face
522 if (dat_crse.box().length(0) == 1) {
523 // amrex::Print() << "DOING INTERP ON XFACE " << dat_crse.box() << " " << dat_fine.box() << std::endl;
524 if (dat_crse.box().ixType()[1] == 0) {
525 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
526 {
527 int i_f = (i == -1) ? -1 : rx*i;
528 if (j == -1) {
529 fine_arr(i_f,j,k) = crse_arr(i,j,k);
530 } else {
531 fine_arr(i_f,ry*j ,k) = crse_arr(i,j,k);
532 if (j < bhi.y) {
533 for (int n = 1; n < ry; n++) {
534 fine_arr(i_f,ry*j+n,k) = crse_arr(i,j,k) + n * yfac * (crse_arr(i,j+1,k) - crse_arr(i,j,k));
535 }
536 }
537 }
538 });
539 } else {
540 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
541 {
542 int i_f = (i == -1) ? -1 : rx*i;
543 if (j == -1) {
544 fine_arr(i_f,j,k) = crse_arr(i,j,k);
545 } else {
546 fine_arr(i_f,ry*j,k) = crse_arr(i,j,k);
547 if (j < bhi.y) {
548 for (int n = 1; n < ry; n++) {
549 fine_arr(i_f,ry*j+n,k) = crse_arr(i,j,k) + n * yfac * (crse_arr(i,j+1,k) - crse_arr(i,j,k));
550 }
551 }
552 }
553 });
554 }
555 } else if (dat_crse.box().length(1) == 1) {
556 // Doing box on y-face
557 // amrex::Print() << "DOING INTERP ON YFACE " << dat_crse.box() << " " << dat_fine.box() << std::endl;
558 if (dat_crse.box().ixType()[0] == 0) {
559 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
560 {
561 int j_f = (j == -1) ? -1 : ry*j;
562 if (i == -1) {
563 fine_arr(i,j_f,k) = crse_arr(i,j,k);
564 } else {
565 fine_arr(rx*i ,j_f,k) = crse_arr(i,j,k);
566 if (i < bhi.x) {
567 for (int n = 1; n < rx; n++) {
568 fine_arr(rx*i+n,j_f,k) = crse_arr(i,j,k) + n * xfac * (crse_arr(i+1,j,k) - crse_arr(i,j,k));
569 }
570 }
571 }
572 });
573 } else {
574 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
575 {
576 int j_f = (j == -1) ? -1 : ry*j;
577 if (i == -1) {
578 fine_arr(i,j_f,k) = crse_arr(i,j,k);
579 } else {
580 fine_arr(rx*i,j_f,k) = crse_arr(i,j,k);
581 if (i < bhi.x) {
582 for (int n = 1; n < rx; n++) {
583 fine_arr(rx*i+n,j_f,k) = crse_arr(i,j,k) + n * xfac * (crse_arr(i+1,j,k) - crse_arr(i,j,k));
584 }
585 }
586 }
587 });
588 }
589 } else {
590 amrex::Abort(" What am I doing here??");
591 }
592}
593
594#endif // REMORA_USE_NETCDF
constexpr amrex::Real one
mf_h setVal(geomdata.ProbHi(2))
AMREX_ALWAYS_ASSERT(!NSPeriodic||!EWPeriodic)
void ReadNetCDFFile(const std::string &fname, amrex::Vector< std::string > names, amrex::Vector< NDArray< DType > > &arrays, bool one_time=false, int fill_time=0)
Read in data from netcdf file and save to data arrays.
bool QueryNetCDFHasVars(const std::string &fname, const amrex::Vector< std::string > &var_names)
Helper function for testing whether a file carries every named variable.
bool QueryNetCDFVarAttrStr(const std::string &fname, const std::string &var_name, const std::string &attr_name)
Helper function for testing for the presence of a single variable attribute.
std::string ReadNetCDFVarAttrStr(const std::string &fname, const std::string &var_name, const std::string &attr_name)
Helper function for reading a single variable attribute.
amrex::FArrayBox yhi_dat_before
FArrayBox to store data at time_before at yhi boundary.
amrex::FArrayBox yhi_dat_after
FArrayBox to store data at time_after at yhi boundary.
amrex::GpuArray< bool, AMREX_SPACEDIM *2 > var_need_data
Array over boundaries indicating whether we need physical data for this variable.
void interp_fab(amrex::FArrayBox &dat_crse, amrex::FArrayBox &dat_fine)
spatially interpolate boundary fabs from level 0 data (read in) to current level
amrex::FArrayBox ylo_dat_before
FArrayBox to store data at time_before at ylo boundary.
amrex::FArrayBox xlo_dat_after
FArrayBox to store data at time_after at xlo boundary.
amrex::Vector< std::string > nc_var_names
Variable names that will be read from file.
amrex::FArrayBox ylo_dat_after
FArrayBox to store data at time_after at ylo boundary.
amrex::Real time_before
Time in ocean_times immediately before the last time interpolated to.
void Initialize()
Read in time array from file and allocate data arrays.
amrex::FArrayBox yhi_dat_interp
FArrayBox to store data at inteprolated time at yhi boundary *‍/.
amrex::FArrayBox xlo_dat_interp
FArrayBox to store data at inteprolated time at xlo boundary *‍/.
amrex::Vector< amrex::Real > bry_times
Time points in netcdf file.
std::string time_name
Field name for time series in netcdf file.
amrex::FArrayBox xhi_dat_interp
FArrayBox to store data at inteprolated time at xhi boundary *‍/.
amrex::IntVect index_type
Index type for field to fill.
int i_time_before
Time index immediately before the last time interpolated to.
std::string field_name
Field name in netcdf file.
amrex::FArrayBox ylo_dat_interp
FArrayBox to store data at inteprolated time at ylo boundary *‍/.
amrex::Vector< amrex::Geometry > m_geom
Geometry at all levels.
amrex::FArrayBox xhi_dat_after
FArrayBox to store data at time_after at xhi boundary.
NCTimeSeriesBoundary(int a_lev, const amrex::Vector< amrex::Geometry > a_geom, const amrex::Vector< std::string > &a_file_name, const std::string a_field_name, const std::string a_time_name, const amrex::IntVect a_index_type, const amrex::GpuArray< bool, AMREX_SPACEDIM *2 > &a_var_need_data, bool a_is2d, int rx, int ry)
Constructor.
void read_in_at_time(amrex::FArrayBox &fab_xlo, amrex::FArrayBox &fab_xhi, amrex::FArrayBox &fab_ylo, amrex::FArrayBox &fab_yhi, int itime)
Read in data from file at time index itime and fill into mf.
amrex::Vector< std::string > file_names
File name to read from.
amrex::Vector< int > file_itime_offset
Offset to access a particular time within its file.
amrex::FArrayBox xhi_dat_before
FArrayBox to store data at time_before at xhi boundary.
bool is2d
Whether the field we're reading in is 2d.
void update_interpolated_to_time(amrex::Real time)
Calculate interpolated values at time, reading in data as necessary.
int m_lev
Level at which we are holding the boundary data.
int m_rx
Refinement ratios relative to level 0.
amrex::FArrayBox xlo_dat_before
FArrayBox to store data at time_before at xlo boundary.
amrex::Real time_after
Time in ocean_times immediately after the last time interpolated to.
amrex::Vector< int > file_for_time
File index to access a particular time.
NDArray is the datatype designed to hold any data, including scalars, multidimensional arrays,...