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>
# include "DataCalcProcess/FindPeaksBySvd.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 ( ) ) ;
QString error = QString ( QStringLiteral ( u " 处理%1异常:%2 " ) ) . arg ( all_channel_particle_data_filename ) . arg ( 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-17 18:38:50 +08:00
FindPeaksBySvd peak_svd ;
std : : vector < FindPeaksBySvd : : PeakInfo > peak_info_vec = peak_svd . FindPeaks ( data , this - > _step_win_width ) ;
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 ;
}