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#ifdef REMORA_USE_NETCDF
9#include "REMORA_NCFile.H"
10#endif
11
12#include <AMReX_buildInfo.H>
13
14using namespace amrex;
15
16amrex::Real REMORA::startCPUTime = zero;
18
20
22
23// Time step control
24amrex::Real REMORA::cfl = Real(0.8);
25amrex::Real REMORA::fixed_dt = -one;
26amrex::Real REMORA::change_max = Real(1.1);
27
28int REMORA::ndtfast = 0;
29
30// Dictate verbosity in screen output
31int REMORA::verbose = 0;
32
33// Frequency of diagnostic output
35amrex::Real REMORA::sum_per = -one;
36
37// Minimum number of digits in plotfile name
39
40// Do we include staggered velocities in the plotfile?
42
43// Do we include nodal data (Nu_nd) in the plotfile?
44bool REMORA::plot_nodal_data = true;
45
46// Native AMReX vs NetCDF
48
49#ifdef REMORA_USE_NETCDF
50
52
53// Do we write one file per timestep (false) or one file for all timesteps (true)
55
56// NetCDF initialization file
57amrex::Vector<std::string> REMORA::nc_bdry_file = {""}; // Must provide via input
58amrex::Vector<amrex::Vector<std::string>> REMORA::nc_init_file = {{""}}; // Must provide via input
59amrex::Vector<amrex::Vector<std::string>> REMORA::nc_grid_file = {{""}}; // Must provide via input
60#endif
61
62/**
63 * constructor:
64 * - reads in parameters from inputs file
65 * - sizes multilevel arrays and data structures
66 * - initializes BCRec boundary condition object
67 */
69{
70 BL_PROFILE("REMORA::REMORA()");
71
72 if (ParallelDescriptor::IOProcessor()) {
75 const char* buildgithash = amrex::buildInfoGetBuildGitHash();
76 const char* buildgitname = amrex::buildInfoGetBuildGitName();
77
78 if (strlen(remora_hash) > 0) {
79 amrex::Print() << "\n"
80 << "REMORA git hash: " << remora_hash << "\n";
81 }
82 if (strlen(amrex_hash) > 0) {
83 amrex::Print() << "AMReX git hash: " << amrex_hash << "\n";
84 }
85 if (strlen(buildgithash) > 0) {
86 amrex::Print() << buildgitname << " git hash: " << buildgithash << "\n";
87 }
88
89 amrex::Print() << "\n";
90 }
91
93
94 // Blocking factor in z set to very large value to be > nz
95 // This guarantees that there will be no domain decomposition in the z-direction
96 // We have to set this by hand here because setting it in the input file will
97 // cause checks in the AmrCore constructor to fail.
100 for (int lev = 0; lev <= max_level; ++lev) {
102 blocking_factor_vec[lev][2] = 4096;
103 }
105
106 const std::string& pv3d = "plot_vars_3d"; set3DPlotVariables(pv3d);
107 const std::string& pv2d = "plot_vars_2d"; set2DPlotVariables(pv2d);
108
110
111 // Geometry on all levels has been defined already.
112
113 // No valid BoxArray and DistributionMapping have been defined.
114 // But the arrays for them have been resized.
115
116 int nlevs_max = max_level + 1;
117
118 istep.resize(nlevs_max, 0);
119 nsubsteps.resize(nlevs_max, 1);
120 for (int lev = 1; lev <= max_level; ++lev) {
122 }
123
124 physbcs.resize(nlevs_max);
125
126 t_new.resize(nlevs_max, zero);
129
130 cons_new.resize(nlevs_max);
131 cons_old.resize(nlevs_max);
132 xvel_new.resize(nlevs_max);
133 xvel_old.resize(nlevs_max);
134 yvel_new.resize(nlevs_max);
135 yvel_old.resize(nlevs_max);
136 zvel_new.resize(nlevs_max);
137 zvel_old.resize(nlevs_max);
138
139 advflux_reg.resize(nlevs_max);
140
141 // Initialize tagging criteria for mesh refinement
143
144 IntVect cum_ref_ratio = IntVect(1,1,0);
145 cum_ref_ratios.push_back(cum_ref_ratio);
146 // We have already read in the ref_Ratio (via amr.ref_ratio =) but we need to enforce
147 // that there is no refinement in the vertical so we test on that here.
148 for (int lev = 0; lev < max_level; ++lev)
149 {
150 amrex::Print() << "Refinement ratio at level " << lev << " set to be " <<
151 ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
152
153 if (ref_ratio[lev][2] != 1)
154 {
155 amrex::Print() << "********************************************************************************" << std::endl;
156 amrex::Print() << "We don't allow refinement in the vertical -- make sure to set ref_ratio = 1 in z" << std::endl;
157 amrex::Print() << "It's possible you set amr.ref_ratio when you meant to set amr.ref_ratio_vect " << std::endl;
158 amrex::Print() << "********************************************************************************" << std::endl;
159 amrex::Abort();
160 }
161
162 cum_ref_ratio[0] *= ref_ratio[lev][0];
163 cum_ref_ratio[1] *= ref_ratio[lev][1];
164 cum_ref_ratios.push_back(cum_ref_ratio);
165 }
166}
167
168REMORA::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)
170{
171 BL_PROFILE("REMORA::REMORA(explicit)");
173
174 if (ParallelDescriptor::IOProcessor()) {
176 const char* amrex_hash = amrex::buildInfoGetGitHash(2);
177 const char* buildgithash = amrex::buildInfoGetBuildGitHash();
178 const char* buildgitname = amrex::buildInfoGetBuildGitName();
179
180 if (strlen(remora_hash) > 0) {
181 amrex::Print() << "\n"
182 << "REMORA git hash: " << remora_hash << "\n";
183 }
184 if (strlen(amrex_hash) > 0) {
185 amrex::Print() << "AMReX git hash: " << amrex_hash << "\n";
186 }
187 if (strlen(buildgithash) > 0) {
188 amrex::Print() << buildgitname << " git hash: " << buildgithash << "\n";
189 }
190
191 amrex::Print() << "\n";
192 }
193
195
196 const std::string& pv3d = "plot_vars_3d"; set3DPlotVariables(pv3d);
197 const std::string& pv2d = "plot_vars_2d"; set2DPlotVariables(pv2d);
198
200
201 int nlevs_max = max_level + 1;
202
203 istep.resize(nlevs_max, 0);
204 nsubsteps.resize(nlevs_max, 1);
205 for (int lev = 1; lev <= max_level; ++lev) {
207 }
208
209 physbcs.resize(nlevs_max);
210
211 t_new.resize(nlevs_max, zero);
214
215 cons_new.resize(nlevs_max);
216 cons_old.resize(nlevs_max);
217 xvel_new.resize(nlevs_max);
218 xvel_old.resize(nlevs_max);
219 yvel_new.resize(nlevs_max);
220 yvel_old.resize(nlevs_max);
221 zvel_new.resize(nlevs_max);
222 zvel_old.resize(nlevs_max);
223
224 advflux_reg.resize(nlevs_max);
225
227
228 for (int lev = 0; lev < max_level; ++lev)
229 {
230 amrex::Print() << "Refinement ratio at level " << lev << " set to be " <<
231 ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
232
233 if (ref_ratio[lev][2] != 1)
234 {
235 amrex::Print() << "********************************************************************************" << std::endl;
236 amrex::Print() << "We don't allow refinement in the vertical -- make sure to set ref_ratio = 1 in z" << std::endl;
237 amrex::Print() << "It's possible you set amr.ref_ratio when you meant to set amr.ref_ratio_vect " << std::endl;
238 amrex::Print() << "********************************************************************************" << std::endl;
239 amrex::Abort();
240 }
241 }
242}
243
245{
246}
247
248void
250{
251 cons_names.clear();
252 cons_names.reserve(ncons);
253 cons_names.emplace_back("temp");
254 cons_names.emplace_back("salt");
255
256 // Passive (dye) scalars come first, then the biology block, matching the component
257 // layout: temp, salt, tracer, tracer_1, ..., NO3, NH4, ...
258 if (nscalar > 0) {
259 cons_names.emplace_back("tracer");
260 for (int i = 1; i < nscalar; ++i) {
261 cons_names.emplace_back("tracer_" + std::to_string(i));
262 }
263 }
264
267 for (const auto& name : bio_names) {
268 cons_names.emplace_back(name);
269 }
270 }
271
272 AMREX_ALWAYS_ASSERT(static_cast<int>(cons_names.size()) == ncons);
273}
274
275void
277{
278 BL_PROFILE_VAR("REMORA::Evolve()",evolve);
279 Real cur_time = t_new[0];
280
281 // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
282 // for finer levels (with or without subcycling)
283 for (int step = istep[0]; step < max_step && cur_time < stop_time; ++step)
284 {
285 amrex::Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
286
287 ComputeDt();
288
289 int lev = 0;
290 int iteration = 1;
291 auto dEvolveTime0 = amrex::second();
292
293 if (max_level == 0) {
295 }
296 else {
298 }
299
300 cur_time += dt[0];
301
302 amrex::Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
303 << " DT = " << dt[0] << std::endl;
304
305 if (verbose > 0)
306 {
307 auto dEvolveTime = amrex::second() - dEvolveTime0;
308 ParallelDescriptor::ReduceRealMax(dEvolveTime,ParallelDescriptor::IOProcessorNumber());
309 amrex::Print() << "Timestep time = " << dEvolveTime << " seconds." << '\n';
310 }
311
313
315
316#ifdef AMREX_MEM_PROFILING
317 {
318 std::ostringstream ss;
319 ss << "[STEP " << step+1 << "]";
320 MemProfiler::report(ss.str());
321 }
322#endif
323
324 if (cur_time >= stop_time - 1.e-6*dt[0]) break;
325 }
326
328
330}
331
332void
334{
335
336 if ( (plot_int > 0 || plot_int_time > zero) && istep[0] > last_plot_file_step)
337 {
340 }
341
342 if ((check_int > 0 || check_int_time > zero) && istep[0] > last_check_file_step) {
344 }
345}
346
347void
366
367/**
368 * @param[in ] nstep which step we're on
369 * @param[in ] time current time
370 * @param[in ] dt_lev0 time step on level 0
371 */
372void
374{
375 BL_PROFILE("REMORA::post_timestep()");
376
377#ifdef REMORA_USE_PARTICLES
378 particleData.Redistribute();
379#endif
380
382 {
383 for (int lev = finest_level-1; lev >= 0; lev--)
384 {
385 // This call refluxes from the lev/lev+1 interface onto lev
386 //getAdvFluxReg(lev+1)->Reflux(*cons_new[lev], 0, 0, NCONS);
387
388 // We need to do this before anything else because refluxing changes the
389 // values of coarse cells underneath fine grids with the assumption they'll
390 // be over-written by averaging down
391 //
393 }
394 }
395
398 }
399}
400
401/**
402 * This is called from main.cpp and handles all initialization, whether from start or restart
403 */
404void
406{
407 BL_PROFILE("REMORA::InitData()");
409 amrex::Print() << "REMORA InitData: driver-managed atm2ocn coupling enabled"
410 << " two_way=" << (driver_uses_two_way_coupling ? 1 : 0)
411 << " active_contract="
413 << "\n";
414 }
415 // Initialize the start time for our CPU-time tracker
416 startCPUTime = Real(ParallelDescriptor::second());
417
418 // Map the words in the inputs file to BC types, then translate
419 // those types into what they mean for each variable
420 init_bcs();
421
422 // Init vertical stretching coeffs
424
429
430 if (restart_chkfile == "") {
431 // start simulation from the beginning
432
434
436 AverageDown();
437 }
438
439 } else { // Restart from a checkpoint
440
441 restart();
442
443 }
444#ifdef REMORA_USE_MOAB
445 InitMOABMesh();
446#endif
447 // Initialize flux registers (whether we start from scratch or restart)
449 advflux_reg[0] = nullptr;
450 for (int lev = 1; lev <= finest_level; lev++)
451 {
453 dmap[lev], dmap[lev-1],
454 geom[lev], geom[lev-1],
455 ref_ratio[lev-1], lev, ncons));
456 }
457 }
458
459 // Fill ghost cells/faces
460 for (int lev = 0; lev <= finest_level; ++lev)
461 {
462 if (lev > 0 && cf_width >= 0) {
464 }
465
466 if (restart_chkfile == "") {
468 FillPatch(lev, t_new[lev], *xvel_new[lev], xvel_new, xvel_bc(), BdyVars::u, 0, true, false,0,0,zero,*xvel_new[lev]);
469 FillPatch(lev, t_new[lev], *yvel_new[lev], yvel_new, yvel_bc(), BdyVars::v, 0, true, false,0,0,zero,*yvel_new[lev]);
470 FillPatch(lev, t_new[lev], *zvel_new[lev], zvel_new, zvel_bc(), BdyVars::null, 0, true, false);
471
472 // Copy from new into old just in case when initializing from scratch
473 int ngs = cons_new[lev]->nGrow();
474 int ngvel = xvel_new[lev]->nGrow();
475 MultiFab::Copy(*cons_old[lev],*cons_new[lev],0,0,ncons,ngs);
476 MultiFab::Copy(*xvel_old[lev],*xvel_new[lev],0,0,1,ngvel);
477 MultiFab::Copy(*yvel_old[lev],*yvel_new[lev],0,0,1,ngvel);
478 MultiFab::Copy(*zvel_old[lev],*zvel_new[lev],0,0,1,IntVect(ngvel,ngvel,0));
479 }
480 } // lev
481
482 // Check for additional plotting variables that are available after
483 // particle containers are setup.
484 const std::string& pv3d = "plot_vars_3d"; append3DPlotVariables(pv3d);
485 const std::string& pv2d = "plot_vars_2d"; append2DPlotVariables(pv2d);
486
487 if (restart_chkfile == "" && (check_int > 0 || check_int_time > zero))
488 {
491 }
492
493 // plot_file_on_restart currently always 1
494 if ( (restart_chkfile == "") ||
496 {
497 if (plot_int > 0 || plot_int_time > zero)
498 {
499 int step0 = 0;
503 }
504 }
505
508 }
509
510 // dt is read from checkpoint on restart so it only needs to be computed if
511 // not restarting
512 if (restart_chkfile == "") {
513 ComputeDt();
514 }
515
516}
517
518/**
519 * @param[in ] lev level to operate on
520 */
521void
523{
524 BL_PROFILE("REMORA::Construct_REMORAFillPatchers()");
525 amrex::Print() << ":::Construct_REMORAFillPatchers " << lev << std::endl;
526
527 auto& ba_fine = cons_new[lev ]->boxArray();
528 auto& ba_crse = cons_new[lev-1]->boxArray();
529 auto& dm_fine = cons_new[lev ]->DistributionMap();
530 auto& dm_crse = cons_new[lev-1]->DistributionMap();
531
532 BoxList bl2d_fine = ba_fine.boxList();
533 for (auto& b : bl2d_fine) {
534 b.setRange(2,0);
535 }
536 BoxArray ba2d_fine(std::move(bl2d_fine));
537
538 BoxList bl2d_crse = ba_crse.boxList();
539 for (auto& b : bl2d_crse) {
540 b.setRange(2,0);
541 }
542 BoxArray ba2d_crse(std::move(bl2d_crse));
543
544 int ncomp = cons_new[lev]->nComp();
545
546 FPr_c.emplace_back(ba_fine, dm_fine, geom[lev] ,
547 ba_crse, dm_crse, geom[lev-1],
549 FPr_u.emplace_back(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
550 convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
552 FPr_v.emplace_back(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
553 convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
555 FPr_w.emplace_back(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
556 convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
558
559 FPr_ubar.emplace_back(convert(ba2d_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
560 convert(ba2d_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
562 FPr_vbar.emplace_back(convert(ba2d_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
563 convert(ba2d_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
565}
566
567/**
568 * @param[in ] lev level to operate on
569 */
570void
572{
573 BL_PROFILE("REMORA::Define_REMORAFillPatchers()");
574 amrex::Print() << ":::Define_REMORAFillPatchers " << lev << std::endl;
575
576 auto& ba_fine = cons_new[lev ]->boxArray();
577 auto& ba_crse = cons_new[lev-1]->boxArray();
578 auto& dm_fine = cons_new[lev ]->DistributionMap();
579 auto& dm_crse = cons_new[lev-1]->DistributionMap();
580
581 BoxList bl2d_fine = ba_fine.boxList();
582 for (auto& b : bl2d_fine) {
583 b.setRange(2,0);
584 }
585 BoxArray ba2d_fine(std::move(bl2d_fine));
586
587 BoxList bl2d_crse = ba_crse.boxList();
588 for (auto& b : bl2d_crse) {
589 b.setRange(2,0);
590 }
591 BoxArray ba2d_crse(std::move(bl2d_crse));
592
593
594 int ncomp = cons_new[lev]->nComp();
595
596 FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
597 ba_crse, dm_crse, geom[lev-1],
599 FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
600 convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
602 FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
603 convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
605 FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
606 convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
608
609 FPr_ubar[lev-1].Define(convert(ba2d_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
610 convert(ba2d_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
612 FPr_vbar[lev-1].Define(convert(ba2d_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
613 convert(ba2d_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
615}
616
617void
619{
620 BL_PROFILE("REMORA::restart()");
622
623 // We set this here so that we don't over-write the checkpoint file we just started from
625 // last_plot_file_step will be updated when plotfile is unconditionally written after restart
626
629}
630
631/**
632 * @param[in ] lev level to operate on
633 */
634void
636{
637 BL_PROFILE("REMORA::set_zeta()");
638 if (lev==0) {
639 if (hires_init_level < 0) {
641 prob->init_analytic_zeta(lev, geom[lev], solverChoice, *this, *vec_zeta[lev]);
642 } else if (solverChoice.ic_type == IC_Type::netcdf) {
643#ifdef REMORA_USE_NETCDF
644 amrex::Print() << "Calling init_zeta_from_netcdf on level " << lev << std::endl;
646 amrex::Print() << "Sea surface height loaded from netcdf file \n " << std::endl;
647#endif
648 } else {
649 amrex::Abort("Unknown IC_Type");
650 }
651 } else {
653 }
654 vec_zeta[lev]->FillBoundary(geom[lev].periodicity());
655 } else {
656 // If our level is higher than the high resolution grid or initialization
657 // is analytic, interpolate from level below. Otherwise, copy over the bathymetry
658 // data that has been averaged down
659 if (lev > hires_init_level) {
660 Real dummy_time = zero;
662 } else {
664 vec_zeta[lev]->FillBoundary(geom[lev].periodicity());
665 }
666 }
668}
669
670/**
671 * @param[in ] lev level to operate on
672 */
673void
675{
676 BL_PROFILE("REMORA::bathymetry()");
677 // Only set bathymetry on level 0, and interpolate for finer levels
678 if (lev==0) {
679 // If grid data is not defined on a level > 0 (negative level) then
680 // initialize from low-resolution grid normally. Otherwise use high-resolution
681 // grid data averaged down to level 0
682 if (hires_grid_level < 0) {
684 prob->init_analytic_bathymetry(lev, geom[lev], solverChoice, *this, *vec_h[lev]);
685 } else if (solverChoice.ic_type == IC_Type::netcdf) {
686#ifdef REMORA_USE_NETCDF
687 amrex::Print() << "Calling init_bathymetry_from_netcdf " << std::endl;
689 amrex::Print() << "Bathymetry loaded from netcdf file \n " << std::endl;
690 amrex::Print() << "Calling init_grid_vars_from_netcdf " << std::endl;
692 amrex::Print() << "Grid variables loaded from netcdf file \n " << std::endl;
693#endif
694 } else {
695 amrex::Abort("Unknown IC_Type");
696 }
697 } else {
699 // Only the netcdf path fills vec_pm/pn_full_domain; with analytic initialization
700 // init_bathymetry_full_domain_from_analytic fills h alone, and set_grid_scale
701 // below derives pm/pn from the geometry.
704 }
705 }
706 // Need FillBoundary to fill at grid-grid boundaries, and EnforcePeriodicity
707 // to make sure ghost cells in the domain corners are consistent.
708 vec_h[lev]->FillBoundary(geom[lev].periodicity());
709 vec_h[lev]->EnforcePeriodicity(geom[lev].periodicity());
710 } else {
711 // If our level is higher than the high resolution grid or initialization
712 // is analytic, interpolate from level below. Otherwise, copy over the bathymetry
713 // data that has been averaged down
714 if (lev > hires_grid_level) {
715 Real dummy_time = zero;
720 } else {
722 vec_h[lev]->FillBoundary(geom[lev].periodicity());
723 vec_h[lev]->EnforcePeriodicity(geom[lev].periodicity());
724 }
725 }
727}
728
729/**
730 * @param[in ] lev level to operate on
731 */
732void
734 Real dummy_time = zero;
735 // Note: don't understand why the grow vector args aren't vec_h and then vec_h_full_domain
740 BdyVars::null,0,false,false,1);
743 BdyVars::null,1,false,false,1);
744}
745
746/**
747 * @param[in ] lev level to operate on
748 */
749void
763
764/**
765 * @param[in ] lev level to operate on
766 */
767void
774
775/**
776 * @param[in ] lev level to operate on
777 */
778void
791
792/**
793 * @param[in ] lev level to operate on
794 */
795void
797 BL_PROFILE("REMORA::set_coriolis()");
800 prob->init_analytic_coriolis(lev, geom[lev], solverChoice, *this, *vec_fcor[lev]);
803#ifdef REMORA_USE_NETCDF
805 if (lev == 0) {
806 amrex::Print() << "Calling init_coriolis_from_netcdf " << std::endl;
808 amrex::Print() << "Coriolis loaded from netcdf file \n" << std::endl;
809 } else {
810 Real dummy_time = zero;
812 }
813#endif
814 } else {
815 Abort("Don't know this coriolis_type!");
816 }
817
818 Real time = zero;
820 vec_fcor[lev]->EnforcePeriodicity(geom[lev].periodicity());
821 }
822}
823
824void
826 BL_PROFILE("REMORA::init_set_vmix()");
831 // The GLS initialization just sets the multifab to a value, so there's
832 // no need to call FillPatch here
833 } else {
834 Abort("Don't know this vertical mixing type");
835 }
836}
837
838/**
839 * @param[in ] lev level to operate on
840 */
841void
843 BL_PROFILE("REMORA::set_analytic_vmix()");
844 Real time = zero;
846 for (int n = 0; n < NAT; n++) {
847 vec_Akt[lev]->setVal(solverChoice.Akt_bak[n], n, 1);
848 }
849 prob->init_analytic_vmix(lev, geom[lev], solverChoice, *this,*vec_Akv[lev], *vec_Akt[lev]);
851 for (int n = 0; n < NAT; n++) {
853 }
854}
855
856/**
857 * @param[in ] lev level to operate on
858 */
859void
861{
863 prob->init_analytic_masks(lev,geom[lev], solverChoice, *this, *vec_mskr[lev]);
866#ifdef REMORA_USE_NETCDF
867 if (lev == 0) {
868 amrex::Print() << "Calling init_masks_from_netcdf level " << lev << std::endl;
870 amrex::Print() << "Masks loaded from netcdf file \n " << std::endl;
871 } else {
872 Real dummy_time = zero;
874 foextrap_bc());
876 }
877#endif
878 }
880}
881
882/**
883 * @param[in ] lev level to operate on
884 */
885void
887{
888 BL_PROFILE("REMORA::set_hmixcoef()");
889
890 // Optional AMR scaling: decrease coefficients on refined levels linearly
891 // with grid size (i.e., proportional to sqrt(cell area)). For a horizontal
892 // refinement ratio rx x ry, the effective scale factor is 1/sqrt(rx*ry).
893 Real lev_scale = one;
895 Real rf = one;
896 for (int l = 0; l < lev; ++l) {
897 rf *= std::sqrt(static_cast<Real>(ref_ratio[l][0]) * static_cast<Real>(ref_ratio[l][1]));
898 }
899 lev_scale = one / rf;
900 }
901
903 prob->init_analytic_hmix(lev, geom[lev], solverChoice,
904 *this, *vec_visc2_p[lev], *vec_visc2_r[lev], *vec_diff2[lev]);
905
909 for (int n = 0; n < ncons; n++) {
910 vec_diff2[lev]->setVal(solverChoice.tnu2[n] * lev_scale, n, 1);
911 }
912
913 // Scale harmonic viscosity and diffusivity by the grid size as ROMS
914 // does in Utility/ini_hmixcoef.F. Intended for curvilinear grids.
915 //
916 // Define the ROMS grid factor (grdscl):
917 // G(i,j) = sqrt( 1 / (pm(i,j) * pn(i,j)) )
918 // = sqrt(cell area)
919 // Gmax = max over grid of G(i,j)
920 //
921 // Then horizontal harmonic mixing coefficients are scaled as:
922 // nu(i,j) = nu0 * G(i,j) / Gmax
923 // kappa_n(i,j) = kappa0 * G(i,j) / Gmax
924 //
925 // where:
926 // nu0 = solverChoice.visc2
927 // kappa0 = solverChoice.tnu2[n]
928 //
929 // This makes mixing strongest where grid spacing is largest.
930 //
931 // NOTE: The normalization (Gmax) is computed over the entire grid (ignoring masks).
932 // Therefore, if the largest cell area occurs over land, the maximum over *wet* cells
933 // (or in masked output files) may be smaller than the user-specified value.
934
936
937 // ------------------------------------------------------------
938 // Step 1: Compute grdmax over entire grid
939 // ------------------------------------------------------------
942 for (int n = 0; n < ncons; n++) {
943 vec_diff2[lev]->setVal(solverChoice.tnu2[n], n, 1);
944 }
945
946 // NOTE: This must be GPU-safe. Do not dereference MultiFab data on host.
947 // Force the reduction to run in the GPU launch region if GPUs are enabled.
948 // (If the launch region is disabled at runtime, ReduceMax may fall back to
949 // a host path that can try to read device-only data.)
950 amrex::Gpu::LaunchSafeGuard lsg(true);
951 Real denom_min = amrex::ReduceMin(*vec_pm[lev], *vec_pn[lev], 0,
952 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
953 Array4<Real const> const& pm,
954 Array4<Real const> const& pn) -> Real
955 {
957 amrex::Loop(bx, [=,&local_min] (int i, int j, int) noexcept
958 {
959 local_min = amrex::min(local_min, pm(i,j,0) * pn(i,j,0));
960 });
961 return local_min;
962 });
963
964 ParallelDescriptor::ReduceRealMin(denom_min);
965 if (denom_min <= zero) {
966 Abort("scaled_to_grid: found non-positive pm*pn (grid metrics must be > 0)");
967 }
968
969 Real grdmax = amrex::ReduceMax(*vec_pm[lev], *vec_pn[lev], 0,
970 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
971 Array4<Real const> const& pm,
972 Array4<Real const> const& pn) -> Real
973 {
974 Real local_max = zero;
975 amrex::Loop(bx, [=,&local_max] (int i, int j, int) noexcept
976 {
977 Real denom = pm(i,j,0) * pn(i,j,0);
978 if (denom > zero) {
979 Real G = std::sqrt(one / denom);
980 local_max = amrex::max(local_max, G);
981 }
982 });
983 return local_max;
984 });
985
986 ParallelDescriptor::ReduceRealMax(grdmax);
987 if (grdmax <= zero) {
988 Abort("scaled_to_grid: grdmax <= 0");
989 }
990
991 // Optional AMR scaling: decrease coefficients on refined levels linearly
992 // with grid size (i.e., proportional to sqrt(cell area)). For a horizontal
993 // refinement ratio rx x ry, the effective scale factor is 1/sqrt(rx*ry).
994 lev_scale = one;
996 Real rf = one;
997 for (int l = 0; l < lev; ++l) {
998 rf *= std::sqrt(static_cast<Real>(ref_ratio[l][0]) * static_cast<Real>(ref_ratio[l][1]));
999 }
1000 lev_scale = one / rf;
1001 }
1002
1004 Real cff = visc0 / grdmax;
1005
1006 // ------------------------------------------------------------
1007 // Step 2: Set rho coefficients everywhere
1008 // ------------------------------------------------------------
1009 amrex::Gpu::DeviceVector<Real> diff0_d(ncons);
1010 amrex::Gpu::copy(amrex::Gpu::hostToDevice,
1011 solverChoice.tnu2.begin(), solverChoice.tnu2.begin() + ncons,
1012 diff0_d.begin());
1013 Real const* diff0_ptr = diff0_d.data();
1014
1015 for (MFIter mfi(*vec_visc2_r[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1016 {
1017 const Box& bx = mfi.validbox();
1018 auto pm = vec_pm[lev]->const_array(mfi);
1019 auto pn = vec_pn[lev]->const_array(mfi);
1020 auto visc2_r = vec_visc2_r[lev]->array(mfi);
1021 auto diff2 = vec_diff2[lev]->array(mfi);
1022
1023 int ncons_local = ncons;
1024 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
1025 {
1026 Real denom = pm(i,j,0) * pn(i,j,0);
1027 Real grdscl = (denom > zero) ? std::sqrt(one / denom) : zero;
1028 visc2_r(i,j,0) = cff * grdscl;
1029
1030 for (int n = 0; n < ncons_local; n++) {
1031 diff2(i,j,0,n) = ((diff0_ptr[n] * lev_scale) / grdmax) * grdscl;
1032 }
1033 });
1034 }
1035
1036 // Fill ghost cells for rho coefficients BEFORE psi averaging
1037 Real time = zero;
1039
1040 // ------------------------------------------------------------
1041 // Step 3: Psi coefficients = average of 4 surrounding rho
1042 // ------------------------------------------------------------
1043 for (MFIter mfi(*vec_visc2_p[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
1044 {
1045 const Box& bx = mfi.validbox();
1046 auto visc2_p = vec_visc2_p[lev]->array(mfi);
1047 auto visc2_r = vec_visc2_r[lev]->const_array(mfi);
1048
1049 ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
1050 {
1051 visc2_p(i,j,0) = fourth * (
1052 visc2_r(i-1,j-1,0) +
1053 visc2_r(i ,j-1,0) +
1054 visc2_r(i-1,j ,0) +
1055 visc2_r(i ,j ,0)
1056 );
1057 });
1058 }
1059
1061
1062 // Diagnostics
1063 // NOTE: coefficients are computed everywhere (including land). Output routines may later
1064 // mask land points (e.g., to FillValue in NetCDF/plotfiles), and analysis tools may
1065 // additionally apply mask_rho (setting land to 0). Report both conventions.
1066 //
1067 // Global (MPI-reduced) extrema over all valid cells (no ghost).
1068 Real visc_min_all = vec_visc2_r[lev]->min(0,0,false);
1069 Real visc_max_all = vec_visc2_r[lev]->max(0,0,false);
1070
1071 // Global extrema over *wet* rho points only, k=0.
1072 amrex::Gpu::LaunchSafeGuard lsg_diag(true);
1073 Real visc_min_wet = amrex::ReduceMin(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1074 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1075 Array4<Real const> const& visc2,
1076 Array4<Real const> const& mskr) -> Real
1077 {
1079 amrex::Loop(bx, [=,&local_min] (int i, int j, int) noexcept
1080 {
1081 if (mskr(i,j,0) > zero) {
1082 local_min = amrex::min(local_min, visc2(i,j,0));
1083 }
1084 });
1085 return local_min;
1086 });
1087 ParallelDescriptor::ReduceRealMin(visc_min_wet);
1088
1089 Real visc_max_wet = amrex::ReduceMax(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1090 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1091 Array4<Real const> const& visc2,
1092 Array4<Real const> const& mskr) -> Real
1093 {
1095 amrex::Loop(bx, [=,&local_max] (int i, int j, int) noexcept
1096 {
1097 if (mskr(i,j,0) > zero) {
1098 local_max = amrex::max(local_max, visc2(i,j,0));
1099 }
1100 });
1101 return local_max;
1102 });
1103 ParallelDescriptor::ReduceRealMax(visc_max_wet);
1104
1105 // Mimic "apply mask_rho" convention (dry -> 0).
1106 Real visc_min_mask0 = amrex::ReduceMin(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1107 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1108 Array4<Real const> const& visc2,
1109 Array4<Real const> const& mskr) -> Real
1110 {
1112 amrex::Loop(bx, [=,&local_min] (int i, int j, int) noexcept
1113 {
1114 const Real v = (mskr(i,j,0) > zero) ? visc2(i,j,0) : zero;
1115 local_min = amrex::min(local_min, v);
1116 });
1117 return local_min;
1118 });
1119 ParallelDescriptor::ReduceRealMin(visc_min_mask0);
1120
1121 Real visc_max_mask0 = amrex::ReduceMax(*vec_visc2_r[lev], *vec_mskr[lev], 0,
1122 [=] AMREX_GPU_HOST_DEVICE (Box const& bx,
1123 Array4<Real const> const& visc2,
1124 Array4<Real const> const& mskr) -> Real
1125 {
1127 amrex::Loop(bx, [=,&local_max] (int i, int j, int) noexcept
1128 {
1129 const Real v = (mskr(i,j,0) > zero) ? visc2(i,j,0) : zero;
1130 local_max = amrex::max(local_max, v);
1131 });
1132 return local_max;
1133 });
1134 ParallelDescriptor::ReduceRealMax(visc_max_mask0);
1135 if (ParallelDescriptor::IOProcessor() && lev == 0)
1136 {
1137 Print() << "\nHorizontal mixing scaled by grid metric\n";
1138 Print() << "grdmax = " << grdmax << "\n";
1140 Print() << "AMR scaling (linear) lev_scale = " << lev_scale << "\n";
1141 }
1142 Print() << "visc2(all) min/max = "
1143 << visc_min_all << " / "
1144 << visc_max_all << "\n";
1145 Print() << "visc2(wet,k=0) min/max = "
1146 << visc_min_wet << " / "
1147 << visc_max_wet << "\n";
1148 Print() << "visc2(mask->0) min/max = "
1149 << visc_min_mask0 << " / "
1150 << visc_max_mask0 << "\n";
1151 }
1152
1153 } else {
1154 Abort("Don't know this horizontal mixing type");
1155 }
1156
1157 // Final FillPatch for all fields
1158 Real time = zero;
1161 for (int n = 0; n < ncons; n++) {
1163 foextrap_periodic_bc(), BdyVars::null, n, false);
1164 }
1165}
1166
1167/**
1168 * @param[in ] lev level to operate on
1169 */
1170void
1172{
1173 BL_PROFILE("REMORA::set_smflux()");
1175 prob->init_analytic_smflux(lev, geom[lev], solverChoice, *this,*vec_sustr[lev], *vec_svstr[lev]);
1177#ifdef REMORA_USE_NETCDF
1178 sustr_data_from_file->update_interpolated_to_time(t_old[lev], lev, vec_sustr[lev].get(), geom, ref_ratio);
1179 svstr_data_from_file->update_interpolated_to_time(t_old[lev], lev, vec_svstr[lev].get(), geom, ref_ratio);
1182#endif
1183 }
1184}
1185
1186/**
1187 * @param[in ] lev level to operate on
1188 */
1189void
1191{
1192 BL_PROFILE("REMORA::set_surface_state()");
1193
1194 auto& bulk_flux_type = solverChoice.bulk_flux_type;
1195
1196 // Every update below skips driver-supplied lanes individually, on
1197 // !driver_atmos_state_from_driver[...]. This used to abort outright if any
1198 // lane was driver-supplied, which made the function unreachable in a coupled
1199 // run and so denied the *withheld* lanes the fallback those guards provide.
1200
1201#ifdef REMORA_USE_NETCDF
1202 auto update_from_netcdf = [&](std::unique_ptr<NCTimeSeries>& data_from_file,
1204 data_from_file->update_interpolated_to_time(t_old[lev], lev, mf_vec[lev].get(), geom, ref_ratio);
1206 foextrap_periodic_bc(), BdyVars::null, 0, false);
1207 };
1208
1211 }
1214 }
1215
1218 }
1222 vec_qair[lev]->mult(amrex::Real(0.01));
1223 }
1224 }
1227 }
1230 }
1233 }
1236 }
1239 }
1240 if (bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::netcdf) {
1242 }
1243#else
1244 for (int idx = 0; idx < BulkFlux::NumTypes; ++idx) {
1245 if (bulk_flux_type[idx] == BulkForcingType::netcdf) {
1246 amrex::Abort("NetCDF bulk-flux forcing requires building with NetCDF");
1247 }
1248 }
1249#endif
1250
1251 MultiFab* analytic_uwind = (bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::analytic &&
1253 MultiFab* analytic_vwind = (bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::analytic &&
1255 MultiFab* analytic_Tair = (bulk_flux_type[BulkFlux::Tair] == BulkForcingType::analytic &&
1257 MultiFab* analytic_qair = (bulk_flux_type[BulkFlux::Qair] == BulkForcingType::analytic &&
1259 MultiFab* analytic_Pair = (bulk_flux_type[BulkFlux::Pair] == BulkForcingType::analytic &&
1261 MultiFab* analytic_srflx = (bulk_flux_type[BulkFlux::SWrad] == BulkForcingType::analytic &&
1263 MultiFab* analytic_lwrad = (bulk_flux_type[BulkFlux::LWrad] == BulkForcingType::analytic &&
1265 MultiFab* analytic_rain = (bulk_flux_type[BulkFlux::Rain] == BulkForcingType::analytic &&
1267 MultiFab* analytic_cloud = (bulk_flux_type[BulkFlux::Cloud] == BulkForcingType::analytic &&
1269 MultiFab* analytic_EminusP = bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::analytic ? vec_EminusP[lev].get() : nullptr;
1270
1271 if (analytic_uwind != nullptr || analytic_vwind != nullptr ||
1272 analytic_Tair != nullptr || analytic_qair != nullptr || analytic_Pair != nullptr ||
1273 analytic_srflx != nullptr || analytic_lwrad != nullptr || analytic_rain != nullptr ||
1274 analytic_cloud != nullptr || analytic_EminusP != nullptr) {
1275 // Every field has to be passed to init_analytic_surface_var, but only the
1276 // analytic ones may be modified: the others hold constant or NetCDF data that is
1277 // set once at level creation or interpolated just above. Hand the non-analytic
1278 // slots scratch data that is thrown away on return, so the problem code can write
1279 // to all ten references unconditionally without clobbering anything.
1281 auto analytic_or_scratch = [&] (MultiFab* mf_analytic,
1282 const std::unique_ptr<MultiFab>& mf_lev) -> MultiFab&
1283 {
1284 if (mf_analytic != nullptr) { return *mf_analytic; }
1285 scratch_mf.emplace_back(new MultiFab(mf_lev->boxArray(), mf_lev->DistributionMap(),
1286 mf_lev->nComp(), mf_lev->nGrowVect()));
1287 return *scratch_mf.back();
1288 };
1289
1290 prob->init_analytic_surface_var(lev, geom[lev], solverChoice, *this,
1301 }
1302
1303 if (vec_uwind[lev] != nullptr) { vec_uwind[lev]->FillBoundary(geom[lev].periodicity()); }
1304 if (vec_vwind[lev] != nullptr) { vec_vwind[lev]->FillBoundary(geom[lev].periodicity()); }
1305 if (vec_Tair[lev] != nullptr) { vec_Tair[lev]->FillBoundary(geom[lev].periodicity()); }
1306 if (vec_qair[lev] != nullptr) { vec_qair[lev]->FillBoundary(geom[lev].periodicity()); }
1307 if (vec_Pair[lev] != nullptr) { vec_Pair[lev]->FillBoundary(geom[lev].periodicity()); }
1308 if (vec_srflx[lev] != nullptr) { vec_srflx[lev]->FillBoundary(geom[lev].periodicity()); }
1309 if (vec_longwave_down[lev] != nullptr) { vec_longwave_down[lev]->FillBoundary(geom[lev].periodicity()); }
1310 if (vec_rain[lev] != nullptr) { vec_rain[lev]->FillBoundary(geom[lev].periodicity()); }
1311 if (vec_cloud[lev] != nullptr) { vec_cloud[lev]->FillBoundary(geom[lev].periodicity()); }
1312 if (vec_EminusP[lev] != nullptr) { vec_EminusP[lev]->FillBoundary(geom[lev].periodicity()); }
1313}
1314
1315/**
1316 * @param[in ] lev level to operate on
1317 * @param[in ] time current time for initialization
1318 */
1319void
1321{
1322 BL_PROFILE("REMORA::init_only()");
1323 t_new[lev] = time;
1325
1326 cons_new[lev]->setVal(zero);
1327 xvel_new[lev]->setVal(zero);
1328 yvel_new[lev]->setVal(zero);
1329 zvel_new[lev]->setVal(zero);
1330
1331 xvel_old[lev]->setVal(zero);
1332 yvel_old[lev]->setVal(zero);
1333 zvel_old[lev]->setVal(zero);
1334
1335 vec_ru[lev]->setVal(zero);
1336 vec_rv[lev]->setVal(zero);
1337
1338 vec_ru2d[lev]->setVal(zero);
1339 vec_rv2d[lev]->setVal(zero);
1340
1343 }
1344 set_masks(lev);
1345
1346#ifdef REMORA_USE_NETCDF
1349
1350 if (solverChoice.do_any_clim_nudg && lev == 0) {
1351 if (nc_clim_his_file.empty() || nc_clim_his_file[0].empty()) {
1352 amrex::Error("NetCDF climatology file name must be provided via input");
1353 }
1356 clim_ubar_time_varname, geom[lev].Domain(),vec_ubar[lev].get(),true,true));
1358 clim_ubar_time_varname, geom[lev].Domain(),vec_vbar[lev].get(),true,true));
1359 ubar_clim_data_from_file->Initialize();
1360 vbar_clim_data_from_file->Initialize();
1361 }
1365 u_clim_data_from_file->Initialize();
1366 v_clim_data_from_file->Initialize();
1367 }
1368 // Since the NCTimeSeries object isn't filling the cons_new MultiFab directly, we don't have to specify a component.
1369 // It just needs to know the shape of the MultiFab
1371 for (int icomp = 0; icomp < ncons; ++icomp) {
1372 if (!solverChoice.do_cons_clim_nudg[icomp]) { continue; }
1373 // A tracer's climatology is stored in the file under the tracer's own
1374 // name, following the same convention ROMS uses. Check up front rather
1375 // than letting the read fail deep inside NCTimeSeries.
1376 for (const auto& fname : nc_clim_his_file) {
1378 amrex::Abort("Climatology file " + fname + " does not contain '" +
1379 cons_names[icomp] + "', which is required by remora.do_" +
1380 cons_names[icomp] + "_clim_nudg. Either add it to the file "
1381 "or turn that flag off.");
1382 }
1383 }
1386 cons_clim_data_from_file[icomp]->Initialize();
1387 }
1388 }
1389 }
1390
1392 amrex::Print() << "Calling init_bdry_from_netcdf at level " << lev << std::endl;
1394 amrex::Print() << "Boundary data loaded from netcdf file \n " << std::endl;
1395 }
1396
1397 // This will be a non-op if forcings specified analytically
1399 if (lev==0) {
1400 if (nc_frc_file.empty() || nc_frc_file[0].empty()) {
1401 amrex::Error("NetCDF forcing file name must be provided via input for surface momentum fluxes");
1402 }
1403 sustr_data_from_file.reset(new NCTimeSeries(nc_frc_file, "sustr", frc_time_varname, geom[lev].Domain(),vec_sustr[lev].get(), true, false));
1404 svstr_data_from_file.reset(new NCTimeSeries(nc_frc_file, "svstr", frc_time_varname, geom[lev].Domain(),vec_svstr[lev].get(), true, false));
1405 sustr_data_from_file->Initialize();
1406 svstr_data_from_file->Initialize();
1407 } else {
1410 }
1411 }
1412
1413 // Conditionally load atmospheric forcing fields from NetCDF based on source type.
1414 const auto& bulk_flux_type = solverChoice.bulk_flux_type;
1415 bool any_bulk_netcdf = false;
1416 for (int idx = 0; idx < BulkFlux::NumTypes; ++idx) {
1418 }
1419 if (lev == 0 && any_bulk_netcdf && (nc_frc_file.empty() || nc_frc_file[0].empty())) {
1420 amrex::Error("NetCDF forcing file name must be provided via input for bulk-flux atmospheric forcing");
1421 }
1422
1423 if (lev==0) {
1424 if (bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::netcdf) {
1425 Uwind_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Uwind", frc_time_varname, geom[lev].Domain(),vec_uwind[lev].get(), true, false));
1426 Uwind_data_from_file->Initialize();
1427 }
1428 if (bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::netcdf) {
1429 Vwind_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Vwind", frc_time_varname, geom[lev].Domain(),vec_vwind[lev].get(), true, false));
1430 Vwind_data_from_file->Initialize();
1431 }
1432 if (bulk_flux_type[BulkFlux::Tair] == BulkForcingType::netcdf) {
1433 Tair_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Tair", frc_time_varname, geom[lev].Domain(),vec_Tair[lev].get(), true, false));
1434 Tair_data_from_file->Initialize();
1435 }
1436 if (bulk_flux_type[BulkFlux::Qair] == BulkForcingType::netcdf) {
1437 qair_data_from_file.reset(new NCTimeSeries(nc_frc_file, "qair", frc_time_varname, geom[lev].Domain(),vec_qair[lev].get(), true, false));
1438 qair_data_from_file->Initialize();
1439 }
1440 if (bulk_flux_type[BulkFlux::Pair] == BulkForcingType::netcdf) {
1441 Pair_data_from_file.reset(new NCTimeSeries(nc_frc_file, "Pair", frc_time_varname, geom[lev].Domain(),vec_Pair[lev].get(), true, false));
1442 Pair_data_from_file->Initialize();
1443 }
1444 if (bulk_flux_type[BulkFlux::SWrad] == BulkForcingType::netcdf) {
1445 srflx_data_from_file.reset(new NCTimeSeries(nc_frc_file, "swrad", frc_time_varname, geom[lev].Domain(),vec_srflx[lev].get(), true, false));
1446 srflx_data_from_file->Initialize();
1447 }
1448 if (bulk_flux_type[BulkFlux::Rain] == BulkForcingType::netcdf) {
1449 rain_data_from_file.reset(new NCTimeSeries(nc_frc_file, "rain", frc_time_varname, geom[lev].Domain(),vec_rain[lev].get(), true, false));
1450 rain_data_from_file->Initialize();
1451 }
1452 if (bulk_flux_type[BulkFlux::Cloud] == BulkForcingType::netcdf) {
1453 cloud_data_from_file.reset(new NCTimeSeries(nc_frc_file, "cloud", frc_time_varname, geom[lev].Domain(),vec_cloud[lev].get(), true, false));
1454 cloud_data_from_file->Initialize();
1455 }
1456 if (bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::netcdf) {
1457 EminusP_data_from_file.reset(new NCTimeSeries(nc_frc_file, "EminusP", frc_time_varname, geom[lev].Domain(),vec_EminusP[lev].get(), true, false));
1458 EminusP_data_from_file->Initialize();
1459 }
1460 if (bulk_flux_type[BulkFlux::LWrad] == BulkForcingType::netcdf) {
1462 geom[lev].Domain(), vec_longwave_down[lev].get(), true, false));
1463 longwave_down_data_from_file->Initialize();
1464 }
1465 } else {
1466 if (bulk_flux_type[BulkFlux::Uwind] == BulkForcingType::netcdf) {
1468 }
1469 if (bulk_flux_type[BulkFlux::Vwind] == BulkForcingType::netcdf) {
1471 }
1472 if (bulk_flux_type[BulkFlux::Tair] == BulkForcingType::netcdf) {
1473 FillCoarsePatch(lev, time, vec_Tair[lev].get(), vec_Tair[lev-1].get(), foextrap_bc());
1474 }
1475 if (bulk_flux_type[BulkFlux::Qair] == BulkForcingType::netcdf) {
1476 FillCoarsePatch(lev, time, vec_qair[lev].get(), vec_qair[lev-1].get(), foextrap_bc());
1477 }
1478 if (bulk_flux_type[BulkFlux::Pair] == BulkForcingType::netcdf) {
1479 FillCoarsePatch(lev, time, vec_Pair[lev].get(), vec_Pair[lev-1].get(), foextrap_bc());
1480 }
1481 if (bulk_flux_type[BulkFlux::SWrad] == BulkForcingType::netcdf) {
1483 }
1484 if (bulk_flux_type[BulkFlux::Rain] == BulkForcingType::netcdf) {
1485 FillCoarsePatch(lev, time, vec_rain[lev].get(), vec_rain[lev-1].get(), foextrap_bc());
1486 }
1487 if (bulk_flux_type[BulkFlux::Cloud] == BulkForcingType::netcdf) {
1489 }
1490 if (bulk_flux_type[BulkFlux::EminusP] == BulkForcingType::netcdf) {
1492 }
1493 if (bulk_flux_type[BulkFlux::LWrad] == BulkForcingType::netcdf) {
1495 }
1496 }
1497
1498 // Only need to read in rivers on level 0
1499 // Will need to be on higher levels eventually
1500 if (solverChoice.do_rivers) {
1501 if (nc_riv_file.empty() || nc_riv_file[0].empty()) {
1502 amrex::Error("NetCDF river file name must be provided via input for rivers");
1503 }
1504 auto dom = geom[0].Domain();
1505 int nz = dom.length(2);
1506 // Every cell-centered tracer can take river input. The field is named for the
1507 // tracer, as in ROMS: river_temp, river_salt, river_tracer, river_NO3, ...
1508 river_source_cons.resize(ncons);
1509 for (int icomp = 0; icomp < ncons; ++icomp) {
1510 if (!solverChoice.do_rivers_cons[icomp]) { continue; }
1511
1512 const std::string field = "river_" + cons_names[icomp];
1513 for (const auto& fname : nc_riv_file) {
1514 if (!QueryNetCDFHasVars(fname, {field})) {
1515 // The flag may have come from remora.do_rivers_scalar rather than the
1516 // per-tracer key, so name the tracer and the key that switches it off.
1517 amrex::Abort("River file " + fname + " does not contain '" + field +
1518 "', but river input is enabled for tracer '" +
1519 cons_names[icomp] + "'. Either add that variable to the "
1520 "file, or set remora.do_rivers_" + cons_names[icomp] +
1521 " = false.");
1522 }
1523 }
1524
1526 river_source_cons[icomp]->Initialize();
1527 }
1528 river_source_transport.reset(new NCTimeSeriesRiver(nc_riv_file, "river_transport", riv_time_varname, nz, 0, 1));
1529 river_source_transport->Initialize();
1530 river_source_transportbar.reset(new NCTimeSeriesRiver(nc_riv_file, "river_transport", riv_time_varname, nz, 1, 1));
1531 river_source_transportbar->Initialize();
1533 }
1534
1536 amrex::Print() << "Reading high resolution bathymetry and grid data" << std::endl;
1540 amrex::Print() << "Done reading in high resolution bathymetry and grid data" << std::endl;
1541 }
1543 amrex::Print() << "Reading high resolution initial data" << std::endl;
1546 // Biology source is chosen by remora.biology_ic_type, not by ic_type,
1547 // so this goes through the same dispatcher as the per-level path.
1548 // Must follow init_data_full_domain_from_netcdf: the analytic biology
1549 // profiles read temperature.
1552 amrex::Print() << "Done reading in high resolution initial data" << std::endl;
1553 }
1554#else
1556 Abort("Not compiled with NetCDF, but remora.ic_type = netcdf reads initial and grid data from file");
1557 }
1558 // No guard on hires_grid_level here: with analytic initialization it needs no NetCDF at all --
1559 // the bathymetry comes from prob->init_analytic_bathymetry evaluated at the fine level and
1560 // averaged down. hires_init_level needs no guard either: it is rejected for analytic
1561 // initialization in ReadParameters, and the netcdf case is caught just above.
1563 Abort("Not compiled with NetCDF, but selected boundary conditions require NetCDF");
1564 }
1565 if (solverChoice.do_rivers) {
1566 Abort("Not compiled with NetCDF, but using river sources requires NetCDF");
1567 }
1568#endif
1569
1573 }
1574
1578 }
1579
1581 set_zeta(lev);
1583
1586 }
1587
1588 if (lev==0) {
1589 if (hires_init_level < 0) {
1592 } else if (solverChoice.ic_type == IC_Type::netcdf) {
1593#ifdef REMORA_USE_NETCDF
1594 amrex::Print() << "Calling init_data_from_netcdf " << std::endl;
1596 bool apply_eminusp = false;
1598 amrex::Print() << "Initial data loaded from netcdf file \n " << std::endl;
1599#endif
1600 } else {
1601 amrex::Abort("Unknown IC_Type");
1602 }
1603 // Biology last, and outside the ic_type branches: its source is
1604 // chosen independently by remora.biology_ic_type, and the analytic
1605 // profiles need the physical fields already in place.
1607 } else {
1608 set_init_data_averaged_down(lev); // also sets biology data
1609 bool apply_eminusp = false;
1611 // Since set_grid_scale is usually called from init_analytic for analytic problems
1614 }
1615 }
1616 } else {
1617 if (lev > hires_init_level) {
1622 } else {
1623 set_init_data_averaged_down(lev); // also sets biology data
1624 bool apply_eminusp = false;
1627 // Since set_grid_scale is usually called from init_analytic for analytic problems
1629 }
1630 }
1631 }
1632
1633 // Ensure that the face-based data are the same on both sides of a periodic domain.
1634 // The data associated with the lower grid ID is considered the correct value.
1635 xvel_new[lev]->OverrideSync(geom[lev].periodicity());
1636 yvel_new[lev]->OverrideSync(geom[lev].periodicity());
1637 zvel_new[lev]->OverrideSync(geom[lev].periodicity());
1638
1640
1644
1645 // Previously set smflux here with OverrideSync:
1646// set_smflux(lev);
1647// prob->init_analytic_smflux(lev, geom[lev], solverChoice, *this, *vec_sustr[lev], *vec_svstr[lev]);
1648// vec_sustr[lev]->OverrideSync(geom[lev].periodicity());
1649// vec_svstr[lev]->OverrideSync(geom[lev].periodicity());
1650
1651}
1652
1653void
1655{
1656 BL_PROFILE("REMORA::ReadParameters()");
1657 {
1658 ParmParse pp; // Traditionally, max_step and stop_time do not have prefix, so allow it for now.
1659 bool noprefix_max_step = pp.queryAdd("max_step", max_step);
1660 bool noprefix_stop_time = pp.queryAdd("stop_time", stop_time);
1661 bool remora_max_step = pp.queryAdd("remora.max_step", max_step);
1662 bool remora_stop_time = pp.queryAdd("remora.stop_time", stop_time);
1664 Abort("remora.max_step and max_step are both specified. Please use only one!");
1665 }
1667 Abort("remora.stop_time and stop_time are both specified. Please use only one!");
1668 }
1669 }
1670
1672
1673 // Common physics and simulation parameters
1675 pp.queryAdd("biology_model", biology_model_string);
1677
1680
1681 // Source of the biology initial condition, independent of ic_type.
1682 // Default "follow" reproduces the previous behaviour exactly.
1684 pp.queryAdd("biology_ic_type", biology_ic_string);
1686
1687 // Bridge-vs-native selection and diagnostic verbosity are runtime
1688 // controls so a parity comparison never requires a rebuild. Both
1689 // parse unconditionally; without USE_FENNEL_FORT there is no bridge
1690 // to select, so asking for it is an error rather than a silent
1691 // fallback to the path being validated.
1692 pp.queryAdd("use_biology_cpp_answer", use_biology_cpp_answer);
1693 pp.queryAdd("biology_debug", biology_debug);
1694 pp.queryAdd("biology_debug_i", biology_debug_i);
1695 pp.queryAdd("biology_debug_j", biology_debug_j);
1696#ifndef REMORA_USE_FENNEL_FORT
1697 if (use_biology_cpp_answer == 0) {
1698 amrex::Abort("remora.use_biology_cpp_answer = 0 selects the ROMS "
1699 "Fennel Fortran bridge, which is not compiled in. "
1700 "Rebuild with USE_FENNEL_FORT=TRUE (GNUmake) or "
1701 "-DREMORA_ENABLE_FENNEL_FORT=ON (CMake).");
1702 }
1703#endif
1704#ifndef REMORA_USE_BIOLOGY_DIAG
1705 if (biology_debug > 0) {
1706 amrex::Abort("remora.biology_debug > 0 requests the Fennel parity "
1707 "diagnostics, which are not compiled in. Rebuild with "
1708 "USE_BIOLOGY_DIAG=TRUE (GNUmake) or "
1709 "-DREMORA_ENABLE_BIOLOGY_DIAG=ON (CMake).");
1710 }
1711#endif
1712
1713 // Biology tracers are counted separately from the passive scalars, so a run can
1714 // carry dye and biology at once.
1715 nbio = static_cast<int>(REMORABiology::tracer_names(biology_model, fennel_params).size());
1716 } else {
1717 nbio = 0;
1718 }
1719 // Dye is opt-in, biology or not: a component nothing asked for is one more thing to
1720 // advect, diffuse, and explain in every plotfile and boundary file.
1721 pp.queryAdd("nscalar", nscalar);
1722 if (nscalar < 0) {
1723 amrex::Abort("remora.nscalar must be non-negative");
1724 }
1728
1729 // remora.nscalar used to be required to equal the biology tracer count; it now counts
1730 // dye only and adds to it. Print the layout so a run carrying both is unmistakable,
1731 // and an input written against the old meaning is caught by eye rather than by a
1732 // surprising component count much later.
1733 if (nbio > 0 && nscalar > 0) {
1734 amrex::Print() << "Carrying " << nscalar << " passive scalar(s) and " << nbio
1735 << " biology tracer(s), for " << ncons << " cell-centered components: ";
1736 for (int icomp = 0; icomp < ncons; ++icomp) {
1737 amrex::Print() << cons_names[icomp] << (icomp + 1 < ncons ? " " : "\n");
1738 }
1739 }
1740
1741 pp.queryAdd("check_file", check_file);
1742 pp.queryAdd("check_int", check_int);
1743 pp.queryAdd("check_int_time", check_int_time);
1744 pp.queryAdd("expand_plotvars_to_unif_rr", expand_plotvars_to_unif_rr);
1745 pp.query("plotfile_fill_value", plotfile_fill_value);
1746 pp.query("netcdf_fill_value", netcdf_fill_value);
1747 pp.queryAdd("restart", restart_chkfile);
1748 pp.queryAdd("start_time", start_time);
1749
1750 num_boxes_at_level.resize(max_level + 1, 0);
1751 boxes_at_level.resize(max_level + 1);
1752 num_boxes_at_level[0] = 1;
1753 boxes_at_level[0].resize(1);
1754 boxes_at_level[0][0] = geom[0].Domain();
1755
1756 if (pp.contains("data_log")) {
1757 int num_datalogs = pp.countval("data_log");
1758 datalog.resize(num_datalogs);
1759 datalogname.resize(num_datalogs);
1760 pp.queryarr("data_log", datalogname, 0, num_datalogs);
1761 for (int i = 0; i < num_datalogs; i++)
1763 }
1764
1765 pp.queryAdd("v", verbose);
1766 pp.queryAdd("sum_interval", sum_interval);
1767 pp.queryAdd("sum_period", sum_per);
1768 pp.queryAdd("file_min_digits", file_min_digits);
1769
1770 if (file_min_digits < 0) {
1771 amrex::Abort("remora.file_min_digits must be non-negative");
1772 }
1773
1774 pp.queryAdd("cfl", cfl);
1775 pp.queryAdd("change_max", change_max);
1776 pp.queryAdd("fixed_dt", fixed_dt);
1777
1778 // remora.fixed_fast_dt has been removed. It only ever served to infer the number of
1779 // barotropic substeps, and only when remora.fixed_dt was also given -- which left the
1780 // ratio at zero on every other path, including a CFL-driven run. amrex does not abort
1781 // on unused inputs by default, so catch it here rather than letting a stale input file
1782 // silently fall back to whatever remora.ndtfast happens to be.
1783 if (pp.contains("fixed_fast_dt")) {
1784 amrex::Abort("remora.fixed_fast_dt has been removed. Set remora.ndtfast (the "
1785 "number of barotropic steps per baroclinic step) instead; it is what "
1786 "fixed_fast_dt was used to infer, as remora.fixed_dt / "
1787 "remora.fixed_fast_dt");
1788 }
1789
1790 // remora.ndtfast is the preferred name; remora.fixed_ndtfast_ratio is kept as a
1791 // deprecated alias so existing input files keep working. Read the alias first, so
1792 // that the queryAdd below records the resulting value under the preferred name.
1793 if (pp.contains("fixed_ndtfast_ratio")) {
1794 if (pp.contains("ndtfast")) {
1795 amrex::Abort("remora.ndtfast and remora.fixed_ndtfast_ratio are both "
1796 "specified. Please use only remora.ndtfast");
1797 }
1798 amrex::Print() << "WARNING: remora.fixed_ndtfast_ratio is deprecated. "
1799 << "Please use remora.ndtfast instead." << std::endl;
1800 // Deprecated alias for remora.ndtfast.
1801 pp.queryAdd("fixed_ndtfast_ratio", ndtfast);
1802 }
1803 // Number of barotropic (fast) steps taken per baroclinic (slow) step.
1804 pp.queryAdd("ndtfast", ndtfast);
1805
1806 // Advance and timeStepML form the fast step as dt / ndtfast, and set_weights sizes
1807 // the barotropic filter with the same number, so a non-positive value divides by zero
1808 // at all three sites. Nothing can infer it: dt is not known until run time on a
1809 // CFL-driven run.
1810 if (ndtfast <= 0) {
1811 amrex::Abort("remora.ndtfast must be a positive integer: it is the number of "
1812 "barotropic steps taken per baroclinic step");
1813 }
1814
1815 // remora.use_barotropic has been removed -- the barotropic mode is always on. Reject
1816 // it on presence rather than on value: amrex does not abort on unused inputs by
1817 // default, so a stale "= false" would otherwise silently run different physics than
1818 // the input file asks for. Tested with contains() rather than query() so the schema
1819 // scraper behind Exec/Generic does not re-advertise a parameter that no longer exists.
1820 if (pp.contains("use_barotropic")) {
1821 amrex::Abort("remora.use_barotropic has been removed. The barotropic (2D) mode is "
1822 "always active; please delete this line from your inputs file");
1823 }
1824
1826
1827 num_files_at_level.resize(max_level + 1, 0);
1828 num_boxes_at_level.resize(max_level + 1, 0);
1829 boxes_at_level.resize(max_level + 1);
1830 num_boxes_at_level[0] = 1;
1831 boxes_at_level[0].resize(1);
1832 boxes_at_level[0][0] = geom[0].Domain();
1833
1834 pp.queryAdd("plot_file", plot_file_name);
1835 pp.queryAdd("plot_int", plot_int);
1836 pp.queryAdd("plot_int_time", plot_int_time);
1837 pp.query("plot_staggered_vels", plot_staggered_vels);
1838 pp.query("plot_nodal_data", plot_nodal_data);
1839
1840 std::string plotfile_type_str = "amrex";
1841 pp.queryAdd("plotfile_type", plotfile_type_str);
1842 if (plotfile_type_str == "amrex") {
1844 } else if (plotfile_type_str == "netcdf" || plotfile_type_str == "NetCDF") {
1846#ifdef REMORA_USE_NETCDF
1847 pp.queryAdd("write_history_file",write_history_file);
1848 pp.queryAdd("chunk_history_file",chunk_history_file);
1849 pp.queryAdd("steps_per_history_file",steps_per_history_file);
1850 // CDF-5 output has no practical size limit, so REMORA doesn't size history
1851 // files. Chunking is opt-in; the writer divides by steps_per_history_file.
1853 if (steps_per_history_file <= 0) {
1854 amrex::Abort("remora.chunk_history_file requires remora.steps_per_history_file > 0");
1855 }
1856 Print() << "NetCDF history files will have " << steps_per_history_file << " steps per file." << std::endl;
1857 }
1858#endif
1859 } else {
1860 amrex::Print() << "User selected plotfile_type = " << plotfile_type_str << std::endl;
1861 amrex::Abort("Dont know this plotfile_type");
1862 }
1863#ifndef REMORA_USE_NETCDF
1865 {
1866 amrex::Abort("Please compile with NetCDF in order to enable NetCDF plotfiles");
1867 }
1868
1869#endif
1870#ifdef REMORA_USE_NETCDF
1871 nc_init_file.resize(max_level+1);
1872 nc_grid_file.resize(max_level+1);
1873 num_files_at_level.resize(max_level + 1, 0);
1874
1875 boundary_series.resize(max_level+1);
1876
1877
1878 // NetCDF initialization files -- possibly multiple files at each of multiple levels
1879 // but we always have exactly one file at level 0
1880 for (int lev = 0; lev <= max_level; lev++)
1881 {
1882 const std::string nc_file_names = amrex::Concatenate("nc_init_file_",lev,1);
1883 const std::string nc_bathy_file_names = amrex::Concatenate("nc_grid_file_",lev,1);
1884
1885 if (pp.contains(nc_file_names.c_str()))
1886 {
1887 int num_files = pp.countval(nc_file_names.c_str());
1888 int num_bathy_files = pp.countval(nc_bathy_file_names.c_str());
1889 if (num_files != num_bathy_files) {
1890 amrex::Error("Must have same number of netcdf files for grid info as for solution");
1891 }
1892
1894 nc_init_file[lev].resize(num_files);
1895 nc_grid_file[lev].resize(num_files);
1896
1897 pp.queryarr(nc_file_names.c_str() , nc_init_file[lev] ,0,num_files);
1898 pp.queryarr(nc_bathy_file_names.c_str(), nc_grid_file[lev],0,num_files);
1899 }
1900 }
1901
1902 pp.queryAdd("nc_grid_file_hires", nc_grid_file_hires);
1903 pp.queryAdd("nc_init_file_hires", nc_init_file_hires);
1904
1905 // We only read boundary data at level 0
1906 pp.queryarr("nc_bdry_file", nc_bdry_file);
1907
1908 // Also only read forcings at level 0 (for now)
1909 if (pp.contains("nc_frc_file")) {
1910 int num_files = pp.countval("nc_frc_file");
1911 nc_frc_file.resize(num_files);
1912 pp.queryarr("nc_frc_file", nc_frc_file, 0, num_files);
1913 }
1914
1915 // Get river file
1916 if (pp.contains("nc_river_file")) {
1917 int num_files = pp.countval("nc_river_file");
1918 nc_riv_file.resize(num_files);
1919 pp.queryarr("nc_river_file", nc_riv_file, 0, num_files);
1920 }
1921
1922 // Read in file names for climatology history and nudging weights
1923 if (pp.contains("nc_clim_his_file")) {
1924 int num_files = pp.countval("nc_clim_his_file");
1926 pp.queryarr("nc_clim_his_file", nc_clim_his_file, 0, num_files);
1927 }
1928 pp.queryAdd("nc_clim_coeff_file", nc_clim_coeff_file);
1929
1930 for (int i=0; i<BdyVars::NumTypes(ncons); i++) {
1931 bdry_time_name_byvar.push_back("");
1932 }
1933 pp.queryAdd("bdy_time_varname",bdry_time_varname);
1934 // Every tracer takes its time-axis name from its own variable name, so temp and salt
1935 // keep bdy_temp_time_varname / bdy_salt_time_varname and a biology tracer uses e.g.
1936 // bdy_NO3_time_varname
1937 for (int icomp = 0; icomp < ncons; ++icomp) {
1938 pp.queryAdd(("bdy_"+cons_names[icomp]+"_time_varname").c_str(),
1940 }
1941 pp.queryAdd("bdy_u_time_varname",bdry_time_name_byvar[BdyVars::u]);
1942 pp.queryAdd("bdy_v_time_varname",bdry_time_name_byvar[BdyVars::v]);
1943 pp.queryAdd("bdy_ubar_time_varname",bdry_time_name_byvar[BdyVars::ubar(ncons)]);
1944 pp.queryAdd("bdy_vbar_time_varname",bdry_time_name_byvar[BdyVars::vbar(ncons)]);
1945 pp.queryAdd("bdy_zeta_time_varname",bdry_time_name_byvar[BdyVars::zeta(ncons)]);
1946
1947 // If not specified per variable, populate with the default
1948 for (int i=0; i<BdyVars::NumTypes(ncons); i++) {
1949 if (bdry_time_name_byvar[i] == "") {
1951 }
1952 }
1953
1954 pp.queryAdd("frc_time_varname",frc_time_varname);
1955
1956 pp.queryAdd("riv_time_varname",riv_time_varname);
1957
1958 pp.queryAdd("clim_ubar_time_varname",clim_ubar_time_varname);
1959 pp.queryAdd("clim_vbar_time_varname",clim_vbar_time_varname);
1960 pp.queryAdd("clim_u_time_varname",clim_u_time_varname);
1961 pp.queryAdd("clim_v_time_varname",clim_v_time_varname);
1962 // As for the boundary data, each tracer takes its climatology time-axis name from its
1963 // own variable name, so temp and salt keep clim_temp_time_varname /
1964 // clim_salt_time_varname and a biology tracer uses e.g. clim_NO3_time_varname
1965 clim_cons_time_varname.assign(ncons, "ocean_time");
1966 for (int icomp = 0; icomp < ncons; ++icomp) {
1967 pp.queryAdd(("clim_"+cons_names[icomp]+"_time_varname").c_str(),
1969 }
1970
1971#endif
1972 // A hires level of 0 is not "level 0 is the hires level", it is a null pointer: the
1973 // full-domain arrays are only allocated for lev > 0 (see allocate_init_full_domain and
1974 // allocate_bathymetry_grid_vars_full_domain), while every consumer branch tests < 0 and
1975 // so would take the averaged-down path against an unallocated MultiFab. -1 means off.
1976 pp.queryAdd("hires_grid_level", hires_grid_level);
1978 amrex::Abort("hires_grid_level must be less than or equal to amr.max_level");
1979 }
1980 if (hires_grid_level == 0) {
1981 amrex::Abort("hires_grid_level must be greater than 0; use -1 to specify grid data at level 0");
1982 }
1983 pp.queryAdd("hires_init_level", hires_init_level);
1985 amrex::Abort("hires_init_level must be less than or equal to amr.max_level");
1986 }
1987 if (hires_init_level == 0) {
1988 amrex::Abort("hires_init_level must be greater than 0; use -1 to specify initial data at level 0");
1989 }
1990#ifdef REMORA_USE_PARTICLES
1992#endif
1993
1994 {
1995 ParmParse pp_amr("amr");
1996 pp_amr.queryAdd("regrid_int", regrid_int);
1997 pp_amr.queryAdd("do_substep", do_substep);
1998 if (do_substep) {
1999 amrex::Abort("Time substepping is not yet implemented. amr.do_substep must be 0");
2000 }
2001
2002 }
2004
2005 // The biology IC source is chosen independently of ic_type, but only one of the two
2006 // mixed combinations works: NetCDF physics with analytic biology. The reverse has no
2007 // file to read from -- nc_init_file is only populated on the netcdf path -- so catch
2008 // it here instead of failing inside PnetCDF on an empty file name.
2012 amrex::Abort("remora.biology_ic_type = netcdf requires remora.ic_type = netcdf: the biology "
2013 "initial data is read from the same files as the physical initial data, and no "
2014 "such file is given for analytic initial conditions. Use "
2015 "remora.biology_ic_type = analytic (or follow) instead.");
2016 }
2017
2018#ifndef REMORA_USE_NETCDF
2020 amrex::Abort("Please compile with NetCDF in order to use remora.ic_type = netcdf");
2021 }
2022#endif
2023
2024 // NOTE: This feature is not yet implemented because it will require passing x,y,z to prob functions.
2025 // Currently these are accessed by passing a pointer to the REMORA class. However, this requires the
2026 // coordinates at hires_init_level to already exist (and specifically for the hires_init_level level
2027 // to already be initialized), which is generally not the case. A solution is to create a separate
2028 // coordinates object that is passed to the prob functions instead of the REMORA object. Then x,y,z
2029 // coordinates can be calculated at any level without the corresponding level having been created.
2031 amrex::Abort("Cannot do high-resolution initialization for analytic initial conditions. Not yet implemented");
2032 }
2033
2034}
2035
2036
2037void
2039{
2040 BL_PROFILE("REMORA::AverageDown()");
2041 for (int lev = finest_level-1; lev >= 0; --lev)
2042 {
2044 }
2045}
2046
2047/**
2048 * @param[in ] crse_lev level to average down to
2049 */
2050void
2073
2074/**
2075 * @param[in ] crse_lev level to average data down to
2076 * @param[inout] vec_mf vector over levels of multifabs containing data to average
2077 */
2078void
2080{
2081 auto const& crsema = vec_mf[crse_lev]->arrays();
2082 auto const& finema = vec_mf[crse_lev+1]->const_arrays();
2084 auto index_type = (vec_mf[crse_lev]->boxArray().ixType()).toIntVect();
2085 auto nghost_crse = cum_ref_ratios[crse_lev] - index_type;
2086 if (index_type[0]==0 and index_type[1]==0) {
2088 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
2089 {
2091 });
2092 } else if (index_type[0]==1 and index_type[1]==0) {
2094 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
2095 {
2097 });
2098 } else if (index_type[0]==0 and index_type[1]==1) {
2100 [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k, int n) noexcept
2101 {
2103 });
2104 } else {
2105 amrex::Abort("Unexpected nodality in average_down_with_grow_cells");
2106 }
2107 Gpu::streamSynchronize();
2108}
2109
2110/**
2111 * @param[in ] lev level at which to get time
2112 */
2113amrex::Real REMORA::get_t_old(int lev) const
2114{
2115 return t_old[lev];
2116}
constexpr amrex::Real bogus_large_value
constexpr amrex::Real one
constexpr amrex::Real fourth
constexpr amrex::Real zero
PlotfileType
plotfile format
#define NAT
#define Tracer_comp
mf_h setVal(geomdata.ProbHi(2))
AMREX_ALWAYS_ASSERT(!NSPeriodic||!EWPeriodic)
bool QueryNetCDFHasVars(const std::string &fname, const amrex::Vector< std::string > &var_names)
Helper function for testing whether a file carries every named variable.
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:1770
std::string nc_grid_file_hires
Grid file for high resolution bathymetry.
Definition REMORA.H:1782
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_EminusP
evaporation minus precipitation [kg/m^2/s], defined at rho-points
Definition REMORA.H:509
amrex::Vector< std::string > nc_riv_file
NetCDF river file(s)
Definition REMORA.H:1799
void set_grid_vars_averaged_down(int lev)
Set pm/pn by averaging down from higher-resolution grid.
Definition REMORA.cpp:750
std::string riv_time_varname
Name of time field for river time.
Definition REMORA.H:1823
int foextrap_periodic_bc() const noexcept
Definition REMORA.H:1320
amrex::Vector< std::string > nc_clim_his_file
NetCDF climatology history file(s)
Definition REMORA.H:1802
int ncons
Number of conserved scalars in the state (temperature + salt + passive scalars + biology tracers)
Definition REMORA.H:1644
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_zeta_full_domain
high resolution initial free surface height (2D)
Definition REMORA.H:554
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rv2d
v velocity RHS (2D, includes horizontal and vertical advection)
Definition REMORA.H:424
std::string nc_init_file_hires
Init file for high resolution.
Definition REMORA.H:1789
int biology_debug_i
Target column i index for biology_debug = 1.
Definition REMORA.H:1661
static amrex::Real fixed_dt
User specified fixed baroclinic time step.
Definition REMORA.H:1671
amrex::Real last_plot_file_time
Simulation time when we last output a plotfile.
Definition REMORA.H:1607
int zvel_bc() const noexcept
Definition REMORA.H:1315
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:1764
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:1313
void set_zeta_averaged_down(int lev)
Copy over zeta data that has been averaged down from high res.
Definition REMORA.cpp:768
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:1455
static amrex::Real previousCPUTimeUsed
Accumulator variable for CPU time used thusfar.
Definition REMORA.H:1882
amrex::Vector< std::string > cons_names
Names of scalars for plotfile output.
Definition REMORA.H:1709
bool running_with_coupling_driver
True once REMORA has received forcing through the coupling driver.
Definition REMORA.H:514
amrex::Vector< std::unique_ptr< amrex::YAFluxRegister > > advflux_reg
array of flux registers for refluxing in multilevel
Definition REMORA.H:1569
std::unique_ptr< NCTimeSeries > sustr_data_from_file
Data container for u-component surface momentum flux read from file.
Definition REMORA.H:1445
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_fcor
coriolis factor (2D)
Definition REMORA.H:577
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:397
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:406
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pm
horizontal scaling factor: 1 / dx (2D)
Definition REMORA.H:568
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:1513
void init_biology_ic(int lev)
Initialize biology tracers from whichever source remora.biology_ic_type selects. Call after the physi...
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:386
static bool write_history_file
Whether to output NetCDF files as a single history file with several time steps.
Definition REMORA.H:1442
void init_biology_ic_full_domain()
Full-domain counterpart of init_biology_ic, for the hires_init_level average-down path.
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:1463
REMORABiology::BiologyModel biology_model
Active biology package.
Definition REMORA.H:1646
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_vwind
Wind in the v direction, defined at rho-points.
Definition REMORA.H:474
std::unique_ptr< ProblemBase > prob
Pointer to container of analytical functions for problem definition.
Definition REMORA.H:1542
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_mskr
land/sea mask at cell centers (2D)
Definition REMORA.H:557
void Construct_REMORAFillPatchers(int lev)
Construct FillPatchers.
Definition REMORA.cpp:522
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:1756
int history_count
Counter for which time index we are writing to in the netcdf history file.
Definition REMORA.H:1702
amrex::Real stop_time
Whether max_step was set in the inputs; the default above is not a distinguishable sentinel.
Definition REMORA.H:1624
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_rain
precipitation rate [kg/m^2/s]
Definition REMORA.H:503
int do_substep
Whether to substep fine levels in time.
Definition REMORA.H:1678
void Evolve()
Advance solution to final time.
Definition REMORA.cpp:276
std::string bdry_time_varname
Default name of time field for boundary data.
Definition REMORA.H:1807
amrex::Real plotfile_fill_value
fill value for masked arrays in amrex plotfiles
Definition REMORA.H:1723
void ReadCheckpointFile()
read checkpoint file from disk
int biology_debug
Biology diagnostic verbosity: 0 off, 1 target column, 2 all columns. See Source/Biology/Fortran/tag_m...
Definition REMORA.H:1659
bool chunk_history_file
Whether to split the netcdf history file into fixed-length chunks.
Definition REMORA.H:1698
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_sustr
Surface stress in the u direction.
Definition REMORA.H:467
amrex::Real get_t_old(int lev) const
Accessor method for t_old to expose to outside classes.
Definition REMORA.cpp:2113
int yvel_bc() const noexcept
Definition REMORA.H:1314
std::unique_ptr< NCTimeSeries > longwave_down_data_from_file
Data container for downward longwave radiation flux read from file.
Definition REMORA.H:1461
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_ru2d
u velocity RHS (2D, includes horizontal and vertical advection)
Definition REMORA.H:422
amrex::Vector< std::string > datalogname
Definition REMORA.H:1914
amrex::Vector< amrex::MultiFab * > zvel_new
multilevel data container for current step's z velocities (largely unused; W stored separately)
Definition REMORA.H:392
void set_surface_state(int lev)
Initialize or calculate wind speed and other surface state vars from file or analytic.
Definition REMORA.cpp:1190
void WriteAtIntermediateTime(int step, amrex::Real cur_time)
Write checkpoint and plotfiles at intermediate point of simulation, if needed.
Definition REMORA.cpp:348
void init_only(int lev, amrex::Real time)
Init (NOT restart or regrid)
Definition REMORA.cpp:1320
void init_set_vmix(int lev)
Initialize vertical mixing coefficients from file or analytic.
Definition REMORA.cpp:825
std::unique_ptr< NCTimeSeries > v_clim_data_from_file
Data container for v-velocity climatology data read from file.
Definition REMORA.H:1476
std::string clim_u_time_varname
Name of time field for u climatology data.
Definition REMORA.H:1816
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:796
int foextrap_bc() const noexcept
Definition REMORA.H:1321
amrex::Vector< REMORAFillPatcher > FPr_u
Vector over levels of FillPatchers for u (3D)
Definition REMORA.H:1511
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
the boxes specified at each level by tagging criteria
Definition REMORA.H:1549
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Holds info for dynamically generated tagging criteria.
Definition REMORA.H:1831
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Akt
Vertical diffusion coefficient (3D)
Definition REMORA.H:432
std::unique_ptr< NCTimeSeriesRiver > river_source_transportbar
Data container for vertically integrated momentum transport in rivers.
Definition REMORA.H:1487
std::array< bool, AtmosState::NumTypes > driver_atmos_state_from_driver
provenance flags for driver-supplied atmospheric forcing lanes
Definition REMORA.H:512
std::string clim_ubar_time_varname
Name of time field for ubar climatology data.
Definition REMORA.H:1812
std::unique_ptr< NCTimeSeries > u_clim_data_from_file
Data container for u-velocity climatology data read from file.
Definition REMORA.H:1474
std::string check_file
Checkpoint file prefix.
Definition REMORA.H:1691
static amrex::Real startCPUTime
Variable for CPU timing.
Definition REMORA.H:1880
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pm_full_domain
horizontal scaling factor: 1 / dx (2D) on whole domain
Definition REMORA.H:572
amrex::Vector< amrex::MultiFab * > xvel_old
multilevel data container for last step's x velocities (u in ROMS)
Definition REMORA.H:379
amrex::Real start_time
Time of the start of the simulation, in seconds.
Definition REMORA.H:1627
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:390
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_uwind
Wind in the u direction, defined at rho-points.
Definition REMORA.H:472
static bool plot_nodal_data
Whether to write nodal data (Nu_nd) to plotfiles.
Definition REMORA.H:1767
int regrid_int
how often each level regrids the higher levels of refinement (after a level advances that many time s...
Definition REMORA.H:1681
amrex::Real check_int_time
Checkpoint output interval in seconds.
Definition REMORA.H:1695
DriverAtmosForcingMode driver_atmos_forcing_mode
Active atmosphere-to-ocean forcing contract on the most recent driver apply.
Definition REMORA.H:518
void init_scalar_metadata()
Build runtime scalar names after nscalar is known.
Definition REMORA.cpp:249
int zeta_bc() const noexcept
Definition REMORA.H:1318
void Define_REMORAFillPatchers(int lev)
Define FillPatchers.
Definition REMORA.cpp:571
amrex::Vector< amrex::IntVect > cum_ref_ratios
Cumulative refinement ratio between level 0 and level i.
Definition REMORA.H:1794
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:434
amrex::Real plot_int_time
Plotfile output interval in seconds.
Definition REMORA.H:1689
amrex::Vector< int > num_files_at_level
how many netcdf input files specified at each level
Definition REMORA.H:1547
amrex::Vector< REMORAFillPatcher > FPr_vbar
Vector over levels of FillPatchers for vbar (2D)
Definition REMORA.H:1521
void AverageDownTo(int crse_lev)
more flexible version of AverageDown() that lets you average down across multiple levels
Definition REMORA.cpp:2051
int steps_per_history_file
Time steps per netcdf history file. Must be > 0 if chunk_history_file.
Definition REMORA.H:1700
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Called after every level 0 timestep.
Definition REMORA.cpp:373
int max_step
maximum number of steps
Definition REMORA.H:1620
amrex::Vector< amrex::MultiFab * > zvel_old
multilevel data container for last step's z velocities (largely unused; W stored separately)
Definition REMORA.H:383
std::unique_ptr< NCTimeSeries > svstr_data_from_file
Data container for v-component surface momentum flux read from file.
Definition REMORA.H:1447
amrex::Vector< std::string > nc_frc_file
NetCDF forcing file(s)
Definition REMORA.H:1797
amrex::Vector< int > num_boxes_at_level
how many boxes specified at each level by tagging criteria
Definition REMORA.H:1545
amrex::Vector< amrex::MultiFab * > xvel_new
multilevel data container for current step's x velocities (u in ROMS)
Definition REMORA.H:388
void refinement_criteria_setup()
Set refinement criteria.
int Bio_comp
First cons component of the biology block, i.e. Tracer_comp + nscalar. The state is laid out as temp,...
Definition REMORA.H:1641
int last_check_file_step
Step when we last output a checkpoint file.
Definition REMORA.H:1610
int bdy_zeta() const noexcept
Definition REMORA.H:1331
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:1814
amrex::Vector< int > nsubsteps
How many substeps on each level?
Definition REMORA.H:1554
amrex::Vector< std::unique_ptr< REMORAPhysBCFunct > > physbcs
Vector (over level) of functors to apply physical boundary conditions.
Definition REMORA.H:1566
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:1467
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:1687
std::unique_ptr< NCTimeSeries > cloud_data_from_file
Data container for cloud cover fraction read from file.
Definition REMORA.H:1465
int nbio
Number of biology tracers, set by the active biology model. Zero when no biology model is active.
Definition REMORA.H:1638
void WriteAtFinalTime()
Write checkpoint and plotfiles at end of simulation.
Definition REMORA.cpp:333
void InitData()
Initialize multilevel data.
Definition REMORA.cpp:405
void set3DPlotVariables(const std::string &pp_plot_var_names_3d)
amrex::Vector< int > istep
which step?
Definition REMORA.H:1552
void WriteCheckpointFile()
write checkpoint file to disk
std::string nc_clim_coeff_file
NetCDF climatology coefficient file.
Definition REMORA.H:1804
void setRecordDataInfo(int i, const std::string &filename)
Definition REMORA.H:1900
void set_analytic_vmix(int lev)
Set vertical mixing coefficients from analytic.
Definition REMORA.cpp:842
amrex::Vector< std::string > bdry_time_name_byvar
Name of time fields for boundary data.
Definition REMORA.H:1809
static int file_min_digits
Minimum number of digits in plotfile name or chunked history file.
Definition REMORA.H:1761
void init_riv_pos_from_netcdf(int lev)
static amrex::Vector< std::string > nc_bdry_file
NetCDF boundary data.
Definition REMORA.H:57
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_visc2_r
Harmonic viscosity defined on the rho points (centers)
Definition REMORA.H:436
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:399
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_svstr
Surface stress in the v direction.
Definition REMORA.H:469
std::unique_ptr< NCTimeSeries > srflx_data_from_file
Data container for shortwave radiation flux read from file.
Definition REMORA.H:1459
REMORA()
Definition REMORA.cpp:68
void set_zeta(int lev)
Initialize zeta from file or analytic.
Definition REMORA.cpp:635
static amrex::Real change_max
Fraction maximum change in subsequent time steps.
Definition REMORA.H:1669
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:374
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_h_full_domain
Bathymetry data on the whole domain at each potential level.
Definition REMORA.H:409
void set_bathymetry(int lev)
Initialize bathymetry from file or analytic.
Definition REMORA.cpp:674
amrex::Vector< amrex::MultiFab * > yvel_old
multilevel data container for last step's y velocities (v in ROMS)
Definition REMORA.H:381
std::unique_ptr< NCTimeSeries > ubar_clim_data_from_file
Data container for ubar climatology data read from file.
Definition REMORA.H:1470
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:1509
int hires_init_level
Which level the high resolution initialization data is at.
Definition REMORA.H:1787
amrex::Vector< std::string > clim_cons_time_varname
Vector over cons components of the name of the time field for that tracer's climatology data.
Definition REMORA.H:1821
std::unique_ptr< NCTimeSeries > Tair_data_from_file
Data container for air temperature read from file.
Definition REMORA.H:1453
int nscalar
Number of passive (dye) scalars carried in the state, beyond temperature and salinity....
Definition REMORA.H:1635
std::string clim_v_time_varname
Name of time field for v climatology data.
Definition REMORA.H:1818
amrex::Vector< REMORAFillPatcher > FPr_w
Vector over levels of FillPatchers for w.
Definition REMORA.H:1515
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:2079
std::unique_ptr< NCTimeSeries > Uwind_data_from_file
Data container for u-direction wind read from file.
Definition REMORA.H:1449
std::unique_ptr< NCTimeSeries > Pair_data_from_file
Data container for air pressure read from file.
Definition REMORA.H:1457
amrex::Vector< amrex::Real > t_new
new time at each level
Definition REMORA.H:1556
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:1717
void set_masks(int lev)
Initialize land-sea masks from file or analytic.
Definition REMORA.cpp:860
void set_zeta_to_Ztavg(int lev, bool apply_eminusp=true)
Set zeta components to be equal to time-averaged Zt_avg1.
bool driver_uses_two_way_coupling
Driver-level direction flag copied in before InitData.
Definition REMORA.H:516
amrex::Vector< amrex::Vector< std::unique_ptr< NCTimeSeriesBoundary > > > boundary_series
Vector over BdyVars of boundary series data containers.
Definition REMORA.H:1490
int cf_set_width
Width for fixing values at coarse-fine interface.
Definition REMORA.H:1506
int biology_debug_j
Target column j index for biology_debug = 1.
Definition REMORA.H:1663
void ReadParameters()
read in some parameters from inputs file
Definition REMORA.cpp:1654
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_ru
u velocity RHS (3D, includes horizontal and vertical advection)
Definition REMORA.H:418
void sum_integrated_quantities(amrex::Real time)
Integrate conserved quantities for diagnostics.
static int total_nc_plot_file_step
Definition REMORA.H:1345
static amrex::Vector< amrex::Vector< std::string > > nc_grid_file
NetCDF grid file.
Definition REMORA.H:59
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_longwave_down
Downward longwave radiation.
Definition REMORA.H:487
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_zeta
free surface height (2D)
Definition REMORA.H:551
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_vbar
barotropic y velocity (2D)
Definition REMORA.H:549
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...
bool expand_plotvars_to_unif_rr
whether plotfile variables should be expanded to a uniform refinement ratio
Definition REMORA.H:1720
int plot_file_on_restart
Whether to output a plotfile on restart from checkpoint.
Definition REMORA.H:1614
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:547
amrex::Vector< amrex::MultiFab * > cons_old
multilevel data container for last step's scalar data: temperature, salinity, passive tracer
Definition REMORA.H:377
std::string frc_time_varname
Name of time field for forcing data.
Definition REMORA.H:1825
amrex::Vector< REMORAFillPatcher > FPr_ubar
Vector over levels of FillPatchers for ubar (2D)
Definition REMORA.H:1519
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:395
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:1451
static constexpr bool DriverUsesStateForcing(DriverAtmosForcingMode mode) noexcept
Definition REMORA.H:98
static int ndtfast
User specified, number of barotropic steps per baroclinic step.
Definition REMORA.H:1673
void init_bathymetry_full_domain_from_netcdf()
Full domain high-res bathymetry data initialization from NetCDF file.
amrex::Vector< std::unique_ptr< NCTimeSeries > > cons_clim_data_from_file
Vector over cons components of climatology data read from file.
Definition REMORA.H:1480
void set_hmixcoef(int lev)
Initialize horizontal mixing coefficients.
Definition REMORA.cpp:886
amrex::Vector< std::unique_ptr< NCTimeSeriesRiver > > river_source_cons
Vector of data containers for scalar data in rivers.
Definition REMORA.H:1483
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:1485
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:2038
amrex::Real netcdf_fill_value
fill value for masked arrays in netcdf output
Definition REMORA.H:1725
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_pn_full_domain
horizontal scaling factor: 1 / dy (2D) on whole domain
Definition REMORA.H:574
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:570
amrex::Vector< std::unique_ptr< std::fstream > > datalog
Definition REMORA.H:1913
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Akv
Vertical viscosity coefficient (3D)
Definition REMORA.H:430
static amrex::Real cfl
CFL condition.
Definition REMORA.H:1667
void append3DPlotVariables(const std::string &pp_plot_var_names_3d)
REMORABiology::FennelParameters fennel_params
Runtime parameters for the Fennel biology package.
Definition REMORA.H:1648
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:779
static int verbose
Verbosity level of output.
Definition REMORA.H:1753
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_cloud
cloud cover fraction [0-1], defined at rho-points
Definition REMORA.H:507
std::string plot_file_name
Plotfile prefix.
Definition REMORA.H:1685
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Zt_avg1
Average of the free surface, zeta (2D)
Definition REMORA.H:464
int check_int
Checkpoint output interval in iterations.
Definition REMORA.H:1693
void set_smflux(int lev)
Initialize or calculate surface momentum flux from file or analytic.
Definition REMORA.cpp:1171
void WritePlotFile(int istep)
main driver for writing AMReX plotfiles
std::string restart_chkfile
If set, restart from this checkpoint file.
Definition REMORA.H:1630
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:420
int cf_width
Nudging width at coarse-fine interface.
Definition REMORA.H:1504
static amrex::Vector< amrex::Vector< std::string > > nc_init_file
NetCDF initialization file.
Definition REMORA.H:58
int last_plot_file_step
Step when we last output a plotfile.
Definition REMORA.H:1605
int use_biology_cpp_answer
Select the native C++ biology kernel (1) or the ROMS Fortran bridge oracle (0). Only meaningful when ...
Definition REMORA.H:1656
amrex::Vector< amrex::Real > t_old
old time at each level
Definition REMORA.H:1558
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_srflx
Shortwave radiation flux [W/m²], defined at rho-points.
Definition REMORA.H:483
amrex::Real last_check_file_time
Simulation time when we last output a checkpoint file.
Definition REMORA.H:1612
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:733
amrex::Vector< amrex::Real > dt
time step at each level
Definition REMORA.H:1560
static amrex::Real sum_per
Diagnostic sum output interval in time.
Definition REMORA.H:1758
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Pair
Air pressure [mb], defined at rho-points.
Definition REMORA.H:480
virtual ~REMORA()
Definition REMORA.cpp:244
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_qair
Specific humidity [kg/kg], defined at rho-points.
Definition REMORA.H:478
int hires_grid_level
Which level the high resolution bathymetry is at.
Definition REMORA.H:1780
void restart()
Definition REMORA.cpp:618
std::unique_ptr< NCTimeSeries > vbar_clim_data_from_file
Data container for vbar climatology data read from file.
Definition REMORA.H:1472
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_Tair
Air temperature [°C], defined at rho-points.
Definition REMORA.H:476
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vec_diff2
Harmonic diffusivity for temperature / salinity.
Definition REMORA.H:438
REMORABiology::BiologyICType biology_ic_type
Source of the biology tracer initial condition, independent of remora.ic_type. Default follows ic_typ...
Definition REMORA.H:1651
@ 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
static constexpr int t
cons component Temp_comp
static constexpr int u
int NumTypes(int ncons) noexcept
static constexpr int v
int vbar(int ncons) noexcept
int cons(int icomp) noexcept
static constexpr int null
int zeta(int ncons) noexcept
int ubar(int ncons) noexcept
@ 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]
Vector< std::string > tracer_names(BiologyModel model, FennelParameters const &fennel_parameters)
std::string biology_ic_type_name(BiologyICType type)
bool has_biology(BiologyModel model) noexcept
BiologyICType parse_biology_ic_type(const std::string &name)
BiologyModel parse_biology_model(const std::string &name)
std::string biology_model_name(BiologyModel model)
const char * buildInfoGetGitHash(int i)
void init_params(const std::string &remora_prefix)
amrex::Vector< amrex::Real > Akt_bak
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
void init_params(int ncons, int nscalar, const amrex::Vector< std::string > &cons_names)
read in and initialize parameters
SMFluxType smflux_type
VertMixingType vert_mixing_type
std::array< BulkForcingType, BulkFlux::NumTypes > bulk_flux_type
amrex::Vector< int > do_cons_clim_nudg
CouplingType coupling_type