Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:18:18

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 <fun4all/SubsysReco.h>
0010 #include <math.h>
0011 #include <phool/PHIODataNode.h>
0012 #include <phparameter/PHParameterInterface.h>
0013 #include <trackbase/ActsSurfaceMaps.h>
0014 #include <trackbase/InttDefs.h>
0015 #include <trackbase/MvtxDefs.h>
0016 #include <trackbase/TpcDefs.h>
0017 #include <trackbase/TrackFitUtils.h>
0018 #include <trackbase/TrkrClusterContainer.h>
0019 #include <trackbase/TrkrClusterContainerv4.h>
0020 #include <trackbase/TrkrClusterv3.h>
0021 #include <trackbase/TrkrDefs.h>  // for cluskey, getTrkrId, tpcId
0022 #include <trackbase/alignmentTransformationContainer.h>
0023 
0024 #include <trackbase_historic/TrackSeedContainer.h>
0025 #include <trackbase_historic/SvtxAlignmentState.h>
0026 #include <trackbase_historic/SvtxAlignmentStateMap_v1.h>
0027 #include <trackbase_historic/SvtxAlignmentState_v1.h>
0028 #include <trackbase_historic/SvtxTrackMap_v2.h>
0029 #include <trackbase_historic/SvtxTrackState_v1.h>
0030 #include <trackbase_historic/SvtxTrack_v4.h>
0031 #include <trackbase_historic/TrackSeedHelper.h>
0032 #include <trackbase_historic/TrackSeed_v2.h>
0033 
0034 #include <globalvertex/SvtxVertex.h>
0035 #include <globalvertex/SvtxVertexMap.h>
0036 
0037 #include <Acts/Definitions/Algebra.hpp>
0038 #include <Acts/Definitions/Units.hpp>
0039 
0040 #include <fun4all/Fun4AllReturnCodes.h>
0041 
0042 #include <phool/PHCompositeNode.h>
0043 #include <phool/getClass.h>
0044 #include <phool/phool.h>
0045 
0046 #include <TFile.h>
0047 #include <TNtuple.h>
0048 
0049 #include <climits>  // for UINT_MAX
0050 #include <cmath>    // for fabs, 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 (fabs(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 or
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                     << " dx/dz " << fitpars[2] << " Z0 " << fitpars[3] << " eta " << tracklet->get_eta() << " phi " << tracklet->get_phi() << std::endl;
0401         }
0402         if (fabs(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 (fabs(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     for (const auto& [vtxkey, vertex] : *m_vertexmap)
0910     {
0911       for (auto trackiter = vertex->begin_tracks(); trackiter != vertex->end_tracks(); ++trackiter)
0912       {
0913         SvtxTrack* vtxtrack = m_trackmap->get(*trackiter);
0914         if (vtxtrack)
0915         {
0916           unsigned int const vtxtrackid = vtxtrack->get_id();
0917           if (trackid == vtxtrackid)
0918           {
0919             event_vtx(0) = vertex->get_x();
0920             event_vtx(1) = vertex->get_y();
0921             event_vtx(2) = vertex->get_z();
0922             if (Verbosity() > 0)
0923             {
0924               std::cout << "     setting event_vertex for trackid " << trackid << " to vtxid " << vtxkey
0925                         << " vtx " << event_vtx(0) << "  " << event_vtx(1) << "  " << event_vtx(2) << std::endl;
0926             }
0927           }
0928         }
0929       }
0930     }
0931 
0932 
0933     // The residual for the vtx case is (event vtx - track vtx)
0934     // that is -dca
0935     float dca3dxy = 0;
0936     float dca3dz = 0;
0937     float dca3dxysigma = 0;
0938     float dca3dzsigma = 0;
0939     if (!straight_line_fit)
0940     {
0941       get_dca(newTrack, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma, event_vtx);
0942     }
0943     else
0944     {
0945       get_dca_zero_field(newTrack, dca3dxy, dca3dz, dca3dxysigma, dca3dzsigma, event_vtx);
0946     }
0947 
0948     // These are local coordinate residuals in the perigee surface
0949     Acts::Vector2 vtx_residual(-dca3dxy, -dca3dz);
0950 
0951     float lclvtx_derivativeX[AlignmentDefs::NLC];
0952     float lclvtx_derivativeY[AlignmentDefs::NLC];
0953     if (straight_line_fit)
0954     {
0955       getLocalVtxDerivativesZeroFieldXY(newTrack, event_vtx, fitpars, lclvtx_derivativeX, lclvtx_derivativeY);
0956     }
0957     else
0958     {
0959       getLocalVtxDerivativesXY(newTrack, event_vtx, fitpars, lclvtx_derivativeX, lclvtx_derivativeY);
0960     }
0961 
0962     // The global derivs dimensions are [alpha/beta/gamma](x/y/z)
0963     float glblvtx_derivativeX[3];
0964     float glblvtx_derivativeY[3];
0965     getGlobalVtxDerivativesXY(newTrack, event_vtx, glblvtx_derivativeX, glblvtx_derivativeY);
0966 
0967     if (use_event_vertex)
0968     {
0969       for (int p = 0; p < 3; p++)
0970       {
0971         if (is_vertex_param_fixed(p))
0972         {
0973           glblvtx_derivativeX[p] = 0;
0974           glblvtx_derivativeY[p] = 0;
0975         }
0976       }
0977       if (Verbosity() > 1)
0978       {
0979         std::cout << "vertex info for track " << trackid << " with charge " << newTrack.get_charge() << std::endl;
0980 
0981         std::cout << "vertex is " << event_vtx.transpose() << std::endl;
0982         std::cout << "vertex residuals " << vtx_residual.transpose()
0983                   << std::endl;
0984         std::cout << "local derivatives " << std::endl;
0985         for (float const i : lclvtx_derivativeX)
0986         {
0987           std::cout << i << ", ";
0988         }
0989         std::cout << std::endl;
0990         for (float const i : lclvtx_derivativeY)
0991         {
0992           std::cout << i << ", ";
0993         }
0994         std::cout << "global vtx derivaties " << std::endl;
0995         for (float const i : glblvtx_derivativeX)
0996         {
0997           std::cout << i << ", ";
0998         }
0999         std::cout << std::endl;
1000         for (float const i : glblvtx_derivativeY)
1001         {
1002           std::cout << i << ", ";
1003         }
1004       }
1005 
1006       if (!isnan(vtx_residual(0)))
1007       {
1008         if (arr_has_nan(lclvtx_derivativeX))
1009         {
1010           std::cerr << "lclvtx_derivativeX is NaN" << std::endl;
1011           continue;
1012         }
1013         if (arr_has_nan(glblvtx_derivativeX))
1014         {
1015           std::cerr << "glblvtx_derivativeX is NaN" << std::endl;
1016           continue;
1017         }
1018         _mille->mille(AlignmentDefs::NLC, lclvtx_derivativeX, AlignmentDefs::NGLVTX, glblvtx_derivativeX, AlignmentDefs::glbl_vtx_label, vtx_residual(0), vtx_sigma(0));
1019       }
1020       if (!isnan(vtx_residual(1)))
1021       {
1022         if (arr_has_nan(lclvtx_derivativeY))
1023         {
1024           std::cerr << "lclvtx_derivativeY is NaN" << std::endl;
1025           continue;
1026         }
1027         if (arr_has_nan(glblvtx_derivativeY))
1028         {
1029           std::cerr << "glblvtx_derivativeY is NaN" << std::endl;
1030           continue;
1031         }
1032         _mille->mille(AlignmentDefs::NLC, lclvtx_derivativeY, AlignmentDefs::NGLVTX, glblvtx_derivativeY, AlignmentDefs::glbl_vtx_label, vtx_residual(1), vtx_sigma(1));
1033       }
1034     }
1035 
1036     if (make_ntuple)
1037     {
1038       Acts::Vector3 const mom(newTrack.get_px(), newTrack.get_py(), newTrack.get_pz());
1039       Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
1040       float const perigee_phi = atan2(r(1), r(0));
1041       float const track_phi = atan2(newTrack.get_py(), newTrack.get_px());
1042       float const track_eta = atanh(newTrack.get_pz() / newTrack.get_p());
1043       if (straight_line_fit)
1044       {
1045         float ntp_data[28] = {(float) trackid, (float) vtx_residual(0), (float) vtx_residual(1), (float) vtx_sigma(0), (float) vtx_sigma(1),
1046                               lclvtx_derivativeX[0], lclvtx_derivativeX[1], lclvtx_derivativeX[2], lclvtx_derivativeX[3],
1047                               glblvtx_derivativeX[0], glblvtx_derivativeX[1], glblvtx_derivativeX[2],
1048                               lclvtx_derivativeY[0], lclvtx_derivativeY[1], lclvtx_derivativeY[2], lclvtx_derivativeY[3],
1049                               glblvtx_derivativeY[0], glblvtx_derivativeY[1], glblvtx_derivativeY[2],
1050                               newTrack.get_x(), newTrack.get_y(), newTrack.get_z(),
1051                               (float) event_vtx(0), (float) event_vtx(1), (float) event_vtx(2), track_phi, perigee_phi, track_eta};
1052 
1053         track_ntp->Fill(ntp_data);
1054       }
1055       else
1056       {
1057         float ntp_data[29] = {(float) trackid, (float) vtx_residual(0), (float) vtx_residual(1), (float) vtx_sigma(0), (float) vtx_sigma(1),
1058                               lclvtx_derivativeX[0], lclvtx_derivativeX[1], lclvtx_derivativeX[2], lclvtx_derivativeX[3], lclvtx_derivativeX[4],
1059                               glblvtx_derivativeX[0], glblvtx_derivativeX[1], glblvtx_derivativeX[2],
1060                               lclvtx_derivativeY[0], lclvtx_derivativeY[1], lclvtx_derivativeY[2], lclvtx_derivativeY[3], lclvtx_derivativeY[4],
1061                               glblvtx_derivativeY[0], glblvtx_derivativeY[1], glblvtx_derivativeY[2],
1062                               newTrack.get_x(), newTrack.get_y(), newTrack.get_z(),
1063                               (float) event_vtx(0), (float) event_vtx(1), (float) event_vtx(2), track_phi, perigee_phi};
1064 
1065         track_ntp->Fill(ntp_data);
1066       }
1067 
1068     }
1069 
1070     if (Verbosity() > 1)
1071     {
1072       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;
1073       std::cout << "track_x " << newTrack.get_x() << "track_y " << newTrack.get_y() << "track_z " << newTrack.get_z() << std::endl;
1074     }
1075     // close out this track
1076     _mille->end();
1077 
1078   }  // end loop over tracks
1079 
1080   return Fun4AllReturnCodes::EVENT_OK;
1081 }
1082 /*
1083 std::make_pair<unsigned int, Acts::Vector3> HelicalFitter::getAverageVertex( std::vector<Acts::Vector3> cumulative_vertex)
1084 {
1085 
1086 
1087 
1088 
1089 }
1090 */
1091 Acts::Vector3 HelicalFitter::get_helix_surface_intersection(const Surface& surf, std::vector<float>& fitpars, Acts::Vector3 global)
1092 {
1093   // we want the point where the helix intersects the plane of the surface
1094   // get the plane of the surface
1095   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // convert to cm
1096   Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1097   sensorNormal /= sensorNormal.norm();
1098 
1099   // there are analytic solutions for a line-plane intersection.
1100   // to use this, need to get the vector tangent to the helix near the measurement and a point on it.
1101   std::pair<Acts::Vector3, Acts::Vector3> const line = get_helix_tangent(fitpars, std::move(global));
1102   Acts::Vector3 const pca = line.first;
1103   Acts::Vector3 const tangent = line.second;
1104 
1105   Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal);
1106 
1107   return intersection;
1108 }
1109 
1110 Acts::Vector3 HelicalFitter::get_line_surface_intersection(const Surface& surf, std::vector<float>& fitpars)
1111 {
1112   // we want the point where the helix intersects the plane of the surface
1113   // get the plane of the surface
1114   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // convert to cm
1115   Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1116   sensorNormal /= sensorNormal.norm();
1117 
1118   /*
1119   // we need the direction of the line
1120 
1121   // consider a point some distance along the straight line.
1122   // Consider a value of x, calculate y, calculate radius, calculate z
1123   double x = 2;
1124   double y = fitpars[0]*x + fitpars[1];
1125   double rxy = sqrt(x*x+y*y);
1126   double z = fitpars[2]*rxy + fitpars[3];
1127   Acts::Vector3 arb_point(x, y, z);
1128 
1129   double x2 = 4;
1130   double y2 = fitpars[0]*x2 + fitpars[1];
1131   double rxy2 = sqrt(x2*x2+y2*y2);
1132   double z2 = fitpars[2]*rxy2 + fitpars[3];
1133   Acts::Vector3 arb_point2(x2, y2, z2);
1134 
1135   Acts::Vector3 tangent = arb_point2 - arb_point;   // direction of line
1136   */
1137   auto line = get_line_zero_field(fitpars);  // do not need the direction
1138 
1139   auto arb_point = line.first;
1140   auto tangent = line.second;
1141 
1142   Acts::Vector3 intersection = get_line_plane_intersection(arb_point, tangent, sensorCenter, sensorNormal);
1143 
1144   return intersection;
1145 }
1146 
1147 Acts::Vector3 HelicalFitter::get_helix_surface_intersection(const Surface& surf, std::vector<float>& fitpars, Acts::Vector3 global, Acts::Vector3& pca, Acts::Vector3& tangent)
1148 {
1149   // we want the point where the helix intersects the plane of the surface
1150 
1151   // get the plane of the surface
1152   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) * 0.1;  // convert to cm
1153   Acts::Vector3 sensorNormal = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1154   sensorNormal /= sensorNormal.norm();
1155 
1156   // there are analytic solutions for a line-plane intersection.
1157   // to use this, need to get the vector tangent to the helix near the measurement and a point on it.
1158   std::pair<Acts::Vector3, Acts::Vector3> const line = get_helix_tangent(fitpars, std::move(global));
1159   pca = line.first;
1160   tangent = line.second;
1161 
1162   Acts::Vector3 intersection = get_line_plane_intersection(pca, tangent, sensorCenter, sensorNormal);
1163 
1164   return intersection;
1165 }
1166 
1167 Acts::Vector3 HelicalFitter::get_helix_vtx(Acts::Vector3 event_vtx, const std::vector<float>& fitpars)
1168 {
1169   Acts::Vector2 pca2d = TrackFitUtils::get_circle_point_pca(fitpars[0], fitpars[1], fitpars[2], std::move(event_vtx));
1170   Acts::Vector3 helix_vtx(pca2d(0), pca2d(1), fitpars[4]);
1171 
1172   return helix_vtx;
1173 }
1174 
1175 Acts::Vector3 HelicalFitter::get_line_vtx(Acts::Vector3 event_vtx, const std::vector<float>& fitpars)
1176 {
1177   Acts::Vector2 pca2d = TrackFitUtils::get_line_point_pca(fitpars[0], fitpars[1], std::move(event_vtx));
1178   Acts::Vector3 line_vtx(pca2d(0), pca2d(1), fitpars[3]);
1179 
1180   return line_vtx;
1181 }
1182 
1183 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_line_tangent(const std::vector<float>& fitpars, Acts::Vector3 global)
1184 {
1185   // returns the equation of the line, with the direction obtained from the global cluster point
1186 
1187   // Get the rough direction of the line from the global vector, which is a point on the line
1188   float const phi = atan2(global(1), global(0));
1189 
1190   // we need the direction of the line
1191   // consider a point some distance along the straight line.
1192   // Consider a value of x, calculate y, calculate radius, calculate z
1193   double const x = 0;
1194   double const y = fitpars[0] * x + fitpars[1];
1195   //  double rxy = sqrt(x*x+y*y);
1196   double const z = fitpars[2] * x + fitpars[3];
1197   Acts::Vector3 arb_point(x, y, z);
1198 
1199   double const x2 = 1;
1200   double const y2 = fitpars[0] * x2 + fitpars[1];
1201   double const z2 = fitpars[2] * x2 + fitpars[3];
1202   Acts::Vector3 const arb_point2(x2, y2, z2);
1203 
1204   float const arb_phi = atan2(arb_point(1), arb_point(0));
1205   Acts::Vector3 tangent = arb_point2 - arb_point;  // direction of line
1206   if (fabs(arb_phi - phi) > M_PI / 2)
1207   {
1208     tangent = arb_point - arb_point2;  // direction of line
1209   }
1210 
1211   tangent /= tangent.norm();
1212 
1213   std::pair<Acts::Vector3, Acts::Vector3> line = std::make_pair(arb_point, tangent);
1214 
1215   return line;
1216 }
1217 
1218 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_line_zero_field(const std::vector<float>& fitpars)
1219 {
1220   // Returns the line equation, but without the direction of the track
1221   // consider a point some distance along the straight line.
1222   // Consider a value of x, calculate y, calculate z
1223   double const x = 0;
1224   double const y = fitpars[0] * x + fitpars[1];
1225   double const z = fitpars[2] * x + fitpars[3];
1226   Acts::Vector3 const arb_point(x, y, z);
1227 
1228   double const x2 = 1;
1229   double const y2 = fitpars[0] * x2 + fitpars[1];
1230   double const z2 = fitpars[2] * x2 + fitpars[3];
1231   Acts::Vector3 const arb_point2(x2, y2, z2);
1232 
1233   Acts::Vector3 tangent = arb_point2 - arb_point;  // +/- times direction of line
1234   tangent /= tangent.norm();
1235 
1236   std::pair<Acts::Vector3, Acts::Vector3> line = std::make_pair(arb_point, tangent);
1237 
1238   return line;
1239 }
1240 
1241 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_line(const std::vector<float>& fitpars)
1242 {
1243   // we need the direction of the line
1244   // consider a point some distance along the straight line.
1245   // Consider a value of x, calculate y, calculate radius, calculate z
1246   double const x = 0.0;
1247   double const y = fitpars[0] * x + fitpars[1];
1248   double const rxy = sqrt(x * x + y * y);
1249   double const z = fitpars[2] * rxy + fitpars[3];
1250   Acts::Vector3 const arb_point(x, y, z);
1251 
1252   double const x2 = 1;
1253   double const y2 = fitpars[0] * x2 + fitpars[1];
1254   double const rxy2 = sqrt(x2 * x2 + y2 * y2);
1255   double const z2 = fitpars[2] * rxy2 + fitpars[3];
1256   Acts::Vector3 const arb_point2(x2, y2, z2);
1257 
1258   Acts::Vector3 tangent = arb_point2 - arb_point;  // direction of line
1259   tangent /= tangent.norm();
1260 
1261   std::pair<Acts::Vector3, Acts::Vector3> line = std::make_pair(arb_point, tangent);
1262 
1263   return line;
1264 }
1265 
1266 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)
1267 {
1268   // get the intersection of the line made by PCA and tangent with the plane of the sensor
1269 
1270   // For a point on the line:      p = PCA + d * tangent;
1271   // for a point on the plane:  (p - sensor_center).sensor_normal = 0
1272 
1273   // The solution is:
1274   float const d = (sensor_center - PCA).dot(sensor_normal) / tangent.dot(sensor_normal);
1275   Acts::Vector3 intersection = PCA + d * tangent;
1276 
1277   /*
1278   std::cout << "    sensor center " << sensor_center(0) << "  " << sensor_center(1) << "  " << sensor_center(2) << std::endl;
1279   std::cout << "      intersection " << intersection(0) << "  " << intersection(1) << "  " << intersection(2) << std::endl;
1280   std::cout << "      PCA " << PCA(0) << "  " << PCA(1) << "  " << PCA(2) << std::endl;
1281   std::cout << "      tangent " << tangent(0) << "  " << tangent(1) << "  " << tangent(2) << std::endl;
1282   std::cout << "            d " << d << std::endl;
1283   */
1284 
1285   return intersection;
1286 }
1287 
1288 std::pair<Acts::Vector3, Acts::Vector3> HelicalFitter::get_helix_tangent(const std::vector<float>& fitpars, Acts::Vector3 global)
1289 {
1290   auto pair = TrackFitUtils::get_helix_tangent(fitpars, global);
1291   /*
1292     save for posterity purposes
1293   if(Verbosity() > 2)
1294     {
1295       // different method for checking:
1296       // project the circle PCA vector an additional small amount and find the helix PCA to that point
1297 
1298       float projection = 0.25;  // cm
1299       Acts::Vector3 second_point = pca + projection * pca/pca.norm();
1300       Acts::Vector2 second_point_pca_circle = TrackFitUtils::get_circle_point_pca(radius, x0, y0, second_point);
1301       float second_point_pca_z = second_point_pca_circle.norm() * zslope + z0;
1302       Acts::Vector3 second_point_pca2(second_point_pca_circle(0), second_point_pca_circle(1), second_point_pca_z);
1303       Acts::Vector3 tangent2 = (second_point_pca2 - pca) /  (second_point_pca2 - pca).norm();
1304       Acts::Vector3 final_pca2 = getPCALinePoint(global, tangent2, pca);
1305 
1306       std::cout << " get_helix_tangent: getting tangent at angle_pca: " << angle_pca * 180.0 / M_PI << std::endl
1307                 << " original first point pca                      " << pca(0) << "  " << pca(1) << "  " << pca(2) << std::endl
1308                 << " original second point pca  " << second_point_pca(0) << "  " << second_point_pca(1) << "  " << second_point_pca(2) << std::endl
1309                 << " original tangent " << tangent(0) << "  " << tangent(1) << "  " << tangent(2) << std::endl
1310                 << " original final pca from line " << final_pca(0) << "  " << final_pca(1) << "  " << final_pca(2) << std::endl;
1311 
1312       if(Verbosity() > 3)
1313         {
1314           std::cout  << "    Check: 2nd point pca meth 2 "<< second_point_pca2(0)<< "  "<< second_point_pca2(1) << "  "<< second_point_pca2(2) << std::endl
1315                         << "    check tangent " << tangent2(0) << "  " << tangent2(1) << "  " << tangent2(2) << std::endl
1316                         << "    check final pca from line " << final_pca2(0) << "  " << final_pca2(1) << "  " << final_pca2(2)
1317                         << std::endl;
1318         }
1319 
1320     }
1321   */
1322 
1323   return pair;
1324 }
1325 
1326 int HelicalFitter::End(PHCompositeNode* /*unused*/)
1327 {
1328   // closes output file in destructor
1329   delete _mille;
1330 
1331   if (make_ntuple)
1332   {
1333     fout->Write();
1334     fout->Close();
1335   }
1336 
1337   return Fun4AllReturnCodes::EVENT_OK;
1338 }
1339 int HelicalFitter::CreateNodes(PHCompositeNode* topNode)
1340 {
1341   PHNodeIterator iter(topNode);
1342 
1343   PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
1344 
1345   if (!dstNode)
1346   {
1347     std::cerr << "DST node is missing, quitting" << std::endl;
1348     throw std::runtime_error("Failed to find DST node in PHActsTrkFitter::createNodes");
1349   }
1350 
1351   PHNodeIterator dstIter(topNode);
1352   PHCompositeNode* svtxNode = dynamic_cast<PHCompositeNode*>(dstIter.findFirst("PHCompositeNode", "SVTX"));
1353   if (!svtxNode)
1354   {
1355     svtxNode = new PHCompositeNode("SVTX");
1356     dstNode->addNode(svtxNode);
1357   }
1358 
1359   m_trackmap = findNode::getClass<SvtxTrackMap>(topNode, "HelicalFitterTrackMap");
1360   if (!m_trackmap)
1361   {
1362     m_trackmap = new SvtxTrackMap_v2;
1363     PHIODataNode<PHObject>* node = new PHIODataNode<PHObject>(m_trackmap, "HelicalFitterTrackMap", "PHObject");
1364     svtxNode->addNode(node);
1365   }
1366 
1367   m_alignmentmap = findNode::getClass<SvtxAlignmentStateMap>(topNode, "HelicalFitterAlignmentStateMap");
1368   if (!m_alignmentmap)
1369   {
1370     m_alignmentmap = new SvtxAlignmentStateMap_v1;
1371     PHIODataNode<PHObject>* node = new PHIODataNode<PHObject>(m_alignmentmap, "HelicalFitterAlignmentStateMap", "PHObject");
1372     svtxNode->addNode(node);
1373   }
1374 
1375   return Fun4AllReturnCodes::EVENT_OK;
1376 }
1377 int HelicalFitter::GetNodes(PHCompositeNode* topNode)
1378 {
1379   //---------------------------------
1380   // Get additional objects off the Node Tree
1381   //---------------------------------
1382 
1383   _track_map_silicon = findNode::getClass<TrackSeedContainer>(topNode, _silicon_track_map_name);
1384   if (!_track_map_silicon && (fitsilicon || fitfulltrack))
1385   {
1386     cerr << PHWHERE << " ERROR: Can't find SiliconTrackSeedContainer " << endl;
1387     return Fun4AllReturnCodes::ABORTEVENT;
1388   }
1389 
1390   _track_map_tpc = findNode::getClass<TrackSeedContainer>(topNode, _track_map_name);
1391   if (!_track_map_tpc && (fittpc || fitfulltrack))
1392   {
1393     cerr << PHWHERE << " ERROR: Can't find " << _track_map_name.c_str() << endl;
1394     return Fun4AllReturnCodes::ABORTEVENT;
1395   }
1396 
1397   _cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
1398   if (!_cluster_map)
1399   {
1400     std::cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl;
1401     return Fun4AllReturnCodes::ABORTEVENT;
1402   }
1403 
1404   _tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
1405   if (!_tGeometry)
1406   {
1407     std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl;
1408     return Fun4AllReturnCodes::ABORTEVENT;
1409   }
1410 
1411   m_vertexmap = findNode::getClass<SvtxVertexMap>(topNode, "SvtxVertexMap");
1412   if (!m_vertexmap)
1413   {
1414     std::cout << PHWHERE << " ERROR: Can't find node SvtxVertexMap" << std::endl;
1415     // return Fun4AllReturnCodes::ABORTEVENT;
1416   }
1417 
1418   // global position wrapper
1419   m_globalPositionWrapper.loadNodes(topNode);
1420 
1421   return Fun4AllReturnCodes::EVENT_OK;
1422 }
1423 
1424 Acts::Vector3 HelicalFitter::get_helix_pca(std::vector<float>& fitpars, const Acts::Vector3& global)
1425 {
1426   return TrackFitUtils::get_helix_pca(fitpars, global);
1427 }
1428 
1429 Acts::Vector3 HelicalFitter::getPCALinePoint(const Acts::Vector3& global, const Acts::Vector3& tangent, const Acts::Vector3& posref)
1430 {
1431   // Approximate track with a straight line consisting of the state position posref and the vector (px,py,pz)
1432 
1433   // The position of the closest point on the line to global is:
1434   // posref + projection of difference between the point and posref on the tangent vector
1435   Acts::Vector3 pca = posref + ((global - posref).dot(tangent)) * tangent;
1436 
1437   return pca;
1438 }
1439 
1440 float HelicalFitter::convertTimeToZ(TrkrDefs::cluskey cluster_key, TrkrCluster* cluster)
1441 {
1442   // must convert local Y from cluster average time of arival to local cluster z position
1443   double const drift_velocity = _tGeometry->get_drift_velocity();
1444   double const zdriftlength = cluster->getLocalY() * drift_velocity;
1445   double const surfCenterZ = 52.89;          // 52.89 is where G4 thinks the surface center is
1446   double zloc = surfCenterZ - zdriftlength;  // converts z drift length to local z position in the TPC in north
1447   unsigned int const side = TpcDefs::getSide(cluster_key);
1448   if (side == 0)
1449   {
1450     zloc = -zloc;
1451   }
1452   float const z = zloc;  // in cm
1453 
1454   return z;
1455 }
1456 
1457 void HelicalFitter::makeTpcGlobalCorrections(TrkrDefs::cluskey cluster_key, short int crossing, Acts::Vector3& global)
1458 {
1459   // make all corrections to global position of TPC cluster
1460   unsigned int const side = TpcDefs::getSide(cluster_key);
1461   global.z() = m_clusterCrossingCorrection.correctZ(global.z(), side, crossing);
1462 
1463   // apply distortion corrections
1464   global = m_globalPositionWrapper.applyDistortionCorrections(global);
1465 }
1466 
1467 void HelicalFitter::getTrackletClusters(TrackSeed* tracklet, std::vector<Acts::Vector3>& global_vec, std::vector<TrkrDefs::cluskey>& cluskey_vec)
1468 {
1469   getTrackletClusterList(tracklet, cluskey_vec);
1470   // store cluster global positions in a vector
1471   TrackFitUtils::getTrackletClusters(_tGeometry, _cluster_map, global_vec, cluskey_vec);
1472 }
1473 
1474 void HelicalFitter::getTrackletClusterList(TrackSeed* tracklet, std::vector<TrkrDefs::cluskey>& cluskey_vec)
1475 {
1476   for (auto clusIter = tracklet->begin_cluster_keys();
1477        clusIter != tracklet->end_cluster_keys();
1478        ++clusIter)
1479   {
1480     auto key = *clusIter;
1481     auto cluster = _cluster_map->findCluster(key);
1482     if (!cluster)
1483     {
1484       std::cout << PHWHERE << "Failed to get cluster with key " << key << std::endl;
1485       continue;
1486     }
1487 
1488     /// Make a safety check for clusters that couldn't be attached to a surface
1489     auto surf = _tGeometry->maps().getSurface(key, cluster);
1490     if (!surf)
1491     {
1492       continue;
1493     }
1494 
1495     // drop some bad layers in the TPC completely
1496     unsigned int const layer = TrkrDefs::getLayer(key);
1497     if (layer == 7 || layer == 22 || layer == 23 || layer == 38 || layer == 39)
1498     {
1499       continue;
1500     }
1501 
1502     // drop INTT clusters for now  -- TEMPORARY!
1503     // if (layer > 2 && layer < 7)
1504     //{
1505     //  continue;
1506     //}
1507 
1508     cluskey_vec.push_back(key);
1509 
1510   }  // end loop over clusters for this track
1511 }
1512 
1513 std::vector<float> HelicalFitter::fitClusters(std::vector<Acts::Vector3>& global_vec, std::vector<TrkrDefs::cluskey> cluskey_vec)
1514 {
1515   return TrackFitUtils::fitClusters(global_vec, std::move(cluskey_vec), use_intt_zfit);  // do helical fit
1516 }
1517 
1518 Acts::Vector2 HelicalFitter::getClusterError(TrkrCluster* cluster, TrkrDefs::cluskey cluskey, Acts::Vector3& global)
1519 {
1520   Acts::Vector2 clus_sigma(0, 0);
1521 
1522   double const clusRadius = sqrt(global[0] * global[0] + global[1] * global[1]);
1523   auto para_errors = _ClusErrPara.get_clusterv5_modified_error(cluster, clusRadius, cluskey);
1524   double const phierror = sqrt(para_errors.first);
1525   double const zerror = sqrt(para_errors.second);
1526   clus_sigma(1) = zerror;
1527   clus_sigma(0) = phierror;
1528 
1529   return clus_sigma;
1530 }
1531 
1532 // new one
1533 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)
1534 {
1535   // Calculate the derivatives of the residual wrt the track parameters numerically
1536   std::vector<float> temp_fitpars;
1537 
1538   std::vector<float> fitpars_delta;
1539   fitpars_delta.push_back(0.1);  // radius, cm
1540   fitpars_delta.push_back(0.1);  // X0, cm
1541   fitpars_delta.push_back(0.1);  // Y0, cm
1542   fitpars_delta.push_back(0.1);  // zslope, cm
1543   fitpars_delta.push_back(0.1);  // Z0, cm
1544 
1545   temp_fitpars.reserve(fitpars.size());
1546   for (float const fitpar : fitpars)
1547   {
1548     temp_fitpars.push_back(fitpar);
1549   }
1550 
1551   // calculate projX and projY vectors once for the optimum fit parameters
1552   if (Verbosity() > 1)
1553   {
1554     std::cout << "Call get_helix_tangent for best fit fitpars" << std::endl;
1555   }
1556   std::pair<Acts::Vector3, Acts::Vector3> const tangent = get_helix_tangent(fitpars, global);
1557 
1558   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1559   get_projectionXY(surf, tangent, projX, projY);
1560 
1561   Acts::Vector3 const intersection = get_helix_surface_intersection(surf, temp_fitpars, global);
1562 
1563   // loop over the track fit parameters
1564   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1565   {
1566     Acts::Vector3 intersection_delta[2];
1567     for (int ipm = 0; ipm < 2; ++ipm)
1568     {
1569       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1570       float const deltapm = pow(-1.0, ipm);
1571       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1572 
1573       Acts::Vector3 const temp_intersection = get_helix_surface_intersection(surf, temp_fitpars, global);
1574       intersection_delta[ipm] = temp_intersection - intersection;
1575     }
1576     Acts::Vector3 average_intersection_delta = (intersection_delta[0] - intersection_delta[1]) / (2 * fitpars_delta[ip]);
1577 
1578     if (Verbosity() > 1)
1579     {
1580       std::cout << " average_intersection_delta / delta " << average_intersection_delta(0) << "  " << average_intersection_delta(1) << "  " << average_intersection_delta(2) << std::endl;
1581     }
1582 
1583     // calculate the change in fit for X and Y
1584     // - note negative sign from ATLAS paper is dropped here because mille wants the derivative of the fit, not the derivative of the residual
1585     lcl_derivativeX[ip] = average_intersection_delta.dot(projX);
1586     lcl_derivativeY[ip] = average_intersection_delta.dot(projY);
1587     if (Verbosity() > 1)
1588     {
1589       std::cout << " layer " << layer << " ip " << ip << "  derivativeX " << lcl_derivativeX[ip] << "  "
1590                 << " derivativeY " << lcl_derivativeY[ip] << std::endl;
1591     }
1592 
1593     temp_fitpars[ip] = fitpars[ip];
1594   }
1595 }
1596 
1597 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)
1598 {
1599   // Calculate the derivatives of the residual wrt the track parameters numerically
1600   // This version differs from the field on one in that:
1601   // Fitpars has parameters of a straight line (4) instead of a helix (5)
1602   // The track tangent is just the line direction
1603 
1604   std::vector<float> temp_fitpars;
1605 
1606   std::vector<float> fitpars_delta;
1607   fitpars_delta.push_back(0.1);  // xyslope, cm
1608   fitpars_delta.push_back(0.1);  // y0, cm
1609   fitpars_delta.push_back(0.1);  // zslope, cm
1610   fitpars_delta.push_back(0.1);  // Z0, cm
1611 
1612   temp_fitpars.reserve(fitpars.size());
1613   for (float const fitpar : fitpars)
1614   {
1615     temp_fitpars.push_back(fitpar);
1616   }
1617 
1618   // calculate projX and projY vectors once for the optimum fit parameters
1619   if (Verbosity() > 1)
1620   {
1621     std::cout << "Call get_line to get tangent for ZF fitpars" << std::endl;
1622   }
1623 
1624   std::pair<Acts::Vector3, Acts::Vector3> const tangent = get_line_tangent(fitpars, global);
1625 
1626   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1627   get_projectionXY(surf, tangent, projX, projY);
1628 
1629   Acts::Vector3 const intersection = get_line_surface_intersection(surf, temp_fitpars);
1630 
1631   // loop over the track fit parameters
1632   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1633   {
1634     Acts::Vector3 intersection_delta[2];
1635     for (int ipm = 0; ipm < 2; ++ipm)
1636     {
1637       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1638       float const deltapm = pow(-1.0, ipm);
1639       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1640 
1641       Acts::Vector3 const temp_intersection = get_line_surface_intersection(surf, temp_fitpars);
1642       intersection_delta[ipm] = temp_intersection - intersection;
1643     }
1644     Acts::Vector3 average_intersection_delta = (intersection_delta[0] - intersection_delta[1]) / (2 * fitpars_delta[ip]);
1645 
1646     if (Verbosity() > 1)
1647     {
1648       std::cout << " average_intersection_delta / delta " << average_intersection_delta(0) << "  " << average_intersection_delta(1) << "  " << average_intersection_delta(2) << std::endl;
1649     }
1650 
1651     // calculate the change in fit for X and Y
1652     // - note negative sign from ATLAS paper is dropped here because mille wants the derivative of the fit, not the derivative of the residual
1653     lcl_derivativeX[ip] = average_intersection_delta.dot(projX);
1654     lcl_derivativeY[ip] = average_intersection_delta.dot(projY);
1655     if (Verbosity() > 1)
1656     {
1657       std::cout << " layer " << layer << " ip " << ip << "  derivativeX " << lcl_derivativeX[ip] << "  "
1658                 << " derivativeY " << lcl_derivativeY[ip] << std::endl;
1659     }
1660 
1661     temp_fitpars[ip] = fitpars[ip];
1662   }
1663 }
1664 
1665 void HelicalFitter::getLocalVtxDerivativesXY(SvtxTrack& track, const Acts::Vector3& event_vtx, const std::vector<float>& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5])
1666 {
1667   // Calculate the derivatives of the residual wrt the track parameters numerically
1668   std::vector<float> temp_fitpars;
1669   Acts::Vector3 const track_vtx(track.get_x(), track.get_y(), track.get_z());
1670 
1671   std::vector<float> fitpars_delta;
1672   fitpars_delta.push_back(0.1);  // radius, cm
1673   fitpars_delta.push_back(0.1);  // X0, cm
1674   fitpars_delta.push_back(0.1);  // Y0, cm
1675   fitpars_delta.push_back(0.1);  // zslope, cm
1676   fitpars_delta.push_back(0.1);  // Z0, cm
1677 
1678   temp_fitpars.reserve(fitpars.size());
1679   for (float const fitpar : fitpars)
1680   {
1681     temp_fitpars.push_back(fitpar);
1682   }
1683 
1684   // calculate projX and projY vectors once for the optimum fit parameters
1685   if (Verbosity() > 1)
1686   {
1687     std::cout << "Get tangent from track momentum vector" << std::endl;
1688   }
1689 
1690   Acts::Vector3 const perigeeNormal(track.get_px(), track.get_py(), track.get_pz());
1691 
1692   // loop over the track fit parameters
1693   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1694   {
1695     Acts::Vector3 localPerturb[2];
1696     Acts::Vector3 paperPerturb[2];  // for local derivative calculation like from the paper
1697 
1698     for (int ipm = 0; ipm < 2; ++ipm)
1699     {
1700       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1701       float const deltapm = pow(-1.0, ipm);
1702       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1703 
1704       Acts::Vector3 const temp_track_vtx = get_helix_vtx(event_vtx, temp_fitpars);  // temporary pca
1705       paperPerturb[ipm] = temp_track_vtx;                                           // for og local derivative calculation
1706 
1707       // old method is next two lines
1708       Acts::Vector3 const localtemp_track_vtx = globalvtxToLocalvtx(track, event_vtx, temp_track_vtx);
1709       localPerturb[ipm] = localtemp_track_vtx;
1710 
1711       if (Verbosity() > 1)
1712       {
1713         std::cout << "vtx local parameter " << ip << " with ipm " << ipm << " deltapm " << deltapm << " :" << std::endl;
1714         std::cout << " fitpars " << fitpars[ip] << " temp_fitpars " << temp_fitpars[ip] << std::endl;
1715         std::cout << " localtmp_track_vtx: " << localtemp_track_vtx << std::endl;
1716       }
1717     }
1718 
1719     Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1720     get_projectionVtxXY(track, event_vtx, projX, projY);
1721 
1722     Acts::Vector3 const average_vtxX = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1723     Acts::Vector3 const average_vtxY = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1724 
1725     // average_vtxX and average_vtxY are the numerical results in global coords for d(fit)/d(par)
1726     // The ATLAS paper formula is for the derivative of the residual, which is (measurement - fit = event vertex - track vertex)
1727     // Millepede wants the derivative of the fit, so we drop the minus sign from the paper
1728     lcl_derivativeX[ip] = average_vtxX.dot(projX);  //
1729     lcl_derivativeY[ip] = average_vtxY.dot(projY);
1730 
1731     temp_fitpars[ip] = fitpars[ip];
1732   }
1733 }
1734 
1735 void HelicalFitter::getLocalVtxDerivativesZeroFieldXY(SvtxTrack& track, const Acts::Vector3& event_vtx, const std::vector<float>& fitpars, float lcl_derivativeX[5], float lcl_derivativeY[5])
1736 {
1737   // Calculate the derivatives of the residual wrt the track parameters numerically
1738   std::vector<float> temp_fitpars;
1739   Acts::Vector3 const track_vtx(track.get_x(), track.get_y(), track.get_z());
1740 
1741   std::vector<float> fitpars_delta;
1742   fitpars_delta.push_back(0.1);  // xyslope, cm
1743   fitpars_delta.push_back(0.1);  // y0, cm
1744   fitpars_delta.push_back(0.1);  // zslope, cm
1745   fitpars_delta.push_back(0.1);  // Z0, cm
1746 
1747   temp_fitpars.reserve(fitpars.size());
1748   for (float const fitpar : fitpars)
1749   {
1750     temp_fitpars.push_back(fitpar);
1751   }
1752 
1753   Acts::Vector3 const perigeeNormal(track.get_px(), track.get_py(), track.get_pz());
1754 
1755   // loop over the track fit parameters
1756   for (unsigned int ip = 0; ip < fitpars.size(); ++ip)
1757   {
1758     Acts::Vector3 localPerturb[2];
1759     Acts::Vector3 paperPerturb[2];  // for local derivative calculation like from the paper
1760 
1761     for (int ipm = 0; ipm < 2; ++ipm)
1762     {
1763       temp_fitpars[ip] = fitpars[ip];  // reset to best fit value
1764       float const deltapm = pow(-1.0, ipm);
1765       temp_fitpars[ip] += deltapm * fitpars_delta[ip];
1766 
1767       Acts::Vector3 const temp_track_vtx = get_line_vtx(event_vtx, temp_fitpars);  // temporary pca
1768       paperPerturb[ipm] = temp_track_vtx;                                          // for og local derivative calculation
1769 
1770       // old method is next two lines
1771       Acts::Vector3 const localtemp_track_vtx = globalvtxToLocalvtx(track, event_vtx, temp_track_vtx);
1772       localPerturb[ipm] = localtemp_track_vtx;
1773 
1774       if (Verbosity() > 1)
1775       {
1776         std::cout << "vtx local parameter " << ip << " with ipm " << ipm << " deltapm " << deltapm << " :" << std::endl;
1777         std::cout << " fitpars " << fitpars[ip] << " temp_fitpars " << temp_fitpars[ip] << std::endl;
1778         std::cout << " localtmp_track_vtx: " << localtemp_track_vtx << std::endl;
1779       }
1780     }
1781 
1782     // calculate projX and projY vectors once for the optimum fit parameters
1783     Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1784     get_projectionVtxXY(track, event_vtx, projX, projY);
1785 
1786     Acts::Vector3 const average_vtxX = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1787     Acts::Vector3 const average_vtxY = (paperPerturb[0] - paperPerturb[1]) / (2 * fitpars_delta[ip]);
1788 
1789     // average_vtxX and average_vtxY are the numerical results in global coords for d(fit)/d(par)
1790     // The ATLAS paper formula is for the derivative of the residual, which is (measurement - fit = event vertex - track vertex)
1791     // Millepede wants the derivative of the fit, so we drop the minus sign from the paper
1792     lcl_derivativeX[ip] = average_vtxX.dot(projX);  //
1793     lcl_derivativeY[ip] = average_vtxY.dot(projY);
1794 
1795     temp_fitpars[ip] = fitpars[ip];
1796   }
1797 }
1798 
1799 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)
1800 {
1801   // calculate projX and projY vectors once for the optimum fit parameters
1802   std::pair<Acts::Vector3, Acts::Vector3> tangent;
1803   if (straight_line_fit)
1804   {
1805     tangent = get_line_tangent(fitpars, global);
1806   }
1807   else
1808   {
1809     tangent = get_helix_tangent(fitpars, global);
1810   }
1811 
1812   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1813   get_projectionXY(surf, tangent, projX, projY);
1814 
1815   /*
1816   // translations in polar coordinates, unit vectors must be in polar coordinates
1817   //   -- There is an implicit assumption here that unitrphi is a length
1818   // unit vector in r is the normalized radial vector pointing to the surface center
1819 
1820   Acts::Vector3 center = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;
1821   Acts::Vector3 unitr( center(0), center(1), 0.0);
1822   unitr /= unitr.norm();
1823   float phi = atan2(center(1), center(0));
1824   Acts::Vector3 unitrphi(-sin(phi), cos(phi), 0.0);  // unit vector phi in polar coordinates
1825   Acts::Vector3 unitz(0, 0, 1);
1826 
1827   glbl_derivativeX[3] = unitr.dot(projX);
1828   glbl_derivativeX[4] = unitrphi.dot(projX);
1829   glbl_derivativeX[5] = unitz.dot(projX);
1830 
1831   glbl_derivativeY[3] = unitr.dot(projY);
1832   glbl_derivativeY[4] = unitrphi.dot(projY);
1833   glbl_derivativeY[5] = unitz.dot(projY);
1834   */
1835 
1836   // translations in cartesian coordinates
1837   // Unit vectors in the global cartesian frame
1838   Acts::Vector3 const unitx(1, 0, 0);
1839   Acts::Vector3 const unity(0, 1, 0);
1840   Acts::Vector3 const unitz(0, 0, 1);
1841 
1842   glbl_derivativeX[3] = unitx.dot(projX);
1843   glbl_derivativeX[4] = unity.dot(projX);
1844   glbl_derivativeX[5] = unitz.dot(projX);
1845 
1846   glbl_derivativeY[3] = unitx.dot(projY);
1847   glbl_derivativeY[4] = unity.dot(projY);
1848   glbl_derivativeY[5] = unitz.dot(projY);
1849 
1850   /*
1851   // note: the global derivative sign should be reversed from the ATLAS paper
1852   // because mille wants the derivative of the fit, while the ATLAS paper gives the derivative of the residual.
1853   // But this sign reversal does NOT work.
1854   // Verified that not reversing the sign here produces the correct sign of the prediction of the residual..
1855   for(unsigned int i = 3; i < 6; ++i)
1856   {
1857   glbl_derivativeX[i] *= -1.0;
1858   glbl_derivativeY[i] *= -1.0;
1859   }
1860   */
1861   // rotations
1862   // need center of sensor to intersection point
1863   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;  // convert to cm
1864   Acts::Vector3 const OM = fitpoint - sensorCenter;                                                                   // this effectively reverses the sign from the ATLAS paper
1865 
1866   /*
1867   glbl_derivativeX[0] = (unitr.cross(OM)).dot(projX);
1868   glbl_derivativeX[1] = (unitrphi.cross(OM)).dot(projX);
1869   glbl_derivativeX[2] = (unitz.cross(OM)).dot(projX);
1870 
1871   glbl_derivativeY[0] = (unitr.cross(OM)).dot(projY);
1872   glbl_derivativeY[1] = (unitrphi.cross(OM)).dot(projY);
1873   glbl_derivativeY[2] = (unitz.cross(OM)).dot(projY);
1874   */
1875 
1876   glbl_derivativeX[0] = (unitx.cross(OM)).dot(projX);
1877   glbl_derivativeX[1] = (unity.cross(OM)).dot(projX);
1878   glbl_derivativeX[2] = (unitz.cross(OM)).dot(projX);
1879 
1880   glbl_derivativeY[0] = (unitx.cross(OM)).dot(projY);
1881   glbl_derivativeY[1] = (unity.cross(OM)).dot(projY);
1882   glbl_derivativeY[2] = (unitz.cross(OM)).dot(projY);
1883 
1884   if (Verbosity() > 1)
1885   {
1886     for (int ip = 0; ip < 6; ++ip)
1887     {
1888       std::cout << " layer " << layer << " ip " << ip
1889                 << "  glbl_derivativeX " << glbl_derivativeX[ip] << "  "
1890                 << " glbl_derivativeY " << glbl_derivativeY[ip] << std::endl;
1891     }
1892   }
1893 
1894   /*
1895   if(Verbosity() > 2)
1896     {
1897       std::cout << "    unitr mag: " << unitr.norm() << " unitr: " << std::endl << unitr << std::endl;
1898       std::cout << "    unitrphi mag: " << unitrphi.norm() << " unitrphi: " << std::endl << unitrphi << std::endl;
1899       std::cout << "    unitz mag: " << unitz.norm() << " unitz: " << std::endl << unitz << std::endl;
1900       std::cout << "    projX: " << std::endl << projX << std::endl;
1901       std::cout << "    projY: " << std::endl << projY << std::endl;
1902     }
1903   */
1904 }
1905 
1906 void HelicalFitter::getGlobalVtxDerivativesXY(SvtxTrack& track, const Acts::Vector3& event_vtx, float glbl_derivativeX[3], float glbl_derivativeY[3])
1907 {
1908   Acts::Vector3 const unitx(1, 0, 0);
1909   Acts::Vector3 const unity(0, 1, 0);
1910   Acts::Vector3 const unitz(0, 0, 1);
1911 
1912   Acts::Vector3 const track_vtx(track.get_x(), track.get_y(), track.get_z());
1913   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
1914 
1915   // calculate projX and projY vectors once for the optimum fit parameters
1916   Acts::Vector3 projX(0, 0, 0), projY(0, 0, 0);
1917   get_projectionVtxXY(track, event_vtx, projX, projY);
1918 
1919   // translations
1920   glbl_derivativeX[0] = unitx.dot(projX);
1921   glbl_derivativeX[1] = unity.dot(projX);
1922   glbl_derivativeX[2] = unitz.dot(projX);
1923   glbl_derivativeY[0] = unitx.dot(projY);
1924   glbl_derivativeY[1] = unity.dot(projY);
1925   glbl_derivativeY[2] = unitz.dot(projY);
1926 
1927   // The derivation in the ATLAS paper used above gives the derivative of the residual (= measurement - fit)
1928   // pede wants the derivative of the fit, so we reverse that - valid if our residual is (event vertex - track vertex)
1929 
1930   // Verified that reversing these signs produces the correct sign and magnitude for the prediction of the residual.
1931   // tested this by offsetting the simulated event vertex with zero misalignments. Pede fit reproduced simulated (xvtx, yvtx) within 7%.
1932   //   -- test gave zero for zvtx param, since this is determined relative to the measured event z vertex.
1933   for (int i = 0; i < 3; ++i)
1934   {
1935     glbl_derivativeX[i] *= -1.0;
1936     glbl_derivativeY[i] *= -1.0;
1937   }
1938 }
1939 
1940 void HelicalFitter::get_projectionXY(const Surface& surf, const std::pair<Acts::Vector3, Acts::Vector3>& tangent, Acts::Vector3& projX, Acts::Vector3& projY)
1941 {
1942   // we only need the direction part of the tangent
1943   Acts::Vector3 const tanvec = tangent.second;
1944   // get the plane of the surface
1945   Acts::Vector3 const sensorCenter = surf->center(_tGeometry->geometry().getGeoContext()) / Acts::UnitConstants::cm;  // convert to cm
1946 
1947   // We need the three unit vectors in the sensor local frame, transformed to the global frame
1948   //====================================================================
1949   // sensorNormal is the Z vector in the global frame
1950   Acts::Vector3 const Z = -surf->normal(_tGeometry->geometry().getGeoContext(), Acts::Vector3(1, 1, 1), Acts::Vector3(1, 1, 1));
1951   // get surface X and Y unit vectors in global frame
1952   // transform Xlocal = 1.0 to global, subtract the surface center, normalize to 1
1953   Acts::Vector3 const xloc(1.0, 0.0, 0.0);  // local coord unit vector in x
1954   Acts::Vector3 xglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (xloc * Acts::UnitConstants::cm);
1955   xglob /= Acts::UnitConstants::cm;
1956   Acts::Vector3 const yloc(0.0, 1.0, 0.0);
1957   Acts::Vector3 yglob = surf->transform(_tGeometry->geometry().getGeoContext()) * (yloc * Acts::UnitConstants::cm);
1958   yglob /= Acts::UnitConstants::cm;
1959   // These are the local frame unit vectors transformed to the global frame
1960   Acts::Vector3 const X = (xglob - sensorCenter) / (xglob - sensorCenter).norm();
1961   Acts::Vector3 const Y = (yglob - sensorCenter) / (yglob - sensorCenter).norm();
1962 
1963   // see equation 31 of the ATLAS paper (and discussion) for this
1964   // The unit vector in the local frame transformed to the global frame (X),
1965   // minus Z scaled by the track vector overlap with X, divided by the track vector overlap with Z.
1966   projX = X - (tanvec.dot(X) / tanvec.dot(Z)) * Z;
1967   projY = Y - (tanvec.dot(Y) / tanvec.dot(Z)) * Z;
1968 
1969   if(Verbosity() > 1)
1970     {
1971       std::cout << "    tanvec: " << std::endl << tanvec << std::endl;
1972       std::cout << "    X: " << std::endl << X << std::endl;
1973       std::cout << "    Y: " << std::endl << Y << std::endl;
1974       std::cout << "    Z: " << std::endl << Z << std::endl;
1975 
1976       std::cout << "    projX: " << std::endl << projX << std::endl;
1977       std::cout << "    projY: " << std::endl << projY << std::endl;
1978     }
1979 
1980   return;
1981 }
1982 
1983 void HelicalFitter::get_projectionVtxXY(SvtxTrack& track, const Acts::Vector3& event_vtx, Acts::Vector3& projX, Acts::Vector3& projY)
1984 {
1985   Acts::Vector3 tanvec(track.get_px(), track.get_py(), track.get_pz());
1986   Acts::Vector3 normal(track.get_px(), track.get_py(), 0);
1987 
1988   tanvec /= tanvec.norm();
1989   normal /= normal.norm();
1990 
1991   // get surface X and Y unit vectors in global frame
1992   Acts::Vector3 const xloc(1.0, 0.0, 0.0);
1993   Acts::Vector3 const yloc(0.0, 0.0, 1.0);  // local y
1994   Acts::Vector3 const xglob = localvtxToGlobalvtx(track, event_vtx, xloc);
1995   Acts::Vector3 const yglob = yloc + event_vtx;
1996   Acts::Vector3 const X = (xglob - event_vtx) / (xglob - event_vtx).norm();  // local unit vector transformed to global coordinates
1997   Acts::Vector3 const Y = (yglob - event_vtx) / (yglob - event_vtx).norm();
1998 
1999   // see equation 31 of the ATLAS paper (and discussion) for this
2000   projX = X - (tanvec.dot(X) / tanvec.dot(normal)) * normal;
2001   projY = Y - (tanvec.dot(Y) / tanvec.dot(normal)) * normal;
2002   return;
2003 }
2004 
2005 unsigned int HelicalFitter::addSiliconClusters(std::vector<float>& fitpars, std::vector<Acts::Vector3>& global_vec, std::vector<TrkrDefs::cluskey>& cluskey_vec)
2006 {
2007   return TrackFitUtils::addClusters(fitpars, dca_cut, _tGeometry, _cluster_map, global_vec, cluskey_vec, 0, 6);
2008 }
2009 bool HelicalFitter::is_vertex_param_fixed(unsigned int param)
2010 {
2011   bool ret = false;
2012   auto it = fixed_vertex_params.find(param);
2013   if (it != fixed_vertex_params.end())
2014   {
2015     ret = true;
2016   }
2017   return ret;
2018 }
2019 bool HelicalFitter::is_intt_layer_fixed(unsigned int layer)
2020 {
2021   bool ret = false;
2022   auto it = fixed_intt_layers.find(layer);
2023   if (it != fixed_intt_layers.end())
2024   {
2025     ret = true;
2026   }
2027 
2028   return ret;
2029 }
2030 
2031 bool HelicalFitter::is_mvtx_layer_fixed(unsigned int layer, unsigned int clamshell)
2032 {
2033   bool ret = false;
2034 
2035   std::pair const pair = std::make_pair(layer, clamshell);
2036   auto it = fixed_mvtx_layers.find(pair);
2037   if (it != fixed_mvtx_layers.end())
2038   {
2039     ret = true;
2040   }
2041   return ret;
2042 }
2043 
2044 void HelicalFitter::set_intt_layer_fixed(unsigned int layer)
2045 {
2046   fixed_intt_layers.insert(layer);
2047 }
2048 
2049 void HelicalFitter::set_mvtx_layer_fixed(unsigned int layer, unsigned int clamshell)
2050 {
2051   fixed_mvtx_layers.insert(std::make_pair(layer, clamshell));
2052 }
2053 
2054 bool HelicalFitter::is_layer_param_fixed(unsigned int layer, unsigned int param)
2055 {
2056   bool ret = false;
2057   std::pair<unsigned int, unsigned int> const pair = std::make_pair(layer, param);
2058   auto it = fixed_layer_params.find(pair);
2059   if (it != fixed_layer_params.end())
2060   {
2061     ret = true;
2062   }
2063 
2064   return ret;
2065 }
2066 
2067 void HelicalFitter::set_layer_param_fixed(unsigned int layer, unsigned int param)
2068 {
2069   std::pair<unsigned int, unsigned int> const pair = std::make_pair(layer, param);
2070   fixed_layer_params.insert(pair);
2071 }
2072 
2073 void HelicalFitter::set_tpc_sector_fixed(unsigned int region, unsigned int sector, unsigned int side)
2074 {
2075   // make a combined subsector index
2076   unsigned int const subsector = region * 24 + side * 12 + sector;
2077   fixed_sectors.insert(subsector);
2078 }
2079 
2080 bool HelicalFitter::is_tpc_sector_fixed(unsigned int layer, unsigned int sector, unsigned int side)
2081 {
2082   bool ret = false;
2083   unsigned int const region = AlignmentDefs::getTpcRegion(layer);
2084   unsigned int const subsector = region * 24 + side * 12 + sector;
2085   auto it = fixed_sectors.find(subsector);
2086   if (it != fixed_sectors.end())
2087   {
2088     ret = true;
2089   }
2090 
2091   return ret;
2092 }
2093 
2094 void HelicalFitter::correctTpcGlobalPositions(std::vector<Acts::Vector3> global_vec, const std::vector<TrkrDefs::cluskey> &cluskey_vec)
2095 {
2096   for (unsigned int iclus = 0; iclus < cluskey_vec.size(); ++iclus)
2097   {
2098     auto cluskey = cluskey_vec[iclus];
2099     auto global = global_vec[iclus];
2100     const unsigned int trkrId = TrkrDefs::getTrkrId(cluskey);
2101     if (trkrId == TrkrDefs::tpcId)
2102     {
2103       // have to add corrections for TPC clusters after transformation to global
2104       int const crossing = 0;  // for now
2105       makeTpcGlobalCorrections(cluskey, crossing, global);
2106       global_vec[iclus] = global;
2107     }
2108   }
2109 }
2110 
2111 float HelicalFitter::getVertexResidual(Acts::Vector3 vtx)
2112 {
2113   float const phi = atan2(vtx(1), vtx(0));
2114   float const r = vtx(0) / cos(phi);
2115   float const test_r = sqrt(vtx(0) * vtx(0) + vtx(1) * vtx(1));
2116 
2117   if (Verbosity() > 1)
2118   {
2119     std::cout << "my method position: " << vtx << std::endl;
2120     std::cout << "r " << r << " phi: " << phi * 180 / M_PI << " test_r" << test_r << std::endl;
2121   }
2122   return r;
2123 }
2124 
2125 void HelicalFitter::get_dca(SvtxTrack& track, float& dca3dxy, float& dca3dz, float& dca3dxysigma, float& dca3dzsigma, const Acts::Vector3& event_vertex)
2126 {
2127   // give trackseed
2128   dca3dxy = NAN;
2129   Acts::Vector3 track_vtx(track.get_x(), track.get_y(), track.get_z());
2130   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2131 
2132   track_vtx -= event_vertex;  // difference between track_vertex and event_vtx
2133 
2134   Acts::ActsSquareMatrix<3> posCov;
2135   for (int i = 0; i < 3; ++i)
2136   {
2137     for (int j = 0; j < 3; ++j)
2138     {
2139       posCov(i, j) = track.get_error(i, j);
2140     }
2141   }
2142 
2143   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2144 
2145   float phi = atan2(r(1), r(0));
2146   Acts::RotationMatrix3 rot;
2147   Acts::RotationMatrix3 rot_T;
2148   phi *= -1;
2149   rot(0, 0) = cos(phi);
2150   rot(0, 1) = -sin(phi);
2151   rot(0, 2) = 0;
2152   rot(1, 0) = sin(phi);
2153   rot(1, 1) = cos(phi);
2154   rot(1, 2) = 0;
2155   rot(2, 0) = 0;
2156   rot(2, 1) = 0;
2157   rot(2, 2) = 1;
2158   rot_T = rot.transpose();
2159 
2160   Acts::Vector3 pos_R = rot * track_vtx;
2161   Acts::ActsSquareMatrix<3> rotCov = rot * posCov * rot_T;
2162   dca3dxy = pos_R(0);
2163   dca3dz = pos_R(2);
2164   dca3dxysigma = sqrt(rotCov(0, 0));
2165   dca3dzsigma = sqrt(rotCov(2, 2));
2166 
2167   if (Verbosity() > 1)
2168   {
2169     std::cout << " Helix: momentum.cross(z): " << r << " phi: " << phi * 180 / M_PI << std::endl;
2170     std::cout << "dca3dxy " << dca3dxy << " dca3dz: " << dca3dz << " pos_R(1): " << pos_R(1) << " dca3dxysigma " << dca3dxysigma << " dca3dzsigma " << dca3dzsigma << std::endl;
2171   }
2172 }
2173 
2174 void HelicalFitter::get_dca_zero_field(SvtxTrack& track, float& dca3dxy, float& dca3dz, float& dca3dxysigma, float& dca3dzsigma, const Acts::Vector3& event_vertex)
2175 {
2176   dca3dxy = NAN;
2177   // This is (pca2d(0), pca2d(1), Z0)
2178   Acts::Vector3 track_vtx(track.get_x(), track.get_y(), track.get_z());
2179   track_vtx -= event_vertex;  // difference between track_vertex and event_vtx
2180 
2181   // get unit direction vector for zero field track
2182   // for zero field case this is the tangent unit vector
2183   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2184 
2185   Acts::ActsSquareMatrix<3> posCov;
2186   for (int i = 0; i < 3; ++i)
2187   {
2188     for (int j = 0; j < 3; ++j)
2189     {
2190       posCov(i, j) = track.get_error(i, j);
2191     }
2192   }
2193 
2194   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2195 
2196   float phi = atan2(r(1), r(0));
2197   Acts::RotationMatrix3 rot;
2198   Acts::RotationMatrix3 rot_T;
2199   phi *= -1;
2200   rot(0, 0) = cos(phi);
2201   rot(0, 1) = -sin(phi);
2202   rot(0, 2) = 0;
2203   rot(1, 0) = sin(phi);
2204   rot(1, 1) = cos(phi);
2205   rot(1, 2) = 0;
2206   rot(2, 0) = 0;
2207   rot(2, 1) = 0;
2208   rot(2, 2) = 1;
2209   rot_T = rot.transpose();
2210 
2211   Acts::Vector3 pos_R = rot * track_vtx;
2212   Acts::ActsSquareMatrix<3> rotCov = rot * posCov * rot_T;
2213   dca3dxy = pos_R(0);
2214   dca3dz = pos_R(2);
2215   dca3dxysigma = sqrt(rotCov(0, 0));
2216   dca3dzsigma = sqrt(rotCov(2, 2));
2217 
2218   if (Verbosity() > 1)
2219   {
2220     std::cout << " Zero Field: momentum.cross(z): " << r << " phi (deg): " << phi * 180 / M_PI << std::endl;
2221     std::cout << "dca3dxy " << dca3dxy << " dca3dz: " << dca3dz << " pos_R(1): " << pos_R(1) << " dca3dxysigma " << dca3dxysigma << " dca3dzsigma " << dca3dzsigma << std::endl;
2222   }
2223 }
2224 
2225 Acts::Vector3 HelicalFitter::globalvtxToLocalvtx(SvtxTrack& track, const Acts::Vector3& event_vertex)
2226 {
2227   Acts::Vector3 track_vtx(track.get_x(), track.get_y(), track.get_z());
2228   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2229   track_vtx -= event_vertex;  // difference between track_vertex and event_vtx
2230 
2231   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2232   float phi = atan2(r(1), r(0));
2233   Acts::RotationMatrix3 rot;
2234   Acts::RotationMatrix3 rot_T;
2235   phi *= -1;
2236   rot(0, 0) = cos(phi);
2237   rot(0, 1) = -sin(phi);
2238   rot(0, 2) = 0;
2239   rot(1, 0) = sin(phi);
2240   rot(1, 1) = cos(phi);
2241   rot(1, 2) = 0;
2242   rot(2, 0) = 0;
2243   rot(2, 1) = 0;
2244   rot(2, 2) = 1;
2245   rot_T = rot.transpose();
2246 
2247   Acts::Vector3 pos_R = rot * track_vtx;
2248 
2249   if (Verbosity() > 1)
2250   {
2251     std::cout << " momentum X z: " << r << " phi: " << phi * 180 / M_PI << std::endl;
2252     std::cout << " pos_R(0): " << pos_R(0) << " pos_R(1): " << pos_R(1) << std::endl;
2253   }
2254   return pos_R;
2255 }
2256 
2257 Acts::Vector3 HelicalFitter::globalvtxToLocalvtx(SvtxTrack& track, const Acts::Vector3& event_vertex, Acts::Vector3 PCA)
2258 {
2259   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2260   PCA -= event_vertex;  // difference between track_vertex and event_vtx
2261 
2262   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2263   float phi = atan2(r(1), r(0));
2264   Acts::RotationMatrix3 rot;
2265   Acts::RotationMatrix3 rot_T;
2266   phi *= -1;
2267   rot(0, 0) = cos(phi);
2268   rot(0, 1) = -sin(phi);
2269   rot(0, 2) = 0;
2270   rot(1, 0) = sin(phi);
2271   rot(1, 1) = cos(phi);
2272   rot(1, 2) = 0;
2273   rot(2, 0) = 0;
2274   rot(2, 1) = 0;
2275   rot(2, 2) = 1;
2276   rot_T = rot.transpose();
2277 
2278   Acts::Vector3 pos_R = rot * PCA;
2279 
2280   if (Verbosity() > 1)
2281   {
2282     std::cout << " momentum X z: " << r << " phi: " << phi * 180 / M_PI << std::endl;
2283     std::cout << " pos_R(0): " << pos_R(0) << " pos_R(1): " << pos_R(1) << std::endl;
2284   }
2285   return pos_R;
2286 }
2287 
2288 Acts::Vector3 HelicalFitter::localvtxToGlobalvtx(SvtxTrack& track, const Acts::Vector3& event_vtx, const Acts::Vector3& local)
2289 {
2290   // Acts::Vector3 track_vtx = local;
2291   Acts::Vector3 const mom(track.get_px(), track.get_py(), track.get_pz());
2292   // std::cout << "first pos: " << pos << " mom: " << mom << std::endl;
2293   // local -= event_vertex; // difference between track_vertex and event_vtx
2294 
2295   Acts::Vector3 r = mom.cross(Acts::Vector3(0., 0., 1.));
2296   float const phi = atan2(r(1), r(0));
2297   Acts::RotationMatrix3 rot;
2298   Acts::RotationMatrix3 rot_T;
2299   // phi *= -1;
2300   rot(0, 0) = cos(phi);
2301   rot(0, 1) = -sin(phi);
2302   rot(0, 2) = 0;
2303   rot(1, 0) = sin(phi);
2304   rot(1, 1) = cos(phi);
2305   rot(1, 2) = 0;
2306   rot(2, 0) = 0;
2307   rot(2, 1) = 0;
2308   rot(2, 2) = 1;
2309 
2310   rot_T = rot.transpose();
2311 
2312   Acts::Vector3 pos_R = rot * local;
2313   pos_R += event_vtx;
2314   if (Verbosity() > 1)
2315   {
2316     std::cout << " momentum X z: " << r << " phi: " << phi * 180 / M_PI << std::endl;
2317     std::cout << " pos_R(0): " << pos_R(0) << " pos_R(1): " << pos_R(1) << "pos_R(2): " << pos_R(2) << std::endl;
2318   }
2319   return pos_R;
2320 }