Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
d20fce8
warm up porting
lastgeorge Oct 28, 2025
a457e9e
continue validation
lastgeorge Oct 28, 2025
eb3190d
continue validation
lastgeorge Oct 28, 2025
c7021b2
continue validation
lastgeorge Oct 28, 2025
8211d9b
continue validation
lastgeorge Oct 28, 2025
2ced978
fix a bug in the Box Recombination Model
lastgeorge Oct 28, 2025
277fd15
fix a bug in the Box Recombination Model
lastgeorge Oct 28, 2025
122ad0b
fix a bug
lastgeorge Oct 28, 2025
6a446b4
catch up
lastgeorge Oct 28, 2025
26db774
update logic
lastgeorge Oct 28, 2025
9653eaf
update code
lastgeorge Oct 28, 2025
089a471
implement algorithm for the break_segment_at_point
lastgeorge Oct 28, 2025
16da43d
continue validation
lastgeorge Oct 29, 2025
cf5d832
catch up
lastgeorge Oct 29, 2025
0e32d88
add validation to multi-track fitting
lastgeorge Nov 4, 2025
a75fd20
fix a bug
lastgeorge Nov 4, 2025
ad02e81
catch up
lastgeorge Nov 5, 2025
fca0f7c
continue dbug
lastgeorge Nov 6, 2025
49421f1
fix another bug
lastgeorge Nov 6, 2025
1e430e0
fix bug validation
lastgeorge Nov 6, 2025
7b37aab
add a function
lastgeorge Nov 27, 2025
8bb4783
add a function of check_direction
lastgeorge Nov 27, 2025
8d485e5
implement check_connectivity function
lastgeorge Nov 27, 2025
7444f5a
implement the connect_graph_overclustering_projection as connect_grap…
lastgeorge Nov 27, 2025
d999e6a
implement the new graph
lastgeorge Nov 27, 2025
3397df4
prepare files for Pattern Recognition
lastgeorge Nov 29, 2025
4a37136
add a function
lastgeorge Nov 29, 2025
b531f0a
implement some functions
lastgeorge Nov 29, 2025
87aea6e
put in a template
lastgeorge Nov 30, 2025
df694df
catch up
lastgeorge Nov 30, 2025
dea665a
implement init_first_segment
lastgeorge Nov 30, 2025
c0b0091
check the code
lastgeorge Nov 30, 2025
70d4033
catch code
lastgeorge Nov 30, 2025
6ddfa36
add proto_extend_point
lastgeorge Nov 30, 2025
19ff94b
implement function proto_break_tracks
lastgeorge Dec 1, 2025
ae3556f
implement the replace_segment_and_vertex function
lastgeorge Dec 1, 2025
ab4fcba
break_segment_into_two
lastgeorge Dec 1, 2025
a0572c3
implement break_segments function
lastgeorge Dec 1, 2025
8573112
update code
lastgeorge Dec 1, 2025
067122e
merge two segments into one
lastgeorge Dec 1, 2025
1b71a1e
add merge vertices
lastgeorge Dec 1, 2025
7ceced7
implement two examine_structure functions
lastgeorge Dec 5, 2025
a806d4b
add examine_structure_4
lastgeorge Dec 5, 2025
a07e55b
implement the find_other_segments
lastgeorge Dec 5, 2025
f59f3e9
implement the find_other_segments
lastgeorge Dec 5, 2025
3807877
clean up
lastgeorge Dec 6, 2025
3fa9812
catch up
lastgeorge Dec 6, 2025
c26940d
implement crawl_segment
lastgeorge Dec 7, 2025
911e339
add examine_segment
lastgeorge Dec 7, 2025
367cb73
implement the examine_vertices_1p
lastgeorge Dec 7, 2025
1ee2b3b
implement examine_Vertices_1
lastgeorge Dec 7, 2025
a1f3781
implement examine_vertices_2
lastgeorge Dec 7, 2025
883b9a9
implement examine_vertices_4
lastgeorge Dec 7, 2025
5305889
implement examine_vertices
lastgeorge Dec 7, 2025
d82f180
implement the examine partial identical segments
lastgeorge Dec 7, 2025
28fc7db
get_local_extension
lastgeorge Dec 7, 2025
c5cabfd
implement the examine_vertices_3 function
lastgeorge Dec 8, 2025
88c95a7
implement find_proto_vertex
lastgeorge Dec 8, 2025
7c17ed8
implement the init_point_segment
lastgeorge Dec 8, 2025
c58c0f7
implement the first function of examine_structure_final_1
lastgeorge Dec 16, 2025
ffd4f50
implement the examine_structure_final functions
lastgeorge Dec 16, 2025
e8ea63a
improve implementations
lastgeorge Dec 16, 2025
d5b4ada
implement the search_for_vertex_activities
lastgeorge Dec 17, 2025
d0f1673
catch up
lastgeorge Dec 17, 2025
9498c3b
catch up
lastgeorge Dec 17, 2025
32b80f3
add the local to global indices mapping
lastgeorge Dec 17, 2025
5bbb93d
update code
lastgeorge Dec 17, 2025
12142ef
add a function to transfer information from segment to cluster
lastgeorge Dec 17, 2025
7e91ac6
add sufficient code for transfer information from segment to cluster
lastgeorge Dec 17, 2025
f59a2da
implement determine_direction
lastgeorge Dec 18, 2025
b4a159a
implement examine_good_tracks
lastgeorge Dec 18, 2025
6901400
implement examine_good_tracks
lastgeorge Dec 18, 2025
e443a5d
implement another improve maps function
lastgeorge Dec 18, 2025
c1d02a0
implement the examine_maps function
lastgeorge Dec 18, 2025
717489f
implement the examine_all_showers
lastgeorge Dec 18, 2025
b928b5c
implement EM shower related
lastgeorge Dec 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion aux/src/ClusterHelpers.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ std::map<std::string, size_t> Aux::count(const cluster_graph_t& cgraph, bool nod
}




