13from ROOT
import Belle2
24import trackfindingcdc.harvest.cdc_peelers
as cdc_peelers
30 return logging.getLogger(__name__)
34 """Harvester to generate, postprocess and inspect MC events for track-segment-pair fit validation"""
38 generator_module =
"simple_gun"
43 segment_orientation =
"outwards"
46 fit_method_name =
"fuse-sz"
50 """Get the output ROOT filename"""
62 """Harvest and post-process the MC events"""
65 path.add_module(harvesting_module)
66 return harvesting_module
69 """Convert command-line arguments to basf2 argument list"""
72 argument_parser.add_argument(
75 choices=[
"no",
"medium",
"full"],
78 help=
'Amount of monte carlo information to be used in the segment generation.',
81 argument_parser.add_argument(
83 choices=[
"zreco",
"fuse-pre",
"fuse-sz",
"fuse-sz-re"],
85 dest=
"fit_method_name",
86 help=(
"Choose which fit positional information of the segment should be used. \n"
87 "* 'zreco' means the z coordinate is reconstructed and a linear sz fit is made. "
88 "No covariance between the circle and the linear sz part can be made.\n"
89 "* 'fuse-sz' means the Kalmanesk fuse of the two trajectory fits.\n"
90 "* 'fuse-sz-re' means the Kalmanesk fuse of the two trajectory fits but reestimate the drift length."
94 return argument_parser
97 """Determine which track-segment-pair fitter to use"""
100 if fit_method_name ==
'zreco':
103 def z_reconstruction_fit(pair):
104 return sz_fitter.update(pair)
105 return z_reconstruction_fit
107 elif fit_method_name.startswith(
'fuse-pre'):
110 fusionFit = CDCAxialStereoFusion()
112 def sz_segment_pair_preliminary_fit(pair):
113 fusionFit.fusePreliminary(pair)
114 return sz_segment_pair_preliminary_fit
116 elif fit_method_name.startswith(
'fuse-sz'):
119 reestimateDriftLength = fit_method_name.endswith(
"re")
120 fusionFit = CDCAxialStereoFusion(reestimateDriftLength)
122 def sz_segment_pair_fusion_fit(pair):
123 fusionFit.reconstructFuseTrajectories(pair)
126 trajectory3D = pair.getTrajectory3D()
127 revFromSegment = pair.getFromSegment().reversed()
128 revToSegment = pair.getToSegment().reversed()
129 revPair = CDCSegmentPair(revToSegment, revFromSegment)
131 CDCAxialStereoFusion.reconstructFuseTrajectories(revPair)
132 revTrajectory3D = revPair.getTrajectory3D().reversed()
142 print(
"One parameters", [trajectory3D.getLocalHelix().parameters()[i]
for i
in range(5)])
143 print(
"Rev parameters", [revTrajectory3D.getLocalHelix().parameters()[i]
for i
in range(5)])
145 print(
"One covariance")
147 print([trajectory3D.getLocalHelix().helixCovariance()(i, j)
for i
in range(5)])
149 print(
"Rev covariance")
151 print([revTrajectory3D.getLocalHelix().helixCovariance()(i, j)
for i
in range(5)])
156 return sz_segment_pair_fusion_fit
159 raise ValueError(f
"Unexpected fit_positions {fit_method_name}")
161 def create_path(self):
163 Sets up a path that plays back pregenerated events or generates events
164 based on the properties
in the base
class.
166 path = super().create_path()
168 path.add_module("TFCDC_WireHitPreparer",
169 flightTimeEstimation=
"outwards",
173 path.add_module(
"TFCDC_ClusterPreparer")
178 path.add_module(
"TFCDC_SegmentFinderFacetAutomaton",
179 SegmentOrientation=
"outwards"
182 path.add_module(
"TFCDC_SegmentFitter",
183 inputSegments=
"CDCSegment2DVector",
184 updateDriftLength=
True,
185 useAlphaInDriftLength=
True,
190 path.add_module(
"TFCDC_SegmentFinderFacetAutomaton",
192 FacetRelationFilter=
"truth",
193 SegmentOrientation=
"outwards"
196 path.add_module(
"TFCDC_SegmentFitter",
197 inputSegments=
"CDCSegment2DVector",
198 updateDriftLength=
True,
199 useAlphaInDriftLength=
True,
205 path.add_module(
"TFCDC_SegmentCreatorMCTruth",
206 reconstructedDriftLength=
False,
207 reconstructedPositions=
True,
211 path.add_module(
"TFCDC_SegmentFitter",
212 inputSegments=
"CDCSegment2DVector",
213 updateDriftLength=
False,
218 raise ValueError(
"Invalid degree of Monte Carlo information")
220 path.add_module(
"TFCDC_SegmentOrienter",
221 SegmentOrientation=
"outwards",
223 inputSegments=
"CDCSegment2DVector",
224 segments=
"CDCSegment2DVectorOriented"
227 path.add_module(
"TFCDC_TrackFinderSegmentPairAutomaton",
228 inputSegments=
"CDCSegment2DVectorOriented",
229 WriteSegmentPairs=
True,
230 SegmentPairFilter=
"truth",
231 SegmentPairFilterParameters={
"allowReverse":
True},
232 SegmentPairRelationFilter=
"none"
241 """Module to collect information about the generated segment pairs and
242 compose validation plots on terminate."""
247 output_file_name=output_file_name,
248 foreach="CDCSegmentPairVector"
255 """Receive signal at the start of event processing"""
260 """Initialize the MC-hit lookup method"""
264 """Select segment pairs with 4 or more hits per segment and a matching primary MC particle"""
266 from_segment = segment_pair.getFromSegment()
267 to_segment = segment_pair.getToSegment()
268 mc_particle = mc_segment_lookup.getMCParticle(from_segment)
269 return (mc_particle
and
270 is_primary(mc_particle)
and
271 from_segment.size() > 3
and
272 to_segment.size() > 3)
275 """Aggregate the track and MC information for track-segment analysis"""
279 to_segment = segment_pair.getToSegment()
284 fit3d_truth = mc_segment_lookup.getTrajectory3D(to_segment)
286 fb_info = 1
if segment_pair.getAutomatonCell().getCellWeight() > 0
else -1
288 curvature_truth=fb_info * fit3d_truth.getCurvatureXY(),
289 tan_lambda_truth=fb_info * fit3d_truth.getTanLambda(),
293 segment_pair_crops.update(truth_crops)
294 return segment_pair_crops
298 save_histograms = refiners.save_histograms(outlier_z_score=5.0, allow_discrete=
True)
300 save_tree = refiners.save_tree()
303 save_curvature_pull_aux = refiners.save_pull_analysis(
304 part_name=
"curvature",
308 aux_names=[
"superlayer_id_pair",
"tan_lambda_truth"],
313 save_curvature_pull = refiners.save_pull_analysis(
314 part_name=
"curvature",
317 groupby=[
None,
"superlayer_id_pair"],
321 save_absolute_curvature_pull = refiners.save_pull_analysis(
322 part_name=
"curvature",
325 groupby=[
None,
"superlayer_id_pair"],
329 save_tan_lambda_pull = refiners.save_pull_analysis(
330 part_name=
"tan_lambda",
331 quantity_name=
"tan #lambda",
333 groupby=[
None,
"superlayer_id_pair"],
337 save_fit_quality_histograms = refiners.save_histograms(
339 select={
"ndf":
"ndf",
341 "p_value":
"p-value",
343 groupby=[
None,
"superlayer_id_pair"],
344 description=
"Distribution of {part_name} in the segment fits",
348 save_fit_quality_by_tan_lambda_profiles = refiners.save_profiles(
350 "p_value":
"fit p-value",
351 "tan_lambda_truth":
"true tan #lambda",
353 groupby=[
None,
"superlayer_id_pair"],
354 x=
"true tan #lambda",
356 check=(
"The {y_part_name} should be essentially the same over"
357 "the whole range of the tan lambda spectrum"),
358 description=(
"Investigating the reconstruction quality for different "
359 "tan lambda regions of the CDC. Most notably is the superlayer dependency."
360 "For stereo superlayers the curve is not flat but has distinct slope."),
366 """Fit axial and stereo track segment pairs"""
370 """Default method to fit the generated segment pairs."""
373 CDCAxialStereoFusion.reconstructFuseTrajectories(segmentPair,
390 """Called by basf2 for each event"""
394 """Fits all pairs in the StoreArray with designated fit method."""
399 wrapped_segment_pair_relations = stored_segment_pair_relations.obj()
400 segment_pair_relations = wrapped_segment_pair_relations.get()
402 for segment_pair_relation
in segment_pair_relations:
408 run.configure_and_execute_from_commandline()
411if __name__ ==
"__main__":
412 logging.basicConfig(stream=sys.stdout, level=logging.INFO, format=
'%(levelname)s:%(message)s')
def peel_segment_pair(segment_pair, key="{part_name}")
a (simplified) python wrapper for StoreObjPtr.
Utility class implementing the Kalmanesk combination of to two dimensional trajectories to one three ...
static const CDCMCHitLookUp & getInstance()
Getter for the singletone instance.
static const CDCMCSegment2DLookUp & getInstance()
Getter for the singletone instance.
static const CDCSZFitter & getFitter()
Getter for a standard sz line fitter instance.
Class representing a pair of one reconstructed axial segment and one stereo segment in adjacent super...
def default_fit_method(segmentPair)
def __init__(self, fit_method=None)
fit_method
fit_method : function A function called on each stored segment pair as its only argument to update it...
mc_segment_lookup
by default, there is no method to find matching MC track segments
def peel(self, segment_pair)
def pick(self, segment_pair)
def __init__(self, output_file_name)
def create_argument_parser(self, **kwds)
monte_carlo
Degree of refinement of the segment generation.
str fit_method_name
use the Kalmanesk fuse of the two trajectory fits
def harvesting_module(self, path=None)
str monte_carlo
do not generate new events
def output_file_name(self)
None output_file_name
Disable the writing of an output ROOT file.
root_input_file
generating events, so there is no ROOT input file
None root_input_file
By default, there is no input ROOT TFile.
None output_file_name
There is no default for the name of the output TFile.