7 from ROOT
import Belle2
20 import trackfindingcdc.harvest.cdc_peelers
as cdc_peelers
26 return logging.getLogger(__name__)
29 CONTACT =
"oliver.frost@desy.de"
33 """Harvester to generate, postprocess and inspect MC events for track-segment-pair fit validation"""
37 generator_module =
"simple_gun"
42 segment_orientation =
"outwards"
45 fit_method_name =
"fuse-sz"
49 """Get the output ROOT filename"""
61 """Harvest and post-process the MC events"""
64 path.add_module(harvesting_module)
65 return harvesting_module
68 """Convert command-line arguments to basf2 argument list"""
71 argument_parser.add_argument(
74 choices=[
"no",
"medium",
"full"],
77 help=
'Amount of monte carlo information to be used in the segment generation.',
80 argument_parser.add_argument(
82 choices=[
"zreco",
"fuse-pre",
"fuse-sz",
"fuse-sz-re"],
84 dest=
"fit_method_name",
85 help=(
"Choose which fit positional information of the segment should be used. \n"
86 "* 'zreco' means the z coordinate is reconstructed and a linear sz fit is made. "
87 "No covariance between the circle and the linear sz part can be made.\n"
88 "* 'fuse-sz' means the Kalmanesk fuse of the two trajectory fits.\n"
89 "* 'fuse-sz-re' means the Kalmanesk fuse of the two trajectory fits but reestimate the drift length."
93 return argument_parser
96 """Determine which track-segment-pair fitter to use"""
99 if fit_method_name ==
'zreco':
102 def z_reconstruction_fit(pair):
103 return sz_fitter.update(pair)
104 return z_reconstruction_fit
106 elif fit_method_name.startswith(
'fuse-pre'):
109 fusionFit = CDCAxialStereoFusion()
111 def sz_segment_pair_preliminary_fit(pair):
112 fusionFit.fusePreliminary(pair)
113 return sz_segment_pair_preliminary_fit
115 elif fit_method_name.startswith(
'fuse-sz'):
118 reestimateDriftLength = fit_method_name.endswith(
"re")
119 fusionFit = CDCAxialStereoFusion(reestimateDriftLength)
121 def sz_segment_pair_fusion_fit(pair):
122 fusionFit.reconstructFuseTrajectories(pair)
125 trajectory3D = pair.getTrajectory3D()
126 revFromSegment = pair.getFromSegment().reversed()
127 revToSegment = pair.getToSegment().reversed()
128 revPair = CDCSegmentPair(revToSegment, revFromSegment)
130 CDCAxialStereoFusion.reconstructFuseTrajectories(revPair)
131 revTrajectory3D = revPair.getTrajectory3D().reversed()
141 print(
"One parameters", [trajectory3D.getLocalHelix().parameters()[i]
for i
in range(5)])
142 print(
"Rev parameters", [revTrajectory3D.getLocalHelix().parameters()[i]
for i
in range(5)])
144 print(
"One covariance")
146 print([trajectory3D.getLocalHelix().helixCovariance()(i, j)
for i
in range(5)])
148 print(
"Rev covariance")
150 print([revTrajectory3D.getLocalHelix().helixCovariance()(i, j)
for i
in range(5)])
155 return sz_segment_pair_fusion_fit
158 raise ValueError(
"Unexpected fit_positions %s" % fit_method_name)
162 Sets up a path that plays back pregenerated events or generates events
163 based on the properties in the base class.
167 path.add_module(
"TFCDC_WireHitPreparer",
168 flightTimeEstimation=
"outwards",
172 path.add_module(
"TFCDC_ClusterPreparer")
177 path.add_module(
"TFCDC_SegmentFinderFacetAutomaton",
178 SegmentOrientation=
"outwards"
181 path.add_module(
"TFCDC_SegmentFitter",
182 inputSegments=
"CDCSegment2DVector",
183 updateDriftLength=
True,
184 useAlphaInDriftLength=
True,
189 path.add_module(
"TFCDC_SegmentFinderFacetAutomaton",
191 FacetRelationFilter=
"truth",
192 SegmentOrientation=
"outwards"
195 path.add_module(
"TFCDC_SegmentFitter",
196 inputSegments=
"CDCSegment2DVector",
197 updateDriftLength=
True,
198 useAlphaInDriftLength=
True,
204 path.add_module(
"TFCDC_SegmentCreatorMCTruth",
205 reconstructedDriftLength=
False,
206 reconstructedPositions=
True,
210 path.add_module(
"TFCDC_SegmentFitter",
211 inputSegments=
"CDCSegment2DVector",
212 updateDriftLength=
False,
217 raise ValueError(
"Invalid degree of Monte Carlo information")
219 path.add_module(
"TFCDC_SegmentOrienter",
220 SegmentOrientation=
"outwards",
222 inputSegments=
"CDCSegment2DVector",
223 segments=
"CDCSegment2DVectorOriented"
226 path.add_module(
"TFCDC_TrackFinderSegmentPairAutomaton",
227 inputSegments=
"CDCSegment2DVectorOriented",
228 WriteSegmentPairs=
True,
229 SegmentPairFilter=
"truth",
230 SegmentPairFilterParameters={
"allowReverse":
True},
231 SegmentPairRelationFilter=
"none"
240 """Module to collect information about the generated segment pairs and
241 compose validation plots on terminate."""
245 super(SegmentPairFitValidationModule, self).
__init__(
246 output_file_name=output_file_name,
247 foreach=
"CDCSegmentPairVector"
254 """Receive signal at the start of event processing"""
256 super(SegmentPairFitValidationModule, self).
initialize()
259 """Initialize the MC-hit lookup method"""
263 """Select segment pairs with 4 or more hits per segment and a matching primary MC particle"""
265 from_segment = segment_pair.getFromSegment()
266 to_segment = segment_pair.getToSegment()
267 mc_particle = mc_segment_lookup.getMCParticle(from_segment)
268 return (mc_particle
and
269 is_primary(mc_particle)
and
270 from_segment.size() > 3
and
271 to_segment.size() > 3)
274 """Aggregate the track and MC information for track-segment analysis"""
277 from_segment = segment_pair.getFromSegment()
278 to_segment = segment_pair.getToSegment()
280 mc_particle = mc_segment_lookup.getMCParticle(from_segment)
283 fit3d_truth = mc_segment_lookup.getTrajectory3D(to_segment)
285 fb_info = 1
if segment_pair.getAutomatonCell().getCellWeight() > 0
else -1
287 curvature_truth=fb_info * fit3d_truth.getCurvatureXY(),
288 tan_lambda_truth=fb_info * fit3d_truth.getTanLambda(),
292 segment_pair_crops.update(truth_crops)
293 return segment_pair_crops
297 save_histograms = refiners.save_histograms(outlier_z_score=5.0, allow_discrete=
True)
299 save_tree = refiners.save_tree()
302 save_curvature_pull_aux = refiners.save_pull_analysis(
303 part_name=
"curvature",
307 aux_names=[
"superlayer_id_pair",
"tan_lambda_truth"],
312 save_curvature_pull = refiners.save_pull_analysis(
313 part_name=
"curvature",
316 groupby=[
None,
"superlayer_id_pair"],
320 save_absolute_curvature_pull = refiners.save_pull_analysis(
321 part_name=
"curvature",
324 groupby=[
None,
"superlayer_id_pair"],
328 save_tan_lambda_pull = refiners.save_pull_analysis(
329 part_name=
"tan_lambda",
330 quantity_name=
"tan #lambda",
332 groupby=[
None,
"superlayer_id_pair"],
336 save_fit_quality_histograms = refiners.save_histograms(
338 select={
"ndf":
"ndf",
340 "p_value":
"p-value",
342 groupby=[
None,
"superlayer_id_pair"],
343 description=
"Distribution of {part_name} in the segment fits",
347 save_fit_quality_by_tan_lambda_profiles = refiners.save_profiles(
349 "p_value":
"fit p-value",
350 "tan_lambda_truth":
"true tan #lambda",
352 groupby=[
None,
"superlayer_id_pair"],
353 x=
"true tan #lambda",
355 check=(
"The {y_part_name} should be essentially the same over"
356 "the whole range of the tan lambda spectrum"),
357 description=(
"Investigating the reconstruction quality for different "
358 "tan lambda regions of the CDC. Most notably is the superlayer dependency."
359 "For stereo superlayers the curve is not flat but has distinct slope."),
365 """Fit axial and stereo track segment pairs"""
369 """Default method to fit the generated segment pairs."""
372 CDCAxialStereoFusion.reconstructFuseTrajectories(segmentPair,
386 super(AxialStereoPairFitterModule, self).
__init__()
389 """Called by basf2 for each event"""
393 """Fits all pairs in the StoreArray with designated fit method."""
398 wrapped_segment_pair_relations = stored_segment_pair_relations.obj()
399 segment_pair_relations = wrapped_segment_pair_relations.get()
401 for segment_pair_relation
in segment_pair_relations:
407 run.configure_and_execute_from_commandline()
410 if __name__ ==
"__main__":
411 logging.basicConfig(stream=sys.stdout, level=logging.INFO, format=
'%(levelname)s:%(message)s')