From a3b16ecdf5531eab47f0c7ad388571ccbd98962e Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Thu, 2 Jan 2025 12:58:13 +0800 Subject: [PATCH] add exprtk library --- CMakeLists.txt | 2 ++ GCTLConfig.cmake.in | 2 ++ config.h.in | 1 + example/text_io_ex.cpp | 10 +++--- lib/gctl_config.h | 1 + lib/io/dsv_io.cpp | 75 ++++++++++++++++++++++++++++++++++-------- lib/io/dsv_io.h | 23 ++++++++++++- 7 files changed, 96 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 13ffd60..fa01c46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ option(GCTL_NETCDF "Use the NetCDF library" ON) option(GCTL_FFTW3 "Use the FFTW3 library" ON) option(GCTL_EEMD "Use the EEMD library" ON) option(GCTL_OPENBLAS "Use the Openblas library" OFF) +option(GCTL_EXPRTK "Use the ExprTK library" ON) option(GCTL_CHECK_BOUNDER "Check array's index" OFF) option(GCTL_CHECK_SIZE "Check array's size" OFF) # 传递安装地址给编译期宏变量 @@ -24,6 +25,7 @@ message(STATUS "[GCTL] Use the NetCDF library: " ${GCTL_NETCDF}) message(STATUS "[GCTL] Use the FFTW3 library: " ${GCTL_FFTW3}) message(STATUS "[GCTL] Use the EEMD library: " ${GCTL_EEMD}) message(STATUS "[GCTL] Use the Openblas library: " ${GCTL_OPENBLAS}) +message(STATUS "[GCTL] Use the ExprTK library: " ${GCTL_EXPRTK}) message(STATUS "[GCTL] Check Bounder: " ${GCTL_CHECK_BOUNDER}) message(STATUS "[GCTL] Check Size: " ${GCTL_CHECK_SIZE}) diff --git a/GCTLConfig.cmake.in b/GCTLConfig.cmake.in index bc9dc79..8713ff0 100644 --- a/GCTLConfig.cmake.in +++ b/GCTLConfig.cmake.in @@ -15,6 +15,7 @@ set(@PROJECT_NAME@_FFTW3 @GCTL_FFTW3@) set(@PROJECT_NAME@_EEMD @GCTL_EEMD@) set(@PROJECT_NAME@_OPENMP @GCTL_OPENMP@) set(@PROJECT_NAME@_OPENBLAS @GCTL_OPENBLAS@) +set(@PROJECT_NAME@_EXPRTK @GCTL_EXPRTK@) set(@PROJECT_NAME@_CHECK_BOUNDER @GCTL_CHECK_BOUNDER@) set(@PROJECT_NAME@_CHECK_SIZE @GCTL_CHECK_SIZE@) @@ -23,6 +24,7 @@ message(STATUS "[GCTL] Use the FFTW3 library: " @GCTL_FFTW3@) message(STATUS "[GCTL] Use the EEMD library: " @GCTL_EEMD@) message(STATUS "[GCTL] Use the OpenMP library: " @GCTL_OPENMP@) message(STATUS "[GCTL] Use the Openblas library: " @GCTL_OPENBLAS@) +message(STATUS "[GCTL] Use the ExprTK library: " @GCTL_EXPRTK@) message(STATUS "[GCTL] Check Bounder: " @GCTL_CHECK_BOUNDER@) message(STATUS "[GCTL] Check Size: " @GCTL_CHECK_SIZE@) diff --git a/config.h.in b/config.h.in index 8ff890e..676698d 100644 --- a/config.h.in +++ b/config.h.in @@ -4,5 +4,6 @@ #cmakedefine GCTL_FFTW3 #cmakedefine GCTL_EEMD #cmakedefine GCTL_OPENBLAS +#cmakedefine GCTL_EXPRTK #cmakedefine GCTL_CHECK_BOUNDER #cmakedefine GCTL_CHECK_SIZE \ No newline at end of file diff --git a/example/text_io_ex.cpp b/example/text_io_ex.cpp index 1e343de..d5bd8fd 100644 --- a/example/text_io_ex.cpp +++ b/example/text_io_ex.cpp @@ -54,8 +54,8 @@ int main(int argc, char const *argv[]) try geodsv_io tc; tc.load_text("tmp/topo", ".txt", ColumnHead); tc.set_column_names({"x (m)", "y (m)", "elev (m)"}); - //tc.set_column_type(Float, "x (m)"); - //tc.set_column_type(Float, "y (m)"); + tc.set_column_type(Float, "x (m)"); + tc.set_column_type(Float, "y (m)"); tc.set_column_type(Float, "elev (m)"); array topo; @@ -76,8 +76,11 @@ int main(int argc, char const *argv[]) try tc.add_column(2, "elev_plus"); tc.fill_column(elev, "elev_plus"); + tc.add_column(-1, "dist"); + tc.cal_column("dist := sqrt(C1*C1 + C3*C3)", {"dist", "C1", "C3"}); + tc.add_row(3); - tc.fill_row(array{4.4, 3.3, 2.2, 1.1}, 3); + tc.fill_row(array{5.5, 4.4, 3.3, 2.2, 1.1}, 3); _1s_vector s = tc.get_tags(); s.push_back("Elev = 1000"); @@ -89,7 +92,6 @@ int main(int argc, char const *argv[]) try std::clog << std::setprecision(12) << tc.cell(2, 1) << "\n"; tc.info(); - return 0; } catch(std::exception &e) diff --git a/lib/gctl_config.h b/lib/gctl_config.h index 5971345..4fba59e 100644 --- a/lib/gctl_config.h +++ b/lib/gctl_config.h @@ -4,5 +4,6 @@ #define GCTL_FFTW3 #define GCTL_EEMD /* #undef GCTL_OPENBLAS */ +#define GCTL_EXPRTK /* #undef GCTL_CHECK_BOUNDER */ /* #undef GCTL_CHECK_SIZE */ diff --git a/lib/io/dsv_io.cpp b/lib/io/dsv_io.cpp index b66c88f..977a228 100644 --- a/lib/io/dsv_io.cpp +++ b/lib/io/dsv_io.cpp @@ -433,22 +433,16 @@ int gctl::dsv_io::name_index(std::string name, bool iter_row) // 拾取行号或列号 格式为R和C std::smatch ret; std::regex patr("R(\\d*)"), patc("C(\\d*)"); - if (regex_search(name, ret, patr)) - { - int r = atoi(std::string(ret[1]).c_str()); - if (r >= 1 && r <= row_num_) return r; - else return -1; - } - - if (regex_search(name, ret, patc)) - { - int c = atoi(std::string(ret[1]).c_str()); - if (c >= 1 && c <= col_num_) return c; - else return -1; - } if (iter_row) { + if (regex_search(name, ret, patr)) + { + int r = atoi(std::string(ret[1]).c_str()); + if (r >= 1 && r <= row_num_) return r; + else return -1; + } + for (size_t i = 1; i <= row_num_; i++) { if (table_[i][0].str_ == name) return i; @@ -458,6 +452,13 @@ int gctl::dsv_io::name_index(std::string name, bool iter_row) } else { + if (regex_search(name, ret, patc)) + { + int c = atoi(std::string(ret[1]).c_str()); + if (c >= 1 && c <= col_num_) return c; + else return -1; + } + for (size_t i = 1; i <= col_num_; i++) { if (table_[0][i].str_ == name) return i; @@ -590,6 +591,54 @@ void gctl::dsv_io::add_row(std::string id_name, std::string name) return; } +#ifdef GCTL_EXPRTK + +void gctl::dsv_io::cal_column(std::string expr_str, const std::vector &col_list, int p) +{ + array idx(col_list.size()); + for (size_t i = 0; i < col_list.size(); i++) + { + idx[i] = name_index(col_list[i]); + + if (table_[0][idx[i]].type_ != Int && table_[0][idx[i]].type_ != Float) + { + throw std::runtime_error("[gctl::dsv_io] Invalid column type for numerical calculating."); + } + } + + exprtk::symbol_table symbol_table; + array var(col_list.size()); + + for (size_t i = 0; i < var.size(); i++) + { + symbol_table.add_variable(col_list[i], var[i]); + } + + exprtk::expression expression; + expression.register_symbol_table(symbol_table); + + exprtk::parser parser; + if (!parser.compile(expr_str, expression)) + { + throw std::runtime_error("[gctl::dsv_io] Fail to compile the math expression."); + } + + for (size_t i = 1; i <= row_num_; i++) + { + // Remeber we put the output in the first element + for (size_t j = 1; j < var.size(); j++) + { + var[j] = table_[i][idx[j]].value(); + } + + var[0] = expression.value(); + table_[i][idx[0]].value(var[0], p); + } + return; +} + +#endif // GCTL_EXPRTK + gctl::geodsv_io::geodsv_io(){} gctl::geodsv_io::~geodsv_io(){} diff --git a/lib/io/dsv_io.h b/lib/io/dsv_io.h index 93785c9..aeab508 100644 --- a/lib/io/dsv_io.h +++ b/lib/io/dsv_io.h @@ -28,11 +28,16 @@ #ifndef _GCTL_DSV_IO_H #define _GCTL_DSV_IO_H +#include "../gctl_config.h" #include "../core.h" #include "../utility.h" #include "../geometry.h" #include "regex.h" +#ifdef GCTL_EXPRTK +#include "exprtk.hpp" +#endif // GCTL_EXPRTK + namespace gctl { enum cell_type_e @@ -51,7 +56,7 @@ namespace gctl table_cell() { str_ = ""; - type_ = String; + type_ = Float; out_ok_ = true; } @@ -444,6 +449,22 @@ namespace gctl */ void add_row(std::string id_name, std::string name = ""); +#ifdef GCTL_EXPRTK + + /** + * @brief 使用现有的表格数据计算新的列数据。使用时需要提供计算表达式,例如:C3 := C1 + C2 + * 表示将C1与C2列数据的和保存到C3列,其中C表示计算所使用数据的索引,你也可以使用具体的列名称。 + * + * @note 只有单元格类型为float和Int类型的列数据才能用于计算。计算由exprtk库完成,支持的表达式见其说明文档。 + * + * @param expr_str 计算表达式 如C3 := C1 + C2 + * @param col_list 列索引列表 如C3 C1 C2 (注意保存计算结果的列要放在开头) + * @param p 浮点类数据保存时的有效数字位数 + */ + void cal_column(std::string expr_str, const std::vector &col_list, int p = 6); + +#endif // GCTL_EXPRTK + /** * @brief 填充表格 *