From 3bc94c1db223d2b25df9bee36a9e2d79521e42a7 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Fri, 10 Jan 2025 16:34:55 +0800 Subject: [PATCH 01/12] tmp --- lib/geometry/point2c.h | 15 +++++--------- lib/geometry/point2p.h | 14 +++++++++++++ lib/io/dsv_io.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++ lib/io/dsv_io.h | 38 +++++++++++++++++++++++++++++++++++ lib/io/gmsh_io.cpp | 11 +++++++++++ lib/io/gmsh_io.h | 1 + lib/maths/mathfunc_t.h | 6 ++++++ 7 files changed, 120 insertions(+), 10 deletions(-) diff --git a/lib/geometry/point2c.h b/lib/geometry/point2c.h index a58b291..341461e 100644 --- a/lib/geometry/point2c.h +++ b/lib/geometry/point2c.h @@ -531,25 +531,20 @@ namespace gctl * @brief 生成一维网格节点数组,其中每一个点都是一个二维坐标点。 * * @param out_ps 返回网格节点数组 - * @param[in] xmin x最小值 - * @param[in] xmax x最大值 + * @param[in] x_st x起始值 + * @param[in] x_ed x终止值 * @param[in] dx x间隔 * @param[in] ele 高程值 */ template - void grid_points_1d(array> &out_ps, T xmin, T xmax, T dx, T ele) + void grid_points_1d(array> &out_ps, T x_st, T x_ed, T dx, T ele) { - if (xmin >= xmax || xmin + dx > xmax || dx <= 0) - { - throw std::invalid_argument("[gctl::grid_points_1d] Invalid parameters."); - } - - int xnum = round((xmax - xmin)/dx) + 1; + int xnum = round(std::abs((x_ed - x_st)/dx)) + 1; out_ps.resize(xnum); for (int i = 0; i < xnum; i++) { - out_ps[i].x = xmin + dx*i; + out_ps[i].x = x_st + dx*i; out_ps[i].y = ele; } return; diff --git a/lib/geometry/point2p.h b/lib/geometry/point2p.h index 064aef2..9664244 100644 --- a/lib/geometry/point2p.h +++ b/lib/geometry/point2p.h @@ -375,6 +375,20 @@ namespace gctl } return false; } + + template + void grid_points_1d(array> &obsp, T deg_st, T deg_ed, T ddeg, T rad) + { + int m = round(std::abs((deg_st - deg_ed)/ddeg)) + 1; + + obsp.resize(m); + for (size_t i = 0; i < m; i++) + { + obsp[i].arc = arc(deg_st + i*ddeg); + obsp[i].rad = rad; + } + return; + } } #endif // _GCTL_POINT2P_H \ No newline at end of file diff --git a/lib/io/dsv_io.cpp b/lib/io/dsv_io.cpp index f587243..4bd91d2 100644 --- a/lib/io/dsv_io.cpp +++ b/lib/io/dsv_io.cpp @@ -963,6 +963,29 @@ void gctl::geodsv_io::fill_column_point2dc(const array &data, std::str return; } +void gctl::geodsv_io::fill_column_point2dp(const array &data, int rid, int cid, int p) +{ + if (rid > col_num_ || cid > col_num_ || rid == cid || rid <= 0 || cid <= 0) + { + throw std::runtime_error("[gctl::geodsv_io] Invalid column index."); + } + + std::stringstream ss; + std::string s; + for (size_t i = 1; i <= std::min(row_num_, (int) data.size()); i++) + { + table_[i][rid].value(data[i - 1].rad, p); + table_[i][cid].value(data[i - 1].arc, p); + } + return; +} + +void gctl::geodsv_io::fill_column_point2dp(const array &data, std::string rname, std::string cname, int p) +{ + fill_column_point2dp(data, name_index(rname, false), name_index(cname, false), p); + return; +} + void gctl::geodsv_io::fill_column_point3dc(const array &data, int xid, int yid, int zid, int p) { if (xid > col_num_ || yid > col_num_ || zid > col_num_ || xid == yid || yid == zid || xid == zid @@ -1035,6 +1058,28 @@ void gctl::geodsv_io::get_column_point2dc(array &data, std::string xna return; } +void gctl::geodsv_io::get_column_point2dp(array &data, int rid, int cid) +{ + if (rid > col_num_ || cid > col_num_ || rid == cid || rid <= 0 || cid <= 0) + { + throw std::runtime_error("[gctl::geodsv_io] Invalid column index."); + } + + data.resize(row_num_); + for (size_t i = 1; i <= row_num_; i++) + { + data[i - 1].rad = table_[i][rid].value(); + data[i - 1].arc = table_[i][cid].value(); + } + return; +} + +void gctl::geodsv_io::get_column_point2dp(array &data, std::string rname, std::string cname) +{ + get_column_point2dp(data, name_index(rname, false), name_index(cname, false)); + return; +} + void gctl::geodsv_io::get_column_point3dc(array &data, int xid, int yid, int zid) { if (xid > col_num_ || yid > col_num_ || zid > col_num_ || xid == yid || yid == zid || xid == zid diff --git a/lib/io/dsv_io.h b/lib/io/dsv_io.h index c6f2fba..f8c8d7e 100644 --- a/lib/io/dsv_io.h +++ b/lib/io/dsv_io.h @@ -828,6 +828,26 @@ namespace gctl */ void fill_column_point2dc(const array &data, std::string xname, std::string yname, int p = 6); + /** + * @brief 填充二维坐标列 + * + * @param rid rad坐标列索引 从1开始 + * @param cid arc坐标列索引 从1开始 + * @param data 返回的二维坐标数据 + * @param p 填入的浮点数据有效位数(精度) + */ + void fill_column_point2dp(const array &data, int rid, int cid, int p = 6); + + /** + * @brief 填充二维坐标列 + * + * @param rname rad坐标列名称 + * @param cname arc坐标列名称 + * @param data 返回的二维坐标数据 + * @param p 填入的浮点数据有效位数(精度) + */ + void fill_column_point2dp(const array &data, std::string rname, std::string cname, int p = 6); + /** * @brief 填充三维坐标列 * @@ -890,6 +910,24 @@ namespace gctl */ void get_column_point2dc(array &data, std::string xname, std::string yname); + /** + * @brief 读取二维坐标列 + * + * @param rid rad坐标列索引 从1开始 + * @param cid arc坐标列索引 从1开始 + * @param data 返回的二维坐标数据 + */ + void get_column_point2dp(array &data, int rid, int cid); + + /** + * @brief 读取二维坐标列 + * + * @param rname rad坐标列名称 + * @param cname arc坐标列名称 + * @param data 返回的二维坐标数据 + */ + void get_column_point2dp(array &data, std::string rname, std::string cname); + /** * @brief 读取三维坐标列 * diff --git a/lib/io/gmsh_io.cpp b/lib/io/gmsh_io.cpp index e1b7d7b..fefd4fb 100644 --- a/lib/io/gmsh_io.cpp +++ b/lib/io/gmsh_io.cpp @@ -152,4 +152,15 @@ void gctl::gmshio::save_physical_groups(const array &phy_gr } gmsh_out << "$EndPhysicalNames\n"; return; +} + +int gctl::gmshio::physical_name2tag(const array &phy_groups, std::string name) +{ + for (size_t i = 0; i < phy_groups.size(); i++) + { + if (phy_groups[i].name == name) return phy_groups[i].phys_tag; + } + + throw std::runtime_error("[gctl::gmshio::physical_name2tag] Physical group name not found."); + return -1; } \ No newline at end of file diff --git a/lib/io/gmsh_io.h b/lib/io/gmsh_io.h index 41ba2a7..cb4c7d0 100644 --- a/lib/io/gmsh_io.h +++ b/lib/io/gmsh_io.h @@ -61,6 +61,7 @@ namespace gctl void read_physical_groups(array &phy_groups); void save_physical_groups(const array &phy_groups); + int physical_name2tag(const array &phy_groups, std::string name); template void read_node(array> &out_nodes); template void read_node(array> &out_nodes); diff --git a/lib/maths/mathfunc_t.h b/lib/maths/mathfunc_t.h index c6baae5..040402d 100644 --- a/lib/maths/mathfunc_t.h +++ b/lib/maths/mathfunc_t.h @@ -48,6 +48,12 @@ namespace gctl return deg*GCTL_Pi/180.0; } + template + inline T deg(T arc) + { + return arc*180.0/GCTL_Pi; + } + template inline T sind(T deg) { From 363a4499cad31c9c76e61c04aeff133f20b5ab73 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Fri, 10 Jan 2025 22:31:43 +0800 Subject: [PATCH 02/12] update array --- example/CMakeLists.txt | 2 +- example/array_ex.cpp | 5 ++++- lib/core/array.h | 35 +++++++++++++++++++++++++++++------ 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 6b39b6d..71fe3e9 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -29,4 +29,4 @@ add_example(multinary_ex OFF) add_example(text_io_ex OFF) add_example(getoption_ex OFF) add_example(process_ex OFF) -add_example(array_ex OFF) \ No newline at end of file +add_example(array_ex ON) \ No newline at end of file diff --git a/example/array_ex.cpp b/example/array_ex.cpp index 08f39d9..9f4ab9f 100644 --- a/example/array_ex.cpp +++ b/example/array_ex.cpp @@ -42,7 +42,7 @@ int main(int argc, char const *argv[]) try A.linear2log(2); A.show(); - A.parallel_for_each([](double &a, size_t i){a += 1;}); + A.for_each([](double &a){a += 1;}); A.show(); A.sequence(1.0, 0.5, 3, 4, 1); @@ -64,6 +64,9 @@ int main(int argc, char const *argv[]) try P.sequence(point3dc(0, 0, 0), point3dc(2, 1, 0.5)); P.show(std::cout, '\n'); + array Px = P.extract([](const point3dc &p)->double{return p.x;}); + Px.show(); + // create a new 2D array matrix C(5, 5, 1); C.sequence(0, 1, 10); diff --git a/lib/core/array.h b/lib/core/array.h index 9d89361..3b63eb0 100644 --- a/lib/core/array.h +++ b/lib/core/array.h @@ -593,22 +593,45 @@ namespace gctl /** * @brief 并行执行指定操作 * - * 对数组中的每个元素并行执行给定的操作,第一个参数为数组元素的引用,第二个参数为元素的索引。 - * 例如:[](ArrValType &a, size_t i){do something here...} + * 对数组中的每个元素并行执行指定的操作,参数为数组元素的引用。 + * 例如:[](ArrValType &a){do something here...} * - * @tparam BiaryOp 二元操作类型 第一个参数为数组元素的引用,第二个参数为元素的索引 + * @tparam UnaryOp 一元操作类型 参数为数组元素的引用 * @param op 要执行的操作 */ - template - void parallel_for_each(BiaryOp op) + template + void for_each(UnaryOp op) { #pragma omp parallel for for (size_t i = 0; i < length_; i++) { - op(val_[i], i); + op(val_[i]); } + return; } + /** + * @brief 并行执行提取操作(比如提取结构体的成员变量数组) + * + * 对数组中的每个元素并行执行给定的操作并将输出组成一个新数组,参数为数组元素的常引用。 + * 例如:[](const ArrValType &a)->OutType{do something here...} + * + * @tparam UnaryOp 一元操作类型 参数为数组元素的引用 + * @param op 要执行的操作 + */ + template + array extract(UnaryOp op) + { + array arr(length_); + #pragma omp parallel for + for (size_t i = 0; i < length_; i++) + { + arr[i] = op(val_[i]); + } + return arr; + } + + /** * @brief Display the elements. * From fc8442bacd5e07e780a021c244d32cd80550a2d6 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Sat, 11 Jan 2025 21:18:26 +0800 Subject: [PATCH 03/12] tmp update --- example/array_ex.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/example/array_ex.cpp b/example/array_ex.cpp index 9f4ab9f..9729e6f 100644 --- a/example/array_ex.cpp +++ b/example/array_ex.cpp @@ -30,6 +30,11 @@ using namespace gctl; +double get_x(const point3dc &p) +{ + return p.x; +} + int main(int argc, char const *argv[]) try { // create a new array and give initial values @@ -64,7 +69,8 @@ int main(int argc, char const *argv[]) try P.sequence(point3dc(0, 0, 0), point3dc(2, 1, 0.5)); P.show(std::cout, '\n'); - array Px = P.extract([](const point3dc &p)->double{return p.x;}); + //array Px = P.extract([](const point3dc &p)->double{return p.x;}); + array Px = P.extract(get_x); Px.show(); // create a new 2D array From b54c1b319128edd97adb4ab4a362ae09bd16d1d7 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Sat, 18 Jan 2025 19:21:11 +0800 Subject: [PATCH 04/12] tmp --- lib/io/dsv_io.cpp | 23 ----------------------- lib/io/dsv_io.h | 18 ++---------------- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/lib/io/dsv_io.cpp b/lib/io/dsv_io.cpp index 4bd91d2..cc5a13a 100644 --- a/lib/io/dsv_io.cpp +++ b/lib/io/dsv_io.cpp @@ -512,19 +512,6 @@ void gctl::dsv_io::row_output(std::string name, switch_type_e s) return; } -void gctl::dsv_io::add_column(std::string name) -{ - table_cell empty_cell; - for (size_t i = 0; i < table_.size(); i++) - { - table_[i].push_back(empty_cell); - } - - table_[0].back().str_ = name; - col_num_++; - return; -} - void gctl::dsv_io::add_column(int idx, std::string name) { table_cell empty_cell; @@ -557,16 +544,6 @@ void gctl::dsv_io::add_column(std::string id_name, std::string name) return; } -void gctl::dsv_io::add_row(std::string name) -{ - std::vector empty_line; - table_.push_back(empty_line); - table_.back().resize(col_num_ + 1); - table_.back().front().str_ = name; - row_num_++; - return; -} - void gctl::dsv_io::add_row(int idx, std::string name) { std::vector empty_line; diff --git a/lib/io/dsv_io.h b/lib/io/dsv_io.h index f8c8d7e..7fafe8a 100644 --- a/lib/io/dsv_io.h +++ b/lib/io/dsv_io.h @@ -402,16 +402,9 @@ namespace gctl * @param s 设置输出类型 */ void row_output(std::string name, switch_type_e s = Disable); - - /** - * @brief 在表格末尾添加一个空白列 - * - * @param name 设置列名称 - */ - void add_column(std::string name = ""); /** - * @brief 在索引为idx的列插入一个空白列 + * @brief 在索引为idx的列之后插入一个空白列 * * @param idx 列索引 小于等于0时将在表尾添加一列 * @param name 设置列名称 @@ -419,20 +412,13 @@ namespace gctl void add_column(int idx, std::string name = ""); /** - * @brief 在名称为id_name的列插入一个空白列 + * @brief 在名称为id_name的列之后插入一个空白列 * * @param id_name 索引列名称 * @param name 设置列名称 */ void add_column(std::string id_name, std::string name = ""); - /** - * @brief 在表格末尾添加一个空白行 - * - * @param name 设置行名称 - */ - void add_row(std::string name = ""); - /** * @brief 在索引为idx的列插入一个空白行 * From c3b2701bba36c11677ce38e9d182b38063d4a62e Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Mon, 20 Jan 2025 10:49:53 +0800 Subject: [PATCH 05/12] tmp --- example/CMakeLists.txt | 2 +- example/text_io_ex.cpp | 7 ++++++ lib/io/dsv_io.cpp | 57 +++++++++++++++++++++++++++++++----------- lib/io/dsv_io.h | 38 +++++++++++++++++----------- 4 files changed, 75 insertions(+), 29 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 71fe3e9..6b39b6d 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -29,4 +29,4 @@ add_example(multinary_ex OFF) add_example(text_io_ex OFF) add_example(getoption_ex OFF) add_example(process_ex OFF) -add_example(array_ex ON) \ No newline at end of file +add_example(array_ex OFF) \ No newline at end of file diff --git a/example/text_io_ex.cpp b/example/text_io_ex.cpp index f864ca0..124dd56 100644 --- a/example/text_io_ex.cpp +++ b/example/text_io_ex.cpp @@ -44,6 +44,13 @@ int main(int argc, char const *argv[]) try tc.filt_column("America", "Continent_s", {"Name_s", "Population_n", "GNP_n"}, tout); //tc.match_column("America", "Continent_s", {}, tout); + //tout.add_column("GNP_n2", "Population_n"); + //array GNP_n2(tout.row_number(), 1000.0); + //tout.fill_column(GNP_n2, "GNP_n2"); + + int lr_id = tout.add_row(); + tout.fill_row(array{"Asia", "China", "14000000", "1949"}, lr_id); + tout.set_delimeter('|'); tout.save_text("out"); diff --git a/lib/io/dsv_io.cpp b/lib/io/dsv_io.cpp index cc5a13a..dcb20ba 100644 --- a/lib/io/dsv_io.cpp +++ b/lib/io/dsv_io.cpp @@ -293,6 +293,29 @@ void gctl::dsv_io::save_text(std::string filename, std::string file_exten) outfile << "# " << annotates_[i] << std::endl; } + // 探测是否有行头 + bool col_st = 1; + for (int i = 0; i <= row_num_; i++) + { + if (table_[i][0].out_ok_ && table_[i][0].str_ != "") + { + col_st = 0; + break; + } + } + + for (int i = 0; i <= row_num_; i++) + { + // 单独处理第一列 即行头 + outfile << table_[i][col_st].str_; + for (int j = col_st + 1; j <= col_num_; j++) + { + if (table_[i][j].out_ok_) outfile << deli_sym_ << table_[i][j].str_; + } + outfile << std::endl; + } + +/* // 单独处理第一行 即列头 bool line_st = false; if (table_[0][0].out_ok_ && table_[0][0].str_ != "") @@ -336,7 +359,7 @@ void gctl::dsv_io::save_text(std::string filename, std::string file_exten) } outfile << std::endl; } - +*/ outfile.close(); return; } @@ -508,14 +531,16 @@ void gctl::dsv_io::row_output(int idx, switch_type_e s) void gctl::dsv_io::row_output(std::string name, switch_type_e s) { - row_output(name_index(name), s); + row_output(name_index(name, true), s); return; } -void gctl::dsv_io::add_column(int idx, std::string name) +int gctl::dsv_io::add_column(std::string name, int idx) { + if (idx <= 0) throw std::runtime_error("[gctl::dsv_io] Invalid column index."); + table_cell empty_cell; - if (idx <= 0) + if (idx > col_num_) { for (size_t i = 0; i < table_.size(); i++) { @@ -524,6 +549,7 @@ void gctl::dsv_io::add_column(int idx, std::string name) table_[0].back().str_ = name; col_num_++; + return col_num_; } else { @@ -534,25 +560,28 @@ void gctl::dsv_io::add_column(int idx, std::string name) table_[0][idx].str_ = name; col_num_++; + return idx; } - return; + return -1; } -void gctl::dsv_io::add_column(std::string id_name, std::string name) +int gctl::dsv_io::add_column(std::string name, std::string id_name) { - add_column(name_index(id_name), name); - return; + return add_column(name, name_index(id_name)); } -void gctl::dsv_io::add_row(int idx, std::string name) +int gctl::dsv_io::add_row(std::string name, int idx) { + if (idx <= 0) throw std::runtime_error("[gctl::dsv_io] Invalid row index."); + std::vector empty_line; - if (idx <= 0) + if (idx > row_num_) { table_.push_back(empty_line); table_.back().resize(col_num_ + 1); table_.back().front().str_ = name; row_num_++; + return row_num_; } else { @@ -560,14 +589,14 @@ void gctl::dsv_io::add_row(int idx, std::string name) table_[idx].resize(col_num_ + 1); table_[idx].front().str_ = name; row_num_++; + return idx; } - return; + return -1; } -void gctl::dsv_io::add_row(std::string id_name, std::string name) +int gctl::dsv_io::add_row(std::string name, std::string id_name) { - add_row(name_index(id_name), name); - return; + return add_row(name, name_index(id_name, true)); } void gctl::dsv_io::filt_column(std::string cnd_str, std::string cnd_col, diff --git a/lib/io/dsv_io.h b/lib/io/dsv_io.h index 7fafe8a..ed9536e 100644 --- a/lib/io/dsv_io.h +++ b/lib/io/dsv_io.h @@ -404,40 +404,50 @@ namespace gctl void row_output(std::string name, switch_type_e s = Disable); /** - * @brief 在索引为idx的列之后插入一个空白列 + * @brief 在索引为idx的位置插入一个空白列,剩余列后移一位。如果idx大于列数则在表尾添加一列。 * - * @param idx 列索引 小于等于0时将在表尾添加一列 + * @param idx 列索引 * @param name 设置列名称 + * + * @return 索引 返回的索引(大于等于1 小于等于行数或列数)失败则返回-1 */ - void add_column(int idx, std::string name = ""); + int add_column(std::string name = "", int idx = 9999); /** - * @brief 在名称为id_name的列之后插入一个空白列 + * @brief 在名称为id_name的列的位置插入一个空白列,剩余列后移一位。 * * @param id_name 索引列名称 * @param name 设置列名称 - */ - void add_column(std::string id_name, std::string name = ""); - - /** - * @brief 在索引为idx的列插入一个空白行 * - * @param idx 行索引 小于等于0时将在表尾添加一行 - * @param name 设置行名称 + * @return 索引 返回的索引(大于等于1 小于等于行数或列数)失败则返回-1 */ - void add_row(int idx, std::string name = ""); + int add_column(std::string name, std::string id_name); /** - * @brief 在名称为id_name的列插入一个空白行 + * @brief 在索引为idx的位置插入一个空白行,剩余行后移一位。如果idx大于等于行数则在表尾添加一行。 + * + * @param idx 行索引 + * @param name 设置行名称 + * + * @return 索引 返回的索引(大于等于1 小于等于行数或列数)失败则返回-1 + */ + int add_row(std::string name = "", int idx = 9999); + + /** + * @brief 在名称为id_name的行的位置插入一个空白行,剩余行后移一位。 * * @param id_name 索引行名称 * @param name 设置行名称 + * + * @return 索引 返回的索引(大于等于1 小于等于行数或列数)失败则返回-1 */ - void add_row(std::string id_name, std::string name = ""); + int add_row(std::string name, std::string id_name); /** * @brief 按行过滤并返回符合条件的列数据 * + * @note 过滤后的表格第一列尾用于匹配正则表达式的列,剩余列尾为筛选后符合条件的列数据。 + * * @param cnd_str 正则表达式 * @param cnd_col 用于匹配正则表达式的列名称 * @param out_col 输出的列索引列表(列表为空时则会输出所有列),正则表达式为真时即筛选这些行与列上对应的数据 From 4aaea1cf33192fdff89c31335c07d7526b2fe89b Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Mon, 20 Jan 2025 17:17:50 +0800 Subject: [PATCH 06/12] tmp --- lib/io/gmsh_io.h | 108 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/lib/io/gmsh_io.h b/lib/io/gmsh_io.h index cb4c7d0..1da881b 100644 --- a/lib/io/gmsh_io.h +++ b/lib/io/gmsh_io.h @@ -65,6 +65,7 @@ namespace gctl template void read_node(array> &out_nodes); template void read_node(array> &out_nodes); + template void read_element(array> &out_elements, const array> &nodes, _2i_vector *ele_tag = nullptr); template void read_element(array> &out_elements, const array> &nodes, _2i_vector *ele_tag = nullptr); template void read_element(array> &out_elements, const array> &nodes, _2i_vector *ele_tag = nullptr); template void read_element(array> &out_elements, const array> &nodes, _2i_vector *ele_tag = nullptr); @@ -151,6 +152,14 @@ namespace gctl return; } + template + void gmshio::read_element(array> &out_elements, const array> &nodes, _2i_vector *ele_tag) + { + initialized(Input); + read_gmsh_element(gmsh_in, out_elements, nodes, in_packed, ele_tag); + return; + } + template void gmshio::read_element(array> &out_elements, const array> &nodes, _2i_vector *ele_tag) { @@ -1135,6 +1144,105 @@ namespace gctl return; } + /** + * @brief Read element index from a Gmsh file. + * + * @param[in] infile The input file stream + * @param element The output element object array + * @param node The node array + * @param[in] packed Indicates whether the index in the node file starts from zero. The + * index is deemed to be started with one if this option is false. The default value of this + * variable is true. + * @param[in] ele_tag Return elements' tags by a 2D integer vector. + * + */ + template + void read_gmsh_element(std::ifstream &infile, array> &element, + const array> &node, index_packed_e packed = Packed, + _2i_vector *ele_tag = nullptr) + { + if (node.empty()) + throw runtime_error("The input array is empty. From gctl::read_gmsh_element(...)"); + + // 重置数据 + if (!element.empty()) element.clear(); + // 重置标签 + if (ele_tag != nullptr && !ele_tag->empty()) ele_tag->clear(); + + // 将文件指针重置到文件头 + infile.clear(std::ios::goodbit); + infile.seekg(std::ios::beg); + + int i_size = 0, ele_count = 0; + int tmp_int, ele_type, attri_num; + int tmp_index[2]; + std::string tmp_str; + std::stringstream tmp_ss; + while(getline(infile,tmp_str)) + { + if (tmp_str == "$Elements") //读入模型空间顶点集 msh文件版本为2.2 + { + getline(infile,tmp_str); + gctl::str2ss(tmp_str, tmp_ss); + tmp_ss >> i_size; //第一个数为顶点的个数 + + // 我们先用一个临时的向量来储存元素 + edge2d tmp_edge; + std::vector element_vec; + std::vector tmp_tag; + + for (int i = 0; i < i_size; i++) + { + getline(infile,tmp_str); + str2ss(tmp_str, tmp_ss); + tmp_ss >> tmp_int >> ele_type >> attri_num; + if (ele_type == 1) + { + tmp_edge.id = ele_count; + + tmp_tag.clear(); + for (int a = 0; a < attri_num; a++) + { + tmp_ss >> tmp_int; + tmp_tag.push_back(tmp_int); + } + + if (ele_tag != nullptr) + ele_tag->push_back(tmp_tag); + + tmp_ss >> tmp_index[0] >> tmp_index[1]; + + if (packed == NotPacked) + { + for (int j = 0; j < 2; j++) + tmp_edge.vert[j] = node.get(tmp_index[j]-1); + } + else + { + for (int j = 0; j < 2; j++) + tmp_edge.vert[j] = node.get(tmp_index[j]); + } + element_vec.push_back(tmp_edge); + + ele_count++; + } + } + + //将元素转移到向量上来 + element.resize(element_vec.size()); + for (int i = 0; i < element.size(); i++) + { + element[i].id = element_vec[i].id; + for (int j = 0; j < 2; j++) + element[i].vert[j] = element_vec[i].vert[j]; + } + destroy_vector(element_vec); + break; + } + } + return; + } + /** * @brief Read element index from a Gmsh file. * From e29b31efa10cd78b55acc47d16399c3236db5fca Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Tue, 21 Jan 2025 10:33:52 +0800 Subject: [PATCH 07/12] tmp update --- example/CMakeLists.txt | 2 +- example/meshio_ex.cpp | 41 +++++---- lib/io/mesh_io.cpp | 191 +++++++++++++++++++++++++++++------------ lib/io/mesh_io.h | 137 +++++++++++++++++------------ 4 files changed, 243 insertions(+), 128 deletions(-) diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 6b39b6d..fd48dbb 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -23,7 +23,7 @@ add_example(windowfunc_ex OFF) add_example(legendre_ex OFF) add_example(refellipsoid_ex OFF) add_example(kde_ex OFF) -add_example(meshio_ex OFF) +add_example(meshio_ex ON) add_example(autodiff_ex OFF) add_example(multinary_ex OFF) add_example(text_io_ex OFF) diff --git a/example/meshio_ex.cpp b/example/meshio_ex.cpp index 1b74f20..0bb3399 100644 --- a/example/meshio_ex.cpp +++ b/example/meshio_ex.cpp @@ -33,28 +33,35 @@ using namespace gctl; int main(int argc, char const *argv[]) try { mesh_io mshio; - - //mshio.read_tetgen_ascii("tmp/ex1.1"); - //mshio.edit_group(Disable, GeometryTag, 5); - //mshio.edit_group(GeometryTag, 1, PhysicalTag, 1); - //mshio.edit_group(GeometryTag, 2, PhysicalTag, 2); - //mshio.edit_group(GeometryTag, 3, PhysicalTag, 3); - //mshio.edit_group(GeometryTag, 4, PhysicalTag, 4); - //mshio.edit_group(GeometryTag, 1, "Boundary"); - //mshio.edit_group(GeometryTag, 2, "Body1"); - //mshio.edit_group(GeometryTag, 3, "Body2"); - //mshio.edit_group(GeometryTag, 4, "Body3"); - //mshio.save_gmsh_v2_ascii("tmp/ex1.1"); -/* + +/* + mshio.read_tetgen_ascii("tmp/ex1.1"); + mshio.edit_group(Disable, GeometryTag, 5); + mshio.edit_group(GeometryTag, 1, PhysicalTag, 1); + mshio.edit_group(GeometryTag, 2, PhysicalTag, 2); + mshio.edit_group(GeometryTag, 3, PhysicalTag, 3); + mshio.edit_group(GeometryTag, 4, PhysicalTag, 4); + mshio.edit_group(GeometryTag, 1, "Boundary"); + mshio.edit_group(GeometryTag, 2, "Body1"); + mshio.edit_group(GeometryTag, 3, "Body2"); + mshio.edit_group(GeometryTag, 4, "Body3"); + mshio.save_gmsh_v2_ascii("tmp/ex1.1"); +*/ + mshio.read_gmsh_v2_ascii("tmp/ex1.1"); mshio.convert_tags_to_data(GeometryTag); + array body_val(mshio.element_size("Body2"), 2.0); - mshio.create_data(body_val, "BodyValue", "Body2"); + mshio.add_element_data(body_val, "BodyValue", "Body2"); + + array body_val2(mshio.element_size("Body3"), 1.0); + mshio.add_element_data(body_val2, "BodyValue", "Body3"); + mshio.save_gmsh_v2_ascii("tmp/ex1.2"); //mshio.save_vtk_legacy_ascii("tmp/ex1.1"); mshio.info(); - array nodes = mshio.get_nodes(); + const array &nodes = mshio.get_nodes(); array body2_tets; mshio.export_elements_to(body2_tets, "All"); @@ -63,8 +70,7 @@ int main(int argc, char const *argv[]) try gio.init_file("tmp.msh", Output); gio.set_packed(NotPacked, Output); gio.save_mesh(body2_tets, nodes); -*/ - +/* mshio.read_gmsh_v2_ascii("tmp/wjb.1"); mshio.edit_group(Disable); mshio.edit_group(Enable, GeometryTag, 3); @@ -72,6 +78,7 @@ int main(int argc, char const *argv[]) try mshio.edit_group(Enable, GeometryTag, 9); mshio.save_gmsh_v2_ascii("tmp/wjb.2"); +*/ return 0; } catch(std::exception &e) diff --git a/lib/io/mesh_io.cpp b/lib/io/mesh_io.cpp index 42bdd7b..1fa8338 100644 --- a/lib/io/mesh_io.cpp +++ b/lib/io/mesh_io.cpp @@ -564,13 +564,12 @@ void gctl::mesh_io::convert_tags_to_data(element_tag_enum tag_type) } else { - int t = 0; tmp_data.enabled = true; tmp_data.d_type = ElemData; - if (tag_type == PhysicalTag) {tmp_data.str_tag.resize(1, "Physical Tag"); t = 0;} - else if (tag_type == GeometryTag) {tmp_data.str_tag.resize(1, "Geometry Tag"); t = 1;} - else if (tag_type == PartitionTag) {tmp_data.str_tag.resize(1, "Partition Tag"); t = 2;} + if (tag_type == PhysicalTag) tmp_data.str_tag.resize(1, "Physical Tag"); + else if (tag_type == GeometryTag) tmp_data.str_tag.resize(1, "Geometry Tag"); + else if (tag_type == PartitionTag) tmp_data.str_tag.resize(1, "Partition Tag"); tmp_data.real_tag.resize(1, 0.0); tmp_data.int_tag.resize(3, 0); @@ -686,7 +685,7 @@ void gctl::mesh_io::export_elements_to(array &tets, std::string phy tets.resize(s); s = 0; - for (size_t i = 0; i < elems_.size(); i++) + for (size_t i = 0; i < groups_.size(); i++) { if (groups_[i].enabled && groups_[i].type == _4NodeTetrahedron && (groups_[i].name == phys_name || phys_name == "All")) @@ -722,7 +721,7 @@ void gctl::mesh_io::export_elements_to(array &tets, element_tag_enu tets.resize(s); s = 0; - for (size_t i = 0; i < elems_.size(); i++) + for (size_t i = 0; i < groups_.size(); i++) { if (groups_[i].enabled && groups_[i].type == _4NodeTetrahedron && (tag_type == PhysicalTag && groups_[i].phys_group == tag) || @@ -743,35 +742,101 @@ void gctl::mesh_io::export_elements_to(array &tets, element_tag_enu return; } -void gctl::mesh_io::create_node_data(const array &data, std::string name) +int gctl::mesh_io::if_saved_data(std::string name) { + for (size_t i = 0; i < datas_.size(); i++) + { + if (datas_[i].str_tag.front() == name) return i; + } + return -1; +} + +void gctl::mesh_io::add_node_data(const array &data, std::string name) +{ + size_t s = nodes_.size(); + if (data.size()!= s) throw std::runtime_error("[gctl::mesh_io::create_node_data] Incompatible data size."); + + int d_id = if_saved_data(name); + if (d_id != -1) + { + for (size_t i = 0; i < s; i++) + { + datas_[d_id].val[i] = data[i]; + } + return; + } + mesh_data new_data; new_data.enabled = true; new_data.d_type = NodeData; new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; + new_data.int_tag[2] = s; + new_data.vert_ptrs.resize(s, nullptr); + new_data.val.resize(s); - size_t c = 0; - for (size_t i = 0; i < nodes_.size(); i++) + for (size_t i = 0; i < s; i++) { - if (nodes_[i].id != DEFAULT_INVALID_TAG) c++; + new_data.vert_ptrs[i] = nodes_.get(i); + new_data.val[i] = data[i]; } - if (data.size() != c) throw std::runtime_error("[gctl::mesh_io::create_node_data] Incompatible data size."); - - new_data.int_tag[2] = c; - new_data.vert_ptrs.resize(c, nullptr); - new_data.val.resize(c); + datas_.push_back(new_data); + return; +} - c = 0; +void gctl::mesh_io::add_node_data(const array &data, const array &boolen, std::string name) +{ + size_t s = nodes_.size(); + if (data.size()!= s || boolen.size() != s) throw std::runtime_error("[gctl::mesh_io::create_node_data] Incompatible data size."); + + s = 0; for (size_t i = 0; i < nodes_.size(); i++) { - if (nodes_[i].id != DEFAULT_INVALID_TAG) + if (boolen[i]) s++; + } + + int d_id = if_saved_data(name); + if (d_id != -1) + { + datas_[d_id].val.resize(s); + datas_[d_id].vert_ptrs.resize(s, nullptr); + datas_[d_id].int_tag[2] = s; + + s = 0; + for (size_t i = 0; i < nodes_.size(); i++) { - new_data.vert_ptrs[c] = nodes_.get(i); - new_data.val[c] = data[c]; - c++; + if (boolen[i]) + { + datas_[d_id].vert_ptrs[s] = nodes_.get(i); + datas_[d_id].val[s] = data[i]; + s++; + } + } + return; + } + + mesh_data new_data; + new_data.enabled = true; + new_data.d_type = NodeData; + new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); + new_data.int_tag.resize(3, 0); + new_data.int_tag[1] = 1; + new_data.int_tag[2] = s; + new_data.vert_ptrs.resize(s, nullptr); + new_data.val.resize(s); + + s = 0; + for (size_t i = 0; i < nodes_.size(); i++) + { + if (boolen[i]) + { + new_data.vert_ptrs[s] = nodes_.get(i); + new_data.val[s] = data[i]; + s++; } } @@ -779,12 +844,13 @@ void gctl::mesh_io::create_node_data(const array &data, std::string name return; } -void gctl::mesh_io::create_element_data(const array &data, std::string name, element_type_enum e_type) +void gctl::mesh_io::add_element_data(const array &data, std::string name, element_type_enum e_type) { mesh_data new_data; new_data.enabled = true; new_data.d_type = ElemData; new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; @@ -818,12 +884,13 @@ void gctl::mesh_io::create_element_data(const array &data, std::string n return; } -void gctl::mesh_io::create_element_data(const array &data, std::string name, element_tag_enum tag_type, int tag) +void gctl::mesh_io::add_element_data(const array &data, std::string name, element_tag_enum tag_type, int tag) { mesh_data new_data; new_data.enabled = true; new_data.d_type = ElemData; new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; @@ -866,15 +933,8 @@ void gctl::mesh_io::create_element_data(const array &data, std::string n return; } -void gctl::mesh_io::create_element_data(const array &data, std::string name, std::string phys_name) +void gctl::mesh_io::add_element_data(const array &data, std::string name, std::string phys_name) { - mesh_data new_data; - new_data.enabled = true; - new_data.d_type = ElemData; - new_data.str_tag.resize(1, name); - new_data.int_tag.resize(3, 0); - new_data.int_tag[1] = 1; - size_t e = 0; for (size_t i = 0; i < groups_.size(); i++) { @@ -886,11 +946,44 @@ void gctl::mesh_io::create_element_data(const array &data, std::string n if (data.size() != e) throw std::runtime_error("[gctl::mesh_io::create_element_data] Incompatible data size."); + int d_id = if_saved_data(name); + if (d_id != -1) + { + array more_elem_ptrs(e, nullptr); + array more_val(e, 0.0); + + e = 0; + for (size_t i = 0; i < groups_.size(); i++) + { + if (groups_[i].enabled && groups_[i].name == phys_name) + { + for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) + { + more_elem_ptrs[e] = groups_[i].elem_ptrs[j]; + more_val[e] = data[e]; + e++; + } + } + } + + datas_[d_id].int_tag[2] += e; + datas_[d_id].elem_ptrs.concat(more_elem_ptrs); + datas_[d_id].val.concat(more_val); + return; + } + + mesh_data new_data; + new_data.enabled = true; + new_data.d_type = ElemData; + new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); + new_data.int_tag.resize(3, 0); + new_data.int_tag[1] = 1; new_data.int_tag[2] = e; new_data.elem_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); - e = 0; + e = 0; for (size_t i = 0; i < groups_.size(); i++) { if (groups_[i].enabled && groups_[i].name == phys_name) @@ -1205,7 +1298,7 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p size_t p_size = 0; size_t n_size = 0; array phys; - + while(getline(infile,tmp_str)) { if (tmp_str == "$PhysicalNames") @@ -1268,28 +1361,12 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p elems_[i].type = elem_gmsh_type(type_code); elems_[i].vert_ptrs.resize(elem_size(elems_[i].type)); - if (attri_num >= 3) // default tags will be assgined to DEFAULT_INVALID_TAG + // we get at least three tags. see below for tag types + // default tags will be assgined to DEFAULT_INVALID_TAG + int_tag[i].resize(GCTL_MAX(3, attri_num), DEFAULT_INVALID_TAG); + for (size_t a = 0; a < attri_num; a++) { - int_tag[i].resize(attri_num); - for (size_t a = 0; a < attri_num; a++) - { - tmp_ss >> int_tag[i][a]; - } - } - else if (attri_num == 2) - { - int_tag[i].resize(3, DEFAULT_INVALID_TAG); - tmp_ss >> int_tag[i][0]; - tmp_ss >> int_tag[i][1]; - } - else if (attri_num == 1) - { - int_tag[i].resize(3, DEFAULT_INVALID_TAG); - tmp_ss >> int_tag[i][0]; - } - else - { - int_tag[i].resize(3, DEFAULT_INVALID_TAG); + tmp_ss >> int_tag[i][a]; } for (size_t v = 0; v < elems_[i].vert_ptrs.size(); v++) @@ -1392,6 +1469,7 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p tmp_group.elem_ptrs.push_back(elems_.get(0)); groups_.push_back(tmp_group); + // 元素类型与三个标记都一致的元素将被分到同一组 bool not_found; for (size_t i = 1; i < elems_.size(); i++) { @@ -1413,9 +1491,9 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p { tmp_group.elem_ptrs.clear(); tmp_group.type = elems_[i].type; - tmp_group.phys_group = int_tag[i][0]; - tmp_group.geom_group = int_tag[i][1]; - tmp_group.part_group = int_tag[i][2]; + tmp_group.phys_group = int_tag[i][0]; // 物理组 + tmp_group.geom_group = int_tag[i][1]; // 几何组 + tmp_group.part_group = int_tag[i][2]; // 剖分组(一般以元素的维度区分) tmp_group.elem_ptrs.push_back(elems_.get(i)); groups_.push_back(tmp_group); } @@ -1423,6 +1501,7 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p if (!phys.empty()) { + // 遍历所有元素组 按物理组为标准为元素组命名 并以将元素维度赋值为剖分组 for (size_t g = 0; g < groups_.size(); g++) { for (size_t p = 0; p < phys.size(); p++) diff --git a/lib/io/mesh_io.h b/lib/io/mesh_io.h index d7b63f1..7a3ca62 100644 --- a/lib/io/mesh_io.h +++ b/lib/io/mesh_io.h @@ -93,10 +93,10 @@ namespace gctl */ enum element_tag_enum { - PhysicalTag, - GeometryTag, - PartitionTag, - NodeTag, + PhysicalTag, // 元素的物理分组标签 + GeometryTag, // 元素的几何分组标签 + PartitionTag, // 元素的剖分分组标签 + NodeTag, // 顶点的标签(仅用于输出顶点标签数据) }; /** @@ -105,11 +105,11 @@ namespace gctl */ struct mesh_element { - bool enabled; - int id; - element_type_enum type; - array vert_ptrs; - array neigh_ptrs; + bool enabled; // 单元体是否有效 + int id; // 单元体编号 + element_type_enum type; // 单元体类型 + array vert_ptrs; // 顶点指针数组 + array neigh_ptrs; // 相邻单元体指针数组 mesh_element(); }; @@ -120,14 +120,14 @@ namespace gctl */ struct mesh_data { - bool enabled; - mesh_data_type_e d_type; - array str_tag; - array real_tag; - array int_tag; + bool enabled; // 数据体是否有效 + mesh_data_type_e d_type; // 数据类型 + array str_tag; // 字符串类型的标签(默认为一个,即为数据的名称) + array real_tag; // 实数类型的标签(默认为一个,等于0.0) + array int_tag; // 整数类型的标签(最少三个,最后一个为数据的长度) array vert_ptrs; // 两者只能存在一个 array elem_ptrs; // 两者只能存在一个 - array val; + array val; // 数据值 mesh_data(); @@ -150,13 +150,13 @@ namespace gctl */ struct mesh_element_group { - bool enabled; - element_type_enum type; - int phys_group; - int geom_group; - int part_group; - std::string name; - std::vector elem_ptrs; + bool enabled; // 组是否有效 + element_type_enum type; // 组内单元体类型 + int phys_group; // 物理分组标签 + int geom_group; // 几何分组标签 + int part_group; // 剖分分组标签 + std::string name; // 组名 + std::vector elem_ptrs; // 组内单元体指针数组 mesh_element_group(); @@ -256,14 +256,14 @@ namespace gctl const array &get_node_tag(); /** - * @brief 返回顶点数组的引用。 + * @brief 返回所有顶点数组的引用。 * * @return 顶点数组的引用。 */ const array &get_nodes(); /** - * @brief 返回单元体数组的引用。 + * @brief 返回所有单元体数组的引用。 * * @return 单元体数组的引用。 */ @@ -336,40 +336,68 @@ namespace gctl void export_elements_to(array &tets, element_tag_enum tag_type, int tag); /** - * @brief 创建一个顶点数据对象。 + * @brief 检查是否存在名为name的数据 * - * @param data 输入的数据数组。 - * @param name 新建的数据名称。 + * @param name 数据名称 + * + * @return 存在则返回数据索引,不存在则返回-1。 */ - void create_node_data(const array &data, std::string name); + int if_saved_data(std::string name); /** - * @brief 按单元体类型筛选创建一个单元体数据对象。 + * @brief 添加一个顶点数据对象。数据将依次添加到所有顶点位置。 + * + * @note 若对应名称的数据已经存在则会覆盖 + * + * @param data 输入的数据数组,长度与网格所有顶点数据相同。 + * @param name 新建的数据名称。 + */ + void add_node_data(const array &data, std::string name); + + /** + * @brief 添加一个顶点数据对象。数据将依次添加到布尔为真的顶点位置。 + * + * @note 若对应名称的数据已经存在则会覆盖 + * + * @param data 输入的数据数组,长度与网格所有顶点数据相同。 + * @param boolen 输入的布尔,只有为真元素位置的顶点数据将被保存。 + * @param name 新建的数据名称。 + */ + void add_node_data(const array &data, const array &boolen, std::string name); + + /** + * @brief 按单元体类型筛选创建一个单元体数据对象。数据将依次添加到所选元素位置。 + * + * @note 若对应名称的数据已经存在则会覆盖 * * @param data 输入的数据数组。 * @param name 新建数据名称。 * @param e_type 新建数据的单元体类型(缺省值为NotSet,表示选择所有有效的单元体)。 */ - void create_element_data(const array &data, std::string name, element_type_enum e_type = NotSet); + void add_element_data(const array &data, std::string name, element_type_enum e_type = NotSet); /** * @brief 按单元体标签值筛选创建一个单元体数据对象。 * + * @note 若对应名称的数据已经存在则会追加 + * * @param data 输入的数据数组。 * @param name 新建数据名称。 * @param tag_type 标签类型。 * @param tag 标签值。 */ - void create_element_data(const array &data, std::string name, element_tag_enum tag_type, int tag); + void add_element_data(const array &data, std::string name, element_tag_enum tag_type, int tag); /** * @brief 按单元体组的名称筛选创建一个单元体数据对象。 * + * @note 若对应名称的数据已经存在则会追加 + * * @param data 输入的数据数组。 * @param name 新建数据名称。 * @param phys_name 单元体组的名称。 */ - void create_element_data(const array &data, std::string name, std::string phys_name); + void add_element_data(const array &data, std::string name, std::string phys_name); /** * @brief 读入triangle软件输出的网格剖分文件。 @@ -422,30 +450,31 @@ namespace gctl void save_data_to_xyz(std::string filename, std::string dataname = "null", coordinate_system_e out_coor = Cartesian, double refr = GCTL_Earth_Radius, double refR = GCTL_Earth_Radius); private: - bool initialized_; - - size_t valid_node_size_, valid_elem_size_, valid_group_size_; - array nodes_; - array elems_; - std::vector datas_; - std::vector groups_; - array nodes_tag_; + bool initialized_; // 类型是否已经初始化完成 - element_type_enum elem_gmshcode2type_[94]; - element_type_enum elem_vtkcode2type_[14]; - std::map elem_type2gmshcode_; - std::map elem_type2vtkcode_; - std::map elem_type2size_; - std::map elem_type2name_; + // 有效的顶点、单元体和单元体组的数量 + size_t valid_node_size_, valid_elem_size_, valid_group_size_; + array nodes_; // 网格顶点 当顶点索引为无效值时将不会被输出 + array elems_; // 网格元素 + std::vector datas_; // 网格数据 + std::vector groups_; // 网格单元体组 + array nodes_tag_; // 顶点标签 + + element_type_enum elem_gmshcode2type_[94]; // gmsh的单元体类型数组 数组索引为gmsh的单元体类型码值 + element_type_enum elem_vtkcode2type_[14]; // vtk的单元体类型数组 数组索引为vtk的单元体类型码值 + std::map elem_type2gmshcode_; // 单元体类型到gmsh类型码值的映射 + std::map elem_type2vtkcode_; // 单元体类型到vtk类型码值的映射 + std::map elem_type2size_; // 单元体类型到单元体顶点数量的映射 + std::map elem_type2name_; // 单元体类型到单元体名称的映射 - std::string elem_name(element_type_enum e_type); - int elem_gmsh_code(element_type_enum e_type); - int elem_vtk_code(element_type_enum e_type); - int elem_size(element_type_enum e_type); - element_type_enum elem_gmsh_type(int code); - element_type_enum elem_vtk_type(int code); - void update_indexing(); - void sort_groups(); + std::string elem_name(element_type_enum e_type); // 获取单元体名称字符串 + int elem_gmsh_code(element_type_enum e_type); // 获取单元体gmsh类型码值 + int elem_vtk_code(element_type_enum e_type); // 获取单元体vtk类型码值 + int elem_size(element_type_enum e_type); // 获取单元体顶点数量 + element_type_enum elem_gmsh_type(int code); // 获取对应gmsh类型码的单元体类型 + element_type_enum elem_vtk_type(int code); // 获取对应vtk类型码的单元体类型 + void update_indexing(); // 更新索引(对网格的元素进行操作后需调用) + void sort_groups(); // 对单元体组进行梳理(对网格的元素进行操作后需调用) }; } From 3a22285275375643b9ad1151c4dc894b47a815fb Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Tue, 21 Jan 2025 17:21:19 +0800 Subject: [PATCH 08/12] tmp --- example/meshio_ex.cpp | 4 +- lib/io/mesh_io.cpp | 310 +++++++++++++++++++++++++++++++++--------- lib/io/mesh_io.h | 92 +++++++++---- 3 files changed, 319 insertions(+), 87 deletions(-) diff --git a/example/meshio_ex.cpp b/example/meshio_ex.cpp index 0bb3399..b8c739c 100644 --- a/example/meshio_ex.cpp +++ b/example/meshio_ex.cpp @@ -52,10 +52,10 @@ int main(int argc, char const *argv[]) try mshio.convert_tags_to_data(GeometryTag); array body_val(mshio.element_size("Body2"), 2.0); - mshio.add_element_data(body_val, "BodyValue", "Body2"); + mshio.add_element_data("BodyValue", "Body2", body_val); array body_val2(mshio.element_size("Body3"), 1.0); - mshio.add_element_data(body_val2, "BodyValue", "Body3"); + mshio.add_element_data("BodyValue", "Body3", body_val2); mshio.save_gmsh_v2_ascii("tmp/ex1.2"); //mshio.save_vtk_legacy_ascii("tmp/ex1.1"); diff --git a/lib/io/mesh_io.cpp b/lib/io/mesh_io.cpp index 1fa8338..4c9eb85 100644 --- a/lib/io/mesh_io.cpp +++ b/lib/io/mesh_io.cpp @@ -27,20 +27,20 @@ #include "mesh_io.h" -gctl::mesh_element::mesh_element() +gctl::meshio_element::meshio_element() { enabled = false; id = DEFAULT_INVALID_TAG; type = NotSet; } -gctl::mesh_data::mesh_data() +gctl::meshio_data::meshio_data() { enabled = false; d_type = NodeData; } -void gctl::mesh_data::clear() +void gctl::meshio_data::clear() { enabled = false; str_tag.clear(); @@ -52,7 +52,7 @@ void gctl::mesh_data::clear() return; } -bool gctl::mesh_data::pass_check() +bool gctl::meshio_data::pass_check() { // 检查是否同时连接了顶点和单元体 if (vert_ptrs.empty() && elem_ptrs.empty()) return false; @@ -63,7 +63,7 @@ bool gctl::mesh_data::pass_check() return true; } -gctl::mesh_element_group::mesh_element_group() +gctl::meshio_element_group::meshio_element_group() { enabled = false; type = NotSet; @@ -71,7 +71,7 @@ gctl::mesh_element_group::mesh_element_group() phys_group = geom_group = part_group = DEFAULT_INVALID_TAG; } -void gctl::mesh_element_group::enable_elements() +void gctl::meshio_element_group::enable_elements() { for (size_t e = 0; e < elem_ptrs.size(); e++) { @@ -80,7 +80,7 @@ void gctl::mesh_element_group::enable_elements() return; } -void gctl::mesh_element_group::disable_elements() +void gctl::meshio_element_group::disable_elements() { for (size_t e = 0; e < elem_ptrs.size(); e++) { @@ -481,12 +481,23 @@ const gctl::array &gctl::mesh_io::get_node_tag() return nodes_tag_; } +int gctl::mesh_io::get_tag(element_tag_enum anchor_type, std::string anchor_name) +{ + for (size_t i = 0; i < groups_.size(); i++) + { + if (anchor_type == PhysicalTag && groups_[i].name == anchor_name) return groups_[i].phys_group; + if (anchor_type == GeometryTag && groups_[i].name == anchor_name) return groups_[i].geom_group; + if (anchor_type == PartitionTag && groups_[i].name == anchor_name) return groups_[i].part_group; + } + return DEFAULT_INVALID_TAG; +} + const gctl::array &gctl::mesh_io::get_nodes() { return nodes_; } -const gctl::array &gctl::mesh_io::get_elems() +const gctl::array &gctl::mesh_io::get_elems() { return elems_; } @@ -535,7 +546,7 @@ size_t gctl::mesh_io::element_size(std::string phys_name) void gctl::mesh_io::convert_tags_to_data(element_tag_enum tag_type) { - mesh_data tmp_data; + meshio_data tmp_data; if (tag_type == NodeTag && (!nodes_tag_.empty())) { tmp_data.enabled = true; @@ -742,21 +753,76 @@ void gctl::mesh_io::export_elements_to(array &tets, element_tag_enu return; } -int gctl::mesh_io::if_saved_data(std::string name) +void gctl::mesh_io::get_gmsh_physical_groups(std::vector &g_groups) +{ + if (!g_groups.empty()) g_groups.clear(); + + gmsh_physical_group tmp_group; + bool not_found; + for (size_t i = 0; i < groups_.size(); i++) + { + if (g_groups.empty() && groups_[i].enabled) + { + tmp_group.name = groups_[i].name; + tmp_group.phys_tag = groups_[i].phys_group; + tmp_group.dim_tag = groups_[i].part_group; + g_groups.push_back(tmp_group); + } + else + { + not_found = true; + for (size_t g = 0; g < g_groups.size(); g++) + { + if (groups_[i].part_group == g_groups[g].dim_tag && + groups_[i].phys_group == g_groups[g].phys_tag) + { + not_found = false; + break; + } + } + + if (not_found && groups_[i].enabled) + { + tmp_group.name = groups_[i].name; + tmp_group.phys_tag = groups_[i].phys_group; + tmp_group.dim_tag = groups_[i].part_group; + g_groups.push_back(tmp_group); + } + } + } + return; +} + +int gctl::mesh_io::if_saved_data(std::string name, mesh_data_type_e type) { for (size_t i = 0; i < datas_.size(); i++) { - if (datas_[i].str_tag.front() == name) return i; + if (datas_[i].str_tag.front() == name && + datas_[i].d_type == type) return i; } return -1; } -void gctl::mesh_io::add_node_data(const array &data, std::string name) +gctl::meshio_data &gctl::mesh_io::get_data(std::string name, mesh_data_type_e type) +{ + int id = if_saved_data(name, type); + if (id == -1) throw std::runtime_error("[gctl::mesh_io::get_data] Data not found."); + return datas_[id]; +} + +gctl::meshio_data *gctl::mesh_io::get_data_ptr(std::string name, mesh_data_type_e type) +{ + int id = if_saved_data(name, type); + if (id == -1) throw std::runtime_error("[gctl::mesh_io::get_data] Data not found."); + return &datas_[id]; +} + +void gctl::mesh_io::add_node_data(std::string name, const array &data) { size_t s = nodes_.size(); if (data.size()!= s) throw std::runtime_error("[gctl::mesh_io::create_node_data] Incompatible data size."); - int d_id = if_saved_data(name); + int d_id = if_saved_data(name, NodeData); if (d_id != -1) { for (size_t i = 0; i < s; i++) @@ -766,7 +832,7 @@ void gctl::mesh_io::add_node_data(const array &data, std::string name) return; } - mesh_data new_data; + meshio_data new_data; new_data.enabled = true; new_data.d_type = NodeData; new_data.str_tag.resize(1, name); @@ -787,7 +853,7 @@ void gctl::mesh_io::add_node_data(const array &data, std::string name) return; } -void gctl::mesh_io::add_node_data(const array &data, const array &boolen, std::string name) +void gctl::mesh_io::add_node_data(std::string name, const array &data, const array &boolen) { size_t s = nodes_.size(); if (data.size()!= s || boolen.size() != s) throw std::runtime_error("[gctl::mesh_io::create_node_data] Incompatible data size."); @@ -798,7 +864,7 @@ void gctl::mesh_io::add_node_data(const array &data, const array & if (boolen[i]) s++; } - int d_id = if_saved_data(name); + int d_id = if_saved_data(name, NodeData); if (d_id != -1) { datas_[d_id].val.resize(s); @@ -818,7 +884,7 @@ void gctl::mesh_io::add_node_data(const array &data, const array & return; } - mesh_data new_data; + meshio_data new_data; new_data.enabled = true; new_data.d_type = NodeData; new_data.str_tag.resize(1, name); @@ -844,16 +910,8 @@ void gctl::mesh_io::add_node_data(const array &data, const array & return; } -void gctl::mesh_io::add_element_data(const array &data, std::string name, element_type_enum e_type) +void gctl::mesh_io::add_element_data(std::string name, const array &data, element_type_enum e_type) { - mesh_data new_data; - new_data.enabled = true; - new_data.d_type = ElemData; - new_data.str_tag.resize(1, name); - new_data.real_tag.resize(1, 0.0); - new_data.int_tag.resize(3, 0); - new_data.int_tag[1] = 1; - size_t e = 0; for (size_t i = 0; i < groups_.size(); i++) { @@ -862,6 +920,36 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name if (data.size() != e) throw std::runtime_error("[gctl::mesh_io::create_element_data] Incompatible data size."); + int d_id = if_saved_data(name, ElemData); + if (d_id != -1) + { + datas_[d_id].int_tag[2] = e; + datas_[d_id].elem_ptrs.resize(e, nullptr); + datas_[d_id].val.resize(e, 0.0); + + e = 0; + for (size_t i = 0; i < groups_.size(); i++) + { + if ((e_type == NotSet || groups_[i].type == e_type) && groups_[i].enabled) + { + for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) + { + datas_[d_id].elem_ptrs[e] = groups_[i].elem_ptrs[j]; + datas_[d_id].val[e] = data[e]; + e++; + } + } + } + return; + } + + meshio_data new_data; + new_data.enabled = true; + new_data.d_type = ElemData; + new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); + new_data.int_tag.resize(3, 0); + new_data.int_tag[1] = 1; new_data.int_tag[2] = e; new_data.elem_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); @@ -884,16 +972,8 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name return; } -void gctl::mesh_io::add_element_data(const array &data, std::string name, element_tag_enum tag_type, int tag) +void gctl::mesh_io::add_element_data(std::string name, const array &data, element_tag_enum tag_type, int tag) { - mesh_data new_data; - new_data.enabled = true; - new_data.d_type = ElemData; - new_data.str_tag.resize(1, name); - new_data.real_tag.resize(1, 0.0); - new_data.int_tag.resize(3, 0); - new_data.int_tag[1] = 1; - size_t e = 0; for (size_t i = 0; i < groups_.size(); i++) { @@ -908,6 +988,42 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name if (data.size() != e) throw std::runtime_error("[gctl::mesh_io::create_element_data] Incompatible data size."); + int d_id = if_saved_data(name, ElemData); + if (d_id != -1) + { + array more_elem_ptrs(e, nullptr); + array more_val(e, 0.0); + + e = 0; + for (size_t i = 0; i < groups_.size(); i++) + { + if ((tag_type == PhysicalTag && groups_[i].phys_group == tag) || + (tag_type == GeometryTag && groups_[i].geom_group == tag) || + (tag_type == PartitionTag && groups_[i].part_group == tag) && + groups_[i].enabled) + { + for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) + { + more_elem_ptrs[e] = groups_[i].elem_ptrs[j]; + more_val[e] = data[e]; + e++; + } + } + } + + datas_[d_id].int_tag[2] += e; + datas_[d_id].elem_ptrs.concat(more_elem_ptrs); + datas_[d_id].val.concat(more_val); + return; + } + + meshio_data new_data; + new_data.enabled = true; + new_data.d_type = ElemData; + new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); + new_data.int_tag.resize(3, 0); + new_data.int_tag[1] = 1; new_data.int_tag[2] = e; new_data.elem_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); @@ -933,7 +1049,7 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name return; } -void gctl::mesh_io::add_element_data(const array &data, std::string name, std::string phys_name) +void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, const array &data) { size_t e = 0; for (size_t i = 0; i < groups_.size(); i++) @@ -946,10 +1062,10 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name if (data.size() != e) throw std::runtime_error("[gctl::mesh_io::create_element_data] Incompatible data size."); - int d_id = if_saved_data(name); + int d_id = if_saved_data(name, ElemData); if (d_id != -1) { - array more_elem_ptrs(e, nullptr); + array more_elem_ptrs(e, nullptr); array more_val(e, 0.0); e = 0; @@ -972,7 +1088,7 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name return; } - mesh_data new_data; + meshio_data new_data; new_data.enabled = true; new_data.d_type = ElemData; new_data.str_tag.resize(1, name); @@ -1001,6 +1117,72 @@ void gctl::mesh_io::add_element_data(const array &data, std::string name return; } +void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, double phys_val) +{ + size_t e = 0; + for (size_t i = 0; i < groups_.size(); i++) + { + if (groups_[i].enabled && groups_[i].name == phys_name) + { + e += groups_[i].elem_ptrs.size(); + } + } + + int d_id = if_saved_data(name, ElemData); + if (d_id != -1) + { + array more_elem_ptrs(e, nullptr); + array more_val(e, 0.0); + + e = 0; + for (size_t i = 0; i < groups_.size(); i++) + { + if (groups_[i].enabled && groups_[i].name == phys_name) + { + for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) + { + more_elem_ptrs[e] = groups_[i].elem_ptrs[j]; + more_val[e] = phys_val; + e++; + } + } + } + + datas_[d_id].int_tag[2] += e; + datas_[d_id].elem_ptrs.concat(more_elem_ptrs); + datas_[d_id].val.concat(more_val); + return; + } + + meshio_data new_data; + new_data.enabled = true; + new_data.d_type = ElemData; + new_data.str_tag.resize(1, name); + new_data.real_tag.resize(1, 0.0); + new_data.int_tag.resize(3, 0); + new_data.int_tag[1] = 1; + new_data.int_tag[2] = e; + new_data.elem_ptrs.resize(e, nullptr); + new_data.val.resize(e, 0.0); + + e = 0; + for (size_t i = 0; i < groups_.size(); i++) + { + if (groups_[i].enabled && groups_[i].name == phys_name) + { + for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) + { + new_data.elem_ptrs[e] = groups_[i].elem_ptrs[j]; + new_data.val[e] = phys_val; + e++; + } + } + } + + datas_.push_back(new_data); + return; +} + void gctl::mesh_io::read_triangle_ascii(std::string filename, index_packed_e is_packed) { if (initialized_ == true) @@ -1056,7 +1238,7 @@ void gctl::mesh_io::read_triangle_ascii(std::string filename, index_packed_e is_ } // 整理单元体组 - mesh_element_group tmp_group; + meshio_element_group tmp_group; tmp_group.type = elems_[0].type; tmp_group.phys_group = int_tag[0][0]; tmp_group.geom_group = int_tag[0][1]; @@ -1205,7 +1387,7 @@ void gctl::mesh_io::read_tetgen_ascii(std::string filename, index_packed_e is_pa } // 整理单元体组 - mesh_element_group tmp_group; + meshio_element_group tmp_group; tmp_group.type = elems_[0].type; tmp_group.phys_group = int_tag[0][0]; tmp_group.geom_group = int_tag[0][1]; @@ -1339,7 +1521,7 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p // 读入模型空间元素集 int i_size, type_code, attri_num, vt_idx; - array > int_tag; + array > file_itag; while(getline(infile,tmp_str)) { if (tmp_str == "$Elements") @@ -1350,23 +1532,24 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p valid_elem_size_ = i_size; elems_.resize(i_size); - int_tag.resize(valid_elem_size_); + file_itag.resize(valid_elem_size_); for (size_t i = 0; i < i_size; i++) { getline(infile,tmp_str); str2ss(tmp_str, tmp_ss); tmp_ss >> elems_[i].id >> type_code >> attri_num; + if (is_packed == NotPacked) elems_[i].id -= 1; elems_[i].type = elem_gmsh_type(type_code); elems_[i].vert_ptrs.resize(elem_size(elems_[i].type)); // we get at least three tags. see below for tag types // default tags will be assgined to DEFAULT_INVALID_TAG - int_tag[i].resize(GCTL_MAX(3, attri_num), DEFAULT_INVALID_TAG); + file_itag[i].resize(GCTL_MAX(3, attri_num), DEFAULT_INVALID_TAG); for (size_t a = 0; a < attri_num; a++) { - tmp_ss >> int_tag[i][a]; + tmp_ss >> file_itag[i][a]; } for (size_t v = 0; v < elems_[i].vert_ptrs.size(); v++) @@ -1381,7 +1564,7 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p } // 读入数据模块 - mesh_data tmp_data; + meshio_data tmp_data; while(getline(infile,tmp_str)) { if (!infile.good()) break; @@ -1461,11 +1644,11 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p infile.close(); // 整理单元体组 - mesh_element_group tmp_group; + meshio_element_group tmp_group; tmp_group.type = elems_[0].type; - tmp_group.phys_group = int_tag[0][0]; - tmp_group.geom_group = int_tag[0][1]; - tmp_group.part_group = int_tag[0][2]; + tmp_group.phys_group = file_itag[0][0]; + tmp_group.geom_group = file_itag[0][1]; + tmp_group.part_group = file_itag[0][2]; tmp_group.elem_ptrs.push_back(elems_.get(0)); groups_.push_back(tmp_group); @@ -1477,9 +1660,9 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p for (size_t g = 0; g < groups_.size(); g++) { if (groups_[g].type == elems_[i].type && - groups_[g].phys_group == int_tag[i][0] && - groups_[g].geom_group == int_tag[i][1] && - groups_[g].part_group == int_tag[i][2]) + groups_[g].phys_group == file_itag[i][0] && + groups_[g].geom_group == file_itag[i][1] && + groups_[g].part_group == file_itag[i][2]) { groups_[g].elem_ptrs.push_back(elems_.get(i)); not_found = false; @@ -1491,9 +1674,9 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p { tmp_group.elem_ptrs.clear(); tmp_group.type = elems_[i].type; - tmp_group.phys_group = int_tag[i][0]; // 物理组 - tmp_group.geom_group = int_tag[i][1]; // 几何组 - tmp_group.part_group = int_tag[i][2]; // 剖分组(一般以元素的维度区分) + tmp_group.phys_group = file_itag[i][0]; // 物理组 + tmp_group.geom_group = file_itag[i][1]; // 几何组 + tmp_group.part_group = file_itag[i][2]; // 剖分组(一般以元素的维度区分) tmp_group.elem_ptrs.push_back(elems_.get(i)); groups_.push_back(tmp_group); } @@ -1539,11 +1722,14 @@ void gctl::mesh_io::save_gmsh_v2_ascii(std::string filename, index_packed_e is_p outfile << "$MeshFormat\n2.2 0 8\n$EndMeshFormat\n"; - outfile << "$PhysicalNames\n" << valid_group_size_ << "\n"; - for (size_t i = 0; i < groups_.size(); i++) + std::vector gmsh_groups; + get_gmsh_physical_groups(gmsh_groups); + + outfile << "$PhysicalNames\n" << gmsh_groups.size() << "\n"; + for (size_t i = 0; i < gmsh_groups.size(); i++) { - if (groups_[i].enabled && groups_[i].phys_group != DEFAULT_INVALID_TAG) outfile << groups_[i].part_group << " " << groups_[i].phys_group << " \"" << groups_[i].name << "\"\n"; - else if (groups_[i].enabled) outfile << groups_[i].part_group << " 0 \"" << groups_[i].name << "\"\n"; + if (gmsh_groups[i].phys_tag != DEFAULT_INVALID_TAG) outfile << gmsh_groups[i].dim_tag << " " << gmsh_groups[i].phys_tag << " \"" << gmsh_groups[i].name << "\"\n"; + else outfile << gmsh_groups[i].dim_tag << " 0 \"" << gmsh_groups[i].name << "\"\n"; } outfile << "$EndPhysicalNames\n"; @@ -1929,7 +2115,7 @@ void gctl::mesh_io::update_indexing() void gctl::mesh_io::sort_groups() { // 拷贝到临时组 - std::vector tmp_groups = groups_; + std::vector tmp_groups = groups_; // 清空对象 for (size_t i = 0; i < groups_.size(); i++) @@ -1940,7 +2126,7 @@ void gctl::mesh_io::sort_groups() // 整理单元体组 bool not_found; - mesh_element_group tmp_group; + meshio_element_group tmp_group; for (size_t i = 0; i < tmp_groups.size(); i++) { tmp_group = tmp_groups[i]; diff --git a/lib/io/mesh_io.h b/lib/io/mesh_io.h index 7a3ca62..372fd98 100644 --- a/lib/io/mesh_io.h +++ b/lib/io/mesh_io.h @@ -103,22 +103,22 @@ namespace gctl * @brief 网格单元体结构体 * */ - struct mesh_element + struct meshio_element { bool enabled; // 单元体是否有效 int id; // 单元体编号 element_type_enum type; // 单元体类型 array vert_ptrs; // 顶点指针数组 - array neigh_ptrs; // 相邻单元体指针数组 + array neigh_ptrs; // 相邻单元体指针数组 - mesh_element(); + meshio_element(); }; /** * @brief 网格数据结构体 * */ - struct mesh_data + struct meshio_data { bool enabled; // 数据体是否有效 mesh_data_type_e d_type; // 数据类型 @@ -126,10 +126,10 @@ namespace gctl array real_tag; // 实数类型的标签(默认为一个,等于0.0) array int_tag; // 整数类型的标签(最少三个,最后一个为数据的长度) array vert_ptrs; // 两者只能存在一个 - array elem_ptrs; // 两者只能存在一个 + array elem_ptrs; // 两者只能存在一个 array val; // 数据值 - mesh_data(); + meshio_data(); /** * @brief 清空数组并重置变量。 @@ -148,7 +148,7 @@ namespace gctl * @brief 网格单元体分组结构体。 * */ - struct mesh_element_group + struct meshio_element_group { bool enabled; // 组是否有效 element_type_enum type; // 组内单元体类型 @@ -156,9 +156,9 @@ namespace gctl int geom_group; // 几何分组标签 int part_group; // 剖分分组标签 std::string name; // 组名 - std::vector elem_ptrs; // 组内单元体指针数组 + std::vector elem_ptrs; // 组内单元体指针数组 - mesh_element_group(); + meshio_element_group(); /** * @brief 将组内所有单元体设置为有效状态。 @@ -255,6 +255,15 @@ namespace gctl */ const array &get_node_tag(); + /** + * @brief 返回指定类型与名称的标签值 + * + * @param anchor_type 查找的标签类型(PhysicalTag,GeometryTag或者PartitionTag)。 + * @param anchor_name 查找的元素组名称。 + * @return 标签值 + */ + int get_tag(element_tag_enum anchor_type, std::string anchor_name); + /** * @brief 返回所有顶点数组的引用。 * @@ -267,10 +276,10 @@ namespace gctl * * @return 单元体数组的引用。 */ - const array &get_elems(); + const array &get_elems(); /** - * @brief 返回对应类型单元体的数量。 + * @brief 返回对应类型单元体的数量(注意只会统计有效的单元体组)。 * * @param e_type 单元体类型(缺省为NotSet,返回所有单元体类型的总和)。 * @return 整型大小。 @@ -278,7 +287,7 @@ namespace gctl size_t element_size(element_type_enum e_type = NotSet); /** - * @brief 返回对应标签类型与标签值的单元体数量。 + * @brief 返回对应标签类型与标签值的单元体数量(注意只会统计有效的单元体组)。 * * @param tag_type 标签类型。 * @param tag 标签值。 @@ -287,7 +296,7 @@ namespace gctl size_t element_size(element_tag_enum tag_type, int tag); /** - * @brief 返回对应名称的单元体数量。 + * @brief 返回对应名称的单元体数量(注意只会统计有效的单元体组)。 * * @param phys_name 单元体组名称 * @return 整型大小。 @@ -335,14 +344,40 @@ namespace gctl */ void export_elements_to(array &tets, element_tag_enum tag_type, int tag); + /** + * @brief 获取gmsh格式分组表 + * + * @param g_groups gmsh格式表 + */ + void get_gmsh_physical_groups(std::vector &g_groups); + /** * @brief 检查是否存在名为name的数据 * * @param name 数据名称 + * @param type 数据类型 * * @return 存在则返回数据索引,不存在则返回-1。 */ - int if_saved_data(std::string name); + int if_saved_data(std::string name, mesh_data_type_e type); + + /** + * @brief 获取数据对象的引用 + * + * @param name 数据名称 + * @param type 数据类型 + * @return 数据引用 + */ + meshio_data &get_data(std::string name, mesh_data_type_e type); + + /** + * @brief 获取数据对象的指针 + * + * @param name 数据名称 + * @param type 数据类型 + * @return 数据指针 + */ + meshio_data *get_data_ptr(std::string name, mesh_data_type_e type); /** * @brief 添加一个顶点数据对象。数据将依次添加到所有顶点位置。 @@ -352,7 +387,7 @@ namespace gctl * @param data 输入的数据数组,长度与网格所有顶点数据相同。 * @param name 新建的数据名称。 */ - void add_node_data(const array &data, std::string name); + void add_node_data(std::string name, const array &data); /** * @brief 添加一个顶点数据对象。数据将依次添加到布尔为真的顶点位置。 @@ -363,7 +398,7 @@ namespace gctl * @param boolen 输入的布尔,只有为真元素位置的顶点数据将被保存。 * @param name 新建的数据名称。 */ - void add_node_data(const array &data, const array &boolen, std::string name); + void add_node_data(std::string name, const array &data, const array &boolen); /** * @brief 按单元体类型筛选创建一个单元体数据对象。数据将依次添加到所选元素位置。 @@ -374,7 +409,7 @@ namespace gctl * @param name 新建数据名称。 * @param e_type 新建数据的单元体类型(缺省值为NotSet,表示选择所有有效的单元体)。 */ - void add_element_data(const array &data, std::string name, element_type_enum e_type = NotSet); + void add_element_data(std::string name, const array &data, element_type_enum e_type = NotSet); /** * @brief 按单元体标签值筛选创建一个单元体数据对象。 @@ -386,7 +421,7 @@ namespace gctl * @param tag_type 标签类型。 * @param tag 标签值。 */ - void add_element_data(const array &data, std::string name, element_tag_enum tag_type, int tag); + void add_element_data(std::string name, const array &data, element_tag_enum tag_type, int tag); /** * @brief 按单元体组的名称筛选创建一个单元体数据对象。 @@ -397,7 +432,18 @@ namespace gctl * @param name 新建数据名称。 * @param phys_name 单元体组的名称。 */ - void add_element_data(const array &data, std::string name, std::string phys_name); + void add_element_data(std::string name, std::string phys_name, const array &data); + + /** + * @brief 按单元体组的名称筛选创建一个单元体数据对象。 + * + * @note 若对应名称的数据已经存在则会追加 + * + * @param phys_val 数据初始值 + * @param name 新建数据名称。 + * @param phys_name 单元体组的名称。 + */ + void add_element_data(std::string name, std::string phys_name, double phys_val); /** * @brief 读入triangle软件输出的网格剖分文件。 @@ -449,15 +495,15 @@ namespace gctl */ void save_data_to_xyz(std::string filename, std::string dataname = "null", coordinate_system_e out_coor = Cartesian, double refr = GCTL_Earth_Radius, double refR = GCTL_Earth_Radius); - private: + protected: bool initialized_; // 类型是否已经初始化完成 // 有效的顶点、单元体和单元体组的数量 size_t valid_node_size_, valid_elem_size_, valid_group_size_; array nodes_; // 网格顶点 当顶点索引为无效值时将不会被输出 - array elems_; // 网格元素 - std::vector datas_; // 网格数据 - std::vector groups_; // 网格单元体组 + array elems_; // 网格元素 + std::vector datas_; // 网格数据 + std::vector groups_; // 网格单元体组 array nodes_tag_; // 顶点标签 element_type_enum elem_gmshcode2type_[94]; // gmsh的单元体类型数组 数组索引为gmsh的单元体类型码值 From a927a93997ca04088bd10633f76e9db1bba901b8 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Thu, 23 Jan 2025 10:07:17 +0800 Subject: [PATCH 09/12] update mesh_io --- lib/io/mesh_io.cpp | 126 ++++++++++++++++++++++++--------------------- lib/io/mesh_io.h | 5 +- 2 files changed, 68 insertions(+), 63 deletions(-) diff --git a/lib/io/mesh_io.cpp b/lib/io/mesh_io.cpp index 4c9eb85..8d3a03e 100644 --- a/lib/io/mesh_io.cpp +++ b/lib/io/mesh_io.cpp @@ -46,8 +46,7 @@ void gctl::meshio_data::clear() str_tag.clear(); real_tag.clear(); int_tag.clear(); - vert_ptrs.clear(); - elem_ptrs.clear(); + tar_ptrs.clear(); val.clear(); return; } @@ -55,11 +54,10 @@ void gctl::meshio_data::clear() bool gctl::meshio_data::pass_check() { // 检查是否同时连接了顶点和单元体 - if (vert_ptrs.empty() && elem_ptrs.empty()) return false; - if (!vert_ptrs.empty() && !elem_ptrs.empty()) return false; + if (tar_ptrs.empty()) return false; + if (int_tag[2] != val.size()) return false; + if (tar_ptrs.size() != val.size()) return false; if (str_tag.empty() || real_tag.empty() || int_tag.size() < 3) return false; - if (!vert_ptrs.empty() && (vert_ptrs.size() != val.size() || int_tag[2] != val.size())) return false; - if (!elem_ptrs.empty() && (elem_ptrs.size() != val.size() || int_tag[2] != val.size())) return false; return true; } @@ -319,7 +317,7 @@ void gctl::mesh_io::info(std::ostream &ss) ss << "nodedata: \""; for (size_t l = 0; l < datas_[d].val.size(); l++) { - if (datas_[d].vert_ptrs[l]->id != DEFAULT_INVALID_TAG) + if (reinterpret_cast(datas_[d].tar_ptrs[l])->id != DEFAULT_INVALID_TAG) { min = std::min(min, datas_[d].val[l]); max = std::max(max, datas_[d].val[l]); @@ -332,7 +330,7 @@ void gctl::mesh_io::info(std::ostream &ss) ss << "elementdata: \""; for (size_t l = 0; l < datas_[d].val.size(); l++) { - if (datas_[d].elem_ptrs[l]->enabled) + if (reinterpret_cast(datas_[d].tar_ptrs[l])->enabled) { min = std::min(min, datas_[d].val[l]); max = std::max(max, datas_[d].val[l]); @@ -558,7 +556,7 @@ void gctl::mesh_io::convert_tags_to_data(element_tag_enum tag_type) tmp_data.int_tag[2] = valid_node_size_; tmp_data.val.resize(valid_node_size_); - tmp_data.vert_ptrs.resize(valid_node_size_); + tmp_data.tar_ptrs.resize(valid_node_size_); size_t c = 0; for (size_t i = 0; i < nodes_.size(); i++) @@ -566,7 +564,7 @@ void gctl::mesh_io::convert_tags_to_data(element_tag_enum tag_type) if (nodes_[i].id != DEFAULT_INVALID_TAG) { tmp_data.val[c] = (double) nodes_tag_[i]; - tmp_data.vert_ptrs[c] = nodes_.get(i); + tmp_data.tar_ptrs[c] = nodes_.get(i); c++; } } @@ -588,7 +586,7 @@ void gctl::mesh_io::convert_tags_to_data(element_tag_enum tag_type) tmp_data.int_tag[2] = valid_elem_size_; tmp_data.val.resize(valid_elem_size_); - tmp_data.elem_ptrs.resize(valid_elem_size_); + tmp_data.tar_ptrs.resize(valid_elem_size_); size_t c = 0; for (size_t g = 0; g < groups_.size(); g++) @@ -600,7 +598,7 @@ void gctl::mesh_io::convert_tags_to_data(element_tag_enum tag_type) if (tag_type == PhysicalTag) tmp_data.val[c] = (double) groups_[g].phys_group; if (tag_type == GeometryTag) tmp_data.val[c] = (double) groups_[g].geom_group; if (tag_type == PartitionTag) tmp_data.val[c] = (double) groups_[g].part_group; - tmp_data.elem_ptrs[c] = groups_[g].elem_ptrs[e]; + tmp_data.tar_ptrs[c] = groups_[g].elem_ptrs[e]; c++; } } @@ -840,12 +838,12 @@ void gctl::mesh_io::add_node_data(std::string name, const array &data) new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; new_data.int_tag[2] = s; - new_data.vert_ptrs.resize(s, nullptr); + new_data.tar_ptrs.resize(s, nullptr); new_data.val.resize(s); for (size_t i = 0; i < s; i++) { - new_data.vert_ptrs[i] = nodes_.get(i); + new_data.tar_ptrs[i] = nodes_.get(i); new_data.val[i] = data[i]; } @@ -868,7 +866,7 @@ void gctl::mesh_io::add_node_data(std::string name, const array &data, c if (d_id != -1) { datas_[d_id].val.resize(s); - datas_[d_id].vert_ptrs.resize(s, nullptr); + datas_[d_id].tar_ptrs.resize(s, nullptr); datas_[d_id].int_tag[2] = s; s = 0; @@ -876,7 +874,7 @@ void gctl::mesh_io::add_node_data(std::string name, const array &data, c { if (boolen[i]) { - datas_[d_id].vert_ptrs[s] = nodes_.get(i); + datas_[d_id].tar_ptrs[s] = nodes_.get(i); datas_[d_id].val[s] = data[i]; s++; } @@ -892,7 +890,7 @@ void gctl::mesh_io::add_node_data(std::string name, const array &data, c new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; new_data.int_tag[2] = s; - new_data.vert_ptrs.resize(s, nullptr); + new_data.tar_ptrs.resize(s, nullptr); new_data.val.resize(s); s = 0; @@ -900,7 +898,7 @@ void gctl::mesh_io::add_node_data(std::string name, const array &data, c { if (boolen[i]) { - new_data.vert_ptrs[s] = nodes_.get(i); + new_data.tar_ptrs[s] = nodes_.get(i); new_data.val[s] = data[i]; s++; } @@ -924,7 +922,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data if (d_id != -1) { datas_[d_id].int_tag[2] = e; - datas_[d_id].elem_ptrs.resize(e, nullptr); + datas_[d_id].tar_ptrs.resize(e, nullptr); datas_[d_id].val.resize(e, 0.0); e = 0; @@ -934,7 +932,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data { for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) { - datas_[d_id].elem_ptrs[e] = groups_[i].elem_ptrs[j]; + datas_[d_id].tar_ptrs[e] = groups_[i].elem_ptrs[j]; datas_[d_id].val[e] = data[e]; e++; } @@ -951,7 +949,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; new_data.int_tag[2] = e; - new_data.elem_ptrs.resize(e, nullptr); + new_data.tar_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); e = 0; @@ -961,7 +959,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data { for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) { - new_data.elem_ptrs[e] = groups_[i].elem_ptrs[j]; + new_data.tar_ptrs[e] = groups_[i].elem_ptrs[j]; new_data.val[e] = data[e]; e++; } @@ -991,7 +989,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data int d_id = if_saved_data(name, ElemData); if (d_id != -1) { - array more_elem_ptrs(e, nullptr); + array more_elem_ptrs(e, nullptr); array more_val(e, 0.0); e = 0; @@ -1012,7 +1010,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data } datas_[d_id].int_tag[2] += e; - datas_[d_id].elem_ptrs.concat(more_elem_ptrs); + datas_[d_id].tar_ptrs.concat(more_elem_ptrs); datas_[d_id].val.concat(more_val); return; } @@ -1025,7 +1023,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; new_data.int_tag[2] = e; - new_data.elem_ptrs.resize(e, nullptr); + new_data.tar_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); e = 0; @@ -1038,7 +1036,7 @@ void gctl::mesh_io::add_element_data(std::string name, const array &data { for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) { - new_data.elem_ptrs[e] = groups_[i].elem_ptrs[j]; + new_data.tar_ptrs[e] = groups_[i].elem_ptrs[j]; new_data.val[e] = data[e]; e++; } @@ -1065,7 +1063,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, co int d_id = if_saved_data(name, ElemData); if (d_id != -1) { - array more_elem_ptrs(e, nullptr); + array more_elem_ptrs(e, nullptr); array more_val(e, 0.0); e = 0; @@ -1083,7 +1081,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, co } datas_[d_id].int_tag[2] += e; - datas_[d_id].elem_ptrs.concat(more_elem_ptrs); + datas_[d_id].tar_ptrs.concat(more_elem_ptrs); datas_[d_id].val.concat(more_val); return; } @@ -1096,7 +1094,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, co new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; new_data.int_tag[2] = e; - new_data.elem_ptrs.resize(e, nullptr); + new_data.tar_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); e = 0; @@ -1106,7 +1104,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, co { for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) { - new_data.elem_ptrs[e] = groups_[i].elem_ptrs[j]; + new_data.tar_ptrs[e] = groups_[i].elem_ptrs[j]; new_data.val[e] = data[e]; e++; } @@ -1131,7 +1129,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, do int d_id = if_saved_data(name, ElemData); if (d_id != -1) { - array more_elem_ptrs(e, nullptr); + array more_elem_ptrs(e, nullptr); array more_val(e, 0.0); e = 0; @@ -1149,7 +1147,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, do } datas_[d_id].int_tag[2] += e; - datas_[d_id].elem_ptrs.concat(more_elem_ptrs); + datas_[d_id].tar_ptrs.concat(more_elem_ptrs); datas_[d_id].val.concat(more_val); return; } @@ -1162,7 +1160,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, do new_data.int_tag.resize(3, 0); new_data.int_tag[1] = 1; new_data.int_tag[2] = e; - new_data.elem_ptrs.resize(e, nullptr); + new_data.tar_ptrs.resize(e, nullptr); new_data.val.resize(e, 0.0); e = 0; @@ -1172,7 +1170,7 @@ void gctl::mesh_io::add_element_data(std::string name, std::string phys_name, do { for (size_t j = 0; j < groups_[i].elem_ptrs.size(); j++) { - new_data.elem_ptrs[e] = groups_[i].elem_ptrs[j]; + new_data.tar_ptrs[e] = groups_[i].elem_ptrs[j]; new_data.val[e] = phys_val; e++; } @@ -1612,28 +1610,28 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p if (tmp_data.d_type == NodeData) { - tmp_data.vert_ptrs.resize(tmp_data.int_tag.back()); + tmp_data.tar_ptrs.resize(tmp_data.int_tag.back()); tmp_data.val.resize(tmp_data.int_tag.back()); for (size_t i = 0; i < tmp_data.val.size(); i++) { getline(infile,tmp_str); str2ss(tmp_str, tmp_ss); tmp_ss >> vt_idx >> tmp_data.val[i]; - if (is_packed == Packed) tmp_data.vert_ptrs[i] = nodes_.get(vt_idx); - else tmp_data.vert_ptrs[i] = nodes_.get(vt_idx - 1); + if (is_packed == Packed) tmp_data.tar_ptrs[i] = nodes_.get(vt_idx); + else tmp_data.tar_ptrs[i] = nodes_.get(vt_idx - 1); } } else { - tmp_data.elem_ptrs.resize(tmp_data.int_tag.back()); + tmp_data.tar_ptrs.resize(tmp_data.int_tag.back()); tmp_data.val.resize(tmp_data.int_tag.back()); for (size_t i = 0; i < tmp_data.val.size(); i++) { getline(infile,tmp_str); str2ss(tmp_str, tmp_ss); tmp_ss >> vt_idx >> tmp_data.val[i]; - if (is_packed == Packed) tmp_data.elem_ptrs[i] = elems_.get(vt_idx); - else tmp_data.elem_ptrs[i] = elems_.get(vt_idx - 1); + if (is_packed == Packed) tmp_data.tar_ptrs[i] = elems_.get(vt_idx); + else tmp_data.tar_ptrs[i] = elems_.get(vt_idx - 1); } } @@ -1791,7 +1789,7 @@ void gctl::mesh_io::save_gmsh_v2_ascii(std::string filename, index_packed_e is_p d_size = 0; for (size_t n = 0; n < datas_[i].val.size(); n++) { - if (datas_[i].vert_ptrs[n]->id != DEFAULT_INVALID_TAG) d_size++; + if (reinterpret_cast(datas_[i].tar_ptrs[n])->id != DEFAULT_INVALID_TAG) d_size++; } if (d_size) @@ -1816,10 +1814,12 @@ void gctl::mesh_io::save_gmsh_v2_ascii(std::string filename, index_packed_e is_p } outfile << d_size << "\n"; + int tmp_id; for (size_t a = 0; a < datas_[i].val.size(); a++) { - if (datas_[i].vert_ptrs[a]->id != DEFAULT_INVALID_TAG && is_packed == Packed) outfile << datas_[i].vert_ptrs[a]->id << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; - else if (datas_[i].vert_ptrs[a]->id != DEFAULT_INVALID_TAG) outfile << datas_[i].vert_ptrs[a]->id + 1 << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; + tmp_id = reinterpret_cast(datas_[i].tar_ptrs[a])->id; + if (tmp_id != DEFAULT_INVALID_TAG && is_packed == Packed) outfile << tmp_id << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; + else if (tmp_id != DEFAULT_INVALID_TAG) outfile << tmp_id + 1 << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; } outfile << "$EndNodeData\n"; } @@ -1829,7 +1829,7 @@ void gctl::mesh_io::save_gmsh_v2_ascii(std::string filename, index_packed_e is_p d_size = 0; for (size_t n = 0; n < datas_[i].val.size(); n++) { - if (datas_[i].elem_ptrs[n]->enabled) d_size++; + if (reinterpret_cast(datas_[i].tar_ptrs[n])->enabled) d_size++; } if (d_size) @@ -1854,10 +1854,14 @@ void gctl::mesh_io::save_gmsh_v2_ascii(std::string filename, index_packed_e is_p } outfile << d_size << "\n"; + int tmp_id; + bool d_ok; for (size_t a = 0; a < datas_[i].val.size(); a++) { - if (datas_[i].elem_ptrs[a]->enabled && is_packed == Packed) outfile << datas_[i].elem_ptrs[a]->id << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; - else if (datas_[i].elem_ptrs[a]->enabled) outfile << datas_[i].elem_ptrs[a]->id + 1 << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; + tmp_id = reinterpret_cast(datas_[i].tar_ptrs[a])->id; + d_ok = reinterpret_cast(datas_[i].tar_ptrs[a])->enabled; + if (d_ok && is_packed == Packed) outfile << tmp_id << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; + else if (d_ok) outfile << tmp_id + 1 << " " << std::setprecision(12) << datas_[i].val[a] << "\n"; } outfile << "$EndElementData\n"; } @@ -1927,7 +1931,7 @@ void gctl::mesh_io::save_vtk_legacy_ascii(std::string filename) d_size = 0; for (size_t n = 0; n < datas_[i].val.size(); n++) { - if (datas_[i].vert_ptrs[n]->id != DEFAULT_INVALID_TAG) d_size++; + if (reinterpret_cast(datas_[i].tar_ptrs[n])->id != DEFAULT_INVALID_TAG) d_size++; } if (d_size && d_size == valid_node_size_) @@ -1939,7 +1943,7 @@ void gctl::mesh_io::save_vtk_legacy_ascii(std::string filename) for (size_t a = 0; a < datas_[i].val.size(); a++) { - if (datas_[i].vert_ptrs[a]->id != DEFAULT_INVALID_TAG) outfile << std::setprecision(16) << datas_[i].val[a] << "\n"; + if (reinterpret_cast(datas_[i].tar_ptrs[a])->id != DEFAULT_INVALID_TAG) outfile << std::setprecision(16) << datas_[i].val[a] << "\n"; } } } @@ -1948,7 +1952,7 @@ void gctl::mesh_io::save_vtk_legacy_ascii(std::string filename) d_size = 0; for (size_t n = 0; n < datas_[i].val.size(); n++) { - if (datas_[i].elem_ptrs[n]->enabled) d_size++; + if (reinterpret_cast(datas_[i].tar_ptrs[n])->enabled) d_size++; } if (d_size && d_size == valid_elem_size_) @@ -1960,7 +1964,7 @@ void gctl::mesh_io::save_vtk_legacy_ascii(std::string filename) for (size_t a = 0; a < datas_[i].val.size(); a++) { - if (datas_[i].elem_ptrs[a]->enabled) outfile << std::setprecision(16) << datas_[i].val[a] << "\n"; + if (reinterpret_cast(datas_[i].tar_ptrs[a])->enabled) outfile << std::setprecision(16) << datas_[i].val[a] << "\n"; } } } @@ -1989,13 +1993,14 @@ void gctl::mesh_io::save_data_to_xyz(std::string filename, std::string dataname, if (datas_[i].d_type == NodeData) { - for (size_t n = 0; n < datas_[i].vert_ptrs.size(); n++) + for (size_t n = 0; n < datas_[i].tar_ptrs.size(); n++) { - if (datas_[i].vert_ptrs[n]->id != DEFAULT_INVALID_TAG) + vertex3dc* vptr = reinterpret_cast(datas_[i].tar_ptrs[n]); + if (vptr->id != DEFAULT_INVALID_TAG) { if (out_coor == Spherical) { - ps = datas_[i].vert_ptrs[n]->c2s(); + ps = vptr->c2s(); ps.rad -= ellipse_radius_2d(refR, refr, ps.lat*M_PI/180.0); ofile << ps.lon << " " << ps.lat << " " << ps.rad << " " << datas_[i].val[n] << "\n"; @@ -2007,17 +2012,18 @@ void gctl::mesh_io::save_data_to_xyz(std::string filename, std::string dataname, } else { - for (size_t e = 0; e < datas_[i].elem_ptrs.size(); e++) + for (size_t e = 0; e < datas_[i].tar_ptrs.size(); e++) { - if (datas_[i].elem_ptrs[e]->enabled) + meshio_element* mptr = reinterpret_cast(datas_[i].tar_ptrs[e]); + if (mptr->enabled) { pc = point3dc(0.0, 0.0, 0.0); - tmp_size = datas_[i].elem_ptrs[e]->vert_ptrs.size(); - for (size_t v = 0; v < datas_[i].elem_ptrs[e]->vert_ptrs.size(); v++) + tmp_size = mptr->vert_ptrs.size(); + for (size_t v = 0; v < mptr->vert_ptrs.size(); v++) { - pc.x += datas_[i].elem_ptrs[e]->vert_ptrs[v]->x; - pc.y += datas_[i].elem_ptrs[e]->vert_ptrs[v]->y; - pc.z += datas_[i].elem_ptrs[e]->vert_ptrs[v]->z; + pc.x += mptr->vert_ptrs[v]->x; + pc.y += mptr->vert_ptrs[v]->y; + pc.z += mptr->vert_ptrs[v]->z; } pc.x /= tmp_size; pc.y /= tmp_size; diff --git a/lib/io/mesh_io.h b/lib/io/mesh_io.h index 372fd98..40998c8 100644 --- a/lib/io/mesh_io.h +++ b/lib/io/mesh_io.h @@ -125,9 +125,8 @@ namespace gctl array str_tag; // 字符串类型的标签(默认为一个,即为数据的名称) array real_tag; // 实数类型的标签(默认为一个,等于0.0) array int_tag; // 整数类型的标签(最少三个,最后一个为数据的长度) - array vert_ptrs; // 两者只能存在一个 - array elem_ptrs; // 两者只能存在一个 - array val; // 数据值 + array tar_ptrs; // 数据连接的对象指针数组 具体类型为vertex3dc*或meshio_element* + array val; // 数据值(目前仅支持标量数据,后续再添加对矢量数据的支持) meshio_data(); From ad55ba233aca16aeebf886e5c4f81b10f9a08f90 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Sun, 26 Jan 2025 12:03:46 +0800 Subject: [PATCH 10/12] update dsv_io --- lib/io/dsv_io.cpp | 42 +++++++++++++++++++++++++++++++++--------- lib/io/dsv_io.h | 29 ++++++++++++++++------------- 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/lib/io/dsv_io.cpp b/lib/io/dsv_io.cpp index dcb20ba..986b679 100644 --- a/lib/io/dsv_io.cpp +++ b/lib/io/dsv_io.cpp @@ -94,22 +94,46 @@ void gctl::dsv_io::get_column_names(std::vector &names) return; } -void gctl::dsv_io::set_row_names(const std::vector &names, std::string corner_name) +void gctl::dsv_io::set_row_names(const std::vector &names, const std::vector &idx, std::string corner_name) { - for (size_t i = 1; i <= std::min(row_num_, (int) names.size()); i++) + if (!idx.empty()) { - table_[i][0].str_ = names[i - 1]; + if (idx.size() != names.size()) throw std::runtime_error("[gctl::dsv_io] The size of idx and names must be the same."); + + for (size_t i = 0; i < names.size(); i++) + { + table_[idx[i]][0].str_ = names[i]; + } + } + else + { + for (size_t i = 1; i <= std::min(row_num_, (int) names.size()); i++) + { + table_[i][0].str_ = names[i - 1]; + } } table_[0][0].str_ = corner_name; return; } -void gctl::dsv_io::set_column_names(const std::vector &names) +void gctl::dsv_io::set_column_names(const std::vector &names, const std::vector &idx) { - for (size_t i = 1; i <= std::min(col_num_, (int) names.size()); i++) + if (!idx.empty()) { - table_[0][i].str_ = names[i - 1]; + if (idx.size() != names.size()) throw std::runtime_error("[gctl::dsv_io] The size of idx and names must be the same."); + + for (size_t i = 0; i < names.size(); i++) + { + table_[0][idx[i]].str_ = names[i]; + } + } + else + { + for (size_t i = 1; i <= std::min(col_num_, (int) names.size()); i++) + { + table_[0][i].str_ = names[i - 1]; + } } return; } @@ -674,7 +698,7 @@ void gctl::dsv_io::filt_column(std::string cnd_str, std::string cnd_col, } out_table.set_column_names(io_col); - out_table.set_row_names(row_names, table_[0][0].str_); + out_table.set_row_names(row_names, {}, table_[0][0].str_); destroy_vector(row_names); destroy_vector(io_col); @@ -749,7 +773,7 @@ void gctl::dsv_io::filt_column(rowbool_func_t func, const std::vector或列名称C指定相应的行或列 + * @brief DSV文本读写类型可以读写并处理一定格式保存的文本数据,具体的格式如下: + * 1. 所有以注释符(默认为#号)开始的行均会保存至注释变量内,可由用户提取; + * 2. 所有以标记符(默认为#!号)开始的行均会保存至标记变量内,可由用户提取; + * 3. 文件内可以包含n(默认为0)行不以注释或标记符开始头信息行,保存为头信息变量内,可由用户提取; + * 4. 注释、标记和头信息可出现在文本数据的任意行,且只有在头信息读入结束后才会开始读入数据; + * 5. 读入的表格保存为一个二维字符串数组,可由用户提取。浮点类型在读入/保存时可设置有效数字位数; + * 6. 若制定读入的数据表格存在行或列表头,则读入表格的第一列或第一行将被初始化为对应的行名称或列名称; + * 7. 表格的行与列数据可通过数字索引访问(从1开始计数),也可由具体的行或列名称指定; + * 8. 表格可识别内置的行与列名称(格式为为R和C),但不能用于输出文件。 */ class dsv_io { @@ -273,16 +273,19 @@ namespace gctl /** * @brief 设置行名称 * - * @param names 名称 + * @param names 名称数组 + * @param idx 索引数组(若为空则依次设置行名称) + * @param corner_name 表格左上角位置名称(默认为RowNames) */ - void set_row_names(const std::vector &names, std::string corner_name = "row-idx"); + void set_row_names(const std::vector &names, const std::vector &idx = {}, std::string corner_name = "RowNames"); /** * @brief 设置列名称 * - * @param names 名称 + * @param names 名称数组 + * @param idx 索引数组(若为空则依次设置行名称) */ - void set_column_names(const std::vector &names); + void set_column_names(const std::vector &names, const std::vector &idx = {}); /** * @brief 设置行类型 From 45bbee79e9337bf798bb3c8b6b0136c65c1539ae Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Mon, 3 Feb 2025 10:22:27 +0800 Subject: [PATCH 11/12] tmp --- lib/io/mesh_io.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/io/mesh_io.cpp b/lib/io/mesh_io.cpp index 8d3a03e..b0b55b1 100644 --- a/lib/io/mesh_io.cpp +++ b/lib/io/mesh_io.cpp @@ -1541,6 +1541,8 @@ void gctl::mesh_io::read_gmsh_v2_ascii(std::string filename, index_packed_e is_p elems_[i].type = elem_gmsh_type(type_code); elems_[i].vert_ptrs.resize(elem_size(elems_[i].type)); + // 这里暂时不考虑单元体的邻居关系 相关功能不应该由IO类型实现 + //elems_[i].neigh_ptrs.resize(elem_size(elems_[i].type), nullptr); // we get at least three tags. see below for tag types // default tags will be assgined to DEFAULT_INVALID_TAG @@ -2169,5 +2171,7 @@ void gctl::mesh_io::sort_groups() { if (groups_[i].enabled) valid_group_size_++; } + + destroy_vector(tmp_groups); return; } \ No newline at end of file From c8a39f403c42fe659d081747a78befce179200b2 Mon Sep 17 00:00:00 2001 From: Yi Zhang Date: Mon, 3 Feb 2025 11:23:32 +0800 Subject: [PATCH 12/12] update readme --- GCTL_logo.jpg | Bin 0 -> 33450 bytes README.md | 265 ++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 236 insertions(+), 29 deletions(-) create mode 100644 GCTL_logo.jpg diff --git a/GCTL_logo.jpg b/GCTL_logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..80cc01674ce063dd80360c915207d19eda1acaa0 GIT binary patch literal 33450 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 421bf2e..322c215 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,249 @@ +![logo](GCTL_logo.jpg) + # Geophysical Computational Tools & Library (GCTL) -GCTL is a package of computational tools and C++ library for geophysical studies. The complete package is composed of a core library and additional libraries and command line tools. A full list of GCTL's libraries are listed as: +GCTL 是一个用于地球物理研究的计算工具和 C++ 库。完整的软件包由核心库和额外的库以及命令行工具组成。本库采用现代 C++ 设计,提供高性能的数值计算和数据处理功能。 -1. **gctl**: the core library (stored at this repository); -2. **gctl_potential**: library of the algorithms for working with the potential field data (i.e., gravitational and magnetic data); -3. **gctl_seismic**: library of the algorithms for working with the seismic/earthquake data; -4. **gctl_elecmag**: library of the algorithms for working with the elecmagnetic/magnetotelluric data; -5. **gctl_optimization**: library of the optimization algorithms; -6. **gctl_ai**: library of the artificial intelligence algorithms; -6. **gctl_graphic**: library for data visualization; -7. **gctl_examples**: executable examples; -8. **gctl_toolkits**: command line tools. +## 主要特性 -## Dependences +- **高性能**: 采用现代 C++ 技术,支持并行计算和 SIMD 优化 +- **易用性**: 直观的 API 设计,完善的文档和示例 +- **可扩展**: 模块化设计,支持自定义扩展 +- **可靠性**: 完整的单元测试,异常安全保证 +- **跨平台**: 支持 Linux、macOS 和 Windows -There are several third-party libraries that could be employed by the GCTL during the compilation to enable extral functionalities. The inclusion of the exterior libraries are controlled using the CMake compile options as `-D