Skip to content

Commit 74070a3

Browse files
authored
Variable Coriolis (#2201)
* Variable Coriolis. * Make coriolis vars not depend upon netcdf since we need their pointer in other places. * clean up style. * Add docs and make user choose to employ var_cor.
1 parent f6727ed commit 74070a3

File tree

12 files changed

+224
-80
lines changed

12 files changed

+224
-80
lines changed

Docs/sphinx_doc/Inputs.rst

+4
Original file line numberDiff line numberDiff line change
@@ -1169,6 +1169,10 @@ List of Parameters
11691169
| **erf.use_coriolis** | Include Coriolis | true / false | false |
11701170
| | forcing | | |
11711171
+-------------------------------------+------------------------+-------------------+---------------------+
1172+
| **erf.variable_coriolis** | Include Coriolis | true / false | false |
1173+
| | forcing that varies | | |
1174+
| | with latitude | | |
1175+
+-------------------------------------+------------------------+-------------------+---------------------+
11721176
| **erf.rotational_time_period** | Used to calculate the | Real | 86400.0 |
11731177
| | Coriolis frequency | | |
11741178
+-------------------------------------+------------------------+-------------------+---------------------+

Docs/sphinx_doc/theory/Forcings.rst

+8
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ period (measured in seconds), and :math:`\phi` the latitude.
5454
Values for ``erf.rotational_time_period``, ``erf.latitude``, and ``erf.coriolis_3d``; the first two are used
5555
to compute the Coriolis frequency and the last of these determines whether to include the z-component in the Coriolis forcing.
5656

57+
When initializing from a ``wrfinput`` or ``met_em`` file, the latitude at the grid cell centers will be known. For this case, a user may specify
58+
59+
::
60+
61+
variable_coriolis == true
62+
63+
to use the grid latitude, :math:`\phi(y)`, when computing the sine and cosine coefficients above.
64+
5765
There is no dependence on the radial distance from the center of the earth, thus the curvature of the earth is neglected.
5866

5967
Rayleigh Damping

Source/BoundaryConditions/ERF_ABLMost.H

+1-1
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ public:
468468
amrex::Real
469469
get_zref () { return m_ma.get_zref(); }
470470

471-
const amrex::FArrayBox*
471+
amrex::FArrayBox*
472472
get_z0 (const int& lev) { return &z_0[lev]; }
473473

474474
bool have_variable_sea_roughness() { return m_var_z0; }

Source/DataStructs/ERF_DataStruct.H

+7-2
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,8 @@ struct SolverChoice {
326326

327327
// Include Coriolis forcing?
328328
pp.query("use_coriolis", use_coriolis);
329+
pp.query("has_lat_lon", has_lat_lon);
330+
if (has_lat_lon) { pp.query("variable_coriolis", variable_coriolis); }
329331

330332
// Include Rayleigh damping (separate flags for each variable)
331333
pp.query("rayleigh_damp_U", rayleigh_damp_U);
@@ -369,7 +371,7 @@ struct SolverChoice {
369371

370372
if (use_coriolis)
371373
{
372-
build_coriolis_forcings(pp_prefix);
374+
build_coriolis_forcings_const_lat(pp_prefix);
373375
}
374376

375377
pp.query("add_custom_rhotheta_forcing", custom_rhotheta_forcing);
@@ -591,7 +593,7 @@ struct SolverChoice {
591593
}
592594
}
593595

594-
void build_coriolis_forcings(std::string pp_prefix)
596+
void build_coriolis_forcings_const_lat (std::string pp_prefix)
595597
{
596598
amrex::ParmParse pp(pp_prefix);
597599

@@ -765,6 +767,9 @@ struct SolverChoice {
765767
std::string abl_geo_wind_table;
766768
bool have_geo_wind_profile {false};
767769

770+
bool has_lat_lon{false};
771+
bool variable_coriolis{false};
772+
768773
int ave_plane {2};
769774
// Microphysics params
770775
bool use_moist_background {false};

Source/ERF.H

+3-1
Original file line numberDiff line numberDiff line change
@@ -678,9 +678,11 @@ private:
678678
amrex::Vector<amrex::Vector<amrex::FArrayBox>> bdy_data_yhi;
679679

680680
amrex::Real bdy_time_interval;
681-
amrex::Vector<std::unique_ptr<amrex::MultiFab>> lat_m, lon_m;
681+
amrex::Vector<std::unique_ptr<amrex::MultiFab>> lat_m, lon_m; // Latitude and Longitude on the grid
682682
#endif // ERF_USE_NETCDF
683683

684+
amrex::Vector<std::unique_ptr<amrex::MultiFab>> sinPhi_m, cosPhi_m; // Coriolis factors on the grid
685+
684686
// Struct for working with the sounding data we take as an input
685687
InputSoundingData input_sounding_data;
686688

Source/ERF.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -344,13 +344,20 @@ ERF::ERF_shared ()
344344
// Size lat long arrays if using netcdf
345345
lat_m.resize(nlevs_max);
346346
lon_m.resize(nlevs_max);
347-
for (int lev = 0; lev < max_level; ++lev)
348-
{
347+
for (int lev = 0; lev < max_level; ++lev) {
349348
lat_m[lev] = nullptr;
350349
lon_m[lev] = nullptr;
351350
}
352351
#endif
353352

353+
// Variable coriolis
354+
sinPhi_m.resize(nlevs_max);
355+
cosPhi_m.resize(nlevs_max);
356+
for (int lev = 0; lev < max_level; ++lev) {
357+
sinPhi_m[lev] = nullptr;
358+
cosPhi_m[lev] = nullptr;
359+
}
360+
354361
// Initialize tagging criteria for mesh refinement
355362
refinement_criteria_setup();
356363

Source/IO/ERF_Checkpoint.cpp

+71-3
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,34 @@ ERF::WriteCheckpointFile () const
228228
}
229229
VisMF::Write(z0, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "Z0"));
230230
}
231-
}
231+
232+
#ifdef ERF_USE_NETCDF
233+
// Write lat/lon if it exists
234+
if (lat_m[lev] && lon_m[lev] && solverChoice.has_lat_lon) {
235+
amrex::Print() << "Writing Lat/Lon variables" << std::endl;
236+
IntVect ngv = ng; ngv[2] = 0;
237+
MultiFab lat(ba2d,dmap[lev],1,ngv);
238+
MultiFab lon(ba2d,dmap[lev],1,ngv);
239+
MultiFab::Copy(lat,*lat_m[lev],0,0,1,ngv);
240+
MultiFab::Copy(lon,*lon_m[lev],0,0,1,ngv);
241+
VisMF::Write(lat, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LAT"));
242+
VisMF::Write(lon, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "LON"));
243+
}
244+
245+
// Write sinPhi and cosPhi if it exists
246+
if (cosPhi_m[lev] && sinPhi_m[lev] && solverChoice.variable_coriolis) {
247+
amrex::Print() << "Writing Coriolis factors" << std::endl;
248+
IntVect ngv = ng; ngv[2] = 0;
249+
MultiFab sphi(ba2d,dmap[lev],1,ngv);
250+
MultiFab cphi(ba2d,dmap[lev],1,ngv);
251+
MultiFab::Copy(sphi,*sinPhi_m[lev],0,0,1,ngv);
252+
MultiFab::Copy(cphi,*cosPhi_m[lev],0,0,1,ngv);
253+
VisMF::Write(sphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "SinPhi"));
254+
VisMF::Write(cphi, MultiFabFileFullPrefix(lev, checkpointname, "Level_", "CosPhi"));
255+
}
256+
#endif
257+
258+
} // for lev
232259

