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());
31 time_name = a_time_name;
32 field_name = a_field_name;
33 domain = a_geom[a_lev].Domain();
34 index_type = a_index_type;
35 var_need_data = *a_var_need_data;
36 is2d = a_is2d;
37 m_rx = a_rx;
38 m_ry = a_ry;
39}
40
42{
43 // Initialize Fabs
44 amrex::Arena* Arena_Used = amrex::The_Arena();
45#ifdef AMREX_USE_GPU
46 Arena_Used = amrex::The_Pinned_Arena();
47#endif
48
49 // open file
50 amrex::Print() << "Setting up boundary data for " << field_name << " coming from NetCDF file " << std::endl;
51
52 // The time field can have any number of names, depending on the field.
53 // If not specified in input file (time_name.empty()) then set it by default
54 if (time_name.empty())
55 {
56 time_name = "ocean_time";
57 }
58
59 int ioproc = amrex::ParallelDescriptor::IOProcessorNumber();
60 for (int ifile = 0; ifile < file_names.size(); ifile++) {
61 std::string file_name = file_names[ifile];
62 // Check units of time stamps; should be days, if unit attribute exists.
63 // If it does not, print a warning and assume days
64 int has_units = QueryNetCDFVarAttrStr(file_name, time_name, "units");
65 amrex::ParallelDescriptor::Bcast(&has_units,1,ioproc);
66 if (has_units) {
67 std::string unit_str = ReadNetCDFVarAttrStr(file_name, time_name, "units"); // works on proc 0
68 if (amrex::ParallelDescriptor::IOProcessor())
69 {
70 if (unit_str.find("days") == std::string::npos) {
71 amrex::Print() << "Units of ocean_time given as: " << unit_str << std::endl;
72 amrex::Abort("Units must be in days.");
73 }
74 }
75 } else {
76 amrex::Warning("Units attribute not found on time variable " + time_name + ". Assuming days");
77 }
78 // get times and put in array
79 using RARRAY = NDArray<amrex::Real>;
80 amrex::Vector<RARRAY> array_ts(1);
81 ReadNetCDFFile(file_name, {time_name}, array_ts); // filled only on proc 0
82 if (amrex::ParallelDescriptor::IOProcessor())
83 {
84 int ntimes_io = array_ts[0].get_vshape()[0];
85 for (int nt(0); nt < ntimes_io; nt++)
86 {
87 // Convert ocean time from days to seconds
88 bry_times.push_back((*(array_ts[0].get_data() + nt)) * amrex::Real(60.0) * amrex::Real(60.0) * amrex::Real(24.0));
89 file_for_time.push_back(ifile);
90 file_itime_offset.push_back(nt);
91 }
92 }
93 }
94
95 int ntimes = bry_times.size();
96 // Only do checks on IO processor since bry_times isn't populated on other ranks yet
97 if (amrex::ParallelDescriptor::IOProcessor()) {
98 AMREX_ASSERT(std::is_sorted(bry_times.begin(), bry_times.end()));
99 if (ntimes <= 1) {
100 amrex::Error("Time series of boundary data must be given at at least two times");
101 }
102 }
103 amrex::ParallelDescriptor::Bcast(&ntimes,1,ioproc);
104 if (!(amrex::ParallelDescriptor::IOProcessor())) {
105 bry_times.resize(ntimes);
106 file_for_time.resize(ntimes);
107 file_itime_offset.resize(ntimes);
108 }
109 amrex::ParallelDescriptor::Bcast(bry_times.data(), bry_times.size(), ioproc);
110 amrex::ParallelDescriptor::Bcast(file_for_time.data(), file_for_time.size(), ioproc);
111 amrex::ParallelDescriptor::Bcast(file_itime_offset.data(), file_itime_offset.size(), ioproc);
112
113 const auto& lo = domain.loVect();
114 const auto& hi = domain.hiVect();
115
116 amrex::Box xlo_bx(amrex::IntVect(lo[0]+index_type[0]-1, lo[1]+index_type[1]-1, lo[2]),
117 amrex::IntVect(lo[0]+index_type[0]-1, hi[1]+1 , hi[2]), index_type);
118 amrex::Box xhi_bx(amrex::IntVect(hi[0]+1 , lo[1]+index_type[1]-1, lo[2]),
119 amrex::IntVect(hi[0]+1 , hi[1]+1 , hi[2]), index_type);
120 amrex::Box ylo_bx(amrex::IntVect(lo[0]+index_type[0]-1, lo[1]+index_type[1]-1, lo[2]),
121 amrex::IntVect(hi[0]+1 , lo[1]+index_type[1]-1, hi[2]), index_type);
122 amrex::Box yhi_bx(amrex::IntVect(lo[0]+index_type[0]-1, hi[1]+1 , lo[2]),
123 amrex::IntVect(hi[0]+1 , hi[1]+1 , hi[2]), index_type);
124 if (is2d) {
125 xlo_bx.makeSlab(2,0);
126 xhi_bx.makeSlab(2,0);
127 ylo_bx.makeSlab(2,0);
128 yhi_bx.makeSlab(2,0);
129 }
130
131 // amrex::Print() << xlo_bx << " " << xhi_bx << " " << ylo_bx << " " << yhi_bx << std::endl;
132
133 xlo_dat_before = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
134 xhi_dat_before = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
135 ylo_dat_before = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
136 yhi_dat_before = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
137
138 xlo_dat_after = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
139 xhi_dat_after = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
140 ylo_dat_after = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
141 yhi_dat_after = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
142
143 xlo_dat_interp = amrex::FArrayBox(xlo_bx, 1, Arena_Used);
144 xhi_dat_interp = amrex::FArrayBox(xhi_bx, 1, Arena_Used);
145 ylo_dat_interp = amrex::FArrayBox(ylo_bx, 1, Arena_Used);
146 yhi_dat_interp = amrex::FArrayBox(yhi_bx, 1, Arena_Used);
147
148 // dummy initialization
149 i_time_before = -100;
150
151 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::low)] == true) {
152 nc_var_names.push_back(field_name + "_west");
153 }
154 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::high)] == true) {
155 nc_var_names.push_back(field_name + "_east");
156 }
157 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::low)] == true) {
158 nc_var_names.push_back(field_name + "_south");
159 }
160 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::high)] == true) {
161 nc_var_names.push_back(field_name + "_north");
162 }
163}
164
165/**
166 * @param time time to interpolate to
167 */
169{
170 // Initialize Fabs
171 amrex::Arena* Arena_Used = amrex::The_Arena();
172#ifdef AMREX_USE_GPU
173 Arena_Used = amrex::The_Pinned_Arena();
174#endif
175
176 // Figure out time index:
177 AMREX_ASSERT(time >= bry_times[0]);
178 AMREX_ASSERT(time <= bry_times[bry_times.size()-1]);
179 int i_time_before_old = i_time_before;
180 for (int nt=0; nt < bry_times.size()-1; nt++) {
181 if ((bry_times[nt] <= time) and (bry_times[nt+1] >= time)) {
182 i_time_before = nt;
184 time_after = bry_times[nt+1];
185 break;
186 }
187 }
188
189 int i_time_after = i_time_before + 1;
190
191 amrex::FArrayBox crse_xlo_dat;
192 amrex::FArrayBox crse_xhi_dat;
193 amrex::FArrayBox crse_ylo_dat;
194 amrex::FArrayBox crse_yhi_dat;
195
196 if (m_lev > 0) {
197 const auto& crse_lo = m_geom[0].Domain().loVect();
198 const auto& crse_hi = m_geom[0].Domain().hiVect();
199
200 amrex::Box crse_xlo_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_lo[1]+index_type[1]-1, crse_lo[2]),
201 amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_hi[1]+1 , crse_hi[2]), index_type);
202 amrex::Box crse_xhi_bx(amrex::IntVect(crse_hi[0]+1 , crse_lo[1]+index_type[1]-1, crse_lo[2]),
203 amrex::IntVect(crse_hi[0]+1 , crse_hi[1]+1 , crse_hi[2]), index_type);
204 amrex::Box crse_ylo_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_lo[1]+index_type[1]-1, crse_lo[2]),
205 amrex::IntVect(crse_hi[0]+1 , crse_lo[1]+index_type[1]-1, crse_hi[2]), index_type);
206 amrex::Box crse_yhi_bx(amrex::IntVect(crse_lo[0]+index_type[0]-1, crse_hi[1]+1 , crse_lo[2]),
207 amrex::IntVect(crse_hi[0]+1 , crse_hi[1]+1 , crse_hi[2]), index_type);
208 if (is2d) {
209 crse_xlo_bx.makeSlab(2,0);
210 crse_xhi_bx.makeSlab(2,0);
211 crse_ylo_bx.makeSlab(2,0);
212 crse_yhi_bx.makeSlab(2,0);
213 }
214
215 crse_xlo_dat = amrex::FArrayBox(crse_xlo_bx, 1, Arena_Used);
216 crse_xhi_dat = amrex::FArrayBox(crse_xhi_bx, 1, Arena_Used);
217 crse_ylo_dat = amrex::FArrayBox(crse_ylo_bx, 1, Arena_Used);
218 crse_yhi_dat = amrex::FArrayBox(crse_yhi_bx, 1, Arena_Used);
219 }
220
221 if (i_time_before_old + 1 == i_time_before) {
222 // swap multifabs so we only have to read in one MultiFab
223 std::swap(xlo_dat_before, xlo_dat_after);
224 std::swap(xhi_dat_before, xhi_dat_after);
225 std::swap(ylo_dat_before, ylo_dat_after);
226 std::swap(yhi_dat_before, yhi_dat_after);
227
228 amrex::Print() << "Reading in " << field_name << " at (after) time " << i_time_after << std::endl;
229
230 if (m_lev == 0) {
232 } else {
233
234 read_in_at_time(crse_xlo_dat, crse_xhi_dat, crse_ylo_dat, crse_yhi_dat, i_time_after);
235
236 interp_fab(crse_xlo_dat, xlo_dat_after);
237 interp_fab(crse_xhi_dat, xhi_dat_after);
238 interp_fab(crse_ylo_dat, ylo_dat_after);
239 interp_fab(crse_yhi_dat, yhi_dat_after);
240
241 }
242
243 } else if (i_time_before_old != i_time_before) {
244
245
246 if (m_lev == 0) {
247 amrex::Print() << "Reading in " << field_name << " at (before) time " << i_time_before << std::endl;
249 amrex::Print() << "Reading in " << field_name << " at (after) time " << i_time_after << std::endl;
251 } else {
252
253 amrex::Print() << "Reading in " << field_name << " at (before) time " << i_time_before << std::endl;
254
255 read_in_at_time(crse_xlo_dat, crse_xhi_dat, crse_ylo_dat,crse_yhi_dat, i_time_before);
256
257 interp_fab(crse_xlo_dat, xlo_dat_before);
258 interp_fab(crse_xhi_dat, xhi_dat_before);
259 interp_fab(crse_ylo_dat, ylo_dat_before);
260 interp_fab(crse_yhi_dat, yhi_dat_before);
261
262 amrex::Print() << "Reading in " << field_name << " at time " << i_time_after << std::endl;
263
264 read_in_at_time(crse_xlo_dat, crse_xhi_dat, crse_ylo_dat, crse_yhi_dat, i_time_after);
265
266 interp_fab(crse_xlo_dat, xlo_dat_after);
267 interp_fab(crse_xhi_dat, xhi_dat_after);
268 interp_fab(crse_ylo_dat, ylo_dat_after);
269 interp_fab(crse_yhi_dat, yhi_dat_after);
270 } // lev
271 } // i_time
272
273 amrex::Real dt = time_after - time_before;
274 amrex::Real time_before_copy = time_before;
275
276 amrex::Array4<amrex::Real> xlo_interp_arr = xlo_dat_interp.array();
277 amrex::Array4<amrex::Real> xhi_interp_arr = xhi_dat_interp.array();
278 amrex::Array4<amrex::Real> ylo_interp_arr = ylo_dat_interp.array();
279 amrex::Array4<amrex::Real> yhi_interp_arr = yhi_dat_interp.array();
280
281 amrex::Array4<amrex::Real> xlo_before_arr = xlo_dat_before.array();
282 amrex::Array4<amrex::Real> xhi_before_arr = xhi_dat_before.array();
283 amrex::Array4<amrex::Real> ylo_before_arr = ylo_dat_before.array();
284 amrex::Array4<amrex::Real> yhi_before_arr = yhi_dat_before.array();
285
286 amrex::Array4<amrex::Real> xlo_after_arr = xlo_dat_after.array();
287 amrex::Array4<amrex::Real> xhi_after_arr = xhi_dat_after.array();
288 amrex::Array4<amrex::Real> ylo_after_arr = ylo_dat_after.array();
289 amrex::Array4<amrex::Real> yhi_after_arr = yhi_dat_after.array();
290
291 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::low)] == true) {
292 amrex::ParallelFor(xlo_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
293 {
294 xlo_interp_arr(i,j,k) = xlo_before_arr(i,j,k) + (time - time_before_copy) * (xlo_after_arr(i,j,k) - xlo_before_arr(i,j,k)) / dt;
295 });
296 }
297
298 if (var_need_data[amrex::Orientation(amrex::Direction::x,amrex::Orientation::high)] == true) {
299 amrex::ParallelFor(xhi_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
300 {
301 xhi_interp_arr(i,j,k) = xhi_before_arr(i,j,k) + (time - time_before_copy) * (xhi_after_arr(i,j,k) - xhi_before_arr(i,j,k)) / dt;
302 });
303 }
304
305 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::low)] == true) {
306 amrex::ParallelFor(ylo_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
307 {
308 ylo_interp_arr(i,j,k) = ylo_before_arr(i,j,k) + (time - time_before_copy) * (ylo_after_arr(i,j,k) - ylo_before_arr(i,j,k)) / dt;
309 });
310 }
311
312 if (var_need_data[amrex::Orientation(amrex::Direction::y,amrex::Orientation::high)] == true) {
313 amrex::ParallelFor(yhi_dat_interp.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
314 {
315 yhi_interp_arr(i,j,k) = yhi_before_arr(i,j,k) + (time - time_before_copy) * (yhi_after_arr(i,j,k) - yhi_before_arr(i,j,k)) / dt;
316 });
317 }
318}
319
320/**
321 * @param[inout] fab_xlo fab to store xlo boundary data into
322 * @param[inout] fab_xhi fab to store xhi boundary data into
323 * @param[inout] fab_ylo fab to store ylo boundary data into
324 * @param[inout] fab_yhi fab to store yhi boundary data into
325 * @param[in ] itime index of time step to read from file
326 */
327void NCTimeSeriesBoundary::read_in_at_time (amrex::FArrayBox& fab_xlo,
328 amrex::FArrayBox& fab_xhi,
329 amrex::FArrayBox& fab_ylo,
330 amrex::FArrayBox& fab_yhi,
331 int itime) {
332 using RARRAY = NDArray<amrex::Real>;
333 amrex::Vector<RARRAY> arrays(nc_var_names.size());
334
335 amrex::Print() << "Actually reading in " << field_name << " at time " << bry_times[itime] << std::endl;
336 std::string nc_bdry_file = file_names[file_for_time[itime]];
337 int itime_offset = file_itime_offset[itime];
338 ReadNetCDFFile(nc_bdry_file, nc_var_names, arrays, true, itime_offset); // does work on proc 0 only
339
340 for (int iv=0; iv < nc_var_names.size(); iv++) {
341 if (amrex::ParallelDescriptor::IOProcessor())
342 {
343 std::string last4 = nc_var_names[iv].substr(nc_var_names[iv].size()-4, 4);
344 std::string last5 = nc_var_names[iv].substr(nc_var_names[iv].size()-5, 5);
345 int nx, ny, nz, n_plane;
346 int i, j, k, ioff, joff;
347 if (last4 == "west") {
348 amrex::Box my_box = fab_xlo.box();
349 if (is2d) {
350 nz = 1;
351 ny = arrays[iv].get_vshape()[1];
352 } else {
353 nz = arrays[iv].get_vshape()[1];
354 ny = arrays[iv].get_vshape()[2];
355 }
356 n_plane = ny * nz;
357 AMREX_ALWAYS_ASSERT(my_box.numPts() == n_plane);
358
359 i = my_box.smallEnd()[0];
360 joff = my_box.smallEnd()[1];
361
362 amrex::Array4<amrex::Real> fab_arr = fab_xlo.array();
363
364 for (int n(0); n < n_plane; n++) {
365 k = n / ny;
366 j = n - (k * ny);
367 fab_arr(i, j+joff, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
368 }
369 } else if (last4 == "east") {
370 amrex::Box my_box = fab_xhi.box();
371 if (is2d) {
372 nz = 1;
373 ny = arrays[iv].get_vshape()[1];
374 } else {
375 nz = arrays[iv].get_vshape()[1];
376 ny = arrays[iv].get_vshape()[2];
377 }
378 n_plane = ny * nz;
379 AMREX_ALWAYS_ASSERT(my_box.numPts() == n_plane);
380
381 i = my_box.smallEnd()[0];
382 joff = my_box.smallEnd()[1];
383
384 amrex::Array4<amrex::Real> fab_arr = fab_xhi.array();
385 for (int n(0); n < n_plane; n++) {
386 k = n / ny;
387 j = n - (k * ny);
388 fab_arr(i, j+joff, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
389 }
390 } else if (last5 == "south") {
391 amrex::Box my_box = fab_ylo.box();
392 if (is2d) {
393 nz = 1;
394 nx = arrays[iv].get_vshape()[1];
395 } else {
396 nz = arrays[iv].get_vshape()[1];
397 nx = arrays[iv].get_vshape()[2];
398 }
399 n_plane = nx * nz;
400 AMREX_ALWAYS_ASSERT(my_box.numPts() == n_plane);
401
402 j = my_box.smallEnd()[1];
403 ioff = my_box.smallEnd()[0];
404
405 amrex::Array4<amrex::Real> fab_arr = fab_ylo.array();
406 for (int n(0); n < n_plane; n++) {
407 k = n / nx;
408 i = n - (k * nx);
409 fab_arr(i+ioff, j, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
410 }
411 } else if (last5 == "north") {
412 amrex::Box my_box = fab_yhi.box();
413 if (is2d) {
414 nz = 1;
415 nx = arrays[iv].get_vshape()[1];
416 } else {
417 nz = arrays[iv].get_vshape()[1];
418 nx = arrays[iv].get_vshape()[2];
419 }
420 n_plane = nx * nz;
421 AMREX_ALWAYS_ASSERT(my_box.numPts() == n_plane);
422
423 j = my_box.smallEnd()[1];
424 ioff = my_box.smallEnd()[0];
425
426 amrex::Array4<amrex::Real> fab_arr = fab_yhi.array();
427 for (int n(0); n < n_plane; n++) {
428 k = n / nx;
429 i = n - (k * nx);
430 fab_arr(i+ioff, j, k, 0) = static_cast<amrex::Real>(*(arrays[iv].get_data() + n));
431 }
432 }
433 }
434 }
435
436 amrex::ParallelDescriptor::Barrier();
437
438 // When an FArrayBox is built, space is allocated on every rank. However, we only
439 // filled the data in these FABs on the IOProcessor. So here we broadcast
440 // the data to every rank.
441 int ioproc = amrex::ParallelDescriptor::IOProcessorNumber(); // I/O rank
442 amrex::ParallelDescriptor::Bcast(fab_xlo.dataPtr(),fab_xlo.box().numPts(),ioproc);
443 amrex::ParallelDescriptor::Bcast(fab_xhi.dataPtr(),fab_xhi.box().numPts(),ioproc);
444 amrex::ParallelDescriptor::Bcast(fab_ylo.dataPtr(),fab_ylo.box().numPts(),ioproc);
445 amrex::ParallelDescriptor::Bcast(fab_yhi.dataPtr(),fab_yhi.box().numPts(),ioproc);
446
447 amrex::Print() << "DONE reading in " << field_name << " at time " << bry_times[itime] << std::endl;
448}
449
450/**
451 * @param[in ] dat_crse fab of coarse data to interpolate from
452 * @param[ out] dat_fine fab of fine data to interpoalte to
453 */
454void NCTimeSeriesBoundary::interp_fab(amrex::FArrayBox& dat_crse, amrex::FArrayBox& dat_fine)
455{
456 amrex::Array4<amrex::Real> crse_arr = dat_crse.array();
457 amrex::Array4<amrex::Real> fine_arr = dat_fine.array();
458
459 const auto& bhi = ubound(dat_crse.box());
460
461 int rx = m_rx;
462 int ry = m_ry;
463
464 amrex::Real xfac = 1.0 / static_cast<amrex::Real>(rx);
465 amrex::Real yfac = 1.0 / static_cast<amrex::Real>(ry);
466
467 // Doing box on x-face
468 if (dat_crse.box().length(0) == 1) {
469 // amrex::Print() << "DOING INTERP ON XFACE " << dat_crse.box() << " " << dat_fine.box() << std::endl;
470 if (dat_crse.box().ixType()[1] == 0) {
471 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
472 {
473 int i_f = (i == -1) ? -1 : rx*i;
474 if (j == -1) {
475 fine_arr(i_f,j,k) = crse_arr(i,j,k);
476 } else {
477 fine_arr(i_f,ry*j ,k) = crse_arr(i,j,k);
478 if (j < bhi.y) {
479 for (int n = 1; n < ry; n++) {
480 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));
481 }
482 }
483 }
484 });
485 } else {
486 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
487 {
488 int i_f = (i == -1) ? -1 : rx*i;
489 if (j == -1) {
490 fine_arr(i_f,j,k) = crse_arr(i,j,k);
491 } else {
492 fine_arr(i_f,ry*j,k) = crse_arr(i,j,k);
493 if (j < bhi.y) {
494 for (int n = 1; n < ry; n++) {
495 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));
496 }
497 }
498 }
499 });
500 }
501 } else if (dat_crse.box().length(1) == 1) {
502 // Doing box on y-face
503 // amrex::Print() << "DOING INTERP ON YFACE " << dat_crse.box() << " " << dat_fine.box() << std::endl;
504 if (dat_crse.box().ixType()[0] == 0) {
505 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
506 {
507 int j_f = (j == -1) ? -1 : ry*j;
508 if (i == -1) {
509 fine_arr(i,j_f,k) = crse_arr(i,j,k);
510 } else {
511 fine_arr(rx*i ,j_f,k) = crse_arr(i,j,k);
512 if (i < bhi.x) {
513 for (int n = 1; n < rx; n++) {
514 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));
515 }
516 }
517 }
518 });
519 } else {
520 amrex::ParallelFor(dat_crse.box(), [=] AMREX_GPU_DEVICE (int i, int j, int k)
521 {
522 int j_f = (j == -1) ? -1 : ry*j;
523 if (i == -1) {
524 fine_arr(i,j_f,k) = crse_arr(i,j,k);
525 } else {
526 fine_arr(rx*i,j_f,k) = crse_arr(i,j,k);
527 if (i < bhi.x) {
528 for (int n = 1; n < rx; n++) {
529 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));
530 }
531 }
532 }
533 });
534 }
535 } else {
536 amrex::Abort(" What am I doing here??");
537 }
538}
539
540#endif // REMORA_USE_NETCDF
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 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.
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.
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.
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,...