std::unordered_map<int, std::set<cluster_vertex_t> > Aux::blob_clusters(
const cluster_graph_t& cg)
{
Expand Down Expand Up @@ -368,4 +370,4 @@ std::unordered_map<int, std::set<cluster_vertex_t> > Aux::blob_clusters(
}

return groups;
}
}
11 changes: 11 additions & 0 deletions cfg/pgrapher/common/clus.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ local wc = import "wirecell.jsonnet";
} + dv_cfg + pcts_cfg
},

tagger_check_neutrino(name="", trackfitting_config_file="", particle_dataset="", recombination_model="") :: {
type: "TaggerCheckNeutrino",
name: prefix + name,
data: {
grouping: "live", // Which grouping to process
trackfitting_config_file: trackfitting_config_file,
particle_dataset: particle_dataset,
recombination_model: recombination_model,
} + dv_cfg + pcts_cfg
},

pointed(name="", groupings=["live"]) :: {
type: "ClusteringPointed",
name: prefix+name,
Expand Down
24 changes: 24 additions & 0 deletions clus/inc/WireCellClus/Facade_Cluster.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,30 @@ namespace WireCell::Clus::Facade {
double charge_cut = 4000.0,
bool disable_dead_mix_cell = true) const;

/// Get segment IDs for all points (computed from graph analysis)
/// @return Vector of segment IDs, -1 for unassigned points
std::vector<int> segment_ids() const;

/// Get shower flags for all points (computed from graph analysis)
/// @return Vector of flags, 1=shower, 0=track
std::vector<int> shower_flags() const;

/// Get segment ID for a specific point
/// @param point_index Global point index in cluster
/// @return Segment ID or -1 if unassigned
int segment_id(size_t point_index) const;

/// Get shower flag for a specific point
/// @param point_index Global point index in cluster
/// @return 1 if shower, 0 if track
int shower_flag(size_t point_index) const;

/// Invalidate cached segment data (IDs and shower flags)
/// Call this before re-computing segment information
void invalidate_segment_data() {
cache().invalidate_segment_data();
}



// Return vector is size 3 holding vectors of size npoints providing k-d tree coordinate points.
Expand Down
12 changes: 12 additions & 0 deletions clus/inc/WireCellClus/Facade_ClusterCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,23 @@ namespace WireCell::Clus::Facade {
// Set of point indices excluded during graph operations (equivalent to prototype's excluded_points)
std::set<size_t> excluded_points;

// Segment IDs by point index (computed from graph analysis)
std::vector<int> point_segment_ids;

// Shower flags by point index (computed from graph analysis)
std::vector<int> point_shower_flags;

// Steiner point cloud k-d tree cache
mutable std::unique_ptr<KDTree::MultiQuery> steiner_kd;
mutable decltype(std::declval<KDTree::MultiQuery>().get<double>(std::vector<std::string>{})) steiner_query3d;
mutable std::string cached_steiner_pc_name;
mutable bool steiner_kd_built{false};

// Invalidate segment-related cached data
void invalidate_segment_data() {
point_segment_ids.clear();
point_shower_flags.clear();
}
};

}
Expand Down
3 changes: 3 additions & 0 deletions clus/inc/WireCellClus/Facade_Util.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ namespace WireCell::Clus::Facade {
results_type get_closest_index(const geo_point_t& p, const size_t N) const;
/// @return index, geo_point_t
std::pair<size_t, geo_point_t> get_closest_wcpoint(const geo_point_t& p) const;
double get_closest_dis(const geo_point_t& p) const;

std::vector<std::pair<size_t, geo_point_t>> get_closest_wcpoints_radius(const geo_point_t& p, const double radius) const;

/// @param p_test1 is the point to start from
/// @param dir is the direction to search along
Expand Down
Empty file.
Empty file.
Empty file.
Empty file.
110 changes: 110 additions & 0 deletions clus/inc/WireCellClus/NeutrinoPatternBase.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "WireCellClus/PRGraph.h"
#include "WireCellClus/Facade_Cluster.h"
#include "WireCellClus/TrackFitting.h"

namespace WireCell::Clus::PR {
class PatternAlgorithms{
public:
std::set<VertexPtr> find_cluster_vertices(Graph& graph, const Facade::Cluster& cluster);
std::set<SegmentPtr> find_cluster_segments(Graph& graph, const Facade::Cluster& cluster);
bool clean_up_graph(Graph& graph, const Facade::Cluster& cluster);

SegmentPtr init_first_segment(Graph& graph, Facade::Cluster& cluster, Facade::Cluster* main_cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv, bool flag_back_search = true);

// find the shortest path using steiner graph
std::vector<Facade::geo_point_t> do_rough_path(const Facade::Cluster& cluster,Facade::geo_point_t& first_point, Facade::geo_point_t& last_point);
std::vector<Facade::geo_point_t> do_rough_path_reg_pc(const Facade::Cluster& cluster, Facade::geo_point_t& first_point, Facade::geo_point_t& last_point, std::string graph_name = "relaxed_pid");
// create a segment given a path
SegmentPtr create_segment_for_cluster(WireCell::Clus::Facade::Cluster& cluster, IDetectorVolumes::pointer dv, const std::vector<Facade::geo_point_t>& path_points, int dir = 0);
// create a segment given two vertices, null, if failed
SegmentPtr create_segment_from_vertices(Graph& graph, Facade::Cluster& cluster, VertexPtr v1, VertexPtr v2, IDetectorVolumes::pointer dv);
// replace a segment and vertex with another segment and vertex, assuming the original vertex only connect to this segment
bool replace_segment_and_vertex(Graph& graph, SegmentPtr& seg, VertexPtr& vtx, std::list<Facade::geo_point_t>& path_point_list, Facade::geo_point_t& break_point, IDetectorVolumes::pointer dv);
bool replace_segment_and_vertex(Graph& graph, SegmentPtr& seg, VertexPtr old_vertex, VertexPtr new_vertex, IDetectorVolumes::pointer dv);
bool break_segment_into_two(Graph& graph, VertexPtr vtx1, SegmentPtr seg, VertexPtr vtx2, std::list<Facade::geo_point_t>& path_point_list1, Facade::geo_point_t& break_point, std::list<Facade::geo_point_t>& path_point_list2, IDetectorVolumes::pointer dv);


// return the point and its index in the steiner tree as a pair
std::pair<Facade::geo_point_t, size_t> proto_extend_point(const Facade::Cluster& cluster, Facade::geo_point_t& p, Facade::geo_vector_t& dir, Facade::geo_vector_t& dir_other, bool flag_continue);
// return Steiner Graph path in wcps_list1 and wcps_list2
bool proto_break_tracks(const Facade::Cluster& cluster, const Facade::geo_point_t& first_wcp, const Facade::geo_point_t& curr_wcp, const Facade::geo_point_t& last_wcp, std::list<Facade::geo_point_t>& wcps_list1, std::list<Facade::geo_point_t>& wcps_list2, bool flag_pass_check);
// breaking segments ...
bool break_segments(Graph& graph, TrackFitting& track_fitter, IDetectorVolumes::pointer dv, std::vector<SegmentPtr>& remaining_segments, float dis_cut = 0);
// merge two segments to one
bool merge_two_segments_into_one(Graph& graph, SegmentPtr& seg1, VertexPtr& vtx, SegmentPtr& seg2, IDetectorVolumes::pointer dv);
// merge vertex into another
bool merge_vertex_into_another(Graph& graph, VertexPtr& vtx_from, VertexPtr& vtx_to, IDetectorVolumes::pointer dv);

// get direction with distance cut ...
Facade::geo_vector_t vertex_get_dir(VertexPtr& vertex, Graph& graph, double dis_cut = 5*units::cm);
Facade::geo_vector_t vertex_segment_get_dir(VertexPtr& vertex, SegmentPtr& segment, Graph& graph, double dis_cut = 2*units::cm);


// Structure examination
void examine_structure(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv); // call examine_structure_1 and examine_structure_2
bool examine_structure_1(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_structure_2(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);

bool examine_structure_3(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_structure_4(VertexPtr vertex, bool flag_final_vertex, Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);

// identify other segments giving the graph ...
void find_other_segments(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv , bool flag_break_track =true, double search_range = 1.5*units::cm, double scaling_2d = 0.8);

// examine segment
void examine_segment(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool crawl_segment(Graph& graph, Facade::Cluster& cluster, SegmentPtr seg, VertexPtr vertex, TrackFitting& track_fitter, IDetectorVolumes::pointer dv );
void examine_partial_identical_segments(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);

//examine vertices
void examine_vertices(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_vertices_1(Graph&graph, Facade::Cluster&cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_vertices_1p(Graph&graph, VertexPtr v1, VertexPtr v2, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_vertices_2(Graph&graph, Facade::Cluster&cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_vertices_4(Graph&graph, Facade::Cluster&cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_vertices_4p(Graph&graph, VertexPtr v1, VertexPtr v2, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
Facade::geo_point_t get_local_extension(Facade::Cluster& cluster, Facade::geo_point_t& wcp);
void examine_vertices_3(Graph& graph, Facade::Cluster& main_cluster, std::pair<VertexPtr, VertexPtr> main_cluster_initial_pair_vertices, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);

// master pattern recognition function
bool find_proto_vertex(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv, bool flag_break_track = true, int nrounds_find_other_tracks = 2, bool flag_back_search = true);

void init_point_segment(Graph& graph, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);

// examine the structure of the patterns ...
bool examine_structure_final_1(Graph& graph, VertexPtr main_vertex, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_structure_final_1p(Graph& graph, VertexPtr main_vertex, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_structure_final_2(Graph& graph, VertexPtr main_vertex, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_structure_final_3(Graph& graph, VertexPtr main_vertex, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);
bool examine_structure_final(Graph& graph, VertexPtr main_vertex, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv);

// EM shower related
void clustering_points(Graph& graph, Facade::Cluster& cluster, const IDetectorVolumes::pointer& dv, const std::string& cloud_name = "associated_points", double search_range = 1.2*units::cm, double scaling_2d = 0.7);
void separate_track_shower(Graph&graph, Facade::Cluster& cluster);
// Direction
void determine_direction(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, const IRecombinationModel::pointer& recomb_model);
std::pair<int, double> calculate_num_daughter_showers(Graph& graph, VertexPtr vertex, SegmentPtr segment, bool flag_count_shower = true);
void examine_good_tracks(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data);
// about fix maps
void fix_maps_multiple_tracks_in(Graph& graph, Facade::Cluster& cluster);
void fix_maps_shower_in_track_out(Graph& graph, Facade::Cluster& cluster);
void improve_maps_one_in(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, const IRecombinationModel::pointer& recomb_model, bool flag_strong_check = true);
void improve_maps_shower_in_track_out(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, const IRecombinationModel::pointer& recomb_model, bool flag_strong_check = true);
void improve_maps_no_dir_tracks(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, const IRecombinationModel::pointer& recomb_model);
void improve_maps_multiple_tracks_in(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, const IRecombinationModel::pointer& recomb_model);
void judge_no_dir_tracks_close_to_showers(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, IDetectorVolumes::pointer dv);
bool examine_maps(Graph&graph, Facade::Cluster& cluster);
void examine_all_showers(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data);
void shower_determining_in_main_cluster(Graph& graph, Facade::Cluster& cluster, const Clus::ParticleDataSet::pointer& particle_data, const IRecombinationModel::pointer& recomb_model, IDetectorVolumes::pointer dv);

// vertex related functions
bool search_for_vertex_activities(Graph& graph, VertexPtr vertex, std::set<SegmentPtr>& segments_set, Facade::Cluster& cluster, TrackFitting& track_fitter, IDetectorVolumes::pointer dv, double search_range = 1.5*units::cm);

// global information transfer
void transfer_info_from_segment_to_cluster(Graph& graph, Facade::Cluster& cluster, const std::string& cloud_name = "associated_points");

// print information
void print_segs_info(Graph& graph, Facade::Cluster& cluster, VertexPtr vertex= nullptr);

};
}
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
12 changes: 6 additions & 6 deletions clus/inc/WireCellClus/PRCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,18 @@ namespace WireCell::Clus::PR {
// multi APA/face detectors?
struct WCPoint {
WireCell::Point point; // 3D point
int uvw[3] = {-1,-1,-1}; // wire indices
int index{-1}; // point index in some container
// int uvw[3] = {-1,-1,-1}; // wire indices
// int index{-1}; // point index in some container

// FIXME: WCP had this, does WCT need it?
// blob* b;


// Return true if the point information has been filled.
bool valid() const {
if (index < 0) return false;
return true;
}
// bool valid() const {
// if (index < 0) return false;
// return true;
// }
};
using WCPointVector = std::vector<WCPoint>;

Expand Down
22 changes: 20 additions & 2 deletions clus/inc/WireCellClus/PRGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,27 @@ namespace WireCell::Clus::PR {
/// The two Vertex objects are those associated with the source/target nodes
/// of the segment's edge. The pair is ordered. The first Vertex is the
/// one with a "wcpoint" closest to the segment's initial "wcpoint".
std::pair<VertexPtr, VertexPtr> find_endpoints(Graph& graph, SegmentPtr seg);
std::pair<VertexPtr, VertexPtr> find_vertices(Graph& graph, SegmentPtr seg);


/// Return the other vertex connected to a segment, given one known vertex.
///
/// Returns nullptr if:
/// - The segment edge is not in the graph
/// - The given vertex is not connected to the segment
///
/// This is useful when you have one vertex of a segment and need to find
/// the vertex at the other end.
VertexPtr find_other_vertex(Graph& graph, SegmentPtr seg, VertexPtr vertex);

/// Find the segment connecting two vertices.
///
/// Returns nullptr if:
/// - Either vertex is not in the graph
/// - No edge exists between the two vertices
///
/// This function searches for an edge between the two given vertices and
/// returns the associated segment if found.
SegmentPtr find_segment(Graph& graph, VertexPtr vtx1, VertexPtr vtx2);

};
#endif
28 changes: 27 additions & 1 deletion clus/inc/WireCellClus/PRSegment.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ namespace WireCell::Clus::PR {
// Getters
const std::shared_ptr<Aux::ParticleInfo>& particle_info() const { return m_particle_info; }
std::shared_ptr<Aux::ParticleInfo>& particle_info() { return m_particle_info; }
double particle_score() const { return m_particle_score; }
void particle_score(double score) { m_particle_score = score; }

// Chainable setter
Segment& particle_info(std::shared_ptr<Aux::ParticleInfo> pinfo) {
Expand Down Expand Up @@ -115,10 +117,30 @@ namespace WireCell::Clus::PR {
bool fit_flag_skip(int i);
void fit_flag_skip(int i, bool flag);

void set_fit_associate_vec(std::vector<WireCell::Point >& tmp_fit_pt_vec, std::vector<int>& tmp_fit_index, std::vector<bool>& tmp_fit_skip, const IDetectorVolumes::pointer& dv,const std::string& cloud_name="fit");
void set_fit_associate_vec(std::vector<PR::Fit >& tmp_fit_vec, const IDetectorVolumes::pointer& dv,const std::string& cloud_name="fit");

// Global indices management for point clouds
void set_global_indices(const std::string& cloud_name, std::vector<size_t> indices) {
m_pc_global_indices[cloud_name] = std::move(indices);
}

const std::vector<size_t>& global_indices(const std::string& cloud_name) const {
static const std::vector<size_t> empty_vec;
auto it = m_pc_global_indices.find(cloud_name);
return (it != m_pc_global_indices.end()) ? it->second : empty_vec;
}

bool has_global_indices(const std::string& cloud_name) const {
return m_pc_global_indices.find(cloud_name) != m_pc_global_indices.end();
}

// Add public accessor:
int id() const { return m_id; }
void set_id(int id) { m_id = id; }

private:
// Add to PRSegment.h private section:
int m_id{-1};

std::vector<WCPoint> m_wcpts;
std::vector<Fit> m_fits;
Expand All @@ -127,6 +149,10 @@ namespace WireCell::Clus::PR {
bool m_dir_weak{false};

std::shared_ptr<Aux::ParticleInfo> m_particle_info{nullptr};
double m_particle_score{100};

// Mapping from local DPC index to global cluster point index
std::map<std::string, std::vector<size_t>> m_pc_global_indices;



Expand Down
Loading