# Add code to apply FT module joints and specify origin for survey errors

FT modules have separate alignment constants for the top and bottom half. In theory a single set of constants at the 'module' level would be enough. However, there is currently no concept of a full module in the geometry. Furthermore, in the installed detector the modules are a bit 'banana-shaped'. We would like to exploit the split of the module in the geometry to approximate this shape.

One solution is to consider the module to have a 'joint' in the middle. This merge requests allows to implement this model by providing a new type of survey constraint: it constrains the parameters of two alignables A and B to each other. The chi2-quare contributions looks like

` chi2 = (pA - pB)^T V^-1 (pA- pB)`

where pA (pB) is the set of parameters (Tx,Ty,Tz,Rx,Ry,Rz) of element A (B) and V is a covariance matrix. (In the implementation the latter is diagonal.) The parameters need to be compared in a common frame. For the case of two FT half modules that would be the place where the two half modules are connected. This is at (x,y,z) = (0 -1212.75 0) in the local half module frame.

The configuration of joint constraints is done with:

```
from TAlignment.Alignables import SurveyConstraints
surveyconstraints = SurveyConstraints()
nametop="FT/T1/X/HL0/Q0/M0"
namebot="FT/T1/X/HL0/Q2/M0"
errors="0.01 0.01 0.01 0.0001 0.0002 0.0002"
pivot="0 -1212.75 0"
surveyconstraints.ElementJoints.append( " : ".join([nametop,namebot,errors,pivot]))
```

In this example, `errors`

represents the diagonal elements of the covariance matrix of the constraint: In this case 1 micron for the coordinates and 0.2 mrad for the angles. The string called `pivot`

represents the coordinates of the point where the parameters are compared, in the frame of the first of the two elements. We still need to think a bit about realistic errors for the constraint.

To make the configuration a bit easier, the half constraints can be computed by Alignables:

```
from TAlignment.Alignables import Alignables, SurveyConstraints
elements = Alignables()
elements.FTHalfModules("TxRz")
surveyconstraints = SurveyConstraints()
errors="0.001 0.001 0.001 0.0002 0.0002 0.0002"
surveyconstraints.ElementJoints += elements.FTHalfModuleJoints(errors)
```

and to simplify even more, you can add SurveyConstraints to add the joints:

```
from TAlignment.Alignables import SurveyConstraints
surveyconstraints = SurveyConstraints()
surveyconstraints.FT(addHalfModuleJoints=True)
```

In addition this merge requests adds a feature that was still missing in setting constraint errors. The error matrix is always assumed diagonal. Normally this is in the 'nominal center' of the geometry element. This is a bit inconvenient if the survey was performed off-center. The solution is to provide a pivot point for the survey data. In the XML this can already be done. The small modification made here is that it can now also be done for constraints to the nominal geometry, for instance:

```
surveyconstraints.Constraints += [
# allow for an Rz of ~1mm/1m around the z=0 part of the half module
"FT/T./(X1|X2|U|V)/HL./Q./M. : 0 0 0 0 0 0 : 0.1 0.1 0.1 0.001 0.001 0.001 : 0 +1213 0"]
```

will allow for a generous Rz rotation of the FT half module around the point of the readout side of the module, while keeping the position at that location fixed. The last three digits represent the pivot point. The next step is to add these pivot points also to the survey XML. (Not in this merge request.)