From 9b0ff669e0b598d503b414ebe506c499a968e942 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Mon, 30 Mar 2020 08:42:14 -0400 Subject: [PATCH 1/9] Setup basics --- .gitignore | 1 + .gitlab-ci.yml | 19 +++++ .gitmodules | 9 +++ CMakeLists.txt | 24 ++++++ README.md | 13 +++- src/CMakeLists.txt | 28 +++++++ src/double.hpp | 44 +++++++++++ src/inputs.hpp | 19 +++++ src/main.cpp | 24 ++++++ src/parser.cpp | 136 ++++++++++++++++++++++++++++++++++ src/tests/CMakeLists.txt | 44 +++++++++++ src/tests/parser/inputs.t.cpp | 38 ++++++++++ src/tests/parser/main.cpp | 2 + subprojects/Catch2 | 1 + subprojects/PEGTL | 1 + subprojects/mfix | 1 + 16 files changed, 403 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 .gitlab-ci.yml create mode 100644 .gitmodules create mode 100644 CMakeLists.txt create mode 100644 src/CMakeLists.txt create mode 100644 src/double.hpp create mode 100644 src/inputs.hpp create mode 100644 src/main.cpp create mode 100644 src/parser.cpp create mode 100644 src/tests/CMakeLists.txt create mode 100644 src/tests/parser/inputs.t.cpp create mode 100644 src/tests/parser/main.cpp create mode 160000 subprojects/Catch2 create mode 160000 subprojects/PEGTL create mode 160000 subprojects/mfix diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..6203ce2 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,19 @@ +image: mwm126/mfix-exa:cuda + +variables: + GIT_STRATEGY: fetch + GIT_SUBMODULE_STRATEGY: normal + +###### Test jobs ##### + +test:all: + script: + - cmake -S . + -B build + -G Ninja + - cmake --build build --target unit_tests + - ./build/src/tests/unit_tests + - cmake --build build --target mfix-parser + - find -name inputs |xargs -l ./build/mfix-parser + tags: + - mfix-exa diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..13d03b2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "PEGTL"] + path = subprojects/PEGTL + url = https://github.com/taocpp/PEGTL +[submodule "mfix/subprojects/mfix"] + path = subprojects/mfix + url = https://mfix.netl.doe.gov/gitlab/exa/mfix +[submodule "subprojects/Catch2"] + path = subprojects/Catch2 + url = https://github.com/catchorg/Catch2 diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b700115 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.14) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +project(MFIX-Parser + DESCRIPTION "A parser for MFIX-Exa input files" + HOMEPAGE_URL "https://mfix.netl.doe.gov/gitlab/exa/mfix-parser" + LANGUAGES CXX + ) + +set( CMAKE_EXPORT_COMPILE_COMMANDS ON ) +set(USE_CCACHE "") +find_program(CCACHE_FOUND ccache) +if(CCACHE_FOUND) + set( CMAKE_CXX_COMPILER_LAUNCHER ccache ) +endif() + +add_subdirectory(src) + +set(EXENAME "mfix-parser") +add_executable(${EXENAME} src/main.cpp) +target_link_libraries(${EXENAME} parser) diff --git a/README.md b/README.md index 3dad396..e3caf45 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ # mfix-parser -Repo for parsing and validating MFIX input(s) files for use by mfix-app \ No newline at end of file +Repo for parsing and validating MFIX input(s) files for use by mfix-app. + +This has the MFIX-Exa repo as a submodule in order to test against all existing ``inputs`` files. + + +## Build and Test with CMake + +> python3 pip install cmake # if CMake not installed +> cmake -S. -Bbuild +> cmake --build build +> cd build +> ctest diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..d5adbfc --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,28 @@ +################################################################################ +# inputs Parser +################################################################################ + +add_library(parser + parser.cpp + ) + +target_include_directories(parser PRIVATE + ${CMAKE_SOURCE_DIR}/subprojects/PEGTL/include) + +target_link_libraries(parser PRIVATE stdc++fs) + +add_subdirectory(tests) + +find_program(CLANG_FMT NAMES clang-format-9 clang-format-8 clang-format-7 clang-format) + +if(CLANG_FMT) + get_target_property(_psrcs unit_tests SOURCES) + add_custom_target(fmt_test + COMMAND ${CLANG_FMT} -i ${_psrcs} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/tests + ) + file(GLOB _includes ${PROJECT_SOURCE_DIR}/src/*.hpp) + + add_custom_target(fmt) + add_dependencies(fmt fmt_test) +endif() diff --git a/src/double.hpp b/src/double.hpp new file mode 100644 index 0000000..80e8115 --- /dev/null +++ b/src/double.hpp @@ -0,0 +1,44 @@ +// Copyright (c) 2014-2019 Dr. Colin Hirsch and Daniel Frey +// Please see LICENSE for license or visit https://github.com/taocpp/PEGTL/ + +#ifndef TAO_PEGTL_SRC_EXAMPLES_PEGTL_DOUBLE_HPP +#define TAO_PEGTL_SRC_EXAMPLES_PEGTL_DOUBLE_HPP + +#include + +namespace double_ { +// A grammar for doubles suitable for std::stod without locale support. +// See also: http://en.cppreference.com/w/cpp/string/basic_string/stof + +using namespace TAO_PEGTL_NAMESPACE; + +// clang-format off + struct plus_minus : opt< one< '+', '-' > > {}; + struct dot : one< '.' > {}; + + struct inf : seq< istring< 'i', 'n', 'f' >, + opt< istring< 'i', 'n', 'i', 't', 'y' > > > {}; + + struct nan : seq< istring< 'n', 'a', 'n' >, + opt< one< '(' >, + plus< alnum >, + one< ')' > > > {}; + + template< typename D > + struct number : if_then_else< dot, + plus< D >, + seq< plus< D >, opt< dot, star< D > > > > {}; + + struct e : one< 'e', 'E' > {}; + struct p : one< 'p', 'P' > {}; + struct exponent : seq< plus_minus, plus< digit > > {}; + + struct decimal : seq< number< digit >, opt< e, exponent > > {}; + struct hexadecimal : seq< one< '0' >, one< 'x', 'X' >, number< xdigit >, opt< p, exponent > > {}; + + struct grammar : seq< plus_minus, sor< hexadecimal, decimal, inf, nan > > {}; +// clang-format on + +} // namespace double_ + +#endif diff --git a/src/inputs.hpp b/src/inputs.hpp new file mode 100644 index 0000000..5b66392 --- /dev/null +++ b/src/inputs.hpp @@ -0,0 +1,19 @@ +#ifndef INPUTS_H_ +#define INPUTS_H_ + +#include +#include +#include +#include +#include +#include + +namespace parser { + +using InputInfo = std::map; + +std::optional parse_inputs(std::string); + +} // namespace parser + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..b4f7920 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +#include "inputs.hpp" + +std::string read_file(std::string inputs_file) { + std::ifstream in_stream; + in_stream.open(inputs_file.c_str()); + + std::stringstream str_stream; + str_stream << in_stream.rdbuf(); + return str_stream.str(); +} + +int main(int argc, char *argv[]) { + std::string fname(argv[1]); + auto inputs_str = read_file(fname); + auto maybe_success = parser::parse_inputs(inputs_str); + if (maybe_success.has_value()) { + return 0; + } + return -1; +} diff --git a/src/parser.cpp b/src/parser.cpp new file mode 100644 index 0000000..c7714cf --- /dev/null +++ b/src/parser.cpp @@ -0,0 +1,136 @@ +// standard includes +#include +#include +#include + +// subproject includes +#include + +// includes +#include "double.hpp" +#include "inputs.hpp" + +using namespace TAO_PEGTL_NAMESPACE; + +namespace { + +struct parser_state { + std::string current_name; + parser::InputInfo info; +}; + +} // namespace + +namespace { + +struct escaped_x : seq, rep<2, must>> {}; +struct escaped_u : seq, rep<4, must>> {}; +struct escaped_U : seq, rep<8, must>> {}; +struct escaped_c + : one<'\'', '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v'> {}; + +struct escaped : sor {}; + +struct character + : if_must_else, escaped, utf8::range<0x20, 0x10FFFF>> {}; +struct string_literal : if_must, until, character>> {}; + +struct padded_double : pad {}; + +struct L_FUN : pad, space> {}; +struct R_FUN : pad, space> {}; +struct L_ARR : pad, space> {}; +struct R_ARR : pad, space> {}; +struct L_BLK : pad, space> {}; +struct R_BLK : pad, space> {}; +struct S_CLN : pad, space> {}; + +struct true_literal : string<'t', 'r', 'u', 'e'> {}; +struct false_literal : string<'f', 'a', 'l', 's', 'e'> {}; + +struct boolean_literal : sor {}; + +struct special_identifier : seq, identifier> {}; + +struct name : sor {}; + +struct vector_cell : padded_double {}; + +struct vector : seq>, R_ARR> {}; + +struct vector_attr : vector {}; + +struct value + : sor {}; + +struct comment : if_must, until> {}; + +struct key : list> {}; +struct keyval : seq, string<'='>, pad> {}; +struct grammar : pad, space> {}; + +template struct action {}; + +template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + std::stringstream ss(in.string()); + ss >> st.current_name; + } +}; + +template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + std::stringstream ss(in.string()); + std::string v; + ss >> v; + st.info[st.current_name] = v; + } +}; + +template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + std::stringstream ss(in.string()); + double v; + ss >> v; + st.info[st.current_name] = v; + } +}; + +template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + st.info[st.current_name] = true; + } +}; + +template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + st.info[st.current_name] = false; + } +}; + +std::optional do_parse(std::string str) { + parser_state st; + memory_input in(str, "std::cin"); + if (!parse(in, st)) { + return std::nullopt; + } + return st; +} + +} // namespace + +namespace parser { + +std::optional parse_inputs(std::string str) { + auto maybe_state = do_parse(str); + if (!maybe_state.has_value()) { + return std::nullopt; + } + return maybe_state.value().info; +} +} // namespace parser diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt new file mode 100644 index 0000000..6238fab --- /dev/null +++ b/src/tests/CMakeLists.txt @@ -0,0 +1,44 @@ +################################################################################ +# Parser Tests +################################################################################ + +add_executable(unit_tests EXCLUDE_FROM_ALL + ../parser.cpp + parser/main.cpp + parser/inputs.t.cpp + ) + +target_include_directories(unit_tests PRIVATE + ${CMAKE_SOURCE_DIR}/subprojects/PEGTL/include + ${CMAKE_SOURCE_DIR}/src + ) + +SET(catch2_dir ${PROJECT_SOURCE_DIR}/subprojects/Catch2) + +find_package(Git QUIET) +if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") + # Update submodules as needed + option(GIT_SUBMODULE "Check submodules during build" ON) + if(GIT_SUBMODULE) + message(STATUS "Submodule update") + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + RESULT_VARIABLE GIT_SUBMOD_RESULT) + if(NOT GIT_SUBMOD_RESULT EQUAL "0") + message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules") + endif() + endif() +endif() + +if(NOT EXISTS "${catch2_dir}/CMakeLists.txt") + message(FATAL_ERROR "The submodules were not downloaded! GIT_SUBMODULE was turned off or failed. Please update submodules and try again.") +endif() + +add_subdirectory(${catch2_dir} ${CMAKE_CURRENT_BINARY_DIR}/catch_build) +list(APPEND CMAKE_MODULE_PATH "${catch2_dir}/contrib/") + +target_link_libraries(unit_tests Catch2::Catch2) + +include(CTest) +include(Catch) +catch_discover_tests(unit_tests) diff --git a/src/tests/parser/inputs.t.cpp b/src/tests/parser/inputs.t.cpp new file mode 100644 index 0000000..34685fc --- /dev/null +++ b/src/tests/parser/inputs.t.cpp @@ -0,0 +1,38 @@ +#include "catch2/catch.hpp" + +#include + +TEST_CASE("comment", "[]") { + auto maybe_st = parser::parse_inputs(R"( +# this is a comment +)"); + CHECK(maybe_st.has_value()); +} + +TEST_CASE("integer", "[]") { + auto maybe_st = parser::parse_inputs(R"( +mfix.max_step = 100 +)"); + CHECK(maybe_st.has_value()); +} + +TEST_CASE("double", "[]") { + auto maybe_st = parser::parse_inputs(R"( +mfix.stop_time = 0.20 +)"); + CHECK(maybe_st.has_value()); +} + +TEST_CASE("string", "[]") { + auto maybe_st = parser::parse_inputs(R"( + mfix.particle_init_type = "Auto" +)"); + CHECK(maybe_st.has_value()); +} + +TEST_CASE("array", "[]") { + auto maybe_st = parser::parse_inputs(R"( + mfix.gravity = -9.81 0.0 0.0 +)"); + CHECK(maybe_st.has_value()); +} diff --git a/src/tests/parser/main.cpp b/src/tests/parser/main.cpp new file mode 100644 index 0000000..fc72584 --- /dev/null +++ b/src/tests/parser/main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN // Catch main() - only add to one cpp file +#include "catch2/catch.hpp" diff --git a/subprojects/Catch2 b/subprojects/Catch2 new file mode 160000 index 0000000..6260962 --- /dev/null +++ b/subprojects/Catch2 @@ -0,0 +1 @@ +Subproject commit 62609621088df6723e48ea1d164108303511755b diff --git a/subprojects/PEGTL b/subprojects/PEGTL new file mode 160000 index 0000000..054e446 --- /dev/null +++ b/subprojects/PEGTL @@ -0,0 +1 @@ +Subproject commit 054e44694f6c8cd24259b70f48cc09d84a9af395 diff --git a/subprojects/mfix b/subprojects/mfix new file mode 160000 index 0000000..e4aaa45 --- /dev/null +++ b/subprojects/mfix @@ -0,0 +1 @@ +Subproject commit e4aaa45a48378bf8f220a359994a42066692f194 -- GitLab From dd7c1800f5a8219305950a33b58af7b5595db6b2 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Wed, 1 Apr 2020 00:11:48 -0400 Subject: [PATCH 2/9] Avoid unneeded submodules --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6203ce2..d7ca2ec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,7 +2,6 @@ image: mwm126/mfix-exa:cuda variables: GIT_STRATEGY: fetch - GIT_SUBMODULE_STRATEGY: normal ###### Test jobs ##### -- GitLab From a7f9ca1c0b63b9d15bdf9d2eaccbf53c148c7113 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Wed, 1 Apr 2020 00:21:21 -0400 Subject: [PATCH 3/9] retry --- .gitlab-ci.yml | 2 +- src/tests/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d7ca2ec..c1612ee 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ image: mwm126/mfix-exa:cuda variables: - GIT_STRATEGY: fetch + GIT_STRATEGY: clone ###### Test jobs ##### diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 6238fab..8f84e0e 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -21,7 +21,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") option(GIT_SUBMODULE "Check submodules during build" ON) if(GIT_SUBMODULE) message(STATUS "Submodule update") - execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init subprojects/Catch2 subprojects/PEGTL subprojects/mfix WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE GIT_SUBMOD_RESULT) if(NOT GIT_SUBMOD_RESULT EQUAL "0") -- GitLab From 6f6e8a830c765e3a99996c67d80e2be5b80718b1 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Wed, 1 Apr 2020 00:29:34 -0400 Subject: [PATCH 4/9] Fix --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 13d03b2..25ed73a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,7 +3,7 @@ url = https://github.com/taocpp/PEGTL [submodule "mfix/subprojects/mfix"] path = subprojects/mfix - url = https://mfix.netl.doe.gov/gitlab/exa/mfix + url = ../mfix [submodule "subprojects/Catch2"] path = subprojects/Catch2 url = https://github.com/catchorg/Catch2 -- GitLab From 5fef0f1a912d0cfb175b934be8612c953f045a75 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Wed, 1 Apr 2020 00:30:56 -0400 Subject: [PATCH 5/9] Revert --- .gitlab-ci.yml | 3 ++- src/tests/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c1612ee..6203ce2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,8 @@ image: mwm126/mfix-exa:cuda variables: - GIT_STRATEGY: clone + GIT_STRATEGY: fetch + GIT_SUBMODULE_STRATEGY: normal ###### Test jobs ##### diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 8f84e0e..efe4fd1 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -21,7 +21,7 @@ if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git") option(GIT_SUBMODULE "Check submodules during build" ON) if(GIT_SUBMODULE) message(STATUS "Submodule update") - execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init subprojects/Catch2 subprojects/PEGTL subprojects/mfix + execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE GIT_SUBMOD_RESULT) if(NOT GIT_SUBMOD_RESULT EQUAL "0") -- GitLab From e170f5ef3864a9091ae4930757b18e912d0187f7 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Thu, 2 Apr 2020 10:35:58 -0400 Subject: [PATCH 6/9] Parse doubles and (quoted) strings --- src/inputs.hpp | 3 +- src/parser.cpp | 65 ++++++---- src/tests/parser/inputs.t.cpp | 238 +++++++++++++++++++++++++++++++++- 3 files changed, 277 insertions(+), 29 deletions(-) diff --git a/src/inputs.hpp b/src/inputs.hpp index 5b66392..1edb545 100644 --- a/src/inputs.hpp +++ b/src/inputs.hpp @@ -10,7 +10,8 @@ namespace parser { -using InputInfo = std::map; +using InputValue = std::variant; +using InputInfo = std::map; std::optional parse_inputs(std::string); diff --git a/src/parser.cpp b/src/parser.cpp index c7714cf..bbcf584 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -15,7 +15,8 @@ using namespace TAO_PEGTL_NAMESPACE; namespace { struct parser_state { - std::string current_name; + std::string current_key; + parser::InputValue current_value; parser::InputInfo info; }; @@ -45,23 +46,24 @@ struct L_BLK : pad, space> {}; struct R_BLK : pad, space> {}; struct S_CLN : pad, space> {}; -struct true_literal : string<'t', 'r', 'u', 'e'> {}; -struct false_literal : string<'f', 'a', 'l', 's', 'e'> {}; +// struct true_literal : string<'t', 'r', 'u', 'e'> {}; +// struct false_literal : string<'f', 'a', 'l', 's', 'e'> {}; -struct boolean_literal : sor {}; +// struct boolean_literal : sor {}; -struct special_identifier : seq, identifier> {}; +// struct special_identifier : seq, identifier> {}; -struct name : sor {}; +struct name : identifier {}; -struct vector_cell : padded_double {}; +// struct vector_cell : padded_double {}; -struct vector : seq>, R_ARR> {}; +// struct vector : seq>, R_ARR> {}; -struct vector_attr : vector {}; +// struct vector_attr : vector {}; -struct value - : sor {}; +// struct value : sor {}; +struct value : sor {}; struct comment : if_must, until> {}; @@ -71,11 +73,12 @@ struct grammar : pad, space> {}; template struct action {}; -template <> struct action { +template <> struct action { template static void apply(const Input &in, parser_state &st) { std::stringstream ss(in.string()); - ss >> st.current_name; + ss >> st.current_key; + std::cout << "PARSED key: " << st.current_key << std::endl; } }; @@ -85,7 +88,8 @@ template <> struct action { std::stringstream ss(in.string()); std::string v; ss >> v; - st.info[st.current_name] = v; + st.current_value = v; + std::cout << "Parsed string: " << v << std::endl; } }; @@ -95,21 +99,34 @@ template <> struct action { std::stringstream ss(in.string()); double v; ss >> v; - st.info[st.current_name] = v; + std::cout << "Parsed double: " << v << std::endl; + st.current_value = v; + std::cout << "Parsed double: " << std::get(st.current_value) + << std::endl; } }; -template <> struct action { +// template <> struct action { +// template +// static void apply(const Input &in, parser_state &st) { +// st.info[st.current_key] = true; +// } +// }; + +// template <> struct action { +// template +// static void apply(const Input &in, parser_state &st) { +// st.info[st.current_key] = false; +// } +// }; + +template <> struct action { template static void apply(const Input &in, parser_state &st) { - st.info[st.current_name] = true; - } -}; - -template <> struct action { - template - static void apply(const Input &in, parser_state &st) { - st.info[st.current_name] = false; + std::cout << "key == " << st.current_key << std::endl; + st.info[st.current_key] = st.current_value; + // std::cout << "value == " << st.current_value << std::endl; + // std::cout << "map[key] == " << st.info[st.current_key] << std::endl; } }; diff --git a/src/tests/parser/inputs.t.cpp b/src/tests/parser/inputs.t.cpp index 34685fc..039e15e 100644 --- a/src/tests/parser/inputs.t.cpp +++ b/src/tests/parser/inputs.t.cpp @@ -1,3 +1,5 @@ +#include + #include "catch2/catch.hpp" #include @@ -9,30 +11,258 @@ TEST_CASE("comment", "[]") { CHECK(maybe_st.has_value()); } -TEST_CASE("integer", "[]") { +TEST_CASE("double_int", "[]") { auto maybe_st = parser::parse_inputs(R"( mfix.max_step = 100 )"); - CHECK(maybe_st.has_value()); + REQUIRE(maybe_st.has_value()); + auto info = maybe_st.value(); + auto value = info["mfix.max_step"]; + auto dd = std::get(value); + REQUIRE(dd == 100); } TEST_CASE("double", "[]") { auto maybe_st = parser::parse_inputs(R"( mfix.stop_time = 0.20 )"); - CHECK(maybe_st.has_value()); + REQUIRE(maybe_st.has_value()); + auto info = maybe_st.value(); + auto value = info["mfix.stop_time"]; + auto dd = std::get(value); + REQUIRE(dd == 0.2); } TEST_CASE("string", "[]") { auto maybe_st = parser::parse_inputs(R"( mfix.particle_init_type = "Auto" )"); - CHECK(maybe_st.has_value()); + REQUIRE(maybe_st.has_value()); + auto info = maybe_st.value(); + auto value = info["mfix.particle_init_type"]; + auto ss = std::get(value); + REQUIRE(ss == "\"Auto\""); } +/* TEST_CASE("array", "[]") { auto maybe_st = parser::parse_inputs(R"( mfix.gravity = -9.81 0.0 0.0 +)"); + REQUIRE(maybe_st.has_value()); + auto info = maybe_st.value(); + REQUIRE(info["mfix.gravity"] == "-9.81 0.0 0.0"); +} + +TEST_CASE("whole_file", "[]") { + auto maybe_st = parser::parse_inputs(R"( + +#_______________________________________________________________________ +# Solver settings + +#amrex.fpe_trap_invalid = 1 + +#! Fluid solver +#!-----------------------------------------------------------// +mfix.cfl = 0.5 + +mfix.max_step = 100 +#mfix.stop_time = 0.20 + +mfix.particle_init_type = "Auto" + +mfix.gravity = -9.81 0.0 0.0 + +mfix.drag_type = "BVK2" + +mac_proj.verbose = 0 +nodal_proj.verbose = 1 + +amr.blocking_factor = 1 + +#_______________________________________________________________________ +# Geometry / grids / tiles + +# Maximum level in hierarchy (for now must be 0, i.e., one level in total) +amr.max_level = 0 + +geometry.coord_sys = 0 # 0: Cartesian +geometry.is_periodic = 0 0 0 # Is periodic in each direction? +geometry.prob_lo = 0. 0. 0. # lo corner of physical domain +geometry.prob_hi = 0.004 0.001 0.001 # hi corner of physical domain + +# Number of grid cells in each direction at the coarsest level +amr.n_cell = 20 5 5 + +#! Grids +#!-----------------------------------------------------------// +# Maximum allowable size of each fluid subdomain in the problem domain; + +# Fluid +amr.max_grid_size_x = 1024 +amr.max_grid_size_y = 1024 +amr.max_grid_size_z = 1024 + +# Particles (not with KDTree) +#particles.max_grid_size_x = 32 +#particles.max_grid_size_y = 32 +#particles.max_grid_size_z = 32 + +#! Tiles +#!-----------------------------------------------------------// + +# Fluid: Maximum tile size within each grid +fabarray.mfiter_tile_size = 1024 1024 1024 + +# Particles: Maximum particle title size +particles.tile_size = 1024 1024 1024 + + +#! EB settings +#!-----------------------------------------------------------// + +# Level-set refinement and padding +mfix.levelset__refinement = 4 # levelset resolution + +mfix.write_eb_surface = true # Needed to output eb-surfaces + + +#_______________________________________________________________________ +# Particle load balancing + +#mfix.load_balance_type = "KnapSack" + +amr.dual_grid = 0 +amr.regrid_int = -1 + +#! KnapSack settings +#!-----------------------------------------------------------// +#default is "RunTimeCosts"; options include RunTimeCosts or NumParticles +#this option is only relevant if load_balance_type = KnapSack + +#mfix.knapsack_weight_type = "NumParticles" +#mfix.knapsack_weight_type = "RunTimeCosts" + +#_______________________________________________________________________ +# IO / Checkpointing + +amr.par_ascii_int = -1 +amr.par_ascii_file ="vis" + +amr.plot_int = -1 +amr.plot_file ="plt" + +amr.check_int = -1 +amr.check_file ="chk" + +#! Restart from checkpoint +#!-----------------------------------------------------------// +#amr.restart ="chk00100" + + +#_______________________________________________________________________ +# Fluid model settings +# +fluid.solve = fluid + +fluid.density = constant +fluid.density.constant = 1.0 + +fluid.viscosity = constant +fluid.viscosity.constant = 2.0e-5 + + +#_______________________________________________________________________ +# DEM model settings +# +dem.solve = solid0 + +dem.friction_coeff.pp = 0.0 +dem.friction_coeff.pw = 0.0 + +dem.spring_const.pp = 10.0 +dem.spring_const.pw = 10.0 + +dem.restitution_coeff.solid0.solid0 = 0.8 +dem.restitution_coeff.solid0.wall = 1.0 + +dem.spring_tang_fac.pp = 0.285714285 +dem.spring_tang_fac.pw = 0.285714285 + +dem.damping_tang_fac.pp = 0.5 +dem.damping_tang_fac.pw = 0.5 + + +#_______________________________________________________________________ +# EB geometry +# +mfix.geometry = "cylinder" + +cylinder.internal_flow = true + +cylinder.radius = 0.00045 +cylinder.height = -1.0 + +cylinder.direction = 0 +cylinder.center = 0.0020 0.0005 0.0005 + + +#_______________________________________________________________________ +# Regions for defining ICs and BCs +# +mfix.regions = full-domain bed inflow outflow + +regions.full-domain.lo = 0.0000 0.0000 0.0000 +regions.full-domain.hi = 0.0040 0.0010 0.0010 + +regions.bed.lo = 0.0003 0.0000 0.0000 +regions.bed.hi = 0.0032 0.0010 0.0010 + +regions.inflow.lo = 0.0000 0.0000 0.0000 +regions.inflow.hi = 0.0000 0.0010 0.0010 + +regions.outflow.lo = 0.0040 0.0000 0.0000 +regions.outflow.hi = 0.0040 0.0010 0.0010 + +#_______________________________________________________________________ +# Initial Conditions +# +ic.regions = full-domain bed + +ic.full-domain.fluid.volfrac = 1.0 +ic.full-domain.fluid.velocity = 0.015 0.0 0.0 + +ic.bed.fluid.volfrac = 0.725 +ic.bed.fluid.velocity = 0.00 0.00 0.00 + +ic.bed.solids = solid0 +ic.bed.packing = random + +ic.bed.solid0.volfrac = 0.275 +ic.bed.solid0.velocity = 0.00 0.00 0.00 + +ic.bed.solid0.diameter = constant +ic.bed.solid0.density = constant + +ic.bed.solid0.diameter.constant = 100.0e-6 +ic.bed.solid0.density.constant = 1000.0 + + +#_______________________________________________________________________ +# Boundary Conditions +# +bc.regions = inflow outflow + +bc.inflow = mi +bc.inflow.fluid.volfrac = 1.0 +bc.inflow.fluid.velocity = 0.015 0.0 0.0 + + +bc.outflow = po +bc.outflow.fluid.pressure = 0.0 + )"); CHECK(maybe_st.has_value()); } + +*/ -- GitLab From 733b7db725fb0692ae3ca8e26d957dc2d495176d Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Thu, 2 Apr 2020 13:15:02 -0400 Subject: [PATCH 7/9] Parse whole file --- src/inputs.hpp | 3 +- src/parser.cpp | 65 +++++++++++++---------------------- src/tests/parser/inputs.t.cpp | 36 +++++++++++++------ 3 files changed, 51 insertions(+), 53 deletions(-) diff --git a/src/inputs.hpp b/src/inputs.hpp index 1edb545..0f91fb6 100644 --- a/src/inputs.hpp +++ b/src/inputs.hpp @@ -10,7 +10,8 @@ namespace parser { -using InputValue = std::variant; +using InputArray = std::vector; +using InputValue = std::variant; using InputInfo = std::map; std::optional parse_inputs(std::string); diff --git a/src/parser.cpp b/src/parser.cpp index bbcf584..10ac228 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,6 +1,5 @@ // standard includes #include -#include #include // subproject includes @@ -16,6 +15,7 @@ namespace { struct parser_state { std::string current_key; + std::vector current_vec; parser::InputValue current_value; parser::InputInfo info; }; @@ -35,8 +35,9 @@ struct escaped : sor {}; struct character : if_must_else, escaped, utf8::range<0x20, 0x10FFFF>> {}; struct string_literal : if_must, until, character>> {}; +struct implicit_string : if_must> {}; -struct padded_double : pad {}; +struct whitespace_delimited_array : list>> {}; struct L_FUN : pad, space> {}; struct R_FUN : pad, space> {}; @@ -46,24 +47,10 @@ struct L_BLK : pad, space> {}; struct R_BLK : pad, space> {}; struct S_CLN : pad, space> {}; -// struct true_literal : string<'t', 'r', 'u', 'e'> {}; -// struct false_literal : string<'f', 'a', 'l', 's', 'e'> {}; - -// struct boolean_literal : sor {}; - -// struct special_identifier : seq, identifier> {}; - struct name : identifier {}; -// struct vector_cell : padded_double {}; - -// struct vector : seq>, R_ARR> {}; - -// struct vector_attr : vector {}; - -// struct value : sor {}; -struct value : sor {}; +struct value + : sor {}; struct comment : if_must, until> {}; @@ -78,18 +65,26 @@ template <> struct action { static void apply(const Input &in, parser_state &st) { std::stringstream ss(in.string()); ss >> st.current_key; - std::cout << "PARSED key: " << st.current_key << std::endl; } }; template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + std::stringstream ss(in.string()); + std::string v; + ss >> v; + st.current_value = v.substr(1, v.length() - 2); // strip quotes + } +}; + +template <> struct action { template static void apply(const Input &in, parser_state &st) { std::stringstream ss(in.string()); std::string v; ss >> v; st.current_value = v; - std::cout << "Parsed string: " << v << std::endl; } }; @@ -99,34 +94,22 @@ template <> struct action { std::stringstream ss(in.string()); double v; ss >> v; - std::cout << "Parsed double: " << v << std::endl; - st.current_value = v; - std::cout << "Parsed double: " << std::get(st.current_value) - << std::endl; + st.current_vec.push_back(v); + } +}; +template <> struct action { + template + static void apply(const Input &in, parser_state &st) { + std::stringstream ss(in.string()); + st.current_value = st.current_vec; + st.current_vec.clear(); } }; - -// template <> struct action { -// template -// static void apply(const Input &in, parser_state &st) { -// st.info[st.current_key] = true; -// } -// }; - -// template <> struct action { -// template -// static void apply(const Input &in, parser_state &st) { -// st.info[st.current_key] = false; -// } -// }; template <> struct action { template static void apply(const Input &in, parser_state &st) { - std::cout << "key == " << st.current_key << std::endl; st.info[st.current_key] = st.current_value; - // std::cout << "value == " << st.current_value << std::endl; - // std::cout << "map[key] == " << st.info[st.current_key] << std::endl; } }; diff --git a/src/tests/parser/inputs.t.cpp b/src/tests/parser/inputs.t.cpp index 039e15e..dad519c 100644 --- a/src/tests/parser/inputs.t.cpp +++ b/src/tests/parser/inputs.t.cpp @@ -1,5 +1,3 @@ -#include - #include "catch2/catch.hpp" #include @@ -18,8 +16,9 @@ mfix.max_step = 100 REQUIRE(maybe_st.has_value()); auto info = maybe_st.value(); auto value = info["mfix.max_step"]; - auto dd = std::get(value); - REQUIRE(dd == 100); + auto aa = std::get(value); + CHECK(aa.size() == 1); + CHECK(aa[0] == 100); } TEST_CASE("double", "[]") { @@ -29,8 +28,9 @@ mfix.stop_time = 0.20 REQUIRE(maybe_st.has_value()); auto info = maybe_st.value(); auto value = info["mfix.stop_time"]; - auto dd = std::get(value); - REQUIRE(dd == 0.2); + auto aa = std::get(value); + CHECK(aa.size() == 1); + CHECK(aa[0] == 0.2); } TEST_CASE("string", "[]") { @@ -41,17 +41,33 @@ TEST_CASE("string", "[]") { auto info = maybe_st.value(); auto value = info["mfix.particle_init_type"]; auto ss = std::get(value); - REQUIRE(ss == "\"Auto\""); + CHECK(ss == "Auto"); +} + +TEST_CASE("implicit string", "[]") { + auto maybe_st = parser::parse_inputs(R"( +fluid.solve = fluid +)"); + REQUIRE(maybe_st.has_value()); + auto info = maybe_st.value(); + auto value = info["fluid.solve"]; + auto ss = std::get(value); + CHECK(ss == "fluid"); } -/* TEST_CASE("array", "[]") { auto maybe_st = parser::parse_inputs(R"( mfix.gravity = -9.81 0.0 0.0 )"); + REQUIRE(maybe_st.has_value()); auto info = maybe_st.value(); - REQUIRE(info["mfix.gravity"] == "-9.81 0.0 0.0"); + auto value = info["mfix.gravity"]; + auto aa = std::get(value); + CHECK(aa.size() == 3); + CHECK(aa[0] == -9.81); + CHECK(aa[1] == 0.0); + CHECK(aa[2] == 0.0); } TEST_CASE("whole_file", "[]") { @@ -264,5 +280,3 @@ bc.outflow.fluid.pressure = 0.0 )"); CHECK(maybe_st.has_value()); } - -*/ -- GitLab From d41d1d343814725d251db970c8aa5ee279f37ee9 Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Thu, 2 Apr 2020 13:16:52 -0400 Subject: [PATCH 8/9] Debug --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6203ce2..a841b77 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -14,6 +14,7 @@ test:all: - cmake --build build --target unit_tests - ./build/src/tests/unit_tests - cmake --build build --target mfix-parser + - find -name inputs - find -name inputs |xargs -l ./build/mfix-parser tags: - mfix-exa -- GitLab From e4b95447a1e983cd3d1b08b1861d901e46e89efb Mon Sep 17 00:00:00 2001 From: Mark Meredith Date: Thu, 2 Apr 2020 14:33:16 -0400 Subject: [PATCH 9/9] Update README --- README.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e3caf45..fccc9c2 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,25 @@ Repo for parsing and validating MFIX input(s) files for use by mfix-app. -This has the MFIX-Exa repo as a submodule in order to test against all existing ``inputs`` files. +Uses PEGTL for parsing and Catch2 for tests. +This has the MFIX-Exa repo as a submodule in order to test against existing ``inputs`` files. -## Build and Test with CMake + +## Build > python3 pip install cmake # if CMake not installed > cmake -S. -Bbuild > cmake --build build > cd build > ctest + +## Run Tests + +> cmake --build build --target unit_tests +> ./build/src/tests/unit_tests + +## Run on inputs file + +> cmake --build build --target mfix-parser +> ./build/mfix-parser subprojects/mfix/benchmarks/01-HCS/Size0001/inputs && echo "Parsing succeeded." -- GitLab