Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:20:50

0001 #include "HelicalFitter.h"
0002 
0003 #include "AlignmentDefs.h"
0004 #include "Mille.h"
0005 
0006 #include <tpc/TpcClusterZCrossingCorrection.h>
0007 
0008 /// Tracking includes
0009 #include <trackbase/ActsSurfaceMaps.h>
0010 #include <trackbase/InttDefs.h>
0011 #include <trackbase/MvtxDefs.h>
0012 #include <trackbase/TpcDefs.h>
0013 #include <trackbase/TrackFitUtils.h>
0014 #include <trackbase/TrkrClusterContainer.h>
0015 #include <trackbase/TrkrClusterContainerv4.h>
0016 #include <trackbase/TrkrClusterv3.h>
0017 #include <trackbase/TrkrDefs.h>  // for cluskey, getTrkrId, tpcId
0018 #include <trackbase/alignmentTransformationContainer.h>
0019 
0020 #include <trackbase_historic/TrackSeedContainer.h>
0021 #include <trackbase_historic/SvtxAlignmentState.h>
0022 #include <trackbase_historic/SvtxAlignmentStateMap_v1.h>
0023 #include <trackbase_historic/SvtxAlignmentState_v1.h>
0024 #include <trackbase_historic/SvtxTrackMap_v2.h>
0025 #include <trackbase_historic/SvtxTrackState_v1.h>
0026 #include <trackbase_historic/SvtxTrack_v4.h>
0027 #include <trackbase_historic/TrackSeedHelper.h>
0028 #include <trackbase_historic/TrackSeed_v2.h>
0029 
0030 #include <globalvertex/SvtxVertex.h>
0031 #include <globalvertex/SvtxVertexMap.h>
0032 
0033 #include <phparameter/PHParameterInterface.h>
0034 
0035 #include <fun4all/Fun4AllReturnCodes.h>
0036 #include <fun4all/SubsysReco.h>
0037 
0038 #include <phool/PHCompositeNode.h>
0039 #include <phool/PHIODataNode.h>
0040 #include <phool/getClass.h>
0041 #include <phool/phool.h>
0042 
0043 #include <Acts/Definitions/Algebra.hpp>
0044 #include <Acts/Definitions/Units.hpp>
0045 
0046 #include <TFile.h>
0047 #include <TNtuple.h>
0048 
0049 #include <climits>  // for UINT_MAX
0050 #include <cmath>    // for std::abs, sqrt
0051 #include <fstream>
0052 #include <iostream>  // for operator<<, basic_ostream
0053 #include <memory>
0054 #include <set>  // for _Rb_tree_const_iterator
0055 #include <stdexcept>
0056 #include <string>
0057 #include <tuple>
0058 #include <utility>  // for pair
0059 #include <vector>
0060 
0061 using namespace std;
0062 
0063 // The derivative formulae used in this code follow the derivation in the ATLAS paper
0064 // Global chi^2 approach to the Alignment of the ATLAS Silicon Tracking Detectors
0065 // ATL-INDET-PUB-2005-002, 11 October 2005
0066 
0067 namespace
0068 {  // Anonymous
0069   bool arr_has_nan(float* arr)
0070   {
0071     for (int i = 0; i < AlignmentDefs::NLC; ++i)
0072     {
0073       if (isnan(arr[i]))
0074       {
0075         return true;
0076       }
0077     }
0078     return false;
0079   }
0080 };  // namespace
0081 //____________________________________________________________________________..
0082 HelicalFitter::HelicalFitter(const std::string& name)
0083   : SubsysReco(name)
0084   , PHParameterInterface(name)
0085   , _mille(nullptr)
0086 {
0087   InitializeParameters();
0088 
0089   vertexPosition(0) = 0;
0090   vertexPosition(1) = 0;
0091 
0092   vtx_sigma(0) = 0.005;
0093   vtx_sigma(1) = 0.005;
0094 }
0095 
0096 //____________________________________________________________________________..
0097 int HelicalFitter::InitRun(PHCompositeNode* topNode)
0098 {
0099   UpdateParametersWithMacro();
0100 
0101   int ret = GetNodes(topNode);
0102   if (ret != Fun4AllReturnCodes::EVENT_OK)
0103   {
0104     return ret;
0105   }
0106 
0107   ret = CreateNodes(topNode);
0108   if (ret != Fun4AllReturnCodes::EVENT_OK)
0109   {
0110     return ret;
0111   }
0112 
0113   // Instantiate Mille and open output data file
0114   if (test_output)
0115   {
0116     _mille = new Mille(data_outfilename.c_str(), false);  // write text in data files, rather than binary, for debugging only
0117   }
0118   else
0119   {
0120     _mille = new Mille(data_outfilename.c_str());
0121   }
0122 
0123   // Write the steering file here, and add the data file path to it
0124   std::ofstream steering_file(steering_outfilename);
0125   steering_file << data_outfilename << std::endl;
0126   steering_file.close();
0127 
0128   if (make_ntuple)
0129   {
0130     // fout = new TFile("HF_ntuple.root","recreate");
0131     fout = new TFile(ntuple_outfilename.c_str(), "recreate");
0132     if (straight_line_fit)
0133     {
0134       ntp = new TNtuple("ntp", "HF ntuple", "event:trkid:layer:nsilicon:crosshalfmvtx:ntpc:nclus:trkrid:sector:side:subsurf:phi:glbl0:glbl1:glbl2:glbl3:glbl4:glbl5:sensx:sensy:sensz:normx:normy:normz:sensxideal:sensyideal:senszideal:normxideal:normyideal:normzideal:xglobideal:yglobideal:zglobideal:XYs:Y0:Zs:Z0:xglob:yglob:zglob:xfit:yfit:zfit:xfitMvtxHalf:yfitMvtxHalf:zfitMvtxHalf:pcax:pcay:pcaz:tangx:tangy:tangz:X:Y:fitX:fitY:fitXMvtxHalf:fitYMvtxHalf:dXdXYs:dXdY0:dXdZs:dXdZ0:dXdalpha:dXdbeta:dXdgamma:dXdx:dXdy:dXdz:dYdXYs:dYdY0:dYdZs:dYdZ0:dYdalpha:dYdbeta:dYdgamma:dYdx:dYdy:dYdz");
0135     }
0136     else
0137     {
0138       ntp = new TNtuple("ntp", "HF ntuple", "event:trkid:layer:nsilicon:ntpc:nclus:trkrid:sector:side:subsurf:phi:glbl0:glbl1:glbl2:glbl3:glbl4:glbl5:sensx:sensy:sensz:normx:normy:normz:sensxideal:sensyideal:senszideal:normxideal:normyideal:normzideal:xglobideal:yglobideal:zglobideal:R:X0:Y0:Zs:Z0:xglob:yglob:zglob:xfit:yfit:zfit:pcax:pcay:pcaz:tangx:tangy:tangz:X:Y:fitX:fitY:dXdR:dXdX0:dXdY0:dXdZs:dXdZ0:dXdalpha:dXdbeta:dXdgamma:dXdx:dXdy:dXdz:dYdR:dYdX0:dYdY0:dYdZs:dYdZ0:dYdalpha:dYdbeta:dYdgamma:dYdx:dYdy:dYdz");
0139     }
0140 
0141     if (straight_line_fit)
0142     {
0143       track_ntp = new TNtuple("track_ntp", "HF track ntuple", "track_id:residual_x:residual_y:residualxsigma:residualysigma:dXdXYs:dXdY0:dXdZs:dXdZ0:dXdx:dXdy:dXdz:dYdXYs:dYdY0:dYdZs:dYdZ0:dYdx:dYdy:dYdz:track_xvtx:track_yvtx:track_zvtx:event_xvtx:event_yvtx:event_zvtx:track_phi:perigee_phi:track_eta");
0144     }
0145     else
0146     {
0147       track_ntp = new TNtuple("track_ntp", "HF track ntuple", "track_id:residual_x:residual_y:residualxsigma:residualysigma:dXdR:dXdX0:dXdY0:dXdZs:dXdZ0:dXdx:dXdy:dXdz:dYdR:dYdX0:dYdY0:dYdZs:dYdZ0:dYdx:dYdy:dYdz:track_xvtx:track_yvtx:track_zvtx:event_xvtx:event_yvtx:event_zvtx:track_phi:perigee_phi");
0148     }
0149   }
0150 
0151   // print grouping setup to log file:
0152   std::cout << "HelicalFitter::InitRun: Surface groupings are mvtx " << mvtx_grp << " intt " << intt_grp << " tpc " << tpc_grp << " mms " << mms_grp << std::endl;
0153   std::cout << " possible groupings are:" << std::endl
0154             << " mvtx "
0155             << AlignmentDefs::mvtxGrp::snsr << "  "
0156             << AlignmentDefs::mvtxGrp::stv << "  "
0157             << AlignmentDefs::mvtxGrp::mvtxlyr << "  "
0158             << AlignmentDefs::mvtxGrp::clamshl << "  " << std::endl
0159             << " intt "
0160             << AlignmentDefs::inttGrp::chp << "  "
0161             << AlignmentDefs::inttGrp::lad << "  "
0162             << AlignmentDefs::inttGrp::inttlyr << "  "
0163             << AlignmentDefs::inttGrp::inttbrl << "  " << std::endl
0164             << " tpc "
0165             << AlignmentDefs::tpcGrp::htst << "  "
0166             << AlignmentDefs::tpcGrp::sctr << "  "
0167             << AlignmentDefs::tpcGrp::tp << "  " << std::endl
0168             << " mms "
0169             << AlignmentDefs::mmsGrp::tl << "  "
0170             << AlignmentDefs::mmsGrp::mm << "  " << std::endl;
0171 
0172   event = -1;
0173 
0174   return ret;
0175 }
0176 
0177 //_____________________________________________________________________
0178 void HelicalFitter::SetDefaultParameters()
0179 {
0180   return;
0181 }
0182 
0183 //____________________________________________________________________________..
0184 int HelicalFitter::process_event(PHCompositeNode* /*unused*/)
0185 {
0186   // _track_map_tpc contains the TPC seed track stubs
0187   // _track_map_silicon contains the silicon seed track stubs
0188   // _svtx_seed_map contains the combined silicon and tpc track seeds
0189 
0190   event++;
0191 
0192   if (Verbosity() > 0)
0193   {
0194     if (_track_map_tpc)
0195     {
0196       std::cout << PHWHERE
0197                 << " TPC seed map size " << _track_map_tpc->size() << std::endl;
0198     }
0199     if (_track_map_silicon)
0200     {
0201       std::cout << " Silicon seed map size " << _track_map_silicon->size()
0202                 << std::endl;
0203     }
0204   }
0205 
0206   if (fitsilicon && _track_map_silicon != nullptr)
0207   {
0208     if (_track_map_silicon->size() == 0)
0209     {
0210       return Fun4AllReturnCodes::ABORTEVENT;
0211     }
0212   }
0213   if (fittpc && _track_map_tpc != nullptr)
0214   {
0215     if (_track_map_tpc->size() == 0)
0216     {
0217       return Fun4AllReturnCodes::ABORTEVENT;
0218     }
0219   }
0220 
0221   // Decide whether we want to make a helical fit for silicon or TPC
0222   unsigned int maxtracks = 0;
0223   unsigned int nsilicon = 0;
0224   unsigned int ntpc = 0;
0225   unsigned int nclus = 0;
0226   bool h2h_flag = false;
0227   bool mvtx_east_only = false;
0228   bool mvtx_west_only = false;
0229   if (do_mvtx_half == 0)
0230   {
0231     mvtx_east_only = true;
0232   }
0233   if (do_mvtx_half == 1)
0234   {
0235     mvtx_west_only = true;
0236   }
0237   std::vector<std::vector<Acts::Vector3>> cumulative_global_vec;
0238   std::vector<std::vector<TrkrDefs::cluskey>> cumulative_cluskey_vec;
0239   std::vector<std::vector<float>> cumulative_fitpars_vec;
0240   std::vector<std::vector<float>> cumulative_fitpars_mvtx_half_vec;
0241   std::vector<Acts::Vector3> cumulative_vertex;
0242   std::vector<TrackSeed> cumulative_someseed;
0243   std::vector<SvtxTrack_v4> cumulative_newTrack;
0244 
0245   if (fittpc && _track_map_tpc != nullptr)
0246   {
0247     maxtracks = _track_map_tpc->size();
0248   }
0249   if (fitsilicon && _track_map_silicon != nullptr)
0250   {
0251     maxtracks = _track_map_silicon->size();
0252   }
0253   for (unsigned int trackid = 0; trackid < maxtracks; ++trackid)
0254   {
0255     TrackSeed* tracklet = nullptr;
0256     if (fitsilicon && _track_map_silicon != nullptr)
0257     {
0258       tracklet = _track_map_silicon->get(trackid);
0259     }
0260     else if (fittpc && _track_map_tpc != nullptr)
0261     {
0262       tracklet = _track_map_tpc->get(trackid);
0263     }
0264     if (!tracklet)
0265     {
0266       continue;
0267     }
0268 
0269     std::vector<Acts::Vector3> global_vec;
0270     std::vector<TrkrDefs::cluskey> cluskey_vec;
0271 
0272     // Get a vector of cluster keys from the tracklet
0273     getTrackletClusterList(tracklet, cluskey_vec);
0274     if (cluskey_vec.size() < 3)
0275     {
0276       continue;
0277     }
0278     int nintt = 0;
0279     for (auto& key : cluskey_vec)
0280     {
0281       if (TrkrDefs::getTrkrId(key) == TrkrDefs::inttId)
0282       {
0283         nintt++;
0284       }
0285     }
0286 
0287     // store cluster global positions in a vector global_vec and cluskey_vec
0288 
0289     TrackFitUtils::getTrackletClusters(_tGeometry, _cluster_map, global_vec, cluskey_vec);
0290 
0291     correctTpcGlobalPositions(global_vec, cluskey_vec);
0292 
0293 
0294     std::vector<float> fitpars;
0295     std::vector<float> fitpars_mvtx_half;
0296     if (straight_line_fit)
0297     {
0298       fitpars = TrackFitUtils::fitClustersZeroField(global_vec, cluskey_vec, use_intt_zfit, false, false);
0299       fitpars_mvtx_half = TrackFitUtils::fitClustersZeroField(global_vec, cluskey_vec, use_intt_zfit, mvtx_east_only, mvtx_west_only);
0300       if (fitpars_mvtx_half.size() < 3)
0301       {
0302         fitpars_mvtx_half = fitpars;
0303       }
0304       if (fitpars.size() == 0)
0305       {
0306         continue;  // discard this track, not enough clusters to fit
0307       }
0308 
0309       if (Verbosity() > 1)
0310       {
0311         std::cout << " Track " << trackid << " xy slope " << fitpars[0] << " y intercept " << fitpars[1]
0312                   << " zslope " << fitpars[2] << " Z0 " << fitpars[3] << " eta " << tracklet->get_eta() << " phi " << tracklet->get_phi() << std::endl;
0313       }
0314     }
0315     else
0316     {
0317       if (fitsilicon && nintt < 2)
0318       {
0319         continue;  // discard incomplete seeds
0320       }
0321       if (std::abs(tracklet->get_eta()) > m_eta_cut)
0322       {
0323         continue;
0324       }
0325 
0326       fitpars = TrackFitUtils::fitClusters(global_vec, cluskey_vec);  // do helical fit
0327 
0328       if (fitpars.size() == 0)
0329       {
0330         continue;  // discard this track, not enough clusters to fit
0331       }
0332 
0333       if (Verbosity() > 1)
0334       {
0335         std::cout << " Track " << trackid << " radius " << fitpars[0] << " X0 " << fitpars[1] << " Y0 " << fitpars[2]
0336                   << " zslope " << fitpars[3] << " Z0 " << fitpars[4] << std::endl;
0337       }
0338     }
0339 
0340     //// Create a track map for diagnostics
0341     SvtxTrack_v4 newTrack;
0342     newTrack.set_id(trackid);
0343     if (fitsilicon)
0344     {
0345       newTrack.set_silicon_seed(tracklet);
0346     }
0347     else if (fittpc)
0348     {
0349       newTrack.set_tpc_seed(tracklet);
0350     }
0351 
0352     // if a full track is requested, get the silicon clusters too and refit
0353     if (fittpc && fitfulltrack)
0354     {
0355       // this associates silicon clusters and adds them to the vectors
0356       ntpc = cluskey_vec.size();
0357 
0358       if (straight_line_fit)
0359       {
0360         std::tuple<double, double> linefit_xy(fitpars[0], fitpars[1]);
0361         nsilicon = TrackFitUtils::addClustersOnLine(linefit_xy, true, dca_cut, _tGeometry, _cluster_map, global_vec, cluskey_vec, 0, 6);
0362       }
0363       else
0364       {
0365         nsilicon = TrackFitUtils::addClusters(fitpars, dca_cut, _tGeometry, _cluster_map, global_vec, cluskey_vec, 0, 6);
0366       }
0367 
0368       if (nsilicon < 5)
0369       {
0370         continue;  // discard this TPC seed, did not get a good match to silicon
0371       }
0372       auto trackseed = std::make_unique<TrackSeed_v2>();
0373       for (auto& ckey : cluskey_vec)
0374       {
0375         if (TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::mvtxId ||
0376             TrkrDefs::getTrkrId(ckey) == TrkrDefs::TrkrId::inttId)
0377         {
0378           trackseed->insert_cluster_key(ckey);
0379         }
0380       }
0381 
0382       newTrack.set_silicon_seed(trackseed.get());
0383 
0384       // fit the full track now
0385       fitpars.clear();
0386       fitpars_mvtx_half.clear();
0387 
0388       if (straight_line_fit)
0389       {
0390         fitpars = TrackFitUtils::fitClustersZeroField(global_vec, cluskey_vec, use_intt_zfit);
0391         fitpars_mvtx_half = TrackFitUtils::fitClustersZeroField(global_vec, cluskey_vec, use_intt_zfit, mvtx_east_only, mvtx_west_only);
0392         if (fitpars.size() == 0)
0393         {
0394           continue;  // discard this track, not enough clusters to fit
0395         }
0396 
0397         if (Verbosity() > 1)
0398         {
0399           std::cout << " Track " << trackid << " dy/dx " << fitpars[0] << " y intercept " << fitpars[1]
0400                     << " dz/dx " << fitpars[2] << " Z0 " << fitpars[3] << " eta " << tracklet->get_eta() << " phi " << tracklet->get_phi() << std::endl;
0401         }
0402         if (std::abs(tracklet->get_eta()) > m_eta_cut)
0403         {
0404           continue;
0405         }
0406       }
0407       else
0408       {
0409         fitpars = TrackFitUtils::fitClusters(global_vec, cluskey_vec, use_intt_zfit);  // do helical fit
0410 
0411         if (fitpars.size() == 0)
0412         {
0413           continue;  // discard this track, fit failed
0414         }
0415 
0416         if (Verbosity() > 1)
0417         {
0418           std::cout << " Full track " << trackid << " radius " << fitpars[0] << " X0 " << fitpars[1] << " Y0 " << fitpars[2]
0419                     << " zslope " << fitpars[3] << " Z0 " << fitpars[4] << std::endl;
0420         }
0421       }
0422     }
0423     else if (fitsilicon)
0424     {
0425       nsilicon = cluskey_vec.size();
0426       h2h_flag = TrackFitUtils::isTrackCrossMvtxHalf(cluskey_vec);
0427     }
0428     else if (fittpc && !fitfulltrack)
0429     {
0430       ntpc = cluskey_vec.size();
0431     }
0432 
0433     Acts::Vector3 const beamline(0, 0, 0);
0434     Acts::Vector2 pca2d;
0435     Acts::Vector3 track_vtx;
0436     if (straight_line_fit)
0437     {
0438       pca2d = TrackFitUtils::get_line_point_pca(fitpars[0], fitpars[1], beamline);
0439       track_vtx(0) = pca2d(0);
0440       track_vtx(1) = pca2d(1);
0441       track_vtx(2) = fitpars[3];  // z axis intercept
0442     }
0443     else
0444     {
0445       pca2d = TrackFitUtils::get_circle_point_pca(fitpars[0], fitpars[1], fitpars[2], beamline);
0446       track_vtx(0) = pca2d(0);
0447       track_vtx(1) = pca2d(1);
0448       track_vtx(2) = fitpars[4];  // z axis intercept
0449     }
0450 
0451     newTrack.set_crossing(tracklet->get_crossing());
0452     newTrack.set_id(trackid);
0453 
0454     /// use the track seed functions to help get the track trajectory values
0455     /// in the usual coordinates
0456 
0457     TrackSeed_v2 someseed;
0458     for (auto& ckey : cluskey_vec)
0459     {
0460       someseed.insert_cluster_key(ckey);
0461     }
0462 
0463     if (straight_line_fit)
0464     {
0465       someseed.set_qOverR(1.0);
0466       someseed.set_phi(tracklet->get_phi());
0467 
0468       someseed.set_X0(fitpars[0]);
0469       someseed.set_Y0(fitpars[1]);
0470       someseed.set_Z0(fitpars[3]);
0471       someseed.set_slope(fitpars[2]);
0472 
0473       auto tangent = get_line_tangent(fitpars, global_vec[0]);
0474       newTrack.set_x(track_vtx(0));
0475       newTrack.set_y(track_vtx(1));
0476       newTrack.set_z(track_vtx(2));
0477       newTrack.set_px(tangent.second(0));
0478       newTrack.set_py(tangent.second(1));
0479       newTrack.set_pz(tangent.second(2));
0480       newTrack.set_charge(tracklet->get_charge());
0481     }
0482     else
0483     {
0484       someseed.set_qOverR(tracklet->get_charge() / fitpars[0]);
0485       someseed.set_phi(tracklet->get_phi());
0486 
0487       someseed.set_X0(fitpars[1]);
0488       someseed.set_Y0(fitpars[2]);
0489       someseed.set_Z0(fitpars[4]);
0490       someseed.set_slope(fitpars[3]);
0491 
0492       const auto position = TrackSeedHelper::get_xyz(&someseed);
0493 
0494       newTrack.set_x(position.x());
0495       newTrack.set_y(position.y());
0496       newTrack.set_z(position.z());
0497       newTrack.set_px(someseed.get_px());
0498       newTrack.set_py(someseed.get_py());
0499       newTrack.set_pz(someseed.get_pz());
0500       newTrack.set_charge(tracklet->get_charge());
0501     }
0502 
0503     nclus = ntpc + nsilicon;
0504 
0505     // some basic track quality requirements
0506     if (fittpc && ntpc < 35)
0507     {
0508       if (Verbosity() > 1)
0509       {
0510         std::cout << " reject this track, ntpc = " << ntpc << std::endl;
0511       }
0512       continue;
0513     }
0514     if ((fitsilicon || fitfulltrack) && nsilicon < 3)
0515     {
0516       if (Verbosity() > 1)
0517       {
0518         std::cout << " reject this track, nsilicon = " << nsilicon << std::endl;
0519       }
0520       continue;
0521     }
0522     if (std::abs(newTrack.get_eta()) > m_eta_cut)
0523     {
0524       continue;
0525     }
0526     cumulative_global_vec.push_back(global_vec);
0527     cumulative_cluskey_vec.push_back(cluskey_vec);
0528     cumulative_vertex.push_back(track_vtx);
0529     cumulative_fitpars_vec.push_back(fitpars);
0530     cumulative_fitpars_mvtx_half_vec.push_back(fitpars_mvtx_half);
0531     cumulative_someseed.push_back(someseed);
0532     cumulative_newTrack.push_back(newTrack);
0533   }
0534 
0535   // terminate loop over tracks
0536   // Collect fitpars for each track by intializing array of size maxtracks and populaating thorughout the loop
0537   // Then start new loop over tracks and for each track go over clsutaer
0538   //  make vector of global_vecs
0539   float xsum = 0;
0540   float ysum = 0;
0541   float zsum = 0;
0542   unsigned int const accepted_tracks = cumulative_fitpars_vec.size();
0543 
0544   for (unsigned int trackid = 0; trackid < accepted_tracks; ++trackid)
0545   {
0546     xsum += cumulative_vertex[trackid][0];
0547     ysum += cumulative_vertex[trackid][1];
0548     zsum += cumulative_vertex[trackid][2];
0549   }
0550   Acts::Vector3 averageVertex(xsum / accepted_tracks, ysum / accepted_tracks, zsum / accepted_tracks);
0551 
0552   for (unsigned int trackid = 0; trackid < accepted_tracks; ++trackid)
0553   {
0554     const auto& global_vec = cumulative_global_vec[trackid];
0555     const auto& cluskey_vec = cumulative_cluskey_vec[trackid];
0556     auto fitpars = cumulative_fitpars_vec[trackid];
0557     auto fitpars_mvtx_half = cumulative_fitpars_mvtx_half_vec[trackid];
0558     const auto& someseed = cumulative_someseed[trackid];
0559     auto newTrack = cumulative_newTrack[trackid];
0560     SvtxAlignmentStateMap::StateVec statevec;
0561 
0562     // get the residuals and derivatives for all clusters
0563     for (unsigned int ivec = 0; ivec < global_vec.size(); ++ivec)
0564     {
0565       auto global = global_vec[ivec];
0566       auto cluskey = cluskey_vec[ivec];
0567       auto cluster = _cluster_map->findCluster(cluskey);
0568 
0569       if (!cluster)
0570       {
0571         continue;
0572       }
0573 
0574       unsigned int const trkrid = TrkrDefs::getTrkrId(cluskey);
0575 
0576       // What we need now is to find the point on the surface at which the helix would intersect
0577       // If we have that point, we can transform the fit back to local coords
0578       // we have fitpars for the helix, and the cluster key - from which we get the surface
0579 
0580       Surface const surf = _tGeometry->maps().getSurface(cluskey, cluster);
0581       Acts::Vector3 helix_pca(0, 0, 0);
0582       Acts::Vector3 helix_tangent(0, 0, 0);
0583       Acts::Vector3 fitpoint;
0584       Acts::Vector3 fitpoint_mvtx_half;
0585       if (straight_line_fit)
0586       {
0587         fitpoint = get_line_surface_intersection(surf, fitpars);
0588         fitpoint_mvtx_half = get_line_surface_intersection(surf, fitpars_mvtx_half);
0589       }
0590       else
0591       {
0592         fitpoint = get_helix_surface_intersection(surf, fitpars, global, helix_pca, helix_tangent);
0593       }
0594 
0595       // fitpoint is the point where the helical fit intersects the plane of the surface
0596       // Now transform the helix fitpoint to local coordinates to compare with cluster local coordinates
0597       Acts::Vector3 fitpoint_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint * Acts::UnitConstants::cm);
0598       Acts::Vector3 fitpoint_mvtx_half_local = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (fitpoint_mvtx_half * Acts::UnitConstants::cm);
0599 
0600       fitpoint_local /= Acts::UnitConstants::cm;
0601       fitpoint_mvtx_half_local /= Acts::UnitConstants::cm;
0602 
0603       auto xloc = cluster->getLocalX();  // in cm
0604       auto zloc = cluster->getLocalY();
0605 
0606       if (trkrid == TrkrDefs::tpcId)
0607       {
0608         zloc = convertTimeToZ(cluskey, cluster);
0609       }
0610 
0611       Acts::Vector2 residual(xloc - fitpoint_local(0), zloc - fitpoint_local(1));
0612 
0613       unsigned int const layer = TrkrDefs::getLayer(cluskey_vec[ivec]);
0614       float const phi = atan2(global(1), global(0));
0615 
0616       SvtxTrackState_v1 svtxstate(fitpoint.norm());
0617       svtxstate.set_x(fitpoint(0));
0618       svtxstate.set_y(fitpoint(1));
0619       svtxstate.set_z(fitpoint(2));
0620       std::pair<Acts::Vector3, Acts::Vector3> tangent;
0621       if (straight_line_fit)
0622       {
0623         tangent = get_line_tangent(fitpars, global);
0624       }
0625       else
0626       {
0627         tangent = get_helix_tangent(fitpars, global);
0628       }
0629 
0630       svtxstate.set_px(someseed.get_p() * tangent.second.x());
0631       svtxstate.set_py(someseed.get_p() * tangent.second.y());
0632       svtxstate.set_pz(someseed.get_p() * tangent.second.z());
0633       newTrack.insert_state(&svtxstate);
0634 
0635       if (Verbosity() > 1)
0636       {
0637         Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm);
0638         loc_check /= Acts::UnitConstants::cm;
0639         std::cout << "    layer " << layer << std::endl
0640                   << " cluster global " << global(0) << " " << global(1) << " " << global(2) << std::endl
0641                   << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl
0642                   << " fitpoint_local " << fitpoint_local(0) << " " << fitpoint_local(1) << " " << fitpoint_local(2) << std::endl
0643                   << " cluster local x " << cluster->getLocalX() << " cluster local y " << cluster->getLocalY() << std::endl
0644                   << " cluster global to local x " << loc_check(0) << " local y " << loc_check(1) << "  local z " << loc_check(2) << std::endl
0645                   << " cluster local residual x " << residual(0) << " cluster local residual y " << residual(1) << std::endl;
0646       }
0647 
0648       if (Verbosity() > 1)
0649       {
0650         Acts::Transform3 transform = surf->transform(_tGeometry->geometry().getGeoContext());
0651         std::cout << "Transform is:" << std::endl;
0652         std::cout << transform.matrix() << std::endl;
0653         Acts::Vector3 loc_check = surf->transform(_tGeometry->geometry().getGeoContext()).inverse() * (global * Acts::UnitConstants::cm);
0654         loc_check /= Acts::UnitConstants::cm;
0655         unsigned int const sector = TpcDefs::getSectorId(cluskey_vec[ivec]);
0656         unsigned int const side = TpcDefs::getSide(cluskey_vec[ivec]);
0657         std::cout << "    layer " << layer << " sector " << sector << " side " << side << " subsurf " << cluster->getSubSurfKey() << std::endl
0658                   << " cluster global " << global(0) << " " << global(1) << " " << global(2) << std::endl
0659                   << " fitpoint " << fitpoint(0) << " " << fitpoint(1) << " " << fitpoint(2) << std::endl
0660                   << " fitpoint_local " << fitpoint_local(0) << " " << fitpoint_local(1) << " " << fitpoint_local(2) << std::endl
0661                   << " cluster local x " << cluster->getLocalX() << " cluster local y " << cluster->getLocalY() << std::endl
0662                   << " cluster global to local x " << loc_check(0) << " local y " << loc_check(1) << "  local z " << loc_check(2) << std::endl
0663                   << " cluster local residual x " << residual(0) << " cluster local residual y " << residual(1) << std::endl;
0664       }
0665 
0666       // need standard deviation of measurements
0667       Acts::Vector2 clus_sigma = getClusterError(cluster, cluskey, global);
0668       if (isnan(clus_sigma(0)) || isnan(clus_sigma(1)))
0669       {
0670         continue;
0671       }
0672 
0673       int glbl_label[AlignmentDefs::NGL];
0674       if (layer < 3)
0675       {
0676         AlignmentDefs::getMvtxGlobalLabels(surf, cluskey, glbl_label, mvtx_grp);
0677       }
0678       else if (layer > 2 && layer < 7)
0679       {
0680         AlignmentDefs::getInttGlobalLabels(surf, cluskey, glbl_label, intt_grp);
0681       }
0682       else if (layer < 55)
0683       {
0684         AlignmentDefs::getTpcGlobalLabels(surf, cluskey, glbl_label, tpc_grp);
0685       }
0686       else
0687       {
0688         continue;
0689       }
0690 
0691       // These derivatives are for the local parameters
0692       float lcl_derivativeX[AlignmentDefs::NLC] = {0., 0., 0., 0., 0.};
0693       float lcl_derivativeY[AlignmentDefs::NLC] = {0., 0., 0., 0., 0.};
0694       if (straight_line_fit)
0695       {
0696         getLocalDerivativesZeroFieldXY(surf, global, fitpars, lcl_derivativeX, lcl_derivativeY, layer);
0697       }
0698       else
0699       {
0700         getLocalDerivativesXY(surf, global, fitpars, lcl_derivativeX, lcl_derivativeY, layer);
0701       }
0702 
0703       // The global derivs dimensions are [alpha/beta/gamma](x/y/z)
0704       float glbl_derivativeX[AlignmentDefs::NGL];
0705       float glbl_derivativeY[AlignmentDefs::NGL];
0706       getGlobalDerivativesXY(surf, global, fitpoint, fitpars, glbl_derivativeX, glbl_derivativeY, layer);
0707 
0708       auto alignmentstate = std::make_unique<SvtxAlignmentState_v1>();
0709       alignmentstate->set_residual(residual);
0710       alignmentstate->set_cluster_key(cluskey);
0711       SvtxAlignmentState::GlobalMatrix svtxglob =
0712           SvtxAlignmentState::GlobalMatrix::Zero();
0713       SvtxAlignmentState::LocalMatrix svtxloc =
0714           SvtxAlignmentState::LocalMatrix::Zero();
0715       for (int i = 0; i < AlignmentDefs::NLC; i++)
0716       {
0717         svtxloc(0, i) = lcl_derivativeX[i];
0718         svtxloc(1, i) = lcl_derivativeY[i];
0719       }
0720       for (int i = 0; i < AlignmentDefs::NGL; i++)
0721       {
0722         svtxglob(0, i) = glbl_derivativeX[i];
0723         svtxglob(1, i) = glbl_derivativeY[i];
0724       }
0725 
0726       alignmentstate->set_local_derivative_matrix(svtxloc);
0727       alignmentstate->set_global_derivative_matrix(svtxglob);
0728 
0729       statevec.push_back(alignmentstate.release());
0730 
0731       for (unsigned int i = 0; i < AlignmentDefs::NGL; ++i)
0732       {
0733         if (trkrid == TrkrDefs::mvtxId)
0734         {
0735           // need stave to get clamshell
0736           auto stave = MvtxDefs::getStaveId(cluskey_vec[ivec]);
0737           auto clamshell = AlignmentDefs::getMvtxClamshell(layer, stave);
0738           if (is_layer_param_fixed(layer, i) || is_mvtx_layer_fixed(layer, clamshell))
0739           {
0740             glbl_derivativeX[i] = 0;
0741             glbl_derivativeY[i] = 0;
0742           }
0743         }
0744 
0745         if (trkrid == TrkrDefs::inttId)
0746         {
0747           if (is_layer_param_fixed(layer, i) || is_intt_layer_fixed(layer))
0748           {
0749             glbl_derivativeX[i] = 0;
0750             glbl_derivativeY[i] = 0;
0751           }
0752         }
0753 
0754         if (trkrid == TrkrDefs::tpcId)
0755         {
0756           unsigned int const sector = TpcDefs::getSectorId(cluskey_vec[ivec]);
0757           unsigned int const side = TpcDefs::getSide(cluskey_vec[ivec]);
0758           if (is_layer_param_fixed(layer, i) || is_tpc_sector_fixed(layer, sector, side))
0759           {
0760             glbl_derivativeX[i] = 0;
0761             glbl_derivativeY[i] = 0;
0762           }
0763         }
0764       }
0765 
0766       // Add the measurement separately for each coordinate direction to Mille
0767       // set the derivatives non-zero only for parameters we want to be optimized
0768       // local parameter numbering is arbitrary:
0769       float errinf = 1.0;
0770 
0771       if (_layerMisalignment.find(layer) != _layerMisalignment.end())
0772       {
0773         errinf = _layerMisalignment.find(layer)->second;
0774       }
0775       if (make_ntuple)
0776       {
0777         // get the local parameters using the ideal transforms
0778         alignmentTransformationContainer::use_alignment = false;
0779         Acts::Vector3 ideal_center = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;
0780         Acts::Vector3 ideal_norm = -surf->normal(_tGeometry->geometry().getGeoContext(),Acts::Vector3(1,1,1), Acts::Vector3(1,1,1));
0781         Acts::Vector3 const ideal_local(xloc, zloc, 0.0);  // cm
0782         Acts::Vector3 ideal_glob = surf->transform(_tGeometry->geometry().getGeoContext()) * (ideal_local * Acts::UnitConstants::cm);
0783         ideal_glob /= Acts::UnitConstants::cm;
0784         alignmentTransformationContainer::use_alignment = true;
0785 
0786         Acts::Vector3 sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // cm
0787         Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1,1,1), Acts::Vector3(1,1,1));
0788         unsigned int sector = TpcDefs::getSectorId(cluskey_vec[ivec]);
0789         unsigned int const side = TpcDefs::getSide(cluskey_vec[ivec]);
0790         unsigned int subsurf = cluster->getSubSurfKey();
0791         if (layer < 3)
0792         {
0793           sector = MvtxDefs::getStaveId(cluskey_vec[ivec]);
0794           subsurf = MvtxDefs::getChipId(cluskey_vec[ivec]);
0795         }
0796         else if (layer > 2 && layer < 7)
0797         {
0798           sector = InttDefs::getLadderPhiId(cluskey_vec[ivec]);
0799           subsurf = InttDefs::getLadderZId(cluskey_vec[ivec]);
0800         }
0801         if (straight_line_fit)
0802         {
0803           float ntp_data[78] = {
0804               (float) event, (float) trackid,
0805               (float) layer, (float) nsilicon, (float) h2h_flag, (float) ntpc, (float) nclus, (float) trkrid, (float) sector, (float) side,
0806               (float) subsurf, phi,
0807               (float) glbl_label[0], (float) glbl_label[1], (float) glbl_label[2], (float) glbl_label[3], (float) glbl_label[4], (float) glbl_label[5],
0808               (float) sensorCenter(0), (float) sensorCenter(1), (float) sensorCenter(2),
0809               (float) sensorNormal(0), (float) sensorNormal(1), (float) sensorNormal(2),
0810               (float) ideal_center(0), (float) ideal_center(1), (float) ideal_center(2),
0811               (float) ideal_norm(0), (float) ideal_norm(1), (float) ideal_norm(2),
0812               (float) ideal_glob(0), (float) ideal_glob(1), (float) ideal_glob(2),
0813               (float) fitpars[0], (float) fitpars[1], (float) fitpars[2], (float) fitpars[3],
0814               (float) global(0), (float) global(1), (float) global(2),
0815               (float) fitpoint(0), (float) fitpoint(1), (float) fitpoint(2),
0816               (float) fitpoint_mvtx_half(0), (float) fitpoint_mvtx_half(1), (float) fitpoint_mvtx_half(2),
0817               (float) tangent.first.x(), (float) tangent.first.y(), (float) tangent.first.z(),
0818               (float) tangent.second.x(), (float) tangent.second.y(), (float) tangent.second.z(),
0819               xloc, zloc, (float) fitpoint_local(0), (float) fitpoint_local(1), (float) fitpoint_mvtx_half_local(0), (float) fitpoint_mvtx_half_local(1),
0820               lcl_derivativeX[0], lcl_derivativeX[1], lcl_derivativeX[2], lcl_derivativeX[3],
0821               glbl_derivativeX[0], glbl_derivativeX[1], glbl_derivativeX[2], glbl_derivativeX[3], glbl_derivativeX[4], glbl_derivativeX[5],
0822               lcl_derivativeY[0], lcl_derivativeY[1], lcl_derivativeY[2], lcl_derivativeY[3],
0823               glbl_derivativeY[0], glbl_derivativeY[1], glbl_derivativeY[2], glbl_derivativeY[3], glbl_derivativeY[4], glbl_derivativeY[5]};
0824 
0825           ntp->Fill(ntp_data);
0826         }
0827         else
0828         {
0829           float ntp_data[75] = {
0830               (float) event, (float) trackid,
0831               (float) layer, (float) nsilicon, (float) ntpc, (float) nclus, (float) trkrid, (float) sector, (float) side,
0832               (float) subsurf, phi,
0833               (float) glbl_label[0], (float) glbl_label[1], (float) glbl_label[2], (float) glbl_label[3], (float) glbl_label[4], (float) glbl_label[5],
0834               (float) sensorCenter(0), (float) sensorCenter(1), (float) sensorCenter(2),
0835               (float) sensorNormal(0), (float) sensorNormal(1), (float) sensorNormal(2),
0836               (float) ideal_center(0), (float) ideal_center(1), (float) ideal_center(2),
0837               (float) ideal_norm(0), (float) ideal_norm(1), (float) ideal_norm(2),
0838               (float) ideal_glob(0), (float) ideal_glob(1), (float) ideal_glob(2),
0839               (float) fitpars[0], (float) fitpars[1], (float) fitpars[2], (float) fitpars[3], (float) fitpars[4],
0840               (float) global(0), (float) global(1), (float) global(2),
0841               (float) fitpoint(0), (float) fitpoint(1), (float) fitpoint(2),
0842               (float) tangent.first.x(), (float) tangent.first.y(), (float) tangent.first.z(),
0843               (float) tangent.second.x(), (float) tangent.second.y(), (float) tangent.second.z(),
0844               xloc, zloc, (float) fitpoint_local(0), (float) fitpoint_local(1),
0845               lcl_derivativeX[0], lcl_derivativeX[1], lcl_derivativeX[2], lcl_derivativeX[3], lcl_derivativeX[4],
0846               glbl_derivativeX[0], glbl_derivativeX[1], glbl_derivativeX[2], glbl_derivativeX[3], glbl_derivativeX[4], glbl_derivativeX[5],
0847               lcl_derivativeY[0], lcl_derivativeY[1], lcl_derivativeY[2], lcl_derivativeY[3], lcl_derivativeY[4],
0848               glbl_derivativeY[0], glbl_derivativeY[1], glbl_derivativeY[2], glbl_derivativeY[3], glbl_derivativeY[4], glbl_derivativeY[5]};
0849 
0850           ntp->Fill(ntp_data);
0851 
0852           if (Verbosity() > 2)
0853           {
0854             for (auto& i : ntp_data)
0855             {
0856               std::cout << i << "  ";
0857             }
0858             std::cout << std::endl;
0859           }
0860         }
0861       }
0862 
0863       if (!isnan(residual(0)) && clus_sigma(0) < 1.0)  // discards crazy clusters
0864       {
0865         if (arr_has_nan(lcl_derivativeX))
0866         {
0867           std::cerr << "lcl_derivativeX is NaN" << std::endl;
0868           continue;
0869         }
0870         if (arr_has_nan(glbl_derivativeX))
0871         {
0872           std::cerr << "glbl_derivativeX is NaN" << std::endl;
0873           continue;
0874         }
0875         _mille->mille(AlignmentDefs::NLC, lcl_derivativeX, AlignmentDefs::NGL, glbl_derivativeX, glbl_label, residual(0), errinf * clus_sigma(0));
0876       }
0877 
0878       if (!isnan(residual(1)) && clus_sigma(1) < 1.0)
0879       {
0880         if (arr_has_nan(lcl_derivativeY))
0881         {
0882           std::cerr << "lcl_derivativeY is NaN" << std::endl;
0883           continue;
0884         }
0885         if (arr_has_nan(glbl_derivativeY))
0886         {
0887           std::cerr << "glbl_derivativeY is NaN" << std::endl;
0888           continue;
0889         }
0890         _mille->mille(AlignmentDefs::NLC, lcl_derivativeY, AlignmentDefs::NGL, glbl_derivativeY, glbl_label, residual(1), errinf * clus_sigma(1));
0891       }
0892     }
0893 
0894     m_alignmentmap->insertWithKey(trackid, statevec);
0895     m_trackmap->insertWithKey(&newTrack, trackid);
0896 
0897     // if cosmics, end here, if collision track, continue with vtx
0898     //   skip the common vertex requirement for this track unless there are 3 tracks in the event
0899     if (accepted_tracks < 3)
0900     {
0901       _mille->end();
0902       continue;
0903     }
0904     // calculate vertex residual with perigee surface
0905     //-------------------------------------------------------
0906 
0907     Acts::Vector3 event_vtx(averageVertex(0), averageVertex(1), averageVertex(2));
0908 
0909     if (m_vertexmap)
0910     {
0911       for (const auto& [vtxkey, vertex] : *m_vertexmap)
0912       {
0913         for (auto trackiter = vertex->begin_tracks(); trackiter != vertex->end_tracks(); ++trackiter)
0914         {
0915           SvtxTrack* vtxtrack = m_trackmap->get(*trackiter);
0916           if (vtxtrack)
0917           {
0918             unsigned int const vtxtrackid = vtxtrack->get_id();
0919             if (trackid == vtxtrackid)
0920             {
0921               event_vtx(0) = vertex->get_x();
0922               event_vtx(1) = vertex->get_y();
0923               event_vtx(2) = vertex->get_z();
0924               if (Verbosity() > 0)
0925               {
0926                 std::cout << "     setting event_vertex for trackid " << trackid << " to vtxid " << vtxkey
0927                           << " vtx " << event_vtx(0) << "  " << event_vtx(1) << "  " << event_vtx(2) << std::endl;
0928               }
0929             }
0930           }
0931         }
0932       }
0933     }
0934 
0935     // The residual for the vtx case is (event vtx - track vtx)
0936     // that is -dca
0937     float dca3dxy = 0;
0938     float dca3dz = 0;
0939     float dca3dxysigma = 0;
0940     float dca3dzsigma = 0;
0941     if (!straight_line_fit)
0942     {
0943       get_dca(newTrack, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma, event_vtx);
0944     }
0945     else
0946     {
0947       get_dca_zero_field(newTrack, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma, event_vtx);
0948     }
0949 
0950     // These are local coordinate residuals in the perigee surface
0951     Acts::Vector2 vtx_residual(-dca3dxy, -dca3dz);
0952 
0953     float lclvtx_derivativeX[AlignmentDefs::NLC];
0954     float lclvtx_derivativeY[AlignmentDefs::NLC];
0955     if (straight_line_fit)
0956     {
0957       getLocalVtxDerivativesZeroFieldXY(newTrack, event_vtx, fitpars, lclvtx_derivativeX, lclvtx_derivativeY);
0958     }
0959     else
0960     {
0961       getLocalVtxDerivativesXY(newTrack, event_vtx, fitpars, lclvtx_derivativeX, lclvtx_derivativeY);
0962     }
0963 
0964     // The global derivs dimensions are [alpha/beta/gamma](x/y/z)
0965     float glblvtx_derivativeX[3];
0966     float glblvtx_derivativeY[3];
0967     getGlobalVtxDerivativesXY(newTrack, event_vtx, glblvtx_derivativeX, glblvtx_derivativeY);
0968 
0969     if (use_event_vertex)
0970     {
0971       for (int p = 0; p < 3; p++)
0972       {
0973         if (is_vertex_param_fixed(p))
0974         {
0975           glblvtx_derivativeX[p] = 0;
0976           glblvtx_derivativeY[p] = 0;
0977         }
0978       }
0979       if (Verbosity() > 1)
0980       {
0981         std::cout << "vertex info for track " << trackid << " with charge " << newTrack.get_charge() << std::endl;
0982 
0983         std::cout << "vertex is " << event_vtx.transpose() << std::endl;
0984         std::cout << "vertex residuals " << vtx_residual.transpose()
0985                   << std::endl;
0986         std::cout << "local derivatives " << std::endl;
0987         for (float const i : lclvtx_derivativeX)
0988         {
0989           std::cout << i << ", ";
0990         }
0991         std::cout << std::endl;
0992         for (float const i : lclvtx_derivativeY)
0993         {
0994           std::cout << i << ", ";
0995         }
0996         std::cout << "global vtx derivaties " << std::endl;
0997         for (float const i : glblvtx_derivativeX)
0998         {
0999           std::cout << i << ", ";
1000         }
1001         std::cout << std::endl;
1002         for (float const i : glblvtx_derivativeY)
1003         {
1004           std::cout << i << ", ";
1005         }
1006       }
1007 
1008       if (!isnan(vtx_residual(0)))
1009       {
1010         if (arr_has_nan(lclvtx_derivativeX))
1011         {
1012           std::cerr << "lclvtx_derivativeX is NaN" << std::endl;
1013           continue;
1014         }
1015         if (arr_has_nan(glblvtx_derivativeX))
1016         {
1017           std::cerr << "glblvtx_derivativeX is NaN" << std::endl;
1018           continue;
1019         }
1020         _mille->mille(AlignmentDefs::NLC, lclvtx_derivativeX, AlignmentDefs::NGLVTX, glblvtx_derivativeX, AlignmentDefs::glbl_vtx_label, vtx_residual(0), vtx_sigma(0));
1021       }
1022       if (!isnan(vtx_residual(1)))
1023       {
1024         if (arr_has_nan(lclvtx_derivativeY))
1025         {
1026           std::cerr << "lclvtx_derivativeY is NaN" << std::endl;
1027           continue;
1028         }
1029         if (arr_has_nan(glblvtx_derivativeY))
1030         {
1031           std::cerr << "glblvtx_derivativeY is NaN" << std::endl;
1032           continue;
1033         }
1034         _mille->mille(AlignmentDefs::NLC, lclvtx_derivativeY, AlignmentDefs::NGLVTX, glblvtx_derivativeY, AlignmentDefs::glbl_vtx_label, vtx_residual(1), vtx_sigma(1));
1035       }
1036     }
1037 
1038     if (make_ntuple)
1039     {
1040       Acts::Vector3 const mom(newTrack.get_px(), newTrack.get_py(), newTrack.get_pz());
1041       Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
1042       float const perigee_phi = atan2(r(1), r(0));
1043       float const track_phi = atan2(newTrack.get_py(), newTrack.get_px());
1044       float const track_eta = atanh(newTrack.get_pz() / newTrack.get_p());
1045       if (straight_line_fit)
1046       {
1047         float ntp_data[28] = {(float) trackid, (float) vtx_residual(0), (float) vtx_residual(1), (float) vtx_sigma(0), (float) vtx_sigma(1),
1048                               lclvtx_derivativeX[0], lclvtx_derivativeX[1], lclvtx_derivativeX[2], lclvtx_derivativeX[3],
1049                               glblvtx_derivativeX[0], glblvtx_derivativeX[1], glblvtx_derivativeX[2],
1050                               lclvtx_derivativeY[0], lclvtx_derivativeY[1], lclvtx_derivativeY[2], lclvtx_derivativeY[3],
1051                               glblvtx_derivativeY[0], glblvtx_derivativeY[1], glblvtx_derivativeY[2],
1052                               newTrack.get_x(), newTrack.get_y(), newTrack.get_z(),
1053                               (float) event_vtx(0), (float) event_vtx(1), (float) event_vtx(2), track_phi, perigee_phi, track_eta};
1054 
1055         track_ntp->Fill(ntp_data);
1056       }
1057       else
1058       {
1059         float ntp_data[29] = {(float) trackid, (float) vtx_residual(0), (float) vtx_residual(1), (float) vtx_sigma(0), (float) vtx_sigma(1),
1060                               lclvtx_derivativeX[0], lclvtx_derivativeX[1], lclvtx_derivativeX[2], lclvtx_derivativeX[3], lclvtx_derivativeX[4],
1061                               glblvtx_derivativeX[0], glblvtx_derivativeX[1], glblvtx_derivativeX[2],
1062                               lclvtx_derivativeY[0], lclvtx_derivativeY[1], lclvtx_derivativeY[2], lclvtx_derivativeY[3], lclvtx_derivativeY[4],
1063                               glblvtx_derivativeY[0], glblvtx_derivativeY[1], glblvtx_derivativeY[2],
1064                               newTrack.get_x(), newTrack.get_y(), newTrack.get_z(),
1065                               (float) event_vtx(0), (float) event_vtx(1), (float) event_vtx(2), track_phi, perigee_phi};
1066 
1067         track_ntp->Fill(ntp_data);
1068       }
1069 
1070     }
1071 
1072     if (Verbosity() > 1)
1073     {
1074       std::cout << "vtx_residual xy: " << vtx_residual(0) << " vtx_residual z: " << vtx_residual(1) << " vtx_sigma xy: " << vtx_sigma(0) << " vtx_sigma z: " << vtx_sigma(1) << std::endl;
1075       std::cout << "track_x " << newTrack.get_x() << "track_y " << newTrack.get_y() << "track_z " << newTrack.get_z() << std::endl;
1076     }
1077     // close out this track
1078     _mille->end();
1079 
1080   }  // end loop over tracks
1081 
1082   return Fun4AllReturnCodes::EVENT_OK;
1083 }
1084 /*
1085 std::make_pair<unsigned int, Acts::Vector3> HelicalFitter::getAverageVertex( std::vector<Acts::Vector3> cumulative_vertex)
1086 {
1087 
1088 
1089 
1090 
1091 }
1092 */
1093 Acts::Vector3 HelicalFitter::get_helix_surface_intersection(const Surface& surf, std::vector<float>& fitpars, Acts::Vector3 global)
1094 {
1095   // we want the point where the helix intersects the plane of the surface
1096   // get the plane of the surface
1097   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // convert to cm
1098   Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1099   sensorNormal /= sensorNormal.norm();
1100 
1101   // there are analytic solutions for a line-plane intersection.
1102   // to use this, need to get the vector tangent to the helix near the measurement and a point on it.
1103   std::pair<Acts::Vector3, Acts::Vector3> const line = get_helix_tangent(fitpars, std::move(global));
1104   Acts::Vector3 const pca = line.first;
1105   Acts::Vector3 const tangent = line.second;
1106 
1107   Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal);
1108 
1109   return intersection;
1110 }
1111 
1112 Acts::Vector3 HelicalFitter::get_line_surface_intersection(const Surface& surf, std::vector<float>& fitpars)
1113 {
1114   // we want the point where the helix intersects the plane of the surface
1115   // get the plane of the surface
1116   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // convert to cm
1117   Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1118   sensorNormal /= sensorNormal.norm();
1119 
1120   /*
1121   // we need the direction of the line
1122 
1123   // consider a point some distance along the straight line.
1124   // Consider a value of x, calculate y, calculate radius, calculate z
1125   double x = 2;
1126   double y = fitpars[0]*x + fitpars[1];
1127   double rxy = sqrt(x*x+y*y);
1128   double z = fitpars[2]*rxy + fitpars[3];
1129   Acts::Vector3 arb_point(x, y, z);
1130 
1131   double x2 = 4;
1132   double y2 = fitpars[0]*x2 + fitpars[1];
1133   double rxy2 = sqrt(x2*x2+y2*y2);
1134   double z2 = fitpars[2]*rxy2 + fitpars[3];
1135   Acts::Vector3 arb_point2(x2, y2, z2);
1136 
1137   Acts::Vector3 tangent = arb_point2 - arb_point;   // direction of line
1138   */
1139   auto line = get_line_zero_field(fitpars);  // do not need the direction
1140 
1141   auto arb_point = line.first;
1142   auto tangent = line.second;
1143 
1144   Acts::Vector3 intersection = get_line_plane_intersection(arb_point, tangent, sensorCenter, sensorNormal);
1145 
1146   return intersection;
1147 }
1148 
1149 Acts::Vector3 HelicalFitter::get_helix_surface_intersection(const Surface& surf, std::vector<float>& fitpars, Acts::Vector3 global, Acts::Vector3& pca, Acts::Vector3& tangent)
1150 {
1151   // we want the point where the helix intersects the plane of the surface
1152 
1153   // get the plane of the surface
1154   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // convert to cm
1155   Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1156   sensorNormal /= sensorNormal.norm();
1157 
1158   // there are analytic solutions for a line-plane intersection.
1159   // to use this, need to get the vector tangent to the helix near the measurement and a point on it.
1160   std::pair<Acts::Vector3, Acts::Vector3> const line = get_helix_tangent(fitpars, std::move(global));
1161   pca = line.first;
1162   tangent = line.second;
1163 
1164   Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal);
1165 
1166   return intersection;
1167 }
1168 
1169 Acts::Vector3 HelicalFitter::get_helix_vtx(Acts::Vector3 event_vtx, const std::vector<float>& fitpars)
1170 {
1171   Acts::Vector2 pca2d = TrackFitUtils::get_circle_point_pca(fitpars[0], fitpars[1], fitpars[2], std::move(event_vtx));
1172   Acts::Vector3 helix_vtx(pca2d(0), pca2d(1), fitpars[4]);
1173 
1174   return helix_vtx;
1175 }
1176 
1177 Acts::Vector3 HelicalFitter::get_line_vtx(Acts::Vector3 event_vtx, const std::vector<float>& fitpars)
1178 {
1179   Acts::Vector2 pca2d = TrackFitUtils::get_line_point_pca(fitpars[0], fitpars[1], std::move(event_vtx));
1180   Acts::Vector3 line_vtx(pca2d(0), pca2d(1), fitpars[3]);
1181 
1182   return line_vtx;
1183 }
1184 
1185 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_line_tangent(const std::vector<float>& fitpars, Acts::Vector3 global)
1186 {
1187   // returns the equation of the line, with the direction obtained from the global cluster point
1188 
1189   // Get the rough direction of the line from the global vector, which is a point on the line
1190   float const phi = atan2(global(1), global(0));
1191 
1192   // we need the direction of the line
1193   // consider a point some distance along the straight line.
1194   // Consider a value of x, calculate y, calculate radius, calculate z
1195   double const x = 0;
1196   double const y = fitpars[0] * x + fitpars[1];
1197   //  double rxy = sqrt(x*x+y*y);
1198   double const z = fitpars[2] * x + fitpars[3];
1199   Acts::Vector3 arb_point(x, y, z);
1200 
1201   double const x2 = 1;
1202   double const y2 = fitpars[0] * x2 + fitpars[1];
1203   double const z2 = fitpars[2] * x2 + fitpars[3];
1204   Acts::Vector3 const arb_point2(x2, y2, z2);
1205 
1206   float const arb_phi = atan2(arb_point(1), arb_point(0));
1207   Acts::Vector3 tangent = arb_point2 - arb_point;  // direction of line
1208   if (std::abs(arb_phi - phi) > M_PI / 2)
1209   {
1210     tangent = arb_point - arb_point2;  // direction of line
1211   }
1212 
1213   tangent /= tangent.norm();
1214 
1215   std::pair<Acts::Vector3, Acts::Vector3> line = std::make_pair(arb_point, tangent);
1216 
1217   return line;
1218 }
1219 
1220 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_line_zero_field(const std::vector<float>& fitpars)
1221 {
1222   // Returns the line equation, but without the direction of the track
1223   // consider a point some distance along the straight line.
1224   // Consider a value of x, calculate y, calculate z
1225   double const x = 0;
1226   double const y = fitpars[0] * x + fitpars[1];
1227   double const z = fitpars[2] * x + fitpars[3];
1228   Acts::Vector3 const arb_point(x, y, z);
1229 
1230   double const x2 = 1;
1231   double const y2 = fitpars[0] * x2 + fitpars[1];
1232   double const z2 = fitpars[2] * x2 + fitpars[3];
1233   Acts::Vector3 const arb_point2(x2, y2, z2);
1234 
1235   Acts::Vector3 tangent = arb_point2 - arb_point;  // +/- times direction of line
1236   tangent /= tangent.norm();
1237 
1238   std::pair<Acts::Vector3, Acts::Vector3> line = std::make_pair(arb_point, tangent);
1239 
1240   return line;
1241 }
1242 
1243 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_line(const std::vector<float>& fitpars)
1244 {
1245   // we need the direction of the line
1246   // consider a point some distance along the straight line.
1247   // Consider a value of x, calculate y, calculate radius, calculate z
1248   double const x = 0.0;
1249   double const y = fitpars[0] * x + fitpars[1];
1250   double const rxy = sqrt(x * x + y * y);
1251   double const z = fitpars[2] * rxy + fitpars[3];
1252   Acts::Vector3 const arb_point(x, y, z);
1253 
1254   double const x2 = 1;
1255   double const y2 = fitpars[0] * x2 + fitpars[1];
1256   double const rxy2 = sqrt(x2 * x2 + y2 * y2);
1257   double const z2 = fitpars[2] * rxy2 + fitpars[3];
1258   Acts::Vector3 const arb_point2(x2, y2, z2);
1259 
1260   Acts::Vector3 tangent = arb_point2 - arb_point;  // direction of line
1261   tangent /= tangent.norm();
1262 
1263   std::pair<Acts::Vector3, Acts::Vector3> line = std::make_pair(arb_point, tangent);
1264 
1265   return line;
1266 }
1267 
1268 Acts::Vector3 HelicalFitter::get_line_plane_intersection(const Acts::Vector3& PCA, const Acts::Vector3& tangent, const Acts::Vector3& sensor_center, const Acts::Vector3& sensor_normal)
1269 {
1270   // get the intersection of the line made by PCA and tangent with the plane of the sensor
1271 
1272   // For a point on the line:      p = PCA + d * tangent;
1273   // for a point on the plane:  (p - sensor_center).sensor_normal = 0
1274 
1275   // The solution is:
1276   float const d = (sensor_center - PCA).dot(sensor_normal) / tangent.dot(sensor_normal);
1277   Acts::Vector3 intersection = PCA + d * tangent;
1278 
1279   /*
1280   std::cout << "    sensor center " << sensor_center(0) << "  " << sensor_center(1) << "  " << sensor_center(2) << std::endl;
1281   std::cout << "      intersection " << intersection(0) << "  " << intersection(1) << "  " << intersection(2) << std::endl;
1282   std::cout << "      PCA " << PCA(0) << "  " << PCA(1) << "  " << PCA(2) << std::endl;
1283   std::cout << "      tangent " << tangent(0) << "  " << tangent(1) << "  " << tangent(2) << std::endl;
1284   std::cout << "            d " << d << std::endl;
1285   */
1286 
1287   return intersection;
1288 }
1289 
1290 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_helix_tangent(const std::vector<float>& fitpars, Acts::Vector3 global)
1291 {
1292   auto pair = TrackFitUtils::get_helix_tangent(fitpars, global);
1293   /*
1294     save for posterity purposes
1295   if(Verbosity() > 2)
1296     {
1297       // different method for checking:
1298       // project the circle PCA vector an additional small amount and find the helix PCA to that point
1299 
1300       float projection = 0.25;  // cm
1301       Acts::Vector3 second_point = pca + projection * pca/pca.norm();
1302       Acts::Vector2 second_point_pca_circle = TrackFitUtils::get_circle_point_pca(radius, x0, y0, second_point);
1303       float second_point_pca_z = second_point_pca_circle.norm() * zslope + z0;
1304       Acts::Vector3 second_point_pca2(second_point_pca_circle(0), second_point_pca_circle(1), second_point_pca_z);
1305       Acts::Vector3 tangent2 = (second_point_pca2 - pca) /  (second_point_pca2 - pca).norm();
1306       Acts::Vector3 final_pca2 = getPCALinePoint(global, tangent2, pca);
1307 
1308       std::cout << " get_helix_tangent: getting tangent at angle_pca: " << angle_pca * 180.0 / M_PI << std::endl
1309                 << " original first point pca                      " << pca(0) << "  " << pca(1) << "  " << pca(2) << std::endl
1310                 << " original second point pca  " << second_point_pca(0) << "  " << second_point_pca(1) << "  " << second_point_pca(2) << std::endl
1311                 << " original tangent " << tangent(0) << "  " << tangent(1) << "  " << tangent(2) << std::endl
1312                 << " original final pca from line " << final_pca(0) << "  " << final_pca(1) << "  " << final_pca(2) << std::endl;
1313 
1314       if(Verbosity() > 3)
1315         {
1316           std::cout  << "    Check: 2nd point pca meth 2 "<< second_point_pca2(0)<< "  "<< second_point_pca2(1) << "  "<< second_point_pca2(2) << std::endl
1317                         << "    check tangent " << tangent2(0) << "  " << tangent2(1) << "  " << tangent2(2) << std::endl
1318                         << "    check final pca from line " << final_pca2(0) << "  " << final_pca2(1) << "  " << final_pca2(2)
1319                         << std::endl;
1320         }
1321 
1322     }
1323   */
1324 
1325   return pair;
1326 }
1327 
1328 int HelicalFitter::End(PHCompositeNode* /*unused*/)
1329 {
1330   // closes output file in destructor
1331   delete _mille;
1332 
1333   if (make_ntuple)
1334   {
1335     fout->Write();
1336     fout->Close();
1337   }
1338 
1339   return Fun4AllReturnCodes::EVENT_OK;
1340 }
1341 int HelicalFitter::CreateNodes(PHCompositeNode* topNode)
1342 {
1343   PHNodeIterator iter(topNode);
1344 
1345   PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
1346 
1347   if (!dstNode)
1348   {
1349     std::cerr << "DST node is missing, quitting" << std::endl;
1350     throw std::runtime_error("Failed to find DST node in PHActsTrkFitter::createNodes");
1351   }
1352 
1353   PHNodeIterator dstIter(topNode);
1354   PHCompositeNode* svtxNode = dynamic_cast<PHCompositeNode*>(dstIter.findFirst("PHCompositeNode", "SVTX"));
1355   if (!svtxNode)
1356   {
1357     svtxNode = new PHCompositeNode("SVTX");
1358     dstNode->addNode(svtxNode);
1359   }
1360 
1361   m_trackmap = findNode::getClass<SvtxTrackMap>(topNode, "HelicalFitterTrackMap");
1362   if (!m_trackmap)
1363   {
1364     m_trackmap = new SvtxTrackMap_v2;
1365     PHIODataNode<PHObject>* node = new PHIODataNode<PHObject>(m_trackmap, "HelicalFitterTrackMap", "PHObject");
1366     svtxNode->addNode(node);
1367   }
1368 
1369   m_alignmentmap = findNode::getClass<SvtxAlignmentStateMap>(topNode, "HelicalFitterAlignmentStateMap");
1370   if (!m_alignmentmap)
1371   {
1372     m_alignmentmap = new SvtxAlignmentStateMap_v1;
1373     PHIODataNode<PHObject>* node = new PHIODataNode<PHObject>(m_alignmentmap, "HelicalFitterAlignmentStateMap", "PHObject");
1374     svtxNode->addNode(node);
1375   }
1376 
1377   return Fun4AllReturnCodes::EVENT_OK;
1378 }
1379 int HelicalFitter::GetNodes(PHCompositeNode* topNode)
1380 {
1381   //---------------------------------
1382   // Get additional objects off the Node Tree
1383   //---------------------------------
1384 
1385   _track_map_silicon = findNode::getClass<TrackSeedContainer>(topNode, _silicon_track_map_name);
1386   if (!_track_map_silicon && (fitsilicon || fitfulltrack))
1387   {
1388     cerr << PHWHERE << " ERROR: Can't find SiliconTrackSeedContainer " << endl;
1389     return Fun4AllReturnCodes::ABORTEVENT;
1390   }
1391 
1392   _track_map_tpc = findNode::getClass<TrackSeedContainer>(topNode, _track_map_name);
1393   if (!_track_map_tpc && (fittpc || fitfulltrack))
1394   {
1395     cerr << PHWHERE << " ERROR: Can't find " << _track_map_name.c_str() << endl;
1396     return Fun4AllReturnCodes::ABORTEVENT;
1397   }
1398 
1399   _cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
1400   if (!_cluster_map)
1401   {
1402     std::cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl;
1403     return Fun4AllReturnCodes::ABORTEVENT;
1404   }
1405 
1406   _tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
1407   if (!_tGeometry)
1408   {
1409     std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl;
1410     return Fun4AllReturnCodes::ABORTEVENT;
1411   }
1412 
1413   m_vertexmap = findNode::getClass<SvtxVertexMap>(topNode, "SvtxVertexMap");
1414   if (!m_vertexmap)
1415   {
1416     std::cout << PHWHERE << " ERROR: Can't find node SvtxVertexMap" << std::endl;
1417     // return Fun4AllReturnCodes::ABORTEVENT;
1418   }
1419 
1420   // global position wrapper
1421   m_globalPositionWrapper.loadNodes(topNode);
1422 
1423   return Fun4AllReturnCodes::EVENT_OK;
1424 }
1425 
1426 Acts::Vector3 HelicalFitter::get_helix_pca(std::vector<float>& fitpars, const Acts::Vector3& global)
1427 {
1428   return TrackFitUtils::get_helix_pca(fitpars, global);
1429 }
1430 
1431 Acts::Vector3 HelicalFitter::getPCALinePoint(const Acts::Vector3& global, const Acts::Vector3& tangent, const Acts::Vector3& posref)
1432 {
1433   // Approximate track with a straight line consisting of the state position posref and the vector (px,py,pz)
1434 
1435   // The position of the closest point on the line to global is:
1436   // posref + projection of difference between the point and posref on the tangent vector
1437   Acts::Vector3 pca = posref + ((global - posref).dot(tangent)) * tangent;
1438 
1439   return pca;
1440 }
1441 
1442 float HelicalFitter::convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster* cluster)
1443 {
1444   // must convert local Y from cluster average time of arival to local cluster z position
1445   double const drift_velocity = _tGeometry->get_drift_velocity();
1446   double const zdriftlength = cluster->getLocalY() * drift_velocity;
1447   double const surfCenterZ = 52.89;          // 52.89 is where G4 thinks the surface center is
1448   double zloc = surfCenterZ - zdriftlength;  // converts z drift length to local z position in the TPC in north
1449   unsigned int const side = TpcDefs::getSide(cluster_key);
1450   if (side == 0)
1451   {
1452     zloc = -zloc;
1453   }
1454   float const z = zloc;  // in cm
1455 
1456   return z;
1457 }
1458 
1459 void HelicalFitter::makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global)
1460 {
1461   // make all corrections to global position of TPC cluster
1462   unsigned int const side = TpcDefs::getSide(cluster_key);
1463   global.z() = m_clusterCrossingCorrection.correctZ(global.z(), side, crossing);
1464 
1465   // apply distortion corrections
1466   global = m_globalPositionWrapper.applyDistortionCorrections(global);
1467 }
1468 
1469 void HelicalFitter::getTrackletClusters(TrackSeed* tracklet, std::vector<Acts::Vector3>& global_vec, std::vector<TrkrDefs::cluskey>& cluskey_vec)
1470 {
1471   getTrackletClusterList(tracklet, cluskey_vec);
1472   // store cluster global positions in a vector
1473   TrackFitUtils::getTrackletClusters(_tGeometry, _cluster_map, global_vec, cluskey_vec);
1474 }
1475 
1476 void HelicalFitter::getTrackletClusterList(TrackSeed* tracklet, std::vector<TrkrDefs::cluskey>& cluskey_vec)
1477 {
1478   for (auto clusIter = tracklet->begin_cluster_keys();
1479        clusIter != tracklet->end_cluster_keys();
1480        ++clusIter)
1481   {
1482     auto key = *clusIter;
1483     auto cluster = _cluster_map->findCluster(key);
1484     if (!cluster)
1485     {
1486       std::cout << PHWHERE << "Failed to get cluster with key " << key << std::endl;
1487       continue;
1488     }
1489 
1490     /// Make a safety check for clusters that couldn't be attached to a surface
1491     auto surf = _tGeometry->maps().getSurface(key, cluster);
1492     if (!surf)
1493     {
1494       continue;
1495     }
1496 
1497     // drop some bad layers in the TPC completely
1498     unsigned int const layer = TrkrDefs::getLayer(key);
1499     if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39)
1500     {
1501       continue;
1502     }
1503 
1504     // drop INTT clusters for now  -- TEMPORARY!
1505     // if (layer > 2 && layer < 7)
1506     //{
1507     //  continue;
1508     //}
1509 
1510     cluskey_vec.push_back(key);
1511 
1512   }  // end loop over clusters for this track
1513 }
1514 
1515 std::vector<float> HelicalFitter::fitClusters(std::vector<Acts::Vector3>& global_vec, std::vector<TrkrDefs::cluskey> cluskey_vec)
1516 {
1517   return TrackFitUtils::fitClusters(global_vec, std::move(cluskey_vec), use_intt_zfit);  // do helical fit
1518 }
1519 
1520 Acts::Vector2 HelicalFitter::getClusterError(TrkrCluster* cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global)
1521 {
1522   Acts::Vector2 clus_sigma(0, 0);
1523 
1524   double const clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]);
1525   auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey);
1526   double const phierror = sqrt(para_errors.first);
1527   double const zerror = sqrt(para_errors.second);
1528   clus_sigma(1) = zerror;
1529   clus_sigma(0) = phierror;
1530 
1531   return clus_sigma;
1532 }
1533 
1534 // new one
1535 void HelicalFitter::getLocalDerivativesXY(const Surface& surf, const Acts::Vector3& global, const std::vector<float>& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer)
1536 {
1537   // Calculate the derivatives of the residual wrt the track parameters numerically
1538   std::vector<float> temp_fitpars;
1539 
1540   std::vector<float> fitpars_delta;
1541   fitpars_delta.push_back(0.1);  // radius, cm
1542   fitpars_delta.push_back(0.1);  // X0, cm
1543   fitpars_delta.push_back(0.1);  // Y0, cm
1544   fitpars_delta.push_back(0.1);  // zslope, cm
1545   fitpars_delta.push_back(0.1);  // Z0, cm
1546 
1547   temp_fitpars.reserve(fitpars.size());
1548   for (float const fitpar : fitpars)
1549   {
1550     temp_fitpars.push_back(fitpar);
1551   }
1552 
1553   // calculate projX and projY vectors once for the optimum fit parameters
1554   if (Verbosity() > 1)
1555   {
1556     std::cout << "Call get_helix_tangent for best fit fitpars" << std::endl;
1557   }
1558   std::pair<Acts::Vector3, Acts::Vector3> const tangent = get_helix_tangent(fitpars, global);
1559 
1560   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1561   get_projectionXY(surf, tangent, projX, projY);
1562 
1563   Acts::Vector3 const intersection = get_helix_surface_intersection(surf, temp_fitpars, global);
1564 
1565   // loop over the track fit parameters
1566   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1567   {
1568     Acts::Vector3 intersection_delta[2];
1569     for (int ipm = 0; ipm < 2; ++ipm)
1570     {
1571       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1572       float const deltapm = pow(-1.0, ipm);
1573       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1574 
1575       Acts::Vector3 const temp_intersection = get_helix_surface_intersection(surf, temp_fitpars, global);
1576       intersection_delta[ipm] = temp_intersection - intersection;
1577     }
1578     Acts::Vector3 average_intersection_delta = (intersection_delta[0] - intersection_delta[1]) / (2 * fitpars_delta[ip]);
1579 
1580     if (Verbosity() > 1)
1581     {
1582       std::cout << " average_intersection_delta / delta " << average_intersection_delta(0) << "  " << average_intersection_delta(1) << "  " << average_intersection_delta(2) << std::endl;
1583     }
1584 
1585     // calculate the change in fit for X and Y
1586     // - note negative sign from ATLAS paper is dropped here because mille wants the derivative of the fit, not the derivative of the residual
1587     lcl_derivativeX[ip] = average_intersection_delta.dot(projX);
1588     lcl_derivativeY[ip] = average_intersection_delta.dot(projY);
1589     if (Verbosity() > 1)
1590     {
1591       std::cout << " layer " << layer << " ip " << ip << "  derivativeX " << lcl_derivativeX[ip] << "  "
1592                 << " derivativeY " << lcl_derivativeY[ip] << std::endl;
1593     }
1594 
1595     temp_fitpars[ip] = fitpars[ip];
1596   }
1597 }
1598 
1599 void HelicalFitter::getLocalDerivativesZeroFieldXY(const Surface& surf, const Acts::Vector3& global, const std::vector<float>& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5], unsigned int layer)
1600 {
1601   // Calculate the derivatives of the residual wrt the track parameters numerically
1602   // This version differs from the field on one in that:
1603   // Fitpars has parameters of a straight line (4) instead of a helix (5)
1604   // The track tangent is just the line direction
1605 
1606   std::vector<float> temp_fitpars;
1607 
1608   std::vector<float> fitpars_delta;
1609   fitpars_delta.push_back(0.1);  // xyslope, cm
1610   fitpars_delta.push_back(0.1);  // y0, cm
1611   fitpars_delta.push_back(0.1);  // zslope, cm
1612   fitpars_delta.push_back(0.1);  // Z0, cm
1613 
1614   temp_fitpars.reserve(fitpars.size());
1615   for (float const fitpar : fitpars)
1616   {
1617     temp_fitpars.push_back(fitpar);
1618   }
1619 
1620   // calculate projX and projY vectors once for the optimum fit parameters
1621   if (Verbosity() > 1)
1622   {
1623     std::cout << "Call get_line to get tangent for ZF fitpars" << std::endl;
1624   }
1625 
1626   std::pair<Acts::Vector3, Acts::Vector3> const tangent = get_line_tangent(fitpars, global);
1627 
1628   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1629   get_projectionXY(surf, tangent, projX, projY);
1630 
1631   Acts::Vector3 const intersection = get_line_surface_intersection(surf, temp_fitpars);
1632 
1633   // loop over the track fit parameters
1634   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1635   {
1636     Acts::Vector3 intersection_delta[2];
1637     for (int ipm = 0; ipm < 2; ++ipm)
1638     {
1639       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1640       float const deltapm = pow(-1.0, ipm);
1641       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1642 
1643       Acts::Vector3 const temp_intersection = get_line_surface_intersection(surf, temp_fitpars);
1644       intersection_delta[ipm] = temp_intersection - intersection;
1645     }
1646     Acts::Vector3 average_intersection_delta = (intersection_delta[0] - intersection_delta[1]) / (2 * fitpars_delta[ip]);
1647 
1648     if (Verbosity() > 1)
1649     {
1650       std::cout << " average_intersection_delta / delta " << average_intersection_delta(0) << "  " << average_intersection_delta(1) << "  " << average_intersection_delta(2) << std::endl;
1651     }
1652 
1653     // calculate the change in fit for X and Y
1654     // - note negative sign from ATLAS paper is dropped here because mille wants the derivative of the fit, not the derivative of the residual
1655     lcl_derivativeX[ip] = average_intersection_delta.dot(projX);
1656     lcl_derivativeY[ip] = average_intersection_delta.dot(projY);
1657     if (Verbosity() > 1)
1658     {
1659       std::cout << " layer " << layer << " ip " << ip << "  derivativeX " << lcl_derivativeX[ip] << "  "
1660                 << " derivativeY " << lcl_derivativeY[ip] << std::endl;
1661     }
1662 
1663     temp_fitpars[ip] = fitpars[ip];
1664   }
1665 }
1666 
1667 void HelicalFitter::getLocalVtxDerivativesXY(SvtxTrack& track, const Acts::Vector3& event_vtx, const std::vector<float>& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5])
1668 {
1669   // Calculate the derivatives of the residual wrt the track parameters numerically
1670   std::vector<float> temp_fitpars;
1671   Acts::Vector3 const track_vtx(track.get_x(), track.get_y(), track.get_z());
1672 
1673   std::vector<float> fitpars_delta;
1674   fitpars_delta.push_back(0.1);  // radius, cm
1675   fitpars_delta.push_back(0.1);  // X0, cm
1676   fitpars_delta.push_back(0.1);  // Y0, cm
1677   fitpars_delta.push_back(0.1);  // zslope, cm
1678   fitpars_delta.push_back(0.1);  // Z0, cm
1679 
1680   temp_fitpars.reserve(fitpars.size());
1681   for (float const fitpar : fitpars)
1682   {
1683     temp_fitpars.push_back(fitpar);
1684   }
1685 
1686   // calculate projX and projY vectors once for the optimum fit parameters
1687   if (Verbosity() > 1)
1688   {
1689     std::cout << "Get tangent from track momentum vector" << std::endl;
1690   }
1691 
1692   Acts::Vector3 const perigeeNormal(track.get_px(), track.get_py(), track.get_pz());
1693 
1694   // loop over the track fit parameters
1695   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1696   {
1697     Acts::Vector3 localPerturb[2];
1698     Acts::Vector3 paperPerturb[2];  // for local derivative calculation like from the paper
1699 
1700     for (int ipm = 0; ipm < 2; ++ipm)
1701     {
1702       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1703       float const deltapm = pow(-1.0, ipm);
1704       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1705 
1706       Acts::Vector3 const temp_track_vtx = get_helix_vtx(event_vtx, temp_fitpars);  // temporary pca
1707       paperPerturb[ipm] = temp_track_vtx;                                           // for og local derivative calculation
1708 
1709       // old method is next two lines
1710       Acts::Vector3 const localtemp_track_vtx = globalvtxToLocalvtx(track, event_vtx, temp_track_vtx);
1711       localPerturb[ipm] = localtemp_track_vtx;
1712 
1713       if (Verbosity() > 1)
1714       {
1715         std::cout << "vtx local parameter " << ip << " with ipm " << ipm << " deltapm " << deltapm << " :" << std::endl;
1716         std::cout << " fitpars " << fitpars[ip] << " temp_fitpars " << temp_fitpars[ip] << std::endl;
1717         std::cout << " localtmp_track_vtx: " << localtemp_track_vtx << std::endl;
1718       }
1719     }
1720 
1721     Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1722     get_projectionVtxXY(track, event_vtx, projX, projY);
1723 
1724     Acts::Vector3 const average_vtxX = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1725     Acts::Vector3 const average_vtxY = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1726 
1727     // average_vtxX and average_vtxY are the numerical results in global coords for d(fit)/d(par)
1728     // The ATLAS paper formula is for the derivative of the residual, which is (measurement - fit = event vertex - track vertex)
1729     // Millepede wants the derivative of the fit, so we drop the minus sign from the paper
1730     lcl_derivativeX[ip] = average_vtxX.dot(projX);  //
1731     lcl_derivativeY[ip] = average_vtxY.dot(projY);
1732 
1733     temp_fitpars[ip] = fitpars[ip];
1734   }
1735 }
1736 
1737 void HelicalFitter::getLocalVtxDerivativesZeroFieldXY(SvtxTrack& track, const Acts::Vector3& event_vtx, const std::vector<float>& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5])
1738 {
1739   // Calculate the derivatives of the residual wrt the track parameters numerically
1740   std::vector<float> temp_fitpars;
1741   Acts::Vector3 const track_vtx(track.get_x(), track.get_y(), track.get_z());
1742 
1743   std::vector<float> fitpars_delta;
1744   fitpars_delta.push_back(0.1);  // xyslope, cm
1745   fitpars_delta.push_back(0.1);  // y0, cm
1746   fitpars_delta.push_back(0.1);  // zslope, cm
1747   fitpars_delta.push_back(0.1);  // Z0, cm
1748 
1749   temp_fitpars.reserve(fitpars.size());
1750   for (float const fitpar : fitpars)
1751   {
1752     temp_fitpars.push_back(fitpar);
1753   }
1754 
1755   Acts::Vector3 const perigeeNormal(track.get_px(), track.get_py(), track.get_pz());
1756 
1757   // loop over the track fit parameters
1758   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1759   {
1760     Acts::Vector3 localPerturb[2];
1761     Acts::Vector3 paperPerturb[2];  // for local derivative calculation like from the paper
1762 
1763     for (int ipm = 0; ipm < 2; ++ipm)
1764     {
1765       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1766       float const deltapm = pow(-1.0, ipm);
1767       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1768 
1769       Acts::Vector3 const temp_track_vtx = get_line_vtx(event_vtx, temp_fitpars);  // temporary pca
1770       paperPerturb[ipm] = temp_track_vtx;                                          // for og local derivative calculation
1771 
1772       // old method is next two lines
1773       Acts::Vector3 const localtemp_track_vtx = globalvtxToLocalvtx(track, event_vtx, temp_track_vtx);
1774       localPerturb[ipm] = localtemp_track_vtx;
1775 
1776       if (Verbosity() > 1)
1777       {
1778         std::cout << "vtx local parameter " << ip << " with ipm " << ipm << " deltapm " << deltapm << " :" << std::endl;
1779         std::cout << " fitpars " << fitpars[ip] << " temp_fitpars " << temp_fitpars[ip] << std::endl;
1780         std::cout << " localtmp_track_vtx: " << localtemp_track_vtx << std::endl;
1781       }
1782     }
1783 
1784     // calculate projX and projY vectors once for the optimum fit parameters
1785     Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1786     get_projectionVtxXY(track, event_vtx, projX, projY);
1787 
1788     Acts::Vector3 const average_vtxX = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1789     Acts::Vector3 const average_vtxY = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1790 
1791     // average_vtxX and average_vtxY are the numerical results in global coords for d(fit)/d(par)
1792     // The ATLAS paper formula is for the derivative of the residual, which is (measurement - fit = event vertex - track vertex)
1793     // Millepede wants the derivative of the fit, so we drop the minus sign from the paper
1794     lcl_derivativeX[ip] = average_vtxX.dot(projX);  //
1795     lcl_derivativeY[ip] = average_vtxY.dot(projY);
1796 
1797     temp_fitpars[ip] = fitpars[ip];
1798   }
1799 }
1800 
1801 void HelicalFitter::getGlobalDerivativesXY(const Surface& surf, const Acts::Vector3& global, const Acts::Vector3& fitpoint, const std::vector<float>& fitpars, float glbl_derivativeX[6], float glbl_derivativeY[6], unsigned int layer)
1802 {
1803   // calculate projX and projY vectors once for the optimum fit parameters
1804   std::pair<Acts::Vector3, Acts::Vector3> tangent;
1805   if (straight_line_fit)
1806   {
1807     tangent = get_line_tangent(fitpars, global);
1808   }
1809   else
1810   {
1811     tangent = get_helix_tangent(fitpars, global);
1812   }
1813 
1814   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1815   get_projectionXY(surf, tangent, projX, projY);
1816 
1817   /*
1818   // translations in polar coordinates, unit vectors must be in polar coordinates
1819   //   -- There is an implicit assumption here that unitrphi is a length
1820   // unit vector in r is the normalized radial vector pointing to the surface center
1821 
1822   Acts::Vector3 center = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;
1823   Acts::Vector3 unitr( center(0), center(1), 0.0);
1824   unitr /= unitr.norm();
1825   float phi = atan2(center(1), center(0));
1826   Acts::Vector3 unitrphi(-sin(phi), cos(phi), 0.0);  // unit vector phi in polar coordinates
1827   Acts::Vector3 unitz(0, 0, 1);
1828 
1829   glbl_derivativeX[3] = unitr.dot(projX);
1830   glbl_derivativeX[4] = unitrphi.dot(projX);
1831   glbl_derivativeX[5] = unitz.dot(projX);
1832 
1833   glbl_derivativeY[3] = unitr.dot(projY);
1834   glbl_derivativeY[4] = unitrphi.dot(projY);
1835   glbl_derivativeY[5] = unitz.dot(projY);
1836   */
1837 
1838   // translations in cartesian coordinates
1839   // Unit vectors in the global cartesian frame
1840   Acts::Vector3 const unitx(1, 0, 0);
1841   Acts::Vector3 const unity(0, 1, 0);
1842   Acts::Vector3 const unitz(0, 0, 1);
1843 
1844   glbl_derivativeX[3] = unitx.dot(projX);
1845   glbl_derivativeX[4] = unity.dot(projX);
1846   glbl_derivativeX[5] = unitz.dot(projX);
1847 
1848   glbl_derivativeY[3] = unitx.dot(projY);
1849   glbl_derivativeY[4] = unity.dot(projY);
1850   glbl_derivativeY[5] = unitz.dot(projY);
1851 
1852   /*
1853   // note: the global derivative sign should be reversed from the ATLAS paper
1854   // because mille wants the derivative of the fit, while the ATLAS paper gives the derivative of the residual.
1855   // But this sign reversal does NOT work.
1856   // Verified that not reversing the sign here produces the correct sign of the prediction of the residual..
1857   for(unsigned int i = 3; i < 6; ++i)
1858   {
1859   glbl_derivativeX[i] *= -1.0;
1860   glbl_derivativeY[i] *= -1.0;
1861   }
1862   */
1863   // rotations
1864   // need center of sensor to intersection point
1865   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;  // convert to cm
1866   Acts::Vector3 const OM = fitpoint - sensorCenter;                                                                   // this effectively reverses the sign from the ATLAS paper
1867 
1868   /*
1869   glbl_derivativeX[0] = (unitr.cross(OM)).dot(projX);
1870   glbl_derivativeX[1] = (unitrphi.cross(OM)).dot(projX);
1871   glbl_derivativeX[2] = (unitz.cross(OM)).dot(projX);
1872 
1873   glbl_derivativeY[0] = (unitr.cross(OM)).dot(projY);
1874   glbl_derivativeY[1] = (unitrphi.cross(OM)).dot(projY);
1875   glbl_derivativeY[2] = (unitz.cross(OM)).dot(projY);
1876   */
1877 
1878   glbl_derivativeX[0] = (unitx.cross(OM)).dot(projX);
1879   glbl_derivativeX[1] = (unity.cross(OM)).dot(projX);
1880   glbl_derivativeX[2] = (unitz.cross(OM)).dot(projX);
1881 
1882   glbl_derivativeY[0] = (unitx.cross(OM)).dot(projY);
1883   glbl_derivativeY[1] = (unity.cross(OM)).dot(projY);
1884   glbl_derivativeY[2] = (unitz.cross(OM)).dot(projY);
1885 
1886   if (Verbosity() > 1)
1887   {
1888     for (int ip = 0; ip < 6; ++ip)
1889     {
1890       std::cout << " layer " << layer << " ip " << ip
1891                 << "  glbl_derivativeX " << glbl_derivativeX[ip] << "  "
1892                 << " glbl_derivativeY " << glbl_derivativeY[ip] << std::endl;
1893     }
1894   }
1895 
1896   /*
1897   if(Verbosity() > 2)
1898     {
1899       std::cout << "    unitr mag: " << unitr.norm() << " unitr: " << std::endl << unitr << std::endl;
1900       std::cout << "    unitrphi mag: " << unitrphi.norm() << " unitrphi: " << std::endl << unitrphi << std::endl;
1901       std::cout << "    unitz mag: " << unitz.norm() << " unitz: " << std::endl << unitz << std::endl;
1902       std::cout << "    projX: " << std::endl << projX << std::endl;
1903       std::cout << "    projY: " << std::endl << projY << std::endl;
1904     }
1905   */
1906 }
1907 
1908 void HelicalFitter::getGlobalVtxDerivativesXY(SvtxTrack& track, const Acts::Vector3& event_vtx, float glbl_derivativeX[3], float glbl_derivativeY[3])
1909 {
1910   Acts::Vector3 const unitx(1, 0, 0);
1911   Acts::Vector3 const unity(0, 1, 0);
1912   Acts::Vector3 const unitz(0, 0, 1);
1913 
1914   Acts::Vector3 const track_vtx(track.get_x(), track.get_y(), track.get_z());
1915   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
1916 
1917   // calculate projX and projY vectors once for the optimum fit parameters
1918   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1919   get_projectionVtxXY(track, event_vtx, projX, projY);
1920 
1921   // translations
1922   glbl_derivativeX[0] = unitx.dot(projX);
1923   glbl_derivativeX[1] = unity.dot(projX);
1924   glbl_derivativeX[2] = unitz.dot(projX);
1925   glbl_derivativeY[0] = unitx.dot(projY);
1926   glbl_derivativeY[1] = unity.dot(projY);
1927   glbl_derivativeY[2] = unitz.dot(projY);
1928 
1929   // The derivation in the ATLAS paper used above gives the derivative of the residual (= measurement - fit)
1930   // pede wants the derivative of the fit, so we reverse that - valid if our residual is (event vertex - track vertex)
1931 
1932   // Verified that reversing these signs produces the correct sign and magnitude for the prediction of the residual.
1933   // tested this by offsetting the simulated event vertex with zero misalignments. Pede fit reproduced simulated (xvtx, yvtx) within 7%.
1934   //   -- test gave zero for zvtx param, since this is determined relative to the measured event z vertex.
1935   for (int i = 0; i < 3; ++i)
1936   {
1937     glbl_derivativeX[i] *= -1.0;
1938     glbl_derivativeY[i] *= -1.0;
1939   }
1940 }
1941 
1942 void HelicalFitter::get_projectionXY(const Surface& surf, const std::pair<Acts::Vector3, Acts::Vector3>& tangent, Acts::Vector3& projX, Acts::Vector3& projY)
1943 {
1944   // we only need the direction part of the tangent
1945   Acts::Vector3 const tanvec = tangent.second;
1946   // get the plane of the surface
1947   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;  // convert to cm
1948 
1949   // We need the three unit vectors in the sensor local frame, transformed to the global frame
1950   //====================================================================
1951   // sensorNormal is the Z vector in the global frame
1952   Acts::Vector3 const Z = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1953   // get surface X and Y unit vectors in global frame
1954   // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1
1955   Acts::Vector3 const xloc(1.0, 0.0, 0.0);  // local coord unit vector in x
1956   Acts::Vector3 xglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm);
1957   xglob /= Acts::UnitConstants::cm;
1958   Acts::Vector3 const yloc(0.0, 1.0, 0.0);
1959   Acts::Vector3 yglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm);
1960   yglob /= Acts::UnitConstants::cm;
1961   // These are the local frame unit vectors transformed to the global frame
1962   Acts::Vector3 const X = (xglob - sensorCenter) / (xglob - sensorCenter).norm();
1963   Acts::Vector3 const Y = (yglob - sensorCenter) / (yglob - sensorCenter).norm();
1964 
1965   // see equation 31 of the ATLAS paper (and discussion) for this
1966   // The unit vector in the local frame transformed to the global frame (X),
1967   // minus Z scaled by the track vector overlap with X, divided by the track vector overlap with Z.
1968   projX = X - (tanvec.dot(X) / tanvec.dot(Z)) * Z;
1969   projY = Y - (tanvec.dot(Y) / tanvec.dot(Z)) * Z;
1970 
1971   if(Verbosity() > 1)
1972     {
1973       std::cout << "    tanvec: " << std::endl << tanvec << std::endl;
1974       std::cout << "    X: " << std::endl << X << std::endl;
1975       std::cout << "    Y: " << std::endl << Y << std::endl;
1976       std::cout << "    Z: " << std::endl << Z << std::endl;
1977 
1978       std::cout << "    projX: " << std::endl << projX << std::endl;
1979       std::cout << "    projY: " << std::endl << projY << std::endl;
1980     }
1981 
1982   return;
1983 }
1984 
1985 void HelicalFitter::get_projectionVtxXY(SvtxTrack& track, const Acts::Vector3& event_vtx, Acts::Vector3& projX, Acts::Vector3& projY)
1986 {
1987   Acts::Vector3 tanvec(track.get_px(), track.get_py(), track.get_pz());
1988   Acts::Vector3 normal(track.get_px(), track.get_py(), 0);
1989 
1990   tanvec /= tanvec.norm();
1991   normal /= normal.norm();
1992 
1993   // get surface X and Y unit vectors in global frame
1994   Acts::Vector3 const xloc(1.0, 0.0, 0.0);
1995   Acts::Vector3 const yloc(0.0, 0.0, 1.0);  // local y
1996   Acts::Vector3 const xglob = localvtxToGlobalvtx(track, event_vtx, xloc);
1997   Acts::Vector3 const yglob = yloc + event_vtx;
1998   Acts::Vector3 const X = (xglob - event_vtx) / (xglob - event_vtx).norm();  // local unit vector transformed to global coordinates
1999   Acts::Vector3 const Y = (yglob - event_vtx) / (yglob - event_vtx).norm();
2000 
2001   // see equation 31 of the ATLAS paper (and discussion) for this
2002   projX = X - (tanvec.dot(X) / tanvec.dot(normal)) * normal;
2003   projY = Y - (tanvec.dot(Y) / tanvec.dot(normal)) * normal;
2004   return;
2005 }
2006 
2007 unsigned int HelicalFitter::addSiliconClusters(std::vector<float>& fitpars, std::vector<Acts::Vector3>& global_vec, std::vector<TrkrDefs::cluskey>& cluskey_vec)
2008 {
2009   return TrackFitUtils::addClusters(fitpars, dca_cut, _tGeometry, _cluster_map, global_vec, cluskey_vec, 0, 6);
2010 }
2011 bool HelicalFitter::is_vertex_param_fixed(unsigned int param)
2012 {
2013   bool ret = false;
2014   auto it = fixed_vertex_params.find(param);
2015   if (it != fixed_vertex_params.end())
2016   {
2017     ret = true;
2018   }
2019   return ret;
2020 }
2021 bool HelicalFitter::is_intt_layer_fixed(unsigned int layer)
2022 {
2023   bool ret = false;
2024   auto it = fixed_intt_layers.find(layer);
2025   if (it != fixed_intt_layers.end())
2026   {
2027     ret = true;
2028   }
2029 
2030   return ret;
2031 }
2032 
2033 bool HelicalFitter::is_mvtx_layer_fixed(unsigned int layer, unsigned int clamshell)
2034 {
2035   bool ret = false;
2036 
2037   std::pair const pair = std::make_pair(layer, clamshell);
2038   auto it = fixed_mvtx_layers.find(pair);
2039   if (it != fixed_mvtx_layers.end())
2040   {
2041     ret = true;
2042   }
2043   return ret;
2044 }
2045 
2046 void HelicalFitter::set_intt_layer_fixed(unsigned int layer)
2047 {
2048   fixed_intt_layers.insert(layer);
2049 }
2050 
2051 void HelicalFitter::set_mvtx_layer_fixed(unsigned int layer, unsigned int clamshell)
2052 {
2053   fixed_mvtx_layers.insert(std::make_pair(layer, clamshell));
2054 }
2055 
2056 bool HelicalFitter::is_layer_param_fixed(unsigned int layer, unsigned int param)
2057 {
2058   bool ret = false;
2059   std::pair<unsigned int, unsigned int> const pair = std::make_pair(layer, param);
2060   auto it = fixed_layer_params.find(pair);
2061   if (it != fixed_layer_params.end())
2062   {
2063     ret = true;
2064   }
2065 
2066   return ret;
2067 }
2068 
2069 void HelicalFitter::set_layer_param_fixed(unsigned int layer, unsigned int param)
2070 {
2071   std::pair<unsigned int, unsigned int> const pair = std::make_pair(layer, param);
2072   fixed_layer_params.insert(pair);
2073 }
2074 
2075 void HelicalFitter::set_tpc_sector_fixed(unsigned int region, unsigned int sector, unsigned int side)
2076 {
2077   // make a combined subsector index
2078   unsigned int const subsector = region * 24 + side * 12 + sector;
2079   fixed_sectors.insert(subsector);
2080 }
2081 
2082 bool HelicalFitter::is_tpc_sector_fixed(unsigned int layer, unsigned int sector, unsigned int side)
2083 {
2084   bool ret = false;
2085   unsigned int const region = AlignmentDefs::getTpcRegion(layer);
2086   unsigned int const subsector = region * 24 + side * 12 + sector;
2087   auto it = fixed_sectors.find(subsector);
2088   if (it != fixed_sectors.end())
2089   {
2090     ret = true;
2091   }
2092 
2093   return ret;
2094 }
2095 
2096 void HelicalFitter::correctTpcGlobalPositions(std::vector<Acts::Vector3> global_vec, const std::vector<TrkrDefs::cluskey> &cluskey_vec)
2097 {
2098   for (unsigned int iclus = 0; iclus < cluskey_vec.size(); ++iclus)
2099   {
2100     auto cluskey = cluskey_vec[iclus];
2101     auto global = global_vec[iclus];
2102     const unsigned int trkrId = TrkrDefs::getTrkrId(cluskey);
2103     if (trkrId == TrkrDefs::tpcId)
2104     {
2105       // have to add corrections for TPC clusters after transformation to global
2106       int const crossing = 0;  // for now
2107       makeTpcGlobalCorrections(cluskey, crossing, global);
2108       global_vec[iclus] = global;
2109     }
2110   }
2111 }
2112 
2113 float HelicalFitter::getVertexResidual(Acts::Vector3 vtx)
2114 {
2115   float const phi = atan2(vtx(1), vtx(0));
2116   float const r = vtx(0) / cos(phi);
2117   float const test_r = sqrt(vtx(0) * vtx(0) + vtx(1) * vtx(1));
2118 
2119   if (Verbosity() > 1)
2120   {
2121     std::cout << "my method position: " << vtx << std::endl;
2122     std::cout << "r " << r << " phi: " << phi * 180 / M_PI << " test_r" << test_r << std::endl;
2123   }
2124   return r;
2125 }
2126 
2127 void HelicalFitter::get_dca(SvtxTrack& track, float& dca3dxy, float& dca3dz, float& dca3dxysigma, float& dca3dzsigma, const Acts::Vector3& event_vertex)
2128 {
2129   // give trackseed
2130   dca3dxy = NAN;
2131   Acts::Vector3 track_vtx(track.get_x(), track.get_y(), track.get_z());
2132   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2133 
2134   track_vtx -= event_vertex;  // difference between track_vertex and event_vtx
2135 
2136   Acts::ActsSquareMatrix<3> posCov;
2137   for (int i = 0; i < 3; ++i)
2138   {
2139     for (int j = 0; j < 3; ++j)
2140     {
2141       posCov(i, j) = track.get_error(i, j);
2142     }
2143   }
2144 
2145   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2146 
2147   float phi = atan2(r(1), r(0));
2148   Acts::RotationMatrix3 rot;
2149   Acts::RotationMatrix3 rot_T;
2150   phi *= -1;
2151   rot(0, 0) = cos(phi);
2152   rot(0, 1) = -sin(phi);
2153   rot(0, 2) = 0;
2154   rot(1, 0) = sin(phi);
2155   rot(1, 1) = cos(phi);
2156   rot(1, 2) = 0;
2157   rot(2, 0) = 0;
2158   rot(2, 1) = 0;
2159   rot(2, 2) = 1;
2160   rot_T = rot.transpose();
2161 
2162   Acts::Vector3 pos_R = rot * track_vtx;
2163   Acts::ActsSquareMatrix<3> rotCov = rot * posCov * rot_T;
2164   dca3dxy = pos_R(0);
2165   dca3dz = pos_R(2);
2166   dca3dxysigma = sqrt(rotCov(0, 0));
2167   dca3dzsigma = sqrt(rotCov(2, 2));
2168 
2169   if (Verbosity() > 1)
2170   {
2171     std::cout << " Helix: momentum.cross(z): " << r << " phi: " << phi * 180 / M_PI << std::endl;
2172     std::cout << "dca3dxy " << dca3dxy << " dca3dz: " << dca3dz << " pos_R(1): " << pos_R(1) << " dca3dxysigma " << dca3dxysigma << " dca3dzsigma " << dca3dzsigma << std::endl;
2173   }
2174 }
2175 
2176 void HelicalFitter::get_dca_zero_field(SvtxTrack& track, float& dca3dxy, float& dca3dz, float& dca3dxysigma, float& dca3dzsigma, const Acts::Vector3& event_vertex)
2177 {
2178   dca3dxy = NAN;
2179   // This is (pca2d(0), pca2d(1), Z0)
2180   Acts::Vector3 track_vtx(track.get_x(), track.get_y(), track.get_z());
2181   track_vtx -= event_vertex;  // difference between track_vertex and event_vtx
2182 
2183   // get unit direction vector for zero field track
2184   // for zero field case this is the tangent unit vector
2185   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2186 
2187   Acts::ActsSquareMatrix<3> posCov;
2188   for (int i = 0; i < 3; ++i)
2189   {
2190     for (int j = 0; j < 3; ++j)
2191     {
2192       posCov(i, j) = track.get_error(i, j);
2193     }
2194   }
2195 
2196   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2197 
2198   float phi = atan2(r(1), r(0));
2199   Acts::RotationMatrix3 rot;
2200   Acts::RotationMatrix3 rot_T;
2201   phi *= -1;
2202   rot(0, 0) = cos(phi);
2203   rot(0, 1) = -sin(phi);
2204   rot(0, 2) = 0;
2205   rot(1, 0) = sin(phi);
2206   rot(1, 1) = cos(phi);
2207   rot(1, 2) = 0;
2208   rot(2, 0) = 0;
2209   rot(2, 1) = 0;
2210   rot(2, 2) = 1;
2211   rot_T = rot.transpose();
2212 
2213   Acts::Vector3 pos_R = rot * track_vtx;
2214   Acts::ActsSquareMatrix<3> rotCov = rot * posCov * rot_T;
2215   dca3dxy = pos_R(0);
2216   dca3dz = pos_R(2);
2217   dca3dxysigma = sqrt(rotCov(0, 0));
2218   dca3dzsigma = sqrt(rotCov(2, 2));
2219 
2220   if (Verbosity() > 1)
2221   {
2222     std::cout << " Zero Field: momentum.cross(z): " << r << " phi (deg): " << phi * 180 / M_PI << std::endl;
2223     std::cout << "dca3dxy " << dca3dxy << " dca3dz: " << dca3dz << " pos_R(1): " << pos_R(1) << " dca3dxysigma " << dca3dxysigma << " dca3dzsigma " << dca3dzsigma << std::endl;
2224   }
2225 }
2226 
2227 Acts::Vector3 HelicalFitter::globalvtxToLocalvtx(SvtxTrack& track, const Acts::Vector3& event_vertex)
2228 {
2229   Acts::Vector3 track_vtx(track.get_x(), track.get_y(), track.get_z());
2230   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2231   track_vtx -= event_vertex;  // difference between track_vertex and event_vtx
2232 
2233   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2234   float phi = atan2(r(1), r(0));
2235   Acts::RotationMatrix3 rot;
2236   Acts::RotationMatrix3 rot_T;
2237   phi *= -1;
2238   rot(0, 0) = cos(phi);
2239   rot(0, 1) = -sin(phi);
2240   rot(0, 2) = 0;
2241   rot(1, 0) = sin(phi);
2242   rot(1, 1) = cos(phi);
2243   rot(1, 2) = 0;
2244   rot(2, 0) = 0;
2245   rot(2, 1) = 0;
2246   rot(2, 2) = 1;
2247   rot_T = rot.transpose();
2248 
2249   Acts::Vector3 pos_R = rot * track_vtx;
2250 
2251   if (Verbosity() > 1)
2252   {
2253     std::cout << " momentum X z: " << r << " phi: " << phi * 180 / M_PI << std::endl;
2254     std::cout << " pos_R(0): " << pos_R(0) << " pos_R(1): " << pos_R(1) << std::endl;
2255   }
2256   return pos_R;
2257 }
2258 
2259 Acts::Vector3 HelicalFitter::globalvtxToLocalvtx(SvtxTrack& track, const Acts::Vector3& event_vertex, Acts::Vector3 PCA)
2260 {
2261   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2262   PCA -= event_vertex;  // difference between track_vertex and event_vtx
2263 
2264   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2265   float phi = atan2(r(1), r(0));
2266   Acts::RotationMatrix3 rot;
2267   Acts::RotationMatrix3 rot_T;
2268   phi *= -1;
2269   rot(0, 0) = cos(phi);
2270   rot(0, 1) = -sin(phi);
2271   rot(0, 2) = 0;
2272   rot(1, 0) = sin(phi);
2273   rot(1, 1) = cos(phi);
2274   rot(1, 2) = 0;
2275   rot(2, 0) = 0;
2276   rot(2, 1) = 0;
2277   rot(2, 2) = 1;
2278   rot_T = rot.transpose();
2279 
2280   Acts::Vector3 pos_R = rot * PCA;
2281 
2282   if (Verbosity() > 1)
2283   {
2284     std::cout << " momentum X z: " << r << " phi: " << phi * 180 / M_PI << std::endl;
2285     std::cout << " pos_R(0): " << pos_R(0) << " pos_R(1): " << pos_R(1) << std::endl;
2286   }
2287   return pos_R;
2288 }
2289 
2290 Acts::Vector3 HelicalFitter::localvtxToGlobalvtx(SvtxTrack& track, const Acts::Vector3& event_vtx, const Acts::Vector3& local)
2291 {
2292   // Acts::Vector3 track_vtx = local;
2293   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2294   // std::cout << "first pos: " << pos << " mom: " << mom << std::endl;
2295   // local -= event_vertex; // difference between track_vertex and event_vtx
2296 
2297   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2298   float const phi = atan2(r(1), r(0));
2299   Acts::RotationMatrix3 rot;
2300   Acts::RotationMatrix3 rot_T;
2301   // phi *= -1;
2302   rot(0, 0) = cos(phi);
2303   rot(0, 1) = -sin(phi);
2304   rot(0, 2) = 0;
2305   rot(1, 0) = sin(phi);
2306   rot(1, 1) = cos(phi);
2307   rot(1, 2) = 0;
2308   rot(2, 0) = 0;
2309   rot(2, 1) = 0;
2310   rot(2, 2) = 1;
2311 
2312   rot_T = rot.transpose();
2313 
2314   Acts::Vector3 pos_R = rot * local;
2315   pos_R += event_vtx;
2316   if (Verbosity() > 1)
2317   {
2318     std::cout << " momentum X z: " << r << " phi: " << phi * 180 / M_PI << std::endl;
2319     std::cout << " pos_R(0): " << pos_R(0) << " pos_R(1): " << pos_R(1) << "pos_R(2): " << pos_R(2) << std::endl;
2320   }
2321   return pos_R;
2322 }