想写一个计算缺陷管道失效压力的程序,输入管道尺寸及裂纹参数能够使用不能的方法计算出失效压力,然后输出到csv文件中。
github地址
1、失效模型
根据需求选定策略模型来编写失效模型,方便代码维护。
首先定义一个抽象类,具有calucate
函数,其他子类都要重写这个函数,实现不同的功能。
1 2 3 4 5
| class FailurePressureAbstract { public: virtual double calucate(const Params& params) = 0; virtual ~FailurePressureAbstract() = default; };
C++
|
其中Params
类型是一个列表,可存储float
、double
和int
三种类型,定义如下
1
| using Params = std::vector<std::variant<float, double, int>>;
C++
|
子类集成父类,定义如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| class ASMEB31G2009 : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class RSTRENG085dL : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class PCORRC : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class DNV_RP_F101 : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class C_Fer : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class AGANG18 : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class Netto : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
class RAM_PIPE_REQUAL : public FailurePressureAbstract { public: double calucate(const Params& params) override; };
C++
|
子类实现如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
| double ASMEB31G2009::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double SMYS = std::get<double>(params[4]);
double S_flow = SMYS * 1.1; double z = pow(l, 2) / (D * t);
double M = 0.0; if (z > 50) { M = 0.032 * z + 3.3; } else { M = pow(1 + 0.6275 * z - 0.003375 * pow(z, 2), 0.5); }
double failure_pressure = S_flow * 2 * t / D * (1 - 0.85 * d / t) / (1 - 0.85 * d / t / M); std::cout << "调用 ASMEB31G2009 成功" << failure_pressure << std::endl; return failure_pressure; };
double RSTRENG085dL::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double SMYS = std::get<double>(params[4]);
double S_flow = SMYS + 68.95; double z = pow(l, 2) / (D * t);
double M = 0.0; if (z > 50) { M = 0.032 * z + 3.3; } else { M = pow(1 + 0.6275 * z - 0.003375 * pow(z, 2), 0.5); }
double failure_pressure = S_flow * 2 * t / D * (1 - 0.85 * d / t) / (1 - 0.85 * d / t / M); std::cout << "调用 RSTRENG085dL 成功" << failure_pressure << std::endl; return failure_pressure; }
double PCORRC::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double UTS = std::get<double>(params[4]);
double M = 1 - exp((-0.157 * l) / (pow(D / 2, 0.5) * (t - d)));
double failure_pressure = 2 * t * UTS / D * (1 - d * M / t); cout << "调用 PCORRC 成功" << failure_pressure << endl; return failure_pressure; }
double DNV_RP_F101::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double UTS = std::get<double>(params[4]);
double M = pow(1 + 0.31 * pow(l, 2) / (D * t), 0.5);
double failure_pressure = 2 * t * UTS / (D - t) * ((1 - d / t) / (1 - d / t / M)); cout << "调用 DNV_RP_F101 成功" << failure_pressure << endl; return failure_pressure; }
double C_Fer::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double SMYS = std::get<double>(params[4]);
double z = pow(l, 2) / (D * t); double S_flow = SMYS * 0.9;
double M = 0.0; if (z > 50) { M = 0.032 * z + 3.3; } else { M = pow(1 + 0.6275 * z - 0.003375 * pow(z, 2), 0.5); }
double A0 = l * t; double A = l * d;
double failure_pressure = 2 * t * S_flow / D * (1 - A/A0) / (1- A / A0 / M); cout << "调用 C_Fer 成功" << failure_pressure << endl; return failure_pressure; }
double AGANG18::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double SMYS = std::get<double>(params[4]);
return 0.0; }
double Netto::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double SMYS = std::get<double>(params[4]);
double failure_pressure = 1.1 * SMYS * 2 * t / D * (1 - 0.9435 * pow(d / t, 1.6) * pow(l / D, 0.4)); cout << "调用 Netto 成功" << failure_pressure << endl; return failure_pressure; }
double RAM_PIPE_REQUAL::calucate(const Params& params) { double t = std::get<double>(params[0]); double D = std::get<double>(params[1]); double d = std::get<double>(params[2]); double l = std::get<double>(params[3]); double UTS = std::get<double>(params[4]);
double SCF = 1 + 2 * pow(2 * d / D, 0.5); double failure_pressure = 2.2 * (t - d) * UTS / (D - t) / SCF; cout << "调用 RAM_PIPE_REQUAL 成功" << failure_pressure << endl; return failure_pressure; }
C++
|
2、定义上下文类
使用智能指针管理生命周期,并保证子类的所有权
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class FailurePressureContext { private: std::unique_ptr<FailurePressureAbstract> strategy; public: explicit FailurePressureContext(std::unique_ptr<FailurePressureAbstract> newStrategy) : strategy(move(newStrategy)) { }
void setStrategy(std::unique_ptr<FailurePressureAbstract> newStrategy);
double executeStrategy(const Params& params); };
void FailurePressureContext::setStrategy(std::unique_ptr<FailurePressureAbstract> newStrategy) { strategy = move(newStrategy); }
double FailurePressureContext::executeStrategy(const Params& params) { if (strategy) { return strategy.get()->calucate(params); } }
C++
|
3、输出文件类定义
主要有打开、关闭文件,写入行函数,写入行函数使用模板实现传入不同类型的值。
这里一开始写的写入头
函数只能写入字符串,在调用时需要将其他类型转化一下,不太方便,于是还按照写入行
函数进行调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| class CSVFileWriter { private: std::ofstream file;
public: CSVFileWriter(const std::string& filename);
~CSVFileWriter();
template<typename T> void writeHeader(const std::vector<T>& headers);
template<typename T> void writeRow(const std::vector<T>& row);
bool isOpen() const; };
template<typename T> void CSVFileWriter::writeRow(const std::vector<T>& row) { for (size_t i = 0; i < row.size(); ++i) { std::visit([this, i, size = row.size()](const auto& arg) { file << arg << (i < size - 1 ? "," : ""); }, row[i]); } file << "\n"; }
template<typename T> void CSVFileWriter::writeHeader(const std::vector<T>& headers) { writeRow(headers); }
CSVFileWriter::CSVFileWriter(const std::string& filename) { file.open(filename); if (!file.is_open()) { throw std::runtime_error("无法打开文件: " + filename); } }
CSVFileWriter::~CSVFileWriter() { if (file.is_open()) { file.close(); } }
bool CSVFileWriter::isOpen() const { return file.is_open(); }
C++
|
4、示例调用
这里有详细的注释就不写了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
std::string name = "X52";
Params X52_SMYS = { 6.3, 462.6, 6.0, 200.0, 435.5 };
Params X52_UTS = { 6.3, 462.6, 6.0, 200.0, 530.0 };
using RowParams = std::vector<std::variant<double, std::string>>; RowParams ASMEB31G2009_res_list = { "ASMEB31G2009" }; RowParams RSTRENG085dL_res_list = { "RSTRENG085dL" }; RowParams PCORRC_res_list = { "PCORRC" }; RowParams DNV_RP_F101_res_list = { "DNV_RP_F101" }; RowParams C_Fer_res_list = { "C_Fer" }; RowParams Netto_res_list = { "Netto" }; RowParams RAM_PIPE_REQUAL_res_list = { "RAM_PIPE_REQUAL" };
std::vector<RowParams*> rows; rows.push_back(&ASMEB31G2009_res_list ); rows.push_back(&RSTRENG085dL_res_list ); rows.push_back(&PCORRC_res_list ); rows.push_back(&DNV_RP_F101_res_list); rows.push_back(&C_Fer_res_list ); rows.push_back(&Netto_res_list ); rows.push_back(&RAM_PIPE_REQUAL_res_list );
C++
|
调用上下文类计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
std::vector<double> t = { 1, 2, 3, 4, 5, 6 }; for (size_t i = 0; i < t.size(); i++) { X52_SMYS[2] = t[i]; X52_UTS[2] = t[i];
FailurePressureContext context(make_unique<ASMEB31G2009>()); ASMEB31G2009_res_list.push_back( context.executeStrategy(X52_SMYS) );
context.setStrategy(make_unique<RSTRENG085dL>()); RSTRENG085dL_res_list.push_back(context.executeStrategy(X52_SMYS));
context.setStrategy(make_unique<PCORRC>()); PCORRC_res_list.push_back(context.executeStrategy(X52_UTS) );
context.setStrategy(make_unique<DNV_RP_F101>()); DNV_RP_F101_res_list.push_back(context.executeStrategy(X52_UTS) );
context.setStrategy(make_unique<C_Fer>()); C_Fer_res_list.push_back(context.executeStrategy(X52_SMYS) );
context.setStrategy(make_unique<Netto>()); Netto_res_list.push_back(context.executeStrategy(X52_SMYS) );
context.setStrategy(make_unique<RAM_PIPE_REQUAL>()); RAM_PIPE_REQUAL_res_list.push_back(context.executeStrategy(X52_UTS)); }
C++
|
写入文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| try { CSVFileWriter csvWriter(name + ".csv"); RowParams header = { "method"}; header.insert(header.end(), t.begin(), t.end()); csvWriter.writeHeader(header);
for (const auto& entry : rows) { csvWriter.writeRow(*entry); }
std::cout << "数据已成功写入 " << name << ".csv" << std::endl; std::cout << "大功告成 " << name << ".csv" << std::endl; } catch (const std::exception& e) { std::cerr << "错误: " << e.what() << std::endl; return 1; }
C++
|
输出文件示例