diff --git a/src/csg/impl/levelset_3d.cpp b/src/csg/impl/levelset_3d.cpp index 8f6821d52041d79501f3b0381daa271a48b4d17e..e3498d3ecf3d973c9455a05c9dfd9c5a9f9353a6 100644 --- a/src/csg/impl/levelset_3d.cpp +++ b/src/csg/impl/levelset_3d.cpp @@ -131,8 +131,10 @@ double signed_distance_3d(const Cylinder &cyl, double xx, double yy, double signed_distance_3d(const LinearExtrude &lin_ext, double xx, double yy, double zz) { // TODO: support height, center and twist - double sign_z = (0 <= zz && zz <= lin_ext.height) ? 1.0 : 1.0; // unused zz warning workaround - return sign_z*signed_distance_2d(lin_ext.group, xx, yy); + double sign_z = (0 <= zz && zz <= lin_ext.height) + ? 1.0 + : 1.0; // unused zz warning workaround + return sign_z * signed_distance_2d(lin_ext.group, xx, yy); } double signed_distance_3d(const RotateExtrude &rot_ext, double xx, double yy, diff --git a/src/inputs/geometry.cpp b/src/inputs/geometry.cpp index 7f48246fcd61d18bc782c78ec0346015319ff010..97cdc75ab69cf6a241403061b4242e7be02ab473 100644 --- a/src/inputs/geometry.cpp +++ b/src/inputs/geometry.cpp @@ -1,60 +1,56 @@ -#include - -#include "solver.hpp" +#include "solver_impl.hpp" namespace solver { -std::optional make_geometry(solver::InputInfo ii) { +solver::GeometrySettings make_geometry(solver::InputInfo ii, + std::vector &messages) { solver::GeometrySettings geo; + geo.csg_filename = ""; if (!ii.count(CSG_FILENAME)) { - require(CSG_FILENAME); - return std::nullopt; - } - auto csg_filename = std::get(ii[CSG_FILENAME]); - if (csg_filename.size() != 1) { - std::cout << CSG_FILENAME << " should only have 1 element" << std::endl; - return std::nullopt; + add_missing_msg(CSG_FILENAME, messages, std::vector{""}); + } else { + auto csg_filename = std::get(ii[CSG_FILENAME]); + if (csg_filename.size() != 1) { + add_msg(CSG_FILENAME, messages, std::vector{""}); + } else { + geo.csg_filename = csg_filename[0]; + } } if (!ii.count(PROB_LO)) { - require(PROB_LO); - return std::nullopt; + add_missing_msg(PROB_LO, messages, std::vector{}); } if (!ii.count(PROB_HI)) { - require(PROB_HI); - return std::nullopt; + add_missing_msg(PROB_HI, messages, std::vector{}); } if (!ii.count(PERIODIC)) { - require(PERIODIC); - return std::nullopt; + add_missing_msg(PERIODIC, messages, std::vector{0, 0, 0}); } auto lows = std::get(ii[PROB_LO]); auto highs = std::get(ii[PROB_HI]); auto is_periodic = std::get(ii[PERIODIC]); if (lows.size() != 3) { - std::cout << "prob_lo needs 3 elements " << std::endl; - return std::nullopt; + add_msg(PROB_LO, messages, std::vector{0, 0, 0}); + } 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; + add_msg(PROB_HI, messages, std::vector{0, 0, 0}); + } 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; + add_msg(PERIODIC, messages, std::vector{0, 0, 0}); + } 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]; } - - geo.csg_filename = csg_filename[0]; - 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 76fdb76f0adf23abc6bfc2e58bc499419226089e..d507fda1cec3ab3fce1f49f1a194833593757035 100644 --- a/src/inputs/mesh.cpp +++ b/src/inputs/mesh.cpp @@ -1,29 +1,30 @@ -#include - -#include "solver.hpp" +#include "solver_impl.hpp" namespace solver { -std::optional make_mesh(solver::InputInfo ii) { +solver::MeshSettings make_mesh(solver::InputInfo ii, + std::vector &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(ii[N_CELL]); - if (n_cell.size() != 3) { - std::cout << N_CELL << " needs 3 elements " << std::endl; - return std::nullopt; - } + // NumberArray defaults = std::vector {0}; + add_msg(N_CELL, messages, std::vector{}); + } 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(ii[N_CELL]); + if (n_cell.size() != 3) { + add_msg(N_CELL, messages, std::vector{0, 0, 0}); + } else { + mx.n_cell = n_cell[0]; + my.n_cell = n_cell[1]; + mz.n_cell = n_cell[2]; + } + } auto fabarray_size = std::get(ii[FABARRAY_TILE_SZ]); if (fabarray_size.size() != 3) { - std::cout << FABARRAY_TILE_SZ << " needs 3 elements " << std::endl; + add_msg(FABARRAY_TILE_SZ, messages, std::vector{0, 0, 0}); } else { mx.fluid_max_tile_size = fabarray_size[0]; my.fluid_max_tile_size = fabarray_size[1]; @@ -32,7 +33,7 @@ std::optional make_mesh(solver::InputInfo ii) { auto part_grid_size = std::get(ii[PARTICLE_TILE_SZ]); if (part_grid_size.size() != 3) { - std::cout << PARTICLE_TILE_SZ << " needs 3 elements " << std::endl; + add_msg(PARTICLE_TILE_SZ, messages, std::vector{0, 0, 0}); } else { mx.particle_max_tile_size = part_grid_size[0]; my.particle_max_tile_size = part_grid_size[1]; @@ -41,19 +42,19 @@ std::optional make_mesh(solver::InputInfo ii) { auto grid_size_x = std::get(ii[GRID_SIZE_X]); if (grid_size_x.size() != 1) { - std::cout << GRID_SIZE_X << " is a scalar " << std::endl; + add_msg(GRID_SIZE_X, messages, std::vector{0}); } else { mx.max_grid_size = grid_size_x[0]; } auto grid_size_y = std::get(ii[GRID_SIZE_Y]); if (grid_size_y.size() != 1) { - std::cout << GRID_SIZE_Y << " is a scalar " << std::endl; + add_msg(GRID_SIZE_Y, messages, std::vector{0}); } else { my.max_grid_size = grid_size_y[0]; } auto grid_size_z = std::get(ii[GRID_SIZE_Z]); if (grid_size_z.size() != 1) { - std::cout << GRID_SIZE_Z << " is a scalar " << std::endl; + add_msg(GRID_SIZE_Z, messages, std::vector{0}); } else { mz.max_grid_size = grid_size_z[0]; } @@ -61,35 +62,35 @@ std::optional make_mesh(solver::InputInfo ii) { auto particle_grid_size_x = std::get(ii[PARTICLE_GRID_SIZE_X]); if (particle_grid_size_x.size() != 1) { - std::cout << PARTICLE_GRID_SIZE_X << " is a scalar " << std::endl; + add_msg(PARTICLE_GRID_SIZE_X, messages, std::vector{0}); } else { mx.particle_max_grid_size = particle_grid_size_x[0]; } auto particle_grid_size_y = std::get(ii[PARTICLE_GRID_SIZE_Y]); if (particle_grid_size_y.size() != 1) { - std::cout << PARTICLE_GRID_SIZE_Y << " is a scalar " << std::endl; + add_msg(PARTICLE_GRID_SIZE_Y, messages, std::vector{0}); } else { my.particle_max_grid_size = particle_grid_size_y[0]; } auto particle_grid_size_z = std::get(ii[PARTICLE_GRID_SIZE_Z]); if (particle_grid_size_z.size() != 1) { - std::cout << PARTICLE_GRID_SIZE_Z << " is a scalar " << std::endl; + add_msg(PARTICLE_GRID_SIZE_Z, messages, std::vector{0}); } else { mz.particle_max_grid_size = particle_grid_size_z[0]; } auto bf = std::get(ii[BLOCKING_FACTOR]); if (bf.size() != 1) { - std::cout << BLOCKING_FACTOR << " is a scalar" << std::endl; + add_msg(BLOCKING_FACTOR, messages, std::vector{0}); } else { mesh.blocking_factor = bf[0]; } auto volfrac = std::get(ii[SMALL_VOLFRAC]); if (volfrac.size() != 1) { - std::cout << SMALL_VOLFRAC << " is a scalar" << std::endl; + add_msg(SMALL_VOLFRAC, messages, std::vector{0}); } else { mesh.small_volfrac = volfrac[0]; } diff --git a/src/inputs/parser.cpp b/src/inputs/parser.cpp index 2a4c78b34dc567eefba2a8c2e6324cbcf1d2b8ee..68a65c2f84a72729a347849a2af24ddef3d0428f 100644 --- a/src/inputs/parser.cpp +++ b/src/inputs/parser.cpp @@ -1,5 +1,6 @@ // standard includes #include +#include #include // subproject includes @@ -136,9 +137,18 @@ template <> struct action { std::optional do_parse(std::string str) { parser_state st; memory_input in(str, "std::cin"); - if (!parse(in, st)) { - return std::nullopt; + + try { + if (!parse(in, st)) { + return std::nullopt; + } + } catch (const parse_error &e) { + const auto p = e.positions.front(); + std::cerr << e.what() << std::endl + << in.line_at(p) << std::endl + << std::string(p.byte_in_line, ' ') << '^' << std::endl; } + return st; } diff --git a/src/inputs/solver.cpp b/src/inputs/solver.cpp index 02a506defd4dd53ebc8d38e3afea83f1d310d735..c80a919ecd7b18b0d26938e7f9fffb910794d1a4 100644 --- a/src/inputs/solver.cpp +++ b/src/inputs/solver.cpp @@ -1,44 +1,62 @@ -#include -#include #include #include "solver.hpp" +#include "solver_impl.hpp" namespace solver { -void require(std::string key) { - std::cout << "missing required key: " << key << std::endl; -} +void add_missing_msg(std::string key, std::vector &messages, + Array defaults) { + std::ostringstream oss; -std::optional do_make_solver(solver::InputInfo ii) { - solver::SolverSettings ss; - auto new_geo = make_geometry(ii); - if (!new_geo.has_value()) { - std::cout << "Problem making geometry" << std::endl; - return std::nullopt; + oss << key << " is missing; using defaults: "; + if (auto sarray = std::get_if(&defaults)) { + for (auto def : *sarray) { + oss << def << " "; + } + } else if (auto narray = std::get_if(&defaults)) { + for (auto def : *narray) { + oss << def << " "; + } } - auto new_mesh = make_mesh(ii); - if (!new_mesh.has_value()) { - std::cout << "Problem making mesh" << std::endl; - return std::nullopt; + messages.push_back(InputsMessage{oss.str()}); +} + +void add_msg(std::string key, std::vector &messages, + Array defaults) { + std::ostringstream oss; + std::ostringstream defs; + int size = 0; + + if (auto sarray = std::get_if(&defaults)) { + size = sarray->size(); + for (auto def : *sarray) { + defs << def << " "; + } + } else if (auto narray = std::get_if(&defaults)) { + size = narray->size(); + for (auto def : *narray) { + defs << def << " "; + } } - auto new_time = make_time(ii); - if (!new_time.has_value()) { - std::cout << "Problem making time" << std::endl; - return std::nullopt; + + if (size == 1) { + oss << key << " should be a scalar; using defaults: "; + } else { + oss << key << " should have " << size << " elements; using defaults"; } - ss.geometry = new_geo.value(); - ss.time = new_time.value(); - ss.mesh = new_mesh.value(); - return ss; + oss << defs.str(); + messages.push_back(InputsMessage{oss.str()}); } -std::optional make_solver(solver::InputInfo ii) { - auto maybe_state = do_make_solver(ii); - if (!maybe_state.has_value()) { - return std::nullopt; - } - return maybe_state.value(); +std::pair> +make_solver(solver::InputInfo ii) { + std::vector messages; + solver::SolverSettings ss; + ss.geometry = make_geometry(ii, messages); + ss.mesh = make_mesh(ii, messages); + ss.time = make_time(ii, messages); + return std::make_pair(ss, messages); } std::string serialize(solver::SolverSettings settings) { diff --git a/src/inputs/solver.hpp b/src/inputs/solver.hpp index 8136360a5354d92c8b33eac5edba343b0274c104..0245e1ddc24bbdb1954704fab5f45903cef1a737 100644 --- a/src/inputs/solver.hpp +++ b/src/inputs/solver.hpp @@ -15,7 +15,8 @@ namespace solver { using NumberArray = std::vector; using StringArray = std::vector; -using InputInfo = std::map>; +using Array = std::variant; +using InputInfo = std::map; std::optional parse_inputs(std::string); @@ -57,13 +58,13 @@ struct SolverSettings { TimeSettings time; }; -std::optional make_solver(solver::InputInfo); -std::optional make_geometry(solver::InputInfo); -std::optional make_mesh(solver::InputInfo); -std::optional make_time(solver::InputInfo); +struct InputsMessage { + std::string message; +}; +std::pair> + 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 new file mode 100644 index 0000000000000000000000000000000000000000..b7e0c0ab9a13ceeedd8521b151ad2a0929c0ccc9 --- /dev/null +++ b/src/inputs/solver_impl.hpp @@ -0,0 +1,9 @@ +#include + +namespace solver { +GeometrySettings make_geometry(solver::InputInfo, std::vector &); +MeshSettings make_mesh(solver::InputInfo, std::vector &); +TimeSettings make_time(solver::InputInfo, std::vector &); +void add_missing_msg(std::string key, std::vector &, Array); +void add_msg(std::string key, std::vector &, Array); +} // namespace solver diff --git a/src/inputs/tests/solver.t.cpp b/src/inputs/tests/solver.t.cpp index f160a05d8a3498ea5e2a5a18268e1b34d65490f4..e0ed6f74fee04ad5edaf28d60dd9e6b234289cab 100644 --- a/src/inputs/tests/solver.t.cpp +++ b/src/inputs/tests/solver.t.cpp @@ -5,12 +5,6 @@ #include #include -TEST_CASE("empty (invalid) map", "[]") { - solver::InputInfo ii; - auto maybe_sv = solver::make_solver(ii); - CHECK_FALSE(maybe_sv.has_value()); -} - TEST_CASE("from_origin", "[]") { solver::InputInfo ii; @@ -42,9 +36,7 @@ TEST_CASE("from_origin", "[]") { ii[CFL] = solver::NumberArray({0.77}); ii[TCOLL_RATIO] = solver::NumberArray({49.2}); - auto maybe_sv = solver::make_solver(ii); - REQUIRE(maybe_sv.has_value()); - auto sv = maybe_sv.value(); + auto [sv, messages] = solver::make_solver(ii); SECTION(" Geometry fields ") { auto [xx, yy, zz] = sv.geometry.axes; diff --git a/src/inputs/time.cpp b/src/inputs/time.cpp index 483a00105712dba32bce4422b219367c85623350..3748610be5a3e488bb1c6c2cdac0c17cabcbde2e 100644 --- a/src/inputs/time.cpp +++ b/src/inputs/time.cpp @@ -1,61 +1,59 @@ -#include - -#include "solver.hpp" +#include "solver_impl.hpp" namespace solver { -std::optional make_time(solver::InputInfo ii) { +solver::TimeSettings make_time(solver::InputInfo ii, + std::vector &messages) { solver::TimeSettings time; auto dt_max = std::get(ii[DT_MAX]); if (dt_max.size() != 1) { - std::cout << "dt_max is a scalar: " << dt_max.size() << std::endl; + add_msg(DT_MAX, messages, std::vector{0}); } else { time.dt_max = dt_max[0]; } auto dt_min = std::get(ii[DT_MIN]); if (dt_min.size() != 1) { - std::cout << "dt_min is a scalar" << std::endl; + add_msg(DT_MIN, messages, std::vector{0}); } else { time.dt_min = dt_min[0]; } auto maxstep = std::get(ii[MAXSTEP]); if (maxstep.size() != 1) { - std::cout << "max_step is a scalar" << std::endl; + add_msg(MAXSTEP, messages, std::vector{0}); } else { time.max_step = maxstep[0]; } if (!ii.count(TSTOP)) { - require(TSTOP); - return std::nullopt; + add_msg(TSTOP, messages, std::vector{0}); } auto tstop = std::get(ii[TSTOP]); if (tstop.size() != 1) { - std::cout << "tstop is a scalar" << std::endl; + add_msg(TSTOP, messages, std::vector{0}); } else { time.tstop = tstop[0]; } auto fixed_dt = std::get(ii[FIXED_DT]); if (fixed_dt.size() != 1) { - std::cout << "fixed_dt is a scalar" << std::endl; + add_msg(FIXED_DT, messages, std::vector{0}); } else { time.fixed_dt = (fixed_dt[0] != 0); } auto cfl = std::get(ii[CFL]); if (cfl.size() != 1) { - std::cout << "cfl is a scalar" << std::endl; + add_msg(CFL, messages, std::vector{0}); } else { time.cfl = cfl[0]; } auto tcoll_ratio = std::get(ii[TCOLL_RATIO]); if (tcoll_ratio.size() != 1) { - std::cout << "tcoll_ratio is a scalar" << std::endl; + add_msg(TCOLL_RATIO, messages, std::vector{0}); } else { time.tcoll_ratio = tcoll_ratio[0]; } diff --git a/subprojects/PEGTL b/subprojects/PEGTL index ede3ce17aef7da27648b195dc77814cb1d3c313d..47e878ad4fd72c91253c9d47b6f17e001ca2dfcf 160000 --- a/subprojects/PEGTL +++ b/subprojects/PEGTL @@ -1 +1 @@ -Subproject commit ede3ce17aef7da27648b195dc77814cb1d3c313d +Subproject commit 47e878ad4fd72c91253c9d47b6f17e001ca2dfcf