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
90 amrex::Vector<NDArray<double>> array_ts(1);
91 ReadNetCDFFile(file_name, {time_name}, array_ts); // filled only on proc 0
92 if (amrex::ParallelDescriptor::IOProcessor())
93 {
94 int ntimes_io = array_ts[0].get_vshape()[0];
95 for (int nt(0); nt < ntimes_io; nt++)
96 {
97 // Convert ocean time from days to seconds
98 bry_times.push_back((*(array_ts[0].get_data() + nt)) * 60.0 * 60.0 * 24.0);
99 file_for_time.push_back(ifile);
100 file_itime_offset.push_back(nt);
101 }
102 }
103 }
104
105 int ntimes = bry_times.size();
106 // Only do checks on IO processor since bry_times isn't populated on other ranks yet
107 if (amrex::ParallelDescriptor::IOProcessor()) {
108 AMREX_ASSERT(std::is_sorted(bry_times.begin(), bry_times.end()));
109 if (ntimes <= 1) {
110 amrex::Error("Time series of boundary data must be given at at least two times");
111 }
112 }
113 amrex::ParallelDescriptor::Bcast(&ntimes,1,ioproc);
114 if (!(amrex::ParallelDescriptor::IOProcessor())) {
115 bry_times.resize(ntimes);
116 file_for_time.resize(ntimes);
118 }
119 amrex::ParallelDescriptor::Bcast(bry_times.data(), bry_times.size(), ioproc);
120 amrex::ParallelDescriptor::Bcast(file_for_time.data(), file_for_time.size(), ioproc);
121 amrex::ParallelDescriptor::Bcast(file_itime_offset.data(), file_itime_offset.size(), ioproc);
122
123 const auto& lo = domain.loVect();
124 const auto& hi = domain.hiVect();
125
126 amrex::Box xlo_bx(amrex::IntVect(lo[0]+index_type[0]-1, lo[1]+index_type[1]-1, lo[2]),
127 amrex::IntVect(lo[0]+index_type[0]-1, hi[1]+1 , hi[2]), index_type);
128 amrex::Box xhi_bx(amrex::IntVect(hi[0]+1 , lo[1]+index_type[1]-1, lo[2]),
129 amrex::IntVect(hi[0]+1 , hi[1]+1 , hi[2]), index_type);
130 amrex::Box ylo_bx(amrex::IntVect(lo[0]+index_type[0]-1, lo[1]+index_type[1]-1, lo[2]),
131 amrex::IntVect(hi[0]+1 , lo[1]+index_type[1]-1, hi[2]), index_type);
132 amrex::Box yhi_bx(amrex::IntVect(lo[0]+index_type[0]-1, hi[1]+1 , lo[2]),
133 amrex::IntVect(hi[0]+1 , hi[1]+1 , hi[2]), index_type);
134 if (is2d) {
135 xlo_bx.makeSlab(2,0);
136 xhi_bx.makeSlab(2,0);
137 ylo_bx.makeSlab(2,0);
138 yhi_bx.makeSlab(2,0);
139 }
140
141 // amrex::Print() << xlo_bx << " " << xhi_bx << " " << ylo_bx << " " << yhi_bx << std::endl;
142
143 xlo_dat_before = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
144 xhi_dat_before = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
145 ylo_dat_before = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
146 yhi_dat_before = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
147
148 xlo_dat_after = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
149 xhi_dat_after = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
150 ylo_dat_after = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
151 yhi_dat_after = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
152
153 xlo_dat_interp = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
154 xhi_dat_interp = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
155 ylo_dat_interp = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
156 yhi_dat_interp = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
157
158 // dummy initialization
159 i_time_before = -100;
160
161 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::low)] == true) {
162 nc_var_names.push_back(field_name + "_west");
163 }
164 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::high)] == true) {
165 nc_var_names.push_back(field_name + "_east");
166 }
167 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::low)] == true) {
168 nc_var_names.push_back(field_name + "_south");
169 }
170 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::high)] == true) {
171 nc_var_names.push_back(field_name + "_north");
172 }
173
174 // Nothing to check for a variable that reads no boundary data at all, and skipping
175 // keeps a run with many tracers from opening the file once per inert tracer
176 if (nc_var_names.empty()) {
177 return;
178 }
179
180 // Fail early and by name. read_in_at_time dereferences each variable unconditionally,
181 // so a file that is missing e.g. NO3_west would otherwise fail deep inside the reader
182 // with nothing to say which variable, which file, or which input asked for it.
183 for (const auto& file_name : file_names) {
185 std::string msg = "Boundary file " + file_name + " does not contain all of:";
186 for (const auto& var_name : nc_var_names) {
187 msg += " " + var_name;
188 }
189 msg += ". The boundary condition requested for " + field_name +
190 " reads from file (clamped, chapman, flather, or orlanski_rad_nudg)."
191 " Either add the missing variable(s) to the file, or give " + field_name +
192 " a boundary condition that needs no file data, such as outflow.";
193 amrex::Abort(msg);
194 }
195 }
196}
197
198/**
199 * @param time time to interpolate to
200 */
202{
203 // Nothing in the file for this variable, so there is nothing to read or
204 // interpolate. Returning here also keeps the reader from announcing that it is
205 // reading a variable the file does not contain: the caller updates every tracer
206 // in one sweep, and most of them are typically on a local boundary condition.
207 if (nc_var_names.empty()) {
208 return;
209 }
210
211 // Initialize Fabs
212 amrex::Arena* Arena_Used = amrex::The_Arena();
213#ifdef AMREX_USE_GPU
214 Arena_Used = amrex::The_Pinned_Arena();
215#endif
216
217 // Figure out time index:
219 AMREX_ASSERT(time <= bry_times[bry_times.size()-1]);
221 for (int nt=0; nt < bry_times.size()-1; nt++) {
222 if ((bry_times[nt] <= time) and (bry_times[nt+1] >= time)) {
223 i_time_before = nt;
225 time_after = bry_times[nt+1];
226 break;
227 }
228 }
229
230 int i_time_after = i_time_before + 1;
231
232 amrex::FArrayBox crse_xlo_dat;
233 amrex::FArrayBox crse_xhi_dat;
234 amrex::FArrayBox crse_ylo_dat;
235 amrex::FArrayBox crse_yhi_dat;
236
237 if (m_lev > 0) {
238 const auto& crse_lo = m_geom[0].Domain().loVect();
239 const auto& crse_hi = m_geom[0].Domain().hiVect();
240
241 amrex::Box crse_xlo_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_lo[1]+index_type[1]-1, crse_lo[2]),
242 amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_hi[1]+1 , crse_hi[2]), index_type);
243 amrex::Box crse_xhi_bx(amrex::IntVect(crse_hi[0]+1 , crse_lo[1]+index_type[1]-1, crse_lo[2]),
244 amrex::IntVect(crse_hi[0]+1 , crse_hi[1]+1 , crse_hi[2]), index_type);
245 amrex::Box crse_ylo_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_lo[1]+index_type[1]-1, crse_lo[2]),
246 amrex::IntVect(crse_hi[0]+1 , crse_lo[1]+index_type[1]-1, crse_hi[2]), index_type);
247 amrex::Box crse_yhi_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_hi[1]+1 , crse_lo[2]),
248 amrex::IntVect(crse_hi[0]+1 , crse_hi[1]+1 , crse_hi[2]), index_type);
249 if (is2d) {
250 crse_xlo_bx.makeSlab(2,0);
251 crse_xhi_bx.makeSlab(2,0);
252 crse_ylo_bx.makeSlab(2,0);
253 crse_yhi_bx.makeSlab(2,0);
254 }
255
256 crse_xlo_dat = amrex::FArrayBox(crse_xlo_bx, 1, Arena_Used);
257 crse_xhi_dat = amrex::FArrayBox(crse_xhi_bx, 1, Arena_Used);
258 crse_ylo_dat = amrex::FArrayBox(crse_ylo_bx, 1, Arena_Used);
259 crse_yhi_dat = amrex::FArrayBox(crse_yhi_bx, 1, Arena_Used);
260 }
261
262 if (i_time_before_old + 1 == i_time_before) {
263 // swap multifabs so we only have to read in one MultiFab
264 std::swap(xlo_dat_before, xlo_dat_after);
265 std::swap(xhi_dat_before, xhi_dat_after);
266 std::swap(ylo_dat_before, ylo_dat_after);
267 std::swap(yhi_dat_before, yhi_dat_after);
268
269 amrex::Print() << "Reading in " << field_name << " at (after) time " << i_time_after << std::endl;
270
271 if (m_lev == 0) {
273 } else {
274
276
281
282 // The_Pinned_Arena is not stream-ordered, so wait for interp_fab's
283 // kernels before these fabs are freed at return
284 amrex::Gpu::streamSynchronize();
285
286 }
287
288 } else if (i_time_before_old != i_time_before) {
289
290
291 if (m_lev == 0) {
292 amrex::Print() << "Reading in " << field_name << " at (before) time " << i_time_before << std::endl;
294 amrex::Print() << "Reading in " << field_name << " at (after) time " << i_time_after << std::endl;
296 } else {
297
298 amrex::Print() << "Reading in " << field_name << " at (before) time " << i_time_before << std::endl;
299
301
306
307 amrex::Print() << "Reading in " << field_name << " at time " << i_time_after << std::endl;
308
310
315
316 // The_Pinned_Arena is not stream-ordered, so wait for interp_fab's
317 // kernels before these fabs are freed at return
318 amrex::Gpu::streamSynchronize();
319 } // lev
320 } // i_time
321
322 // Both differences are small, so Real holds them even when the times do not.
323 const amrex::Real dt = static_cast<amrex::Real>(time_after - time_before);
324 const amrex::Real time_since_before = static_cast<amrex::Real>(time - 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::Vector< double > bry_times
Time points in netcdf file, in seconds on the model clock.
double time_before
Time in ocean_times immediately before the last time interpolated to.
void update_interpolated_to_time(double time)
Calculate interpolated values at time, in seconds on the model clock, reading in data as necessary.
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 *‍/.
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.
double time_after
Time in ocean_times immediately after the last time interpolated to.
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.
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::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,...