ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
main.cpp File Reference
#include <iostream>
#include <AMReX.H>
#include <AMReX_BLProfiler.H>
#include <AMReX_ParallelDescriptor.H>
#include "ERF.H"
#include "ERF_InputsName.H"
Include dependency graph for main.cpp:

Functions

void add_par ()
 
int main (int argc, char *argv[])
 

Variables

std::string inputs_name
 

Function Documentation

◆ add_par()

void add_par ( )

Function to set the refine_grid_layout flags to (1,1,0) by default since the ERF default is different from the amrex default (1,1,1) Also set max_grid_size to very large since the only reason for chopping grids is if Nprocs > Ngrids, and set no_box_split_dir to 2 so that grids are never decomposed in the vertical direction

26  {
27  ParmParse pp("amr");
28  ParmParse pp_erf("erf");
29 
30  // Set the refine_grid_layout flags to (1,1,0) by default
31  pp.add("refine_grid_layout_x",1);
32  pp.add("refine_grid_layout_y",1);
33  pp.add("refine_grid_layout_z",0);
34 
35  // no_box_split_dir tells amrex that the grids must never be split in that
36  // direction; max_grid_size and refine_grid_layout are then ignored there.
37  // ERF sets this to 2 (the z-direction) by default so that no grid is ever
38  // decomposed in the vertical -- no two grids then share a face normal to z, so
39  // no column is chopped between them, which is required, e.g., by the implicit
40  // vertical diffusion solves and by the implicit acoustic substepping. (Several
41  // grids may still sit over the same column, as long as they do not touch; what
42  // those solves cannot do is split one contiguous column at a box seam.) Setting
43  // amr.no_box_split_dir = -1 in the inputs file restores the amrex behavior of
44  // allowing grids to be chopped in every direction; ERF::ReadParameters rejects
45  // that if any level uses erf.substepping_type = Implicit.
46  int no_box_split_dir = 2;
47  pp.queryAdd("no_box_split_dir",no_box_split_dir);
48 
49  // n_proper is the minimum number of coarse cells between coarse-fine boundaries
50  // between levels (ell and ell+1) and levels (ell-1 and ell). We want this to be
51  // greater than or equal to the stencil width (a function of spatial order) divided by
52  // ref_ratio (which can be 2,3 or 4). This ensures that fillpatch at level (ell)
53  // does not need to reach beyond level (ell-1). Here to be conservative we set this to 2
54  // (rather than the amrex default of 1).
55  pp.add("n_proper",2);
56 
57  int max_grid_size = 2048;
58  pp.queryAdd("max_grid_size",max_grid_size);
59 
60  // This will set the default value of blocking_factor to be 1, but will allow
61  // the user to override it in the inputs file or on command line
62  int blocking_factor = 1;
63  pp.queryAdd("blocking_factor",blocking_factor);
64 
65  int n_error_buf = 0;
66  pp.queryAdd("n_error_buf",n_error_buf);
67 
68  amrex::Vector<int> legacy_n_cell;
69  amrex::Vector<int> erf_n_cell;
70  const bool has_legacy_n_cell = pp.queryarr("n_cell", legacy_n_cell);
71  const bool has_erf_n_cell = pp_erf.queryarr("n_cell", erf_n_cell);
72  if (has_erf_n_cell && has_legacy_n_cell) {
73  amrex::Abort("erf.n_cell and amr.n_cell are both specified. Please use only one!");
74  }
75  if (has_erf_n_cell) {
76  pp.addarr("n_cell", erf_n_cell);
77  }
78 
79  ParmParse pp_geometry("geometry");
80  amrex::Vector<amrex::Real> legacy_prob_lo;
81  amrex::Vector<amrex::Real> legacy_prob_hi;
82  amrex::Vector<amrex::Real> legacy_prob_extent;
83  amrex::Vector<int> legacy_is_periodic;
84  amrex::Vector<amrex::Real> erf_prob_lo;
85  amrex::Vector<amrex::Real> erf_prob_hi;
86  amrex::Vector<amrex::Real> erf_prob_extent;
87  amrex::Vector<int> erf_is_periodic;
88 
89  const bool has_legacy_prob_lo = pp_geometry.queryarr("prob_lo", legacy_prob_lo);
90  const bool has_legacy_prob_hi = pp_geometry.queryarr("prob_hi", legacy_prob_hi);
91  const bool has_legacy_prob_extent = pp_geometry.queryarr("prob_extent", legacy_prob_extent);
92  const bool has_legacy_is_periodic = pp_geometry.queryarr("is_periodic", legacy_is_periodic);
93 
94  const bool has_erf_prob_lo = pp_erf.queryarr("prob_lo", erf_prob_lo);
95  const bool has_erf_prob_hi = pp_erf.queryarr("prob_hi", erf_prob_hi);
96  const bool has_erf_prob_extent = pp_erf.queryarr("prob_extent", erf_prob_extent);
97  const bool has_erf_is_periodic = pp_erf.queryarr("is_periodic", erf_is_periodic);
98 
99  if (has_erf_prob_lo && has_legacy_prob_lo) {
100  amrex::Abort("erf.prob_lo and geometry.prob_lo are both specified. Please use only one!");
101  }
102  if ((has_erf_prob_hi || has_erf_prob_extent) && !has_erf_prob_lo) {
103  amrex::Abort("ERF prefixed geometry requires erf.prob_lo together with erf.prob_hi or erf.prob_extent.");
104  }
105  if (has_erf_is_periodic && has_legacy_is_periodic) {
106  amrex::Abort("erf.is_periodic and geometry.is_periodic are both specified. Please use only one!");
107  }
108  if (has_erf_prob_hi && has_legacy_prob_hi) {
109  amrex::Abort("erf.prob_hi and geometry.prob_hi are both specified. Please use only one!");
110  }
111  if (has_erf_prob_extent && has_legacy_prob_extent) {
112  amrex::Abort("erf.prob_extent and geometry.prob_extent are both specified. Please use only one!");
113  }
114  if (has_erf_prob_hi || has_erf_prob_extent) {
115  if (has_legacy_prob_hi || has_legacy_prob_extent) {
116  amrex::Abort("ERF prefixed geometry and legacy geometry.prob_hi/prob_extent are both specified. Please use only one form.");
117  }
118  }
119  if (has_erf_prob_hi && has_erf_prob_extent) {
120  amrex::Vector<amrex::Real> derived_prob_hi(erf_prob_extent.size(), 0.0);
121  for (int i = 0; i < static_cast<int>(erf_prob_extent.size()); ++i) {
122  derived_prob_hi[i] = (i < static_cast<int>(erf_prob_lo.size()) ? erf_prob_lo[i] : 0.0) + erf_prob_extent[i];
123  }
125  derived_prob_hi.size() == erf_prob_hi.size(),
126  "erf.prob_hi and erf.prob_extent have inconsistent lengths.");
127  for (int i = 0; i < static_cast<int>(erf_prob_hi.size()); ++i) {
128  if (derived_prob_hi[i] != erf_prob_hi[i]) {
129  amrex::Abort("erf.prob_hi and erf.prob_extent are both specified but inconsistent.");
130  }
131  }
132  }
133 
134  if (has_erf_prob_lo) {
135  pp_geometry.addarr("prob_lo", erf_prob_lo);
136  }
137  if (has_erf_prob_hi) {
138  pp_geometry.addarr("prob_hi", erf_prob_hi);
139  } else if (has_erf_prob_extent) {
140  amrex::Vector<amrex::Real> derived_prob_hi(erf_prob_extent.size(), 0.0);
141  for (int i = 0; i < static_cast<int>(erf_prob_extent.size()); ++i) {
142  derived_prob_hi[i] = (i < static_cast<int>(erf_prob_lo.size()) ? erf_prob_lo[i] : 0.0) + erf_prob_extent[i];
143  }
144  pp_geometry.addarr("prob_hi", derived_prob_hi);
145  }
146  if (has_erf_is_periodic) {
147  pp_geometry.addarr("is_periodic", erf_is_periodic);
148  }
149 }
ParmParse pp("prob")
AMREX_ALWAYS_ASSERT_WITH_MESSAGE(m_cloud_chamber_config.active, "Cloud Chamber: initializer reached without a parsed configuration")

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ main()

