The Gaudi Framework  master (181af51f)
Loading...
Searching...
No Matches
ParticlePropertySvc.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2024 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#include <Gaudi/Decays/CC.h>
14#include <Gaudi/ParticleID.h>
20#include <GaudiKernel/Service.h>
22#include <algorithm>
23#include <boost/algorithm/string.hpp>
24#include <cstdlib>
25#include <fstream>
26#include <functional>
27#include <iostream>
28#include <set>
29
38namespace {
39 std::string defaultFilename() { // the main file with particle properties
40 auto* root = getenv( "PARAMFILESROOT" );
41 return root ? std::string{ root } + "/data/ParticleTable.txt" : std::string{ "./ParticleTable.txt" };
42 }
43} // namespace
44namespace Gaudi {
92 struct ParticlePropertySvc final : public extends<Service, Gaudi::Interfaces::IParticlePropertySvc> {
97 iterator begin() const override { return m_vector.begin(); }
102 iterator end() const override { return m_vector.end(); }
104 size_t size() const override { return m_vector.size(); }
119 const Gaudi::ParticleProperty* find( const std::string& name ) const override { return m_nameMap( name ); }
134 const Gaudi::ParticleProperty* find( const Gaudi::ParticleID& pid ) const override { return m_pidMap( pid ); }
135
151 std::string cc( const std::string& decay ) const override;
152
154 StatusCode initialize() override;
155
160 ParticlePropertySvc( const std::string& name, // the service instance name
161 ISvcLocator* pSvc ) // the Service Locator
162 : base_class( name, pSvc ) {}
163
172
184 void dump();
185
195
200 StatusCode parse( const std::string& file );
205 StatusCode parseLine( const std::string& line );
206
217 StatusCode addParticle( const std::string& pname, const Gaudi::ParticleID& pid, const double charge,
218 const double mass, const double tlife, const double maxWidth, const std::string& evtgen,
219 const int pythia );
220
225
227 bool diff( const Gaudi::ParticleProperty& n, const Gaudi::ParticleProperty& o );
228
230 typedef std::set<std::unique_ptr<Gaudi::ParticleProperty>> Set;
246 "Dump all properties in a table format" };
247
249 typedef std::vector<std::string> Files;
251 typedef std::vector<std::string> Particles;
253 Gaudi::Property<std::string> m_filename{ this, "ParticlePropertiesFile", defaultFilename(),
255 "The name of 'main' particle properties file" };
256
258 "OtherFiles",
259 {},
261 "The (optional) list of additional files with the particle data" };
262
264 "Particles",
265 {},
267 "The (optional) list of special particle properties" };
268
273 this, "ChargeConjugations", Decays::Symbols::instance().cc(), &Gaudi::ParticlePropertySvc::updateCC,
274 "The map of charge-conjugation & protected symbols" };
275
276 typedef std::set<std::string> NameSet;
277 typedef std::set<Gaudi::ParticleID> PidSet;
278
285
289
291 };
292} // namespace Gaudi
293
295 // 1) initialize the base
297 if ( sc.isFailure() ) { return sc; }
298 // 2) create the log
299 MsgStream log( msgSvc(), name() );
300 // 3) rebuild everything
301 sc = rebuild();
302 log << MSG::INFO << "Initialising Gaudi ParticlePropertySvc" << endmsg;
303 if ( sc.isFailure() ) {
304 log << MSG::ERROR << " Unable to initialize the internal structures " << endmsg;
305 return sc;
306 }
307
308 m_by_charge.clear();
309 m_by_mass.clear();
310 m_by_tlife.clear();
311 m_by_width.clear();
312 m_by_evtgen.clear();
313 m_by_pythia.clear();
314 m_replaced_names.clear();
315 m_replaced_pids.clear();
316 m_no_anti.clear();
317
318 m_ccMap.clear();
319
320 if ( m_dump.value() || msgLevel( MSG::DEBUG ) ) { dump(); }
321
322 return StatusCode::SUCCESS;
323}
324
325/* rebuild the Particle Property Data
326 * - clear existing containers
327 * - parse main file
328 * - parse additional files
329 * - parse the specific options
330 * - set particle<->antiparticle links
331 * @return status code
332 */
334 // clear all existing containers
335 m_nameMap.clear();
336 m_pidMap.clear();
337 m_vector.clear();
338 m_ccMap.clear();
339
340 // parse the main file
341 StatusCode sc = parse( m_filename.value() );
342 if ( sc.isFailure() ) { return sc; }
343 // parse the additional files
344 for ( const auto& file : m_other.value() ) {
345 if ( sc = parse( file ); sc.isFailure() ) { return sc; }
346 }
347 // parse the options/lines
348 m_modified.clear();
349 for ( const auto& line : m_particles.value() ) {
350 if ( sc = parseLine( line ); sc.isFailure() ) { return sc; }
351 }
352 // sort the vector
353 std::stable_sort( m_vector.begin(), m_vector.end(), Gaudi::ParticleProperty::Compare() );
354 // set particle<-->antiparticle links
355 sc = setAntiParticles();
356 if ( sc.isFailure() ) { return sc; }
357 // some debug printout
358 if ( msgLevel( MSG::DEBUG ) ) {
359 debug() << " All: " << m_vector.size() << " By Name: " << m_nameMap.size() << " By PID: " << m_pidMap.size()
360 << " Total: " << m_set.size() << endmsg;
361 }
362
363 if ( !m_modified.empty() ) {
364 auto& log = always();
365 log << " New/updated particles (from \"Particles\" property)" << std::endl;
367 log << endmsg;
368 m_modified.clear();
369 }
370
371 if ( !m_by_charge.empty() ) {
372 info() << " Charge has beed redefined for " << Gaudi::Utils::toString( m_by_charge ) << endmsg;
373 }
374 if ( !m_by_mass.empty() ) {
375 info() << " Mass has beed redefined for " << Gaudi::Utils::toString( m_by_mass ) << endmsg;
376 }
377 if ( !m_by_tlife.empty() ) {
378 info() << " Lifetime has beed redefined for " << Gaudi::Utils::toString( m_by_tlife ) << endmsg;
379 }
380 if ( !m_by_width.empty() ) {
381 info() << " MaxWidth has beed redefined for " << Gaudi::Utils::toString( m_by_width ) << endmsg;
382 }
383 if ( !m_by_evtgen.empty() ) {
384 info() << " EvtGenID has beed redefined for " << Gaudi::Utils::toString( m_by_evtgen ) << endmsg;
385 }
386 if ( !m_by_pythia.empty() ) {
387 info() << " PythiaID has beed redefined for " << Gaudi::Utils::toString( m_by_pythia ) << endmsg;
388 }
389 if ( !m_replaced_names.empty() ) {
390 info() << " Replaced names : " << Gaudi::Utils::toString( m_replaced_names ) << endmsg;
391 }
392 if ( !m_replaced_pids.empty() ) {
393 info() << " Replaced PIDs : " << Gaudi::Utils::toString( m_replaced_pids ) << endmsg;
394 }
395 if ( !m_no_anti.empty() ) { info() << " No anti particle : " << Gaudi::Utils::toString( m_no_anti ) << endmsg; }
396
397 return StatusCode::SUCCESS;
398}
399
400/* the action in the case of interactive manipulation with properties:
401 * - no action if the internal data is not yet build
402 * - else rebuild the internal data
403 * Such action will allow more flexible interactive configuration
404 * of the service
405 */
407 if ( FSMState() < Gaudi::StateMachine::INITIALIZED ) { return; }
408
409 info() << "Property triggers the update of internal Particle Property Data : " << p << endmsg;
410 // rebuild the internal data
411 StatusCode sc = rebuild();
412 if ( sc.isFailure() ) {
413 throw GaudiException( "Can't rebuild Particle Properties Data", "*ParticlePropertySvc*", sc );
414 }
415 // clear CC-map
416 m_ccMap.clear();
417}
418
419// the action in the case of redefinition of "ChargeConjugates"
421
422/* the action in the case of interactive manipulation with properties:
423 * of the service
424 * @param p the updated property
425 */
430
432 auto fileAccess = service<IFileAccess>( "VFSSvc" );
433 if ( !fileAccess ) {
434 error() << "Unable to locate IFileAccess('VFSSvc') service" << endmsg;
435 return StatusCode::FAILURE;
436 }
437 // "open" the file
438 auto infile = fileAccess->open( file );
439 if ( !infile.get() ) {
440 error() << "Unable to open file '" << file << "'" << endmsg;
441 return StatusCode::FAILURE;
442 }
443 info() << "Opened particle properties file : " << file << endmsg;
444 bool active = false;
445 // read the file line-by-line
446 while ( *infile ) {
447 std::string line;
448 std::getline( *infile, line );
449 // skip empty lines:
450 if ( line.empty() ) { continue; }
451 // comment lines start with '#'
452 if ( line[0] == '#' ) { continue; }
453 //
454 if ( !active ) {
455 if ( "PARTICLE" == boost::to_upper_copy( boost::trim_copy( line ) ) ) {
456 active = true;
457 continue;
458 }
459 } else {
460 if ( "END PARTICLE" == boost::to_upper_copy( boost::trim_copy( line ) ) ) {
461 active = false;
462 continue;
463 }
464 }
465
466 if ( !active ) { continue; } // skip the lines if not active
467 // parse the line
468 if ( auto sc = parseLine( line ); sc.isFailure() ) {
469 error() << "Unable to parse the file '" << file << "'" << endmsg;
470 return sc;
471 }
472 }
473
474 return StatusCode::SUCCESS;
475}
476
477/* parse the line
478 * the format of the line is defined by old SICB CDF
479 * @param line the line to be parsed
480 * @return status code
481 */
483 // get the input stream from the line :
484 std::istringstream input( line );
485 // get the name
486 std::string p_name;
487 int p_geant; // obsolete, to be ignored
488 int p_pdg;
489 double p_charge;
490 double p_mass;
491 double p_ltime;
492 std::string p_evtgen;
493 int p_pythia;
494 double p_maxwid;
495 // parse the line
496 if ( input >> p_name >> p_geant >> p_pdg >> p_charge >> p_mass >> p_ltime >> p_evtgen >> p_pythia >> p_maxwid ) {
497 // Negative lifetime means the width in GeV-units
498 if ( 0 > p_ltime ) {
500 }
501
502 StatusCode sc = addParticle( p_name, Gaudi::ParticleID( p_pdg ), p_charge,
503 p_mass * Gaudi::Units::GeV, // rescale from CDF units
504 p_ltime * Gaudi::Units::s, // rescale from CDF units
505 p_maxwid * Gaudi::Units::GeV, // rescale from CDF units
506 p_evtgen, p_pythia );
507 if ( sc.isFailure() ) { return sc; }
508 } else {
509 MsgStream log( msgSvc(), name() );
510 log << MSG::ERROR << " could not parse the line: '" << line << "'" << endmsg;
511 return StatusCode::FAILURE;
512 }
513
514 return StatusCode::SUCCESS;
515}
516
518 const double charge, const double mass, const double tlife,
519 const double maxWidth, const std::string& evtgen,
520 const int pythia ) {
521 // create the local object
522 const Gaudi::ParticleProperty pp( pname, pid, charge, mass, tlife, maxWidth, evtgen, pythia );
523
524 // 1) find the object with same name & pid in set:
525 auto it = std::find_if( m_set.begin(), m_set.end(), [&]( const std::unique_ptr<Gaudi::ParticleProperty>& s ) {
526 return s->name() == pp.name() && s->pid() == pp.pid();
527 } );
528 // 2) object is found, redefine it!
529 Gaudi::ParticleProperty* newp = nullptr;
530 if ( m_set.end() != it ) { newp = it->get(); }
531 // new property ?
532 if ( !newp ) {
533 it = m_set.insert( std::make_unique<Gaudi::ParticleProperty>( pp ) ).first;
534 newp = it->get();
535 } else if ( diff( *newp, pp ) ) {
536 *newp = pp; // NB: redefine the properties
537 }
538
539 // insert into name map
540 {
541 auto i1 = m_nameMap.find( newp->name() );
542 if ( m_nameMap.end() != i1 && i1->second != newp ) { m_replaced_names.insert( newp->name() ); }
543 m_nameMap.update( newp->name(), newp );
544 }
545 // insert into PID map
546 {
547 auto i2 = m_pidMap.find( newp->pid() );
548 if ( m_pidMap.end() != i2 && i2->second != newp ) { m_replaced_pids.insert( newp->pid() ); }
549 m_pidMap.update( newp->pid(), newp );
550 }
551 // insert into vector
552 if ( m_vector.end() == std::find( m_vector.begin(), m_vector.end(), newp ) ) { m_vector.push_back( newp ); }
553
554 m_modified.push_back( newp );
555
556 return StatusCode::SUCCESS;
557}
558
560 for ( const Gaudi::ParticleProperty* _pp : m_vector ) {
561 Gaudi::ParticleProperty* pp = const_cast<Gaudi::ParticleProperty*>( _pp );
562 pp->setAntiParticle( nullptr );
563 // get the ID for antiParticle
564 Gaudi::ParticleID panti( -pp->particleID().pid() );
565 //
566 const Gaudi::ParticleProperty* anti = m_pidMap( panti );
567 //
568 if ( !anti && 0 < pp->particleID().pid() && !pp->particleID().isNucleus() ) { anti = _pp; }
569 //
570 pp->setAntiParticle( anti );
571 if ( pp->antiParticle() ) {
572 if ( msgLevel( MSG::VERBOSE ) )
573 verbose() << "Antiparticle for \n" << ( *pp ) << " is set to be \n" << ( *( pp->antiParticle() ) ) << endmsg;
574 }
575 if ( ( !pp->antiParticle() ) && ( 0 == pp->pid().extraBits() ) ) { m_no_anti.insert( pp->name() ); }
576 }
577 return StatusCode::SUCCESS;
578}
579
580namespace {
581 inline bool different( const double a, const double b, const double p = 1.e-8 ) {
582 return std::abs( a - b ) > ( std::abs( a ) + std::abs( b ) ) * std::abs( p );
583 }
584 inline bool different( const std::string& a, const std::string& b ) { return a != b; }
585} // namespace
586
588 bool d = false;
589
590 if ( different( n.charge(), o.charge() ) ) {
591 m_by_charge.insert( n.name() );
592 d = true;
593 }
594 if ( different( n.mass(), o.mass() ) ) {
595 m_by_mass.insert( n.name() );
596 d = true;
597 }
598 if ( different( n.lifetime(), o.lifetime() ) ) {
599 m_by_tlife.insert( n.name() );
600 d = true;
601 }
602 if ( different( n.maxWidth(), o.maxWidth() ) ) {
603 m_by_width.insert( n.name() );
604 d = true;
605 }
606 if ( different( n.evtGen(), o.evtGen() ) ) {
607 m_by_evtgen.insert( n.name() );
608 d = true;
609 }
610 if ( different( n.pythia(), o.pythia() ) ) {
611 m_by_pythia.insert( n.name() );
612 d = true;
613 }
614
615 if ( d ) {
616 MsgStream log( msgSvc(), name() );
617 if ( log.level() <= MSG::DEBUG )
618 log << MSG::DEBUG << " Change the properties of '" << n.name() << "'/" << n.pid().pid() << std::endl
619 << " New: " << n << std::endl
620 << " Old: " << o << endmsg;
621 }
622 return d;
623}
624
626 auto& log = always();
627 log << " The Table of Particle Properties " << std::endl;
629 log << endmsg;
630}
631
632/* make the charge conjugation for the string/decay descriptor
633 *
634 * @code
635 *
636 * std::string decay = "B0 -> pi+ pi-" ;
637 *
638 * Gaudi::IParticlePropertySvc* svc = ... ;
639 *
640 * std::string cc = svc -> cc ( decay ) ;
641 *
642 * @endcode
643 *
644 * @param decay the decay descriptor
645 * @return the charge conjugation for the decay descriptor
646 */
647std::string Gaudi::ParticlePropertySvc::cc( const std::string& decay ) const {
648 // build the map if not done yet
649 if ( m_ccMap.empty() ) {
650 // get the particles from the service
651 for ( const auto& pp : m_vector ) {
652 if ( !pp ) { continue; }
653 const Gaudi::ParticleProperty* anti = pp->antiParticle();
654 if ( !anti ) { continue; }
655 m_ccMap[pp->particle()] = anti->particle();
656 }
657 // get the particles from the options
658 for ( const auto& ic : m_ccmap_.value() ) {
659 m_ccMap[ic.first] = ic.second;
660 m_ccMap[ic.second] = ic.first;
661 }
662 if ( msgLevel( MSG::DEBUG ) ) {
663 Gaudi::Utils::toStream( m_ccMap, ( debug() << " CC-map is \n" ).stream() );
664 debug() << endmsg;
665 }
666 }
667 // use the map
668 return Decays::CC::cc( decay, m_ccMap );
669}
670
StatusCode parse(DataObjID &dest, std::string_view src)
Definition DataObjID.cpp:58
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_COMPONENT(type)
MsgStream & error() const
shortcut for the method msgStream(MSG::ERROR)
MsgStream & verbose() const
shortcut for the method msgStream(MSG::VERBOSE)
const SmartIF< IMessageSvc > & msgSvc() const
The standard message service.
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
MsgStream & always() const
shortcut for the method msgStream(MSG::ALWAYS)
const CCMap & cc() const
get CC-map
Definition Symbols.cpp:121
static Symbols & instance()
static accessor to teh singleton
Definition Symbols.cpp:39
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
std::vector< const Gaudi::ParticleProperty * > ParticleProperties
the actual type of (ordered) container of particle properties
Holds PDG + LHCb extension particle code, following the PDG particle numbering scheme (pdg....
Definition ParticleID.h:43
A trivial class to hold information about a single particle properties.
double charge() const
Get the particle charge.
double lifetime() const
Get the particle lifetime.
const std::string & evtGen() const
Get the EvtGen name.
const std::string & particle() const
Get the particle name.
double maxWidth() const
Get the max width deviation.
double mass() const
Get the particle mass.
const Gaudi::ParticleID & pid() const
get the particle ID
const std::string & name() const
Get the particle name.
int pythia() const
Get the Pythia ID.
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
Define general base for Gaudi exception.
A bit modified version of 'Loki::AssocVector' associative vector from Loki library by Andrei Alexandr...
Definition VectorMap.h:100
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition ISvcLocator.h:42
Definition of the MsgStream class used to transmit messages.
Definition MsgStream.h:29
Gaudi::StateMachine::State FSMState() const override
Definition Service.h:55
const std::string & name() const override
Retrieve name of the service.
Definition Service.cpp:333
SmartIF< IFace > service(const std::string &name, bool createIf=true) const
Definition Service.h:79
StatusCode initialize() override
Definition Service.cpp:118
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:129
constexpr static const auto SUCCESS
Definition StatusCode.h:99
constexpr static const auto FAILURE
Definition StatusCode.h:100
Base class used to extend a class implementing other interfaces.
Definition extends.h:19
std::map< std::string, std::string, CmpCC > MapCC
the actual type of CC-map
Definition CC.h:36
std::string cc(const std::string &decay, const MapCC &map_)
simple function to make charge conjugated inside the original string.
Definition CC.cpp:67
GAUDI_API std::string printAsTable(const std::vector< const Gaudi::ParticleProperty * > &particles, const Gaudi::Interfaces::IParticlePropertySvc *service=0)
print a list of properties in a form of the table
constexpr double s
constexpr double GeV
constexpr double hbar_Planck
std::string toString(const TYPE &obj)
the generic implementation of the type conversion to the string
Definition ToStream.h:326
std::ostream & toStream(ITERATOR first, ITERATOR last, std::ostream &s, const std::string &open, const std::string &close, const std::string &delim)
the helper function to print the sequence
Definition ToStream.h:304
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
@ DEBUG
Definition IMessageSvc.h:22
@ ERROR
Definition IMessageSvc.h:22
@ INFO
Definition IMessageSvc.h:22
@ VERBOSE
Definition IMessageSvc.h:22
Gaudi::ParticleID abs(const Gaudi::ParticleID &p)
Return the absolute value for a PID.
Definition ParticleID.h:191
The comparison criteria for particle properties.
This service provides access to particle properties.
std::vector< std::string > Files
the actual type for the list of files
Gaudi::Property< bool > m_dump
dump the table?
iterator end() const override
get the end-iterator for the container of particle properties It is assumed that the container is pro...
StatusCode initialize() override
Initialize the service.
const Gaudi::ParticleProperty * find(const Gaudi::ParticleID &pid) const override
Retrieve an object by PID:
Gaudi::Property< Particles > m_particles
properties to be redefined explicitly
StatusCode rebuild()
rebuild the Particle Property Data
Gaudi::Property< std::map< std::string, std::string > > m_ccmap_
CC-map for properties.
std::set< std::unique_ptr< Gaudi::ParticleProperty > > Set
the actual storage of all properties
bool diff(const Gaudi::ParticleProperty &n, const Gaudi::ParticleProperty &o)
check the difference of two properties and fill corresponding sets
std::set< Gaudi::ParticleID > PidSet
std::set< std::string > NameSet
Gaudi::Property< std::string > m_filename
the main file with particle properties
StatusCode setAntiParticles()
set properly particle<-->antiparticle relations
StatusCode parse(const std::string &file)
parse the file
StatusCode addParticle(const std::string &pname, const Gaudi::ParticleID &pid, const double charge, const double mass, const double tlife, const double maxWidth, const std::string &evtgen, const int pythia)
add new particle (or redefine the existing one)
ParticlePropertySvc(const std::string &name, ISvcLocator *pSvc)
Standard Constructor.
Set m_set
the actual storage of all particle properties
size_t size() const override
get the container size.
const Gaudi::ParticleProperty * find(const std::string &name) const override
Retrieve an object by name:
PidMap m_pidMap
Map: { "pid" : "property" }.
iterator begin() const override
get the begin-iterator for the container of particle properties It is assumed that the container is p...
Gaudi::Property< Files > m_other
additional files
NameMap m_nameMap
Map: { "name" : "property" }.
StatusCode parseLine(const std::string &line)
parse the line
void updateDump(Gaudi::Details::PropertyBase &p)
the action in the case of interactive manipulation with properties: of the service
GaudiUtils::VectorMap< Gaudi::ParticleID, const Gaudi::ParticleProperty * > PidMap
the actual type of map: { "pid" : "property" }
Vector m_vector
"visible" data (the ordered container)
Gaudi::Interfaces::IParticlePropertySvc::ParticleProperties Vector
std::string cc(const std::string &decay) const override
make the charge conjugation for the string/decay descriptor
void dump()
dump the table of particle properties
GaudiUtils::VectorMap< std::string, const Gaudi::ParticleProperty * > NameMap
the actual type of map: { "name" : "property" }
Decays::CC::MapCC m_ccMap
the CC-map
void updateCC(Gaudi::Details::PropertyBase &p)
the action in the case of interactive manipulation with properties: of the service
std::vector< std::string > Particles
the actual type for the list of particle properties (strings)
void updateHandler(Gaudi::Details::PropertyBase &p)
the action in the case of interactive manipulation with properties: