Why does Gsl swap local x and y for a 180 deg rotation about y?

I am puzzled by local residuals for our DUT, which is an ATLAS Strip detector. We put it in the beam “the wrong way round” … its internal coordinate system has x along global negative x; y along y. I apply a rotation of Pi radians about its y-axis to align it with the telescope. I include the DUT in the Gsl tracking in Tracking4D, where I print out local residuals, the intercept, and global residuals with:

        ROOT::Math::XYZPoint globalRes = track->getGlobalResidual(detectorID);
        ROOT::Math::XYPoint localRes = track->getLocalResidual(detectorID);
        ROOT::Math::XYZPoint intercept = track->getState(detectorID);

if (track->getChi2ndof() < 3.) {
cout << detectorID << ": " << localRes << intercept << globalRes << endl;
}

Resulting in (for the first track found):
mimosa26_0: (-7.81404e-05, -0.00062894)(-0.653122, 0.902229, 0)(-7.81404e-05, -0.00062894, 0)
mimosa26_5: (0.000604319, 1.7071e-05)(-0.17685, 1.00407, 850)(0.000604401, 1.38756e-05, 0)
mimosa26_1: (0.000287192, 0.00119619)(-0.569866, 0.955627, 153)(0.000296676, 0.00119388, 0)
mimosa26_2: (-0.000591934, -0.000583202)(-0.487681, 1.00444, 305)(-0.000594077, -0.000581019, 0)
abc_29: (-10.1802, -0.0190987)(-0.405911, 1.03012, 425)(0.0185752, -10.1802, -8.86416e-10)
mimosa26_3: (-0.000307841, -2.21878e-06)(-0.342598, 1.03449, 559)(-0.000307848, -8.80011e-07, 0)
mimosa26_4: (0.000605309, 0.000273789)(-0.266852, 1.01954, 704)(0.000605372, 0.000273648, 0)
USBPIXI4B_10: (-0.0896679, 0.00730516)(-0.230156, 1.01197, 774)(-0.0076825, -0.0896364, 0)

What I see is that for Mimosas, the global residuals are more or less the same as the locals; xGlob → xLoc and yGlob → yLoc, as expected: they only have minor rotations for alignment.

For our USBPix, xGlob → -yLoc and yGlob → xLoc. That’s what I expect: in the geometry file, USBPix is rotated 90 deg about the z-axis, so I expect to swap x and y coords, with a sign change on one of them.

Our strip DUT abc_29 has the same: xGlob → -yLoc and yGlob → xLoc. Not what I would expect. I have a rotation of the DUT by 180 deg about the y-axis. This should map xGlob → -xLoc and yGlob → yGlob.

(I see in GblTrack.cpp, line 345 or thereabouts,
residual_local_[plane.getName()] = ROOT::Math::XYPoint(gblResiduals(0), gblResiduals(1));
hence I say it is Gbl that is swapping them)

Any ideas?

In GblTrack.cpp I can get cluster local residuals with:
ROOT::Math::XYZPoint corPosLocal = local_fitted_track_points_.at(name);
ROOT::Math::XYZPoint clusterPosLocal = plane.getCluster()->local();
ROOT::Math::XYZPoint resid = clusterPosLocal - corPosLocal;
// Orig: residual_local_[plane.getName()] = ROOT::Math::XYPoint(gblResiduals(0), gblResiduals(1));
residual_local_[plane.getName()] = ROOT::Math::XYPoint(resid.X(), resid.Y());
std::cout << name << “: gblResiduals(” << gblResiduals(0) << ", " << gblResiduals(1) <<
“); ClusterLocal(” << (clusterPosLocal - corPosLocal).X() << ", " << (clusterPosLocal - corPosLocal).Y() << “)\n”;

Then the cout statement shows that for most detectors, this gives identical results; but for our DUT (abc_29) x and y are swapped:

mimosa26_0: gblResiduals(0.000598432, 0.000173058); ClusterLocal(0.000598432, 0.000173058)
mimosa26_1: gblResiduals(-0.00104541, -0.000614258); ClusterLocal(-0.00104541, -0.000614258)
mimosa26_2: gblResiduals(0.000202518, 0.000635957); ClusterLocal(0.000202518, 0.000635957)
abc_29: gblResiduals(-13.0226, -0.00609372); ClusterLocal(-0.00609372, -13.0226)
mimosa26_3: gblResiduals(-4.15319e-05, 0.000498562); ClusterLocal(-4.15319e-05, 0.000498562)
mimosa26_4: gblResiduals(0.000714137, -0.00158278); ClusterLocal(0.000714137, -0.00158278)
USBPIXI4B_10: gblResiduals(0.0631776, 0.00562324); ClusterLocal(0.0631776, 0.00562324)
mimosa26_5: gblResiduals(0.000262485, 0.000685436); ClusterLocal(0.000262485, 0.000685436)

I also saw (somewhere buried in debug statements) that for passive material, they are also swapped (harmless, but seems odd).

I will go with the cluster local version for now.

I think this is also related to issue:
https://corryvreckan-forum.web.cern.ch/t/usbpix-ignores-resolution-setting
where we started looking at measurement errors for our USBPix device, because x and y seemed to be mixed up. We got round that by (i) ignoring the error issue and (ii) stopped swapping x and y when going from EUDAQ raw data to Corryvreckan Detector, and then replacing a 180 deg rotation by a 90 deg rotation.

Coming back to this. I need the following code change to make detectors rotated 180 deg about the y-access get the correct residuals:

Original GblTrack.cpp lines around 331:

auto corPos = plane.getToGlobal() * local_fitted_track_points_.at(name);
ROOT::Math::XYZPoint clusterPos = plane.getCluster()->global();
residual_global_[name] = clusterPos - corPos;
residual_local_[plane.getName()] = ROOT::Math::XYPoint(gblResiduals(0), gblResiduals(1));

Needs to change to:

ROOT::Math::XYZPoint corPosLocal = local_fitted_track_points_.at(name);
ROOT::Math::XYZPoint clusterPosLocal = plane.getCluster()->local();
residual_local_[name] = clusterPosLocal - corPosLocal;

ROOT::Math::XYZPoint corPos = plane.getToGlobal() * corPosLocal;
ROOT::Math::XYZPoint clusterPos = plane.getCluster()->global();
residual_global_[name] = clusterPos - corPos;

Then residuals are then correct (for all detectors) even if it is rotated 180 deg about y axis. Note that he new code only uses Corryvreckan Detector transforms. It does not assume that gblResiduals(0) corresponds to local-x and gblResiduals(1) corresponds to local-y. This assumption seems to be wrong sometimes.

Sorry, title should be GBL, not GSL.