Changes in external/fastjet/contribs/RecursiveTools/RecursiveSymmetryCutBase.cc [1f1f858:b7b836a] in git
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
external/fastjet/contribs/RecursiveTools/RecursiveSymmetryCutBase.cc
r1f1f858 rb7b836a 1 // $Id: RecursiveSymmetryCutBase.cc 700 2014-07-07 12:50:05Z gsoyez $1 // $Id: RecursiveSymmetryCutBase.cc 1080 2017-09-28 07:51:37Z gsoyez $ 2 2 // 3 3 // Copyright (c) 2014-, Gavin P. Salam, Gregory Soyez, Jesse Thaler … … 23 23 #include "fastjet/JetDefinition.hh" 24 24 #include "fastjet/ClusterSequenceAreaBase.hh" 25 #include <cassert> 25 26 #include <algorithm> 26 27 #include <cstdlib> … … 42 43 PseudoJet RecursiveSymmetryCutBase::result(const PseudoJet & jet) const { 43 44 // construct the input jet (by default, recluster with C/A) 44 45 45 if (! jet.has_constituents()){ 46 46 throw Error("RecursiveSymmetryCutBase can only be applied to jets with constituents"); 47 47 } 48 48 49 PseudoJet j = 50 _do_reclustering 51 ? _recluster ? (*_recluster)(jet) 52 : Recluster(cambridge_algorithm, JetDefinition::max_allowable_R)(jet) 53 : jet; 54 55 // issue a warning if the jet is not obtained through a C/A 56 // clustering 57 // if ((! j.has_associated_cluster_sequence()) || 58 // (j.validated_cs()->jet_def().jet_algorithm() != cambridge_algorithm)) 59 // _nonca_warning.warn("RecursiveSymmetryCutBase is designed to be applied on jets from a Cambridge/Aachen clustering; use it with other algorithms at your own risk."); 60 49 PseudoJet j = _recluster_if_needed(jet); 50 51 // sanity check: the jet must have a valid CS 61 52 if (! j.has_valid_cluster_sequence()){ 62 53 throw Error("RecursiveSymmetryCutBase can only be applied to jets associated to a (valid) cluster sequence"); 63 54 } 64 55 56 // check that area information is there in case we have a subtractor 57 // GS: do we really need this since subtraction may not require areas? 65 58 if (_subtractor) { 66 59 const ClusterSequenceAreaBase * csab = … … 75 68 subjet = (*_subtractor)(subjet); 76 69 } 77 78 bool use_mu_cut = (_mu_cut != numeric_limits<double>::infinity());79 70 80 71 // variables for tracking what will happen … … 86 77 std::vector<double> dropped_symmetry; 87 78 std::vector<double> dropped_mu; 79 80 double sym, mu2; 88 81 89 82 // now recurse into the jet's structure 90 while (subjet.has_parents(piece1, piece2)) { 91 92 // first sanity check: 93 // - zero or negative pts are not allowed for the input subjet 94 // - zero or negative masses are not allowed for configurations 95 // in which the mass will effectively appear in a denominator 96 // (The masses will be checked later) 97 if (subjet.pt2() <= 0) return PseudoJet(); 98 99 if (_subtractor) { 100 piece1 = (*_subtractor)(piece1); 101 piece2 = (*_subtractor)(piece2); 102 } 103 104 // determine the symmetry parameter 105 double sym; 106 107 if (_symmetry_measure == y) { 108 // the original d_{ij}/m^2 choice from MDT 109 // first make sure the mass is sensible 110 if (subjet.m2() <= 0) { 111 _negative_mass_warning.warn("RecursiveSymmetryCutBase: cannot calculate y, because (sub)jet mass is negative; bailing out"); 112 return _result_no_substructure(subjet); //TBC: do we return the hardest parent? A NULL PseudoJet? 113 } 114 sym = piece1.kt_distance(piece2) / subjet.m2(); 115 116 } else if (_symmetry_measure == vector_z) { 117 // min(pt1, pt2)/(pt), where the denominator is a vector sum 118 // of the two subjets 119 sym = min(piece1.pt(), piece2.pt()) / subjet.pt(); 120 121 } else if (_symmetry_measure == scalar_z) { 122 // min(pt1, pt2)/(pt1+pt2), where the denominator is a scalar sum 123 // of the two subjets 124 double pt1 = piece1.pt(); 125 double pt2 = piece2.pt(); 126 // make sure denominator is non-zero 127 sym = pt1 + pt2; 128 if (sym == 0) return PseudoJet(); 129 sym = min(pt1, pt2) / sym; 130 131 } else { 132 throw Error ("Unrecognized choice of symmetry_measure"); 133 } 134 135 // determine the symmetry cut 136 // (This function is specified in the derived classes) 137 double this_symmetry_cut = symmetry_cut_fn(piece1, piece2); 138 139 // and make a first tagging decision based on symmetry cut 140 bool tagged = (sym > this_symmetry_cut); 141 142 // if tagged based on symmetry cut, then check the mu cut (if relevant) 143 // and update the tagging decision. Calculate mu^2 regardless, for cases 144 // of users not cutting on mu2, but still interested in its value. 145 double mu2 = max(piece1.m2(), piece2.m2())/subjet.m2(); 146 if (tagged && use_mu_cut) { 147 // first a sanity check -- mu2 won't be sensible if the subjet mass 148 // is negative, so we can't then trust the mu cut - bail out 149 if (subjet.m2() <= 0) { 150 _negative_mass_warning.warn("RecursiveSymmetryCutBase: cannot trust mu, because (sub)jet mass is negative; bailing out"); 151 return PseudoJet(); 152 } 153 if (mu2 > 1) _mu2_gt1_warning.warn("RecursiveSymmetryCutBase encountered mu^2 value > 1"); 154 if (mu2 > pow(_mu_cut,2)) tagged = false; 155 } 156 157 158 // if we've tagged the splitting, return the jet with its substructure 159 if (tagged) { 160 // record relevant information 161 StructureType * structure = new StructureType(subjet); 162 structure->_symmetry = sym; 163 structure->_mu = (mu2 >= 0) ? sqrt(mu2) : -sqrt(-mu2); 164 structure->_delta_R = piece1.delta_R(piece2); 165 if (_verbose_structure) { 166 structure->_has_verbose = true; 167 structure->_dropped_symmetry = dropped_symmetry; 168 structure->_dropped_mu = dropped_mu; 169 structure->_dropped_delta_R = dropped_delta_R; 170 } 171 subjet.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(structure)); 172 return subjet; 173 } 83 RecursionStatus status; 84 while ((status=recurse_one_step(subjet, piece1, piece2, sym, mu2)) != recursion_success) { 85 // start with sanity checks: 86 if ((status == recursion_issue) || (status == recursion_no_parents)) { 87 // we should return piece1 by our convention for recurse_one_step 88 PseudoJet result; 89 if (status == recursion_issue){ 90 result = piece1; 91 if (_verbose) cout << "reached end; returning null jet " << endl; 92 } else { 93 result = _result_no_substructure(piece1); 94 if (_verbose) cout << "no parents found; returning last PJ or empty jet" << endl; 95 } 96 97 if (result != 0) { 98 // if in grooming mode, add dummy structure information 99 StructureType * structure = new StructureType(result); 100 // structure->_symmetry = 0.0; 101 // structure->_mu = 0.0; 102 // structure->_delta_R = 0.0; 103 if (_verbose_structure) { // still want to store verbose information about dropped branches 104 structure->_has_verbose = true; 105 structure->_dropped_symmetry = dropped_symmetry; 106 structure->_dropped_mu = dropped_mu; 107 structure->_dropped_delta_R = dropped_delta_R; 108 } 109 result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(structure)); 110 } 111 112 return result; 113 } 114 115 assert(status == recursion_dropped); 174 116 175 117 // if desired, store information about dropped branches before recursing … … 179 121 dropped_mu.push_back((mu2 >= 0) ? sqrt(mu2) : -sqrt(-mu2)); 180 122 } 181 182 // otherwise continue unclustering, allowing for the different 183 // ways of choosing which parent to look into 184 int choice; 185 if (_recursion_choice == larger_mt) { 186 choice = piece1.mt2() > piece2.mt2() ? 1 : 2; 187 188 } else if (_recursion_choice == larger_pt) { 189 choice = piece1.pt2() > piece2.pt2() ? 1 : 2; 190 191 } else if (_recursion_choice == larger_m) { 192 choice = piece1.m2() > piece2.m2() ? 1 : 2; 193 194 } else { 195 throw Error ("Unrecognized value for recursion_choice"); 196 } 197 if (_verbose) cout << "choice is " << choice << endl;; 198 subjet = (choice == 1) ? piece1 : piece2; 199 } // (subjet.has_parents(...)) 200 201 if (_verbose) cout << "reached end; returning null jet " << endl; 202 203 // decide on tagging versus grooming mode here 204 PseudoJet result = _result_no_substructure(subjet); 205 206 if (result != 0) { 207 // if in grooming mode, add dummy structure information 208 StructureType * structure = new StructureType(result); 209 structure->_symmetry = 0.0; 210 structure->_mu = 0.0; 211 structure->_delta_R = 0.0; 212 if (_verbose_structure) { // still want to store verbose information about dropped branches 213 structure->_has_verbose = true; 214 structure->_dropped_symmetry = dropped_symmetry; 215 structure->_dropped_mu = dropped_mu; 216 structure->_dropped_delta_R = dropped_delta_R; 217 } 218 result.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(structure)); 219 } 220 221 return result; 222 } 223 224 123 124 subjet = piece1; 125 } 126 127 128 // we've tagged the splitting, return the jet with its substructure 129 StructureType * structure = new StructureType(subjet); 130 structure->_symmetry = sym; 131 structure->_mu = (mu2 >= 0) ? sqrt(mu2) : -sqrt(-mu2); 132 structure->_delta_R = sqrt(squared_geometric_distance(piece1, piece2)); 133 if (_verbose_structure) { 134 structure->_has_verbose = true; 135 structure->_dropped_symmetry = dropped_symmetry; 136 structure->_dropped_mu = dropped_mu; 137 structure->_dropped_delta_R = dropped_delta_R; 138 } 139 subjet.set_structure_shared_ptr(SharedPtr<PseudoJetStructureBase>(structure)); 140 return subjet; 141 } 142 143 144 145 //---------------------------------------------------------------------- 146 // the method below is the one actually performing one step of the 147 // recursion. 148 // 149 // It returns a status code (defined above) 150 // 151 // In case of success, all the information is filled 152 // In case of "no parents", piee1 is the same subjet 153 // In case of trouble, piece2 will be a 0 PJ and piece1 is the PJ we 154 // should return (either 0 itself if the issue was critical, or 155 // non-wero in case of a minor issue just causing the recursion to 156 // stop) 157 RecursiveSymmetryCutBase::RecursionStatus 158 RecursiveSymmetryCutBase::recurse_one_step(const PseudoJet & subjet, 159 PseudoJet &piece1, PseudoJet &piece2, 160 double &sym, double &mu2, 161 void *extra_parameters) const { 162 if (!subjet.has_parents(piece1, piece2)){ 163 piece1 = subjet; 164 piece2 = PseudoJet(); 165 return recursion_no_parents; 166 } 167 168 // first sanity check: 169 // - zero or negative pts are not allowed for the input subjet 170 // - zero or negative masses are not allowed for configurations 171 // in which the mass will effectively appear in a denominator 172 // (The masses will be checked later) 173 if (subjet.pt2() <= 0){ // this is a critical problem, return an empty PJ 174 piece1 = piece2 = PseudoJet(); 175 return recursion_issue; 176 } 177 178 if (_subtractor) { 179 piece1 = (*_subtractor)(piece1); 180 piece2 = (*_subtractor)(piece2); 181 } 182 183 // determine the symmetry parameter 184 if (_symmetry_measure == y) { 185 // the original d_{ij}/m^2 choice from MDT 186 // first make sure the mass is sensible 187 if (subjet.m2() <= 0) { 188 _negative_mass_warning.warn("RecursiveSymmetryCutBase: cannot calculate y, because (sub)jet mass is negative; bailing out"); 189 // since rounding errors can give -ve masses, be a it more 190 // tolerant and consider that no substructure has been found 191 piece1 = _result_no_substructure(subjet); 192 piece2 = PseudoJet(); 193 return recursion_issue; 194 } 195 sym = piece1.kt_distance(piece2) / subjet.m2(); 196 197 } else if (_symmetry_measure == vector_z) { 198 // min(pt1, pt2)/(pt), where the denominator is a vector sum 199 // of the two subjets 200 sym = min(piece1.pt(), piece2.pt()) / subjet.pt(); 201 } else if (_symmetry_measure == scalar_z) { 202 // min(pt1, pt2)/(pt1+pt2), where the denominator is a scalar sum 203 // of the two subjets 204 double pt1 = piece1.pt(); 205 double pt2 = piece2.pt(); 206 // make sure denominator is non-zero 207 sym = pt1 + pt2; 208 if (sym == 0){ // this is a critical problem, return an empty PJ 209 piece1 = piece2 = PseudoJet(); 210 return recursion_issue; 211 } 212 sym = min(pt1, pt2) / sym; 213 } else if ((_symmetry_measure == theta_E) || (_symmetry_measure == cos_theta_E)){ 214 // min(E1, E2)/(E1+E2) 215 double E1 = piece1.E(); 216 double E2 = piece2.E(); 217 // make sure denominator is non-zero 218 sym = E1 + E2; 219 if (sym == 0){ // this is a critical problem, return an empty PJ 220 piece1 = piece2 = PseudoJet(); 221 return recursion_issue; 222 } 223 sym = min(E1, E2) / sym; 224 } else { 225 throw Error ("Unrecognized choice of symmetry_measure"); 226 } 227 228 // determine the symmetry cut 229 // (This function is specified in the derived classes) 230 double this_symmetry_cut = symmetry_cut_fn(piece1, piece2, extra_parameters); 231 232 // and make a first tagging decision based on symmetry cut 233 bool tagged = (sym > this_symmetry_cut); 234 235 // if tagged based on symmetry cut, then check the mu cut (if relevant) 236 // and update the tagging decision. Calculate mu^2 regardless, for cases 237 // of users not cutting on mu2, but still interested in its value. 238 bool use_mu_cut = (_mu_cut != numeric_limits<double>::infinity()); 239 mu2 = max(piece1.m2(), piece2.m2())/subjet.m2(); 240 if (tagged && use_mu_cut) { 241 // first a sanity check -- mu2 won't be sensible if the subjet mass 242 // is negative, so we can't then trust the mu cut - bail out 243 if (subjet.m2() <= 0) { 244 _negative_mass_warning.warn("RecursiveSymmetryCutBase: cannot trust mu, because (sub)jet mass is negative; bailing out"); 245 piece1 = piece2 = PseudoJet(); 246 return recursion_issue; 247 } 248 if (mu2 > 1) _mu2_gt1_warning.warn("RecursiveSymmetryCutBase encountered mu^2 value > 1"); 249 if (mu2 > pow(_mu_cut,2)) tagged = false; 250 } 251 252 // we'll continue unclustering, allowing for the different 253 // ways of choosing which parent to look into 254 if (_recursion_choice == larger_pt) { 255 if (piece1.pt2() < piece2.pt2()) std::swap(piece1, piece2); 256 } else if (_recursion_choice == larger_mt) { 257 if (piece1.mt2() < piece2.mt2()) std::swap(piece1, piece2); 258 } else if (_recursion_choice == larger_m) { 259 if (piece1.m2() < piece2.m2()) std::swap(piece1, piece2); 260 } else if (_recursion_choice == larger_E) { 261 if (piece1.E() < piece2.E()) std::swap(piece1, piece2); 262 } else { 263 throw Error ("Unrecognized value for recursion_choice"); 264 } 265 266 return tagged ? recursion_success : recursion_dropped; 267 } 268 269 225 270 //---------------------------------------------------------------------- 226 271 string RecursiveSymmetryCutBase::description() const { … … 235 280 case vector_z: 236 281 ostr << "vector_z"; break; 282 case theta_E: 283 ostr << "theta_E"; break; 284 case cos_theta_E: 285 ostr << "cos_theta_E"; break; 237 286 default: 238 287 cerr << "failed to interpret symmetry_measure" << endl; exit(-1); … … 254 303 case larger_m: 255 304 ostr << "mass"; break; 305 case larger_E: 306 ostr << "energy"; break; 256 307 default: 257 308 cerr << "failed to interpret recursion_choice" << endl; exit(-1); … … 259 310 260 311 if (_subtractor) { 261 ostr << " andsubtractor: " << _subtractor->description();312 ostr << ", subtractor: " << _subtractor->description(); 262 313 if (_input_jet_is_subtracted) {ostr << " (input jet is assumed already subtracted)";} 263 314 } 315 316 if (_recluster) { 317 ostr << " and reclustering using " << _recluster->description(); 318 } 319 264 320 return ostr.str(); 265 321 } 266 322 323 //---------------------------------------------------------------------- 324 // helper for handling the reclustering 325 PseudoJet RecursiveSymmetryCutBase::_recluster_if_needed(const PseudoJet &jet) const{ 326 if (! _do_reclustering) return jet; 327 if (_recluster) return (*_recluster)(jet); 328 if (is_ee()){ 329 #if FASTJET_VERSION_NUMBER >= 30100 330 return Recluster(JetDefinition(ee_genkt_algorithm, JetDefinition::max_allowable_R, 0.0), true)(jet); 331 #else 332 return Recluster(JetDefinition(ee_genkt_algorithm, JetDefinition::max_allowable_R, 0.0))(jet); 333 #endif 334 } 335 336 return Recluster(cambridge_algorithm, JetDefinition::max_allowable_R)(jet); 337 } 338 339 //---------------------------------------------------------------------- 267 340 // decide what to return when no substructure has been found 341 double RecursiveSymmetryCutBase::squared_geometric_distance(const PseudoJet &j1, 342 const PseudoJet &j2) const{ 343 if (_symmetry_measure == theta_E){ 344 double dot_3d = j1.px()*j2.px() + j1.py()*j2.py() + j1.pz()*j2.pz(); 345 double cos_theta = max(-1.0,min(1.0, dot_3d/sqrt(j1.modp2()*j2.modp2()))); 346 double theta = acos(cos_theta); 347 return theta*theta; 348 } else if (_symmetry_measure == cos_theta_E){ 349 double dot_3d = j1.px()*j2.px() + j1.py()*j2.py() + j1.pz()*j2.pz(); 350 return max(0.0, 2*(1-dot_3d/sqrt(j1.modp2()*j2.modp2()))); 351 } 352 353 return j1.squared_distance(j2); 354 } 355 356 //---------------------------------------------------------------------- 268 357 PseudoJet RecursiveSymmetryCutBase::_result_no_substructure(const PseudoJet &last_parent) const{ 269 358 if (_grooming_mode){ … … 277 366 278 367 368 //======================================================================== 369 // implementation of the details of the structure 370 371 // the number of dropped subjets 372 int RecursiveSymmetryCutBase::StructureType::dropped_count(bool global) const { 373 check_verbose("dropped_count()"); 374 375 // if this jet has no substructure, just return an empty vector 376 if (!has_substructure()) return _dropped_delta_R.size(); 377 378 // deal with the non-global case 379 if (!global) return _dropped_delta_R.size(); 380 381 // for the global case, we've unfolded the recursion (likely more 382 // efficient as it requires less copying) 383 unsigned int count = 0; 384 vector<const RecursiveSymmetryCutBase::StructureType*> to_parse; 385 to_parse.push_back(this); 386 387 unsigned int i_parse = 0; 388 while (i_parse<to_parse.size()){ 389 const RecursiveSymmetryCutBase::StructureType *current = to_parse[i_parse]; 390 count += current->_dropped_delta_R.size(); 391 392 // check if we need to recurse deeper in the substructure 393 // 394 // we can have 2 situations here for the underlying structure (the 395 // one we've wrapped around): 396 // - it's of the clustering type 397 // - it's a composite jet 398 // only in the 2nd case do we have to recurse deeper 399 const CompositeJetStructure *css = dynamic_cast<const CompositeJetStructure*>(current->_structure.get()); 400 if (css == 0){ ++i_parse; continue; } 401 402 vector<PseudoJet> prongs = css->pieces(PseudoJet()); // argument irrelevant 403 assert(prongs.size() == 2); 404 for (unsigned int i_prong=0; i_prong<2; ++i_prong){ 405 if (prongs[i_prong].has_structure_of<RecursiveSymmetryCutBase>()){ 406 RecursiveSymmetryCutBase::StructureType* prong_structure 407 = (RecursiveSymmetryCutBase::StructureType*) prongs[i_prong].structure_ptr(); 408 if (prong_structure->has_substructure()) 409 to_parse.push_back(prong_structure); 410 } 411 } 412 413 ++i_parse; 414 } 415 return count; 416 } 417 418 // the delta_R of all the dropped subjets 419 vector<double> RecursiveSymmetryCutBase::StructureType::dropped_delta_R(bool global) const { 420 check_verbose("dropped_delta_R()"); 421 422 // if this jet has no substructure, just return an empty vector 423 if (!has_substructure()) return vector<double>(); 424 425 // deal with the non-global case 426 if (!global) return _dropped_delta_R; 427 428 // for the global case, we've unfolded the recursion (likely more 429 // efficient as it requires less copying) 430 vector<double> all_dropped; 431 vector<const RecursiveSymmetryCutBase::StructureType*> to_parse; 432 to_parse.push_back(this); 433 434 unsigned int i_parse = 0; 435 while (i_parse<to_parse.size()){ 436 const RecursiveSymmetryCutBase::StructureType *current = to_parse[i_parse]; 437 all_dropped.insert(all_dropped.end(), current->_dropped_delta_R.begin(), current->_dropped_delta_R.end()); 438 439 // check if we need to recurse deeper in the substructure 440 // 441 // we can have 2 situations here for the underlying structure (the 442 // one we've wrapped around): 443 // - it's of the clustering type 444 // - it's a composite jet 445 // only in the 2nd case do we have to recurse deeper 446 const CompositeJetStructure *css = dynamic_cast<const CompositeJetStructure*>(current->_structure.get()); 447 if (css == 0){ ++i_parse; continue; } 448 449 vector<PseudoJet> prongs = css->pieces(PseudoJet()); // argument irrelevant 450 assert(prongs.size() == 2); 451 for (unsigned int i_prong=0; i_prong<2; ++i_prong){ 452 if (prongs[i_prong].has_structure_of<RecursiveSymmetryCutBase>()){ 453 RecursiveSymmetryCutBase::StructureType* prong_structure 454 = (RecursiveSymmetryCutBase::StructureType*) prongs[i_prong].structure_ptr(); 455 if (prong_structure->has_substructure()) 456 to_parse.push_back(prong_structure); 457 } 458 } 459 460 ++i_parse; 461 } 462 return all_dropped; 463 } 464 465 // the symmetry of all the dropped subjets 466 vector<double> RecursiveSymmetryCutBase::StructureType::dropped_symmetry(bool global) const { 467 check_verbose("dropped_symmetry()"); 468 469 // if this jet has no substructure, just return an empty vector 470 if (!has_substructure()) return vector<double>(); 471 472 // deal with the non-global case 473 if (!global) return _dropped_symmetry; 474 475 // for the global case, we've unfolded the recursion (likely more 476 // efficient as it requires less copying) 477 vector<double> all_dropped; 478 vector<const RecursiveSymmetryCutBase::StructureType*> to_parse; 479 to_parse.push_back(this); 480 481 unsigned int i_parse = 0; 482 while (i_parse<to_parse.size()){ 483 const RecursiveSymmetryCutBase::StructureType *current = to_parse[i_parse]; 484 all_dropped.insert(all_dropped.end(), current->_dropped_symmetry.begin(), current->_dropped_symmetry.end()); 485 486 // check if we need to recurse deeper in the substructure 487 // 488 // we can have 2 situations here for the underlying structure (the 489 // one we've wrapped around): 490 // - it's of the clustering type 491 // - it's a composite jet 492 // only in the 2nd case do we have to recurse deeper 493 const CompositeJetStructure *css = dynamic_cast<const CompositeJetStructure*>(current->_structure.get()); 494 if (css == 0){ ++i_parse; continue; } 495 496 vector<PseudoJet> prongs = css->pieces(PseudoJet()); // argument irrelevant 497 assert(prongs.size() == 2); 498 for (unsigned int i_prong=0; i_prong<2; ++i_prong){ 499 if (prongs[i_prong].has_structure_of<RecursiveSymmetryCutBase>()){ 500 RecursiveSymmetryCutBase::StructureType* prong_structure 501 = (RecursiveSymmetryCutBase::StructureType*) prongs[i_prong].structure_ptr(); 502 if (prong_structure->has_substructure()) 503 to_parse.push_back(prong_structure); 504 } 505 } 506 507 ++i_parse; 508 } 509 return all_dropped; 510 } 511 512 // the mu of all the dropped subjets 513 vector<double> RecursiveSymmetryCutBase::StructureType::dropped_mu(bool global) const { 514 check_verbose("dropped_mu()"); 515 516 // if this jet has no substructure, just return an empty vector 517 if (!has_substructure()) return vector<double>(); 518 519 // deal with the non-global case 520 if (!global) return _dropped_mu; 521 522 // for the global case, we've unfolded the recursion (likely more 523 // efficient as it requires less copying) 524 vector<double> all_dropped; 525 vector<const RecursiveSymmetryCutBase::StructureType*> to_parse; 526 to_parse.push_back(this); 527 528 unsigned int i_parse = 0; 529 while (i_parse<to_parse.size()){ 530 const RecursiveSymmetryCutBase::StructureType *current = to_parse[i_parse]; 531 all_dropped.insert(all_dropped.end(), current->_dropped_mu.begin(), current->_dropped_mu.end()); 532 533 // check if we need to recurse deeper in the substructure 534 // 535 // we can have 2 situations here for the underlying structure (the 536 // one we've wrapped around): 537 // - it's of the clustering type 538 // - it's a composite jet 539 // only in the 2nd case do we have to recurse deeper 540 const CompositeJetStructure *css = dynamic_cast<const CompositeJetStructure*>(current->_structure.get()); 541 if (css == 0){ ++i_parse; continue; } 542 543 vector<PseudoJet> prongs = css->pieces(PseudoJet()); // argument irrelevant 544 assert(prongs.size() == 2); 545 for (unsigned int i_prong=0; i_prong<2; ++i_prong){ 546 if (prongs[i_prong].has_structure_of<RecursiveSymmetryCutBase>()){ 547 RecursiveSymmetryCutBase::StructureType* prong_structure 548 = (RecursiveSymmetryCutBase::StructureType*) prongs[i_prong].structure_ptr(); 549 if (prong_structure->has_substructure()) 550 to_parse.push_back(prong_structure); 551 } 552 } 553 554 ++i_parse; 555 } 556 return all_dropped; 557 } 558 559 // the maximum of the symmetry over the dropped subjets 560 double RecursiveSymmetryCutBase::StructureType::max_dropped_symmetry(bool global) const { 561 check_verbose("max_dropped_symmetry()"); 562 563 // if there is no substructure, just exit 564 if (!has_substructure()){ return 0.0; } 565 566 // local value of the max_dropped_symmetry 567 double local_max = (_dropped_symmetry.size() == 0) 568 ? 0.0 : *max_element(_dropped_symmetry.begin(),_dropped_symmetry.end()); 569 570 // recurse down the structure if instructed to do so 571 if (global){ 572 // we can have 2 situations here for the underlying structure (the 573 // one we've wrapped around): 574 // - it's of the clustering type 575 // - it's a composite jet 576 // only in the 2nd case do we have to recurse deeper 577 const CompositeJetStructure *css = dynamic_cast<const CompositeJetStructure*>(_structure.get()); 578 if (css == 0) return local_max; 579 580 vector<PseudoJet> prongs = css->pieces(PseudoJet()); // argument irrelevant 581 assert(prongs.size() == 2); 582 for (unsigned int i_prong=0; i_prong<2; ++i_prong){ 583 // check if the prong has further substructure 584 if (prongs[i_prong].has_structure_of<RecursiveSymmetryCutBase>()){ 585 RecursiveSymmetryCutBase::StructureType* prong_structure 586 = (RecursiveSymmetryCutBase::StructureType*) prongs[i_prong].structure_ptr(); 587 local_max = max(local_max, prong_structure->max_dropped_symmetry(true)); 588 } 589 } 590 } 591 592 return local_max; 593 } 594 595 //------------------------------------------------------------------------ 596 // helper class to sort by decreasing thetag 597 class SortRecursiveSoftDropStructureZgThetagPair{ 598 public: 599 bool operator()(const pair<double, double> &p1, const pair<double, double> &p2) const{ 600 return p1.second > p2.second; 601 } 602 }; 603 //------------------------------------------------------------------------ 604 605 // the (zg,thetag) pairs of all the splitting that were found and passed the SD condition 606 vector<pair<double,double> > RecursiveSymmetryCutBase::StructureType::sorted_zg_and_thetag() const { 607 //check_verbose("sorted_zg_and_thetag()"); 608 609 // if this jet has no substructure, just return an empty vector 610 if (!has_substructure()) return vector<pair<double,double> >(); 611 612 // otherwise fill a vector with all the prongs (no specific ordering) 613 vector<pair<double,double> > all; 614 vector<const RecursiveSymmetryCutBase::StructureType*> to_parse; 615 to_parse.push_back(this); 616 617 unsigned int i_parse = 0; 618 while (i_parse<to_parse.size()){ 619 const RecursiveSymmetryCutBase::StructureType *current = to_parse[i_parse]; 620 all.push_back(pair<double,double>(current->_symmetry, current->_delta_R)); 621 622 vector<PseudoJet> prongs = current->pieces(PseudoJet()); 623 assert(prongs.size() == 2); 624 for (unsigned int i_prong=0; i_prong<2; ++i_prong){ 625 if (prongs[i_prong].has_structure_of<RecursiveSymmetryCutBase>()){ 626 RecursiveSymmetryCutBase::StructureType* prong_structure 627 = (RecursiveSymmetryCutBase::StructureType*) prongs[i_prong].structure_ptr(); 628 if (prong_structure->has_substructure()) 629 to_parse.push_back(prong_structure); 630 } 631 } 632 633 ++i_parse; 634 } 635 636 sort(all.begin(), all.end(), SortRecursiveSoftDropStructureZgThetagPair()); 637 return all; 638 } 639 279 640 } // namespace contrib 280 641
Note:
See TracChangeset
for help on using the changeset viewer.