Belle II Software development
PostMergeUpdaterModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <analysis/modules/PostMergeUpdate/PostMergeUpdaterModule.h>
10#include <mdst/dbobjects/BeamSpot.h>
11#include <framework/logging/Logger.h>
12#include <analysis/utility/PCmsLabTransform.h>
13#include <TDatabasePDG.h>
14#include <Math/Vector3D.h>
15
16#include <cmath>
17
18using namespace Belle2;
19
20//-----------------------------------------------------------------
21// Register module
22//-----------------------------------------------------------------
23REG_MODULE(PostMergeUpdater);
24
25// Implementation
27{
28 setDescription("Synchronize parts of the events post merge/embedding. Used in the signal embedding pipeline. Uses kinematic information for the tag / simulated decay stored in eventExtraInfo.");
30 addParam("Mixing", m_mixing, "Mixing (true) or embedding (false) corrections", false);
31 addParam("isCharged", m_isCharged, "Charged (true) or neutral (false) B mesons", true);
32}
33
35{
36 m_mergedArrayIndices.isRequired("MergedArrayIndices");
37 m_eventExtraInfo.isRequired("EventExtraInfo_indepPath"); // indepPath suffix is hardwired for the second part of the event
38 m_eventExtraInfo_orig.isRequired("EventExtraInfo"); // original extra info
39 m_trackFits.isOptional();
40 m_tracks.isOptional();
41 m_eclclusters.isOptional();
42}
43
45{
46 // Unit rotation:
47 ROOT::Math::Rotation3D rot;
48
49 if (
50 m_eventExtraInfo_orig->hasExtraInfo("PX")
51 and m_eventExtraInfo_orig->hasExtraInfo("PY")
52 and m_eventExtraInfo_orig->hasExtraInfo("PZ")
53 and m_eventExtraInfo->hasExtraInfo("PX")
54 and m_eventExtraInfo->hasExtraInfo("PY")
55 and m_eventExtraInfo->hasExtraInfo("PZ")
56 ) {
57 // For embedding, we will rotate the simulated B in the direction of the reconstructed tag
58 ROOT::Math::XYZVector tag3v = ROOT::Math::XYZVector(m_eventExtraInfo_orig->getExtraInfo("PX"),
59 m_eventExtraInfo_orig->getExtraInfo("PY"),
60 m_eventExtraInfo_orig->getExtraInfo("PZ")
61 );
62
63 ROOT::Math::XYZVector sec3v = ROOT::Math::XYZVector(m_eventExtraInfo->getExtraInfo("PX"),
64 m_eventExtraInfo->getExtraInfo("PY"),
65 m_eventExtraInfo->getExtraInfo("PZ")
66 );
67
68 // For mixing, we want to get an opposite direction, the secondary ROE should point in the direction of the primary TAG
69 if (m_mixing) {
71
72 const int iPDG = m_isCharged ? 521 : 511 ;
73 const double mB = TDatabasePDG::Instance()->GetParticle(iPDG)->Mass();
74 double E = sqrt(mB * mB + sec3v.Mag2());
75 ROOT::Math::PxPyPzEVector sec4v(sec3v.X(), sec3v.Y(), sec3v.Z(), E);
76 ROOT::Math::PxPyPzEVector secCMS = T.labToCms(sec4v);
77
78 // reflection:
79 ROOT::Math::PxPyPzEVector secRoeCMS(-secCMS.X(), -secCMS.Y(), -secCMS.Z(), secCMS.E());
80 ROOT::Math::PxPyPzEVector sec4roe = T.cmsToLab(secRoeCMS);
81
82 // update sec3v direction:
83 sec3v.SetXYZ(sec4roe.X(), sec4roe.Y(), sec4roe.Z());
84 }
85
86
87 ROOT::Math::XYZVector cross = tag3v.Unit().Cross(sec3v.Unit());
88 double dot = tag3v.Unit().Dot(sec3v.Unit());
89
90 // Rotation to make secondary B point as tag B
91 rot = ROOT::Math::Rotation3D(ROOT::Math::AxisAngle(cross, -acos(dot)));
92
93 // Closure test that rotation does what expected:
94 ROOT::Math::XYZVector test = rot * sec3v;
95 double smallValue = 1e-12;
96 if ((std::abs(sin(test.Phi() - tag3v.Phi())) > smallValue) or (std::abs(test.Theta() - tag3v.Theta()) > smallValue)) {
97 B2ERROR("Loss of accuracy during rotation" << LogVar("Delta phi", std::abs(sin(test.Phi() - tag3v.Phi())))
98 << LogVar("Delta Theta", std::abs(test.Theta() - tag3v.Theta())));
99 }
100 } else {
101 B2ERROR("No momentum information provided for the tag/simulated particle list, can not update tracks");
102 }
103 return rot;
104}
105
107{
108 if (m_mixing) {
109 // get beam vertex for P2:
110 if (m_eventExtraInfo->hasExtraInfo("IPX")
111 and m_eventExtraInfo->hasExtraInfo("IPY")
112 and m_eventExtraInfo->hasExtraInfo("IPZ")) {
113 double xv2 = m_eventExtraInfo->getExtraInfo("IPX");
114 double yv2 = m_eventExtraInfo->getExtraInfo("IPY");
115 double zv2 = m_eventExtraInfo->getExtraInfo("IPZ");
116 const ROOT::Math::XYZVector origSpot(xv2, yv2, zv2);
117
118 // Now vertex from DB:
119 static DBObjPtr<Belle2::BeamSpot> beamSpotDB;
120 const ROOT::Math::XYZVector beamSpot = beamSpotDB->getIPPosition();
121
122 const ROOT::Math::Rotation3D rot = tag_vertex_rotation();
123 const double bz = BFieldManager::getFieldInTesla(beamSpot).Z();
124
125 // Loop over track fit results from the attached part of the event:
126 // Loop over new tracks and corresponding track fit results
127 for (int idxTr = m_mergedArrayIndices->getExtraInfo("Tracks"); idxTr < m_tracks.getEntries(); idxTr++) {
128 for (short int i : m_tracks[idxTr]->getValidIndices()) {
129 auto t_idx = m_tracks[idxTr]->m_trackFitIndices[i];
130
131 short charge = m_trackFits[t_idx]->getChargeSign();
132 auto helixO = m_trackFits[t_idx]->getHelix();
133 // Move track such that IP becomes centered at the beamSpot
134 helixO.passiveMoveBy(origSpot - beamSpot);
135
136 // Also Rotate:
137 ROOT::Math::XYZVector position = helixO.getPerigee();
138 ROOT::Math::XYZVector momentum = rot * helixO.getMomentum(bz);
139
140 Helix helix(position, momentum, charge, bz);
141
142 // Store back in the mdst:
143 m_trackFits[t_idx]->m_tau[TrackFitResult::iD0] = helix.getD0();
144 m_trackFits[t_idx]->m_tau[TrackFitResult::iPhi0] = helix.getPhi0();
145 m_trackFits[t_idx]->m_tau[TrackFitResult::iOmega] = helix.getOmega();
146 m_trackFits[t_idx]->m_tau[TrackFitResult::iZ0] = helix.getZ0();
147 m_trackFits[t_idx]->m_tau[TrackFitResult::iTanLambda] = helix.getTanLambda();
148
149 }
150 }
151 // also ECL clusters:
152 cluster_rotation(rot);
153
154 } else {
155 B2ERROR("No vertex info, can not update tracks");
156 }
157
158 } else {
159 if (
160 m_eventExtraInfo_orig->hasExtraInfo("X")
161 and m_eventExtraInfo_orig->hasExtraInfo("Y")
162 and m_eventExtraInfo_orig->hasExtraInfo("Z")
163 and m_eventExtraInfo->hasExtraInfo("X")
164 and m_eventExtraInfo->hasExtraInfo("Y")
165 and m_eventExtraInfo->hasExtraInfo("Z")
166 ) {
167
168 ROOT::Math::XYZVector vertexTag(m_eventExtraInfo_orig->getExtraInfo("X"),
169 m_eventExtraInfo_orig->getExtraInfo("Y"),
170 m_eventExtraInfo_orig->getExtraInfo("Z"));
171
172 ROOT::Math::XYZVector vertexEmb(m_eventExtraInfo->getExtraInfo("X"),
173 m_eventExtraInfo->getExtraInfo("Y"),
174 m_eventExtraInfo->getExtraInfo("Z"));
175
176 const double bz = BFieldManager::getFieldInTesla(vertexTag).Z();
177 const ROOT::Math::Rotation3D rot = tag_vertex_rotation();
178
179 // Loop over new tracks and corresponding track fit results
180 for (int idxTr = m_mergedArrayIndices->getExtraInfo("Tracks"); idxTr < m_tracks.getEntries(); idxTr++) {
181 for (short int i : m_tracks[idxTr]->getValidIndices()) {
182 auto t_idx = m_tracks[idxTr]->m_trackFitIndices[i];
183
184 // get d0, z0 vs original simulated-truth vertex. They include smearing due to reconstruction.
185 auto helix = m_trackFits[t_idx]->getHelix();
186 helix.passiveMoveBy(vertexEmb);
187
188 ROOT::Math::XYZVector mom = m_trackFits[t_idx]->getMomentum();
189 short charge = m_trackFits[t_idx]->getChargeSign();
190
191 // Rotate (no boost for now)
192 ROOT::Math::XYZVector momTag = rot * mom;
193
194 // Define new helix "h", based on tag vertex position and rotated track momentum. Note that the vertex position is usually well
195 // reconstructed and smearing in the track position parameters (d0,z0) for the helix h is not sufficient. In addition,
196 // for embedding channels with multiple tracks we need an extra smearing for each track individually. To take into account correlations,
197 // at least to first order, we used determined above (d0,z0) parameters from the track vs original simulated vertex.
198
199 Helix h(vertexTag, momTag, charge, bz);
200
201 m_trackFits[t_idx]->m_tau[TrackFitResult::iD0] = h.getD0() + helix.getD0(); // include smearing simulated -> reconstructed
202 m_trackFits[t_idx]->m_tau[TrackFitResult::iPhi0] = h.getPhi0();
203 m_trackFits[t_idx]->m_tau[TrackFitResult::iZ0] = h.getZ0() + helix.getZ0(); // include smearing simulated -> reconstructed
204 m_trackFits[t_idx]->m_tau[TrackFitResult::iTanLambda] = h.getTanLambda();
205 m_trackFits[t_idx]->m_tau[TrackFitResult::iOmega] = h.getOmega();
206
207 }
208 }
209 cluster_rotation(rot);
210 }
211
212 else {
213 B2ERROR("No track parameters info, can not update tracks");
214 }
215 }
216
217}
218
219
220void PostMergeUpdaterModule::cluster_rotation(const ROOT::Math::Rotation3D& rot)
221{
222 // Loop over added clusters:
223 for (int idxCl = m_mergedArrayIndices->getExtraInfo("ECLClusters"); idxCl < m_eclclusters.getEntries(); idxCl++) {
224 ROOT::Math::XYZVector pos = m_eclclusters[idxCl]->getClusterPosition();
225 ROOT::Math::XYZVector newPos = rot * pos;
226 // Keep same R, update theta/phi:
227 m_eclclusters[idxCl]->setTheta(newPos.Theta());
228 m_eclclusters[idxCl]->setPhi(newPos.Phi());
229 }
230}
R E
internal precision of FFTW codelets
static ROOT::Math::XYZVector getFieldInTesla(const ROOT::Math::XYZVector &pos)
return the magnetic field at a given position in Tesla.
Helix parameter class.
Definition Helix.h:48
Class for accessing objects in the database.
Definition DBObjPtr.h:21
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
Module()
Constructor.
Definition Module.cc:30
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
Class to hold Lorentz transformations from/to CMS and boost vector.
StoreObjPtr< EventExtraInfo > m_eventExtraInfo_orig
Event extra info original.
ROOT::Math::Rotation3D tag_vertex_rotation()
Helper function to determine rotation matrix.
virtual void initialize() override
Initialize the Module.
virtual void event() override
Event processor.
StoreArray< Track > m_tracks
tracks
StoreArray< TrackFitResult > m_trackFits
track fits
StoreObjPtr< EventExtraInfo > m_mergedArrayIndices
indices where the StoreArrays were merged
void cluster_rotation(const ROOT::Math::Rotation3D &rot)
Rotate clusters.
StoreObjPtr< EventExtraInfo > m_eventExtraInfo
Event extra info.
StoreArray< ECLCluster > m_eclclusters
StoreArray of ECLCluster.
bool m_mixing
Fix to common vertex.
static const unsigned int iZ0
Index for z0.
static const unsigned int iTanLambda
Index tan lambda.
static const unsigned int iD0
Index for d0.
static const unsigned int iOmega
Index for omega.
static const unsigned int iPhi0
Index for phi0.
Class to store variables with their name which were sent to the logging service.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
T dot(GeneralVector< T > a, GeneralVector< T > b)
dot product of two general vectors
Abstract base class for different kinds of events.