#include "Road.h"
#include "TreeWalk.h"
#include "Projection.h"
#include "Hitpattern.h"
#include "Hit.h"
#include "WirePlane.h"
#include "Helper.h"
#include "TMath.h"
#include "TBits.h"
#include "TVector2.h"
#include <iostream>
#include <algorithm>
#include <numeric>
#include <map>
#include <utility>
using namespace std;
ClassImp(TreeSearch::Road)
ClassImp(TreeSearch::Road::Point)
ClassImp(TreeSearch::Road::Corners)
namespace TreeSearch {
typedef Hset_t::iterator siter_t;
#define ALL(c) (c).begin(), (c).end()
static const size_t kNcorner = 5;
static const UInt_t kMaxNhitCombos = 1000;
static inline
UInt_t GetOuterBits( UInt_t p )
{
static const char LogTable256[] = {
0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
};
UInt_t ret = 0;
if( p != 0 ) {
register UInt_t t, tt;
if( (tt = p >> 16) )
ret = 1U << ((t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]);
else
ret = 1U << ((t = p >> 8) ? 8 + LogTable256[t] : LogTable256[p]);
t = 1;
while( (p & t) == 0 )
t <<= 1;
ret |= t;
}
return ret;
}
struct BuildInfo_t {
HitSet fCluster;
vector< pair<UShort_t,UShort_t> >
fLimits;
UInt_t fOuterBits;
BuildInfo_t() : fOuterBits(0) {}
BuildInfo_t( const Node_t& node )
: fCluster(node.second),
fOuterBits(GetOuterBits(node.second.plane_pattern))
{
const NodeDescriptor& nd = node.first;
assert( fCluster.plane_pattern > 0 and fCluster.nplanes > 0 );
UInt_t npl = nd.link->GetPattern()->GetNbits();
fLimits.reserve( npl );
for( UInt_t i = 0; i < npl; ++i )
fLimits.push_back( make_pair(nd[i], nd[i]+1) );
}
void ExpandWidth( const NodeDescriptor& nd ) {
UInt_t npl = nd.link->GetPattern()->GetNbits();
assert( fLimits.size() == npl or fLimits.empty() );
if( fLimits.empty() )
fLimits.assign( npl, make_pair(kMaxUShort, 0) );
for( UInt_t i = npl; i; ) { --i;
pair<UShort_t,UShort_t>& lim = fLimits[i];
UInt_t bin = nd[i];
if( bin < lim.first )
lim.first = bin;
if( bin+1 > lim.second )
lim.second = bin+1;
}
}
};
class GetBinX
: public unary_function< pair<Double_t,Double_t>, pair<UInt_t,UInt_t> >
{
private:
const Hitpattern* fHpat;
public:
explicit GetBinX( const Hitpattern* hpat ) : fHpat(hpat) {}
pair<Double_t,Double_t> operator() ( const pair<UInt_t,UInt_t>& bin ) const
{
Double_t lo = static_cast<Double_t>(bin.first) * fHpat->GetBinWidth()
- fHpat->GetOffset();
Double_t hi = static_cast<Double_t>(bin.second) * fHpat->GetBinWidth()
- fHpat->GetOffset();
return make_pair(lo,hi);
}
};
Road::Road( const Projection* proj )
: TObject(), fProjection(proj), fZL(kBig), fZU(kBig),
fPos(kBig), fSlope(kBig), fChi2(kBig), fDof(kMaxUInt), fGood(true),
fTrack(0), fBuild(0), fGrown(false)
#ifdef TESTCODE
, fNfits(0)
#endif
{
assert(fProjection);
memset( fCornerX, 0, kNcorner*sizeof(Double_t) );
fV[2] = fV[1] = fV[0] = kBig;
fPoints.reserve( fProjection->GetNplanes() );
fBuild = new BuildInfo_t;
}
Road::Road( const Node_t& nd, const Projection* proj )
: TObject(), fPatterns(1,&nd), fProjection(proj), fZL(kBig), fZU(kBig),
fPos(kBig), fSlope(kBig), fChi2(kBig), fDof(kMaxUInt), fGood(true),
fTrack(0), fBuild(0), fGrown(true)
#ifdef TESTCODE
, fNfits(0)
#endif
{
assert( fProjection );
assert( CheckMatch(nd.second.hits) );
memset( fCornerX, 0, kNcorner*sizeof(Double_t) );
fV[2] = fV[1] = fV[0] = kBig;
fPoints.reserve( fProjection->GetNplanes() );
fBuild = new BuildInfo_t(nd);
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) {
cout << "New Road:" << endl;
nd.first.Print();
PrintHits(nd.second.hits);
}
#endif
}
Road::Road( const Road& orig ) :
TObject(orig), fPatterns(orig.fPatterns), fHits(orig.fHits),
fGrown(orig.fGrown)
#ifdef TESTCODE
, fNfits(orig.fNfits)
#endif
{
size_t nbytes = (char*)&fTrack - (char*)&fProjection + sizeof(fTrack);
memcpy( &fProjection, &orig.fProjection, nbytes );
CopyPointData( orig );
if( orig.fBuild )
fBuild = new BuildInfo_t( *orig.fBuild );
else
fBuild = 0;
}
Road& Road::operator=( const Road& rhs )
{
if( this != &rhs ) {
TObject::operator=(rhs);
fPatterns = rhs.fPatterns;
fHits = rhs.fHits;
size_t nbytes = (char*)&fTrack - (char*)&fProjection + sizeof(fTrack);
memcpy( &fProjection, &rhs.fProjection, nbytes );
fFitCoord.clear();
DeleteContainerOfContainers( fPoints );
CopyPointData( rhs );
delete fBuild;
if( rhs.fBuild )
fBuild = new BuildInfo_t( *rhs.fBuild );
else
fBuild = 0;
fGrown = rhs.fGrown;
#ifdef TESTCODE
fNfits = rhs.fNfits;
#endif
}
return *this;
}
Road::~Road()
{
DeleteContainerOfContainers( fPoints );
delete fBuild;
}
void Road::CopyPointData( const Road& orig )
{
if( orig.fPoints.empty() )
assert( orig.fFitCoord.empty() );
else {
typedef map<Point*,Point*> Pmap_t;
Pmap_t xref;
fPoints.resize( orig.fPoints.size() );
for( vector<Pvec_t>::size_type i = 0; i < orig.fPoints.size(); ++i ) {
const Pvec_t& old_planepoints = orig.fPoints[i];
fPoints[i].reserve( old_planepoints.size() );
for( Pvec_t::const_iterator it = old_planepoints.begin(); it !=
old_planepoints.end(); ++it ) {
Point* old_point = *it;
Point* new_point = new Point( *old_point );
fPoints[i].push_back( new_point );
pair<Pmap_t::iterator,bool>
ins = xref.insert( make_pair(old_point,new_point) );
assert( ins.second );
}
}
fFitCoord.reserve( orig.fFitCoord.size() );
for( Pvec_t::const_iterator it = orig.fFitCoord.begin(); it !=
orig.fFitCoord.end(); ++it ) {
Point* old_point = *it;
Pmap_t::iterator found = xref.find( old_point );
assert( found != xref.end() );
fFitCoord.push_back( (*found).second );
}
}
}
inline
Bool_t Road::CheckMatch( const Hset_t& hits ) const
{
return HitSet::CheckMatch( hits, fProjection->GetPlaneCombos() );
}
inline
Bool_t Road::IsInBackRange( const NodeDescriptor& nd ) const
{
assert( fBuild && !fBuild->fLimits.empty() );
UInt_t bdist = fProjection->GetBinMaxDistB();
return ( nd.End() + bdist >= fBuild->fLimits.back().first and
nd.End() < fBuild->fLimits.back().second + bdist );
}
Bool_t Road::IsInFrontRange( const NodeDescriptor& nd ) const
{
assert( fBuild && !fBuild->fLimits.empty() );
UInt_t fdist = fProjection->GetBinMaxDistF();
return ( nd.Start() + fdist >= fBuild->fLimits.front().first and
nd.Start() < fBuild->fLimits.front().second + fdist );
}
Bool_t Road::Add( const Node_t& nd )
{
assert(fBuild);
assert( fPatterns.empty() || IsInFrontRange(nd.first) );
const HitSet& new_set = nd.second;
const Hset_t& new_hits = nd.second.hits;
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) {
cout << "Adding:" << endl;
nd.first.Print();
PrintHits(new_hits);
}
#endif
UInt_t hitdist = fProjection->GetHitMaxDist();
if( fPatterns.empty() ) {
assert( CheckMatch(new_hits) );
assert( new_set.nplanes > 0 && new_set.plane_pattern > 0 );
fBuild->fCluster = new_set;
fBuild->ExpandWidth( nd.first );
fBuild->fOuterBits = GetOuterBits( fBuild->fCluster.plane_pattern );
fGrown = true;
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) {
cout << "New cluster:" << endl;
PrintHits( new_hits );
}
#endif
}
else if( IsInBackRange(nd.first) and
fBuild->fCluster.IsSimilarTo(new_set,hitdist) ) {
if( hitdist > 0 ) {
UInt_t outer_bits = fBuild->fOuterBits;
for( siter_t it = new_hits.begin(); it != new_hits.end(); ++it ) {
pair< siter_t, bool > ins = fBuild->fCluster.hits.insert(*it);
if( ins.second and TESTBIT(outer_bits,(*it)->GetPlaneNum()) )
fGrown = true;
}
if( (outer_bits & new_set.plane_pattern) == outer_bits )
fBuild->ExpandWidth( nd.first );
}
else if( new_set.nplanes == fBuild->fCluster.nplanes ) {
fBuild->ExpandWidth( nd.first );
}
}
else {
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 )
cout << "Not a subset of this road" << endl;
#endif
return false;
}
fPatterns.push_back(&nd);
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 )
cout << "new npat = " << fPatterns.size() << endl;
#endif
return true;
}
void Road::Finish()
{
assert(fBuild);
for( list<const Node_t*>::iterator it = fPatterns.begin(); it !=
fPatterns.end(); ++it ) {
(**it).second.used = 1;
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) {
cout << "used pat = ";
(**it).first.Print();
}
#endif
}
assert( fHits.empty() );
fHits.swap( fBuild->fCluster.hits );
vector< pair<Double_t,Double_t> > edgpos;
UInt_t npl = fProjection->GetNplanes(), lastpl = npl-1;
edgpos.reserve( npl );
GetBinX binx( fProjection->GetHitpattern() );
transform( ALL(fBuild->fLimits), back_inserter(edgpos), binx );
TVector2 LL( edgpos.front().first, fProjection->GetPlaneZ(0) );
TVector2 LR( edgpos.front().second, fProjection->GetPlaneZ(0) );
TVector2 UL( edgpos.back().first, fProjection->GetPlaneZ(lastpl) );
TVector2 UR( edgpos.back().second, fProjection->GetPlaneZ(lastpl) );
Double_t slopeL = (UL.X() - LL.X()) / (UL.Y() - LL.Y());
Double_t slopeR = (UR.X() - LR.X()) / (UR.Y() - LR.Y());
Double_t maxdL = 0, maxdR = 0;
for( UInt_t i = lastpl; i>1; ) { --i;
Double_t z = fProjection->GetPlaneZ(i);
Double_t XL = UL.X() + slopeL * (z - UL.Y());
Double_t XR = UR.X() + slopeR * (z - UR.Y());
Double_t lpt = edgpos[i].first, rpt = edgpos[i].second;
Double_t dL = lpt - XL, dR = rpt - XR;
if( dL < maxdL ) {
UL.Set( lpt, z );
maxdL = dL;
}
if( dR > maxdR ) {
UR.Set( rpt, z );
maxdR = dR;
}
}
const Double_t eps = 1e-3;
fZL = fProjection->GetPlaneZ(0) - eps;
fZU = fProjection->GetPlaneZ(lastpl) + eps;
assert( fZL < fZU );
fCornerX[0] = UL.X() + slopeL * (fZL - UL.Y());
fCornerX[1] = UR.X() + slopeR * (fZL - UR.Y());
fCornerX[2] = UR.X() + slopeR * (fZU - UR.Y());
fCornerX[3] = UL.X() + slopeL * (fZU - UL.Y());
fCornerX[4] = fCornerX[0];
assert( fCornerX[0] < fCornerX[1] );
assert( fCornerX[3] < fCornerX[2] );
delete fBuild; fBuild = 0;
fGrown = false;
return;
}
Bool_t Road::Include( const Road* other )
{
static const double eps = 1e-6;
assert( other and !fBuild and fProjection == other->fProjection );
if( includes(ALL(fHits), ALL(other->fHits), fHits.key_comp()) ) {
fCornerX[0] = min( fCornerX[0], other->fCornerX[0] );
fCornerX[1] = max( fCornerX[1], other->fCornerX[1] );
fCornerX[2] = max( fCornerX[2], other->fCornerX[2] );
fCornerX[3] = min( fCornerX[3], other->fCornerX[3] );
fCornerX[4] = fCornerX[0];
return true;
}
if( TMath::Abs(fZL-other->fZL) < eps and
TMath::Abs(fZU-other->fZU) < eps and
fCornerX[0] < other->fCornerX[0] + eps and
other->fCornerX[1] < fCornerX[1] + eps and
fCornerX[3] < other->fCornerX[3] + eps and
other->fCornerX[2] < fCornerX[2] + eps ) {
fHits.insert( ALL(other->fHits) );
return true;
}
return false;
}
Bool_t Road::CollectCoordinates()
{
DeleteContainerOfContainers( fPoints );
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) {
cout << "Collecting coordinates from: (" << fPatterns.size()
<< " patterns)" << endl;
PrintHits( fHits );
cout << "Seed pattern: " << endl;
fPatterns.front()->first.Print();
}
#endif
Double_t zp[kNcorner] = { fZL, fZL, fZU, fZU, fZL };
Bool_t good = true;
TBits planepattern;
UInt_t last_np = kMaxUInt;
for( siter_t it = fHits.begin(); it != fHits.end(); ++it ) {
Hit* hit = const_cast<Hit*>(*it);
if( hit->GetWirePlane()->IsCalibrating() )
continue;
Double_t z = hit->GetZ();
UInt_t np = hit->GetPlaneNum();
int i = (hit->GetDriftDist() == 0.0) ? 1 : 2;
do {
Double_t x = (--i != 0) ? hit->GetPosL() : hit->GetPosR();
if( TMath::IsInside( x, z, kNcorner, &fCornerX[0], zp )) {
if( np != last_np ) {
fPoints.push_back( Pvec_t() );
planepattern.SetBitNumber(np);
last_np = np;
}
fPoints.back().push_back( new Point(x, z, hit) );
}
} while( i );
}
UInt_t patternvalue = 0;
assert( planepattern.GetNbytes() <= sizeof(patternvalue) );
planepattern.Get( &patternvalue );
good = fProjection->GetPlaneCombos()->TestBitNumber(patternvalue)
and planepattern.CountBits() >= fProjection->GetMinFitPlanes();
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) {
cout << "Collected:" << endl;
vector<Pvec_t>::reverse_iterator ipl = fPoints.rbegin();
for( UInt_t i = fProjection->GetNplanes(); i--; ) {
cout << " pl= " << i;
assert( ipl == fPoints.rend() or !(*ipl).empty() );
if( ipl == fPoints.rend()
or i != (*ipl).front()->hit->GetPlaneNum() ) {
if( fProjection->GetPlane(i)->IsCalibrating() )
cout << " calibrating";
else
cout << " missing";
}
else {
Double_t z = (*ipl).front()->z;
cout << " z=" << z << "\t x=";
for( Pvec_t::iterator it = (*ipl).begin(); it != (*ipl).end(); ++it ) {
cout << " " << (*it)->x;
assert( (*it)->z == z );
}
++ipl;
}
cout << endl;
}
if( !good ) {
cout << "REJECTED" << endl;
}
}
#endif
return good;
}
Bool_t Road::Fit()
{
if( !fGood )
return false;
if( fFitCoord.empty() )
assert( fChi2 == kBig );
else {
fFitCoord.clear();
fV[2]= fV[1] = fV[0] = fChi2 = fSlope = fPos = kBig;
fDof = kMaxUInt;
}
fGood = false;
#ifdef TESTCODE
fNfits = 0;
#endif
if( !CollectCoordinates() )
return false;
UInt_t n_combinations = accumulate( ALL(fPoints),
(UInt_t)1, SizeMul<Pvec_t>() );
if( n_combinations > kMaxNhitCombos ) {
return false;
}
vector<Pvec_t>::size_type npts = fPoints.size();
Pvec_t selected;
selected.reserve( npts );
fDof = npts-2;
pdbl_t chi2_interval = fProjection->GetChisqLimits(fDof);
vector<Double_t> w(npts);
for( UInt_t i = 0; i < n_combinations; ++i ) {
NthCombination( i, fPoints, selected );
assert( selected.size() == npts );
Double_t S11 = 0, S12 = 0, S22 = 0, G1 = 0, G2 = 0, chi2 = 0;
for( Pvec_t::size_type j = 0; j < npts; j++) {
register Point* p = selected[j];
register Double_t r = w[j] = 1.0 / ( p->res() * p->res() );
S11 += r;
S12 += p->z * r;
S22 += p->z * p->z * r;
G1 += p->x * r;
G2 += p->x * p->z * r;
}
Double_t D = S11*S22 - S12*S12;
Double_t iD = 1.0/D;
Double_t a1 = (G1*S22 - G2*S12)*iD;
Double_t a2 = (G2*S11 - G1*S12)*iD;
Double_t V[3] = { S22*iD, -S12*iD, S11*iD };
for( Pvec_t::size_type j = 0; j < npts; j++) {
register Point* p = selected[j];
Double_t d = a1 + a2*p->z - p->x;
chi2 += d*d * w[j];
}
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 )
cout << "Fit:"
<< " a1 = " << a1 << " (" << TMath::Sqrt(V[0]) << ")"
<< " a2 = " << a2
<< " chi2 = " << chi2
<< " ndof = " << fDof
<< endl;
#endif
if( chi2 < chi2_interval.first )
continue;
if( chi2 > chi2_interval.second )
continue;
#ifdef TESTCODE
++fNfits;
#endif
if( chi2 < fChi2 ) {
fPos = a1;
fSlope = a2;
fChi2 = chi2;
memcpy( fV, V, 3*sizeof(Double_t) );
fFitCoord.swap( selected );
fGood = true;
#ifdef VERBOSE
if( fProjection->GetDebug() > 3 ) cout << "ACCEPTED" << endl;
#endif
}
}
return fGood;
}
TVector2 Road::Intersect( const Road* other, Double_t z ) const
{
assert(other);
assert(fGood && other->fGood);
assert(fProjection->GetType() != other->fProjection->GetType());
Double_t su = fProjection->GetSinAngle();
Double_t cu = fProjection->GetCosAngle();
Double_t sv = other->fProjection->GetSinAngle();
Double_t cv = other->fProjection->GetCosAngle();
Double_t inv_denom = 1.0/(sv*cu-su*cv);
Double_t x = (GetPos(z) * sv - other->GetPos(z) * su) * inv_denom;
Double_t y = (other->GetPos(z) * cu - GetPos(z) * cv) * inv_denom;
return TVector2(x, y);
}
void Road::Print( Option_t* ) const
{
cout << "Road: " << fProjection->GetName() << " type, "
<< fHits.size() << " hits" << endl;
cout << " TL = (" << fCornerX[3] << "," << fZU << ") "
<< " TR = (" << fCornerX[2] << "," << fZU << ")"
<< endl
<< " BL = (" << fCornerX[0] << "," << fZL << ") "
<< " BR = (" << fCornerX[1] << "," << fZL << ")"
<< endl;
for( Hset_t::reverse_iterator it = fHits.rbegin(); it != fHits.rend();
++it ) {
cout << " ";
(*it)->Print();
}
if( fGood ) {
cout << " fitpos = " << fPos << " (" << TMath::Sqrt(fV[0]) << ")"
<< " slope = " << fSlope
<< " chi2 = " << fChi2
<< " ndof = " << fDof
<< endl;
}
}
}