EnergySpectrumAnalyer/src/DataProcessWorkPool.cpp
2026-03-20 16:21:13 +08:00

751 lines
30 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.

#include "DataProcessWorkPool.h"
#include "MeasureAnalysisProjectModel.h"
#include "GlobalDefine.h"
#include "csv.h"
#include <QDir>
#include <QThreadPool>
#include <algorithm>
#include <fstream>
#include <memory>
#include <queue>
#include <sstream>
#include <string>
#include <vector>
#include <QVariant>
#include <QFuture>
#include <QtConcurrent>
#include "DataCalcProcess/MathModelDefine.h"
#include "DataCalcProcess/FindPeaksBySvd.h"
#include "DataCalcProcess/GaussPolyCoe.h"
#include "DataCalcProcess/NolinearLeastSquaresCurveFit.h"
#include "EnergyScaleDataModel.h"
#include <QDebug>
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<uint, QString> particle_data_filename_list;
try {
QMap<uint, std::shared_ptr<std::ofstream>> 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<std::ofstream> 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<uint, QString> particle_count_filename_list;
// QString all_channel_total_count_filename;
try {
// 统计每个通道的粒子计数(相同板卡号通道号相同道址)
QMap<uint, QMap<uint, uint>> channel_address_counts; // 通道号 -> 地址 -> 计数
// 统计所有通道的粒子计数(不同板卡号通道号相同道址)
// QMap<uint, uint> 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<uint, uint>();
}
channel_address_counts[channel_num][address]++;
// 统计所有通道的粒子计数
// all_channel_address_counts[address]++;
}
// 写入每个通道的粒子计数数据(优化:使用一次打开文件,批量写入)
QMap<uint, std::shared_ptr<std::ofstream>> 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<std::ofstream> 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<uint, uint>& 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<std::string> splitFile(const std::string& input_file, size_t chunk_size)
{
std::vector<std::string> 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<CsvRow> 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<std::string>& chunks, const std::string& output_file)
{
std::vector<std::unique_ptr<io::CSVReader<4>>> chunk_readers;
std::priority_queue<CsvRow> min_heap;
for (const auto& chunk : chunks) {
auto reader = std::make_unique<io::CSVReader<4>>(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<std::string> 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<QString, QVariant> &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<FindPeaksBySvd::PeakInfo> 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<QString, int>& 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<int, QList<double> >& 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<double> 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<double> 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<std::vector<double> > 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<double> 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<double>(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;
}