REMORA
Regional Modeling of Oceans Refined Adaptively
Loading...
Searching...
No Matches
REMORA.cpp
Go to the documentation of this file.
1/**
2 * \file REMORA.cpp
3 */
4
6#include <REMORA.H>
7
8#include <AMReX_buildInfo.H>
9
10using namespace amrex;
11
12amrex::Real REMORA::startCPUTime = zero;
14
15Vector<AMRErrorTag> REMORA::ref_tags;
16
18
19// Time step control
20amrex::Real REMORA::cfl = Real(0.8);
21amrex::Real REMORA::fixed_dt = -one;
22amrex::Real REMORA::fixed_fast_dt = -one;
23amrex::Real REMORA::change_max = Real(1.1);
24
26
27// Dictate verbosity in screen output
28int REMORA::verbose = 0;
29
30// Frequency of diagnostic output
32amrex::Real REMORA::sum_per = -one;
33
34// Minimum number of digits in plotfile name
36
37// Do we include staggered velocities in the plotfile?
39
40// Do we include nodal data (Nu_nd) in the plotfile?
41bool REMORA::plot_nodal_data = true;
42
43// Native AMReX vs NetCDF
45
46#ifdef REMORA_USE_NETCDF
47
49
50// Do we write one file per timestep (false) or one file for all timesteps (true)
52
53// NetCDF initialization file
54amrex::Vector<std::string> REMORA::nc_bdry_file = {""}; // Must provide via input
55amrex::Vector<amrex::Vector<std::string>> REMORA::nc_init_file = {{""}}; // Must provide via input
56amrex::Vector<amrex::Vector<std::string>> REMORA::nc_grid_file = {{""}}; // Must provide via input
57#endif
58
59/**
60 * constructor:
61 * - reads in parameters from inputs file
62 * - sizes multilevel arrays and data structures
63 * - initializes BCRec boundary condition object
64 */
66{
67 BL_PROFILE("REMORA::REMORA()");
68
69 if (ParallelDescriptor::IOProcessor()) {
70 const char* remora_hash = amrex::buildInfoGetGitHash(1);
71 const char* amrex_hash = amrex::buildInfoGetGitHash(2);
72 const char* buildgithash = amrex::buildInfoGetBuildGitHash();
73 const char* buildgitname = amrex::buildInfoGetBuildGitName();
74
75 if (strlen(remora_hash) > 0) {
76 amrex::Print() << "\n"
77 << "REMORA git hash: " << remora_hash << "\n";
78 }
79 if (strlen(amrex_hash) > 0) {
80 amrex::Print() << "AMReX git hash: " << amrex_hash << "\n";
81 }
82 if (strlen(buildgithash) > 0) {
83 amrex::Print() << buildgitname << " git hash: " << buildgithash << "\n";
84 }
85
86 amrex::Print() << "\n";
87 }
88
90
91 // Blocking factor in z set to very large value to be > nz
92 // This guarantees that there will be no domain decomposition in the z-direction
93 // We have to set this by hand here because setting it in the input file will
94 // cause checks in the AmrCore constructor to fail.
95 Vector<IntVect> blocking_factor_vec = Vector<IntVect>();
96 blocking_factor_vec.resize(max_level+1);
97 for (int lev = 0; lev <= max_level; ++lev) {
98 blocking_factor_vec[lev] = blockingFactor(lev);
99 blocking_factor_vec[lev][2] = 4096;
100 }
101 SetBlockingFactor(blocking_factor_vec);
102
103 const std::string& pv3d = "plot_vars_3d"; set3DPlotVariables(pv3d);
104 const std::string& pv2d = "plot_vars_2d"; set2DPlotVariables(pv2d);
105
106 prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
107
108 // Geometry on all levels has been defined already.
109
110 // No valid BoxArray and DistributionMapping have been defined.
111 // But the arrays for them have been resized.
112
113 int nlevs_max = max_level + 1;
114
115 istep.resize(nlevs_max, 0);
116 nsubsteps.resize(nlevs_max, 1);
117 for (int lev = 1; lev <= max_level; ++lev) {
118 nsubsteps[lev] = do_substep ? MaxRefRatio(lev-1) : 1;
119 }
120
121 physbcs.resize(nlevs_max);
122
123 t_new.resize(nlevs_max, zero);
124 t_old.resize(nlevs_max, -bogus_large_value);
125 dt.resize(nlevs_max, bogus_large_value);
126
127 cons_new.resize(nlevs_max);
128 cons_old.resize(nlevs_max);
129 xvel_new.resize(nlevs_max);
130 xvel_old.resize(nlevs_max);
131 yvel_new.resize(nlevs_max);
132 yvel_old.resize(nlevs_max);
133 zvel_new.resize(nlevs_max);
134 zvel_old.resize(nlevs_max);
135
136 advflux_reg.resize(nlevs_max);
137
138 // Initialize tagging criteria for mesh refinement
140
141 IntVect cum_ref_ratio = IntVect(1,1,0);
142 cum_ref_ratios.push_back(cum_ref_ratio);
143 // We have already read in the ref_Ratio (via amr.ref_ratio =) but we need to enforce
144 // that there is no refinement in the vertical so we test on that here.
145 for (int lev = 0; lev < max_level; ++lev)
146 {
147 amrex::Print() << "Refinement ratio at level " << lev << " set to be " <<
148 ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
149
150 if (ref_ratio[lev][2] != 1)
151 {
152 amrex::Print() << "********************************************************************************" << std::endl;
153 amrex::Print() << "We don't allow refinement in the vertical -- make sure to set ref_ratio = 1 in z" << std::endl;
154 amrex::Print() << "It's possible you set amr.ref_ratio when you meant to set amr.ref_ratio_vect " << std::endl;
155 amrex::Print() << "********************************************************************************" << std::endl;
156 amrex::Abort();
157 }
158
159 cum_ref_ratio[0] *= ref_ratio[lev][0];
160 cum_ref_ratio[1] *= ref_ratio[lev][1];
161 cum_ref_ratios.push_back(cum_ref_ratio);
162 }
163}
164
165REMORA::REMORA (const amrex::RealBox& rb, int max_level_in, const amrex::Vector<int>& n_cell_in, int coord, const amrex::Vector<amrex::IntVect>& ref_ratio_in, const amrex::Array<int,AMREX_SPACEDIM>& is_per, std::string prefix)
166 : amrex::AmrCore (rb, max_level_in, n_cell_in, coord, ref_ratio_in, is_per)
167{
168 BL_PROFILE("REMORA::REMORA(explicit)");
169 pp_prefix = prefix;
170
171 if (ParallelDescriptor::IOProcessor()) {
172 const char* remora_hash = amrex::buildInfoGetGitHash(1);
173 const char* amrex_hash = amrex::buildInfoGetGitHash(2);
174 const char* buildgithash = amrex::buildInfoGetBuildGitHash();
175 const char* buildgitname = amrex::buildInfoGetBuildGitName();
176
177 if (strlen(remora_hash) > 0) {
178 amrex::Print() << "\n"
179 << "REMORA git hash: " << remora_hash << "\n";
180 }
181 if (strlen(amrex_hash) > 0) {
182 amrex::Print() << "AMReX git hash: " << amrex_hash << "\n";
183 }
184 if (strlen(buildgithash) > 0) {
185 amrex::Print() << buildgitname << " git hash: " << buildgithash << "\n";
186 }
187
188 amrex::Print() << "\n";
189 }
190
192
193 const std::string& pv3d = "plot_vars_3d"; set3DPlotVariables(pv3d);
194 const std::string& pv2d = "plot_vars_2d"; set2DPlotVariables(pv2d);
195
196 prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
197
198 int nlevs_max = max_level + 1;
199
200 istep.resize(nlevs_max, 0);
201 nsubsteps.resize(nlevs_max, 1);
202 for (int lev = 1; lev <= max_level; ++lev) {
203 nsubsteps[lev] = do_substep ? MaxRefRatio(lev-1) : 1;
204 }
205
206 physbcs.resize(nlevs_max);
207
208 t_new.resize(nlevs_max, zero);
209 t_old.resize(nlevs_max, -bogus_large_value);
210 dt.resize(nlevs_max, bogus_large_value);
211
212 cons_new.resize(nlevs_max);
213 cons_old.resize(nlevs_max);
214 xvel_new.resize(nlevs_max);
215 xvel_old.resize(nlevs_max);
216 yvel_new.resize(nlevs_max);
217 yvel_old.resize(nlevs_max);
218 zvel_new.resize(nlevs_max);
219 zvel_old.resize(nlevs_max);
220
221 advflux_reg.resize(nlevs_max);
222
224
225 for (int lev = 0; lev < max_level; ++lev)
226 {
227 amrex::Print() << "Refinement ratio at level " << lev << " set to be " <<
228 ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
229
230 if (ref_ratio[lev][2] != 1)
231 {
232 amrex::Print() << "********************************************************************************" << std::endl;
233 amrex::Print() << "We don't allow refinement in the vertical -- make sure to set ref_ratio = 1 in z" << std::endl;
234 amrex::Print() << "It's possible you set amr.ref_ratio when you meant to set amr.ref_ratio_vect " << std::endl;
235 amrex::Print() << "********************************************************************************" << std::endl;
236 amrex::Abort();
237 }
238 }
239}
240
242{
243}
244
245void
247{
248 cons_names.clear();
249 cons_names.reserve(ncons);
250 cons_names.emplace_back("temp");
251 cons_names.emplace_back("salt");
252 cons_names.emplace_back("tracer");
253 for (int i = 1; i < nscalar; ++i) {
254 cons_names.emplace_back("tracer_" + std::to_string(i));
255 }
256}
257
258void
260{
261 BL_PROFILE_VAR("REMORA::Evolve()",evolve);
262 Real cur_time = t_new[0];
263
264 // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
265 // for finer levels (with or without subcycling)
266 for (int step = istep[0]; step < max_step && cur_time < stop_time; ++step)
267 {
268 amrex::Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
269
270 ComputeDt();
271
272 int lev = 0;
273 int iteration = 1;
274 auto dEvolveTime0 = amrex::second();
275
276 if (max_level == 0) {
277 timeStep(lev, cur_time, iteration);
278 }
279 else {
280 timeStepML(cur_time, iteration);
281 }
282
283 cur_time += dt[0];
284
285 amrex::Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
286 << " DT = " << dt[0] << std::endl;
287
288 if (verbose > 0)
289 {
290 auto dEvolveTime = amrex::second() - dEvolveTime0;
291 ParallelDescriptor::ReduceRealMax(dEvolveTime,ParallelDescriptor::IOProcessorNumber());
292 amrex::Print() << "Timestep time = " << dEvolveTime << " seconds." << '\n';
293 }
294
295 WriteAtIntermediateTime(step, cur_time);
296
297 post_timestep(step, cur_time, dt[0]);
298
299#ifdef AMREX_MEM_PROFILING
300 {
301 std::ostringstream ss;
302 ss << "[STEP " << step+1 << "]";
303 MemProfiler::report(ss.str());
304 }
305#endif
306
307 if (cur_time >= stop_time - 1.e-6*dt[0]) break;
308 }
309
310 BL_PROFILE_VAR_STOP(evolve);
311
313}
314
315void
317{
318
319 if ( (plot_int > 0 || plot_int_time > zero) && istep[0] > last_plot_file_step)
320 {
323 }
324
325 if ((check_int > 0 || check_int_time > zero) && istep[0] > last_check_file_step) {
327 }
328}
329
330void
331REMORA::WriteAtIntermediateTime(int step, amrex::Real cur_time)
332{
333 if ( (plot_int > 0 && (step+1 - last_plot_file_step) == plot_int ) ||
334 (plot_int_time > 0 && (cur_time >= (last_plot_file_time + plot_int_time))) )
335 {
336 last_plot_file_step = step+1;
337 last_plot_file_time = cur_time;
338 WritePlotFile(step+1);
340 }
341
342 if ((check_int > 0 && (step+1 - last_check_file_step) == check_int)
343 || (check_int_time > 0 && cur_time >= (last_check_file_time + check_int_time))) {
344 last_check_file_step = step+1;
345 last_check_file_time = cur_time;
347 }
348}
349
350/**
351 * @param[in ] nstep which step we're on
352 * @param[in ] time current time
353 * @param[in ] dt_lev0 time step on level 0
354 */
355void
356REMORA::post_timestep (int nstep, Real time, Real dt_lev0)
357{
358 BL_PROFILE("REMORA::post_timestep()");
359
360#ifdef REMORA_USE_PARTICLES
361 particleData.Redistribute();
362#endif
363
365 {
366 for (int lev = finest_level-1; lev >= 0; lev--)
367 {
368 // This call refluxes from the lev/lev+1 interface onto lev
369 //getAdvFluxReg(lev+1)->Reflux(*cons_new[lev], 0, 0, NCONS);
370
371 // We need to do this before anything else because refluxing changes the
372 // values of coarse cells underneath fine grids with the assumption they'll
373 // be over-written by averaging down
374 //
375 AverageDownTo(lev);
376 }
377 }
378
379 if (is_it_time_for_action(nstep, time, dt_lev0, sum_interval, sum_per)) {
381 }
382}
383
384/**
385 * This is called from main.cpp and handles all initialization, whether from start or restart
386 */
387void
389{
390 BL_PROFILE("REMORA::InitData()");
392 amrex::Print() << "REMORA InitData: driver-managed atm2ocn coupling enabled"
393 << " two_way=" << (driver_uses_two_way_coupling ? 1 : 0)
394 << " active_contract="
396 << "\n";
397 }
398 // Initialize the start time for our CPU-time tracker
399 startCPUTime = Real(ParallelDescriptor::second());
400
401 // Map the words in the inputs file to BC types, then translate
402 // those types into what they mean for each variable
403 init_bcs();
404
405 // Init vertical stretching coeffs
407
412
413 if (restart_chkfile == "") {
414 // start simulation from the beginning
415
416 InitFromScratch(start_time);
417
419 AverageDown();
420 }
421
422 } else { // Restart from a checkpoint
423
424 restart();
425
426 }
427#ifdef REMORA_USE_MOAB
428 InitMOABMesh();
429#endif
430 // Initialize flux registers (whether we start from scratch or restart)
432 advflux_reg[0] = nullptr;
433 for (int lev = 1; lev <= finest_level; lev++)
434 {
435 advflux_reg[lev].reset( new YAFluxRegister(grids[lev], grids[lev-1],
436 dmap[lev], dmap[lev-1],
437 geom[lev], geom[lev-1],
438 ref_ratio[lev-1], lev, ncons));
439 }
440 }
441
442 // Fill ghost cells/faces
443 for (int lev = 0; lev <= finest_level; ++lev)
444 {
445 if (lev > 0 && cf_width >= 0) {
447 }
448
449 if (restart_chkfile == "") {
450 FillPatch(lev, t_new[lev], *cons_new[lev], cons_new, BCVars::cons_bc, BdyVars::t, 0, true, false,0,0,zero,*cons_new[lev]);
451 FillPatch(lev, t_new[lev], *xvel_new[lev], xvel_new, xvel_bc(), BdyVars::u, 0, true, false,0,0,zero,*xvel_new[lev]);
452 FillPatch(lev, t_new[lev], *yvel_new[lev], yvel_new, yvel_bc(), BdyVars::v, 0, true, false,0,0,zero,*yvel_new[lev]);
453 FillPatch(lev, t_new[lev], *zvel_new[lev], zvel_new, zvel_bc(), BdyVars::null, 0, true, false);
454
455 // Copy from new into old just in case when initializing from scratch
456 int ngs = cons_new[lev]->nGrow();
457 int ngvel = xvel_new[lev]->nGrow();
458 MultiFab::Copy(*cons_old[lev],*cons_new[lev],0,0,ncons,ngs);
459 MultiFab::Copy(*xvel_old[lev],*xvel_new[lev],0,0,1,ngvel);
460 MultiFab::Copy(*yvel_old[lev],*yvel_new[lev],0,0,1,ngvel);
461 MultiFab::Copy(*zvel_old[lev],*zvel_new[lev],0,0,1,IntVect(ngvel,ngvel,0));
462 }
463 } // lev
464
465 // Check for additional plotting variables that are available after
466 // particle containers are setup.
467 const std::string& pv3d = "plot_vars_3d"; append3DPlotVariables(pv3d);
468 const std::string& pv2d = "plot_vars_2d"; append2DPlotVariables(pv2d);
469
470 if (restart_chkfile == "" && (check_int > 0 || check_int_time > zero))
471 {
474 }
475
476 if ( (restart_chkfile == "") ||
478 {
479 if (plot_int > 0 || plot_int_time > zero)
480 {
481 int step0 = 0;
482 WritePlotFile(step0);
485 }
486 }
487
490 }
491
492 ComputeDt();
493
494}
495
496/**
497 * @param[in ] lev level to operate on
498 */
499void
501{
502 BL_PROFILE("REMORA::Construct_REMORAFillPatchers()");
503 amrex::Print() << ":::Construct_REMORAFillPatchers " << lev << std::endl;
504
505 auto& ba_fine = cons_new[lev ]->boxArray();
506 auto& ba_crse = cons_new[lev-1]->boxArray();
507 auto& dm_fine = cons_new[lev ]->DistributionMap();
508 auto& dm_crse = cons_new[lev-1]->DistributionMap();
509
510 BoxList bl2d_fine = ba_fine.boxList();
511 for (auto& b : bl2d_fine) {
512 b.setRange(2,0);
513 }
514 BoxArray ba2d_fine(std::move(bl2d_fine));
515
516 BoxList bl2d_crse = ba_crse.boxList();
517 for (auto& b : bl2d_crse) {
518 b.setRange(2,0);
519 }
520 BoxArray ba2d_crse(std::move(bl2d_crse));
521
522 int ncomp = cons_new[lev]->nComp();
523
524 FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
525 ba_crse, dm_crse, geom[lev-1],
526 -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
527 FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
528 convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
529 -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
530 FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
531 convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
532 -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
533 FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
534 convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
535 -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
536
537 FPr_ubar.emplace_back(convert(ba2d_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
538 convert(ba2d_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
539 -cf_width, -cf_set_width, 3, &face_cons_linear_interp);
540 FPr_vbar.emplace_back(convert(ba2d_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
541 convert(ba2d_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
542 -cf_width, -cf_set_width, 3, &face_cons_linear_interp);
543}
544
545/**
546 * @param[in ] lev level to operate on
547 */
548void
550{
551 BL_PROFILE("REMORA::Define_REMORAFillPatchers()");
552 amrex::Print() << ":::Define_REMORAFillPatchers " << lev << std::endl;
553
554 auto& ba_fine = cons_new[lev ]->boxArray();
555 auto& ba_crse = cons_new[lev-1]->boxArray();
556 auto& dm_fine = cons_new[lev ]->DistributionMap();
557 auto& dm_crse = cons_new[lev-1]->DistributionMap();
558
559 BoxList bl2d_fine = ba_fine.boxList();
560 for (auto& b : bl2d_fine) {
561 b.setRange(2,0);
562 }
563 BoxArray ba2d_fine(std::move(bl2d_fine));
564
565 BoxList bl2d_crse = ba_crse.boxList();
566 for (auto& b : bl2d_crse) {
567 b.setRange(2,0);
568 }
569 BoxArray ba2d_crse(std::move(bl2d_crse));
570
571
572 int ncomp = cons_new[lev]->nComp();
573
574 FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
575 ba_crse, dm_crse, geom[lev-1],
576 -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
577 FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
578 convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
579 -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
580 FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
581 convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
582 -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
583 FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
584 convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
585 -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
586
587 FPr_ubar[lev-1].Define(convert(ba2d_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
588 convert(ba2d_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
589 -cf_width, -cf_set_width, 3, &face_cons_linear_interp);
590 FPr_vbar[lev-1].Define(convert(ba2d_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
591 convert(ba2d_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
592 -cf_width, -cf_set_width, 3, &face_cons_linear_interp);
593}
594
595void
597{
598 BL_PROFILE("REMORA::restart()");
600
601 // We set this here so that we don't over-write the checkpoint file we just started from
603}
604
605/**
606 * @param[in ] lev level to operate on
607 */
608void
610{
611 BL_PROFILE("REMORA::set_zeta()");
612 if (lev==0) {
613 if (hires_init_level < 0) {
615 prob->init_analytic_zeta(lev, geom[lev], solverChoice, *this, *vec_zeta[lev]);
616 } else if (solverChoice.ic_type == IC_Type::netcdf) {
617#ifdef REMORA_USE_NETCDF
618 amrex::Print() << "Calling init_zeta_from_netcdf on level " << lev << std::endl;
620 amrex::Print() << "Sea surface height loaded from netcdf file \n " << std::endl;
621#endif
622 } else {
623 amrex::Abort("Unknown IC_Type");
624 }
625 } else {
627 }
628 vec_zeta[lev]->FillBoundary(geom[lev].periodicity());
629 } else {
630 // If our level is higher than the high resolution grid or initialization
631 // is analytic, interpolate from level below. Otherwise, copy over the bathymetry
632 // data that has been averaged down
633 if (lev > hires_init_level) {
634 Real dummy_time = zero;
635 FillCoarsePatch(lev,dummy_time,vec_zeta[lev].get(), vec_zeta[lev-1].get(),BCVars::cons_bc);
636 } else {
638 vec_zeta[lev]->FillBoundary(geom[lev].periodicity());
639 }
640 }
641 set_zeta_average(lev);
642}
643
644/**
645 * @param[in ] lev level to operate on
646 */
647void
649{
650 BL_PROFILE("REMORA::bathymetry()");
651 // Only set bathymetry on level 0, and interpolate for finer levels
652 if (lev==0) {
655 // If grid data is not defined on a level > 0 (negative level) then
656 // initialize from low-resolution grid normally. Otherwise use high-resolution
657 // grid data averaged down to level 0
658 } else if (hires_grid_level < 0) {
660 prob->init_analytic_bathymetry(lev, geom[lev], solverChoice, *this, *vec_h[lev]);
661 } else if (solverChoice.ic_type == IC_Type::netcdf) {
662#ifdef REMORA_USE_NETCDF
663 amrex::Print() << "Calling init_bathymetry_from_netcdf " << std::endl;
665 amrex::Print() << "Bathymetry loaded from netcdf file \n " << std::endl;
666 amrex::Print() << "Calling init_grid_vars_from_netcdf " << std::endl;
668 amrex::Print() << "Grid variables loaded from netcdf file \n " << std::endl;
669#endif
670 } else {
671 amrex::Abort("Unknown IC_Type");
672 }
673 } else {
676 }
677 // Need FillBoundary to fill at grid-grid boundaries, and EnforcePeriodicity
678 // to make sure ghost cells in the domain corners are consistent.
679 vec_h[lev]->FillBoundary(geom[lev].periodicity());
680 vec_h[lev]->EnforcePeriodicity(geom[lev].periodicity());
681 } else {
682 // If our level is higher than the high resolution grid or initialization
683 // is analytic, interpolate from level below. Otherwise, copy over the bathymetry
684 // data that has been averaged down
685 if (lev > hires_grid_level) {
686 Real dummy_time = zero;
687 FillCoarsePatch(lev,dummy_time,vec_h[lev].get(), vec_h[lev-1].get(),BCVars::cons_bc);
688 } else {
690 vec_h[lev]->FillBoundary(geom[lev].periodicity());
691 vec_h[lev]->EnforcePeriodicity(geom[lev].periodicity());
692 }
693 }
694 set_grid_scale(lev);
695}
696
697/**
698 * @param[in ] lev level to operate on
699 */
700void
702 Real dummy_time = zero;
703 // Note: don't understand why the grow vector args aren't vec_h and then vec_h_full_domain
704 ParallelCopy(*vec_h[lev].get(), *vec_h_full_domain[lev].get(), 0, 0, 1,vec_h_full_domain[lev]->nGrowVect(),vec_h[lev]->nGrowVect());
705 ParallelCopy(*vec_h[lev].get(), *vec_h_full_domain[lev].get(), 0, 1, 1,vec_h_full_domain[lev]->nGrowVect(),vec_h[lev]->nGrowVect());
706 FillPatch(lev,dummy_time,*vec_h[lev],GetVecOfPtrs(vec_h),
708 BdyVars::null,0,false,false,1);
709 FillPatch(lev,dummy_time,*vec_h[lev],GetVecOfPtrs(vec_h),
711 BdyVars::null,1,false,false,1);
712}
713
714/**
715 * @param[in ] lev level to operate on
716 */
717void
719 Real dummy_time = zero;
720 ParallelCopy(*vec_pm[lev].get(), *vec_pm_full_domain[lev].get(), 0, 0, 1,
721 vec_pm_full_domain[lev]->nGrowVect(),vec_pm[lev]->nGrowVect());
722 ParallelCopy(*vec_pn[lev].get(), *vec_pn_full_domain[lev].get(), 0, 0, 1,
723 vec_pn_full_domain[lev]->nGrowVect(),vec_pn[lev]->nGrowVect());
724 FillPatch(lev,dummy_time,*vec_pm[lev],GetVecOfPtrs(vec_pm),
726 BdyVars::null,0,false);
727 FillPatch(lev,dummy_time,*vec_pn[lev],GetVecOfPtrs(vec_pn),
729 BdyVars::null,0,false);
730}
731
732/**
733 * @param[in ] lev level to operate on
734 */
735void
737 ParallelCopy(*vec_zeta[lev].get(), *vec_zeta_full_domain[lev].get(), 0, 0, 1,
738 vec_zeta_full_domain[lev]->nGrowVect(),vec_zeta[lev]->nGrowVect());
739 FillPatch(lev, t_new[lev], *vec_zeta[lev], GetVecOfPtrs(vec_zeta), zeta_bc(), BdyVars::zeta,
740 0, false,false,0,0,zero,*vec_zeta[lev]);
741}
742
743/**
744 * @param[in ] lev level to operate on
745 */
746void
748 ParallelCopy(*cons_new[lev], *vec_cons_full_domain[lev], 0, 0, ncons,
749 vec_cons_full_domain[lev]->nGrowVect(),cons_new[lev]->nGrowVect());
750 ParallelCopy(*xvel_new[lev], *vec_xvel_full_domain[lev], 0, 0, 1,
751 vec_xvel_full_domain[lev]->nGrowVect(),xvel_new[lev]->nGrowVect());
752 ParallelCopy(*yvel_new[lev], *vec_yvel_full_domain[lev], 0, 0, 1,
753 vec_yvel_full_domain[lev]->nGrowVect(),yvel_new[lev]->nGrowVect());
754
755 FillPatch(lev, t_new[lev], *cons_new[lev], cons_new, BCVars::cons_bc, BdyVars::t, 0, true, false,0,0,zero,*cons_new[lev]);
756 FillPatch(lev, t_new[lev], *xvel_new[lev], xvel_new, xvel_bc(), BdyVars::u, 0, true, false,0,0,zero,*xvel_new[lev]);
757 FillPatch(lev, t_new[lev], *yvel_new[lev], yvel_new, yvel_bc(), BdyVars::v, 0, true, false,0,0,zero,*yvel_new[lev]);
758}
759
760/**
761 * @param[in ] lev level to operate on
762 */
763void
765 BL_PROFILE("REMORA::set_coriolis()");
768 prob->init_analytic_coriolis(lev, geom[lev], solverChoice, *this, *vec_fcor[lev]);
771#ifdef REMORA_USE_NETCDF
773 if (lev == 0) {
774 amrex::Print() << "Calling init_coriolis_from_netcdf " << std::endl;
776 amrex::Print() << "Coriolis loaded from netcdf file \n" << std::endl;
777 } else {
778 Real dummy_time = zero;
779 FillCoarsePatch(lev,dummy_time,vec_fcor[lev].get(), vec_fcor[lev-1].get(),BCVars::cons_bc);
780 }
781#endif
782 } else {
783 Abort("Don't know this coriolis_type!");
784 }
785
786 Real time = zero;
787 FillPatch(lev, time, *vec_fcor[lev], GetVecOfPtrs(vec_fcor), foextrap_bc());
788 vec_fcor[lev]->EnforcePeriodicity(geom[lev].periodicity());
789 }
790}
791
792void
794 BL_PROFILE("REMORA::init_set_vmix()");
799 // The GLS initialization just sets the multifab to a value, so there's
800 // no need to call FillPatch here
801 } else {
802 Abort("Don't know this vertical mixing type");
803 }
804}
805
806/**
807 * @param[in ] lev level to operate on
808 */
809void
811 BL_PROFILE("REMORA::set_analytic_vmix()");
812 Real time = zero;
813 vec_Akv[lev]->setVal(solverChoice.Akv_bak);
814 vec_Akt[lev]->setVal(solverChoice.Akt_bak);
815 prob->init_analytic_vmix(lev, geom[lev], solverChoice, *this,*vec_Akv[lev], *vec_Akt[lev]);
816 FillPatch(lev, time, *vec_Akv[lev], GetVecOfPtrs(vec_Akv), zvel_bc(), BdyVars::null,0,true,false);
817 for (int n = 0; n < ncons; n++) {
818 FillPatch(lev, time, *vec_Akt[lev], GetVecOfPtrs(vec_Akt), zvel_bc(), BdyVars::null,n,false,false);
819 }
820}
821
822/**
823 * @param[in ] lev level to operate on
824 */
825void
827{
829 prob->init_analytic_masks(lev,geom[lev], solverChoice, *this, *vec_mskr[lev]);
832#ifdef REMORA_USE_NETCDF
833 if (lev == 0) {
834 amrex::Print() << "Calling init_masks_from_netcdf level " << lev << std::endl;
836 amrex::Print() << "Masks loaded from netcdf file \n " << std::endl;
837 } else {
838 Real dummy_time = zero;
839 FillCoarsePatchPC(lev, dummy_time, vec_mskr[lev].get(), vec_mskr[lev-1].get(),
840 foextrap_bc());
842 }
843#endif
844 }
845 fill_3d_masks(lev);
846}
847
848/**
849 * @param[in ] lev level to operate on
850 */
851void
853{
854 BL_PROFILE("REMORA::set_hmixcoef()");
855
856 // Optional AMR scaling: decrease coefficients on refined levels linearly
857 // with grid size (i.e., proportional to sqrt(cell area)). For a horizontal
858 // refinement ratio rx x ry, the effective scale factor is 1/sqrt(rx*ry).
859 Real lev_scale = one;
861 Real rf = one;
862 for (int l = 0; l < lev; ++l) {
863 rf *= std::sqrt(static_cast<Real>(ref_ratio[l][0]) * static_cast<Real>(ref_ratio[l][1]));
864 }
865 lev_scale = one / rf;
866 }
867
869 prob->init_analytic_hmix(lev, geom[lev], solverChoice,
870 *this, *vec_visc2_p[lev], *vec_visc2_r[lev], *vec_diff2[lev]);
871
873 vec_visc2_p[lev]->setVal(solverChoice.visc2 * lev_scale);
874 vec_visc2_r[lev]->setVal(solverChoice.visc2 * lev_scale);
875 for (int n = 0; n < ncons; n++) {
876 vec_diff2[lev]->setVal(solverChoice.tnu2[n] * lev_scale, n, 1);
877 }
878
879 // Scale harmonic viscosity and diffusivity by the grid size as ROMS
880 // does in Utility/ini_hmixcoef.F. Intended for curvilinear grids.
881 //
882 // Define the ROMS grid factor (grdscl):
883 // G(i,j) = sqrt( 1 / (pm(i,j) * pn(i,j)) )
884 // = sqrt(cell area)
885 // Gmax = max over grid of G(i,j)
886 //
887 // Then horizontal harmonic mixing coefficients are scaled as:
888 // nu(i,j) = nu0 * G(i,j) / Gmax
889 // kappa_n(i,j) = kappa0 * G(i,j) / Gmax
890 //
891 // where:
892 // nu0 = solverChoice.visc2
893 // kappa0 = solverChoice.tnu2[n]
894 //
895 // This makes mixing strongest where grid spacing is largest.
896 //
897 // NOTE: The normalization (Gmax) is computed over the entire grid (ignoring masks).
898 // Therefore, if the largest cell area occurs over land, the maximum over *wet* cells
899 // (or in masked output files) may be smaller than the user-specified value.
900
902
903 // ------------------------------------------------------------
904 // Step 1: Compute grdmax over entire grid
905 // ------------------------------------------------------------
906 vec_visc2_r[lev]->setVal(solverChoice.visc2);
907 vec_visc2_p[lev]->setVal(solverChoice.visc2);
908 for (int n = 0; n < ncons; n++) {
909 vec_diff2[lev]->setVal(solverChoice.tnu2[n], n, 1);
910 }
911
912 // NOTE: This must be GPU-safe. Do not dereference MultiFab data on host.
913 // Force the reduction to run in the GPU launch region if GPUs are enabled.
914 // (If the launch region is disabled at runtime, ReduceMax may fall back to
915 // a host path that can try to read device-only data.)
916 amrex::Gpu::LaunchSafeGuard lsg(true);
917 Real denom_min = amrex::ReduceMin(*vec_pm[lev], *vec_pn[lev], 0,
918 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
919 Array4<Real const> const& pm,
920 Array4<Real const> const& pn) -> Real
921 {
922 Real local_min = bogus_large_value;
923 amrex::Loop(bx, [=,&local_min] (int i, int j, int) noexcept
924 {
925 local_min = amrex::min(local_min, pm(i,j,0) * pn(i,j,0));
926 });
927 return local_min;
928 });
929
930 ParallelDescriptor::ReduceRealMin(denom_min);
931 if (denom_min <= zero) {
932 Abort("scaled_to_grid: found non-positive pm*pn (grid metrics must be > 0)");
933 }
934
935 Real grdmax = amrex::ReduceMax(*vec_pm[lev], *vec_pn[lev], 0,
936 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
937 Array4<Real const> const& pm,
938 Array4<Real const> const& pn) -> Real
939 {
940 Real local_max = zero;
941 amrex::Loop(bx, [=,&local_max] (int i, int j, int) noexcept
942 {
943 Real denom = pm(i,j,0) * pn(i,j,0);
944 if (denom > zero) {
945 Real G = std::sqrt(one / denom);
946 local_max = amrex::max(local_max, G);
947 }
948 });
949 return local_max;
950 });
951
952 ParallelDescriptor::ReduceRealMax(grdmax);
953 if (grdmax <= zero) {
954 Abort("scaled_to_grid: grdmax <= 0");
955 }
956
957 // Optional AMR scaling: decrease coefficients on refined levels linearly
958 // with grid size (i.e., proportional to sqrt(cell area)). For a horizontal
959 // refinement ratio rx x ry, the effective scale factor is 1/sqrt(rx*ry).
960 lev_scale = one;
962 Real rf = one;
963 for (int l = 0; l < lev; ++l) {
964 rf *= std::sqrt(static_cast<Real>(ref_ratio[l][0]) * static_cast<Real>(ref_ratio[l][1]));
965 }
966 lev_scale = one / rf;
967 }
968
969 Real visc0 = solverChoice.visc2 * lev_scale;
970 Real cff = visc0 / grdmax;
971
972 // ------------------------------------------------------------
973 // Step 2: Set rho coefficients everywhere
974 // ------------------------------------------------------------
975 amrex::Gpu::DeviceVector<Real> diff0_d(ncons);
976 amrex::Gpu::copy(amrex::Gpu::hostToDevice,
977 solverChoice.tnu2.begin(), solverChoice.tnu2.begin() + ncons,
978 diff0_d.begin());
979 Real const* diff0_ptr = diff0_d.data();
980
981 for (MFIter mfi(*vec_visc2_r[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
982 {
983 const Box& bx = mfi.validbox();
984 auto pm = vec_pm[lev]->const_array(mfi);
985 auto pn = vec_pn[lev]->const_array(mfi);
986 auto visc2_r = vec_visc2_r[lev]->array(mfi);
987 auto diff2 = vec_diff2[lev]->array(mfi);
988
989 int ncons_local = ncons;
990 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
991 {
992 Real denom = pm(i,j,0) * pn(i,j,0);
993 Real grdscl = (denom > zero) ? std::sqrt(one / denom) : zero;
994 visc2_r(i,j,0) = cff * grdscl;
995
996 for (int n = 0; n < ncons_local; n++) {
997 diff2(i,j,0,n) = ((diff0_ptr[n] * lev_scale) / grdmax) * grdscl;
998 }
999 });
1000 }
1001
1002 // Fill ghost cells for rho coefficients BEFORE psi averaging
1003 Real time = zero;
1004 FillPatch(lev, time, *vec_visc2_r[lev], GetVecOfPtrs(vec_visc2_r), foextrap_periodic_bc());
1005
1006 // ------------------------------------------------------------
1007 // Step 3: Psi coefficients = average of 4 surrounding rho
1008 // ------------------------------------------------------------
1009 for (MFIter mfi(*vec_visc2_p[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1010 {
1011 const Box& bx = mfi.validbox();
1012 auto visc2_p = vec_visc2_p[lev]->array(mfi);
1013 auto visc2_r = vec_visc2_r[lev]->const_array(mfi);
1014
1015 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
1016 {
1017 visc2_p(i,j,0) = fourth * (
1018 visc2_r(i-1,j-1,0) +
1019 visc2_r(i ,j-1,0) +
1020 visc2_r(i-1,j ,0) +
1021 visc2_r(i ,j ,0)
1022 );
1023 });
1024 }
1025
1026 FillPatch(lev, time, *vec_visc2_p[lev], GetVecOfPtrs(vec_visc2_p), foextrap_periodic_bc());
1027
1028 // Diagnostics
1029 // NOTE: coefficients are computed everywhere (including land). Output routines may later
1030 // mask land points (e.g., to FillValue in NetCDF/plotfiles), and analysis tools may
1031 // additionally apply mask_rho (setting land to 0). Report both conventions.
1032 //
1033 // Global (MPI-reduced) extrema over all valid cells (no ghost).
1034 Real visc_min_all = vec_visc2_r[lev]->min(0,0,false);
1035 Real visc_max_all = vec_visc2_r[lev]->max(0,0,false);
1036
1037 // Global extrema over *wet* rho points only, k=0.
1038 amrex::Gpu::LaunchSafeGuard lsg_diag(true);
1039 Real visc_min_wet = amrex::ReduceMin(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1040 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1041 Array4<Real const> const& visc2,
1042 Array4<Real const> const& mskr) -> Real
1043 {
1044 Real local_min = bogus_large_value;
1045 amrex::Loop(bx, [=,&local_min] (int i, int j, int) noexcept
1046 {
1047 if (mskr(i,j,0) > zero) {
1048 local_min = amrex::min(local_min, visc2(i,j,0));
1049 }
1050 });
1051 return local_min;
1052 });
1053 ParallelDescriptor::ReduceRealMin(visc_min_wet);
1054
1055 Real visc_max_wet = amrex::ReduceMax(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1056 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1057 Array4<Real const> const& visc2,
1058 Array4<Real const> const& mskr) -> Real
1059 {
1060 Real local_max = -bogus_large_value;
1061 amrex::Loop(bx, [=,&local_max] (int i, int j, int) noexcept
1062 {
1063 if (mskr(i,j,0) > zero) {
1064 local_max = amrex::max(local_max, visc2(i,j,0));
1065 }
1066 });
1067 return local_max;
1068 });
1069 ParallelDescriptor::ReduceRealMax(visc_max_wet);
1070
1071 // Mimic "apply mask_rho" convention (dry -> 0).
1072 Real visc_min_mask0 = amrex::ReduceMin(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1073 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1074 Array4<Real const> const& visc2,
1075 Array4<Real const> const& mskr) -> Real
1076 {
1077 Real local_min = bogus_large_value;
1078 amrex::Loop(bx, [=,&local_min] (int i, int j, int) noexcept
1079 {
1080 const Real v = (mskr(i,j,0) > zero) ? visc2(i,j,0) : zero;
1081 local_min = amrex::min(local_min, v);
1082 });
1083 return local_min;
1084 });
1085 ParallelDescriptor::ReduceRealMin(visc_min_mask0);
1086
1087 Real visc_max_mask0 = amrex::ReduceMax(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1088 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1089 Array4<Real const> const& visc2,
1090 Array4<Real const> const& mskr) -> Real
1091 {
1092 Real local_max = -bogus_large_value;
1093 amrex::Loop(bx, [=,&local_max] (int i, int j, int) noexcept
1094 {
1095 const Real v = (mskr(i,j,0) > zero) ? visc2(i,j,0) : zero;
1096 local_max = amrex::max(local_max, v);
1097 });
1098 return local_max;
1099 });
1100 ParallelDescriptor::ReduceRealMax(visc_max_mask0);
1101 if (ParallelDescriptor::IOProcessor() && lev == 0)
1102 {
1103 Print() << "\nHorizontal mixing scaled by grid metric\n";
1104 Print() << "grdmax = " << grdmax << "\n";
1106 Print() << "AMR scaling (linear) lev_scale = " << lev_scale << "\n";
1107 }
1108 Print() << "visc2(all) min/max = "
1109 << visc_min_all << " / "
1110 << visc_max_all << "\n";
1111 Print() << "visc2(wet,k=0) min/max = "
1112 << visc_min_wet << " / "
1113 << visc_max_wet << "\n";
1114 Print() << "visc2(mask->0) min/max = "
1115 << visc_min_mask0 << " / "
1116 << visc_max_mask0 << "\n";
1117 }
1118
1119 } else {
1120 Abort("Don't know this horizontal mixing type");
1121 }
1122
1123 // Final FillPatch for all fields
1124 Real time = zero;
1125 FillPatch(lev, time, *vec_visc2_p[lev], GetVecOfPtrs(vec_visc2_p), foextrap_periodic_bc());
1126 FillPatch(lev, time, *vec_visc2_r[lev], GetVecOfPtrs(vec_visc2_r), foextrap_periodic_bc());
1127 for (int n = 0; n < ncons; n++) {
1128 FillPatch(lev, time, *vec_diff2[lev], GetVecOfPtrs(vec_diff2),
1129 foextrap_periodic_bc(), BdyVars::null, n, false);
1130 }
1131}
1132
1133/**
1134 * @param[in ] lev level to operate on
1135 */
1136void
1138{
1139 BL_PROFILE("REMORA::init_flat_bathymetry()");
1140 vec_h[lev]->setVal(-geom[0].ProbLo()[2]);
1141}
1142
1143/**
1144 * @param[in ] lev level to operate on
1145 */
1146void
1148{
1149 BL_PROFILE("REMORA::set_smflux()");
1151 prob->init_analytic_smflux(lev, geom[lev], solverChoice, *this,*vec_sustr[lev], *vec_svstr[lev]);
1153#ifdef REMORA_USE_NETCDF
1154 sustr_data_from_file->update_interpolated_to_time(t_old[lev], lev, vec_sustr[lev].get(), geom, ref_ratio);
1155 svstr_data_from_file->update_interpolated_to_time(t_old[lev], lev, vec_svstr[lev].get(), geom, ref_ratio);
1156 FillPatch(lev, t_old[lev], *vec_sustr[lev], GetVecOfPtrs(vec_sustr), foextrap_periodic_bc(), BdyVars::null,0,false,false);
1157 FillPatch(lev, t_old[lev], *vec_svstr[lev], GetVecOfPtrs(vec_svstr), foextrap_periodic_bc(), BdyVars::null,0,false,false);
1158#endif
1159 }
1160}
1161
1162/**
1163 * @param[in ] lev level to operate on
1164 */
1165void
1167{
1168 BL_PROFILE("REMORA::set_surface_state()");
1169
1170 auto& bulk_flux_type = solverChoice.bulk_flux_type;
1171
1172 for (int n=0; n < AtmosState::NumTypes; n++) {
1174 amrex::Abort("Reached set_surface_state() but variables have already been specified from driver!");
1175 }
1176 }
1177// const bool driver_has_uwind = driver_atmos_state_from_driver[AtmosState::Uwind];
1178// const bool driver_has_vwind = driver_atmos_state_from_driver[AtmosState::Vwind];
1179//
1180// const bool use_analytic_uwind = bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::analytic &&
1181// !driver_has_uwind;
1182// const bool use_analytic_vwind = bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::analytic &&
1183// !driver_has_vwind;
1184//
1185// if (use_analytic_uwind || use_analytic_vwind) {
1186// std::unique_ptr<MultiFab> tmp_uwind;
1187// std::unique_ptr<MultiFab> tmp_vwind;
1188// MultiFab* analytic_uwind = vec_uwind[lev].get();
1189// MultiFab* analytic_vwind = vec_vwind[lev].get();
1190//
1191// if (!use_analytic_uwind) {
1192// tmp_uwind.reset(new MultiFab(vec_uwind[lev]->boxArray(), vec_uwind[lev]->DistributionMap(),
1193// 1, vec_uwind[lev]->nGrowVect()));
1194// analytic_uwind = tmp_uwind.get();
1195// }
1196// if (!use_analytic_vwind) {
1197// tmp_vwind.reset(new MultiFab(vec_vwind[lev]->boxArray(), vec_vwind[lev]->DistributionMap(),
1198// 1, vec_vwind[lev]->nGrowVect()));
1199// analytic_vwind = tmp_vwind.get();
1200// }
1201//
1202// prob->init_analytic_wind(lev, geom[lev], solverChoice, *this, *analytic_uwind, *analytic_vwind);
1203// }
1204
1205#ifdef REMORA_USE_NETCDF
1206 auto update_from_netcdf = [&](std::unique_ptr<NCTimeSeries>& data_from_file,
1207 Vector<std::unique_ptr<MultiFab>>& mf_vec) {
1208 data_from_file->update_interpolated_to_time(t_old[lev], lev, mf_vec[lev].get(), geom, ref_ratio);
1209 FillPatch(lev, t_old[lev], *mf_vec[lev], GetVecOfPtrs(mf_vec),
1210 foextrap_periodic_bc(), BdyVars::null, 0, false);
1211 };
1212
1214 update_from_netcdf(Uwind_data_from_file, vec_uwind);
1215 }
1217 update_from_netcdf(Vwind_data_from_file, vec_vwind);
1218 }
1219
1221 update_from_netcdf(Tair_data_from_file, vec_Tair);
1222 }
1224 update_from_netcdf(qair_data_from_file, vec_qair);
1226 vec_qair[lev]->mult(amrex::Real(0.01));
1227 }
1228 }
1230 update_from_netcdf(Pair_data_from_file, vec_Pair);
1231 }
1233 update_from_netcdf(srflx_data_from_file, vec_srflx);
1234 }
1237 }
1239 update_from_netcdf(rain_data_from_file, vec_rain);
1240 }
1242 update_from_netcdf(cloud_data_from_file, vec_cloud);
1243 }
1244 if (bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::netcdf) {
1245 update_from_netcdf(EminusP_data_from_file, vec_EminusP);
1246 }
1247#else
1248 for (int idx = 0; idx < BulkFlux::NumTypes; ++idx) {
1249 if (bulk_flux_type[idx] == BulkForcingType::netcdf) {
1250 amrex::Abort("NetCDF bulk-flux forcing requires building with NetCDF");
1251 }
1252 }
1253#endif
1254
1255 MultiFab* analytic_uwind = (bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::analytic &&
1257 MultiFab* analytic_vwind = (bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::analytic &&
1259 MultiFab* analytic_Tair = (bulk_flux_type[BulkFlux::Tair] == BulkForcingType::analytic &&
1261 MultiFab* analytic_qair = (bulk_flux_type[BulkFlux::Qair] == BulkForcingType::analytic &&
1263 MultiFab* analytic_Pair = (bulk_flux_type[BulkFlux::Pair] == BulkForcingType::analytic &&
1265 MultiFab* analytic_srflx = (bulk_flux_type[BulkFlux::SWrad] == BulkForcingType::analytic &&
1267 MultiFab* analytic_lwrad = (bulk_flux_type[BulkFlux::LWrad] == BulkForcingType::analytic &&
1269 MultiFab* analytic_rain = (bulk_flux_type[BulkFlux::Rain] == BulkForcingType::analytic &&
1271 MultiFab* analytic_cloud = (bulk_flux_type[BulkFlux::Cloud] == BulkForcingType::analytic &&
1273 MultiFab* analytic_EminusP = bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::analytic ? vec_EminusP[lev].get() : nullptr;
1274
1275 if (analytic_uwind != nullptr || analytic_vwind != nullptr ||
1276 analytic_Tair != nullptr || analytic_qair != nullptr || analytic_Pair != nullptr ||
1277 analytic_srflx != nullptr || analytic_lwrad != nullptr || analytic_rain != nullptr ||
1278 analytic_cloud != nullptr || analytic_EminusP != nullptr) {
1279 prob->init_analytic_surface_var(lev, geom[lev], solverChoice, *this,
1280 *analytic_uwind, *analytic_vwind,
1281 *analytic_Tair, *analytic_qair, *analytic_Pair,
1282 *analytic_srflx, *analytic_lwrad, *analytic_rain,
1283 *analytic_cloud, *analytic_EminusP);
1284 }
1285
1286 if (vec_uwind[lev] != nullptr) { vec_uwind[lev]->FillBoundary(geom[lev].periodicity()); }
1287 if (vec_vwind[lev] != nullptr) { vec_vwind[lev]->FillBoundary(geom[lev].periodicity()); }
1288 if (vec_Tair[lev] != nullptr) { vec_Tair[lev]->FillBoundary(geom[lev].periodicity()); }
1289 if (vec_qair[lev] != nullptr) { vec_qair[lev]->FillBoundary(geom[lev].periodicity()); }
1290 if (vec_Pair[lev] != nullptr) { vec_Pair[lev]->FillBoundary(geom[lev].periodicity()); }
1291 if (vec_srflx[lev] != nullptr) { vec_srflx[lev]->FillBoundary(geom[lev].periodicity()); }
1292 if (vec_longwave_down[lev] != nullptr) { vec_longwave_down[lev]->FillBoundary(geom[lev].periodicity()); }
1293 if (vec_rain[lev] != nullptr) { vec_rain[lev]->FillBoundary(geom[lev].periodicity()); }
1294 if (vec_cloud[lev] != nullptr) { vec_cloud[lev]->FillBoundary(geom[lev].periodicity()); }
1295 if (vec_EminusP[lev] != nullptr) { vec_EminusP[lev]->FillBoundary(geom[lev].periodicity()); }
1296}
1297
1298/**
1299 * @param[in ] lev level to operate on
1300 * @param[in ] time current time for initialization
1301 */
1302void
1304{
1305 BL_PROFILE("REMORA::init_only()");
1306 t_new[lev] = time;
1307 t_old[lev] = time - bogus_large_value;
1308
1309 cons_new[lev]->setVal(zero);
1310 xvel_new[lev]->setVal(zero);
1311 yvel_new[lev]->setVal(zero);
1312 zvel_new[lev]->setVal(zero);
1313
1314 xvel_old[lev]->setVal(zero);
1315 yvel_old[lev]->setVal(zero);
1316 zvel_old[lev]->setVal(zero);
1317
1318 vec_ru[lev]->setVal(zero);
1319 vec_rv[lev]->setVal(zero);
1320
1321 vec_ru2d[lev]->setVal(zero);
1322 vec_rv2d[lev]->setVal(zero);
1323
1325 set_grid_scale(lev);
1326 }
1327 set_masks(lev);
1328
1329#ifdef REMORA_USE_NETCDF
1332
1333 if (solverChoice.do_any_clim_nudg && lev == 0) {
1334 if (nc_clim_his_file.empty() || nc_clim_his_file[0].empty()) {
1335 amrex::Error("NetCDF climatology file name must be provided via input");
1336 }
1339 clim_ubar_time_varname, geom[lev].Domain(),vec_ubar[lev].get(),true,true));
1341 clim_ubar_time_varname, geom[lev].Domain(),vec_vbar[lev].get(),true,true));
1342 ubar_clim_data_from_file->Initialize();
1343 vbar_clim_data_from_file->Initialize();
1344 }
1346 u_clim_data_from_file.reset(new NCTimeSeries(nc_clim_his_file, "u", clim_u_time_varname, geom[lev].Domain(),xvel_new[lev],false,true));
1347 v_clim_data_from_file.reset(new NCTimeSeries(nc_clim_his_file, "v", clim_v_time_varname, geom[lev].Domain(),yvel_new[lev],false,true));
1348 u_clim_data_from_file->Initialize();
1349 v_clim_data_from_file->Initialize();
1350 }
1351 // Since the NCTimeSeries object isn't filling the cons_new MultiFab directly, we don't have to specify a component.
1352 // It just needs to know the shape of the MultiFab
1354 temp_clim_data_from_file.reset(new NCTimeSeries(nc_clim_his_file, "temp", clim_temp_time_varname,geom[lev].Domain(),cons_new[lev],false,true));
1355 temp_clim_data_from_file->Initialize();
1356 }
1358 salt_clim_data_from_file.reset(new NCTimeSeries(nc_clim_his_file, "salt", clim_salt_time_varname,geom[lev].Domain(),cons_new[lev],false,true));
1359 salt_clim_data_from_file->Initialize();
1360 }
1361 }
1362 }
1363
1365 amrex::Print() << "Calling init_bdry_from_netcdf at level " << lev << std::endl;
1367 amrex::Print() << "Boundary data loaded from netcdf file \n " << std::endl;
1368 }
1369
1370 // This will be a non-op if forcings specified analytically
1372 if (lev==0) {
1373 if (nc_frc_file.empty() || nc_frc_file[0].empty()) {
1374 amrex::Error("NetCDF forcing file name must be provided via input for surface momentum fluxes");
1375 }
1376 sustr_data_from_file.reset(new NCTimeSeries(nc_frc_file, "sustr", frc_time_varname, geom[lev].Domain(),vec_sustr[lev].get(), true, false));
1377 svstr_data_from_file.reset(new NCTimeSeries(nc_frc_file, "svstr", frc_time_varname, geom[lev].Domain(),vec_svstr[lev].get(), true, false));
1378 sustr_data_from_file->Initialize();
1379 svstr_data_from_file->Initialize();
1380 } else {
1381 FillCoarsePatch(lev, time, vec_sustr[lev].get(), vec_sustr[lev-1].get(), foextrap_bc());
1382 FillCoarsePatch(lev, time, vec_svstr[lev].get(), vec_svstr[lev-1].get(), foextrap_bc());
1383 }
1384 }
1385
1386 // Conditionally load atmospheric forcing fields from NetCDF based on source type.
1387 const auto& bulk_flux_type = solverChoice.bulk_flux_type;
1388 bool any_bulk_netcdf = false;
1389 for (int idx = 0; idx < BulkFlux::NumTypes; ++idx) {
1390 any_bulk_netcdf = any_bulk_netcdf || bulk_flux_type[idx] == BulkForcingType::netcdf;
1391 }
1392 if (lev == 0 && any_bulk_netcdf && (nc_frc_file.empty() || nc_frc_file[0].empty())) {
1393 amrex::Error("NetCDF forcing file name must be provided via input for bulk-flux atmospheric forcing");
1394 }
1395
1396 if (lev==0) {
1397 if (bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::netcdf) {
1398 Uwind_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Uwind", frc_time_varname, geom[lev].Domain(),vec_uwind[lev].get(), true, false));
1399 Uwind_data_from_file->Initialize();
1400 }
1401 if (bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::netcdf) {
1402 Vwind_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Vwind", frc_time_varname, geom[lev].Domain(),vec_vwind[lev].get(), true, false));
1403 Vwind_data_from_file->Initialize();
1404 }
1405 if (bulk_flux_type[BulkFlux::Tair] == BulkForcingType::netcdf) {
1406 Tair_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Tair", frc_time_varname, geom[lev].Domain(),vec_Tair[lev].get(), true, false));
1407 Tair_data_from_file->Initialize();
1408 }
1409 if (bulk_flux_type[BulkFlux::Qair] == BulkForcingType::netcdf) {
1410 qair_data_from_file.reset(new NCTimeSeries(nc_frc_file, "qair", frc_time_varname, geom[lev].Domain(),vec_qair[lev].get(), true, false));
1411 qair_data_from_file->Initialize();
1412 }
1413 if (bulk_flux_type[BulkFlux::Pair] == BulkForcingType::netcdf) {
1414 Pair_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Pair", frc_time_varname, geom[lev].Domain(),vec_Pair[lev].get(), true, false));
1415 Pair_data_from_file->Initialize();
1416 }
1417 if (bulk_flux_type[BulkFlux::SWrad] == BulkForcingType::netcdf) {
1418 srflx_data_from_file.reset(new NCTimeSeries(nc_frc_file, "swrad", frc_time_varname, geom[lev].Domain(),vec_srflx[lev].get(), true, false));
1419 srflx_data_from_file->Initialize();
1420 }
1421 if (bulk_flux_type[BulkFlux::Rain] == BulkForcingType::netcdf) {
1422 rain_data_from_file.reset(new NCTimeSeries(nc_frc_file, "rain", frc_time_varname, geom[lev].Domain(),vec_rain[lev].get(), true, false));
1423 rain_data_from_file->Initialize();
1424 }
1425 if (bulk_flux_type[BulkFlux::Cloud] == BulkForcingType::netcdf) {
1426 cloud_data_from_file.reset(new NCTimeSeries(nc_frc_file, "cloud", frc_time_varname, geom[lev].Domain(),vec_cloud[lev].get(), true, false));
1427 cloud_data_from_file->Initialize();
1428 }
1429 if (bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::netcdf) {
1430 EminusP_data_from_file.reset(new NCTimeSeries(nc_frc_file, "EminusP", frc_time_varname, geom[lev].Domain(),vec_EminusP[lev].get(), true, false));
1431 EminusP_data_from_file->Initialize();
1432 }
1433 if (bulk_flux_type[BulkFlux::LWrad] == BulkForcingType::netcdf) {
1435 geom[lev].Domain(), vec_longwave_down[lev].get(), true, false));
1436 longwave_down_data_from_file->Initialize();
1437 }
1438 } else {
1439 if (bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::netcdf) {
1440 FillCoarsePatch(lev, time, vec_uwind[lev].get(), vec_uwind[lev-1].get(), foextrap_bc());
1441 }
1442 if (bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::netcdf) {
1443 FillCoarsePatch(lev, time, vec_vwind[lev].get(), vec_vwind[lev-1].get(), foextrap_bc());
1444 }
1445 if (bulk_flux_type[BulkFlux::Tair] == BulkForcingType::netcdf) {
1446 FillCoarsePatch(lev, time, vec_Tair[lev].get(), vec_Tair[lev-1].get(), foextrap_bc());
1447 }
1448 if (bulk_flux_type[BulkFlux::Qair] == BulkForcingType::netcdf) {
1449 FillCoarsePatch(lev, time, vec_qair[lev].get(), vec_qair[lev-1].get(), foextrap_bc());
1450 }
1451 if (bulk_flux_type[BulkFlux::Pair] == BulkForcingType::netcdf) {
1452 FillCoarsePatch(lev, time, vec_Pair[lev].get(), vec_Pair[lev-1].get(), foextrap_bc());
1453 }
1454 if (bulk_flux_type[BulkFlux::SWrad] == BulkForcingType::netcdf) {
1455 FillCoarsePatch(lev, time, vec_srflx[lev].get(), vec_srflx[lev-1].get(), foextrap_bc());
1456 }
1457 if (bulk_flux_type[BulkFlux::Rain] == BulkForcingType::netcdf) {
1458 FillCoarsePatch(lev, time, vec_rain[lev].get(), vec_rain[lev-1].get(), foextrap_bc());
1459 }
1460 if (bulk_flux_type[BulkFlux::Cloud] == BulkForcingType::netcdf) {
1461 FillCoarsePatch(lev, time, vec_cloud[lev].get(), vec_cloud[lev-1].get(), foextrap_bc());
1462 }
1463 if (bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::netcdf) {
1464 FillCoarsePatch(lev, time, vec_EminusP[lev].get(), vec_EminusP[lev-1].get(), foextrap_bc());
1465 }
1466 if (bulk_flux_type[BulkFlux::LWrad] == BulkForcingType::netcdf) {
1467 FillCoarsePatch(lev, time, vec_longwave_down[lev].get(), vec_longwave_down[lev-1].get(), foextrap_bc());
1468 }
1469 }
1470
1471 // Only need to read in rivers on level 0
1472 // Will need to be on higher levels eventually
1473 if (solverChoice.do_rivers) {
1474 if (nc_riv_file.empty() || nc_riv_file[0].empty()) {
1475 amrex::Error("NetCDF river file name must be provided via input for rivers");
1476 }
1477 auto dom = geom[0].Domain();
1478 int nz = dom.length(2);
1479 river_source_cons.resize(ncons);
1482 river_source_cons[Salt_comp]->Initialize();
1483 }
1486 river_source_cons[Temp_comp]->Initialize();
1487 }
1490 river_source_cons[Tracer_comp]->Initialize();
1491 }
1492 river_source_transport.reset(new NCTimeSeriesRiver(nc_riv_file, "river_transport", riv_time_varname, nz));
1493 river_source_transport->Initialize();
1494 river_source_transportbar.reset(new NCTimeSeriesRiver(nc_riv_file, "river_transport", riv_time_varname, nz, 1));
1495 river_source_transportbar->Initialize();
1497 }
1498
1499 if (lev==0 and hires_grid_level > 0 and solverChoice.ic_type == IC_Type::netcdf) {
1500 amrex::Print() << "Reading high resolution bathymetry and grid data" << std::endl;
1504 amrex::Print() << "Done reading in high resolution bathymetry and grid data" << std::endl;
1505 }
1506 if (lev==0 and hires_init_level > 0 and solverChoice.ic_type == IC_Type::netcdf) {
1507 amrex::Print() << "Reading high resolution initial data" << std::endl;
1511 amrex::Print() << "Done reading in high resolution initial data" << std::endl;
1512 }
1513#else
1515 Abort("Not compiled with NetCDF, but selected boundary conditions require NetCDF");
1516 }
1517 if (solverChoice.do_rivers) {
1518 Abort("Not compiled with NetCDF, but using river sources requires NetCDF");
1519 }
1520#endif
1521
1522 if (lev==0 and hires_grid_level > 0 and solverChoice.ic_type == IC_Type::analytic) {
1525 }
1526
1527 if (lev==0 and hires_init_level > 0 and solverChoice.ic_type == IC_Type::analytic) {
1530 }
1531
1532 set_bathymetry(lev);
1533 set_zeta(lev);
1534 stretch_transform(lev);
1535
1536 if (lev==0 and hires_init_level > 0 and solverChoice.ic_type == IC_Type::analytic) {
1538 }
1539
1540 if (lev==0) {
1541 if (hires_init_level < 0) {
1543 init_analytic(lev);
1544 } else if (solverChoice.ic_type == IC_Type::netcdf) {
1545#ifdef REMORA_USE_NETCDF
1546 amrex::Print() << "Calling init_data_from_netcdf " << std::endl;
1548 set_zeta_to_Ztavg(lev);
1549 amrex::Print() << "Initial data loaded from netcdf file \n " << std::endl;
1550#endif
1551 } else {
1552 amrex::Abort("Unknown IC_Type");
1553 }
1554 } else {
1556 set_zeta_to_Ztavg(lev); // MAYBE???
1557 // Since set_grid_scale is usually called from init_analytic for analytic problems
1559 set_grid_scale(lev);
1560 }
1561 }
1562 } else {
1563 if (lev > hires_init_level) {
1565 FillCoarsePatch(lev, time, xvel_new[lev], xvel_new[lev-1], xvel_bc(), BdyVars::u);
1566 FillCoarsePatch(lev, time, yvel_new[lev], yvel_new[lev-1], yvel_bc(), BdyVars::v);
1568 } else {
1570 set_zeta_to_Ztavg(lev); // MAYBE???
1572 // Since set_grid_scale is usually called from init_analytic for analytic problems
1573 set_grid_scale(lev);
1574 }
1575 }
1576 }
1577
1578 // Ensure that the face-based data are the same on both sides of a periodic domain.
1579 // The data associated with the lower grid ID is considered the correct value.
1580 xvel_new[lev]->OverrideSync(geom[lev].periodicity());
1581 yvel_new[lev]->OverrideSync(geom[lev].periodicity());
1582 zvel_new[lev]->OverrideSync(geom[lev].periodicity());
1583
1584 set_2darrays(lev);
1585
1586 init_set_vmix(lev);
1587 set_hmixcoef(lev);
1588 set_coriolis(lev);
1589
1590 // Previously set smflux here with OverrideSync:
1591// set_smflux(lev);
1592// prob->init_analytic_smflux(lev, geom[lev], solverChoice, *this, *vec_sustr[lev], *vec_svstr[lev]);
1593// vec_sustr[lev]->OverrideSync(geom[lev].periodicity());
1594// vec_svstr[lev]->OverrideSync(geom[lev].periodicity());
1595
1596}
1597
1598void
1600{
1601 BL_PROFILE("REMORA::ReadParameters()");
1602 {
1603 ParmParse pp; // Traditionally, max_step and stop_time do not have prefix, so allow it for now.
1604 bool noprefix_max_step = pp.queryAdd("max_step", max_step);
1605 bool noprefix_stop_time = pp.queryAdd("stop_time", stop_time);
1606 bool remora_max_step = pp.queryAdd("remora.max_step", max_step);
1607 bool remora_stop_time = pp.queryAdd("remora.stop_time", stop_time);
1608 if (remora_max_step and noprefix_max_step) {
1609 Abort("remora.max_step and max_step are both specified. Please use only one!");
1610 }
1611 if (remora_stop_time and noprefix_stop_time) {
1612 Abort("remora.stop_time and stop_time are both specified. Please use only one!");
1613 }
1614 }
1615
1616 ParmParse pp(pp_prefix);
1617
1618 // Common physics and simulation parameters
1619 pp.queryAdd("nscalar", nscalar);
1620 if (nscalar < 1) {
1621 amrex::Abort("remora.nscalar must be at least 1");
1622 }
1625
1626 pp.queryAdd("check_file", check_file);
1627 pp.queryAdd("check_int", check_int);
1628 pp.queryAdd("check_int_time", check_int_time);
1629 pp.queryAdd("expand_plotvars_to_unif_rr", expand_plotvars_to_unif_rr);
1630 pp.query("plotfile_fill_value", plotfile_fill_value);
1631 pp.query("netcdf_fill_value", netcdf_fill_value);
1632 pp.queryAdd("restart", restart_chkfile);
1633 pp.queryAdd("start_time", start_time);
1634
1635 num_boxes_at_level.resize(max_level + 1, 0);
1636 boxes_at_level.resize(max_level + 1);
1637 num_boxes_at_level[0] = 1;
1638 boxes_at_level[0].resize(1);
1639 boxes_at_level[0][0] = geom[0].Domain();
1640
1641 if (pp.contains("data_log")) {
1642 int num_datalogs = pp.countval("data_log");
1643 datalog.resize(num_datalogs);
1644 datalogname.resize(num_datalogs);
1645 pp.queryarr("data_log", datalogname, 0, num_datalogs);
1646 for (int i = 0; i < num_datalogs; i++)
1648 }
1649
1650 pp.queryAdd("v", verbose);
1651 pp.queryAdd("sum_interval", sum_interval);
1652 pp.queryAdd("sum_period", sum_per);
1653 pp.queryAdd("file_min_digits", file_min_digits);
1654
1655 if (file_min_digits < 0) {
1656 amrex::Abort("remora.file_min_digits must be non-negative");
1657 }
1658
1659 pp.queryAdd("cfl", cfl);
1660 pp.queryAdd("change_max", change_max);
1661 pp.queryAdd("fixed_dt", fixed_dt);
1662 pp.queryAdd("fixed_fast_dt", fixed_fast_dt);
1663 pp.queryAdd("fixed_ndtfast_ratio", fixed_ndtfast_ratio);
1664
1667 amrex::Abort("Dt is over-specfied");
1668 }
1669 } else if (fixed_dt > zero && fixed_fast_dt > zero && fixed_ndtfast_ratio <= 0) {
1670 fixed_ndtfast_ratio = static_cast<int>(fixed_dt / fixed_fast_dt);
1671 }
1672 AMREX_ASSERT(cfl > zero || fixed_dt > zero);
1673
1674 num_files_at_level.resize(max_level + 1, 0);
1675 num_boxes_at_level.resize(max_level + 1, 0);
1676 boxes_at_level.resize(max_level + 1);
1677 num_boxes_at_level[0] = 1;
1678 boxes_at_level[0].resize(1);
1679 boxes_at_level[0][0] = geom[0].Domain();
1680
1681 pp.queryAdd("plot_file", plot_file_name);
1682 pp.queryAdd("plot_int", plot_int);
1683 pp.queryAdd("plot_int_time", plot_int_time);
1684 pp.query("plot_staggered_vels", plot_staggered_vels);
1685 pp.query("plot_nodal_data", plot_nodal_data);
1686
1687 std::string plotfile_type_str = "amrex";
1688 pp.queryAdd("plotfile_type", plotfile_type_str);
1689 if (plotfile_type_str == "amrex") {
1691 } else if (plotfile_type_str == "netcdf" || plotfile_type_str == "NetCDF") {
1693#ifdef REMORA_USE_NETCDF
1694 pp.queryAdd("write_history_file",write_history_file);
1695 pp.queryAdd("chunk_history_file",chunk_history_file);
1696 pp.queryAdd("steps_per_history_file",steps_per_history_file);
1697 // Estimate size of domain for one timestep of netcdf
1698 auto dom = geom[0].Domain();
1699 int nx = dom.length(0) + 2;
1700 int ny = dom.length(1) + 2;
1701 int nz = dom.length(2);
1702 Real two_gb = Real(1.6e10);
1703 Real double_bits = Real(64.0);
1705 // Estimate number of steps that will fit into a 2GB file.
1706 steps_per_history_file = int((two_gb - NCH2D * nx * ny * double_bits)
1707 / (nx * ny * double_bits * (NC3D*nz + NC2D)));
1708 // If we calculate that a single step will exceed 2GB and the user has
1709 // requested automatic history file sizing, warn about a possible impending
1710 // error, and set steps_per_history_file = 1 to attempt output anyway.
1711 if (steps_per_history_file == 0) {
1712 amrex::Warning("NetCDF output for a single timestep appears to exceed 2GB. NetCDF output may not work. See Documentation for information about tested MPICH versions.");
1714 }
1715 } else if (write_history_file and !chunk_history_file) {
1716 // Estimate number of output steps we'll need
1717 int nt_out = int((max_step) / plot_int) + 1;
1718 Real est_hist_file_size = NCH2D * nx * ny * double_bits + nt_out * nx * ny * double_bits * (NC3D*nz + NC2D);
1719 if (est_hist_file_size > two_gb) {
1720 amrex::Warning("WARNING: NetCDF history file may be larger than 2GB limit. Consider setting remora.chunk_history_file=true");
1721 }
1722 }
1724 Print() << "NetCDF history files will have " << steps_per_history_file << " steps per file." << std::endl;
1725 }
1726#endif
1727 } else {
1728 amrex::Print() << "User selected plotfile_type = " << plotfile_type_str << std::endl;
1729 amrex::Abort("Dont know this plotfile_type");
1730 }
1731#ifndef REMORA_USE_NETCDF
1733 {
1734 amrex::Abort("Please compile with NetCDF in order to enable NetCDF plotfiles");
1735 }
1736
1737#endif
1738#ifdef REMORA_USE_NETCDF
1739 nc_init_file.resize(max_level+1);
1740 nc_grid_file.resize(max_level+1);
1741 num_files_at_level.resize(max_level + 1, 0);
1742
1743 boundary_series.resize(max_level+1);
1744
1745
1746 // NetCDF initialization files -- possibly multiple files at each of multiple levels
1747 // but we always have exactly one file at level 0
1748 for (int lev = 0; lev <= max_level; lev++)
1749 {
1750 const std::string nc_file_names = amrex::Concatenate("nc_init_file_",lev,1);
1751 const std::string nc_bathy_file_names = amrex::Concatenate("nc_grid_file_",lev,1);
1752
1753 if (pp.contains(nc_file_names.c_str()))
1754 {
1755 int num_files = pp.countval(nc_file_names.c_str());
1756 int num_bathy_files = pp.countval(nc_bathy_file_names.c_str());
1757 if (num_files != num_bathy_files) {
1758 amrex::Error("Must have same number of netcdf files for grid info as for solution");
1759 }
1760
1761 num_files_at_level[lev] = num_files;
1762 nc_init_file[lev].resize(num_files);
1763 nc_grid_file[lev].resize(num_files);
1764
1765 pp.queryarr(nc_file_names.c_str() , nc_init_file[lev] ,0,num_files);
1766 pp.queryarr(nc_bathy_file_names.c_str(), nc_grid_file[lev],0,num_files);
1767 }
1768 }
1769
1770 pp.queryAdd("nc_grid_file_hires", nc_grid_file_hires);
1771 pp.queryAdd("nc_init_file_hires", nc_init_file_hires);
1772
1773 // We only read boundary data at level 0
1774 pp.queryarr("nc_bdry_file", nc_bdry_file);
1775
1776 // Also only read forcings at level 0 (for now)
1777 if (pp.contains("nc_frc_file")) {
1778 int num_files = pp.countval("nc_frc_file");
1779 nc_frc_file.resize(num_files);
1780 pp.queryarr("nc_frc_file", nc_frc_file, 0, num_files);
1781 }
1782
1783 // Get river file
1784 if (pp.contains("nc_river_file")) {
1785 int num_files = pp.countval("nc_river_file");
1786 nc_riv_file.resize(num_files);
1787 pp.queryarr("nc_river_file", nc_riv_file, 0, num_files);
1788 }
1789
1790 // Read in file names for climatology history and nudging weights
1791 if (pp.contains("nc_clim_his_file")) {
1792 int num_files = pp.countval("nc_clim_his_file");
1793 nc_clim_his_file.resize(num_files);
1794 pp.queryarr("nc_clim_his_file", nc_clim_his_file, 0, num_files);
1795 }
1796 pp.queryAdd("nc_clim_coeff_file", nc_clim_coeff_file);
1797
1798 for (int i=0; i<BdyVars::NumTypes; i++) {
1799 bdry_time_name_byvar.push_back("");
1800 }
1801 pp.queryAdd("bdy_time_varname",bdry_time_varname);
1802 pp.queryAdd("bdy_temp_time_varname",bdry_time_name_byvar[BdyVars::t]);
1803 pp.queryAdd("bdy_salt_time_varname",bdry_time_name_byvar[BdyVars::s]);
1804 pp.queryAdd("bdy_u_time_varname",bdry_time_name_byvar[BdyVars::u]);
1805 pp.queryAdd("bdy_v_time_varname",bdry_time_name_byvar[BdyVars::v]);
1806 pp.queryAdd("bdy_ubar_time_varname",bdry_time_name_byvar[BdyVars::ubar]);
1807 pp.queryAdd("bdy_vbar_time_varname",bdry_time_name_byvar[BdyVars::vbar]);
1808 pp.queryAdd("bdy_zeta_time_varname",bdry_time_name_byvar[BdyVars::zeta]);
1809
1810 // If not specified per variable, populate with the default
1811 for (int i=0; i<BdyVars::NumTypes; i++) {
1812 if (bdry_time_name_byvar[i] == "") {
1814 }
1815 }
1816
1817 pp.queryAdd("frc_time_varname",frc_time_varname);
1818
1819 pp.queryAdd("riv_time_varname",riv_time_varname);
1820
1821 pp.queryAdd("clim_ubar_time_varname",clim_ubar_time_varname);
1822 pp.queryAdd("clim_vbar_time_varname",clim_vbar_time_varname);
1823 pp.queryAdd("clim_u_time_varname",clim_u_time_varname);
1824 pp.queryAdd("clim_v_time_varname",clim_v_time_varname);
1825 pp.queryAdd("clim_salt_time_varname",clim_salt_time_varname);
1826 pp.queryAdd("clim_temp_time_varname",clim_temp_time_varname);
1827
1828#endif
1829 pp.queryAdd("hires_grid_level", hires_grid_level);
1830 if (hires_grid_level > max_level) {
1831 amrex::Abort("hires_grid_level must be less than or equal to amr.max_level");
1832 }
1833 pp.queryAdd("hires_init_level", hires_init_level);
1834 if (hires_init_level > max_level) {
1835 amrex::Abort("hires_init_level must be less than or equal to amr.max_level");
1836 }
1837#ifdef REMORA_USE_PARTICLES
1838 readTracersParams();
1839#endif
1840
1841 {
1842 ParmParse pp_amr("amr");
1843 pp_amr.queryAdd("regrid_int", regrid_int);
1844 pp_amr.queryAdd("do_substep", do_substep);
1845 if (do_substep) {
1846 amrex::Abort("Time substepping is not yet implemented. amr.do_substep must be 0");
1847 }
1848
1849 }
1851
1852 // NOTE: This feature is not yet implemented because it will require passing x,y,z to prob functions.
1853 // Currently these are accessed by passing a pointer to the REMORA class. However, this requires the
1854 // coordinates at hires_init_level to already exist (and specifically for the hires_init_level level
1855 // to already be initialized), which is generally not the case. A solution is to create a separate
1856 // coordinates object that is passed to the prob functions instead of the REMORA object. Then x,y,z
1857 // coordinates can be calculated at any level without the corresponding level having been created.
1859 amrex::Abort("Cannot do high-resolution initialization for analytic initial conditions. Not yet implemented");
1860 }
1861
1862}
1863
1864
1865void
1867{
1868 BL_PROFILE("REMORA::AverageDown()");
1869 for (int lev = finest_level-1; lev >= 0; --lev)
1870 {
1871 AverageDownTo(lev);
1872 }
1873}
1874
1875/**
1876 * @param[in ] crse_lev level to average down to
1877 */
1878void
1880{
1881 BL_PROFILE("REMORA::AverageDownTo()");
1882 average_down(*cons_new[crse_lev+1], *cons_new[crse_lev],
1883 0, cons_new[crse_lev]->nComp(), refRatio(crse_lev));
1884 average_down(*vec_Zt_avg1[crse_lev+1].get(), *vec_Zt_avg1[crse_lev].get(),
1885 0, vec_Zt_avg1[crse_lev]->nComp(), refRatio(crse_lev));
1886
1887 Array<MultiFab*,AMREX_SPACEDIM> faces_crse;
1888 Array<MultiFab*,AMREX_SPACEDIM> faces_fine;
1889 faces_crse[0] = xvel_new[crse_lev];
1890 faces_crse[1] = yvel_new[crse_lev];
1891 faces_crse[2] = zvel_new[crse_lev];
1892
1893 faces_fine[0] = xvel_new[crse_lev+1];
1894 faces_fine[1] = yvel_new[crse_lev+1];
1895 faces_fine[2] = zvel_new[crse_lev+1];
1896
1897 average_down_faces(GetArrOfConstPtrs(faces_fine), faces_crse,
1898 refRatio(crse_lev),geom[crse_lev]);
1899 stretch_transform(crse_lev);
1900}
1901
1902/**
1903 * @param[in ] crse_lev level to average data down to
1904 * @param[inout] vec_mf vector over levels of multifabs containing data to average
1905 */
1906void
1907REMORA::average_down_with_grow_cells (int crse_lev, Vector<std::unique_ptr<MultiFab>>& vec_mf)
1908{
1909 auto const& crsema = vec_mf[crse_lev]->arrays();
1910 auto const& finema = vec_mf[crse_lev+1]->const_arrays();
1911 auto ref_ratio_crse = refRatio(crse_lev);
1912 auto index_type = (vec_mf[crse_lev]->boxArray().ixType()).toIntVect();
1913 auto nghost_crse = cum_ref_ratios[crse_lev] - index_type;
1914 if (index_type[0]==0 and index_type[1]==0) {
1915 ParallelFor(*vec_mf[crse_lev], nghost_crse, vec_mf[crse_lev]->nComp(),
1916 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1917 {
1918 amrex_avgdown(i,j,k,n,crsema[box_no],finema[box_no],0,0,ref_ratio_crse);
1919 });
1920 } else if (index_type[0]==1 and index_type[1]==0) {
1921 ParallelFor(*vec_mf[crse_lev], nghost_crse, 1,
1922 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1923 {
1924 amrex_avgdown_faces(i,j,k,n,crsema[box_no],finema[box_no],0,0,ref_ratio_crse,0);
1925 });
1926 } else if (index_type[0]==0 and index_type[1]==1) {
1927 ParallelFor(*vec_mf[crse_lev], nghost_crse, 1,
1928 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
1929 {
1930 amrex_avgdown_faces(i,j,k,n,crsema[box_no],finema[box_no],0,0,ref_ratio_crse,1);
1931 });
1932 } else {
1933 amrex::Abort("Unexpected nodality in average_down_with_grow_cells");
1934 }
1935 Gpu::streamSynchronize();
1936}
1937
1938/**
1939 * @param[in ] lev level at which to get time
1940 */
1941amrex::Real REMORA::get_t_old(int lev) const
1942{
1943 return t_old[lev];
1944}
constexpr amrex::Real bogus_large_value
constexpr amrex::Real one
constexpr amrex::Real fourth
constexpr amrex::Real zero
PlotfileType
plotfile format
#define Temp_comp
#define NC3D
#define Tracer_comp
#define Salt_comp
#define NC2D
#define NCH2D
std::unique_ptr< ProblemBase > amrex_probinit(const amrex_real *problo, const amrex_real *probhi) AMREX_ATTRIBUTE_WEAK
Function to init the physical bounds of the domain and instantiate a Problem derived from ProblemBase...
A class to hold and interpolate time series data read from a NetCDF file.
static PlotfileType plotfile_type
Native or NetCDF plotfile output.
Definition REMORA.H:1656
std::string nc_grid_file_hires
Grid file for high resolution bathymetry.
Definition REMORA.H:1668
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_EminusP
evaporation minus precipitation [kg/m^2/s], defined at rho-points
Definition REMORA.H:491
amrex::Vector< std::string > nc_riv_file
NetCDF river file(s)
Definition REMORA.H:1685
void set_grid_vars_averaged_down(int lev)
Set pm/pn by averaging down from higher-resolution grid.
Definition REMORA.cpp:718
std::string riv_time_varname
Name of time field for river time.
Definition REMORA.H:1710
int foextrap_periodic_bc() const noexcept
Definition REMORA.H:1254
amrex::Vector< std::string > nc_clim_his_file
NetCDF climatology history file(s)
Definition REMORA.H:1688
int ncons
Number of conserved scalars in the state (temperature + salt + passive scalars)
Definition REMORA.H:1546
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_zeta_full_domain
high resolution initial free surface height (2D)
Definition REMORA.H:536
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rv2d
v velocity RHS (2D, includes horizontal and vertical advection)
Definition REMORA.H:406
std::string nc_init_file_hires
Init file for high resolution.
Definition REMORA.H:1675
static amrex::Real fixed_dt
User specified fixed baroclinic time step.
Definition REMORA.H:1554
amrex::Real last_plot_file_time
Simulation time when we last output a plotfile.
Definition REMORA.H:1520
int zvel_bc() const noexcept
Definition REMORA.H:1249
void init_full_domain_zeta_from_analytic()
Initialize high resolution initial sea surface height from analytic functions.
static bool plot_staggered_vels
Whether to write the staggered velocities (not averaged to cell centers)
Definition REMORA.H:1650
void init_bathymetry_from_netcdf(int lev)
Bathymetry data initialization from NetCDF file.
void init_bcs()
Read in boundary parameters from input file and set up data structures.
int xvel_bc() const noexcept
Definition REMORA.H:1247
void set_zeta_averaged_down(int lev)
Copy over zeta data that has been averaged down from high res.
Definition REMORA.cpp:736
void calculate_nodal_masks(int lev)
Calculate u-, v-, and psi-point masks based on rho-point masks after analytic initialization.
std::unique_ptr< NCTimeSeries > qair_data_from_file
Data container for specific humidity read from file.
Definition REMORA.H:1372
static amrex::Real previousCPUTimeUsed
Accumulator variable for CPU time used thusfar.
Definition REMORA.H:1769
amrex::Vector< std::string > cons_names
Names of scalars for plotfile output.
Definition REMORA.H:1597
bool running_with_coupling_driver
True once REMORA has received forcing through the coupling driver.
Definition REMORA.H:496
amrex::Vector< std::unique_ptr< amrex::YAFluxRegister > > advflux_reg
array of flux registers for refluxing in multilevel
Definition REMORA.H:1486
std::unique_ptr< NCTimeSeries > sustr_data_from_file
Data container for u-component surface momentum flux read from file.
Definition REMORA.H:1362
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_fcor
coriolis factor (2D)
Definition REMORA.H:559
void allocate_init_full_domain()
Allocate multifabs for storing full-domain high resolution initial data.
void init_gls_vmix(int lev, SolverChoice solver_choice)
Initialize GLS variables.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_xvel_full_domain
multilevel data container for high res initial x velocities (u in ROMS)
Definition REMORA.H:379
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_h
multilevel data container for current step's z velocities (largely unused; W stored separately)
Definition REMORA.H:388
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pm
horizontal scaling factor: 1 / dx (2D)
Definition REMORA.H:550
void set2DPlotVariables(const std::string &pp_plot_var_names_2d)
amrex::Vector< REMORAFillPatcher > FPr_v
Vector over levels of FillPatchers for v (3D)
Definition REMORA.H:1430
void init_zeta_full_domain_from_netcdf()
Full-domain high res sea-surface height data initialization from NetCDF file.
amrex::Vector< amrex::MultiFab * > cons_new
multilevel data container for current step's scalar data: temperature, salinity, passive tracer
Definition REMORA.H:368
static bool write_history_file
Whether to output NetCDF files as a single history file with several time steps.
Definition REMORA.H:1359
void stretch_transform(int lev)
Calculate vertical stretched coordinates.
std::unique_ptr< NCTimeSeries > rain_data_from_file
Data container for precipitation rate read from file.
Definition REMORA.H:1380
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_vwind
Wind in the v direction, defined at rho-points.
Definition REMORA.H:456
std::unique_ptr< ProblemBase > prob
Pointer to container of analytical functions for problem definition.
Definition REMORA.H:1459
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskr
land/sea mask at cell centers (2D)
Definition REMORA.H:539
void Construct_REMORAFillPatchers(int lev)
Construct FillPatchers.
Definition REMORA.cpp:500
void init_grid_vars_from_netcdf(int lev)
Grid variable initialization from NetCDF file.
static int sum_interval
Diagnostic sum output interval in number of steps.
Definition REMORA.H:1642
int history_count
Counter for which time index we are writing to in the netcdf history file.
Definition REMORA.H:1590
amrex::Real stop_time
Time to stop.
Definition REMORA.H:1535
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rain
precipitation rate [kg/m^2/s]
Definition REMORA.H:485
int do_substep
Whether to substep fine levels in time.
Definition REMORA.H:1563
void Evolve()
Advance solution to final time.
Definition REMORA.cpp:259
std::string bdry_time_varname
Default name of time field for boundary data.
Definition REMORA.H:1693
amrex::Real plotfile_fill_value
fill value for masked arrays in amrex plotfiles
Definition REMORA.H:1609
void ReadCheckpointFile()
read checkpoint file from disk
bool chunk_history_file
Whether to chunk netcdf history file.
Definition REMORA.H:1583
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_sustr
Surface stress in the u direction.
Definition REMORA.H:449
amrex::Real get_t_old(int lev) const
Accessor method for t_old to expose to outside classes.
Definition REMORA.cpp:1941
int yvel_bc() const noexcept
Definition REMORA.H:1248
std::unique_ptr< NCTimeSeries > longwave_down_data_from_file
Data container for downward longwave radiation flux read from file.
Definition REMORA.H:1378
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_ru2d
u velocity RHS (2D, includes horizontal and vertical advection)
Definition REMORA.H:404
amrex::Vector< std::string > datalogname
Definition REMORA.H:1801
amrex::Vector< amrex::MultiFab * > zvel_new
multilevel data container for current step's z velocities (largely unused; W stored separately)
Definition REMORA.H:374
void set_surface_state(int lev)
Initialize or calculate wind speed and other surface state vars from file or analytic.
Definition REMORA.cpp:1166
void WriteAtIntermediateTime(int step, amrex::Real cur_time)
Write checkpoint and plotfiles at intermediate point of simulation, if needed.
Definition REMORA.cpp:331
void init_only(int lev, amrex::Real time)
Init (NOT restart or regrid)
Definition REMORA.cpp:1303
void init_set_vmix(int lev)
Initialize vertical mixing coefficients from file or analytic.
Definition REMORA.cpp:793
std::unique_ptr< NCTimeSeries > v_clim_data_from_file
Data container for v-velocity climatology data read from file.
Definition REMORA.H:1393
std::string clim_u_time_varname
Name of time field for u climatology data.
Definition REMORA.H:1702
void set_grid_scale(int lev)
Set pm and pn arrays and x/y coords on level lev.
void set_coriolis(int lev)
Initialize Coriolis factor from file or analytic.
Definition REMORA.cpp:764
int foextrap_bc() const noexcept
Definition REMORA.H:1255
amrex::Vector< REMORAFillPatcher > FPr_u
Vector over levels of FillPatchers for u (3D)
Definition REMORA.H:1428
std::string clim_temp_time_varname
Name of time field for temperature climatology data.
Definition REMORA.H:1708
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< std::unique_ptr< amrex::MultiFab > > vec_Akt
Vertical diffusion coefficient (3D)
Definition REMORA.H:414
std::unique_ptr< NCTimeSeriesRiver > river_source_transportbar
Data container for vertically integrated momentum transport in rivers.
Definition REMORA.H:1404
std::array< bool, AtmosState::NumTypes > driver_atmos_state_from_driver
provenance flags for driver-supplied atmospheric forcing lanes
Definition REMORA.H:494
std::string clim_ubar_time_varname
Name of time field for ubar climatology data.
Definition REMORA.H:1698
std::unique_ptr< NCTimeSeries > u_clim_data_from_file
Data container for u-velocity climatology data read from file.
Definition REMORA.H:1391
std::string check_file
Checkpoint file prefix.
Definition REMORA.H:1576
static amrex::Real startCPUTime
Variable for CPU timing.
Definition REMORA.H:1767
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pm_full_domain
horizontal scaling factor: 1 / dx (2D) on whole domain
Definition REMORA.H:554
amrex::Vector< amrex::MultiFab * > xvel_old
multilevel data container for last step's x velocities (u in ROMS)
Definition REMORA.H:361
amrex::Real start_time
Time of the start of the simulation, in seconds.
Definition REMORA.H:1538
void init_data_from_netcdf(int lev)
Problem initialization from NetCDF file.
void init_masks_from_netcdf(int lev)
Mask data initialization from NetCDF file.
amrex::Vector< amrex::MultiFab * > yvel_new
multilevel data container for current step's y velocities (v in ROMS)
Definition REMORA.H:372
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_uwind
Wind in the u direction, defined at rho-points.
Definition REMORA.H:454
static bool plot_nodal_data
Whether to write nodal data (Nu_nd) to plotfiles.
Definition REMORA.H:1653
static amrex::Real fixed_fast_dt
User specified fixed barotropic time step.
Definition REMORA.H:1556
int regrid_int
how often each level regrids the higher levels of refinement (after a level advances that many time s...
Definition REMORA.H:1566
amrex::Real check_int_time
Checkpoint output interval in seconds.
Definition REMORA.H:1580
DriverAtmosForcingMode driver_atmos_forcing_mode
Active atmosphere-to-ocean forcing contract on the most recent driver apply.
Definition REMORA.H:500
void init_scalar_metadata()
Build runtime scalar names after nscalar is known.
Definition REMORA.cpp:246
int zeta_bc() const noexcept
Definition REMORA.H:1252
void Define_REMORAFillPatchers(int lev)
Define FillPatchers.
Definition REMORA.cpp:549
amrex::Vector< amrex::IntVect > cum_ref_ratios
Cumulative refinement ratio between level 0 and level i.
Definition REMORA.H:1680
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_visc2_p
Harmonic viscosity defined on the psi points (corners of horizontal grid cells)
Definition REMORA.H:416
amrex::Real plot_int_time
Plotfile output interval in seconds.
Definition REMORA.H:1574
amrex::Vector< int > num_files_at_level
how many netcdf input files specified at each level
Definition REMORA.H:1464
amrex::Vector< REMORAFillPatcher > FPr_vbar
Vector over levels of FillPatchers for vbar (2D)
Definition REMORA.H:1438
void AverageDownTo(int crse_lev)
more flexible version of AverageDown() that lets you average down across multiple levels
Definition REMORA.cpp:1879
int steps_per_history_file
Number of time steps per netcdf history file.
Definition REMORA.H:1588
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Called after every level 0 timestep.
Definition REMORA.cpp:356
int max_step
maximum number of steps
Definition REMORA.H:1533
amrex::Vector< amrex::MultiFab * > zvel_old
multilevel data container for last step's z velocities (largely unused; W stored separately)
Definition REMORA.H:365
std::unique_ptr< NCTimeSeries > svstr_data_from_file
Data container for v-component surface momentum flux read from file.
Definition REMORA.H:1364
amrex::Vector< std::string > nc_frc_file
NetCDF forcing file(s)
Definition REMORA.H:1683
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.
int last_check_file_step
Step when we last output a checkpoint file.
Definition REMORA.H:1523
void init_beta_plane_coriolis(int lev)
Calculate Coriolis parameters from beta plane parametrization.
std::string clim_vbar_time_varname
Name of time field for vbar climatology data.
Definition REMORA.H:1700
amrex::Vector< int > nsubsteps
How many substeps on each level?
Definition REMORA.H:1471
amrex::Vector< std::unique_ptr< REMORAPhysBCFunct > > physbcs
Vector (over level) of functors to apply physical boundary conditions.
Definition REMORA.H:1483
void ComputeDt()
a wrapper for estTimeStep()
void fill_3d_masks(int lev)
Copy maskr to all z levels.
std::unique_ptr< NCTimeSeries > EminusP_data_from_file
Data container for evaporation minus precipitation read from file.
Definition REMORA.H:1384
void FillCoarsePatch(int lev, amrex::Real time, amrex::MultiFab *mf_fine, amrex::MultiFab *mf_crse, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab())
fill an entire multifab by interpolating from the coarser level
int plot_int
Plotfile output interval in iterations.
Definition REMORA.H:1572
std::unique_ptr< NCTimeSeries > cloud_data_from_file
Data container for cloud cover fraction read from file.
Definition REMORA.H:1382
void WriteAtFinalTime()
Write checkpoint and plotfiles at end of simulation.
Definition REMORA.cpp:316
void InitData()
Initialize multilevel data.
Definition REMORA.cpp:388
void set3DPlotVariables(const std::string &pp_plot_var_names_3d)
amrex::Vector< int > istep
which step?
Definition REMORA.H:1469
void WriteCheckpointFile()
write checkpoint file to disk
std::string nc_clim_coeff_file
NetCDF climatology coefficient file.
Definition REMORA.H:1690
void setRecordDataInfo(int i, const std::string &filename)
Definition REMORA.H:1787
void set_analytic_vmix(int lev)
Set vertical mixing coefficients from analytic.
Definition REMORA.cpp:810
void init_flat_bathymetry(int lev)
Initialize flat bathymetry to value from problo.
Definition REMORA.cpp:1137
std::unique_ptr< NCTimeSeries > temp_clim_data_from_file
Data container for temperature climatology data read from file.
Definition REMORA.H:1395
amrex::Vector< std::string > bdry_time_name_byvar
Name of time fields for boundary data.
Definition REMORA.H:1695
static int file_min_digits
Minimum number of digits in plotfile name or chunked history file.
Definition REMORA.H:1647
void init_riv_pos_from_netcdf(int lev)
static amrex::Vector< std::string > nc_bdry_file
NetCDF boundary data.
Definition REMORA.H:54
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_visc2_r
Harmonic viscosity defined on the rho points (centers)
Definition REMORA.H:418
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_yvel_full_domain
multilevel data container for high res initial y velocities (v in ROMS)
Definition REMORA.H:381
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_svstr
Surface stress in the v direction.
Definition REMORA.H:451
std::unique_ptr< NCTimeSeries > srflx_data_from_file
Data container for shortwave radiation flux read from file.
Definition REMORA.H:1376
REMORA()
Definition REMORA.cpp:65
void set_zeta(int lev)
Initialize zeta from file or analytic.
Definition REMORA.cpp:609
static amrex::Real change_max
Fraction maximum change in subsequent time steps.
Definition REMORA.H:1552
void init_zeta_from_netcdf(int lev)
Sea-surface height data initialization from NetCDF file.
void set_zeta_average(int lev)
Set Zt_avg1 to zeta.
void init_coriolis_from_netcdf(int lev)
Coriolis parameter data initialization from NetCDF file.
std::string pp_prefix
default prefix for input file parameters
Definition REMORA.H:356
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_h_full_domain
Bathymetry data on the whole domain at each potential level.
Definition REMORA.H:391
void set_bathymetry(int lev)
Initialize bathymetry from file or analytic.
Definition REMORA.cpp:648
amrex::Vector< amrex::MultiFab * > yvel_old
multilevel data container for last step's y velocities (v in ROMS)
Definition REMORA.H:363
std::unique_ptr< NCTimeSeries > ubar_clim_data_from_file
Data container for ubar climatology data read from file.
Definition REMORA.H:1387
void init_full_domain_from_analytic()
Initialize high resolution initial problem data from analytic functions.
void init_data_full_domain_from_netcdf()
High resolution roblem initialization from NetCDF file.
amrex::Vector< REMORAFillPatcher > FPr_c
Vector over levels of FillPatchers for scalars.
Definition REMORA.H:1426
int hires_init_level
Which level the high resolution initialization data is at.
Definition REMORA.H:1673
std::unique_ptr< NCTimeSeries > Tair_data_from_file
Data container for air temperature read from file.
Definition REMORA.H:1370
int nscalar
Number of passive scalars carried in the state.
Definition REMORA.H:1544
std::string clim_v_time_varname
Name of time field for v climatology data.
Definition REMORA.H:1704
amrex::Vector< REMORAFillPatcher > FPr_w
Vector over levels of FillPatchers for w.
Definition REMORA.H:1432
void average_down_with_grow_cells(int lev, amrex::Vector< std::unique_ptr< amrex::MultiFab > > &mf)
Average down from level lev+1 to lev in mf, including grow cells.
Definition REMORA.cpp:1907
std::string clim_salt_time_varname
Name of time field for salinity climatology data.
Definition REMORA.H:1706
std::unique_ptr< NCTimeSeries > Uwind_data_from_file
Data container for u-direction wind read from file.
Definition REMORA.H:1366
std::unique_ptr< NCTimeSeries > Pair_data_from_file
Data container for air pressure read from file.
Definition REMORA.H:1374
amrex::Vector< amrex::Real > t_new
new time at each level
Definition REMORA.H:1473
void init_stretch_coeffs()
initialize and calculate stretch coefficients
void init_bdry_from_netcdf(int lev)
Boundary data initialization from NetCDF file.
static SolverChoice solverChoice
Container for algorithmic choices.
Definition REMORA.H:1603
void set_masks(int lev)
Initialize land-sea masks from file or analytic.
Definition REMORA.cpp:826
bool driver_uses_two_way_coupling
Driver-level direction flag copied in before InitData.
Definition REMORA.H:498
amrex::Vector< amrex::Vector< std::unique_ptr< NCTimeSeriesBoundary > > > boundary_series
Vector over BdyVars of boundary series data containers.
Definition REMORA.H:1407
int cf_set_width
Width for fixing values at coarse-fine interface.
Definition REMORA.H:1423
void ReadParameters()
read in some parameters from inputs file
Definition REMORA.cpp:1599
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_ru
u velocity RHS (3D, includes horizontal and vertical advection)
Definition REMORA.H:400
void sum_integrated_quantities(amrex::Real time)
Integrate conserved quantities for diagnostics.
static int total_nc_plot_file_step
Definition REMORA.H:1262
static amrex::Vector< amrex::Vector< std::string > > nc_grid_file
NetCDF grid file.
Definition REMORA.H:56
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_longwave_down
Downward longwave radiation.
Definition REMORA.H:469
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_zeta
free surface height (2D)
Definition REMORA.H:533
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_vbar
barotropic y velocity (2D)
Definition REMORA.H:531
void FillCoarsePatchPC(int lev, amrex::Real time, amrex::MultiFab *mf_fine, amrex::MultiFab *mf_crse, const int bccomp, const int bdy_var_type=BdyVars::null, const int icomp=0, const bool fill_all=true, const int n_not_fill=0, const int icomp_calc=0, const amrex::Real dt=zero, const amrex::MultiFab &mf_calc=amrex::MultiFab())
fill an entire multifab by interpolating from the coarser level using the piecewise constant interpol...
void set_zeta_to_Ztavg(int lev)
Set zeta components to be equal to time-averaged Zt_avg1.
bool expand_plotvars_to_unif_rr
whether plotfile variables should be expanded to a uniform refinement ratio
Definition REMORA.H:1606
int plot_file_on_restart
Whether to output a plotfile on restart from checkpoint.
Definition REMORA.H:1527
void set_2darrays(int lev)
Set 2D momentum arrays from 3D momentum.
void init_analytic(int lev)
Initialize initial problem data from analytic functions.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_ubar
barotropic x velocity (2D)
Definition REMORA.H:529
amrex::Vector< amrex::MultiFab * > cons_old
multilevel data container for last step's scalar data: temperature, salinity, passive tracer
Definition REMORA.H:359
std::string frc_time_varname
Name of time field for forcing data.
Definition REMORA.H:1712
amrex::Vector< REMORAFillPatcher > FPr_ubar
Vector over levels of FillPatchers for ubar (2D)
Definition REMORA.H:1436
bool is_it_time_for_action(int nstep, amrex::Real time, amrex::Real dt, int action_interval, amrex::Real action_per)
Decide if it is time to take an action.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_cons_full_domain
multilevel data container for high res initial data: temperature, salinity, passive tracer
Definition REMORA.H:377
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.
std::unique_ptr< NCTimeSeries > Vwind_data_from_file
Data container for v-direction wind read from file.
Definition REMORA.H:1368
static constexpr bool DriverUsesStateForcing(DriverAtmosForcingMode mode) noexcept
Definition REMORA.H:98
void init_bathymetry_full_domain_from_netcdf()
Full domain high-res bathymetry data initialization from NetCDF file.
void set_hmixcoef(int lev)
Initialize horizontal mixing coefficients.
Definition REMORA.cpp:852
amrex::Vector< std::unique_ptr< NCTimeSeriesRiver > > river_source_cons
Vector of data containers for scalar data in rivers.
Definition REMORA.H:1400
void timeStep(int lev, amrex::Real time, int iteration)
advance a level by dt, includes a recursive call for finer levels
std::unique_ptr< NCTimeSeriesRiver > river_source_transport
Data container for momentum transport in rivers.
Definition REMORA.H:1402
void init_grid_vars_full_domain_from_netcdf()
Full domain high-res grid variable initialization from NetCDF file.
void AverageDown()
set covered coarse cells to be the average of overlying fine cells
Definition REMORA.cpp:1866
static int fixed_ndtfast_ratio
User specified, number of barotropic steps per baroclinic step.
Definition REMORA.H:1558
amrex::Real netcdf_fill_value
fill value for masked arrays in netcdf output
Definition REMORA.H:1611
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pn_full_domain
horizontal scaling factor: 1 / dy (2D) on whole domain
Definition REMORA.H:556
void timeStepML(amrex::Real time, int iteration)
advance all levels by dt, loops over finer levels
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pn
horizontal scaling factor: 1 / dy (2D)
Definition REMORA.H:552
amrex::Vector< std::unique_ptr< std::fstream > > datalog
Definition REMORA.H:1800
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Akv
Vertical viscosity coefficient (3D)
Definition REMORA.H:412
static amrex::Real cfl
CFL condition.
Definition REMORA.H:1550
void append3DPlotVariables(const std::string &pp_plot_var_names_3d)
void allocate_bathymetry_grid_vars_full_domain()
Allocate multifabs for storing full-domain bathymetry and grid vars data.
void set_init_data_averaged_down(int lev)
Problem initialization from averaged-down high resolution data.
Definition REMORA.cpp:747
static int verbose
Verbosity level of output.
Definition REMORA.H:1639
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_cloud
cloud cover fraction [0-1], defined at rho-points
Definition REMORA.H:489
std::string plot_file_name
Plotfile prefix.
Definition REMORA.H:1570
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Zt_avg1
Average of the free surface, zeta (2D)
Definition REMORA.H:446
std::unique_ptr< NCTimeSeries > salt_clim_data_from_file
Data container for salinity climatology data read from file.
Definition REMORA.H:1397
int check_int
Checkpoint output interval in iterations.
Definition REMORA.H:1578
void set_smflux(int lev)
Initialize or calculate surface momentum flux from file or analytic.
Definition REMORA.cpp:1147
void WritePlotFile(int istep)
main driver for writing AMReX plotfiles
std::string restart_chkfile
If set, restart from this checkpoint file.
Definition REMORA.H:1541
void init_clim_nudg_coeff(int lev)
Wrapper to initialize climatology nudging coefficient.
void init_bathymetry_full_domain_from_analytic()
Full domain bathymetry data initialization from analytic.
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rv
v velocity RHS (3D, includes horizontal and vertical advection)
Definition REMORA.H:402
int cf_width
Nudging width at coarse-fine interface.
Definition REMORA.H:1421
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
NetCDF initialization file.
Definition REMORA.H:55
int last_plot_file_step
Step when we last output a plotfile.
Definition REMORA.H:1518
amrex::Vector< amrex::Real > t_old
old time at each level
Definition REMORA.H:1475
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_srflx
Shortwave radiation flux [W/m²], defined at rho-points.
Definition REMORA.H:465
amrex::Real last_check_file_time
Simulation time when we last output a checkpoint file.
Definition REMORA.H:1525
void append2DPlotVariables(const std::string &pp_plot_var_names_2d)
void set_bathymetry_averaged_down(int lev)
Copy over bathymetry data that has been averaged down from high resolution input netcdf file.
Definition REMORA.cpp:701
amrex::Vector< amrex::Real > dt
time step at each level
Definition REMORA.H:1477
static amrex::Real sum_per
Diagnostic sum output interval in time.
Definition REMORA.H:1644
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Pair
Air pressure [mb], defined at rho-points.
Definition REMORA.H:462
virtual ~REMORA()
Definition REMORA.cpp:241
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_qair
Specific humidity [kg/kg], defined at rho-points.
Definition REMORA.H:460
int hires_grid_level
Which level the high resolution bathymetry is at.
Definition REMORA.H:1666
void restart()
Definition REMORA.cpp:596
std::unique_ptr< NCTimeSeries > vbar_clim_data_from_file
Data container for vbar climatology data read from file.
Definition REMORA.H:1389
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Tair
Air temperature [°C], defined at rho-points.
Definition REMORA.H:458
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_diff2
Harmonic diffusivity for temperature / salinity.
Definition REMORA.H:420
@ Pair
atmospheric pressure [Pa from driver, mb in REMORA]
@ Vwind
10-m meridional wind [m/s]
@ Qair
specific humidity [kg/kg]
@ SWrad
downward shortwave radiation [W/m^2]
@ LWrad
downward longwave radiation [W/m^2]
@ Uwind
10-m zonal wind [m/s]
@ Rain
precipitation rate [kg/m^2/s]
@ Cloud
cloud fraction [0-1]
@ Tair
air temperature [K from driver, degC in REMORA]
static constexpr int cons_bc
static constexpr int Temp_bc_comp
@ Vwind
10-m meridional wind [m/s]
@ Pair
atmospheric pressure [mb]
@ Uwind
10-m zonal wind [m/s]
@ LWrad
longwave radiation [W/m^2]
@ Tair
air temperature [degC]
@ Qair
specific humidity or relative humidity [kg/kg or fraction]
@ Cloud
cloud fraction [0-1]
@ SWrad
downward shortwave radiation [W/m^2]
@ Rain
precipitation rate [kg/m^2/s]
@ EminusP
evaporation minus precipitation [m/s]
const char * buildInfoGetGitHash(int i)
HorizMixingType horiz_mixing_type
amrex::Real Akv_bak
amrex::Vector< amrex::Real > tnu2
std::string longwave_netcdf_varname
amrex::Vector< int > do_rivers_cons
ScaledToGridAMRScaling scaled_to_grid_amr_scaling
amrex::Real Akt_bak
amrex::Real visc2
void init_params(int ncons)
read in and initialize parameters
SMFluxType smflux_type
VertMixingType vert_mixing_type
std::array< BulkForcingType, BulkFlux::NumTypes > bulk_flux_type
CouplingType coupling_type