gctl_mesh/lib/mesh/mesh.cpp
2025-04-23 21:55:30 +08:00

581 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* Geophysical Computational Tools & Library (GCTL)
*
* Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn)
*
* GCTL is distributed under a dual licensing scheme. You can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either version 2
* of the License, or (at your option) any later version. You should have
* received a copy of the GNU Lesser General Public License along with this
* program. If not, see <http://www.gnu.org/licenses/>.
*
* If the terms and conditions of the LGPL v.2. would prevent you from using
* the GCTL, please consider the option to obtain a commercial license for a
* fee. These licenses are offered by the GCTL's original author. As a rule,
* licenses are provided "as-is", unlimited in time for a one time fee. Please
* send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget
* to include some description of your company and the realm of its activities.
* Also add information on how to contact you by electronic and paper mail.
******************************************************/
#include "mesh.h"
gctl::base_mesh::base_mesh()
{
meshtype_ = UNDEFINED;
meshdim_ = MESH_0D;
meshname_ = "Untitled";
meshinfo_ = "Undefined";
node_num_ = ele_num_ = 0;
initialized_ = false;
// 注意这里我们一定要预先为datalist_分配空间因为
// datalist_为vector类型所以元素增加时可能造成
// 原有的迭代器失效造成访问失败。一个简单的例子是做
// 网格加法时我们通过get_data获取两个网格数据并将
// 计算结果通过add_data保存这时候就可能出现vector
// 扩容造成get_data获取的数据无法访问访问失败。
// 默认可以保存100个网格数据应该是够用了。同时
// 在add_data中添加相应的错误提示。
datalist_.reserve(100);
}
gctl::base_mesh::~base_mesh()
{
clear();
}
void gctl::base_mesh::clear()
{
meshtype_ = UNDEFINED;
meshdim_ = MESH_0D;
meshname_ = "Untitled";
meshinfo_ = "Undefined";
node_num_ = ele_num_ = 0;
initialized_ = false;
destroy_vector(datalist_);
datalist_.reserve(100);
return;
}
bool gctl::base_mesh::initiated() const
{
return initialized_;
}
bool gctl::base_mesh::saved(std::string datname) const
{
if (datalist_.empty()) return false;
else
{
for (size_t i = 0; i < datalist_.size(); i++)
{
if (datalist_[i].name_ == datname) return true;
}
return false;
}
}
gctl::meshdata &gctl::base_mesh::get_data(std::string datname)
{
return datalist_[data_index(datname)];
}
const gctl::meshdata &gctl::base_mesh::get_data(std::string datname) const
{
return datalist_[data_index(datname)];
}
gctl::meshdata *gctl::base_mesh::get_data_ptr(std::string datname)
{
return &datalist_[data_index(datname)];
}
void gctl::base_mesh::remove_data(std::string datname)
{
int idx = data_index(datname);
datalist_.erase(datalist_.begin() + idx);
return;
}
void gctl::base_mesh::show_info(std::ostream &os) const
{
if (meshtype_ == UNDEFINED) os << "Undefined | ";
if (meshtype_ == REGULAR_MESH) os << "Regular | ";
if (meshtype_ == LINEAR_MESH) os << "Linear | ";
if (meshtype_ == TRI_TET_MESH) os << "Unstructured | ";
if (meshtype_ == REGULAR_MESH_SPH) os << "Regular (spherical) | ";
if (meshtype_ == LINEAR_MESH_SPH) os << "Linear (spherical) | ";
if (meshtype_ == TRI_TET_MESH_SPH) os << "Unstructured (spherical) | ";
if (meshtype_ == REGULAR_GRID) os << "Grid | ";
if (meshdim_ == MESH_0D) os << "Unknown" << std::endl;
else if (meshdim_ == MESH_2D) os << "2D" << std::endl;
else if (meshdim_ == MESH_3D) os << "3D" << std::endl;
os << "Name: " << meshname_ << std::endl;
os << "Info: " << meshinfo_ << std::endl;
show_mesh_dimension(os);
for (size_t i = 0; i < datalist_.size(); i++)
{
datalist_[i].show_info(os);
}
return;
}
gctl::mesh_type_e gctl::base_mesh::get_meshtype() const
{
check_initiated();
return meshtype_;
}
gctl::mesh_dim_e gctl::base_mesh::get_meshdim() const
{
check_initiated();
return meshdim_;
}
int gctl::base_mesh::get_nodenum() const
{
check_initiated();
return node_num_;
}
int gctl::base_mesh::get_elenum() const
{
check_initiated();
return ele_num_;
}
int gctl::base_mesh::get_datanum() const
{
check_initiated();
return datalist_.size();
}
std::string gctl::base_mesh::get_meshname() const
{
check_initiated();
return meshname_;
}
void gctl::base_mesh::set_meshname(std::string in_name)
{
check_initiated();
meshname_ = in_name;
return;
}
std::string gctl::base_mesh::get_meshinfo() const
{
check_initiated();
return meshinfo_;
}
void gctl::base_mesh::set_meshinfo(std::string in_info)
{
check_initiated();
meshinfo_ = in_info;
return;
}
gctl::meshdata &gctl::base_mesh::add_data(mesh_data_type_e in_loctype, mesh_data_value_e in_valtype,
std::string name, double init_val, bool if_output, double nan_val)
{
check_initiated();
if (datalist_.size() == 100) throw std::runtime_error("[gctl::base_mesh] Maximal data number reached.");
meshdata new_data(in_loctype, in_valtype, 0, name, if_output, nan_val);
if (in_loctype == NodeData && in_valtype == Scalar) new_data.datval_.resize(node_num_, init_val);
else if (in_loctype == ElemData && in_valtype == Scalar) new_data.datval_.resize(ele_num_, init_val);
else if (in_loctype == NodeData && in_valtype == Vector) new_data.datval_.resize(3*node_num_, init_val);
else if (in_loctype == ElemData && in_valtype == Vector) new_data.datval_.resize(3*ele_num_, init_val);
else if (in_loctype == NodeData && in_valtype == Tensor) new_data.datval_.resize(9*node_num_, init_val);
else if (in_loctype == ElemData && in_valtype == Tensor) new_data.datval_.resize(9*ele_num_, init_val);
else throw std::runtime_error("[gctl::base_mesh] Fail to initialize the new data.");
datalist_.push_back(new_data);
return datalist_.back();
}
gctl::meshdata &gctl::base_mesh::add_data(mesh_data_type_e in_loctype, std::string name,
const array<double> &init_arr, bool if_output, double nan_val)
{
check_initiated();
if (datalist_.size() == 100) throw std::runtime_error("[gctl::base_mesh] Maximal data number reached.");
meshdata new_data(in_loctype, Scalar, 0, name, if_output, nan_val);
if (in_loctype == NodeData)
{
if (init_arr.size() != node_num_) throw std::runtime_error("[gctl::base_mesh] Invalid input data size.");
new_data.datval_ = init_arr;
}
else if (in_loctype == ElemData)
{
if (init_arr.size() != ele_num_) throw std::runtime_error("[gctl::base_mesh] Invalid input data size.");
new_data.datval_ = init_arr;
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data location.");
datalist_.push_back(new_data);
return datalist_.back();
}
gctl::meshdata &gctl::base_mesh::add_data(mesh_data_type_e in_loctype, std::string name,
const array<point3dc> &init_arr, bool if_output, double nan_val)
{
check_initiated();
if (datalist_.size() == 100) throw std::runtime_error("[gctl::base_mesh] Maximal data number reached.");
meshdata new_data(in_loctype, Vector, 0, name, if_output, nan_val);
if (in_loctype == NodeData)
{
if (init_arr.size() != node_num_) throw std::runtime_error("[gctl::base_mesh] Invalid input data size.");
new_data.datval_.resize(3*node_num_);
for (size_t i = 0; i < node_num_; i++)
{
new_data.datval_[3*i] = init_arr[i].x;
new_data.datval_[3*i+1] = init_arr[i].y;
new_data.datval_[3*i+2] = init_arr[i].z;
}
}
else if (in_loctype == ElemData)
{
if (init_arr.size() != ele_num_) throw std::runtime_error("[gctl::base_mesh] Invalid input data size.");
new_data.datval_.resize(3*ele_num_);
for (size_t i = 0; i < ele_num_; i++)
{
new_data.datval_[3*i] = init_arr[i].x;
new_data.datval_[3*i+1] = init_arr[i].y;
new_data.datval_[3*i+2] = init_arr[i].z;
}
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data location.");
datalist_.push_back(new_data);
return datalist_.back();
}
gctl::meshdata &gctl::base_mesh::add_data(mesh_data_type_e in_loctype, std::string name,
const array<tensor> &init_arr, bool if_output, double nan_val)
{
check_initiated();
if (datalist_.size() == 100) throw std::runtime_error("[gctl::base_mesh] Maximal data number reached.");
meshdata new_data(in_loctype, Tensor, 0, name, if_output, nan_val);
if (in_loctype == NodeData)
{
if (init_arr.size() != node_num_) throw std::runtime_error("[gctl::base_mesh] Invalid input data size.");
new_data.datval_.resize(9*node_num_);
for (size_t i = 0; i < node_num_; i++)
{
new_data.datval_[9*i] = init_arr[i].val[0][0];
new_data.datval_[9*i+1] = init_arr[i].val[0][1];
new_data.datval_[9*i+2] = init_arr[i].val[0][2];
new_data.datval_[9*i+3] = init_arr[i].val[1][0];
new_data.datval_[9*i+4] = init_arr[i].val[1][1];
new_data.datval_[9*i+5] = init_arr[i].val[1][2];
new_data.datval_[9*i+6] = init_arr[i].val[2][0];
new_data.datval_[9*i+7] = init_arr[i].val[2][1];
new_data.datval_[9*i+8] = init_arr[i].val[2][2];
}
}
else if (in_loctype == ElemData)
{
if (init_arr.size() != ele_num_) throw std::runtime_error("[gctl::base_mesh] Invalid input data size.");
new_data.datval_.resize(9*ele_num_);
for (size_t i = 0; i < ele_num_; i++)
{
new_data.datval_[9*i] = init_arr[i].val[0][0];
new_data.datval_[9*i+1] = init_arr[i].val[0][1];
new_data.datval_[9*i+2] = init_arr[i].val[0][2];
new_data.datval_[9*i+3] = init_arr[i].val[1][0];
new_data.datval_[9*i+4] = init_arr[i].val[1][1];
new_data.datval_[9*i+5] = init_arr[i].val[1][2];
new_data.datval_[9*i+6] = init_arr[i].val[2][0];
new_data.datval_[9*i+7] = init_arr[i].val[2][1];
new_data.datval_[9*i+8] = init_arr[i].val[2][2];
}
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data location.");
datalist_.push_back(new_data);
return datalist_.back();
}
void gctl::base_mesh::save_gmsh_withdata(std::string filename, output_type_e out_mode, index_packed_e packed)
{
if (out_mode == OverWrite) save_gmsh(filename, packed);
for (size_t i = 0; i < datalist_.size(); i++)
{
if (datalist_[i].loctype_ == NodeData)
{
if (datalist_[i].valtype_ == Scalar) meshio_.save_data(datalist_[i].name_, datalist_[i].datval_, NodeData);
else if (datalist_[i].valtype_ == Vector)
{
array<point3dc> vec_data(node_num_);
for (size_t j = 0; j < node_num_; j++)
{
vec_data[j].x = datalist_[i].datval_[3*j];
vec_data[j].y = datalist_[i].datval_[3*j+1];
vec_data[j].z = datalist_[i].datval_[3*j+2];
}
meshio_.save_data(datalist_[i].name_, vec_data, NodeData);
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data value type.");
}
else if (datalist_[i].loctype_ == ElemData)
{
if (datalist_[i].valtype_ == Scalar) meshio_.save_data(datalist_[i].name_, datalist_[i].datval_, ElemData);
else if (datalist_[i].valtype_ == Vector)
{
array<point3dc> vec_data(ele_num_);
for (size_t j = 0; j < ele_num_; j++)
{
vec_data[j].x = datalist_[i].datval_[3*j];
vec_data[j].y = datalist_[i].datval_[3*j+1];
vec_data[j].z = datalist_[i].datval_[3*j+2];
}
meshio_.save_data(datalist_[i].name_, vec_data, ElemData);
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data value type.");
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data location.");
}
return;
}
void gctl::base_mesh::save_gmsh_withdata(std::string filename, std::string datname, output_type_e out_mode, index_packed_e packed)
{
if (out_mode == OverWrite) save_gmsh(filename, packed);
const meshdata &data = get_data(datname);
if (data.loctype_ == NodeData)
{
if (data.valtype_ == Scalar) meshio_.save_data(data.name_, data.datval_, NodeData);
else if (data.valtype_ == Vector)
{
array<point3dc> vec_data(node_num_);
for (size_t j = 0; j < node_num_; j++)
{
vec_data[j].x = data.datval_[3*j];
vec_data[j].y = data.datval_[3*j+1];
vec_data[j].z = data.datval_[3*j+2];
}
meshio_.save_data(data.name_, vec_data, NodeData);
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data value type.");
}
else if (data.loctype_ == ElemData)
{
//gctl::save_gmsh_data(outfile, data.name_, data.datval_, gctl::ElemData, packed);
if (data.valtype_ == Scalar) meshio_.save_data(data.name_, data.datval_, ElemData);
else if (data.valtype_ == Vector)
{
array<point3dc> vec_data(ele_num_);
for (size_t j = 0; j < ele_num_; j++)
{
vec_data[j].x = data.datval_[3*j];
vec_data[j].y = data.datval_[3*j+1];
vec_data[j].z = data.datval_[3*j+2];
}
meshio_.save_data(data.name_, vec_data, ElemData);
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data value type.");
}
else throw std::runtime_error("[gctl::base_mesh] Invalid input data location.");
return;
}
void gctl::base_mesh::load_gmsh_withdata(std::string filename, index_packed_e packed)
{
load_gmsh(filename, packed);
_2d_vector all_node_data, all_elem_data;
_1s_vector nodedata_names, elemdata_names;
meshio_.read_data(all_node_data, nodedata_names, NodeData);
meshio_.read_data(all_elem_data, elemdata_names, ElemData);
for (size_t i = 0; i < nodedata_names.size(); i++)
{
add_data(NodeData, Scalar, nodedata_names[i], 0.0);
}
for (size_t i = 0; i < elemdata_names.size(); i++)
{
add_data(ElemData, Scalar, elemdata_names[i], 0.0);
}
meshdata *data_ptr = nullptr;
for (size_t i = 0; i < nodedata_names.size(); i++)
{
data_ptr = get_data_ptr(nodedata_names[i]);
if (data_ptr != nullptr)
{
for (size_t n = 0; n < node_num_; n++)
{
data_ptr->datval_[n] = all_node_data[i][n];
}
}
}
for (size_t i = 0; i < elemdata_names.size(); i++)
{
data_ptr = get_data_ptr(elemdata_names[i]);
if (data_ptr != nullptr)
{
for (size_t n = 0; n < ele_num_; n++)
{
data_ptr->datval_[n] = all_elem_data[i][n];
}
}
}
return;
}
void gctl::base_mesh::load_gmsh_withdata(std::string filename, std::string datname,
mesh_data_type_e type, index_packed_e packed)
{
load_gmsh(filename, packed);
array<double> tmp_data;
meshio_.read_data(tmp_data, datname);
if (type == NodeData) add_data(NodeData, datname, tmp_data);
else if (type == ElemData) add_data(ElemData, datname, tmp_data);
else throw std::runtime_error("[gctl::base_mesh] Invalid mesh data type.");
return;
}
/**
* 以下是类的私有函数,可以简单一些
*/
void gctl::base_mesh::check_initiated(bool inverse) const
{
if (inverse == true)
{
if (initialized_) throw std::runtime_error("[gctl::base_mesh] Mesh already initialized.");
else return;
}
if (!initialized_) throw std::runtime_error("[gctl::base_mesh] Mesh not initialized.");
else return;
}
void gctl::base_mesh::init(mesh_type_e in_type, mesh_dim_e in_dim, std::string in_name, std::string in_info)
{
if (in_name == "") throw std::runtime_error("[gctl::base_mesh] The input name is empty.");
if (in_info == "") throw std::runtime_error("[gctl::base_mesh] The input info. is empty.");
meshname_ = in_name;
meshinfo_ = in_info;
meshtype_ = in_type;
meshdim_ = in_dim;
return;
}
int gctl::base_mesh::data_index(std::string datname) const
{
if (datalist_.empty()) throw std::runtime_error("[gctl::base_mesh] No data saved.");
for (size_t i = 0; i < datalist_.size(); i++)
{
if (datalist_[i].name_ == datname) return i;
}
throw gctl::runtime_error("[gctl::base_mesh] No data found by the name: " + datname);
}
void gctl::base_mesh::load_headinfo(std::ifstream &infile, mesh_type_e expected_type, mesh_dim_e expected_dim)
{
// 读入网格头信息
infile.read((char*)&meshtype_, sizeof(int));
infile.read((char*)&meshdim_, sizeof(int));
if (meshdim_ != expected_dim || meshtype_ != expected_type)
{
infile.close();
throw std::runtime_error("[gctl::base_mesh] Invalid input mesh type.");
}
int info_size;
infile.read((char*)&info_size, sizeof(int));
meshname_.resize(info_size);
infile.read((char*)meshname_.c_str(), info_size);
infile.read((char*)&info_size, sizeof(int));
meshinfo_.resize(info_size);
infile.read((char*)meshinfo_.c_str(), info_size);
return;
}
void gctl::base_mesh::load_datablock(std::ifstream &infile)
{
int in_num;
meshdata new_data;
infile.read((char*)&in_num, sizeof(int));
for (int i = 0; i < in_num; i++)
{
new_data.clear();
new_data.load_binary(infile);
datalist_.push_back(new_data);
}
return;
}
void gctl::base_mesh::save_headinfo(std::ofstream &outfile)
{
// 首先输出网格的类型和维度
outfile.write((char*)&meshtype_, sizeof(int));
outfile.write((char*)&meshdim_, sizeof(int));
// 输出网格名称与信息
int info_size = meshname_.size();
outfile.write((char*)&info_size, sizeof(int));
outfile.write((char*)meshname_.c_str(), info_size);
info_size = meshinfo_.size();
outfile.write((char*)&info_size, sizeof(int));
outfile.write((char*)meshinfo_.c_str(), info_size);
return;
}
void gctl::base_mesh::save_datablock(std::ofstream &outfile)
{
int num = 0;
for (size_t i = 0; i < datalist_.size(); i++)
{
if (datalist_[i].output_ok_) num++;
}
outfile.write((char*) &num, sizeof(int));
for (size_t i = 0; i < datalist_.size(); i++)
{
if (datalist_[i].output_ok_)
{
datalist_[i].save_binary(outfile); // 输出数据块
}
}
return;
}