Feature to allow for decay tree fitting with different mass hypothesis for final state particles. Previously, TupleToolDecayTreeFitter allowed this via Substitution attribute where users pass a dictionary {decay descriptor component: "new-pid"} e.g.
dtt=DecayTreeTuple(..)dtt.addBranches({'Dstar':'[D*(2010)+ -> (D0 -> K- K+) pi+]CC'})dtt.Dstar.addTupleTool('TupleToolDecayTreeFitter/ConsDKpi')dtt.Dstar.ConsDKpi.daughtersToConstrain=['D0']#substitue with new pid (Note CC does not work)dtt.Dstar.ConsDKpi.Substitutions={'Charm -> (D0 -> K- ^K+) Meson':'pi+','Charm -> (D~0 -> K+ ^K-) Meson':'pi-'}
Was thinking of a new property (something like SubstitutePID) for DecayTreeFitterAlg that takes such a map using SubstitutePIDTool as before.
I was going to say something similar to @mvesteri below.
For opt2, not sure how useful the RelTable1 would be though. The users, I feel, should only be exposed to Particles -> refitted candidate and not to the intermediate step. So Opt1 implicitly hides it, however for option 2 (if we go for it) perhaps we can hide this from users on the python side?
For option 2 would actually be something like, no?
Given the nature of the v2 event model with zips of tracks, PIDs, etc, I think your option 1 could become a nightmare in the end to cover all possible cases (charged and neutrals for example, which may have different info zipped - am no expert there so would need input).
Seems this is something to raise at the next RTA WP3 "Selections" meeting this coming Tuesday, @poluekt and @mvesteri?
@amathad indeed a brief report/discussion at the next RTA WP3 meeting would be welcome.
I'm not sure why we need to produce any intermediate data though. Naively I'd think that the mass subsitutions are just in the internal configuration-time-fixed state of the DecayTreeFit algorithm.
As said, am no expert in the v2 model but ... I'm not worried about a change of a mass hypothesis on the fly in an algorithm, more about the implications down the line: how do you then ensure relations that make sense, for example, and ensure also that the background category tool reacts appropriately? Because if you change the hypothesis on the particle on the fly then what is a correct match with MC should now become a misID, but that's not going to happen because the relatino particle-MC is immutable. And if you make a new relation, then we're back to option 2 unless I'm missing a subtlety, at which point I very much prefer the verbose and explicit flow of option 2. Reassure me if I'm being too maniac; happy to hear from the event model experts :-).
OK, fair enough. If you really want to create new particles then it is a different question. I was only imagining computing and returning simple types (mass with substitution etc...)
Sorry, I think I see why you say it is OK in general - the user only sees a new relations table that by construction accounts for the ID substitution(s)/change(s). And then everything downstream is given the new table ... That seems fine ... of course provided you have the particles with new IDs somewhere, and that can't be the non-misIDs particles as otherwise we get to the issue I mention just above ;-).
First yes, for every relations table you also get new particles but usually you do not need them.
In option 2 the Substituter produces a new decay tree that can be used in FunTuple directly without needing to make a fit. That could also be a use-case.
Then DTF doesn't need to know how to substitute PIDs as the work is already done. But we need to expose DTF to a RelationsTable as input, as in the output RelationsTable2 the refitted tree is matched to the input (not to the intermediate stuff).
For what concerns background category: it doesn't know or care about decay descriptors, only about the actual mass hypotheses stored in the particles which you pass to it. So as long as the particles themselves remain immutable and the substitution happens on the fly, then I don't see any problem. If you create new particles with new mass hypotheses then you will have to choose which ones you pass to background category, but that problem was always implicitly there.
But I would take a step back here. The typical use-case I am familiar with wants to store the mass under multiple substitutions corresponding to various misidentified backgrounds you worry about. In this case I think you actively do not want to make new particles for the relations table: you exactly want to store a relation between the original particle and the mass created under the substituted hypothesis. So for this use-case, anything you use to compute that substituted hypothesis should exist only within the code doing that computation. What use-case does this approach not address?
Comment from @graven acting as : DTF already has mass constraints. Why not just pass a mass constraint that is different from the expected from PID. I mass constrain the kaon to 139.57 MeV and refit.
Moving the conversation of PID substitution from here with @fevolle and @yamhis to this issue:
"useful to check is whether the DTF can do a different mass hypothesis on the "other tracks", e.g. if we want to search for the Bs -> K K Jpsi background in the Lb -> p K Jpsi data with a Jpsi mass constraint"
The PID substitution is super helpful for the early measurement which plans to use inclusive Hlt2 lines. Not sure how is this going, but the second option will be more flexible and more helpful.
A very interesting use-case of this is the following: if the inclusive line is pi+ pi- pi+, and the analysis channel is K+ pi- pi+, we usually do the first substitution pi+pi-pi+ => K+pi-pi+, since in this substitution the tool will randomly pick one of the two pi+, in order to study the case pi+ pi- K+, it needs to do a second substitution using the first one as the input: K+pi-pi+=>pi+pi-K+, so in case of the first substitution is wrong (misidentification of K+ and pi+), we have the second substitution to recover the correct one, otherwise it's a 50% signal lost.
So making substitution independent of DTF will allow users to do this kind of trick, and it is more flexible.
If the idea is doing this by the mass constraints in DTF, to cover the case I said before, it should be able to parse the decay tree with a stable order, so running two separate DTF, one for pipipi->Kpipi and another for pipipi->pipiK can also solve the problem.
Sorry for this long comment, I'm interested in this!
Hi All, The user-interface (and preliminary implementation) of the new SubstitutePID algorithm were presented in today's slide at DPA-WP3 meeting.
Two options were presented and option 2 was picked (not sure if there was a full consensus). In this thread, however, both @mvesteri and @gligorov argued for option 1, so @pkoppenb mentioned that it might help to add a snippet on how one can use this new algorithm in selections, particularly:
A Hlt2 line builds B+ -> K+ pi+ K- candidates, but the channel of interest has mass hypothesis B+ -> K+ K+ K-. Would like to persist only those B+ -> K+ K+ K- candidates that pass a mass cut under the original B+ -> K+ pi- K+ mass hypothesis. How does the code look like?
It would look something like this:
#get B+ -> K+ pi+ K- candidates from SprucingB_Data=force_location(f'/Event/Spruce/{B_Line}/Particles')#substitute pi+ -> K+subpid_descriptor=["B+ -> K+ {{K+}}pi+ K-"]#build B+ -> K+ K+ K- candidates and relation Table (b/w new and old particles).subpid_KKK=SubstitutePID(Name="SubPID",Input=B_Data,Substitutions=subpid_descriptor)#get new particles (KKK)new_particles=subpid_KKK.ouput_location#Apply a mass cut on the new particles (i.e. B+ -> K+ K+ K-) with the old mass hypothesis (i.e. B+ -> K+ pi+ K-)# The `get_info` method behind the scenes configures the new functor with the relation table (`new` -> `old` particles) built by `SubstitutePID` algorithmfunctor_KKK_masscut=subpid_KKK.get_info(F.MASS>5340)
Is it still possible to write a single tree where variables computed under different hypotheses are just different columns? (As an alternative to writing candidates with different hypotheses to different trees)
I should admit that I’ve never done any analysis requiring mass substitutions so I’m no authority on what is/isn’t useful
Yes there is F.MASSHYPOTHESIS functor for that (simply changes the mass hypothesis and not particle ID). In fact this same functor can be used in the selection with the new particles instead of the above snippet also.
I think for the use-case I was referring to what you would end up doing is then using F.MASSHYPOTHESIS functor to save masses under different hypotheses to your ntuple. Is this correct?