233260
#ifdef ERF_USE_PARTICLES
234261
particleData.Checkpoint(checkpointname);
@@ -532,7 +559,6 @@ ERF::ReadCheckpointFile ()
532559
}
533560
BoxArray ba2d(std::move(bl2d));
534561

535-
{
536562
IntVect ng = mapfac_m[lev]->nGrowVect();
537563
MultiFab mf_m(ba2d,dmap[lev],1,ng);
538564
VisMF::Read(mf_m, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_m"));
@@ -547,8 +573,50 @@ ERF::ReadCheckpointFile ()
547573
MultiFab mf_v(convert(ba2d,IntVect(0,1,0)),dmap[lev],1,ng);
548574
VisMF::Read(mf_v, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "MapFactor_v"));
549575
MultiFab::Copy(*mapfac_v[lev],mf_v,0,0,1,ng);
576+
577+
if (m_most && m_most->have_variable_sea_roughness()) {
578+
amrex::Print() << "Reading variable surface roughness" << std::endl;
579+
ng = vars_new[lev][Vars::cons].nGrowVect(); ng[2]=0;
580+
MultiFab z0(ba2d,dmap[lev],1,ng);
581+
VisMF::Read(z0, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "Z0"));
582+
for (amrex::MFIter mfi(z0); mfi.isValid(); ++mfi) {
583+
const Box& bx = mfi.growntilebox();
584+
FArrayBox* most_z0 = (m_most->get_z0(lev));
585+
most_z0->copy<RunOn::Host>(z0[mfi], bx);
586+
}
550587
}
551-
}
588+
589+
#ifdef ERF_USE_NETCDF
590+
// Read lat/lon if it exists
591+
if (solverChoice.has_lat_lon) {
592+
amrex::Print() << "Reading Lat/Lon variables" << std::endl;
593+
IntVect ngv = ng; ngv[2] = 0;
594+
MultiFab lat(ba2d,dmap[lev],1,ngv);
595+
MultiFab lon(ba2d,dmap[lev],1,ngv);
596+
VisMF::Read(lat, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LAT"));
597+
VisMF::Read(lon, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "LON"));
598+
lat_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
599+
lon_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
600+
MultiFab::Copy(*lat_m[lev],lat,0,0,1,ngv);
601+
MultiFab::Copy(*lon_m[lev],lon,0,0,1,ngv);
602+
}
603+
604+
// Read sinPhi and cosPhi if it exists
605+
if (solverChoice.variable_coriolis) {
606+
amrex::Print() << "Reading Coriolis factors" << std::endl;
607+
IntVect ngv = ng; ngv[2] = 0;
608+
MultiFab sphi(ba2d,dmap[lev],1,ngv);
609+
MultiFab cphi(ba2d,dmap[lev],1,ngv);
610+
VisMF::Read(sphi, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "SinPhi"));
611+
VisMF::Read(cphi, MultiFabFileFullPrefix(lev, restart_chkfile, "Level_", "CosPhi"));
612+
sinPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
613+
cosPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dmap[lev],1,ngv);
614+
MultiFab::Copy(*sinPhi_m[lev],sphi,0,0,1,ngv);
615+
MultiFab::Copy(*cosPhi_m[lev],cphi,0,0,1,ngv);
616+
}
617+
#endif
618+
619+
} // for lev
552620

