Belle II Software  release-05-01-25
ContinuumSuppressionVariables.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Pablo Goldenzweig, Dennis Weyland *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <analysis/variables/ContinuumSuppressionVariables.h>
12 #include <analysis/variables/ROEVariables.h>
13 #include <analysis/VariableManager/Manager.h>
14 #include <analysis/dataobjects/EventExtraInfo.h>
15 #include <analysis/dataobjects/Particle.h>
16 #include <analysis/dataobjects/ContinuumSuppression.h>
17 #include <analysis/utility/ReferenceFrame.h>
18 #include <analysis/ClusterUtility/ClusterUtils.h>
19 #include <analysis/ContinuumSuppression/FoxWolfram.h>
20 
21 #include <framework/logging/Logger.h>
22 #include <framework/datastore/StoreArray.h>
23 #include <framework/datastore/StoreObjPtr.h>
24 #include <framework/utilities/Conversion.h>
25 
26 #include <mdst/dataobjects/PIDLikelihood.h>
27 #include <mdst/dataobjects/Track.h>
28 #include <mdst/dataobjects/ECLCluster.h>
29 
30 #include <TLorentzVector.h>
31 #include <TVector3.h>
32 
33 #include <cmath>
34 
35 
36 namespace Belle2 {
41  namespace Variable {
42 
43  double R2EventLevel(const Particle*)
44  {
45  B2WARNING("The variable R2EventLevel is deprecated. Use `foxWolframR2` and ma.buildEventShape(inputListNames=[], default_cleanup=True, allMoments=False, cleoCones=True, collisionAxis=True, foxWolfram=True, harmonicMoments=True, jets=True, sphericity=True, thrust=True, checkForDuplicates=False, path=mypath)");
46 
47  std::vector<TVector3> p3_all;
48 
49  StoreArray<Track> tracks;
50  for (int i = 0; i < tracks.getEntries(); ++i) {
51  // deal with multiple possible track hypotheses in the track fit: try to
52  // retrieve the most likely from PID, maybe this fit failed so then
53  // create a particle with whatever is closest with a TrackFitResult
54  Const::ParticleType mostLikely = tracks[i]->getRelated<PIDLikelihood>()->getMostLikely();
55  const TrackFitResult* iTrack = tracks[i]->getTrackFitResultWithClosestMass(mostLikely);
56  if (iTrack == nullptr) continue;
57  if (iTrack->getChargeSign() != 0) {
58  Particle particle(tracks[i], iTrack->getParticleType());
59  PCmsLabTransform T;
60  TLorentzVector p_cms = T.rotateLabToCms() * particle.get4Vector();
61  p3_all.push_back(p_cms.Vect());
62  }
63  }
64 
65  StoreArray<ECLCluster> eclClusters;
66  for (int i = 0; i < eclClusters.getEntries(); ++i) {
67  // sum only ECLClusters which have the N1 (n photons) hypothesis
68  if (!eclClusters[i]->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
69  continue;
70 
71  ClusterUtils C;
72  TLorentzVector momECLCluster = C.Get4MomentumFromCluster(eclClusters[i], ECLCluster::EHypothesisBit::c_nPhotons);
73  if (momECLCluster == momECLCluster) {
74  if (eclClusters[i]->isNeutral()) {
75  Particle particle(eclClusters[i]);
76  PCmsLabTransform T;
77  TLorentzVector p_cms = T.rotateLabToCms() * particle.get4Vector();
78  p3_all.push_back(p_cms.Vect());
79  }
80  }
81  }
82 
83  FoxWolfram FW(p3_all);
84  FW.calculateBasicMoments();
85  return FW.getR(2);
86  }
87 
88  double R2(const Particle* particle)
89  {
90  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
91  if (!qq)
92  return std::numeric_limits<float>::quiet_NaN();
93 
94  return qq->getR2();
95  }
96 
97  double thrustBm(const Particle* particle)
98  {
99  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
100  if (!qq)
101  return std::numeric_limits<float>::quiet_NaN();
102 
103  return qq->getThrustBm();
104  }
105 
106  double thrustOm(const Particle* particle)
107  {
108  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
109  if (!qq)
110  return std::numeric_limits<float>::quiet_NaN();
111 
112  return qq->getThrustOm();
113  }
114 
115  double cosTBTO(const Particle* particle)
116  {
117  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
118  if (!qq)
119  return std::numeric_limits<float>::quiet_NaN();
120 
121  return qq->getCosTBTO();
122  }
123 
124  double cosTBz(const Particle* particle)
125  {
126  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
127  if (!qq)
128  return std::numeric_limits<float>::quiet_NaN();
129 
130  return qq->getCosTBz();
131  }
132 
133  Manager::FunctionPtr KSFWVariables(const std::vector<std::string>& arguments)
134  {
135  if (arguments.size() == 1 || arguments.size() == 2) {
136  bool useFS1 = false;
137  auto variableName = arguments[0];
138  if (arguments.size() == 2) {
139  if (arguments[1] == "FS1") {
140  useFS1 = true;
141  } else {
142  B2FATAL("Second argument in KSFWVariables can only be 'FS1' to use the KSFW moments calculated from the B final state particles! Do not include a second argument to use the default KSFW moments calculated from the B primary daughters.");
143  }
144  }
145  int index = -1;
146 
147  // all possible names
148  std::vector<std::string> names = {"mm2", "et",
149  "hso00", "hso01", "hso02", "hso03", "hso04",
150  "hso10", "hso12", "hso14",
151  "hso20", "hso22", "hso24",
152  "hoo0", "hoo1", "hoo2", "hoo3", "hoo4"
153  };
154 
155  // find the index of the name
156  for (unsigned i = 0; i < names.size(); ++i) {
157  if (variableName == names[i])
158  index = i;
159  }
160 
161  // throw helfpul error if name provided was not in allowed list
162  if (index == -1) {
163  std::string allowed = "";
164  for (auto n : names)
165  allowed += n + ", ";
166  B2FATAL("Variable name provided: " << variableName << " is not one of the allowed options. Please choose from one of:" << allowed);
167  }
168 
169  auto func = [index, useFS1](const Particle * particle) -> double {
170  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
171  if (!qq) return std::numeric_limits<double>::quiet_NaN();
172 
173  // get the KSFW moments
174  std::vector<float> ksfw = qq->getKsfwFS0();
175  if (useFS1)
176  ksfw = qq->getKsfwFS1();
177 
178  if (ksfw.size() == 0) B2FATAL("Could not find any KSFW moments");
179  return ksfw.at(index);
180  };
181  return func;
182  } else {
183  B2FATAL("Wrong number of arguments for meta function KSFWVariables. It only takes one or two arguments. The first argument must be the variable and the second can either be left blank or must be FS1 to use the KSFW moments calculated from the B final state particles.");
184  }
185  }
186 
187  Manager::FunctionPtr CleoConesCS(const std::vector<std::string>& arguments)
188  {
189  if (arguments.size() == 1 || arguments.size() == 2) {
190 
191  int coneNumber = 0;
192  try {
193  coneNumber = Belle2::convertString<int>(arguments[0]);
194  } catch (std::invalid_argument&) {
195  B2FATAL("The first argument of the CleoConeCS meta function must be an integer!");
196  }
197 
198  bool useROE = false;
199  if (arguments.size() == 2) {
200  if (arguments[1] == "ROE") {
201  useROE = true;
202  } else {
203  B2FATAL("Second argument in CleoCones can only be 'ROE' to use the CleoCones calculated from the ROE only! Do not include a second argument to use the default CleoCones calculated from all final state particles.");
204  }
205  }
206 
207  auto func = [coneNumber, useROE](const Particle * particle) -> double {
208  const ContinuumSuppression* qq = particle->getRelatedTo<ContinuumSuppression>();
209  if (!qq)
210  return std::numeric_limits<double>::quiet_NaN();
211  std::vector<float> cleoCones = qq->getCleoConesALL();
212  if (useROE)
213  cleoCones = qq->getCleoConesROE();
214  return cleoCones.at(coneNumber - 1);
215  };
216  return func;
217  } else {
218  B2FATAL("Wrong number of arguments for CleoCones function. It only takes one or two arguments. The first argument must be the cone number and the second can either be left blank or must 'ROE' to use the CleoCones calculated from all final state particles.");
219  }
220  }
221 
222  Manager::FunctionPtr transformedNetworkOutput(const std::vector<std::string>& arguments)
223  {
224  if (arguments.size() == 3) {
225  double low = 0;
226  double high = 0;
227  try {
228  low = Belle2::convertString<double>(arguments[1]);
229  high = Belle2::convertString<double>(arguments[2]);
230  } catch (std::invalid_argument&) {
231  B2FATAL("Second and third argument of transformedNetworkOutput meta function must be doubles!");
232  }
233 
234  auto extraInfoName = arguments[0];
235  auto func = [extraInfoName, low, high](const Particle * particle) -> double {
236  if (particle == nullptr)
237  {
238  StoreObjPtr<EventExtraInfo> eventExtraInfo;
239  if (eventExtraInfo->hasExtraInfo(extraInfoName)) {
240  return eventExtraInfo->getExtraInfo(extraInfoName);
241  } else {
242  return std::numeric_limits<double>::quiet_NaN();
243  }
244  }
245  if (particle->hasExtraInfo(extraInfoName))
246  {
247  return std::log(((particle->getExtraInfo(extraInfoName)) - low) / (high - (particle->getExtraInfo(extraInfoName))));
248  } else {
249  return std::numeric_limits<double>::quiet_NaN();
250  }
251  };
252  return func;
253  } else {
254  B2FATAL("Wrong number of arguments for meta function transformedNetworkOutput");
255  }
256  }
257 
258  Manager::FunctionPtr useBThrustFrame(const std::vector<std::string>& arguments)
259  {
260  if (arguments.size() == 2) {
261  auto variableName = arguments[0];
262  std::string mode = arguments[1];
263 
264  const bool modeisSignal = mode == "Signal";
265  const bool modeisAuto = mode == "Auto";
266 
267  if (not modeisSignal and (mode != "ROE") and not modeisAuto)
268  B2FATAL("Second argument in useBThrustFrame can only be 'Signal', 'ROE' or 'Auto'. Your argument was " + mode);
269 
270  const Variable::Manager::Var* var = Manager::Instance().getVariable(variableName);
271 
272  auto func = [var, modeisSignal, modeisAuto](const Particle * particle) -> double {
273  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
274  const Particle* Bparticle = roe->getRelated<Particle>();
275  const ContinuumSuppression* qq = Bparticle->getRelatedTo<ContinuumSuppression>();
276  if (!qq)
277  return std::numeric_limits<double>::quiet_NaN();
278  double isinROE = isInRestOfEvent(particle);
279  TVector3 newZ;
280  if (modeisSignal or (modeisAuto and isinROE < 0.5))
281  newZ = qq->getThrustB();
282  else
283  newZ = qq->getThrustO();
284 
285  TVector3 newY(0, 0, 0);
286  if (newZ(2) == 0 and newZ(1) == 0)
287  newY(0) = 1;
288  else{
289  newY(1) = newZ(2);
290  newY(2) = -newZ(1);
291  }
292  TVector3 newX = newY.Cross(newZ);
293 
294  UseReferenceFrame<CMSRotationFrame> signalframe(newX, newY, newZ);
295 
296  return var->function(particle);
297  };
298  return func;
299  } else {
300  B2FATAL("Wrong number of arguments for meta function useBThrustFrame. It only takes two arguments. The first argument must be the variable and the second can either be .");
301  }
302  }
303 
304 
305  VARIABLE_GROUP("Continuum Suppression");
306  REGISTER_VARIABLE("R2EventLevel", R2EventLevel, "[Eventbased] Event-Level Reduced Fox-Wolfram moment R2");
307  REGISTER_VARIABLE("R2" , R2 , "Reduced Fox-Wolfram moment R2");
308  REGISTER_VARIABLE("thrustBm" , thrustBm , "Magnitude of the signal B thrust axis");
309  REGISTER_VARIABLE("thrustOm" , thrustOm , "Magnitude of the ROE thrust axis");
310  REGISTER_VARIABLE("cosTBTO" , cosTBTO , "Cosine of angle between thrust axis of the signal B and thrust axis of ROE");
311  REGISTER_VARIABLE("cosTBz" , cosTBz , "Cosine of angle between thrust axis of the signal B and z-axis");
312  REGISTER_VARIABLE("KSFWVariables(variable,string)", KSFWVariables,
313  "Returns variable et, mm2, or one of the 16 KSFW moments. If only the variable is specified, the KSFW moment calculated from the B primary daughters is returned. If string is set to ``FS1``, the KSFW moment calculated from the B final state daughters is returned.");
314  REGISTER_VARIABLE("CleoConeCS(integer,string)", CleoConesCS,
315  "Returns i-th cleo cones from the continuum suppression. If only the variable is specified, the CleoCones are calculated from all final state particles. If string is set to 'ROE', the CleoCones are calculated only from ROE particles.\n"
316  "Useful for ContinuumSuppression.\n"
317  "Given particle needs a related ContinuumSuppression object (built using the ContinuumSuppressionBuilder).\n"
318  "Returns NaN if particle has no related ContinuumSuppression object.");
319  REGISTER_VARIABLE("transformedNetworkOutput(name, low, high)", transformedNetworkOutput,
320  "Transforms the network output :math:`C\\to C`' via: :math:`C'=\\operatorname{log}((C-\\mathrm{low})/(\\mathrm{high}-C))`");
321  REGISTER_VARIABLE("useBThrustFrame(variable, mode)", useBThrustFrame,
322  "Returns the variable in respect to rotated coordinates, in which z lies on the specified thrust axis.\n"
323  "If mode is set to Signal it will use the thrust axis of the reconstructed B candidate, if mode is set to ROE it will use the ROE thrust axis.\n"
324  "If mode is set to Auto the function use the thrust axis based on isInRestOfEvent(particle).\n"
325  "Like isinRestofEvent, you have to use path.for_each( . . .) to use this MetaVariable.")
326 
327  }
329 }
Belle2::Variable::Manager::getVariable
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:33
Belle2::ECLCluster::EHypothesisBit::c_nPhotons
@ c_nPhotons
CR is split into n photons (N1)
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::Variable::Manager::FunctionPtr
std::function< double(const Particle *)> FunctionPtr
NOTE: the python interface is documented manually in analysis/doc/Variables.rst (because we use ROOT ...
Definition: Manager.h:118
Belle2::Variable::Manager::Instance
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:27