int main ( int  argc,
char *  argv[] 
)

Main driver – creates the ERF object, calls ERF.InitData() and ERF.Evolve()

155 {
156 
157 auto finalize_mpi_and_return = [](int code) {
158 #ifdef AMREX_USE_MPI
159 #ifdef ERF_USE_WW3_COUPLING
160  amrex::MPMD::Finalize();
161 #else
162  MPI_Finalize();
163 #endif
164 #endif
165 return code;
166 };
167 
168 #if defined(AMREX_MPI_THREAD_MULTIPLE)
169  int requested = MPI_THREAD_MULTIPLE;
170  int provided = -1;
171  MPI_Init_thread(&argc, &argv, requested, &provided);
172 #elif defined(AMREX_USE_MPI)
173  MPI_Init(&argc, &argv);
174 #endif
175 
176  if (argc < 2) {
177  // Print usage and exit with error code if no input file was provided.
178  ERF::print_usage(MPI_COMM_WORLD, std::cout);
180  MPI_COMM_WORLD, "No input file provided. Exiting!!");
181  return 1;
182  }
183 
184  // Look for "-h" or "--help" flag and print usage
185  for (auto i = 1; i < argc; i++) {
186  const std::string param(argv[i]);
187  if ((param == "--help") || (param == "-h") || (param == "--usage")) {
188  ERF::print_banner(MPI_COMM_WORLD, std::cout);
189  ERF::print_usage(MPI_COMM_WORLD, std::cout);
190  return 0;
191  }
192  }
193 
194  if (argc >= 2) {
195  for (auto i = 1; i < argc; i++) {
196  if (std::string(argv[i]) == "--describe") {
197  ERF::writeBuildInfo(std::cout);
198  return finalize_mpi_and_return(0);
199  }
200  }
201  }
202 
203  if (!strchr(argv[1], '=') && !amrex::FileSystem::Exists(std::string(argv[1])))
204  {
205  // Print usage and exit with error code if we cannot find the input file
206  ERF::print_usage(MPI_COMM_WORLD, std::cout);
208  MPI_COMM_WORLD, "Input file does not exist = " +
209  std::string(argv[1]) + ". Exiting!!");
210  return finalize_mpi_and_return(1);
211  }
212 
213  // print_banner(MPI_COMM_WORLD, std::cout);
214  // Check to see if the command line contains --describe
215  if (argc >= 2) {
216  for (auto i = 1; i < argc; i++) {
217  if (std::string(argv[i]) == "--describe") {
218  ERF::writeBuildInfo(std::cout);
219  return 0;
220  }
221  }
222  }
223 #ifdef ERF_USE_WW3_COUPLING
224  MPI_Comm comm = amrex::MPMD::Initialize(argc, argv);
225  amrex::Initialize(argc,argv,true,comm,add_par);
226 #else
227  amrex::Initialize(argc,argv,true,MPI_COMM_WORLD,add_par);
228 #endif
229 
230  // Only when argv[1] is actually an inputs file (same test the surrounding code uses).
231  if (argc > 1 && std::string(argv[1]).find('=') == std::string::npos) {
232  CheckForDuplicateInputs(argv[1]);
233  }
234 
235 #ifdef ERF_USE_KOKKOS
236  // Initialize kokkos
237  if (!Kokkos::is_initialized()) {
238  Kokkos::initialize(Kokkos::InitializationSettings()
239  .set_device_id(amrex::Gpu::Device::deviceId()));
240  }
241 #endif
242 
243  // Save the inputs file name for later.
244  if (!strchr(argv[1], '=')) {
245  inputs_name = argv[1];
246  }
247 
248  // timer for profiling
249  BL_PROFILE_VAR("main()", pmain);
250 
251  // wallclock time
252  const double strt_total = amrex::second();
253 
254  {
255  // constructor - reads in parameters from inputs file
256  // - sizes multilevel arrays and data structures
257  ERF erf;
258 
259  // initialize AMR data
260  erf.InitData();
261 
262  // advance solution to final time
263  erf.Evolve();
264 
265  // wallclock time
266  double end_total = amrex::second() - strt_total;
267 
268  // print wallclock time
269  ParallelDescriptor::ReduceRealMax(end_total ,ParallelDescriptor::IOProcessorNumber());
270  if (erf.Verbose()) {
271  amrex::Print() << "\nTotal Time: " << end_total << '\n';
272  }
273  }
274 
275  // destroy timer for profiling
276  BL_PROFILE_VAR_STOP(pmain);
277 #ifdef ERF_USE_WW3_COUPLING
278  MPI_Barrier(MPI_COMM_WORLD);
279 #endif
280 
281 #ifdef ERF_USE_KOKKOS
282  Kokkos::finalize();
283 #endif
284 
285  amrex::Finalize();
286 #ifdef AMREX_USE_MPI
287 #ifdef ERF_USE_WW3_COUPLING
288  amrex::MPMD::Finalize();
289 #else
290  MPI_Finalize();
291 #endif
292 #endif
293 }
void CheckForDuplicateInputs(const std::string &inputs_file)
Definition: ERF_InputsName.H:26
void Evolve()
Definition: ERF.cpp:140
static void print_banner(MPI_Comm, std::ostream &)
Definition: ERF_ConsoleIO.cpp:63
void InitData()
Definition: ERF.cpp:616
static void print_error(MPI_Comm, const std::string &msg)
Definition: ERF_ConsoleIO.cpp:46
static void writeBuildInfo(std::ostream &os)
Definition: ERF_WriteJobInfo.cpp:178
static void print_usage(MPI_Comm, std::ostream &)
Definition: ERF_ConsoleIO.cpp:29
void add_par()
Definition: main.cpp:26
std::string inputs_name
Definition: main.cpp:15
Definition: ERF_InterpolationUtils.H:15
Here is the call graph for this function:

Variable Documentation

◆ inputs_name

std::string inputs_name

Referenced by main(), and ERF::writeJobInfo().