source: trunk/MagicSoft/Mars/mjobs/MDataSet.cc@ 8746

Last change on this file since 8746 was 8744, checked in by tbretz, 17 years ago
*** empty log message ***
File size: 22.4 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 1/2005 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2004-2007
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MDataSet
28//
29// This class describes a collection of sequences.
30//
31// Such an input file looks like:
32//
33// crab.seq:
34// ---------
35// AnalysisNumber: 1
36//
37// Name: SecondCrab
38//
39// SequencesOn: 35222 35229
40// SequencesOff: 36817
41//
42// SequencePath: /magic/sequences
43// DataPath: /magic/data/star
44//
45// Sequence00035222.File: sequences/sequence035222.txt
46// Sequence00036817.File: sequences/sequence036817.txt
47//
48// Sequence00035222.Dir: /data2/wuerzburg/Crab-Analyse/images/035222
49// Sequence00036817.Dir: /data2/wuerzburg/Crab-Analyse/images/036817
50//
51// WobbleMode: No
52// MonteCarlo: No
53//
54// SourceName: CrabNebula
55// Catalog: /magic/datacenter/setup/magic_favorites_dc.edb
56//
57// AnalysisNumber: The analysis number is an artifical number used to name
58// the output files automatically if the names are not overwritten in the
59// corresponding programs.
60//
61// SequencePath: In case it is not specified the datacenter default path is
62// used. If it is given it is the place at which the sequence files
63// are searched, if not overwritten by either a program command line
64// option (aka. a argument to the constructor) or a resource for
65// an individual sequence file. Note, that the four digits high-level
66// directories to sort the sequences are added to the given path.
67//
68// DataPath: In case it is not specified the datacenter default path is
69// used. If it is given it is the place at which the data files
70// are searched, if not overwritten by either a program command line
71// option (aka. a argument to the constructor) or a resource for
72// an individual data path. Note, that the four digits high-level
73// directories to sort the sequences are added to the given path.
74//
75// SequencesOn/Off: The sequence number are used to concatenate the filenames
76// of the sequences using the file structure used in the datacenter. Each
77// sequence can be added to the on and off data at the same time but only
78// once.
79//
80// If you have different file names you can overwrite the default file names
81// using Sequence%08d.File (make sure you have 8 digits!)
82//
83// In standard coditions (datacenter file system) paths are concatenated
84// by using the information in the sequence files (date, etc). You can
85// overwrite the directories in which the sequence-files (eg I-files) are
86// stored using Sequence%08d.Dir (make sure you have 8 digits!)
87//
88// WobbleMode: This is just a flag which is passed to the program
89// end eveluated (or not) by the individual program, which takes this
90// dataset as an input. For example this is necessary in ganymed to do
91// some wobble mode special setup. If no resource is given (or it is
92// set to "auto") wobble mode if set if the datset contains no off-
93// sequences.
94//
95// MonetCarlo: This is just a flag which is passed to the program
96// end eveluated (or not) by the individual program, which takes this
97// dataset as an input. For example this tells ganymed to skip some
98// parts accessing time stamps which are not available in the MCs.
99//
100// SequencePath/DataPath: This determined were the sequences and data-files
101// are stored. The priorities are as follows:
102// 0) Build in default path: /magic/sequences /magic/data/star
103// 1) Def.path from dataset file: SequencePath DataPath
104// 2) Indiv.path from dataset file: 12345.SequencePath 12345.DataPath
105// 3) Path from command line: Argument in the constructors
106// 4) Path for an indiv. dataset: Sequences00022555.File/Dir
107//
108// Catalog: This is the xephem-style file from the central control
109// containing the observed sky positions.
110//
111// SourceName: The source name, as defined in the catalog, of the object
112// the data corresponds to.
113//
114// Name: A name is stored for your convinience
115//
116// Comment: It is just stored.
117//
118// General Remark: MDataSet doesn't implement any action on the given
119// resources. Whether a resource is used, necessary or ignored, and
120// what will happen if you change the resource is always defined by the
121// executed macro or program.
122//
123// Resource file entries are case sensitive!
124//
125//
126// Collection of datsets
127// ---------------------
128//
129// You can combine more than one datset in a file (if your program
130// supports this) Such a dataset file could look like this:
131//
132// 35222.SequencesOn: 35222
133// 35222.SequencesOff: 36817
134//
135// 65778.SequencesOn: 65778
136//
137// 12345.SequencesOn: 12345
138//
139// 12345.SequencePath: /home/nobody/specialsequences
140// 65778.DataPath: /home/nobody/specialstars
141//
142// SequencePath: /home/nobody/defaultsequences
143// DataPath: /home/nobody/defaultstars
144//
145// Sequence00035222.File: sequences/sequence035222.txt
146// Sequence00035222.Dir: /data2/wuerzburg/Crab-Analyse/images/035222
147//
148// 35222.WobbleMode: Off
149// WobbleMode: On
150//
151//
152// IMPORTANT:
153// * Run filenames must begin with a string which allows correct
154// ordering in time, otherwise synchronization might fail.
155// * Sequence filenames should also have names allowing to order them
156// in time, but it is not necessary.
157//
158//
159// ToDO:
160// * Default paths could be moved into the global .rootrc
161//
162//
163// Class Version 2:
164// + fMonteCarlo
165// + fWobbleMode
166// - fIsWobbleMode
167//
168/////////////////////////////////////////////////////////////////////////////
169#include "MDataSet.h"
170
171#include <string.h> // necessary for Fedora core 2 with kernel 2.6.9-1.667 #1 and gcc 3.4.2
172#include <errno.h> // necessary for Fedora core 2 with kernel 2.6.9-1.667 #1 and gcc 3.4.2
173
174#include <stdlib.h>
175#include <fstream>
176
177#include <TEnv.h>
178#include <TChain.h>
179#include <TRegexp.h>
180#include <TSystem.h> // TSystem::ExpandPath
181
182#include "MLog.h"
183#include "MLogManip.h"
184
185#include "MRead.h"
186#include "MJob.h"
187#include "MEnv.h"
188#include "MAstro.h"
189#include "MDirIter.h"
190#include "MSequence.h"
191#include "MPointingPos.h"
192
193ClassImp(MDataSet);
194
195using namespace std;
196
197const TString MDataSet::fgCatalog = "/magic/datacenter/setup/magic_favorites.edb";
198
199// --------------------------------------------------------------------------
200//
201// Copy the sequence numbers from the TString runs into the TArrayI data
202// Sequences which are twice in the list are only added once. In this case
203// a warning is emitted.
204//
205void MDataSet::Split(TString &runs, TArrayI &data) const
206{
207 const TRegexp regexp("[0-9]+");
208
209 data.Set(0);
210
211 runs.ReplaceAll("\t", " ");
212 runs = runs.Strip(TString::kBoth);
213
214 while (!runs.IsNull())
215 {
216 const TString num = runs(regexp);
217
218 if (num.IsNull())
219 {
220 *fLog << warn << "WARNING - Sequence is NaN (not a number): '" << runs << "'" << endl;
221 break;
222 }
223
224 const Int_t seq = atoi(num.Data());
225 const Int_t n = data.GetSize();
226
227 // skip already existing entries
228 int i;
229 for (i=0; i<n; i++)
230 if (data[i] == seq)
231 break;
232
233 if (i<n)
234 *fLog << warn << "WARNING - Sequence #" << seq << " already in list... skipped." << endl;
235 else
236 {
237 // set new entry
238 data.Set(n+1);
239 data[n] = seq;
240 }
241
242 // remove entry from string
243 runs.Remove(0, runs.First(num)+num.Length());
244 }
245
246 MJob::SortArray(data);
247}
248
249// --------------------------------------------------------------------------
250//
251// After resolving the sequence filename and directory either from the
252// default (/magic/data/sequences/0004/sequence00004000.txt) or from
253// the corresponding entries in the dataset file.
254// The entries are sorted by filename.
255//
256void MDataSet::ResolveSequences(const TEnv &env, const TString &prefix, const TArrayI &num, TList &list) const
257{
258 TString sequences = fPathSequences;
259 TString data = fPathDataFiles;
260
261 for (int i=0; i<num.GetSize(); i++)
262 {
263 TString name = GetEnvValue2(env, prefix, Form("Sequence%08d.File", num[i]), "");
264 TString dir = GetEnvValue2(env, prefix, Form("Sequence%08d.Dir", num[i]), "");
265
266 // Set default sequence file and dir name
267 if (name.IsNull())
268 name = Form("%s%04d/sequence%08d.txt", sequences.Data(), num[i]/10000, num[i]);
269 if (dir.IsNull())
270 dir = Form("%s%04d/%08d", data.Data(), num[i]/10000, num[i]);
271
272 // FIXME: The sequence number from the sequence file is assigned!!!
273 MSequence *seq = new MSequence(name, dir);
274
275 if (seq->IsValid() && seq->GetSequence()!=(UInt_t)num[i])
276 *fLog << warn << "WARNING - Sequence number " << num[i] << " in dataset file doesn't match sequence number " << seq->GetSequence() << " in sequence file!" << endl;
277
278 list.Add(seq);
279 }
280
281 // For the synchronization we must make sure, that all sequences are
282 // in the correct order...
283 // list.Sort();
284}
285
286Bool_t MDataSet::GetWobbleMode(const TEnv &env, const TString &prefix) const
287{
288 TString wob = GetEnvValue2(env, prefix, "WobbleMode", "auto");
289
290 wob.ToLower();
291 wob=wob.Strip(TString::kBoth);
292
293 if (wob=="auto")
294 return !HasOffSequences();
295
296 return GetEnvValue2(env, prefix, "WobbleMode", kFALSE);
297}
298
299// --------------------------------------------------------------------------
300//
301// Read a dataset from the file fname. If num is != -1 all resources are
302// prefixed with the number. This allows constrcutions like:
303//
304// 89123.SequencesOn: 1 2 3 4
305// 89130.SequencesOn: 5 6 7 8
306//
307// For one dataset:
308//
309// 89123.DataPath: /magic/data/star
310//
311// For all other datasets:
312//
313// DataPath: /magic/data/star
314//
315// For one sequence of one datasets:
316//
317// 89123.Sequence00000002.Dir: /magic/data/star
318//
319// and therefore allows storage of several datsets in one file with
320// a defaults for non specific resources.
321//
322// sequences and data are the path to the sequences (/magic/sequences)
323// and the data (/magic/data/star) respectively. Both can be overwritten
324// be a default from the dataset file or a resource for an individual
325// sequence.
326//
327void MDataSet::Init(const char *fname, const UInt_t num, TString sequences, TString &data)
328{
329 // Store given file name as name
330 fName = fname;
331
332 // Delete the stored Sequences automatically at destruction
333 fSequencesOn.SetOwner();
334 fSequencesOff.SetOwner();
335
336 // Determin the prefix to access this resource
337 const TString prefix = num==(UInt_t)-1 ? "" : Form("%d", num);
338
339 // Expand the file name (eg $MARS or ~ are expanded)
340 TString expname(fname);
341 gSystem->ExpandPathName(expname);
342
343 // Check its accessibility
344 const Bool_t access = !gSystem->AccessPathName(expname, kFileExists);
345 if (!access)
346 gLog << err << "ERROR - Dataset file " << expname << " not accessible!" << endl;
347
348 // Open and read the file
349 MEnv env(expname);
350
351 // Get analysis number and name
352 fNumAnalysis = GetEnvValue2(env, prefix, "AnalysisNumber", (Int_t)num);
353 fTitle = GetEnvValue2(env, prefix, "Name", expname);
354
355 // Get sequences from file
356 TString str;
357 str = GetEnvValue2(env, prefix, "SequencesOn", "");
358 Split(str, fNumSequencesOn);
359 str = GetEnvValue2(env, prefix, "SequencesOff", "");
360 Split(str, fNumSequencesOff);
361
362 // Get other resources
363 fNameSource = GetEnvValue2(env, prefix, "SourceName", "");
364 fCatalog = GetEnvValue2(env, prefix, "Catalog", fgCatalog);
365 fMonteCarlo = GetEnvValue2(env, prefix, "MonteCarlo", kFALSE);
366 fComment = GetEnvValue2(env, prefix, "Comment", "");
367
368 fWobbleMode = GetWobbleMode(env, prefix); // needs the number of off sequences
369
370 fNameSource = fNameSource.Strip(TString::kBoth);
371 fCatalog = fCatalog.Strip(TString::kBoth);
372
373 // Check for sequence and data path (GetDefPath needs the monte carlo flag)
374 const TString defpathseq = GetEnvValue2(env, prefix, "SequencePath", GetDefPathSequences());
375 const TString defpathdata = GetEnvValue2(env, prefix, "DataPath", GetDefPathDataFiles());
376
377 SetupDefaultPath(sequences, defpathseq);
378 SetupDefaultPath(data, defpathdata);
379
380 fPathSequences = sequences;
381 fPathDataFiles = data;
382
383 // Resolve sequences
384 ResolveSequences(env, prefix, fNumSequencesOn, fSequencesOn);
385 ResolveSequences(env, prefix, fNumSequencesOff, fSequencesOff);
386
387 // --- Now "touch" resources which are not yet stored in MDataSet ---
388 env.Touch("RunTime");
389
390 // --- Print "untouch" resources ---
391 if (env.GetNumUntouched()>0)
392 {
393 gLog << warn << "WARNING - At least one resource in the dataset-file has not been touched!" << endl;
394 env.PrintUntouched();
395 }
396}
397
398// --------------------------------------------------------------------------
399//
400// Constructor. See Read for more details.
401//
402MDataSet::MDataSet(const char *fname, TString sequences, TString data)
403{
404 Init(fname, (UInt_t)-1, sequences, data);
405}
406
407// --------------------------------------------------------------------------
408//
409// Constructor. See Read for more details.
410//
411MDataSet::MDataSet(const char *fname, Int_t num, TString sequences, TString data)
412{
413 Init(fname, num, sequences, data);
414}
415
416//---------------------------------------------------------------------------
417//
418// Make sure that the name used for writing doesn't contain a full path
419//
420const char *MDataSet::GetName() const
421{
422 const char *pos = strrchr(GetRcName(), '/');
423 return pos>0 ? pos+1 : GetRcName();
424}
425
426
427// --------------------------------------------------------------------------
428//
429// Return '+' if both can be accessed, '-' otherwise.
430//
431void MDataSet::PrintFile(const MSequence &seq)
432{
433 const Char_t access =
434 !gSystem->AccessPathName(seq.GetFileName(), kFileExists) &&
435 !gSystem->AccessPathName(seq.GetDataPath(), kFileExists) ? '+' : '-';
436
437 gLog << "# " << access << " " << seq.GetFileName() << " <" << seq.GetDataPath() << ">" << endl;
438}
439
440// --------------------------------------------------------------------------
441//
442// Print the contents of the sequence
443//
444void MDataSet::Print(Option_t *o) const
445{
446 gLog << all;
447 if (!IsValid())
448 {
449 gLog << "Dataset: " << fName << " <invalid - no analysis number available>" << endl;
450 return;
451 }
452 gLog << "# Path: " << GetRcName() << endl;
453 gLog << "# Name: " << GetName() << endl;
454 gLog << endl;
455 gLog << "AnalysisNumber: " << fNumAnalysis << endl << endl;
456
457 if (!fTitle.IsNull())
458 gLog << "Name: " << fTitle << endl << endl;
459
460 gLog << "SequencesOn: ";
461 for (int i=0; i<fNumSequencesOn.GetSize(); i++)
462 gLog << " " << fNumSequencesOn[i];
463 gLog << endl;
464 gLog << "SequencesOff: ";
465 for (int i=0; i<fNumSequencesOff.GetSize(); i++)
466 gLog << " " << fNumSequencesOff[i];
467 gLog << endl << endl;
468
469 gLog << "SourceName: " << fNameSource << endl;
470 gLog << "Catalog: " << fCatalog << endl;
471
472 gLog << "WobbleMode: " << (fWobbleMode?"Yes":"No") << endl << endl;
473 gLog << "MonteCarlo: " << (fMonteCarlo?"Yes":"No") << endl << endl;
474
475 gLog << "Comment: " << fComment << endl;
476
477 if (fSequencesOn.GetEntries()>0)
478 gLog << endl;
479
480 TIter NextOn(&fSequencesOn);
481 TIter NextOff(&fSequencesOff);
482 MSequence *seq=0;
483 while ((seq=(MSequence*)NextOn()))
484 {
485 gLog << "Sequence" << Form("%08d", seq->GetSequence()) << ".File: " << seq->GetFileName() << endl;
486 gLog << "Sequence" << Form("%08d", seq->GetSequence()) << ".Dir: " << seq->GetDataPath() << endl;
487 }
488 if (fSequencesOff.GetEntries()>0)
489 gLog << endl;
490 while ((seq=(MSequence*)NextOff()))
491 {
492 gLog << "Sequence" << Form("%08d", seq->GetSequence()) << ".File: " << seq->GetFileName() << endl;
493 gLog << "Sequence" << Form("%08d", seq->GetSequence()) << ".Dir: " << seq->GetDataPath() << endl;
494 }
495
496 if (TString(o).Contains("files", TString::kIgnoreCase))
497 {
498 gLog << endl;
499 gLog << "# On-Data Files:" << endl;
500 NextOn.Reset();
501 while ((seq=(MSequence*)NextOn()))
502 PrintFile(*seq);
503
504 gLog << endl;
505 gLog << "# Off-Data Files:" << endl;
506 NextOff.Reset();
507 while ((seq=(MSequence*)NextOff()))
508 PrintFile(*seq);
509
510 return;
511 }
512}
513
514// --------------------------------------------------------------------------
515//
516// Adds all sequences contained in list to the MDirIter. After adding
517// everything MDirIter::Sort is called to sort all entries by name.
518//
519Bool_t MDataSet::AddSequencesFromList(const TList &list, MDirIter &files)
520{
521 TIter Next(const_cast<TList*>(&list));
522
523 MSequence *seq=0;
524 while ((seq=(MSequence*)Next()))
525 {
526 if (!seq->IsValid())
527 {
528 gLog << err;
529 gLog << "ERROR - MDataSet::AddSequencesFromList: Sequence invalid!" << endl;
530 gLog << " + File: " << seq->GetFileName() << endl;
531 gLog << " + Dir: " << seq->GetDataPath() << endl;
532 return kFALSE;
533 }
534
535 if (seq->SetupDatRuns(files, MSequence::kImages)<=0)
536 return kFALSE;
537 }
538
539 // This is important in case of synchronisation, because the
540 // files in the sequences can be interleaved (eg W1, W2)
541 // Filenames MUST begin with an appropriate string which allow
542 // to order them correctly in time!
543 // files.Sort();
544
545 if (gLog.GetDebugLevel()>4)
546 {
547 gLog << inf << "Files which are searched:" << endl;
548 files.Print();
549 }
550 return kTRUE;
551}
552
553Bool_t MDataSet::AddFilesOn(MDirIter &iter) const
554{
555 return AddSequencesFromList(fSequencesOn, iter);
556}
557
558Bool_t MDataSet::AddFilesOff(MDirIter &iter) const
559{
560 return AddSequencesFromList(fSequencesOff, iter);
561}
562
563Bool_t MDataSet::AddFiles(MDirIter &iter) const
564{
565 const Bool_t rc1 = AddFilesOff(iter);
566 const Bool_t rc2 = AddFilesOn(iter);
567 return rc1 && rc2;
568}
569
570Bool_t MDataSet::AddFilesOn(MRead &read) const
571{
572 MDirIter files;
573 if (!AddFilesOn(files))
574 return kFALSE;
575 return read.AddFiles(files)>0;
576}
577
578Bool_t MDataSet::AddFilesOff(MRead &read) const
579{
580 MDirIter files;
581 if (!AddFilesOff(files))
582 return kFALSE;
583 return read.AddFiles(files)>0;
584}
585
586Bool_t MDataSet::AddFiles(MRead &read) const
587{
588 const Bool_t rc1 = AddFilesOff(read);
589 const Bool_t rc2 = AddFilesOn(read);
590 return rc1 && rc2;
591}
592
593Int_t MDataSet::AddFilesToChain(MDirIter &files, TChain &chain)
594{
595 Int_t num=0;
596 while (1)
597 {
598 const TString fname = files.Next();
599 if (fname.IsNull())
600 break;
601
602 const Int_t n = chain.Add(fname);
603 if (n<=0)
604 return kFALSE;
605 num += n;
606 }
607 return num;
608}
609
610Bool_t MDataSet::AddFilesOn(TChain &chain) const
611{
612 MDirIter files;
613 if (!AddSequencesFromList(fSequencesOn, files))
614 return kFALSE;
615 return AddFilesToChain(files, chain)>0;
616}
617
618Bool_t MDataSet::AddFilesOff(TChain &chain) const
619{
620 MDirIter files;
621 if (!AddSequencesFromList(fSequencesOff, files))
622 return kFALSE;
623 return AddFilesToChain(files, chain)>0;
624}
625
626Bool_t MDataSet::AddFiles(TChain &read) const
627{
628 const Bool_t rc1 = AddFilesOff(read);
629 const Bool_t rc2 = AddFilesOn(read);
630 return rc1 && rc2;
631}
632
633Bool_t MDataSet::GetSourcePos(MPointingPos &pos) const
634{
635 if (!HasSource())
636 {
637 gLog << err << "ERROR - MDataSet::GetSourcePos called, but no source available." << endl;
638 return kFALSE;
639 }
640
641 TString catalog(fCatalog);
642 gSystem->ExpandPathName(catalog);
643
644 ifstream fin(catalog);
645 if (!fin)
646 {
647 gLog << err << "Cannot open file " << catalog << ": ";
648 gLog << strerror(errno) << endl;
649 return kFALSE;
650 }
651
652 TString ra, dec, epoch;
653
654 Int_t n = 0;
655 while (1)
656 {
657 TString line;
658 line.ReadLine(fin);
659 if (!fin)
660 {
661 gLog << err << "ERROR - Source '" << fNameSource << "' not found in " << catalog << "." << endl;
662 return kFALSE;
663 }
664
665 n++;
666
667 TObjArray *arr = line.Tokenize(",");
668
669 if (arr->GetEntries()<6)
670 {
671 gLog << err << "ERROR - Not enough arguments in line #" << n << " of " << catalog << endl;
672 delete arr;
673 return kFALSE;;
674 }
675
676 const TString name = (*arr)[0]->GetName();
677
678 ra = (*arr)[2]->GetName();
679 dec = (*arr)[3]->GetName();
680 epoch = (*arr)[5]->GetName();
681
682 delete arr;
683
684 if (name.Strip(TString::kBoth)==fNameSource)
685 break;
686 }
687
688 if (epoch.Strip(TString::kBoth)!=(TString)"2000")
689 {
690 gLog << err << "ERROR - Epoch not 2000... not supported." << endl;
691 return kFALSE;
692 }
693
694 Double_t r,d;
695 if (!MAstro::Coordinate2Angle(ra, r))
696 {
697 gLog << err << "ERROR - Interpreting right ascension: " << ra << endl;
698 return kFALSE;
699 }
700 if (!MAstro::Coordinate2Angle(dec, d))
701 {
702 gLog << err << "ERROR - Interpreting declination: " << dec << endl;
703 return kFALSE;
704 }
705
706 pos.SetSkyPosition(r, d);
707 pos.SetTitle(fNameSource);
708
709 return kTRUE;
710}
711
712// --------------------------------------------------------------------------
713//
714// Calls ReplaceAll(old, news) for all Dir-entries
715//
716void MDataSet::ReplaceDir(TList &list, const TString &old, const TString &news) const
717{
718 TIter Next(&list);
719 TNamed *name = 0;
720 while ((name=(TNamed*)Next()))
721 {
722 TString dir = name->GetTitle();
723 dir.ReplaceAll(old, news);
724 name->SetTitle(dir);
725 }
726}
727
728// --------------------------------------------------------------------------
729//
730// Calls ReplaceAll(old, news) for all File-entries
731//
732void MDataSet::ReplaceFile(TList &list, const TString &old, const TString &news) const
733{
734 TIter Next(&list);
735 TNamed *name = 0;
736 while ((name=(TNamed*)Next()))
737 {
738 TString file = name->GetName();
739 file.ReplaceAll(old, news);
740 name->SetName(file);
741 }
742}
Note: See TracBrowser for help on using the repository browser.