@@ -71,7 +71,7 @@ struct NDPiecewisePolynomialContainer {
7171// /
7272// / For usage see: testMultivarPolynomials.cxx
7373// /
74- // / TODO: add possibillity to perform the fits on scattered data points (+add weighting of points)
74+ // / TODO: add possibillity to perform the fits with weighting of points
7575// /
7676// / \tparam Dim number of dimensions
7777// / \tparam Degree degree of the polynomials
@@ -184,6 +184,11 @@ class NDPiecewisePolynomials : public FlatObject
184184 // / \param nAuxiliaryPoints number of points which will be used for the fits (should be at least 2)
185185 void performFits (const std::function<double (const double x[/* Dim */ ])>& func, const unsigned int nAuxiliaryPoints[/* Dim */ ]);
186186
187+ // / perform the polynomial fits on scatter points
188+ // / \param x scatter points used to make the fits of size 'y.size() * Dim' as in TLinearFitter
189+ // / \param y response values
190+ void performFits (const std::vector<float >& x, const std::vector<float >& y);
191+
187192 // / load parameters from input file (which were written using the writeToFile method)
188193 // / \param inpf input file
189194 // / \param name name of the object in the file
@@ -537,7 +542,7 @@ void NDPiecewisePolynomials<Dim, Degree, InteractionOnly>::performFits(const std
537542 const bool debug = !(++counter % printDebugForNFits);
538543 if (debug) {
539544#ifndef GPUCA_ALIROOT_LIB
540- LOGP (info, " Peforming fit {} out of {}" , counter, nTotalFits);
545+ LOGP (info, " Performing fit {} out of {}" , counter, nTotalFits);
541546#endif
542547 }
543548
@@ -554,6 +559,95 @@ void NDPiecewisePolynomials<Dim, Degree, InteractionOnly>::performFits(const std
554559 }
555560}
556561
562+ template <unsigned int Dim, unsigned int Degree, bool InteractionOnly>
563+ void NDPiecewisePolynomials<Dim, Degree, InteractionOnly>::performFits(const std::vector<float >& x, const std::vector<float >& y)
564+ {
565+ const int nTotalFits = getNPolynomials ();
566+ #ifndef GPUCA_ALIROOT_LIB
567+ LOGP (info, " Perform fitting of {}D-Polynomials of degree {} for a total of {} fits." , Dim, Degree, nTotalFits);
568+ #endif
569+
570+ // approximate number of points
571+ unsigned int nPoints = 2 * y.size () / nTotalFits;
572+
573+ // polynomial index -> indices to datapoints
574+ std::unordered_map<int , std::vector<size_t >> dataPointsIndices;
575+ for (int i = 0 ; i < nTotalFits; ++i) {
576+ dataPointsIndices[i].reserve (nPoints);
577+ }
578+
579+ // check for each data point which polynomial to use
580+ for (size_t i = 0 ; i < y.size (); ++i) {
581+ std::array<int , Dim> index;
582+ float xVal[Dim];
583+ std::copy (x.begin () + i * Dim, x.begin () + i * Dim + Dim, xVal);
584+ setIndex<Dim - 1 >(xVal, index.data ());
585+
586+ std::array<int , Dim> indexClamped{index};
587+ clamp<Dim - 1 >(xVal, indexClamped.data ());
588+
589+ // check if data points are in the grid
590+ if (index == indexClamped) {
591+ // index of the polyniomial
592+ const unsigned int idx = getDataIndex (index.data ()) / MultivariatePolynomialParametersHelper::getNParameters (Degree, Dim, InteractionOnly);
593+
594+ // store index to data point
595+ dataPointsIndices[idx].emplace_back (i);
596+ }
597+ }
598+
599+ // for fitting
600+ MultivariatePolynomialHelper<0 , 0 , false > pol (Dim, Degree, InteractionOnly);
601+ TLinearFitter fitter = pol.getTLinearFitter ();
602+
603+ unsigned int counter = 0 ;
604+ const int printDebugForNFits = int (nTotalFits / 20 ) + 1 ;
605+
606+ // temp storage for x and y values for fitting
607+ std::vector<double > xCords;
608+ std::vector<double > response;
609+
610+ for (int i = 0 ; i < nTotalFits; ++i) {
611+ const bool debug = !(++counter % printDebugForNFits);
612+ if (debug) {
613+ #ifndef GPUCA_ALIROOT_LIB
614+ LOGP (info, " Performing fit {} out of {}" , counter, nTotalFits);
615+ #endif
616+ }
617+
618+ // store values for fitting
619+ if (dataPointsIndices[i].empty ()) {
620+ #ifndef GPUCA_ALIROOT_LIB
621+ LOGP (info, " No data points to fit" );
622+ #endif
623+ continue ;
624+ }
625+
626+ const auto nP = dataPointsIndices[i].size ();
627+ xCords.reserve (Dim * nP);
628+ response.reserve (nP);
629+ xCords.clear ();
630+ response.clear ();
631+
632+ // add datapoints to fit
633+ for (size_t j = 0 ; j < nP; ++j) {
634+ const size_t idxOrig = dataPointsIndices[i][j];
635+
636+ // insert x values at the end of xCords
637+ const int idxXStart = idxOrig * Dim;
638+ xCords.insert (xCords.end (), x.begin () + idxXStart, x.begin () + idxXStart + Dim);
639+ response.emplace_back (y[idxOrig]);
640+ }
641+
642+ // perform the fit on the points TODO make errors configurable
643+ std::vector<double > error;
644+ const auto params = MultivariatePolynomialHelper<0 , 0 , false >::fit (fitter, xCords, response, error, true );
645+
646+ // store parameters
647+ std::copy (params.begin (), params.end (), &mParams [i * MultivariatePolynomialParametersHelper::getNParameters (Degree, Dim, InteractionOnly)]);
648+ }
649+ }
650+
557651template <unsigned int Dim, unsigned int Degree, bool InteractionOnly>
558652void NDPiecewisePolynomials<Dim, Degree, InteractionOnly>::fitInnerGrid(const std::function<double (const double x[/* Dim */ ])>& func, const unsigned int nAuxiliaryPoints[/* Dim */ ], const int currentIndex[/* Dim */ ], TLinearFitter& fitter, std::vector<double >& xCords, std::vector<double >& response)
559653{
0 commit comments