Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2026-08-31 08:21:42

0001 #include "Tpc_PolyClusterDisplay.h"
0002 
0003 #include "tpctrackreco/Tpc_PolyCluster.h"
0004 #include "tpctrackreco/Tpc_PolyClusterContainer.h"
0005 #include "tpctrackreco/Tpc_PolyTrack.h"
0006 #include "tpctrackreco/Tpc_PolyTrackContainer.h"
0007 #include "tpctrackreco/Tpc_PolyTrackVertex.h"
0008 #include "tpctrackreco/Tpc_PolyTrackVertexContainer.h"
0009 
0010 #include <fun4all/Fun4AllReturnCodes.h>
0011 #include <phool/PHCompositeNode.h>
0012 #include <phool/getClass.h>
0013 
0014 #include <TCanvas.h>
0015 #include <TDirectory.h>
0016 #include <TFile.h>
0017 #include <TH3D.h>
0018 #include <TPolyLine3D.h>
0019 #include <TPolyMarker3D.h>
0020 
0021 #include <algorithm>
0022 #include <cmath>
0023 #include <format>
0024 #include <iostream>
0025 #include <limits>
0026 #include <map>
0027 #include <vector>
0028 
0029 namespace
0030 {
0031   int cluster_color(const unsigned int icluster)
0032   {
0033     static const int colors[] = {
0034         kRed + 1, kBlue + 1, kGreen + 2, kMagenta + 1, kCyan + 2,
0035         kOrange + 7, kViolet + 1, kAzure + 1, kPink + 7, kTeal + 3};
0036     return colors[icluster % (sizeof(colors) / sizeof(colors[0]))];
0037   }
0038 
0039   bool cluster_group_z_range(const std::vector<const Tpc_PolyCluster*>& clusters,
0040                              const double display_zmin,
0041                              const double display_zmax,
0042                              double& zmin,
0043                              double& zmax)
0044   {
0045     if (clusters.empty())
0046     {
0047       return false;
0048     }
0049 
0050     zmin = std::numeric_limits<double>::max();
0051     zmax = -std::numeric_limits<double>::max();
0052 
0053     auto update_range = [&](const double z)
0054     {
0055       if (!std::isfinite(z))
0056       {
0057         return;
0058       }
0059       zmin = std::min(zmin, z);
0060       zmax = std::max(zmax, z);
0061     };
0062 
0063     for (const Tpc_PolyCluster* cluster : clusters)
0064     {
0065       if (!cluster || !cluster->isValid())
0066       {
0067         continue;
0068       }
0069       update_range(cluster->get_centroid_z());
0070     }
0071 
0072     if (zmin == std::numeric_limits<double>::max() || zmax == -std::numeric_limits<double>::max())
0073     {
0074       return false;
0075     }
0076 
0077     zmin = std::max(zmin, display_zmin);
0078     zmax = std::min(zmax, display_zmax);
0079     if (zmin > zmax)
0080     {
0081       return false;
0082     }
0083 
0084     if (zmin == zmax)
0085     {
0086       zmin = std::max(zmin - 0.1, display_zmin);
0087       zmax = std::min(zmax + 0.1, display_zmax);
0088     }
0089 
0090     return zmin < zmax;
0091   }
0092 
0093   bool track_vertex_z_selected(const Tpc_PolyTrackVertex* vtx,
0094                                const double vertex_zmin,
0095                                const double vertex_zmax)
0096   {
0097     if (!vtx)
0098     {
0099       return false;
0100     }
0101     const double z0 = vtx->get_z0();
0102     return std::isfinite(z0) && z0 >= vertex_zmin && z0 <= vertex_zmax;
0103   }
0104 
0105   bool poly_track_xy_at_z(const Tpc_PolyTrack* trk,
0106                           const double z,
0107                           const double magnetic_field_tesla,
0108                           const double arc_direction,
0109                           const bool use_straight_line,
0110                           double& x,
0111                           double& y)
0112   {
0113     if (!trk || trk->get_fit_status() == 0 || !std::isfinite(z))
0114     {
0115       return false;
0116     }
0117 
0118     const double x0 = trk->get_x();
0119     const double y0 = trk->get_y();
0120     const double z0 = trk->get_z();
0121     const double px = trk->get_px();
0122     const double py = trk->get_py();
0123     const double pz = trk->get_pz();
0124     const double charge = trk->get_charge();
0125     if (!std::isfinite(x0) || !std::isfinite(y0) || !std::isfinite(z0) ||
0126         !std::isfinite(px) || !std::isfinite(py) || !std::isfinite(pz) ||
0127         !std::isfinite(charge))
0128     {
0129       return false;
0130     }
0131 
0132     const double dz = z - z0;
0133     if (use_straight_line || std::fabs(charge * magnetic_field_tesla) < 1.0e-12)
0134     {
0135       if (std::fabs(pz) < 1.0e-12)
0136       {
0137         return false;
0138       }
0139       x = x0 + arc_direction * px / pz * dz;
0140       y = y0 + arc_direction * py / pz * dz;
0141       return std::isfinite(x) && std::isfinite(y);
0142     }
0143 
0144     const double pt = std::hypot(px, py);
0145     if (pt <= 0.0 || std::fabs(pz) < 1.0e-12)
0146     {
0147       return false;
0148     }
0149 
0150     const double signed_radius = pt / (0.003 * charge * magnetic_field_tesla);
0151     const double radius = std::fabs(signed_radius);
0152     if (!std::isfinite(radius) || radius <= 0.0)
0153     {
0154       return false;
0155     }
0156 
0157     const double tx = px / pt;
0158     const double ty = py / pt;
0159     const double sign = signed_radius > 0.0 ? 1.0 : -1.0;
0160     const double xc = x0 + sign * radius * ty;
0161     const double yc = y0 - sign * radius * tx;
0162     const double phi0 = std::atan2(y0 - yc, x0 - xc);
0163     const double dzds = pz / pt;
0164     if (std::fabs(dzds) < 1.0e-12)
0165     {
0166       return false;
0167     }
0168 
0169     const double arc = arc_direction * dz / dzds;
0170     const double phi = phi0 - sign * arc / radius;
0171     x = xc + radius * std::cos(phi);
0172     y = yc + radius * std::sin(phi);
0173     return std::isfinite(x) && std::isfinite(y);
0174   }
0175 
0176   double cluster_line_residual2(const Tpc_PolyTrack* poly_track,
0177                                 const std::vector<const Tpc_PolyCluster*>& clusters,
0178                                 const double magnetic_field_tesla,
0179                                 const double arc_direction,
0180                                 const bool use_straight_line)
0181   {
0182     if (!poly_track || clusters.empty())
0183     {
0184       return std::numeric_limits<double>::max();
0185     }
0186 
0187     double sum = 0.0;
0188     unsigned int n = 0;
0189     for (const Tpc_PolyCluster* cluster : clusters)
0190     {
0191       if (!cluster || !cluster->isValid())
0192       {
0193         continue;
0194       }
0195       const double cx = cluster->get_centroid_x();
0196       const double cy = cluster->get_centroid_y();
0197       const double cz = cluster->get_centroid_z();
0198       if (!std::isfinite(cx) || !std::isfinite(cy) || !std::isfinite(cz))
0199       {
0200         continue;
0201       }
0202 
0203       double x = 0.0;
0204       double y = 0.0;
0205       if (!poly_track_xy_at_z(poly_track, cz, magnetic_field_tesla, arc_direction, use_straight_line, x, y))
0206       {
0207         continue;
0208       }
0209 
0210       const double dx = x - cx;
0211       const double dy = y - cy;
0212       sum += dx * dx + dy * dy;
0213       ++n;
0214     }
0215 
0216     return n > 0 ? sum / static_cast<double>(n) : std::numeric_limits<double>::max();
0217   }
0218 
0219   TPolyLine3D* make_poly_track_line(const Tpc_PolyTrack* trk,
0220                                     const double zmin,
0221                                     const double zmax,
0222                                     const double xymax,
0223                                     const double magnetic_field_tesla,
0224                                     const double arc_direction,
0225                                     const bool use_straight_line,
0226                                     const int color)
0227   {
0228     if (!trk || trk->get_fit_status() == 0)
0229     {
0230       return nullptr;
0231     }
0232 
0233     std::vector<double> zs;
0234     std::vector<double> xs;
0235     std::vector<double> ys;
0236     const unsigned int nsteps = 80;
0237     zs.reserve(nsteps + 1);
0238     xs.reserve(nsteps + 1);
0239     ys.reserve(nsteps + 1);
0240 
0241     for (unsigned int istep = 0; istep <= nsteps; ++istep)
0242     {
0243       const double f = static_cast<double>(istep) / static_cast<double>(nsteps);
0244       const double z = zmin + f * (zmax - zmin);
0245       double x = 0.0;
0246       double y = 0.0;
0247       if (!poly_track_xy_at_z(trk, z, magnetic_field_tesla, arc_direction, use_straight_line, x, y))
0248       {
0249         continue;
0250       }
0251       if (std::fabs(x) > xymax || std::fabs(y) > xymax)
0252       {
0253         continue;
0254       }
0255       zs.push_back(z);
0256       xs.push_back(x);
0257       ys.push_back(y);
0258     }
0259 
0260     if (zs.size() < 2)
0261     {
0262       return nullptr;
0263     }
0264     TPolyLine3D* line = new TPolyLine3D(static_cast<int>(zs.size()));
0265     for (unsigned int i = 0; i < zs.size(); ++i)
0266     {
0267       line->SetPoint(static_cast<int>(i), zs[i], xs[i], ys[i]);
0268     }
0269     line->SetLineColor(color);
0270     line->SetLineWidth(3);
0271     return line;
0272   }
0273 
0274   TPolyMarker3D* make_cluster_marker(const double z,
0275                                      const double x,
0276                                      const double y,
0277                                      const int color)
0278   {
0279     TPolyMarker3D* marker = new TPolyMarker3D(1);
0280     marker->SetPoint(0, z, x, y);
0281     marker->SetMarkerColor(color);
0282     marker->SetMarkerStyle(20);
0283     marker->SetMarkerSize(1.4);
0284     return marker;
0285   }
0286 
0287   TPolyMarker3D* make_pca_marker(const Tpc_PolyTrackVertex* vtx,
0288                                  const double zmin,
0289                                  const double zmax,
0290                                  const double xymax,
0291                                  const int color)
0292   {
0293     if (!vtx || !vtx->get_pca_valid())
0294     {
0295       return nullptr;
0296     }
0297 
0298     const double x = vtx->get_pca_x();
0299     const double y = vtx->get_pca_y();
0300     const double z = vtx->get_pca_z();
0301     if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
0302     {
0303       return nullptr;
0304     }
0305     if (z < zmin || z > zmax)
0306     {
0307       return nullptr;
0308     }
0309     if (std::fabs(x) > xymax || std::fabs(y) > xymax)
0310     {
0311       return nullptr;
0312     }
0313 
0314     TPolyMarker3D* marker = new TPolyMarker3D(1);
0315     marker->SetPoint(0, z, x, y);
0316     marker->SetMarkerColor(color);
0317     marker->SetMarkerStyle(20);
0318     marker->SetMarkerSize(1.2);
0319     return marker;
0320   }
0321 
0322   TPolyMarker3D* make_collision_vertex_marker(const double x,
0323                                               const double y,
0324                                               const double z,
0325                                               const double zmin,
0326                                               const double zmax,
0327                                               const double xymax)
0328   {
0329     if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
0330     {
0331       return nullptr;
0332     }
0333     if (z < zmin || z > zmax)
0334     {
0335       return nullptr;
0336     }
0337     if (std::fabs(x) > xymax || std::fabs(y) > xymax)
0338     {
0339       return nullptr;
0340     }
0341 
0342     TPolyMarker3D* marker = new TPolyMarker3D(1);
0343     marker->SetPoint(0, z, x, y);
0344     marker->SetMarkerColor(kBlack);
0345     marker->SetMarkerStyle(29);
0346     marker->SetMarkerSize(2.0);
0347     return marker;
0348   }
0349 }  // namespace
0350 
0351 Tpc_PolyClusterDisplay::Tpc_PolyClusterDisplay(const std::string& name,
0352                                                const std::string& outfilename,
0353                                                const std::string& clusterNodeName,
0354                                                const unsigned int maxEventDisplays)
0355   : SubsysReco(name)
0356   , m_outfilename(outfilename)
0357   , m_clusterNodeName(clusterNodeName)
0358   , m_finalTrackNodeName("TPC_POLYTRACKS")
0359   , m_finalTrackVertexNodeName("TPC_POLYTRACKVERTICES")
0360   , m_maxEventDisplays(maxEventDisplays)
0361   , m_evt(0)
0362   , m_eventsSaved(0)
0363   , m_zmin(-102.0)
0364   , m_zmax(102.0)
0365   , m_trackVertexZMin(-20.0)
0366   , m_trackVertexZMax(20.0)
0367   , m_xymax(85.0)
0368   , m_magneticFieldTesla(1.4)
0369   , m_useStraightLineTracks(false)
0370   , m_outfile(nullptr)
0371   , m_clusters(nullptr)
0372   , m_finalTracks(nullptr)
0373   , m_finalTrackVertices(nullptr)
0374 {
0375 }
0376 
0377 Tpc_PolyClusterDisplay::~Tpc_PolyClusterDisplay()
0378 {
0379   if (m_outfile)
0380   {
0381     delete m_outfile;
0382     m_outfile = nullptr;
0383   }
0384 }
0385 
0386 int Tpc_PolyClusterDisplay::Init(PHCompositeNode* /*unused*/)
0387 {
0388   // cppcheck-suppress publicAllocationError
0389   m_outfile = new TFile(m_outfilename.c_str(), "RECREATE");
0390   if (!m_outfile || m_outfile->IsZombie())
0391   {
0392     std::cerr << Name() << "::Init - cannot open output file " << m_outfilename << std::endl;
0393     return Fun4AllReturnCodes::ABORTRUN;
0394   }
0395   m_outfile->mkdir("events");
0396   return Fun4AllReturnCodes::EVENT_OK;
0397 }
0398 
0399 bool Tpc_PolyClusterDisplay::get_nodes(PHCompositeNode* topNode)
0400 {
0401   m_clusters = findNode::getClass<Tpc_PolyClusterContainer>(topNode, m_clusterNodeName);
0402   if (!m_clusters)
0403   {
0404     std::cerr << Name() << " - missing " << m_clusterNodeName << std::endl;
0405     return false;
0406   }
0407   m_finalTracks = findNode::getClass<Tpc_PolyTrackContainer>(topNode, m_finalTrackNodeName);
0408   if (!m_finalTracks)
0409   {
0410     std::cerr << Name() << " - missing " << m_finalTrackNodeName << ", drawing clusters without fitted lines" << std::endl;
0411   }
0412   m_finalTrackVertices = findNode::getClass<Tpc_PolyTrackVertexContainer>(topNode, m_finalTrackVertexNodeName);
0413   if (!m_finalTrackVertices)
0414   {
0415     std::cerr << Name() << " - missing " << m_finalTrackVertexNodeName
0416               << ", drawing without final-track PCA/collision vertices" << std::endl;
0417   }
0418   return true;
0419 }
0420 
0421 int Tpc_PolyClusterDisplay::process_event(PHCompositeNode* topNode)
0422 {
0423   ++m_evt;
0424   if (!get_nodes(topNode))
0425   {
0426     return Fun4AllReturnCodes::EVENT_OK;
0427   }
0428   if (!m_outfile || m_eventsSaved >= m_maxEventDisplays)
0429   {
0430     return Fun4AllReturnCodes::EVENT_OK;
0431   }
0432 
0433   TDirectory* eventsTop = m_outfile->GetDirectory("events");
0434   if (!eventsTop)
0435   {
0436     eventsTop = m_outfile->mkdir("events");
0437   }
0438   eventsTop->cd();
0439 
0440   TDirectory* eventDir = eventsTop->mkdir(std::format("event_{:06}", m_evt).c_str());
0441   if (!eventDir)
0442   {
0443     return Fun4AllReturnCodes::EVENT_OK;
0444   }
0445   eventDir->cd();
0446 
0447   TH3D* h3 = new TH3D(std::format("h3_evt{:06}_tpc_polycluster_centroids_bothsides", m_evt).c_str(),
0448                       std::format("event {} both sides Tpc_PolyCluster centroids;z [cm];x [cm];y [cm]", m_evt).c_str(),
0449                       204, m_zmin, m_zmax,
0450                       170, -m_xymax, m_xymax,
0451                       170, -m_xymax, m_xymax);
0452   h3->SetStats(false);
0453   h3->SetDirectory(nullptr);
0454 
0455   std::vector<TPolyMarker3D*> markers;
0456   std::vector<TPolyMarker3D*> pca_markers;
0457   std::vector<TPolyMarker3D*> collision_vertex_markers;
0458   std::vector<TPolyLine3D*> lines;
0459   std::map<unsigned int, const Tpc_PolyTrackVertex*> poly_track_vertices_by_assembled_track_id;
0460   std::map<unsigned int, std::vector<const Tpc_PolyCluster*> > clusters_by_assembled_track_id;
0461   const unsigned int nvertices = m_finalTrackVertices ? m_finalTrackVertices->size() : 0;
0462   for (unsigned int ivtx = 0; ivtx < nvertices; ++ivtx)
0463   {
0464     const Tpc_PolyTrackVertex* vtx = m_finalTrackVertices->get_vertex(ivtx);
0465     if (!vtx)
0466     {
0467       continue;
0468     }
0469     poly_track_vertices_by_assembled_track_id[vtx->get_source_assembled_track_id()] = vtx;
0470   }
0471 
0472   const bool applyTrackVertexZRange = m_finalTrackVertices != nullptr;
0473   const unsigned int nclusters_total = m_clusters->size();
0474   unsigned int nclusters = 0;
0475   unsigned int nclustersPlotted = 0;
0476   for (unsigned int icluster = 0; icluster < nclusters_total; ++icluster)
0477   {
0478     const Tpc_PolyCluster* cluster = m_clusters->get_cluster(icluster);
0479     if (!cluster || !cluster->isValid())
0480     {
0481       continue;
0482     }
0483     const unsigned int source_id = cluster->get_source_assembled_track_id();
0484     const auto vertex_iter = poly_track_vertices_by_assembled_track_id.find(source_id);
0485     if (applyTrackVertexZRange &&
0486         (vertex_iter == poly_track_vertices_by_assembled_track_id.end() ||
0487          !track_vertex_z_selected(vertex_iter->second, m_trackVertexZMin, m_trackVertexZMax)))
0488     {
0489       continue;
0490     }
0491     clusters_by_assembled_track_id[source_id].push_back(cluster);
0492 
0493     ++nclusters;
0494     const double x = cluster->get_centroid_x();
0495     const double y = cluster->get_centroid_y();
0496     const double z = cluster->get_centroid_z();
0497     if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
0498     {
0499       continue;
0500     }
0501     if (z < m_zmin || z > m_zmax)
0502     {
0503       continue;
0504     }
0505     markers.push_back(make_cluster_marker(z, x, y, cluster_color(source_id)));
0506 
0507     ++nclustersPlotted;
0508   }
0509 
0510   const unsigned int npoly_tracks = m_finalTracks ? m_finalTracks->size() : 0;
0511   for (unsigned int ifinal = 0; ifinal < npoly_tracks; ++ifinal)
0512   {
0513     const Tpc_PolyTrack* trk = m_finalTracks->get_track(ifinal);
0514     if (!trk)
0515     {
0516       continue;
0517     }
0518 
0519     const auto cluster_iter = clusters_by_assembled_track_id.find(trk->get_source_assembled_track_id());
0520     if (cluster_iter == clusters_by_assembled_track_id.end())
0521     {
0522       continue;
0523     }
0524 
0525     double line_zmin = m_zmin;
0526     double line_zmax = m_zmax;
0527     if (!cluster_group_z_range(cluster_iter->second, m_zmin, m_zmax, line_zmin, line_zmax))
0528     {
0529       continue;
0530     }
0531 
0532     const bool use_straight_line = m_useStraightLineTracks || std::fabs(trk->get_charge() * m_magneticFieldTesla) < 1.0e-12;
0533     const double forward_residual2 = cluster_line_residual2(trk, cluster_iter->second, m_magneticFieldTesla, 1.0, use_straight_line);
0534     const double reverse_residual2 = cluster_line_residual2(trk, cluster_iter->second, m_magneticFieldTesla, -1.0, use_straight_line);
0535     const double arc_direction = forward_residual2 <= reverse_residual2 ? 1.0 : -1.0;
0536 
0537     TPolyLine3D* line = make_poly_track_line(trk, line_zmin, line_zmax, m_xymax,
0538                                              m_magneticFieldTesla, arc_direction,
0539                                              use_straight_line,
0540                                              cluster_color(trk->get_source_assembled_track_id()));
0541     if (line)
0542     {
0543       lines.push_back(line);
0544     }
0545   }
0546 
0547   for (unsigned int ivtx = 0; ivtx < nvertices; ++ivtx)
0548   {
0549     const Tpc_PolyTrackVertex* vtx = m_finalTrackVertices->get_vertex(ivtx);
0550     if (!vtx)
0551     {
0552       continue;
0553     }
0554     if (!track_vertex_z_selected(vtx, m_trackVertexZMin, m_trackVertexZMax))
0555     {
0556       continue;
0557     }
0558 
0559     int color = cluster_color(vtx->get_track_id());
0560     const auto cluster_iter = clusters_by_assembled_track_id.find(vtx->get_source_assembled_track_id());
0561     if (cluster_iter != clusters_by_assembled_track_id.end())
0562     {
0563       color = cluster_color(vtx->get_source_assembled_track_id());
0564     }
0565 
0566     TPolyMarker3D* marker = make_pca_marker(vtx, m_zmin, m_zmax, m_xymax, color);
0567     if (marker)
0568     {
0569       pca_markers.push_back(marker);
0570     }
0571   }
0572 
0573   const unsigned int ncollision_vertices = (m_finalTrackVertices && m_finalTrackVertices->get_collision_vertex_valid())
0574                                                ? m_finalTrackVertices->get_collision_vertex_count()
0575                                                : 0;
0576   for (unsigned int ivtx = 0; ivtx < ncollision_vertices; ++ivtx)
0577   {
0578     TPolyMarker3D* marker = make_collision_vertex_marker(m_finalTrackVertices->get_collision_x(ivtx),
0579                                                          m_finalTrackVertices->get_collision_y(ivtx),
0580                                                          m_finalTrackVertices->get_collision_z(ivtx),
0581                                                          m_zmin, m_zmax, m_xymax);
0582     if (marker)
0583     {
0584       collision_vertex_markers.push_back(marker);
0585     }
0586   }
0587 
0588   TCanvas* c3 = new TCanvas(std::format("c3_evt{:06}_tpc_polycluster_z_x_y_centroids_bothsides", m_evt).c_str(),
0589                             std::format("event {} both sides Tpc_PolyCluster centroids", m_evt).c_str(),
0590                             1200, 900);
0591   h3->Draw();
0592   for (TPolyLine3D* line : lines)
0593   {
0594     if (line)
0595     {
0596       line->Draw("same");
0597     }
0598   }
0599   for (TPolyMarker3D* marker : markers)
0600   {
0601     if (marker)
0602     {
0603       marker->Draw("same");
0604     }
0605   }
0606   for (TPolyMarker3D* marker : pca_markers)
0607   {
0608     if (marker)
0609     {
0610       marker->Draw("same");
0611     }
0612   }
0613   for (TPolyMarker3D* marker : collision_vertex_markers)
0614   {
0615     if (marker)
0616     {
0617       marker->Draw("same");
0618     }
0619   }
0620   c3->Modified();
0621   c3->Update();
0622   c3->Write();
0623 
0624   std::cout << Name() << " - saved event " << m_evt
0625             << " clusters=" << nclusters_total
0626             << " selected_clusters=" << nclusters
0627             << " plotted=" << nclustersPlotted
0628             << " poly_tracks=" << npoly_tracks
0629             << " lines=" << lines.size()
0630             << " poly_track_vertices=" << nvertices
0631             << " pca_markers=" << pca_markers.size()
0632             << " collision_vertices=" << ncollision_vertices
0633             << " collision_markers=" << collision_vertex_markers.size() << std::endl;
0634 
0635   ++m_eventsSaved;
0636   return Fun4AllReturnCodes::EVENT_OK;
0637 }
0638 
0639 int Tpc_PolyClusterDisplay::End(PHCompositeNode* /*unused*/)
0640 {
0641   if (m_outfile)
0642   {
0643     m_outfile->Close();
0644     delete m_outfile;
0645     m_outfile = nullptr;
0646   }
0647   return Fun4AllReturnCodes::EVENT_OK;
0648 }