3 #include <fwk/CentralConfig.h>
4 #include <fwk/RunController.h>
5 #include <fwk/LocalCoordinateSystem.h>
7 #include <det/Detector.h>
9 #include <sdet/SDetector.h>
10 #include <sdet/STimeVariance.h>
12 #include <evt/Event.h>
13 #include <evt/ShowerRecData.h>
14 #include <evt/ShowerSRecData.h>
15 #include <evt/ShowerSimData.h>
17 #include <sevt/SEvent.h>
18 #include <sevt/EventTrigger.h>
19 #include <sevt/Station.h>
20 #include <sevt/StationRecData.h>
22 #include <utl/Reader.h>
23 #include <utl/ErrorLogger.h>
24 #include <utl/PhysicalConstants.h>
25 #include <utl/AxialVector.h>
27 #include <utl/String.h>
28 #include <utl/config.h>
30 #include <CLHEP/Matrix/Matrix.h>
31 #include <CLHEP/Matrix/Vector.h>
37 using namespace SdPlaneFitOG;
44 using CLHEP::HepMatrix;
45 using CLHEP::HepVector;
48 #define OUT(_x_) if ((_x_) <= fInfoLevel) cerr
58 namespace SdPlaneFitOG {
65 const double scal = axis * station;
66 return station*station - scal*scal;
73 const auto topB = CentralConfig::GetInstance()->GetTopBranch(
"SdPlaneFit");
75 topB.GetChild(
"infoLevel").GetData(fInfoLevel);
76 if (fInfoLevel < eNone || fInfoLevel > eMinuit) {
77 INFO(
"<infoLevel> out of bounds");
80 fMinuitOutput = (fInfoLevel >= eMinuit);
82 topB.GetChild(
"minNumberOfStations").GetData(fMinNumberOfStations);
83 if (fMinNumberOfStations <= 2) {
84 INFO(
"<minNumberOfStations> must be > 2");
102 const double cosTheta = (reuseFit ? fit.
w : 1);
104 (reuseFit ?
Vector(fit.
u, fit.
v, fit.
w, fgBarycenterCS) : Vector());
105 const auto& sDetector = det::Detector::GetInstance().GetSDetector();
106 const auto& timeVariance = sdet::STimeVariance::GetInstance();
119 for (
const auto&
s : fgCurrentSEvent->CandidateStationsRange()) {
120 const Vector sPos = sDetector.GetStation(
s).GetPosition() - fgBarycenter;
121 const double x = sPos.
GetX(fgBarycenterCS);
122 const double y = sPos.
GetY(fgBarycenterCS);
123 const auto& sRec =
s.GetRecData();
124 const double t = (sRec.GetSignalStartTime() - fgBaryTime).GetInterval();
125 const double sigma2 =
126 timeVariance.GetTimeSigma2(sRec.GetTotalSignal(), sRec.GetT50(), cosTheta,
sqrt(
RPerp2(approxAxis, sPos))) +
127 sRec.GetGPSTimeVariance();
128 const double invSigma2 = 1 / sigma2;
130 const double x_s = x * invSigma2;
135 const double y_s = y * invSigma2;
150 mat[0][0] = sxx; mat[0][1] = sxy; mat[0][2] = -sx;
151 mat[1][0] = sxy; mat[1][1] = syy; mat[1][2] = -sy;
152 mat[2][0] = -sx; mat[2][1] = -sy; mat[2][2] = s1;
158 INFO(
"Matrix inversion failed.");
168 const HepVector
p = mat*k;
170 const double w2 = 1 -
Sqr(p[0]) -
Sqr(p[1]);
173 INFO(
"Unphysical direction cosines");
187 fit.
stage = (reuseFit ? ShowerSRecData::kPlaneFitLinear2 : ShowerSRecData::kPlaneFitLinear);
198 return eContinueLoop;
200 fgCurrentSEvent = &
event.GetSEvent();
201 const auto& sEvent = *fgCurrentSEvent;
203 const auto& detector = det::Detector::GetInstance();
204 const auto& sDetector = detector.GetSDetector();
208 const auto& siteCS = detector.GetSiteCoordinateSystem();
211 const Point siteOrigin(0,0,0, siteCS);
214 return eContinueLoop;
216 const auto& eventTime =
event.GetSEvent().GetTrigger().GetTime();
219 Vector barySum(0,0,0, siteCS);
221 double weightSum = 0;
223 for (
const auto&
s : sEvent.CandidateStationsRange()) {
224 const auto& dStation = sDetector.GetStation(
s);
225 const auto& sRec =
s.GetRecData();
226 const double weight =
sqrt(sRec.GetTotalSignal());
228 barySum += weight * (dStation.GetPosition() - siteOrigin);
229 timeSum += weight * (sRec.GetSignalStartTime() - eventTime);
234 <<
"# candidate stations = " << nStations << endl;
237 if (nStations < fMinNumberOfStations) {
239 <<
"Not enough stations." << endl;
240 return eContinueLoop;
245 <<
"sum of weights = 0" << endl;
246 return eContinueLoop;
249 barySum /= weightSum;
250 timeSum /= weightSum;
251 fgBarycenter = siteOrigin + barySum;
252 fgBaryTime = eventTime + timeSum;
253 fgBarycenterCS = LocalCoordinateSystem::Create(fgBarycenter);
256 <<
"barycenter = (" <<
String::Make(fgBarycenter, siteCS,
meter,
", ") <<
") m (site)\n"
257 "bary time = " << timeSum/
nanosecond <<
" ns (to event time)\n";
260 <<
"local/site zenith angle diff = "
265 const auto mcAxis = -
event.GetSimShower().GetDirection();
267 <<
"MC axis = (" <<
String::Make(mcAxis, fgBarycenterCS, 1,
", ") <<
") (bary)\n";
276 return eContinueLoop;
282 if (PlaneFit3DDriver(fitNonlin) ==
eSuccess) {
285 <<
"Stage " << fitLin.
stage <<
": linear plane fit\n"
286 " axis = (" << fitLin.
u <<
", " << fitLin.
v <<
", " << fitLin.
w <<
") (bary)\n"
287 " ct0 = " << fitLin.
ct0/
meter <<
" m" << endl;
291 <<
" Nonlinear fit failed, using linear approximation." << endl;
302 auto& showerSRec =
event.GetRecShower().GetSRecShower();
304 showerSRec.SetBarycenter(fgBarycenter);
305 showerSRec.SetBarytime(fgBaryTime);
307 const Vector axis(fit->
u, fit->
v, fit->
w, fgBarycenterCS);
308 showerSRec.SetAxis(axis);
310 showerSRec.SetAngleErrors(axis.GetCoordinates(fgBarycenterCS),
313 showerSRec.SetCurvature(0, 0);
314 showerSRec.SetCorePosition(fgBarycenter);
318 double timeMean3d = 0;
319 double timeSpread3d = 0;
321 CalculateTimeResidual3D(axis, fit->
ct0, timeMean3d, timeSpread3d, chi2);
323 showerSRec.SetTimeResidualMean(timeMean3d);
324 showerSRec.SetTimeResidualSpread(timeSpread3d);
325 const int angleNDOF = nStations - 3;
326 showerSRec.SetAngleChi2(chi2, angleNDOF);
328 showerSRec.SetLDFRecStage(fit->
stage);
331 <<
"Stage " << fit->
stage <<
": "
332 << (fit == &fitLin ?
"linear" :
"3d" )
334 " axis = (" << fit->
u <<
", " << fit->
v <<
", " << fit->
w <<
") (bary)\n"
335 " theta = " << acos(fit->
w)/
degree <<
" +/- "
336 << showerSRec.GetThetaError()/
degree <<
" deg (bary)\n"
337 " phi = " << atan2(fit->
v, fit->
u)/
degree <<
" +/- "
338 << showerSRec.GetPhiError()/
degree <<
" deg\n"
339 " ct0 = " << fit->
ct0/
meter <<
" m\n"
340 " time chi2 = " << chi2 <<
" / " << angleNDOF <<
"\n"
341 " time residual = " << timeMean3d <<
" +/- "
342 << timeSpread3d << endl;
346 <<
" deg (to stage " << fitLin.
stage <<
")\n";
349 if (!showerSRec.HasPlaneFrontRecData())
350 showerSRec.MakePlaneFrontRecData();
351 auto& planeFrontRec = showerSRec.GetPlaneFrontRecData();
353 planeFrontRec.SetBarycenter(fgBarycenter);
355 planeFrontRec.SetAxis(axis);
356 planeFrontRec.SetAngleErrors(axis.GetCoordinates(fgBarycenterCS),
358 planeFrontRec.SetAngleChi2Ndof(chi2, angleNDOF);
359 planeFrontRec.SetTimeResidualMean(timeMean3d, timeSpread3d);
361 ++RunController::GetInstance().GetRunData().GetNamedCounters()[
"SdPlaneFit/Axis"];
369 double& mean,
double& spread,
double& chi2)
375 const auto& sDetector = det::Detector::GetInstance().GetSDetector();
376 const auto& timeVariance = sdet::STimeVariance::GetInstance();
378 const double cosTheta = axis.
GetCosTheta(fgBarycenterCS);
383 for (
auto&
s : fgCurrentSEvent->CandidateStationsRange()) {
385 const Vector vx = sDetector.GetStation(
s).GetPosition() - fgBarycenter;
386 const double t = (
s.GetRecData().GetSignalStartTime() - fgBaryTime).GetInterval();
388 auto& sRec =
s.GetRecData();
389 const double sigma2 =
390 timeVariance.GetTimeSigma2(sRec.GetTotalSignal(), sRec.GetT50(), cosTheta,
sqrt(
RPerp2(axis, vx))) +
391 sRec.GetGPSTimeVariance();
392 const double residual = (t - t0 + vx*axis_c) /
std::sqrt(sigma2);
393 sRec.SetResidual(residual);
395 chi2 +=
Sqr(residual);
400 spread =
sqrt(chi2/(n - 1));
412 if (!fMinuitOutput) {
413 minuit.mnexcm(
"SET PRINTOUT", argList, 1, errFlag);
414 minuit.mnexcm(
"SET NOWARNINGS", argList, 0, errFlag);
415 minuit.SetPrintLevel(-1);
420 minuit.mnexcm(
"SET ERRORDEF", argList, 1, errFlag);
422 minuit.mnparm(0,
"u", fit.
u, 0.01, 0, 0, errFlag);
423 minuit.mnparm(1,
"v", fit.
v, 0.01, 0, 0, errFlag);
424 minuit.mnparm(2,
"ct0", fit.
ct0, 10*
meter, 0, 0, errFlag);
428 minuit.mnexcm(
"CALI", argList, 1, errFlag);
431 minuit.mnexcm(
"MINIMIZE", argList, 1, errFlag);
434 <<
" minuit minimize error: " << errFlag <<
'\n';
435 minuit.mnexcm(
"MINOS", argList, 0, errFlag);
438 <<
" minuit minos error: " << errFlag <<
'\n';
445 minuit.GetParameter(0, fit.
u, foo);
446 minuit.GetParameter(1, fit.
v, foo);
447 const double w2 = 1 -
Sqr(fit.
u) -
Sqr(fit.
v);
450 <<
" Fit failed due to unphysical angle cosines." << endl;
454 minuit.GetParameter(2, fit.
ct0, foo);
458 minuit.mnemat(&emat[0][0], 3);
464 fit.
stage = ShowerSRecData::kPlaneFit3d;
472 double*
const par,
const int flag)
474 const double& u = par[0];
475 const double& v = par[1];
476 const double& ct0 = par[2];
486 static vector<StationData> sData;
490 const auto& sDetector = det::Detector::GetInstance().GetSDetector();
492 for (
const auto&
s : fgCurrentSEvent->CandidateStationsRange()) {
493 const auto& sRec =
s.GetRecData();
494 sData.emplace_back(StationData{
495 kSpeedOfLight * (sRec.GetSignalStartTime() - fgBaryTime).GetInterval(),
497 sRec.GetGPSTimeVariance(),
498 sRec.GetTotalSignal(),
499 sDetector.GetStation(
s).GetPosition() - fgBarycenter
502 timeVariance = &sdet::STimeVariance::GetInstance();
505 const double w2 = 1 -
Sqr(u) -
Sqr(v);
513 const double w =
sqrt(w2);
515 const Vector axis(u,v,w, fgBarycenterCS);
519 for (
const auto& d : sData) {
521 Sqr(d.fCTiming - ct0 + axis * d.fPosition) /
std::string Make(const Geo &g, const CS &cs, const double unit=1, const std::string &sep=" ")
constexpr T Sqr(const T &x)
double Angle(const double theta1, const double phi1, const double theta2, const double phi2)
bool HasRecShower() const
Interface class to access to the SD part of an event.
ShowerRecData & GetRecShower()
double GetCosTheta(const CoordinateSystemPtr &coordinateSystem) const
cos of zenith (theta) angle
bool HasSimShower() const
#define INFO(message)
Macro for logging informational messages.
static void PlaneFit3DFnc(int &nPar, double *const grad, double &value, double *const par, const int flag)
double RPerp2(const Vector &axis, const Vector &station)
A TimeStamp holds GPS second and nanosecond for some event.
static utl::CoordinateSystemPtr fgBarycenterCS
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
boost::tuple< double, double, double > Triple
Coordinate triple for easy getting or setting of coordinates.
double GetX(const CoordinateSystemPtr &coordinateSystem) const
constexpr double nanosecond
bool HasTrigger() const
check whether the central trigger object exists
static utl::TimeStamp fgBaryTime
fwk::VModule::ResultFlag LinearFit(FitParameters &fit, const bool reuseFit=false) const
void CalculateTimeResidual3D(const utl::Vector &axis, const double ct0, double &mean, double &spread, double &chi2) const
#define WARNING(message)
Macro for logging warning messages.
static utl::Point fgBarycenter
double GetY(const CoordinateSystemPtr &coordinateSystem) const
constexpr double kSpeedOfLight
fwk::VModule::ResultFlag Run(evt::Event &event) override
Run: invoked once per event.
A TimeInterval is used to represent time elapsed between two events.
ResultFlag
Flag returned by module methods to the RunController.
fwk::VModule::ResultFlag PlaneFit3DDriver(FitParameters &fit) const
static sevt::SEvent * fgCurrentSEvent
constexpr double kSpeedOfLight2
void LinearFit(const vector< double > &x, const vector< double > &y, const vector< double > &ey, double &a0, double &a1, double &chi2)
Do a linear fit and return coefficients and chi2.
bool HasSRecShower() const
sevt::SEvent & GetSEvent()
fwk::VModule::ResultFlag Init() override
Initialize: invoked at beginning of run (NOT beginning of event)
double GetTimeSigma2(const double signal, const double t50, const double cosTheta, const double distance=0) const