Skip to content

Avoid/remove covariance matrix allocations from clients of TrackParameters. use std::optional intrernally to express that is "nullable" but allow for value semantics

The purpose of this MR is to allow us to have value semantics and get rid of quite a few dynamic allocations (new and make_unique/release pairs) for the covariance matrix in few 100s places

Internally for the 5x5 covariance in ParametersBase we move to std::optional from std::unique_ptr.

At large we want to retain the ability to express that the covariance is not being always present. e.g see changes in TrkEvent and TrkSurfaces .

For the client code there quite a bit of removing allocations (e.g remove new , make_unique / release pairs ) and using "values" where we can most common cases. We rely a bit on optional when the logic is a bit more complicated. Although eventually we want to simplify even more this

Some notes:

The kind of standard client code change repeated in various places (and bit different forms) in this MR look like

   - auto cov = std::unique_ptr<AmgSymMatrix(5)>(new AmgSymMatrix(5));
   + auto cov = AmgSymMatrix(5){};
   -   (*cov)(i, i) = pTS->getTrackCovariance(i,i);
   +   (cov)(i, i) = pTS->getTrackCovariance(i,i);
      for(int j=i+1;j<5;j++) {
    
    -    cov->fillSymmetric(i, j, pTS->getTrackCovariance(i,j));
    +    cov.fillSymmetric(i, j, pTS->getTrackCovariance(i,j));
 -     Trk::Perigee* perigee = new Trk::Perigee(d0, z0, phi0, theta, 
- qOverP, perigeeSurface, cov.release());
+     Trk::Perigee* perigee = new Trk::Perigee(d0, z0, phi0, theta, 
+ qOverP, perigeeSurface, std::move(cov));

i.e removing the allocation with make_unique to then release. Use value and move things look similar bar there is no allocation.

For the internal side of things we want to have something that has value semantics but can be "not there" / "nullable" (std::nullopt here) and preferably avoid dynamic allocations all together.

A common use case for optional is the return value of a function that may fail. As opposed to other approaches, such as std::pair<T,bool>, optional handles expensive-to-construct objects well and is more readable

If an optional contains a value, the value is guaranteed to be allocated as part of the optional object footprint, i.e. no dynamic memory allocation ever takes place.

Mentioning @sroe

Edited by Christos Anastopoulos

Merge request reports