2026-03-02 11:07:51 +08:00
# include "DataProcessWorkPool.h"
# include "MeasureAnalysisProjectModel.h"
2026-03-03 18:15:34 +08:00
# include "GlobalDefine.h"
2026-03-02 21:39:41 +08:00
# include "csv.h"
2026-03-03 18:15:34 +08:00
# include <QDir>
# include <QThreadPool>
2026-03-02 21:39:41 +08:00
# include <algorithm>
2026-03-03 18:15:34 +08:00
# include <fstream>
2026-03-02 21:39:41 +08:00
# include <memory>
2026-03-03 18:15:34 +08:00
# include <queue>
2026-03-02 21:39:41 +08:00
# include <sstream>
2026-03-03 18:15:34 +08:00
# include <string>
# include <vector>
2026-03-11 13:59:46 +08:00
# include <QVariant>
# include <QFuture>
# include <QtConcurrent>
2026-03-18 19:31:24 +08:00
# include "DataCalcProcess/MathModelDefine.h"
2026-03-11 13:59:46 +08:00
# include "DataCalcProcess/FindPeaksBySvd.h"
2026-03-18 19:31:24 +08:00
# include "DataCalcProcess/GaussPolyCoe.h"
# include "DataCalcProcess/NolinearLeastSquaresCurveFit.h"
2026-03-19 18:43:03 +08:00
# include "EnergyScaleDataModel.h"
2026-03-17 10:50:33 +08:00
# include <QDebug>
2026-03-02 11:07:51 +08:00
using namespace DataProcessWorkPool ;
2026-03-02 18:56:21 +08:00
using namespace io ;
2026-03-02 11:07:51 +08:00
2026-03-09 21:57:26 +08:00
void DataProcessTask : : SetFinishedNotifier ( QObject * finished_notifier , const char * finished_process , const QString & project_name )
2026-03-02 11:07:51 +08:00
{
this - > _finished_notifier = finished_notifier ;
this - > _finished_notifier_process = finished_process ;
this - > _project_name = project_name ;
}
2026-03-09 21:57:26 +08:00
const QString & DataProcessTask : : GetProjectName ( ) const
2026-03-02 11:07:51 +08:00
{
return this - > _project_name ;
}
2026-03-09 21:57:26 +08:00
const char * DataProcessTask : : GetFinishedNotifierProcess ( ) const
2026-03-02 11:07:51 +08:00
{
return this - > _finished_notifier_process ;
}
2026-03-09 21:57:26 +08:00
QObject * DataProcessTask : : GetFinishedNotifier ( ) const
2026-03-02 11:07:51 +08:00
{
return this - > _finished_notifier ;
}
2026-03-09 21:57:26 +08:00
bool DataProcessTask : : IsValidSetWorkParameters ( ) const
2026-03-02 11:07:51 +08:00
{
2026-03-11 13:59:46 +08:00
return ! ( this - > _project_name . isEmpty ( ) ) ;
2026-03-02 11:07:51 +08:00
}
2026-03-09 21:57:26 +08:00
void DataProcessTask : : StartTask ( )
2026-03-02 11:07:51 +08:00
{
QThreadPool : : globalInstance ( ) - > start ( this ) ;
}
2026-03-09 21:57:26 +08:00
void DataProcessTask : : run ( )
2026-03-02 11:07:51 +08:00
{
if ( ! IsValidSetWorkParameters ( ) ) {
return ;
}
2026-03-09 21:57:26 +08:00
if ( ! processTask ( ) ) {
2026-03-02 11:07:51 +08:00
return ;
}
2026-03-03 18:15:34 +08:00
if ( ( GetFinishedNotifier ( ) ! = nullptr ) & & ( GetFinishedNotifierProcess ( ) ! = nullptr ) ) {
QMetaObject : : invokeMethod ( _finished_notifier , _finished_notifier_process , Qt : : QueuedConnection , Q_ARG ( QString , _project_name ) ) ;
}
2026-03-02 11:07:51 +08:00
}
2026-03-09 21:57:26 +08:00
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
{
2026-03-11 13:59:46 +08:00
return ( ! GetAllChannelParticleDataFilename ( ) . isEmpty ( ) ) & & DataProcessTask : : IsValidSetWorkParameters ( ) ;
2026-03-09 21:57:26 +08:00
}
bool ParticleDataTask : : processTask ( )
{
return processEveryChannelParticleData ( ) ;
}
2026-03-02 18:56:21 +08:00
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
{
2026-03-02 21:39:41 +08:00
return ( ! GetResultDataDir ( ) . isEmpty ( ) ) & & ParticleDataTask : : IsValidSetWorkParameters ( ) ;
2026-03-02 18:56:21 +08:00
}
2026-03-02 11:07:51 +08:00
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 ;
2026-03-02 18:56:21 +08:00
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 ( ) ;
2026-03-02 21:39:41 +08:00
// 使用更灵活的方式处理CSV文件, 忽略额外列
io : : CSVReader <
4 ,
io : : trim_chars < ' ' , ' \t ' > ,
io : : double_quote_escape < ' , ' , ' " ' > ,
io : : throw_on_overflow ,
2026-03-03 18:15:34 +08:00
io : : empty_line_comment >
reader ( QStrToSysPath ( all_channel_particle_data_filename ) ) ;
2026-03-02 21:39:41 +08:00
reader . read_header ( io : : ignore_extra_column , board_id_str , channel_id_str , address_str , time_str ) ;
2026-03-02 18:56:21 +08:00
uint board_id ;
uint channel_id ;
uint address ;
unsigned long long time ;
while ( reader . read_row ( board_id , channel_id , address , time ) ) {
2026-03-02 11:07:51 +08:00
// 板卡和通道号计算,通道号 = 板卡号 * 4 + 通道号
int channel_num = ( board_id ) * 4 + ( channel_id + 1 ) ;
2026-03-09 13:07:22 +08:00
QString particle_data_filename = result_data_output_dir . filePath ( QStringLiteral ( u " 通道%1粒子数据.csv " ) . arg ( channel_num ) ) ;
2026-03-02 11:07:51 +08:00
if ( ! particle_data_filename_list . contains ( channel_num ) ) {
particle_data_filename_list . insert ( channel_num , particle_data_filename ) ;
}
2026-03-03 18:15:34 +08:00
if ( ! ch_particle_data_of_list . contains ( channel_num ) ) {
2026-03-02 11:07:51 +08:00
std : : shared_ptr < std : : ofstream > out (
2026-03-03 18:15:34 +08:00
new std : : ofstream ( QStrToSysPath ( particle_data_filename ) , std : : ios : : out | std : : ios : : app ) ,
[ ] ( std : : ofstream * p ) { p - > close ( ) ; } ) ;
2026-03-02 18:56:21 +08:00
* out < < QString ( QStringLiteral ( u " 板卡号,通道号,道址,时间计数 " ) ) . toStdString ( ) < < std : : endl ;
2026-03-03 18:15:34 +08:00
ch_particle_data_of_list . insert ( channel_num , out ) ;
2026-03-02 11:07:51 +08:00
}
auto ch_particle_data_of = ch_particle_data_of_list . value ( channel_num ) ;
2026-03-02 18:56:21 +08:00
* ch_particle_data_of < < board_id < < " , " < < channel_id < < " , " < < address < < " , " < < time < < std : : endl ;
2026-03-02 11:07:51 +08:00
}
} catch ( const std : : runtime_error & e ) {
2026-03-17 18:38:50 +08:00
const QString & e_what = QString : : fromLatin1 ( e . what ( ) ) ;
QString error = QString ( QStringLiteral ( u " 处理%1发生运行时异常:%2 " ) ) . arg ( all_channel_particle_data_filename ) . arg ( e_what ) ;
2026-03-02 11:07:51 +08:00
LOG_ERROR ( error )
ret_ok = false ;
} catch ( const std : : exception & e ) {
2026-03-17 18:38:50 +08:00
const QString & e_what = QString : : fromLatin1 ( e . what ( ) ) ;
QString error = QString ( QStringLiteral ( u " 处理%1异常:%2 " ) ) . arg ( all_channel_particle_data_filename ) . arg ( e_what ) ;
2026-03-02 11:07:51 +08:00
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 ( ) ;
2026-03-05 20:48:07 +08:00
MeasureAnalysisProjectModel * project_model = ProjectList : : Instance ( ) - > GetProjectModel ( project_name ) ;
2026-03-02 11:07:51 +08:00
if ( project_model = = nullptr ) {
ret_ok = false ;
}
for ( auto it = particle_data_filename_list . begin ( ) ; it ! = particle_data_filename_list . end ( ) ; + + it ) {
2026-03-05 20:48:07 +08:00
// project_model->SetChannelParticleDataFilename(it.key(), it.value());
2026-03-02 11:07:51 +08:00
}
2026-03-03 18:15:34 +08:00
2026-03-02 11:07:51 +08:00
return ret_ok ;
}
2026-03-03 18:15:34 +08:00
void EveryChannelParticleCountDataTask : : SetAllChannelCountResultDir ( const QString & dir_path )
2026-03-02 18:56:21 +08:00
{
this - > _all_ch_count_dir = dir_path ;
}
2026-03-03 18:15:34 +08:00
const QString & EveryChannelParticleCountDataTask : : GetAllChannelCountResultDir ( ) const
2026-03-02 18:56:21 +08:00
{
return this - > _all_ch_count_dir ;
}
2026-03-03 18:15:34 +08:00
void EveryChannelParticleCountDataTask : : SetEveryChannelCountResultDir ( const QString & dir_path )
2026-03-02 18:56:21 +08:00
{
this - > _every_ch_count_dir = dir_path ;
}
2026-03-03 18:15:34 +08:00
const QString & EveryChannelParticleCountDataTask : : GetEveryChannelCountResultDir ( ) const
2026-03-02 18:56:21 +08:00
{
return this - > _every_ch_count_dir ;
}
bool EveryChannelParticleCountDataTask : : IsValidSetWorkParameters ( ) const
{
2026-03-03 18:15:34 +08:00
return ( ! GetAllChannelCountResultDir ( ) . isEmpty ( ) ) & & ( ! GetEveryChannelCountResultDir ( ) . isEmpty ( ) ) & & ParticleDataTask : : IsValidSetWorkParameters ( ) ;
2026-03-02 18:56:21 +08:00
}
2026-03-02 11:07:51 +08:00
bool EveryChannelParticleCountDataTask : : processEveryChannelParticleData ( )
{
bool ret_ok = true ;
2026-03-02 18:56:21 +08:00
const QString & all_ch_count_dir = GetAllChannelCountResultDir ( ) ;
const QString & every_ch_count_dir = GetEveryChannelCountResultDir ( ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
QDir all_ch_count_output_dir ( all_ch_count_dir ) ;
all_ch_count_output_dir . mkpath ( all_ch_count_dir ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
QDir every_ch_count_output_dir ( every_ch_count_dir ) ;
every_ch_count_output_dir . mkpath ( every_ch_count_dir ) ;
2026-03-02 11:07:51 +08:00
const QString & all_channel_particle_data_filename = GetAllChannelParticleDataFilename ( ) ;
2026-03-02 18:56:21 +08:00
QMap < uint , QString > particle_count_filename_list ;
2026-03-09 13:07:22 +08:00
// QString all_channel_total_count_filename;
2026-03-02 11:07:51 +08:00
try {
2026-03-02 18:56:21 +08:00
// 统计每个通道的粒子计数(相同板卡号通道号相同道址)
QMap < uint , QMap < uint , uint > > channel_address_counts ; // 通道号 -> 地址 -> 计数
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 统计所有通道的粒子计数(不同板卡号通道号相同道址)
2026-03-04 16:17:04 +08:00
// QMap<uint, uint> all_channel_address_counts; // 地址 -> 计数
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
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 ( ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
// 使用更灵活的方式处理CSV文件, 忽略额外列
io : : CSVReader <
4 ,
io : : trim_chars < ' ' , ' \t ' > ,
io : : double_quote_escape < ' , ' , ' " ' > ,
io : : throw_on_overflow ,
2026-03-03 18:15:34 +08:00
io : : empty_line_comment >
reader ( QStrToSysPath ( all_channel_particle_data_filename ) ) ;
2026-03-02 21:39:41 +08:00
reader . read_header ( io : : ignore_extra_column , board_id_str , channel_id_str , address_str , time_str ) ;
2026-03-02 18:56:21 +08:00
uint board_id ;
uint channel_id ;
uint address ;
unsigned long long time ;
while ( reader . read_row ( board_id , channel_id , address , time ) ) {
2026-03-02 11:07:51 +08:00
// 板卡和通道号计算,通道号 = 板卡号 * 4 + 通道号
int channel_num = ( board_id ) * 4 + ( channel_id + 1 ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 统计每个通道的粒子计数
if ( ! channel_address_counts . contains ( channel_num ) ) {
channel_address_counts [ channel_num ] = QMap < uint , uint > ( ) ;
2026-03-02 11:07:51 +08:00
}
2026-03-02 18:56:21 +08:00
channel_address_counts [ channel_num ] [ address ] + + ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 统计所有通道的粒子计数
2026-03-04 16:17:04 +08:00
// all_channel_address_counts[address]++;
2026-03-02 18:56:21 +08:00
}
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 写入每个通道的粒子计数数据(优化:使用一次打开文件,批量写入)
QMap < uint , std : : shared_ptr < std : : ofstream > > channel_file_streams ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 预创建所有通道的文件流
for ( auto channel_it = channel_address_counts . begin ( ) ; channel_it ! = channel_address_counts . end ( ) ; + + channel_it ) {
uint channel_num = channel_it . key ( ) ;
2026-03-09 13:07:22 +08:00
QString count_data_filename = every_ch_count_output_dir . filePath ( QStringLiteral ( u " 通道%1粒子计数.csv " ) . arg ( channel_num ) ) ;
2026-03-02 18:56:21 +08:00
particle_count_filename_list . insert ( channel_num , count_data_filename ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 创建文件流
2026-03-03 18:15:34 +08:00
std : : shared_ptr < std : : ofstream > out ( new std : : ofstream ( QStrToSysPath ( count_data_filename ) ) ) ;
2026-03-02 18:56:21 +08:00
channel_file_streams [ channel_num ] = out ;
* out < < QString ( QStringLiteral ( u " 道址 " ) ) . toStdString ( ) < < " , " < < QString ( QStringLiteral ( u " 计数 " ) ) . toStdString ( ) < < std : : endl ;
}
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 批量写入数据
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 ] ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
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 ;
2026-03-02 11:07:51 +08:00
}
}
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 文件流会在shared_ptr析构时自动关闭
channel_file_streams . clear ( ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 18:56:21 +08:00
// 写入所有通道的粒子计数数据
2026-03-04 16:17:04 +08:00
// 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();
2026-03-03 18:15:34 +08:00
2026-03-02 11:07:51 +08:00
} catch ( const std : : runtime_error & e ) {
2026-03-17 18:38:50 +08:00
const QString & e_what = QString : : fromLatin1 ( e . what ( ) ) ;
QString error = QStringLiteral ( u " 处理%1发生运行时异常:%2 " ) . arg ( all_channel_particle_data_filename ) . arg ( e_what ) ;
2026-03-02 11:07:51 +08:00
LOG_ERROR ( error )
ret_ok = false ;
} catch ( const std : : exception & e ) {
2026-03-17 18:38:50 +08:00
const QString & e_what = QString : : fromLatin1 ( e . what ( ) ) ;
QString error = QStringLiteral ( u " 处理%1异常:%2 " ) . arg ( all_channel_particle_data_filename ) . arg ( e_what ) ;
2026-03-02 11:07:51 +08:00
LOG_ERROR ( error )
ret_ok = false ;
} catch ( . . . ) {
2026-03-17 18:38:50 +08:00
QString error = QStringLiteral ( u " 处理%1未知异常. " ) . arg ( all_channel_particle_data_filename ) ;
2026-03-02 11:07:51 +08:00
LOG_ERROR ( error )
ret_ok = false ;
}
const QString & project_name = GetProjectName ( ) ;
2026-03-05 20:48:07 +08:00
MeasureAnalysisProjectModel * project_model = ProjectList : : Instance ( ) - > GetProjectModel ( project_name ) ;
2026-03-02 11:07:51 +08:00
if ( project_model = = nullptr ) {
ret_ok = false ;
2026-03-02 18:56:21 +08:00
} else {
// 更新项目模型中的通道粒子计数数据文件名
for ( auto it = particle_count_filename_list . begin ( ) ; it ! = particle_count_filename_list . end ( ) ; + + it ) {
2026-03-05 20:48:07 +08:00
project_model - > SetChannelAddressCountDataFilename ( it . key ( ) , it . value ( ) ) ;
2026-03-02 18:56:21 +08:00
}
// 更新项目模型中的所有通道粒子总计数数据文件名
2026-03-04 16:17:04 +08:00
// project_model->SetAllChannelParticleTotalCountDataFilename(all_channel_total_count_filename);
2026-03-02 11:07:51 +08:00
}
return ret_ok ;
}
2026-03-02 21:39:41 +08:00
////////////////////////////////////////////////////////////////////////////////////
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 ;
2026-03-03 18:15:34 +08:00
bool operator < ( const CsvRow & other ) const
{
2026-03-02 21:39:41 +08:00
return time > other . time ;
}
} ;
2026-03-03 18:15:34 +08:00
std : : vector < std : : string > splitFile ( const std : : string & input_file , size_t chunk_size )
{
2026-03-02 21:39:41 +08:00
std : : vector < std : : string > chunks ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
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 ( ) ;
2026-03-03 18:15:34 +08:00
io : : CSVReader <
4 ,
io : : trim_chars < ' ' , ' \t ' > ,
io : : double_quote_escape < ' , ' , ' " ' > ,
io : : throw_on_overflow ,
io : : empty_line_comment
> reader ( input_file ) ;
2026-03-02 21:39:41 +08:00
reader . read_header ( io : : ignore_extra_column , board_id_str , channel_id_str , address_str , time_str ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
int chunkIndex = 0 ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
while ( true ) {
std : : vector < CsvRow > rows ;
size_t currentSize = 0 ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
uint board_id ;
uint channel_id ;
uint address ;
unsigned long long time ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
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 ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
// Estimate row size
2026-03-03 18:15:34 +08:00
currentSize + = std : : to_string ( board_id ) . size ( ) + std : : to_string ( channel_id ) . size ( ) + std : : to_string ( address ) . size ( ) + std : : to_string ( time ) . size ( ) + 4 ; // +4 for commas
if ( currentSize > chunk_size & & ! rows . empty ( ) ) {
2026-03-02 21:39:41 +08:00
break ;
}
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
rows . push_back ( row ) ;
}
2026-03-03 18:15:34 +08:00
if ( rows . empty ( ) )
break ;
2026-03-02 21:39:41 +08:00
std : : sort ( rows . begin ( ) , rows . end ( ) , [ ] ( const CsvRow & a , const CsvRow & b ) {
return a . time < b . time ;
} ) ;
2026-03-03 18:15:34 +08:00
std : : string chunkFile = input_file + " .chunk " + std : : to_string ( chunkIndex ) ;
2026-03-02 21:39:41 +08:00
std : : ofstream outFile ( chunkFile ) ;
for ( const auto & row : rows ) {
outFile < < row . board_id < < " , " < < row . channel_id < < " , " < < row . address < < " , " < < row . time < < " \n " ;
}
outFile . close ( ) ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
chunks . push_back ( chunkFile ) ;
chunkIndex + + ;
}
} catch ( const std : : exception & e ) {
2026-03-17 10:50:33 +08:00
throw ( e ) ;
2026-03-02 21:39:41 +08:00
}
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
return chunks ;
}
2026-03-03 18:15:34 +08:00
void mergeChunks ( const std : : vector < std : : string > & chunks , const std : : string & output_file )
{
2026-03-02 21:39:41 +08:00
std : : vector < std : : unique_ptr < io : : CSVReader < 4 > > > chunkReaders ;
std : : priority_queue < CsvRow > minHeap ;
for ( const auto & chunk : chunks ) {
auto reader = std : : make_unique < io : : CSVReader < 4 > > ( chunk ) ;
chunkReaders . push_back ( std : : move ( reader ) ) ;
}
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
for ( size_t i = 0 ; i < chunkReaders . size ( ) ; i + + ) {
uint board_id ;
uint channel_id ;
uint address ;
unsigned long long time ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
if ( chunkReaders [ 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 ;
minHeap . push ( row ) ;
}
}
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
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 ( ) ;
2026-03-03 18:15:34 +08:00
std : : ofstream outFile ( output_file ) ;
2026-03-02 21:39:41 +08:00
outFile < < board_id_str < < " , " < < channel_id_str < < " , " < < address_str < < " , " < < time_str < < " \n " ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
while ( ! minHeap . empty ( ) ) {
CsvRow current = minHeap . top ( ) ;
minHeap . pop ( ) ;
outFile < < current . board_id < < " , " < < current . channel_id < < " , " < < current . address < < " , " < < current . time < < " \n " ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
size_t chunk_index = current . chunk_index ;
if ( chunkReaders [ chunk_index ] ) {
uint board_id ;
uint channel_id ;
uint address ;
unsigned long long time ;
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
if ( chunkReaders [ 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 ;
minHeap . push ( row ) ;
} else {
chunkReaders [ chunk_index ] . reset ( ) ;
}
}
}
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
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 ( ) ;
2026-03-09 13:07:22 +08:00
QString sorted_output_filename = sorted_result_output_dir . filePath ( QStringLiteral ( u " 粒子数据[已排序].csv " ) ) ;
2026-03-02 21:39:41 +08:00
try {
const size_t CHUNK_SIZE = 100 * 1024 * 1024 ; // 100MB chunks
2026-03-03 18:15:34 +08:00
std : : vector < std : : string > chunks = splitFile ( QStrToSysPath ( all_channel_particle_data_filename ) , CHUNK_SIZE ) ;
2026-03-02 21:39:41 +08:00
if ( chunks . empty ( ) ) {
2026-03-03 18:15:34 +08:00
std : : ifstream in_file ( QStrToSysPath ( all_channel_particle_data_filename ) ) ;
std : : ofstream out_file ( QStrToSysPath ( sorted_output_filename ) ) ;
2026-03-02 21:39:41 +08:00
std : : string line ;
2026-03-03 18:15:34 +08:00
while ( std : : getline ( in_file , line ) ) {
out_file < < line < < " \n " ;
2026-03-02 21:39:41 +08:00
}
2026-03-03 18:15:34 +08:00
in_file . close ( ) ;
out_file . close ( ) ;
2026-03-02 21:39:41 +08:00
} else {
2026-03-03 18:15:34 +08:00
mergeChunks ( chunks , QStrToSysPath ( sorted_output_filename ) ) ;
2026-03-02 21:39:41 +08:00
}
2026-03-03 18:15:34 +08:00
2026-03-02 21:39:41 +08:00
} catch ( const std : : exception & e ) {
2026-03-17 18:38:50 +08:00
const QString & e_what = QString : : fromLatin1 ( e . what ( ) ) ;
2026-03-18 19:31:24 +08:00
QString error = QString ( QStringLiteral ( u " 处理%1异常:%2 " ) ) . arg ( all_channel_particle_data_filename ) . arg ( QString : : fromStdString ( e . what ( ) ) ) ;
2026-03-02 21:39:41 +08:00
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 ( ) ;
2026-03-05 20:48:07 +08:00
MeasureAnalysisProjectModel * project_model = ProjectList : : Instance ( ) - > GetProjectModel ( project_name ) ;
2026-03-02 21:39:41 +08:00
if ( project_model = = nullptr ) {
ret_ok = false ;
} else {
project_model - > SetSortedParticleDataFilename ( sorted_output_filename ) ;
}
return ret_ok ;
}
2026-03-11 13:59:46 +08:00
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 ( )
{
2026-03-17 18:38:50 +08:00
QString result_filename = QDir ( this - > _result_dir ) . filePath ( QStringLiteral ( u " 自动寻峰结果.csv " ) ) ;
2026-03-11 13:59:46 +08:00
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 ( ) ;
2026-03-17 10:50:33 +08:00
std : : string height_str = QString ( QStringLiteral ( u " 峰高 " ) ) . toStdString ( ) ;
std : : string fwhm_str = QString ( QStringLiteral ( u " FWHM " ) ) . toStdString ( ) ;
2026-03-17 18:38:50 +08:00
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 ;
2026-03-11 13:59:46 +08:00
}
2026-03-18 19:31:24 +08:00
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 ;
}
2026-03-17 18:38:50 +08:00
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 ) ;
2026-03-11 13:59:46 +08:00
}
}
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 ) ;
}
2026-03-11 22:09:06 +08:00
const QString & info = QStringLiteral ( u " 自动寻峰完成 " ) ;
LOG_INFO ( info ) ;
2026-03-11 13:59:46 +08:00
return true ;
}
2026-03-18 19:31:24 +08:00
void ChannelEnergyScaleFittingTask : : SetData (
2026-03-19 18:43:03 +08:00
const FitDataMap & channel_energy_scale_fit_data_map , const QMap < QString , int > & fit_degree_map )
2026-03-18 19:31:24 +08:00
{
2026-03-19 18:43:03 +08:00
this - > _channel_energy_scale_fit_data_map = channel_energy_scale_fit_data_map ;
2026-03-18 19:31:24 +08:00
this - > _fit_degree_map = fit_degree_map ;
}
2026-03-19 18:43:03 +08:00
void ChannelEnergyScaleFittingTask : : SetResultDir ( const QString & result_dir )
{
this - > _result_dir = result_dir ;
}
2026-03-18 19:31:24 +08:00
bool ChannelEnergyScaleFittingTask : : IsValidSetWorkParameters ( ) const
{
2026-03-19 18:43:03 +08:00
return ( ! this - > _channel_energy_scale_fit_data_map . isEmpty ( ) ) & & ( ! this - > _fit_degree_map . isEmpty ( ) ) & & ( ! this - > _result_dir . isEmpty ( ) ) & & DataProcessTask : : IsValidSetWorkParameters ( ) ;
2026-03-18 19:31:24 +08:00
}
bool ChannelEnergyScaleFittingTask : : processTask ( )
{
2026-03-19 18:43:03 +08:00
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 ( ) ) {
2026-03-18 19:31:24 +08:00
continue ;
}
int fit_degree = this - > _fit_degree_map . value ( channel ) ;
if ( fit_degree < = 0 ) {
continue ;
}
std : : vector < double > vec_x , vec_y1 , vec_y2 ;
2026-03-19 18:43:03 +08:00
for ( const int & addr : energy_scale_fit_data . keys ( ) ) {
2026-03-18 19:31:24 +08:00
vec_x . push_back ( addr ) ;
2026-03-19 18:43:03 +08:00
vec_y1 . push_back ( energy_scale_fit_data . value ( addr ) [ 0 ] ) ;
vec_y2 . push_back ( energy_scale_fit_data . value ( addr ) [ 1 ] ) ;
2026-03-18 19:31:24 +08:00
}
2026-03-19 18:43:03 +08:00
std : : vector < double > energy_scale_fit_result_coeffs ;
2026-03-18 19:31:24 +08:00
try {
2026-03-19 18:43:03 +08:00
energy_scale_fit_result_coeffs = GaussPolyCoe : : PolynomialFit ( vec_x , vec_y1 , fit_degree ) ;
2026-03-18 19:31:24 +08:00
} 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 ) ;
2026-03-19 18:43:03 +08:00
std : : vector < std : : vector < double > > fit_result_data ;
2026-03-18 19:31:24 +08:00
for ( int i = 0 ; i < vec_x . size ( ) ; i + + ) {
int addr = vec_x [ i ] ;
double set_energy = vec_y1 [ i ] ;
2026-03-19 18:43:03 +08:00
double fit_energy = GaussPolyCoe : : Predict ( energy_scale_fit_result_coeffs , addr ) ;
2026-03-18 19:31:24 +08:00
double peak_fwhm = vec_y2 [ i ] ;
double fit_fwhm = FwhmModel ( addr , fwhm_fit_result_coeffs ) ;
2026-03-19 18:43:03 +08:00
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 ) ;
2026-03-18 19:31:24 +08:00
}
2026-03-19 18:43:03 +08:00
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 ) ;
2026-03-18 19:31:24 +08:00
}
2026-03-19 18:43:03 +08:00
if ( ! energy_scale_data_model . SaveData ( ) ) {
2026-03-18 19:31:24 +08:00
return false ;
}
2026-03-19 18:43:03 +08:00
2026-03-18 19:31:24 +08:00
const QString & info = QStringLiteral ( u " 能量刻度拟合完成. " ) ;
LOG_INFO ( info ) ;
return true ;
}