553621
#ifdef ERF_USE_PARTICLES
554622
restartTracers((ParGDBBase*)GetParGDB(),restart_chkfile);

Source/Initialization/ERF_InitFromMetgrid.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -205,18 +205,27 @@ ERF::init_from_metgrid (int lev)
205205
}
206206
}
207207

208-
lat_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
208+
solverChoice.has_lat_lon = true;
209+
lat_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
210+
sinPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
211+
cosPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
209212
for ( MFIter mfi(*(lat_m[lev]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
210213
Box gtbx = mfi.growntilebox();
211214
FArrayBox& dst = (*(lat_m[lev]))[mfi];
212215
FArrayBox& src = NC_LAT_fab[0];
216+
const Array4< Real>& sin_arr = (sinPhi_m[lev])->array(mfi);
217+
const Array4< Real>& cos_arr = (cosPhi_m[lev])->array(mfi);
213218
const Array4< Real>& dst_arr = dst.array();
214219
const Array4<const Real>& src_arr = src.const_array();
215220
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
216221
{
217222
int li = min(max(i, i_lo), i_hi);
218223
int lj = min(max(j, j_lo), j_hi);
219224
dst_arr(i,j,0) = src_arr(li,lj,0);
225+
226+
Real lat_rad = dst_arr(i,j,0) * (PI/180.);
227+
sin_arr(i,j,0) = std::sin(lat_rad);
228+
cos_arr(i,j,0) = std::cos(lat_rad);
220229
});
221230
}
222231

Source/Initialization/ERF_InitFromWRFInput.cpp

+59-50
Original file line numberDiff line numberDiff line change
@@ -375,65 +375,74 @@ ERF::init_from_wrfinput (int lev)
375375
int i_lo = geom[lev].Domain().smallEnd(0); int i_hi = geom[lev].Domain().bigEnd(0);
376376
int j_lo = geom[lev].Domain().smallEnd(1); int j_hi = geom[lev].Domain().bigEnd(1);
377377

378-
// Initialize Latitude
378+
// Initialize Latitude & Coriolis factors
379379
if ( var_name == "XLAT_V" ) {
380-
lat_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
381-
for ( MFIter mfi(*(lat_m[lev]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
382-
Box gtbx = mfi.growntilebox();
383-
const Array4< Real>& dst_arr = (lat_m[lev])->array(mfi);
384-
const Array4<const Real>& src_arr = var_fab.const_array();
385-
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
386-
{
387-
int li = amrex::min(amrex::max(i, i_lo), i_hi);
388-
int lj = amrex::min(amrex::max(j, j_lo), j_hi);
389-
dst_arr(i,j,0) = src_arr(li,lj,0);
390-
});
391-
}
380+
solverChoice.has_lat_lon = true;
381+
lat_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
382+
sinPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
383+
cosPhi_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
384+
for ( MFIter mfi(*(lat_m[lev]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
385+
Box gtbx = mfi.growntilebox();
386+
const Array4< Real>& sin_arr = (sinPhi_m[lev])->array(mfi);
387+
const Array4< Real>& cos_arr = (cosPhi_m[lev])->array(mfi);
388+
const Array4< Real>& dst_arr = (lat_m[lev])->array(mfi);
389+
const Array4<const Real>& src_arr = var_fab.const_array();
390+
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
391+
{
392+
int li = amrex::min(amrex::max(i, i_lo), i_hi);
393+
int lj = amrex::min(amrex::max(j, j_lo), j_hi);
394+
dst_arr(i,j,0) = src_arr(li,lj,0);
395+
396+
Real lat_rad = dst_arr(i,j,0) * (PI/180.);
397+
sin_arr(i,j,0) = std::sin(lat_rad);
398+
cos_arr(i,j,0) = std::cos(lat_rad);
399+
});
400+
}
392401
}
393402

394403
// Initialize Longitude
395404
if ( var_name == "XLONG_U" ) {
396-
lon_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
397-
for ( MFIter mfi(*(lon_m[lev]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
398-
Box gtbx = mfi.growntilebox();
399-
const Array4< Real>& dst_arr = (lon_m[lev])->array(mfi);
400-
const Array4<const Real>& src_arr = var_fab.const_array();
401-
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
402-
{
403-
int li = amrex::min(amrex::max(i, i_lo), i_hi);
404-
int lj = amrex::min(amrex::max(j, j_lo), j_hi);
405-
dst_arr(i,j,0) = src_arr(li,lj,0);
406-
});
407-
}
405+
lon_m[lev] = std::make_unique<MultiFab>(ba2d,dm,1,ngv);
406+
for ( MFIter mfi(*(lon_m[lev]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
407+
Box gtbx = mfi.growntilebox();
408+
const Array4< Real>& dst_arr = (lon_m[lev])->array(mfi);
409+
const Array4<const Real>& src_arr = var_fab.const_array();
410+
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
411+
{
412+
int li = amrex::min(amrex::max(i, i_lo), i_hi);
413+
int lj = amrex::min(amrex::max(j, j_lo), j_hi);
414+
dst_arr(i,j,0) = src_arr(li,lj,0);
415+
});
416+
}
408417
}
409418

410419
// Initialize Landmask
411420
if ( var_name == "LANDMASK" ) {
412-
for ( MFIter mfi(*(lmask_lev[lev][0]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
413-
Box gtbx = mfi.growntilebox();
414-
const Array4< int>& dst_arr = lmask_lev[lev][0]->array(mfi);
415-
const Array4<const Real>& src_arr = var_fab.const_array();
416-
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
417-
{
418-
int li = amrex::min(amrex::max(i, i_lo), i_hi);
419-
int lj = amrex::min(amrex::max(j, j_lo), j_hi);
420-
dst_arr(i,j,0) = static_cast<int>(src_arr(li,lj,0));
421-
});
422-
}
423-
(lmask_lev[lev])[0]->FillBoundary(geom[lev].periodicity());
421+
for ( MFIter mfi(*(lmask_lev[lev][0]), TilingIfNotGPU()); mfi.isValid(); ++mfi ) {
422+
Box gtbx = mfi.growntilebox();
423+
const Array4< int>& dst_arr = lmask_lev[lev][0]->array(mfi);
424+
const Array4<const Real>& src_arr = var_fab.const_array();
425+
ParallelFor(gtbx, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept
426+
{
427+
int li = amrex::min(amrex::max(i, i_lo), i_hi);
428+
int lj = amrex::min(amrex::max(j, j_lo), j_hi);
429+
dst_arr(i,j,0) = static_cast<int>(src_arr(li,lj,0));
430+
});
431+
}
432+
(lmask_lev[lev])[0]->FillBoundary(geom[lev].periodicity());
424433
}
425434

426435
// Initialize MapFac U
427436
if ( var_name == "MAPFAC_UY" ) {
428437
#ifdef _OPENMP
429438
#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
430439
#endif
431-
for ( MFIter mfi(*mapfac_u[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
432-
{
433-
// Define fabs for holding the initial data
434-
FArrayBox &msf_fab = (*mapfac_u[lev])[mfi];
435-
msf_fab.template copy<RunOn::Device>(var_fab);
436-
}
440+
for ( MFIter mfi(*mapfac_u[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
441+
{
442+
// Define fabs for holding the initial data
443+
FArrayBox &msf_fab = (*mapfac_u[lev])[mfi];
444+
msf_fab.template copy<RunOn::Device>(var_fab);
445+
}
437446
}
438447

439448
// Initialize MapFac V
@@ -454,20 +463,20 @@ ERF::init_from_wrfinput (int lev)
454463
#ifdef _OPENMP
455464
#pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
456465
#endif
457-
for ( MFIter mfi(*mapfac_m[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
458-
{
459-
// Define fabs for holding the initial data
460-
FArrayBox &msf_fab = (*mapfac_m[lev])[mfi];
461-
msf_fab.template copy<RunOn::Device>(var_fab);
462-
}
466+
for ( MFIter mfi(*mapfac_m[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi )
467+
{
468+
// Define fabs for holding the initial data
469+
FArrayBox &msf_fab = (*mapfac_m[lev])[mfi];
470+
msf_fab.template copy<RunOn::Device>(var_fab);
471+
}
463472
}
464473

465474
if (success) {
466475
var_fab.clear();
467476
Print() << " DONE\n";
468477
}
469478
} // ivar
470-
Print() << "\n";
479+
Print() << "\n";
471480
} // idx
472481

473482
// Convert the velocities using the map factors

0 commit comments

Comments
 (0)