#include "DataProcessWorkPool.h" #include "MeasureAnalysisProjectModel.h" #include "GlobalDefine.h" #include "csv.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "DataCalcProcess/MathModelDefine.h" #include "DataCalcProcess/FindPeaksBySvd.h" #include "DataCalcProcess/GaussPolyCoe.h" #include "DataCalcProcess/NolinearLeastSquaresCurveFit.h" #include "EnergyScaleDataModel.h" #include using namespace DataProcessWorkPool; using namespace io; void DataProcessTask::SetFinishedNotifier(QObject* finished_notifier, const char* finished_process, const QString& project_name) { this->_finished_notifier = finished_notifier; this->_finished_notifier_process = finished_process; this->_project_name = project_name; } const QString& DataProcessTask::GetProjectName() const { return this->_project_name; } const char* DataProcessTask::GetFinishedNotifierProcess() const { return this->_finished_notifier_process; } QObject* DataProcessTask::GetFinishedNotifier() const { return this->_finished_notifier; } bool DataProcessTask::IsValidSetWorkParameters() const { return !(this->_project_name.isEmpty()); } void DataProcessTask::StartTask() { QThreadPool::globalInstance()->start(this); } void DataProcessTask::run() { if (!IsValidSetWorkParameters()) { return; } bool task_ok = processTask(); if ((GetFinishedNotifier() != nullptr) && (GetFinishedNotifierProcess() != nullptr)) { QMetaObject::invokeMethod( _finished_notifier, _finished_notifier_process, Qt::QueuedConnection, Q_ARG(bool, task_ok), Q_ARG(QString, _project_name), Q_ARG(QVariant, _task_result_data) ); } } void DataProcessTask::updateTaskResultData(const QVariant &task_result_data) { this->_task_result_data = task_result_data; } void ParticleDataTask::SetAllChannelParticleDataFilename(const QString& all_channel_particle_data_filename) { this->_all_channel_particle_data_filename = all_channel_particle_data_filename; } const QString& ParticleDataTask::GetAllChannelParticleDataFilename() const { return this->_all_channel_particle_data_filename; } bool ParticleDataTask::IsValidSetWorkParameters() const { return (!GetAllChannelParticleDataFilename().isEmpty()) && DataProcessTask::IsValidSetWorkParameters(); } bool ParticleDataTask::processTask() { return processEveryChannelParticleData(); } void EveryChannelParticleDataSeparateTask::SetResultDataDir(const QString& result_data_dir) { this->_result_data_dir = result_data_dir; } const QString& EveryChannelParticleDataSeparateTask::GetResultDataDir() const { return this->_result_data_dir; } bool EveryChannelParticleDataSeparateTask::IsValidSetWorkParameters() const { return (!GetResultDataDir().isEmpty()) && ParticleDataTask::IsValidSetWorkParameters(); } bool EveryChannelParticleDataSeparateTask::processEveryChannelParticleData() { bool ret_ok = true; const QString& result_data_output_dir_path = GetResultDataDir(); QDir result_data_output_dir(result_data_output_dir_path); result_data_output_dir.mkpath(result_data_output_dir_path); const QString& all_channel_particle_data_filename = GetAllChannelParticleDataFilename(); QMap particle_data_filename_list; try { QMap> ch_particle_data_of_list; std::string board_id_str = QString(QStringLiteral(u"板卡号")).toStdString(); std::string channel_id_str = QString(QStringLiteral(u"通道号")).toStdString(); std::string address_str = QString(QStringLiteral(u"道址")).toStdString(); std::string time_str = QString(QStringLiteral(u"时间计数")).toStdString(); // 使用更灵活的方式处理CSV文件,忽略额外列 io::CSVReader< 4, io::trim_chars<' ', '\t'>, io::double_quote_escape<',', '"'>, io::throw_on_overflow, io::empty_line_comment> reader(QStrToSysPath(all_channel_particle_data_filename)); reader.read_header(io::ignore_extra_column, board_id_str, channel_id_str, address_str, time_str); uint board_id; uint channel_id; uint address; unsigned long long time; while (reader.read_row(board_id, channel_id, address, time)) { // 板卡和通道号计算,通道号 = 板卡号 * 4 + 通道号 int channel_num = (board_id) * 4 + (channel_id + 1); QString particle_data_filename = result_data_output_dir.filePath(QStringLiteral(u"通道%1粒子数据.csv").arg(channel_num)); if (!particle_data_filename_list.contains(channel_num)) { particle_data_filename_list.insert(channel_num, particle_data_filename); } if (!ch_particle_data_of_list.contains(channel_num)) { std::shared_ptr out( new std::ofstream(QStrToSysPath(particle_data_filename), std::ios::out | std::ios::app), [](std::ofstream* p) { p->close(); }); *out << QString(QStringLiteral(u"板卡号,通道号,道址,时间计数")).toStdString() << std::endl; ch_particle_data_of_list.insert(channel_num, out); } auto ch_particle_data_of = ch_particle_data_of_list.value(channel_num); *ch_particle_data_of << board_id << "," << channel_id << "," << address << "," << time << std::endl; } } catch (const std::runtime_error& e) { const QString& e_what = QString::fromLatin1(e.what()); QString error = QString(QStringLiteral(u"处理%1发生运行时异常:%2")).arg(all_channel_particle_data_filename).arg(e_what); LOG_ERROR(error) ret_ok = false; } catch (const std::exception& e) { const QString& e_what = QString::fromLatin1(e.what()); QString error = QString(QStringLiteral(u"处理%1异常:%2")).arg(all_channel_particle_data_filename).arg(e_what); LOG_ERROR(error) ret_ok = false; } catch (...) { QString error = QString(QStringLiteral(u"处理%1未知异常.")).arg(all_channel_particle_data_filename); LOG_ERROR(error) ret_ok = false; } const QString& project_name = GetProjectName(); MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name); if (project_model == nullptr) { ret_ok = false; } for (auto it = particle_data_filename_list.begin(); it != particle_data_filename_list.end(); ++it) { // project_model->SetChannelParticleDataFilename(it.key(), it.value()); } return ret_ok; } void EveryChannelParticleCountDataTask::SetAllChannelCountResultDir(const QString& dir_path) { this->_all_ch_count_dir = dir_path; } const QString& EveryChannelParticleCountDataTask::GetAllChannelCountResultDir() const { return this->_all_ch_count_dir; } void EveryChannelParticleCountDataTask::SetEveryChannelCountResultDir(const QString& dir_path) { this->_every_ch_count_dir = dir_path; } const QString& EveryChannelParticleCountDataTask::GetEveryChannelCountResultDir() const { return this->_every_ch_count_dir; } bool EveryChannelParticleCountDataTask::IsValidSetWorkParameters() const { return (!GetAllChannelCountResultDir().isEmpty()) && (!GetEveryChannelCountResultDir().isEmpty()) && ParticleDataTask::IsValidSetWorkParameters(); } bool EveryChannelParticleCountDataTask::processEveryChannelParticleData() { bool ret_ok = true; const QString& all_ch_count_dir = GetAllChannelCountResultDir(); const QString& every_ch_count_dir = GetEveryChannelCountResultDir(); QDir all_ch_count_output_dir(all_ch_count_dir); all_ch_count_output_dir.mkpath(all_ch_count_dir); QDir every_ch_count_output_dir(every_ch_count_dir); every_ch_count_output_dir.mkpath(every_ch_count_dir); const QString& all_channel_particle_data_filename = GetAllChannelParticleDataFilename(); QMap particle_count_filename_list; // QString all_channel_total_count_filename; try { // 统计每个通道的粒子计数(相同板卡号通道号相同道址) QMap> channel_address_counts; // 通道号 -> 地址 -> 计数 // 统计所有通道的粒子计数(不同板卡号通道号相同道址) // QMap all_channel_address_counts; // 地址 -> 计数 std::string board_id_str = QString(QStringLiteral(u"板卡号")).toStdString(); std::string channel_id_str = QString(QStringLiteral(u"通道号")).toStdString(); std::string address_str = QString(QStringLiteral(u"道址")).toStdString(); std::string time_str = QString(QStringLiteral(u"时间计数")).toStdString(); // 使用更灵活的方式处理CSV文件,忽略额外列 io::CSVReader< 4, io::trim_chars<' ', '\t'>, io::double_quote_escape<',', '"'>, io::throw_on_overflow, io::empty_line_comment> reader(QStrToSysPath(all_channel_particle_data_filename)); reader.read_header(io::ignore_extra_column, board_id_str, channel_id_str, address_str, time_str); uint board_id; uint channel_id; uint address; unsigned long long time; while (reader.read_row(board_id, channel_id, address, time)) { // 板卡和通道号计算,通道号 = 板卡号 * 4 + 通道号 int channel_num = (board_id) * 4 + (channel_id + 1); // 统计每个通道的粒子计数 if (!channel_address_counts.contains(channel_num)) { channel_address_counts[channel_num] = QMap(); } channel_address_counts[channel_num][address]++; // 统计所有通道的粒子计数 // all_channel_address_counts[address]++; } // 写入每个通道的粒子计数数据(优化:使用一次打开文件,批量写入) QMap> channel_file_streams; // 预创建所有通道的文件流 for (auto channel_it = channel_address_counts.begin(); channel_it != channel_address_counts.end(); ++channel_it) { uint channel_num = channel_it.key(); QString count_data_filename = every_ch_count_output_dir.filePath(QStringLiteral(u"通道%1粒子计数.csv").arg(channel_num)); particle_count_filename_list.insert(channel_num, count_data_filename); // 创建文件流 std::shared_ptr out(new std::ofstream( QStrToSysPath(count_data_filename))); channel_file_streams[channel_num] = out; *out << QString(QStringLiteral(u"道址")).toStdString() << "," << QString(QStringLiteral(u"计数")).toStdString() << std::endl; } // 批量写入数据 for (auto channel_it = channel_address_counts.begin(); channel_it != channel_address_counts.end(); ++channel_it) { uint channel_num = channel_it.key(); const QMap& address_counts = channel_it.value(); auto out_stream = channel_file_streams[channel_num]; for (auto address_it = address_counts.begin(); address_it != address_counts.end(); ++address_it) { uint address = address_it.key(); uint count = address_it.value(); *out_stream << address << "," << count << std::endl; } } // 文件流会在shared_ptr析构时自动关闭 channel_file_streams.clear(); // 写入所有通道的粒子计数数据 // all_channel_total_count_filename = all_ch_count_output_dir.filePath("AllChannelParticleTotalCountData.csv"); // std::ofstream all_channel_out(QStrToSysPath(all_channel_total_count_filename)); // all_channel_out << QString(QStringLiteral(u"道址")).toStdString() << "," << QString(QStringLiteral(u"计数")).toStdString() << std::endl; // for (auto address_it = all_channel_address_counts.begin(); address_it != all_channel_address_counts.end(); ++address_it) { // uint address = address_it.key(); // uint count = address_it.value(); // all_channel_out << address << "," << count << std::endl; // } // all_channel_out.close(); } catch (const std::runtime_error& e) { const QString& e_what = QString::fromLatin1(e.what()); QString error = QStringLiteral(u"处理%1发生运行时异常:%2").arg(all_channel_particle_data_filename).arg(e_what); LOG_ERROR(error) ret_ok = false; } catch (const std::exception& e) { const QString& e_what = QString::fromLatin1(e.what()); QString error = QStringLiteral(u"处理%1异常:%2").arg(all_channel_particle_data_filename).arg(e_what); LOG_ERROR(error) ret_ok = false; } catch (...) { QString error = QStringLiteral(u"处理%1未知异常.").arg(all_channel_particle_data_filename); LOG_ERROR(error) ret_ok = false; } const QString& project_name = GetProjectName(); MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name); if (project_model == nullptr) { ret_ok = false; } else { // 更新项目模型中的通道粒子计数数据文件名 for (auto it = particle_count_filename_list.begin(); it != particle_count_filename_list.end(); ++it) { project_model->SetChannelAddressCountDataFilename(it.key(), it.value()); } // 更新项目模型中的所有通道粒子总计数数据文件名 // project_model->SetAllChannelParticleTotalCountDataFilename(all_channel_total_count_filename); } const QString& info = QStringLiteral(u"所有通道粒子计数处理完成."); LOG_INFO(info); return ret_ok; } //////////////////////////////////////////////////////////////////////////////////// void ParticleDataSortTask::SetSortedResultDir(const QString& sorted_result_dir) { this->_sorted_result_dir = sorted_result_dir; } const QString& ParticleDataSortTask::GetSortedResultDir() const { return this->_sorted_result_dir; } bool ParticleDataSortTask::IsValidSetWorkParameters() const { return (!GetSortedResultDir().isEmpty()) && ParticleDataTask::IsValidSetWorkParameters(); } struct CsvRow { uint board_id; uint channel_id; uint address; unsigned long long time; size_t chunk_index; bool operator<(const CsvRow& other) const { return time > other.time; } }; std::vector splitFile(const std::string& input_file, size_t chunk_size) { std::vector chunks; try { std::string board_id_str = QString(QStringLiteral(u"板卡号")).toStdString(); std::string channel_id_str = QString(QStringLiteral(u"通道号")).toStdString(); std::string address_str = QString(QStringLiteral(u"道址")).toStdString(); std::string time_str = QString(QStringLiteral(u"时间计数")).toStdString(); io::CSVReader< 4, io::trim_chars<' ', '\t'>, io::double_quote_escape<',', '"'>, io::throw_on_overflow, io::empty_line_comment > reader(input_file); reader.read_header(io::ignore_extra_column, board_id_str, channel_id_str, address_str, time_str); int chunk_index = 0; while (true) { std::vector rows; size_t current_size = 0; uint board_id; uint channel_id; uint address; unsigned long long time; while (reader.read_row(board_id, channel_id, address, time)) { CsvRow row; row.board_id = board_id; row.channel_id = channel_id; row.address = address; row.time = time; // Estimate row size current_size += std::to_string(board_id).size() + std::to_string(channel_id).size() + std::to_string(address).size() + std::to_string(time).size() + 4; if (current_size > chunk_size && !rows.empty()) { break; } rows.push_back(row); } if (rows.empty()) break; std::sort(rows.begin(), rows.end(), [](const CsvRow& a, const CsvRow& b) { return a.time < b.time; }); std::string chunk_file = input_file + ".chunk" + std::to_string(chunk_index); std::ofstream outFile(chunk_file); for (const auto& row : rows) { outFile << row.board_id << "," << row.channel_id << "," << row.address << "," << row.time << "\n"; } outFile.close(); chunks.push_back(chunk_file); chunk_index++; } } catch (const std::exception& e) { throw(e); } return chunks; } void mergeChunks(const std::vector& chunks, const std::string& output_file) { std::vector>> chunk_readers; std::priority_queue min_heap; for (const auto& chunk : chunks) { auto reader = std::make_unique>(chunk); chunk_readers.push_back(std::move(reader)); } for (size_t i = 0; i < chunk_readers.size(); i++) { uint board_id; uint channel_id; uint address; unsigned long long time; if (chunk_readers[i]->read_row(board_id, channel_id, address, time)) { CsvRow row; row.board_id = board_id; row.channel_id = channel_id; row.address = address; row.time = time; row.chunk_index = i; min_heap.push(row); } } std::string board_id_str = QString(QStringLiteral(u"板卡号")).toStdString(); std::string channel_id_str = QString(QStringLiteral(u"通道号")).toStdString(); std::string address_str = QString(QStringLiteral(u"道址")).toStdString(); std::string time_str = QString(QStringLiteral(u"时间计数")).toStdString(); std::ofstream outFile(output_file); outFile << board_id_str << "," << channel_id_str << "," << address_str << "," << time_str << "\n"; while (!min_heap.empty()) { CsvRow current = min_heap.top(); min_heap.pop(); outFile << current.board_id << "," << current.channel_id << "," << current.address << "," << current.time << "\n"; size_t chunk_index = current.chunk_index; if (chunk_readers[chunk_index]) { uint board_id; uint channel_id; uint address; unsigned long long time; if (chunk_readers[chunk_index]->read_row(board_id, channel_id, address, time)) { CsvRow row; row.board_id = board_id; row.channel_id = channel_id; row.address = address; row.time = time; row.chunk_index = chunk_index; min_heap.push(row); } else { chunk_readers[chunk_index].reset(); } } } outFile.close(); for (const auto& chunk : chunks) { std::remove(chunk.c_str()); } } bool ParticleDataSortTask::processEveryChannelParticleData() { bool ret_ok = true; const QString& sorted_result_dir = GetSortedResultDir(); QDir sorted_result_output_dir(sorted_result_dir); sorted_result_output_dir.mkpath(sorted_result_dir); const QString& all_channel_particle_data_filename = GetAllChannelParticleDataFilename(); QString sorted_output_filename = sorted_result_output_dir.filePath(QStringLiteral(u"粒子数据.csv")); try { const size_t CHUNK_SIZE = 100 * 1024 * 1024; // 100MB chunks std::vector chunks = splitFile(QStrToSysPath(all_channel_particle_data_filename), CHUNK_SIZE); if (chunks.empty()) { std::ifstream in_file(QStrToSysPath(all_channel_particle_data_filename)); std::ofstream out_file(QStrToSysPath(sorted_output_filename)); std::string line; while (std::getline(in_file, line)) { out_file << line << "\n"; } in_file.close(); out_file.close(); } else { mergeChunks(chunks, QStrToSysPath(sorted_output_filename)); } } catch (const std::exception& e) { const QString& e_what = QString::fromLatin1(e.what()); QString error = QString(QStringLiteral(u"处理%1异常:%2")).arg(all_channel_particle_data_filename).arg(e_what); LOG_ERROR(error) ret_ok = false; } catch (...) { QString error = QString(QStringLiteral(u"处理%1未知异常.")).arg(all_channel_particle_data_filename); LOG_ERROR(error) ret_ok = false; } this->updateTaskResultData(QVariant(sorted_output_filename)); return ret_ok; } void AutoFindPeaksTask::SetAnalysisType(AnalysisType analysis_type) { this->_analysis_type = analysis_type; } void AutoFindPeaksTask::SetDataFileList(const QMap &data_files_set) { this->_data_files_set = data_files_set; } void AutoFindPeaksTask::SetResultDir(const QString &result_dir) { this->_result_dir = result_dir; } void AutoFindPeaksTask::SetFindPeakSetpWinWidth(int step_win_width) { this->_step_win_width = step_win_width; } bool AutoFindPeaksTask::IsValidSetWorkParameters() const { return (!this->_data_files_set.isEmpty()) && (!this->_result_dir.isEmpty()) && DataProcessTask::IsValidSetWorkParameters(); } bool AutoFindPeaksTask::processTask() { QString result_filename = QDir(this->_result_dir).filePath(QStringLiteral(u"自动寻峰结果.csv")); std::ofstream out_file(QStrToSysPath(result_filename)); std::string channel_str = QString(QStringLiteral(u"通道")).toStdString(); std::string addr_str = QString(QStringLiteral(u"峰位")).toStdString(); std::string left_addr_str = QString(QStringLiteral(u"左边界")).toStdString(); std::string lright_addr_str = QString(QStringLiteral(u"右边界")).toStdString(); std::string width_str = QString(QStringLiteral(u"峰宽")).toStdString(); std::string height_str = QString(QStringLiteral(u"峰高")).toStdString(); std::string fwhm_str = QString(QStringLiteral(u"FWHM")).toStdString(); std::string area_str = QString(QStringLiteral(u"峰面积")).toStdString(); out_file << channel_str << "," << addr_str << "," << left_addr_str << "," << lright_addr_str << "," << width_str << "," << height_str << "," << fwhm_str << "," << area_str << "\n"; QStringList ch_count_data_name = this->_data_files_set.keys(); std::sort(ch_count_data_name.begin(), ch_count_data_name.end(), [](const QString& a, const QString& b) { int num_a = ExtractNumberFromString(a); int num_b = ExtractNumberFromString(b); return num_a < num_b; }); for (const QString& ch_count_data_name : ch_count_data_name) { if (ch_count_data_name.contains(ch_count_data_name)) { const QString& ch_count_data_filename = this->_data_files_set.value(ch_count_data_name).toString(); std::string channel = ch_count_data_name.toStdString(); arma::mat data; const std::string data_filename = QStrToSysPath(ch_count_data_filename); if (!data.load(data_filename, arma::csv_ascii)) { QString error = QString(QStringLiteral(u"%1自动寻峰数据加载异常!")).arg(ch_count_data_name); LOG_WARN(error); continue; } std::vector peak_info_vec; try { peak_info_vec = FindPeaksBySvd().FindPeaks(data, this->_step_win_width); } catch (const std::string& e) { QString error = QString(QStringLiteral(u"%1自动寻峰异常:%2!")).arg(ch_count_data_name).arg(QString::fromStdString(e)); LOG_WARN(error); continue; } if (!peak_info_vec.empty()) { for(auto peak_info : peak_info_vec) { int addr = peak_info.pos; int left = peak_info.left; int right = peak_info.left + peak_info.width; int width = peak_info.width; int height = peak_info.height; int fwhm = peak_info.fwhm; double area = peak_info.area; out_file << channel << "," << addr << "," << left << "," << right << "," << width << "," << height << "," << fwhm << "," << area << "\n"; } } else { const QString& error = QStringLiteral(u"%1自动寻峰异常!").arg(ch_count_data_name); LOG_WARN(error); } const QString& info = QStringLiteral(u"%1自动寻峰完成.").arg(ch_count_data_name); LOG_INFO(info); } } const QString& project_name = GetProjectName(); MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name); if (project_model == nullptr) { return false; } else { project_model->SetAnalysisCustomData(this->_analysis_type, QString("AutoFindPeaksResult"), result_filename); } const QString& info = QStringLiteral(u"自动寻峰完成."); LOG_INFO(info); return true; } void ChannelEnergyScaleFittingTask::SetData( const FitDataMap& channel_energy_scale_fit_data_map, const QMap& fit_degree_map) { this->_channel_energy_scale_fit_data_map = channel_energy_scale_fit_data_map; this->_fit_degree_map = fit_degree_map; } void ChannelEnergyScaleFittingTask::SetResultDir(const QString &result_dir) { this->_result_dir = result_dir; } bool ChannelEnergyScaleFittingTask::IsValidSetWorkParameters() const { return (!this->_channel_energy_scale_fit_data_map.isEmpty()) && (!this->_fit_degree_map.isEmpty())&& (!this->_result_dir.isEmpty()) && DataProcessTask::IsValidSetWorkParameters(); } bool ChannelEnergyScaleFittingTask::processTask() { QDir result_dir(this->_result_dir); const QString& energy_scale_data_filename = result_dir.filePath(QStringLiteral(u"多通道能量刻度拟合结果.json")); EnergyScaleDataModel energy_scale_data_model(energy_scale_data_filename); for (const QString& channel : this->_channel_energy_scale_fit_data_map.keys()) { const QMap >& energy_scale_fit_data = this->_channel_energy_scale_fit_data_map.value(channel); if (energy_scale_fit_data.isEmpty()) { continue; } int fit_degree = this->_fit_degree_map.value(channel); if (fit_degree <= 0) { continue; } std::vector vec_x, vec_y1, vec_y2; for (const int& addr : energy_scale_fit_data.keys()) { vec_x.push_back(addr); vec_y1.push_back(energy_scale_fit_data.value(addr)[0]); vec_y2.push_back(energy_scale_fit_data.value(addr)[1]); } std::vector energy_scale_fit_result_coeffs; try { energy_scale_fit_result_coeffs = GaussPolyCoe::PolynomialFit(vec_x, vec_y1, fit_degree); } catch(const std::exception& e) { QString error = QString(QStringLiteral(u"%1能量刻度多项式%2次拟合异常:%3!")).arg(channel).arg(fit_degree).arg(QString::fromStdString(e.what())); LOG_WARN(error); } arma::vec fwhm_fit_result_coeffs; try { fwhm_fit_result_coeffs = NolinearLeastSquaresCurveFit::Lsqcurvefit(FwhmModel, vec_y1, vec_y2, { 1.0, 1.0 }); } catch(const std::exception& e) { QString error = QString(QStringLiteral(u"%1分辨率拟合异常:%2!")).arg(channel).arg(QString::fromStdString(e.what())); LOG_WARN(error); } const QString& info = QStringLiteral(u"%1能量刻度拟合完成.").arg(channel); LOG_INFO(info); std::vector > fit_result_data; for (int i = 0; i < vec_x.size(); i++) { int addr = vec_x[i]; double set_energy = vec_y1[i]; double fit_energy = GaussPolyCoe::Predict(energy_scale_fit_result_coeffs, addr); double peak_fwhm = vec_y2[i]; double fit_fwhm = FwhmModel(addr, fwhm_fit_result_coeffs); std::vector fit_result_item_data; fit_result_item_data.push_back(addr); fit_result_item_data.push_back(set_energy); fit_result_item_data.push_back(fit_energy); fit_result_item_data.push_back(set_energy - fit_energy); fit_result_item_data.push_back(peak_fwhm); fit_result_item_data.push_back(fit_fwhm); fit_result_item_data.push_back(peak_fwhm - fit_fwhm); fit_result_data.push_back(fit_result_item_data); } energy_scale_data_model.SetEnergyFitDegree(channel, fit_degree); energy_scale_data_model.SetEnergyFitResultCoeffs(channel, energy_scale_fit_result_coeffs); energy_scale_data_model.SetFwhmFitResultCoeffs(channel, std::vector(fwhm_fit_result_coeffs.begin(), fwhm_fit_result_coeffs.end())); energy_scale_data_model.SetFitData(channel, fit_result_data); } if (!energy_scale_data_model.SaveData()) { return false; } const QString& info = QStringLiteral(u"能量刻度拟合完成."); LOG_INFO(info); return true; } bool ApplyEnergyScaleTask::processTask() { bool ok = true; const QString& project_name = GetProjectName(); MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetProjectModel(project_name); if (project_model == nullptr) { return false; } const QString& info = QStringLiteral(u"应用能量刻度完成."); LOG_INFO(info); return ok; }