SSO Logout

Subversion Repositories hepmc

Rev

Rev 25 | Rev 65 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 garren 1
//////////////////////////////////////////////////////////////////////////
2
// Matt.Dobbs@Cern.CH, September 1999
3
// GenVertex within an event
4
//////////////////////////////////////////////////////////////////////////
5
 
6
#include "HepMC/GenParticle.h"
7
#include "HepMC/GenVertex.h"
8
#include "HepMC/GenEvent.h"
25 garren 9
#include <iomanip>       // needed for formatted output
2 garren 10
 
11
namespace HepMC {
12
 
43 garren 13
    GenVertex::GenVertex( const FourVector& position,
2 garren 14
                          int id, const WeightContainer& weights )
15
        : m_position(position), m_id(id), m_weights(weights), m_event(0),
16
          m_barcode(0)
17
    {
18
        s_counter++;
19
    }
20
 
21
    GenVertex::GenVertex( const GenVertex& invertex ) : m_event(0),
22
                                                        m_barcode(0) {
23
        // Shallow copy: does not copy the FULL list of particle pointers.
24
        // Creates a copy of  - invertex
25
        //                    - outgoing particles of invertex, but sets the
26
        //                      decay vertex of these particles to NULL
27
        //                    - all incoming particles which do not have a
28
        //                      creation vertex.
29
        // (i.e. it creates copies of all particles which it owns)
30
        // (note - impossible to copy the FULL list of particle pointers 
31
        //         while having the vertex
32
        //         and particles in/out point-back to one another -- unless you
33
        //         copy the entire tree -- which we don't want to do)
34
        *this = invertex;
35
        s_counter++;
36
    }
37
 
38
    GenVertex::~GenVertex() {
39
        //
40
        // need to delete any particles previously owned by this vertex
41
        if ( parent_event() ) parent_event()->remove_barcode(this);
42
        delete_adopted_particles();
43
        s_counter--;
44
    }
45
 
46
    GenVertex& GenVertex::operator=( const GenVertex& invertex ) {
47
        // Shallow: does not copy the FULL list of particle pointers.
48
        // Creates a copy of  - invertex
49
        //                    - outgoing particles of invertex, but sets the
50
        //                      decay vertex of these particles to NULL
51
        //                    - all incoming particles which do not have a
52
        //                      creation vertex.
53
        //                    - it does not alter *this's m_event (!)
54
        // (i.e. it creates copies of all particles which it owns)
55
        // (note - impossible to copy the FULL list of particle pointers 
56
        //         while having the vertex
57
        //         and particles in/out point-back to one another -- unless you
58
        //         copy the entire tree -- which we don't want to do)
59
        //
60
        // first need to delete any particles previously owned by this vertex
61
        delete_adopted_particles();
62
        //
63
        for ( particles_in_const_iterator
64
                  part1 = invertex.particles_in_const_begin();
65
              part1 != invertex.particles_in_const_end(); part1++ ) {
66
            if ( !(*part1)->production_vertex() ) {
67
                GenParticle* pin = new GenParticle(**part1);
68
                add_particle_in(pin);
69
            }
70
        }
71
        for ( particles_out_const_iterator
72
                  part2 = invertex.particles_out_const_begin();
73
              part2 != invertex.particles_out_const_end(); part2++ ) {
74
            GenParticle* pin = new GenParticle(**part2);
75
            add_particle_out(pin);
76
        }
77
        set_position( invertex.position() );
78
        set_id( invertex.id() );
79
        weights() = invertex.weights();
80
        suggest_barcode( invertex.barcode() );
81
        return *this;
82
    }
83
 
84
    bool GenVertex::operator==( const GenVertex& a ) const {
85
        // Returns true if the positions and the particles in the lists of a 
86
        //  and this are identical. Does not compare barcodes.
87
        // Note that it is impossible for two vertices to point to the same 
88
        //  particle's address, so we need to do more than just compare the
89
        //  particle pointers
90
        //
91
        if ( a.position() !=  this->position() ) return 0;
92
        // if the size of the inlist differs, return false.
93
        if ( a.particles_in_size() !=  this->particles_in_size() ) return 0;
94
        // if the size of the outlist differs, return false.
95
        if ( a.particles_out_size() !=  this->particles_out_size() ) return 0;
96
        // loop over the inlist and ensure particles are identical
97
        //   (only do this if the lists aren't empty - we already know
98
        //   if one isn't, then other isn't either!)
99
        if ( a.particles_in_const_begin() != a.particles_in_const_end() ) {
100
            for ( GenVertex::particles_in_const_iterator
101
                      ia = a.particles_in_const_begin(),
102
                      ib = this->particles_in_const_begin();
103
                  ia != a.particles_in_const_end(); ia++, ib++ ){
104
                if ( **ia != **ib ) return 0;
105
            }
106
        }
107
        // loop over the outlist and ensure particles are identical
108
        //   (only do this if the lists aren't empty - we already know
109
        //   if one isn't, then other isn't either!)
110
        if ( a.particles_out_const_begin() != a.particles_out_const_end() ) {
111
            for ( GenVertex::particles_out_const_iterator
112
                      ia = a.particles_out_const_begin(),
113
                      ib = this->particles_out_const_begin();
114
                  ia != a.particles_out_const_end(); ia++, ib++ ){
115
                if ( **ia != **ib ) return 0;
116
            }
117
        }
118
        return 1;
119
    }
120
 
121
    bool GenVertex::operator!=( const GenVertex& a ) const {
122
        // Returns true if the positions and lists of a and this are not equal.
123
        return !( a == *this );
124
    }  
125
 
126
    void GenVertex::print( std::ostream& ostr ) const {
127
        if ( barcode()!=0 ) {
43 garren 128
            if ( position() != FourVector(0,0,0,0) ) {
25 garren 129
                ostr << "Vertex:";
130
                ostr.width(9);
131
                ostr << barcode();
132
                ostr << " ID:";
133
                ostr.width(5);
134
                ostr << id();
135
                ostr << " (X,cT)=";
136
                ostr.width(9);
137
                ostr.precision(2);
138
                ostr.setf(std::ios::scientific, std::ios::floatfield);
139
                ostr.setf(std::ios_base::showpos);
140
                ostr << position().x() << ",";
141
                ostr.width(9);
142
                ostr.precision(2);
143
                ostr << position().y() << ",";
144
                ostr.width(9);
145
                ostr.precision(2);
146
                ostr << position().z() << ",";
147
                ostr.width(9);
148
                ostr.precision(2);
149
                ostr << position().t();
150
                ostr.setf(std::ios::fmtflags(0), std::ios::floatfield);
151
                ostr.unsetf(std::ios_base::showpos);
152
                ostr << std::endl;
2 garren 153
            } else {
25 garren 154
                ostr << "GenVertex:";
155
                ostr.width(9);
156
                ostr << barcode();
157
                ostr << " ID:";
158
                ostr.width(5);
159
                ostr << id();
160
                ostr << " (X,cT):0";
161
                ostr << std::endl;
2 garren 162
            }
163
        } else {
164
            // If the vertex doesn't have a unique barcode assigned, then
165
            //  we print its memory address instead... so that the
166
            //  print out gives us a unique tag for the particle.
43 garren 167
            if ( position() != FourVector(0,0,0,0) ) {
25 garren 168
                ostr << "Vertex:";
169
                ostr.width(9);
170
                ostr << (void*)this;
171
                ostr << " ID:";
172
                ostr.width(5);
173
                ostr << id();
174
                ostr << " (X,cT)=";
175
                ostr.width(9);
176
                ostr.precision(2);
177
                ostr.setf(std::ios::scientific, std::ios::floatfield);
178
                ostr.setf(std::ios_base::showpos);
179
                ostr << position().x();
180
                ostr.width(9);
181
                ostr.precision(2);
182
                ostr << position().y();
183
                ostr.width(9);
184
                ostr.precision(2);
185
                ostr << position().z();
186
                ostr.width(9);
187
                ostr.precision(2);
188
                ostr << position().t();
189
                ostr.setf(std::ios::fmtflags(0), std::ios::floatfield);
190
                ostr.unsetf(std::ios_base::showpos);
191
                ostr << std::endl;
2 garren 192
            } else {
25 garren 193
                ostr << "GenVertex:";
194
                ostr.width(9);
195
                ostr << (void*)this;
196
                ostr << " ID:";
197
                ostr.width(5);
198
                ostr << id();
199
                ostr << " (X,cT):0";
200
                ostr << std::endl;
2 garren 201
            }
202
        }
203
 
204
        // print the weights if there are any
205
        if ( ! weights().empty() ) {
206
            ostr << " Wgts(" << weights().size() << ")=";
207
            for ( WeightContainer::const_iterator wgt = weights().begin();
208
                  wgt != weights().end(); wgt++ ) { ostr << *wgt << " "; }
209
            ostr << std::endl;
210
        }
211
        // print out all the incoming, then outgoing particles
212
        for ( particles_in_const_iterator part1 = particles_in_const_begin();
213
              part1 != particles_in_const_end(); part1++ ) {
214
            if ( part1 == particles_in_const_begin() ) {
25 garren 215
                ostr << " I:";
216
                ostr.width(2);
217
                ostr << m_particles_in.size();
2 garren 218
            } else { ostr << "     "; }
219
            //(*part1)->print( ostr );  //uncomment for long debugging printout
220
            ostr << **part1 << std::endl;
221
        }
222
        for ( particles_out_const_iterator part2 = particles_out_const_begin();
223
              part2 != particles_out_const_end(); part2++ ) {
224
            if ( part2 == particles_out_const_begin() ) {
25 garren 225
                ostr << " O:";
226
                ostr.width(2);
227
                ostr << m_particles_out.size();
2 garren 228
            } else { ostr << "     "; }
229
            //(*part2)->print( ostr ); // uncomment for long debugging printout
230
            ostr << **part2 << std::endl;
231
        }
232
    }
233
 
234
    double GenVertex::check_momentum_conservation() const {
235
        // finds the difference between the total momentum out and the total
236
        // momentum in vectors, and returns the magnitude of this vector
237
        // i.e.         returns | \vec{p_in} - \vec{p_out} |
238
        double sumpx = 0, sumpy = 0, sumpz = 0;
239
        for ( particles_in_const_iterator part1 = particles_in_const_begin();
240
              part1 != particles_in_const_end(); part1++ ) {
241
            sumpx   += (*part1)->momentum().px();
242
            sumpy   += (*part1)->momentum().py();
243
            sumpz   += (*part1)->momentum().pz();
244
        }
245
        for ( particles_out_const_iterator part2 = particles_out_const_begin();
246
              part2 != particles_out_const_end(); part2++ ) {
247
            sumpx   -= (*part2)->momentum().px();
248
            sumpy   -= (*part2)->momentum().py();
249
            sumpz   -= (*part2)->momentum().pz();
250
        }
251
        return sqrt( sumpx*sumpx + sumpy*sumpy + sumpz*sumpz );
252
    }
253
 
254
    void GenVertex::add_particle_in( GenParticle* inparticle ) {
255
        if ( !inparticle ) return;
256
        // if inparticle previously had a decay vertex, remove it from that
257
        // vertex's list
258
        if ( inparticle->end_vertex() ) {
259
            inparticle->end_vertex()->m_particles_in.erase( inparticle );
260
        }
261
        m_particles_in.insert( inparticle );
262
        inparticle->set_end_vertex_( this );
263
    }
264
 
265
    void GenVertex::add_particle_out( GenParticle* outparticle ) {
266
        if ( !outparticle ) return;
267
        // if outparticle previously had a production vertex,
268
        // remove it from that vertex's list
269
        if ( outparticle->production_vertex() ) {
270
            outparticle->production_vertex()->m_particles_out.erase(
271
                outparticle );
272
        }
273
        m_particles_out.insert( outparticle );
274
        outparticle->set_production_vertex_( this );
275
    }
276
 
277
    GenParticle* GenVertex::remove_particle( GenParticle* particle ) {
278
        // this finds *particle in the in and/or out list and removes it from
279
        //  these lists ... it DOES NOT DELETE THE PARTICLE or its relations.
280
        // you could delete the particle too as follows:
281
        //      delete vtx->remove_particle( particle );
282
        // or if the particle has an end vertex, you could:
283
        //      delete vtx->remove_particle( particle )->end_vertex();
284
        // which would delete the particle's end vertex, and thus would
285
        // also delete the particle, since the particle would be 
286
        // owned by the end vertex.
287
        if ( !particle ) return 0;
288
        if ( particle->end_vertex() == this ) {
289
            particle->set_end_vertex_( 0 );
290
            m_particles_in.erase(particle);
291
        }
292
        if ( particle->production_vertex() == this ) {
293
            particle->set_production_vertex_(0);
294
            m_particles_out.erase(particle);
295
        }
296
        return particle;
297
    }
298
 
299
    void GenVertex::delete_adopted_particles() {
300
        // deletes all particles which this vertex owns
301
        // to be used by the vertex destructor and operator=
302
        //
303
        if ( m_particles_out.empty() && m_particles_in.empty() ) return;
304
        // 1. delete all outgoing particles which don't have decay vertices.
305
        //    those that do become the responsibility of the decay vertex
306
        //    and have their productionvertex pointer set to NULL
307
        for ( std::set<GenParticle*>::iterator part1 = m_particles_out.begin();
308
              part1 != m_particles_out.end(); ) {
309
            if ( !(*part1)->end_vertex() ) {
310
                delete *(part1++);
311
            } else {
312
                (*part1)->set_production_vertex_(0);
313
                ++part1;
314
            }
315
        }
316
        m_particles_out.clear();
317
        //
318
        // 2. delete all incoming particles which don't have production
319
        //    vertices. those that do become the responsibility of the 
320
        //    production vertex and have their decayvertex pointer set to NULL
321
        for ( std::set<GenParticle*>::iterator part2 = m_particles_in.begin();
322
              part2 != m_particles_in.end(); ) {
323
            if ( !(*part2)->production_vertex() ) {
324
                delete *(part2++);
325
            } else {
326
                (*part2)->set_end_vertex_(0);
327
                ++part2;
328
            }
329
        }
330
        m_particles_in.clear();
331
    }
332
 
333
    bool GenVertex::suggest_barcode( int the_bar_code )
334
    {
335
        // allows a barcode to be suggested for this vertex.
336
        // In general it is better to let the event pick the barcode for
337
        // you, which is automatic.
338
        // Returns TRUE if the suggested barcode has been accepted (i.e. the
339
        //  suggested barcode has not already been used in the event, 
340
        //  and so it was used).
341
        // Returns FALSE if the suggested barcode was rejected, or if the
342
        //  vertex is not yet part of an event, such that it is not yet
343
        //  possible to know if the suggested barcode will be accepted).
344
        if ( the_bar_code >0 ) {
345
            std::cerr << "GenVertex::suggest_barcode WARNING, vertex bar codes"
346
                      << "\n MUST be negative integers. Positive integers "
347
                      << "\n are reserved for particles only. Your suggestion "
348
                      << "\n has been rejected." << std::endl;
349
            return false;
350
        }
351
        bool success = false;
352
        if ( parent_event() ) {
353
            success = parent_event()->set_barcode( this, the_bar_code );
354
        } else { set_barcode_( the_bar_code ); }
355
        return success;
356
    }
357
 
358
    void GenVertex::set_parent_event_( GenEvent* new_evt )
359
    {
360
        GenEvent* orig_evt = m_event;
361
        m_event = new_evt;
362
        //
363
        // every time a vertex's parent event changes, the map of barcodes
364
        //   in the new and old parent event needs to be modified to 
365
        //   reflect this
366
        if ( orig_evt != new_evt ) {
367
            if (new_evt) new_evt->set_barcode( this, barcode() );
368
            if (orig_evt) orig_evt->remove_barcode( this );
369
            // we also need to loop over all the particles which are owned by 
370
            //  this vertex, and remove their barcodes from the old event.
371
            for ( particles_in_const_iterator part1=particles_in_const_begin();
372
                  part1 != particles_in_const_end(); part1++ ) {
373
                if ( !(*part1)->production_vertex() ) {
374
                    if ( orig_evt ) orig_evt->remove_barcode( *part1 );
375
                    if ( new_evt ) new_evt->set_barcode( *part1,
376
                                                         (*part1)->barcode() );
377
                }
378
            }
379
            for ( particles_out_const_iterator
380
                      part2 = particles_out_const_begin();
381
                  part2 != particles_out_const_end(); part2++ ) {
382
                    if ( orig_evt ) orig_evt->remove_barcode( *part2 );
383
                    if ( new_evt ) new_evt->set_barcode( *part2,
384
                                                         (*part2)->barcode() );
385
            }
386
        }
387
    }
388
 
389
    /////////////
390
    // Static  //
391
    /////////////
392
    unsigned int GenVertex::counter() { return s_counter; }
393
    unsigned int GenVertex::s_counter = 0;
394
 
395
    /////////////
396
    // Friends //
397
    /////////////
398
 
399
    std::ostream& operator<<( std::ostream& ostr, const GenVertex& vtx ) {
400
        if ( vtx.barcode()!=0 ) ostr << "BarCode " << vtx.barcode();
401
        else ostr << "Address " << &vtx;
402
        ostr << " (X,cT)=";
43 garren 403
        if ( vtx.position() != FourVector(0,0,0,0)) {
2 garren 404
            ostr << vtx.position().x() << ","
405
                 << vtx.position().y() << ","
406
                 << vtx.position().z() << ","
407
                 << vtx.position().t();
408
        } else { ostr << 0; }
409
        ostr << " #in:" << vtx.particles_in_size()
410
             << " #out:" << vtx.particles_out_size();
411
        return ostr;
412
    }
413
 
414
    /////////////////////////////
415
    // edge_iterator           // (protected - for internal use only)
416
    /////////////////////////////
417
    // If the user wants the functionality of the edge_iterator, he should
418
    // use particle_iterator with IteratorRange = family, parents, or children
419
    //
420
 
421
    GenVertex::edge_iterator::edge_iterator() : m_vertex(0), m_range(family),
422
        m_is_inparticle_iter(0), m_is_past_end(1)
423
    {}
424
 
425
    GenVertex::edge_iterator::edge_iterator( const GenVertex& vtx,
426
                                          IteratorRange range ) :
427
        m_vertex(&vtx), m_range(family)
428
    {
429
        // Note: (26.1.2000) the original version of edge_iterator inheritted
430
        //       from set<GenParticle*>::const_iterator() rather than using
431
        //       composition as it does now.
432
        //       The inheritted version suffered from a strange bug, which
433
        //       I have not fully understood --- it only occurred after many
434
        //       events were processed and only when I called the delete 
435
        //       function on past events. I believe it had something to do with
436
        //       the past the end values, which are now robustly coded in this
437
        //       version as boolean members.
438
        //
439
        // default range is family, only other choices are children/parents
440
        //    descendants/ancestors not allowed & recasted ot children/parents
441
        if ( range == descendants || range == children ) m_range = children;
442
        if ( range == ancestors   || range == parents  ) m_range = parents;
443
        //
444
        if ( m_vertex->m_particles_in.empty() &&
445
             m_vertex->m_particles_out.empty() ) {
446
            // Case: particles_in and particles_out is empty.
447
            m_is_inparticle_iter = 0;
448
            m_is_past_end = 1;
449
        } else if ( m_range == parents && m_vertex->m_particles_in.empty() ){
450
            // Case: particles in is empty and parents is requested.
451
            m_is_inparticle_iter = 1;
452
            m_is_past_end = 1;
453
        } else if ( m_range == children && m_vertex->m_particles_out.empty() ){
454
            // Case: particles out is empty and children is requested.
455
            m_is_inparticle_iter = 0;
456
            m_is_past_end = 1;
457
        } else if ( m_range == children ) {
458
            // Case: particles out is NOT empty, and children is requested
459
            m_set_iter = m_vertex->m_particles_out.begin();
460
            m_is_inparticle_iter = 0;
461
            m_is_past_end = 0;
462
        } else if ( m_range == family && m_vertex->m_particles_in.empty() ) {
463
            // Case: particles in is empty, particles out is NOT empty,
464
            //       and family is requested. Then skip ahead to partilces out.
465
            m_set_iter = m_vertex->m_particles_out.begin();
466
            m_is_inparticle_iter = 0;
467
            m_is_past_end = 0;
468
        } else {
469
            // Normal scenario: start with the first incoming particle
470
            m_set_iter = m_vertex->m_particles_in.begin();
471
            m_is_inparticle_iter = 1;
472
            m_is_past_end = 0;
473
        }
474
    }
475
 
476
    GenVertex::edge_iterator::edge_iterator( const edge_iterator& p ) {
477
        *this = p;
478
    }
479
 
480
    GenVertex::edge_iterator::~edge_iterator() {}
481
 
482
    GenVertex::edge_iterator& GenVertex::edge_iterator::operator=(
483
        const edge_iterator& p ) {
484
        m_vertex = p.m_vertex;
485
        m_range = p.m_range;
486
        m_set_iter = p.m_set_iter;
487
        m_is_inparticle_iter = p.m_is_inparticle_iter;
488
        m_is_past_end = p.m_is_past_end;
489
        return *this;
490
    }
491
 
492
    GenParticle* GenVertex::edge_iterator::operator*(void) const {
493
        if ( !m_vertex || m_is_past_end ) return 0;
494
        return *m_set_iter;
495
    }
496
 
497
    GenVertex::edge_iterator& GenVertex::edge_iterator::operator++(void){
498
        // Pre-fix increment
499
        //
500
        // increment the set iterator (unless we're past the end value)
501
        if ( m_is_past_end ) return *this;
502
        ++m_set_iter;
503
        // handle cases where m_set_iter points past the end
504
        if ( m_range == family && m_is_inparticle_iter &&
505
             m_set_iter == m_vertex->m_particles_in.end() ) {
506
            // at the end on in particle set, and range is family, so move to
507
            // out particle set
508
            m_set_iter = m_vertex->m_particles_out.begin();
509
            m_is_inparticle_iter = 0;
510
        } else if ( m_range == parents &&
511
                    m_set_iter == m_vertex->m_particles_in.end() ) {
512
            // at the end on in particle set, and range is parents only, so
513
            // move into past the end state
514
            m_is_past_end = 1;
515
        }
516
        // the following is not else if because we might have range=family
517
        // with an empty particles_out set.     
518
        if ( m_set_iter == m_vertex->m_particles_out.end() ) {
519
            //whenever out particles end is reached, go into past the end state
520
            m_is_past_end = 1;
521
        }
522
        return *this;
523
    }
524
 
525
    GenVertex::edge_iterator GenVertex::edge_iterator::operator++(int){
526
        // Post-fix increment
527
        edge_iterator returnvalue = *this;
528
        ++*this;
529
        return returnvalue;
530
    }
531
 
532
    bool GenVertex::edge_iterator::is_parent() const {
533
        if ( **this && (**this)->end_vertex() == m_vertex ) return 1;
534
        return 0;
535
    }
536
 
537
    bool GenVertex::edge_iterator::is_child() const {
538
        if ( **this && (**this)->production_vertex() == m_vertex ) return 1;
539
        return 0;
540
    }
541
 
542
    int GenVertex::edges_size( IteratorRange range ) const {
543
        if ( range == children ) return m_particles_out.size();
544
        if ( range == parents ) return m_particles_in.size();
545
        if ( range == family ) return m_particles_out.size()
546
                                      + m_particles_in.size();
547
        return 0;
548
    }
549
 
550
    /////////////////////
551
    // vertex_iterator //
552
    /////////////////////
553
 
554
    GenVertex::vertex_iterator::vertex_iterator()
555
        : m_vertex(0), m_visited_vertices(0), m_it_owns_set(0),
556
          m_recursive_iterator(0)
557
    {}
558
 
559
    GenVertex::vertex_iterator::vertex_iterator( GenVertex& vtx_root,
560
                                              IteratorRange range )
561
        : m_vertex(&vtx_root), m_range(range)
562
    {
563
        // standard public constructor
564
        //
565
        m_visited_vertices = new std::set<const GenVertex*>;
566
        m_it_owns_set = 1;
567
        m_visited_vertices->insert( m_vertex );
568
        m_recursive_iterator = 0;
569
        m_edge = m_vertex->edges_begin( m_range );
570
        // advance to the first good return value
571
        if ( !follow_edge_() &&
572
             m_edge != m_vertex->edges_end( m_range )) ++*this;
573
    }
574
 
575
    GenVertex::vertex_iterator::vertex_iterator( GenVertex& vtx_root,
576
        IteratorRange range, std::set<const GenVertex*>& visited_vertices ) :
577
        m_vertex(&vtx_root), m_range(range),
578
        m_visited_vertices(&visited_vertices), m_it_owns_set(0),
579
        m_recursive_iterator(0)
580
    {
581
        // This constuctor is only to be called internally by this class
582
        //   for use with its recursive member pointer (m_recursive_iterator).
583
        // Note: we do not need to insert m_vertex_root in the vertex - that is
584
        //  the responsibility of this iterator's mother, which is normally
585
        //  done just before calling this protected constructor.
586
        m_edge = m_vertex->edges_begin( m_range );
587
        // advance to the first good return value
588
        if ( !follow_edge_() &&
589
             m_edge != m_vertex->edges_end( m_range )) ++*this;
590
     }
591
 
592
    GenVertex::vertex_iterator::vertex_iterator( const vertex_iterator& v_iter)
593
        : m_vertex(0), m_visited_vertices(0), m_it_owns_set(0),
594
          m_recursive_iterator(0)
595
    {
596
        *this = v_iter;
597
    }
598
 
599
    GenVertex::vertex_iterator::~vertex_iterator() {
600
        if ( m_recursive_iterator ) delete m_recursive_iterator;
601
        if ( m_it_owns_set ) delete m_visited_vertices;
602
    }
603
 
604
    GenVertex::vertex_iterator& GenVertex::vertex_iterator::operator=(
605
        const vertex_iterator& v_iter )
606
    {
607
        // Note: when copying a vertex_iterator that is NOT the owner
608
        // of its set container, the pointer to the set is copied. Beware!
609
        // (see copy_with_own_set() if you want a different set pointed to)
610
        // In practise the user never needs to worry
611
        // since such iterators are only intended to be used internally.
612
        //
613
        // destruct data member pointers
614
        if ( m_recursive_iterator ) delete m_recursive_iterator;
615
        m_recursive_iterator = 0;
616
        if ( m_it_owns_set ) delete m_visited_vertices;
617
        m_visited_vertices = 0;
618
        m_it_owns_set = 0;
619
        // copy the target vertex_iterator to this iterator 
620
        m_vertex = v_iter.m_vertex;
621
        m_range = v_iter.m_range;
622
        if ( v_iter.m_it_owns_set ) {
623
            // i.e. this vertex will own its set if v_iter points to any
624
            // vertex set regardless of whether v_iter owns the set or not!
625
            m_visited_vertices =
626
                new std::set<const GenVertex*>(*v_iter.m_visited_vertices);
627
            m_it_owns_set = 1;
628
        } else {
629
            m_visited_vertices = v_iter.m_visited_vertices;
630
            m_it_owns_set = 0;
631
        }
632
        //
633
        // Note: m_vertex_root is already included in the set of 
634
        //  tv_iter.m_visited_vertices, we do not need to insert it.
635
        //
636
        m_edge = v_iter.m_edge;
637
        copy_recursive_iterator_( v_iter.m_recursive_iterator );
638
        return *this;
639
    }
640
 
641
    GenVertex* GenVertex::vertex_iterator::operator*(void) const {
642
        // de-reference operator
643
        //
644
        // if this iterator has an iterator_node, then we return the iterator
645
        // node.
646
        if ( m_recursive_iterator ) return  **m_recursive_iterator;
647
        //
648
        // an iterator can only return its m_vertex -- any other vertex
649
        //  is returned by means of a recursive iterator_node 
650
        //  (so this is the only place in the iterator code that a vertex 
651
        //   is returned!) 
652
        if ( m_vertex ) return m_vertex;
653
        return 0;
654
    }
655
 
656
    GenVertex::vertex_iterator& GenVertex::vertex_iterator::operator++(void) {
657
        // Pre-fix incremental operator
658
        //
659
        // check for "past the end condition" denoted by m_vertex=0
660
        if ( !m_vertex ) return *this;
661
        // if at the last edge, move into the "past the end condition"
662
        if ( m_edge == m_vertex->edges_end( m_range ) ) {
663
            m_vertex = 0;
664
            return *this;
665
        }
666
        // check to see if we need to create a new recursive iterator by
667
        // following the current edge only if a recursive iterator doesn't
668
        // already exist. If a new recursive_iterator is created, return it.
669
        if ( follow_edge_() ) {
670
              return *this;
671
        }
672
        //
673
        // if a recursive iterator already exists, increment it, and return its
674
        // value (unless the recursive iterator has null root_vertex [its
675
        // root vertex is set to null if it has already returned its root] 
676
        // - in which case we delete it) 
677
        // and return the vertex pointed to by the edge.
678
        if ( m_recursive_iterator ) {
679
            ++(*m_recursive_iterator);
680
            if ( **m_recursive_iterator ) {
681
                return *this;
682
            } else {
683
                delete m_recursive_iterator;
684
                m_recursive_iterator = 0;
685
            }
686
        }
687
        //
688
        // increment to the next particle edge
689
        ++m_edge;
690
        // if m_edge is at the end, then we have incremented through all
691
        // edges, and it is time to return m_vertex, which we accomplish
692
        // by returning *this
693
        if ( m_edge == m_vertex->edges_end( m_range ) ) return *this;
694
        // otherwise we follow the current edge by recursively ++ing.
695
        return ++(*this);
696
    }
697
 
698
    GenVertex::vertex_iterator GenVertex::vertex_iterator::operator++(int) {
699
        // Post-fix increment
700
        vertex_iterator returnvalue(*this);
701
        ++(*this);
702
        return returnvalue;
703
    }
704
 
705
    void GenVertex::vertex_iterator::copy_with_own_set(
706
        const vertex_iterator& v_iter,
707
        std::set<const GenVertex*>& visited_vertices ) {
708
        // intended for internal use only. (use with care!)
709
        // this is the same as the operator= method, but it allows the
710
        // user to specify which set container m_visited_vertices points to.
711
        // in all cases, this vertex will NOT own its set.
712
        //
713
        // destruct data member pointers
714
        if ( m_recursive_iterator ) delete m_recursive_iterator;
715
        m_recursive_iterator = 0;
716
        if ( m_it_owns_set ) delete m_visited_vertices;
717
        m_visited_vertices = 0;
718
        m_it_owns_set = 0;
719
        // copy the target vertex_iterator to this iterator 
720
        m_vertex = v_iter.m_vertex;
721
        m_range = v_iter.m_range;
722
        m_visited_vertices = &visited_vertices;
723
        m_it_owns_set = 0;
724
        m_edge = v_iter.m_edge;
725
        copy_recursive_iterator_( v_iter.m_recursive_iterator );
726
    }
727
 
728
    GenVertex* GenVertex::vertex_iterator::follow_edge_() {
729
        // follows the edge pointed to by m_edge by creating a 
730
        // recursive iterator for it.
731
        //
732
        // if a m_recursive_iterator already exists, 
733
        // this routine has nothing to do,
734
        // if there's no m_vertex, there's no point following anything, 
735
        // also there's no point trying to follow a null edge.
736
        if ( m_recursive_iterator || !m_vertex || !*m_edge ) return 0;
737
        //
738
        // if the range is parents, children, or family (i.e. <= family)
739
        // then only the iterator which owns the set is allowed to create
740
        // recursive iterators (i.e. recursivity is only allowed to go one
741
        // layer deep)
742
        if ( m_range <= family && m_it_owns_set == 0 ) return 0;
743
        //
744
        // M.Dobbs 2001-07-16
745
        // Take care of the very special-rare case where a particle might
746
        // point to the same vertex for both production and end
747
        if ( (*m_edge)->production_vertex() ==
748
             (*m_edge)->end_vertex() ) return 0;
749
        //
750
        // figure out which vertex m_edge is pointing to
751
        GenVertex* vtx = ( m_edge.is_parent() ?
752
                        (*m_edge)->production_vertex() :
753
                        (*m_edge)->end_vertex() );
754
        // if the pointed to vertex doesn't exist or has already been visited, 
755
        // then return null
756
        if ( !vtx || !(m_visited_vertices->insert(vtx).second) ) return 0;
757
        // follow that edge by creating a recursive iterator
758
        m_recursive_iterator = new vertex_iterator( *vtx, m_range,
759
                                                    *m_visited_vertices);
760
        // and return the vertex pointed to by m_recursive_iterator 
761
        return **m_recursive_iterator;
762
    }
763
 
764
    void GenVertex::vertex_iterator::copy_recursive_iterator_(
765
        const vertex_iterator* recursive_v_iter ) {
766
        // to properly copy the recursive iterator, we need to ensure
767
        // the proper set container is transfered ... then do this 
768
        // operation .... you guessed it .... recursively!
769
        //
770
        if ( !recursive_v_iter ) return;
771
        m_recursive_iterator = new vertex_iterator();
772
        m_recursive_iterator->m_vertex = recursive_v_iter->m_vertex;
773
        m_recursive_iterator->m_range = recursive_v_iter->m_range;
774
        m_recursive_iterator->m_visited_vertices = m_visited_vertices;
775
        m_recursive_iterator->m_it_owns_set = 0;
776
        m_recursive_iterator->m_edge = recursive_v_iter->m_edge;
777
        m_recursive_iterator->copy_recursive_iterator_(
778
            recursive_v_iter->m_recursive_iterator );
779
    }
780
 
781
    ///////////////////////////////
782
    // particle_iterator         //
783
    ///////////////////////////////
784
 
785
    GenVertex::particle_iterator::particle_iterator() {}
786
 
787
    GenVertex::particle_iterator::particle_iterator( GenVertex& vertex_root,
788
                                                     IteratorRange range ) {
789
        // General Purpose Constructor
790
        //
791
        if ( range <= family ) {
792
            m_edge = GenVertex::edge_iterator( vertex_root, range );
793
        } else {
794
            m_vertex_iterator = GenVertex::vertex_iterator(vertex_root, range);
795
            m_edge = GenVertex::edge_iterator( **m_vertex_iterator,
796
                                                  m_vertex_iterator.range() );
797
        }
798
        advance_to_first_();
799
    }
800
 
801
    GenVertex::particle_iterator::particle_iterator(
802
        const particle_iterator& p_iter ){
803
        *this = p_iter;
804
    }
805
 
806
    GenVertex::particle_iterator::~particle_iterator() {}
807
 
808
    GenVertex::particle_iterator&
809
    GenVertex::particle_iterator::operator=( const particle_iterator& p_iter )
810
    {
811
        m_vertex_iterator = p_iter.m_vertex_iterator;
812
        m_edge = p_iter.m_edge;
813
        return *this;
814
    }
815
 
816
    GenParticle* GenVertex::particle_iterator::operator*(void) const {
817
        return *m_edge;
818
    }
819
 
820
    GenVertex::particle_iterator&
821
    GenVertex::particle_iterator::operator++(void) {
822
        //Pre-fix increment 
823
        //
824
        if ( !*m_edge && !*m_vertex_iterator ) {
825
            // past the end condition: do nothing
826
            return *this;
827
        } else if ( !*m_edge && *m_vertex_iterator ) {
828
            // past end of edge, but still have more vertices to visit
829
            // increment the vertex, checking that the result is valid
830
            if ( !*(++m_vertex_iterator) ) return *this;
831
            m_edge = GenVertex::edge_iterator( **m_vertex_iterator,
832
                                                  m_vertex_iterator.range() );
833
        } else {
834
            ++m_edge;
835
        }
836
        advance_to_first_();
837
        return *this;
838
    }
839
 
840
    GenVertex::particle_iterator GenVertex::particle_iterator::operator++(int){
841
        //Post-fix increment
842
        particle_iterator returnvalue(*this);
843
        ++(*this);
844
        return returnvalue;
845
    }
846
 
847
    GenParticle* GenVertex::particle_iterator::advance_to_first_() {
848
        // if the current edge is not a suitable return value ( because
849
        // it is a parent of the vertex root that itself belongs to a 
850
        // different vertex ) it advances to the first suitable return value 
851
        if ( !*m_edge ) return *(++*this);
852
        // if the range is relatives, we need to uniquely assign each particle
853
        // to a single vertex so as to guarantee particles are returned
854
        // exactly once.
855
        if ( m_vertex_iterator.range() == relatives &&
856
             m_edge.is_parent() &&
857
             (*m_edge)->production_vertex() ) return *(++*this);
858
        return *m_edge;
859
    }
860
 
861
} // HepMC