From 82b4ed19be046ce9742f5cc2ddfbd4eabf6bda43 Mon Sep 17 00:00:00 2001
From: Mark Meredith <mark.meredith@netl.doe.gov>
Date: Fri, 8 May 2020 11:52:22 -0400
Subject: [PATCH] Better messages

---
 src/inputs/geometry.cpp    | 49 +++++++++++++++++--------------------
 src/inputs/mesh.cpp        | 50 +++++++++++++++++++-------------------
 src/inputs/solver.cpp      | 36 ++++++++++++---------------
 src/inputs/solver.hpp      |  6 +++--
 src/inputs/solver_impl.hpp |  8 +++---
 src/inputs/time.cpp        | 22 ++++++++---------
 6 files changed, 82 insertions(+), 89 deletions(-)

diff --git a/src/inputs/geometry.cpp b/src/inputs/geometry.cpp
index 25ab51f..5cb26f0 100644
--- a/src/inputs/geometry.cpp
+++ b/src/inputs/geometry.cpp
@@ -1,59 +1,54 @@
-#include <iostream>
-
 #include "solver_impl.hpp"
 
 namespace solver {
 
-std::optional<solver::GeometrySettings> make_geometry(solver::InputInfo ii) {
+solver::GeometrySettings make_geometry(solver::InputInfo ii,
+                                       std::vector<InputsMessage> messages) {
   solver::GeometrySettings geo;
 
   if (ii.count(CSG_FILENAME)) {
     auto csg_filename = std::get<solver::StringArray>(ii[CSG_FILENAME]);
     if (csg_filename.size() != 1) {
-      std::cout << CSG_FILENAME << " should only have 1 element" << std::endl;
-      return std::nullopt;
+      messages.push_back(
+          InputsMessage{"geometry.filename should only have 1 element"});
     }
   } else {
     geo.csg_filename = "";
   }
 
   if (!ii.count(PROB_LO)) {
-    require(PROB_LO);
-    return std::nullopt;
+    require(PROB_LO, messages, 0);
   }
   if (!ii.count(PROB_HI)) {
-    require(PROB_HI);
-    return std::nullopt;
+    require(PROB_HI, messages, 0);
   }
   if (!ii.count(PERIODIC)) {
-    require(PERIODIC);
-    return std::nullopt;
+    require(PERIODIC, messages, 0);
   }
   auto lows = std::get<solver::NumberArray>(ii[PROB_LO]);
   auto highs = std::get<solver::NumberArray>(ii[PROB_HI]);
   auto is_periodic = std::get<solver::NumberArray>(ii[PERIODIC]);
   if (lows.size() != 3) {
-    std::cout << "prob_lo needs 3 elements " << std::endl;
-    return std::nullopt;
+    require(PROB_LO, messages, 3);
+  } else {
+    std::get<0>(geo.axes).low = lows[0];
+    std::get<1>(geo.axes).low = lows[1];
+    std::get<2>(geo.axes).low = lows[2];
   }
   if (highs.size() != 3) {
-    std::cout << "prob_hi needs 3 elements " << std::endl;
-    return std::nullopt;
+    require(PROB_HI, messages, 3);
+  } else {
+    std::get<0>(geo.axes).high = highs[0];
+    std::get<1>(geo.axes).high = highs[1];
+    std::get<2>(geo.axes).high = highs[2];
   }
   if (is_periodic.size() != 3) {
-    std::cout << "periodic needs 3 elements " << std::endl;
-    return std::nullopt;
+    require(PERIODIC, messages, 3);
+  } else {
+    std::get<0>(geo.axes).periodic = is_periodic[0];
+    std::get<1>(geo.axes).periodic = is_periodic[1];
+    std::get<2>(geo.axes).periodic = is_periodic[2];
   }
-
-  std::get<0>(geo.axes).high = highs[0];
-  std::get<0>(geo.axes).low = lows[0];
-  std::get<0>(geo.axes).periodic = is_periodic[0];
-  std::get<1>(geo.axes).high = highs[1];
-  std::get<1>(geo.axes).low = lows[1];
-  std::get<1>(geo.axes).periodic = is_periodic[1];
-  std::get<2>(geo.axes).high = highs[2];
-  std::get<2>(geo.axes).low = lows[2];
-  std::get<2>(geo.axes).periodic = is_periodic[2];
   return geo;
 }
 } // namespace solver
diff --git a/src/inputs/mesh.cpp b/src/inputs/mesh.cpp
index 26eaecd..be69dc6 100644
--- a/src/inputs/mesh.cpp
+++ b/src/inputs/mesh.cpp
@@ -1,29 +1,29 @@
-#include <iostream>
-
 #include "solver_impl.hpp"
 
 namespace solver {
 
-std::optional<solver::MeshSettings> make_mesh(solver::InputInfo ii) {
+solver::MeshSettings make_mesh(solver::InputInfo ii,
+                               std::vector<InputsMessage> messages) {
   solver::MeshSettings mesh;
+  auto [mx, my, mz] = mesh.axes;
+
   if (!ii.count(N_CELL)) {
-    require(N_CELL);
-    return std::nullopt;
-  }
-  auto n_cell = std::get<solver::NumberArray>(ii[N_CELL]);
-  if (n_cell.size() != 3) {
-    std::cout << N_CELL << " needs 3 elements " << std::endl;
-    return std::nullopt;
-  }
+    require(N_CELL, messages, 0);
+  } else {
 
-  auto [mx, my, mz] = mesh.axes;
-  mx.n_cell = n_cell[0];
-  my.n_cell = n_cell[1];
-  mz.n_cell = n_cell[2];
+    auto n_cell = std::get<solver::NumberArray>(ii[N_CELL]);
+    if (n_cell.size() != 3) {
+      require(N_CELL, messages, 3);
+    } else {
+      mx.n_cell = n_cell[0];
+      my.n_cell = n_cell[1];
+      mz.n_cell = n_cell[2];
+    }
+  }
 
   auto fabarray_size = std::get<solver::NumberArray>(ii[FABARRAY_TILE_SZ]);
   if (fabarray_size.size() != 3) {
-    std::cout << FABARRAY_TILE_SZ << " needs 3 elements " << std::endl;
+    require(FABARRAY_TILE_SZ, messages, 3);
   } else {
     mx.fluid_max_tile_size = fabarray_size[0];
     my.fluid_max_tile_size = fabarray_size[1];
@@ -32,7 +32,7 @@ std::optional<solver::MeshSettings> make_mesh(solver::InputInfo ii) {
 
   auto part_grid_size = std::get<solver::NumberArray>(ii[PARTICLE_TILE_SZ]);
   if (part_grid_size.size() != 3) {
-    std::cout << PARTICLE_TILE_SZ << " needs 3 elements " << std::endl;
+    require(PARTICLE_TILE_SZ, messages, 3);
   } else {
     mx.particle_max_tile_size = part_grid_size[0];
     my.particle_max_tile_size = part_grid_size[1];
@@ -41,19 +41,19 @@ std::optional<solver::MeshSettings> make_mesh(solver::InputInfo ii) {
 
   auto grid_size_x = std::get<solver::NumberArray>(ii[GRID_SIZE_X]);
   if (grid_size_x.size() != 1) {
-    std::cout << GRID_SIZE_X << " is a scalar " << std::endl;
+    require(GRID_SIZE_X, messages, 1);
   } else {
     mx.max_grid_size = grid_size_x[0];
   }
   auto grid_size_y = std::get<solver::NumberArray>(ii[GRID_SIZE_Y]);
   if (grid_size_y.size() != 1) {
-    std::cout << GRID_SIZE_Y << " is a scalar " << std::endl;
+    require(GRID_SIZE_Y, messages, 1);
   } else {
     my.max_grid_size = grid_size_y[0];
   }
   auto grid_size_z = std::get<solver::NumberArray>(ii[GRID_SIZE_Z]);
   if (grid_size_z.size() != 1) {
-    std::cout << GRID_SIZE_Z << " is a scalar " << std::endl;
+    require(GRID_SIZE_Z, messages, 1);
   } else {
     mz.max_grid_size = grid_size_z[0];
   }
@@ -61,35 +61,35 @@ std::optional<solver::MeshSettings> make_mesh(solver::InputInfo ii) {
   auto particle_grid_size_x =
       std::get<solver::NumberArray>(ii[PARTICLE_GRID_SIZE_X]);
   if (particle_grid_size_x.size() != 1) {
-    std::cout << PARTICLE_GRID_SIZE_X << " is a scalar " << std::endl;
+    require(PARTICLE_GRID_SIZE_X, messages, 1);
   } else {
     mx.particle_max_grid_size = particle_grid_size_x[0];
   }
   auto particle_grid_size_y =
       std::get<solver::NumberArray>(ii[PARTICLE_GRID_SIZE_Y]);
   if (particle_grid_size_y.size() != 1) {
-    std::cout << PARTICLE_GRID_SIZE_Y << " is a scalar " << std::endl;
+    require(PARTICLE_GRID_SIZE_Y, messages, 1);
   } else {
     my.particle_max_grid_size = particle_grid_size_y[0];
   }
   auto particle_grid_size_z =
       std::get<solver::NumberArray>(ii[PARTICLE_GRID_SIZE_Z]);
   if (particle_grid_size_z.size() != 1) {
-    std::cout << PARTICLE_GRID_SIZE_Z << " is a scalar " << std::endl;
+    require(PARTICLE_GRID_SIZE_Z, messages, 1);
   } else {
     mz.particle_max_grid_size = particle_grid_size_z[0];
   }
 
   auto bf = std::get<solver::NumberArray>(ii[BLOCKING_FACTOR]);
   if (bf.size() != 1) {
-    std::cout << BLOCKING_FACTOR << " is a scalar" << std::endl;
+    require(BLOCKING_FACTOR, messages, 1);
   } else {
     mesh.blocking_factor = bf[0];
   }
 
   auto volfrac = std::get<solver::NumberArray>(ii[SMALL_VOLFRAC]);
   if (volfrac.size() != 1) {
-    std::cout << SMALL_VOLFRAC << " is a scalar" << std::endl;
+    require(SMALL_VOLFRAC, messages, 1);
   } else {
     mesh.small_volfrac = volfrac[0];
   }
diff --git a/src/inputs/solver.cpp b/src/inputs/solver.cpp
index fc1a46f..3705a05 100644
--- a/src/inputs/solver.cpp
+++ b/src/inputs/solver.cpp
@@ -1,33 +1,29 @@
-#include <iostream>
 #include <sstream>
 
 #include "solver_impl.hpp"
 
 namespace solver {
 
-void require(std::string key) {
-  std::cout << "missing required key:  " << key << std::endl;
+void require(std::string key, std::vector<InputsMessage> messages, int size) {
+  std::ostringstream oss;
+
+  if (size == 0) {
+    oss << "missing required key: " << key;
+  } else if (size == 1) {
+    oss << key << " is a scalar";
+  } else if (size == 1) {
+    oss << key << " requires " << size << " elements";
+  }
+  messages.push_back(InputsMessage{oss.str()});
 }
 
-std::pair<solver::SolverSettings, std::vector<std::string>>
+std::pair<solver::SolverSettings, std::vector<InputsMessage>>
 make_solver(solver::InputInfo ii) {
-  std::vector<std::string> messages;
+  std::vector<InputsMessage> messages;
   solver::SolverSettings ss;
-  auto new_geo = make_geometry(ii);
-  if (!new_geo.has_value()) {
-    messages.push_back("Problem making geometry");
-  }
-  auto new_mesh = make_mesh(ii);
-  if (!new_mesh.has_value()) {
-    messages.push_back("Problem making mesh");
-  }
-  auto new_time = make_time(ii);
-  if (!new_time.has_value()) {
-    messages.push_back("Problem making time");
-  }
-  ss.geometry = new_geo.value();
-  ss.time = new_time.value();
-  ss.mesh = new_mesh.value();
+  ss.geometry = make_geometry(ii, messages);
+  ss.mesh = make_mesh(ii, messages);
+  ss.time = make_time(ii, messages);
   return std::make_pair(ss, messages);
 }
 
diff --git a/src/inputs/solver.hpp b/src/inputs/solver.hpp
index 0d9aa33..4b4ad0a 100644
--- a/src/inputs/solver.hpp
+++ b/src/inputs/solver.hpp
@@ -57,11 +57,13 @@ struct SolverSettings {
   TimeSettings time;
 };
 
-std::pair<solver::SolverSettings, std::vector<std::string>>
+struct InputsMessage {
+  std::string message;
+};
+std::pair<solver::SolverSettings, std::vector<InputsMessage>>
     make_solver(solver::InputInfo);
 std::string serialize(solver::SolverSettings);
 
-void require(std::string);
 } // namespace solver
 
 #endif
diff --git a/src/inputs/solver_impl.hpp b/src/inputs/solver_impl.hpp
index 5cd67e7..4ab313f 100644
--- a/src/inputs/solver_impl.hpp
+++ b/src/inputs/solver_impl.hpp
@@ -1,7 +1,9 @@
 #include <solver.hpp>
 
 namespace solver {
-std::optional<GeometrySettings> make_geometry(solver::InputInfo);
-std::optional<MeshSettings> make_mesh(solver::InputInfo);
-std::optional<TimeSettings> make_time(solver::InputInfo);
+GeometrySettings make_geometry(solver::InputInfo,
+                               std::vector<InputsMessage> messages);
+MeshSettings make_mesh(solver::InputInfo, std::vector<InputsMessage> messages);
+TimeSettings make_time(solver::InputInfo, std::vector<InputsMessage> messages);
+void require(std::string, std::vector<InputsMessage>, int);
 } // namespace solver
diff --git a/src/inputs/time.cpp b/src/inputs/time.cpp
index bd6601e..202f362 100644
--- a/src/inputs/time.cpp
+++ b/src/inputs/time.cpp
@@ -1,61 +1,59 @@
-#include <iostream>
-
 #include "solver_impl.hpp"
 
 namespace solver {
 
-std::optional<solver::TimeSettings> make_time(solver::InputInfo ii) {
+solver::TimeSettings make_time(solver::InputInfo ii,
+                               std::vector<InputsMessage> messages) {
   solver::TimeSettings time;
 
   auto dt_max = std::get<solver::NumberArray>(ii[DT_MAX]);
   if (dt_max.size() != 1) {
-    std::cout << "dt_max is a scalar: " << dt_max.size() << std::endl;
+    require(DT_MAX, messages, 1);
   } else {
     time.dt_max = dt_max[0];
   }
 
   auto dt_min = std::get<solver::NumberArray>(ii[DT_MIN]);
   if (dt_min.size() != 1) {
-    std::cout << "dt_min is a scalar" << std::endl;
+    require(DT_MIN, messages, 1);
   } else {
     time.dt_min = dt_min[0];
   }
 
   auto maxstep = std::get<solver::NumberArray>(ii[MAXSTEP]);
   if (maxstep.size() != 1) {
-    std::cout << "max_step is a scalar" << std::endl;
+    require(MAXSTEP, messages, 1);
   } else {
     time.max_step = maxstep[0];
   }
 
   if (!ii.count(TSTOP)) {
-    require(TSTOP);
-    return std::nullopt;
+    require(TSTOP, messages, 0);
   }
   auto tstop = std::get<solver::NumberArray>(ii[TSTOP]);
   if (tstop.size() != 1) {
-    std::cout << "tstop is a scalar" << std::endl;
+    require(TSTOP, messages, 1);
   } else {
     time.tstop = tstop[0];
   }
 
   auto fixed_dt = std::get<solver::NumberArray>(ii[FIXED_DT]);
   if (fixed_dt.size() != 1) {
-    std::cout << "fixed_dt is a scalar" << std::endl;
+    require(FIXED_DT, messages, 1);
   } else {
     time.fixed_dt = (fixed_dt[0] != 0);
   }
 
   auto cfl = std::get<solver::NumberArray>(ii[CFL]);
   if (cfl.size() != 1) {
-    std::cout << "cfl is a scalar" << std::endl;
+    require(CFL, messages, 1);
   } else {
     time.cfl = cfl[0];
   }
 
   auto tcoll_ratio = std::get<solver::NumberArray>(ii[TCOLL_RATIO]);
   if (tcoll_ratio.size() != 1) {
-    std::cout << "tcoll_ratio is a scalar" << std::endl;
+    require(TCOLL_RATIO, messages, 1);
   } else {
     time.tcoll_ratio = tcoll_ratio[0];
   }
-- 
GitLab