source: trunk/Mars/mjobs/MJob.cc@ 13408

Last change on this file since 13408 was 10045, checked in by tbretz, 14 years ago
Fixed a problem in ganymed which made the use of the tilde in pathnames in --out= impossible.
File size: 16.8 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, 8/2004 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2007
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MJob
28//
29// A base class for jobs
30//
31// SetDebugEnv(0) // switch off debugging
32// SetDebugEnv(1) // reserved
33// SetDebugEnv(2) // print untouched resources after evtloop resources setup
34// SetDebugEnv(3) // do 2) and debug setting env completely
35//
36// To allow overwriting the output files call SetOverwrite()
37//
38/////////////////////////////////////////////////////////////////////////////
39#include "MJob.h"
40
41#include "MEnv.h"
42
43#include <TFile.h>
44#include <TClass.h>
45#include <TSystem.h>
46#include <TRandom.h>
47#include <TObjArray.h>
48
49#include "MIter.h"
50
51#include "MLog.h"
52#include "MLogManip.h"
53
54#include "MParList.h"
55#include "MEvtLoop.h"
56
57ClassImp(MJob);
58
59using namespace std;
60
61// --------------------------------------------------------------------------
62//
63// Default constructor.
64//
65// Sets fDataFlag to 0
66//
67MJob::MJob(const char *name, const char *title) : fEnv(0), fEnvDebug(0), fOverwrite(kFALSE), fMaxEvents(0)
68{
69 fName = name ? name : "MJob";
70 fTitle = title ? title : "Base class for jobs";
71}
72
73//------------------------------------------------------------------------
74//
75// If MJob is the owner of fEnv delete fEnv.
76//
77// Reset the owenership bit.
78//
79// Set fEnv to NULL.
80//
81void MJob::ClearEnv()
82{
83 if (fEnv && TestBit(kIsOwner))
84 delete fEnv;
85 ResetBit(kIsOwner);
86 fEnv=0;
87}
88
89//------------------------------------------------------------------------
90//
91// ClearEnv()
92//
93MJob::~MJob()
94{
95 ClearEnv();
96}
97
98//------------------------------------------------------------------------
99//
100// If prefix==0 the prefix is taken from fName up to the first
101// whitespace.
102//
103// A trailing dot is removed.void MJob::SetPrefix(const char *prefix)
104void MJob::SetPrefix(const char *prefix)
105{
106 fEnvPrefix = prefix;
107
108 if (!prefix)
109 fEnvPrefix = fName.First(' ')>0 ? fName(0, fName.First(' ')) : fName;
110
111 if (fEnvPrefix.EndsWith("."))
112 fEnvPrefix.Remove(fEnvPrefix.Length()-1);
113}
114
115//------------------------------------------------------------------------
116//
117// Create a new MEnv from the file env. MJob takes of course the
118// ownership of the newly created MEnv.
119//
120// SetPrefix(prefix)
121//
122// return kFALSE if MEnv is invalid
123//
124Bool_t MJob::SetEnv(const char *env, const char *prefix)
125{
126 SetEnv(new MEnv(env), prefix);
127
128 // Take the owenership of the MEnv instance
129 SetBit(kIsOwner);
130
131 return fEnv->IsValid();
132}
133
134//------------------------------------------------------------------------
135//
136// Set a new fEnv and a new general prefix.
137//
138// Calls SetPrefix(prefix)
139//
140// MJob does not take the owenership of the MEnv instance.
141//
142void MJob::SetEnv(MEnv *env, const char *prefix)
143{
144 ClearEnv();
145
146 fEnv = env;
147
148 SetPrefix(prefix);
149}
150
151//------------------------------------------------------------------------
152//
153// Removes LF's from the path (necessary if the resource file was written
154// with a different operating system than Linux.
155//
156// Removes a trailing slash if the path is not the root-path.
157//
158// Adds fname to the path if given.
159//
160void MJob::FixPath(TString &path)
161{
162 path.ReplaceAll("\015", "");
163
164 if (path==(TString)"/")
165 return;
166
167 if (path.EndsWith("/"))
168 path.Remove(path.Length()-1);
169}
170
171//------------------------------------------------------------------------
172//
173// Calls FixPath
174//
175// Adds fname to the path if given.
176//
177TString MJob::CombinePath(TString path, TString fname)
178{
179 FixPath(path);
180
181 if (fname.IsNull())
182 return path;
183
184 if (path!=(TString)"/")
185 path += "/";
186
187 path += fname;
188
189 return path;
190}
191
192//------------------------------------------------------------------------
193//
194// Sets the output path. The exact meaning (could also be a file) is
195// deined by the derived class.
196//
197void MJob::SetPathOut(const char *path)
198{
199 fPathOut = path;
200 FixPath(fPathOut);
201}
202
203//------------------------------------------------------------------------
204//
205// Sets the input path. The exact meaning (could also be a file) is
206// deined by the derived class.
207//
208void MJob::SetPathIn(const char *path)
209{
210 fPathIn = path;
211 FixPath(fPathIn);
212}
213
214//------------------------------------------------------------------------
215//
216// Returns the TEnv
217//
218const TEnv *MJob::GetEnv() const
219{
220 return static_cast<const TEnv *const>(fEnv);
221}
222
223//------------------------------------------------------------------------
224//
225// Checks GetEnvValue(*fEnv, fEnvPrefix, name, dftl)
226// For details see MParContainer
227//
228Int_t MJob::GetEnv(const char *name, Int_t dflt) const
229{
230 return GetEnvValue2(*fEnv, fEnvPrefix, name, dflt); // return fEnv->GetValue(Form("%s%s", fEnvPrefix.Data(), name), dflt);
231}
232
233//------------------------------------------------------------------------
234//
235// Checks GetEnvValue(*fEnv, fEnvPrefix, name, dftl)
236// For details see MParContainer
237//
238Double_t MJob::GetEnv(const char *name, Double_t dflt) const
239{
240 return GetEnvValue2(*fEnv, fEnvPrefix, name, dflt); // return fEnv->GetValue(Form("%s%s", fEnvPrefix.Data(), name), dflt);
241}
242
243//------------------------------------------------------------------------
244//
245// Checks GetEnvValue(*fEnv, fEnvPrefix, name, dftl)
246// For details see MParContainer
247//
248const char *MJob::GetEnv(const char *name, const char *dflt) const
249{
250 return GetEnvValue2(*fEnv, fEnvPrefix, name, dflt); //fEnv->GetValue(Form("%s%s", fEnvPrefix.Data(), name), dflt);
251}
252
253//------------------------------------------------------------------------
254//
255// Checks IsEnvDefined(*fEnv, fEnvPrefix, name, fEnvDebug>2)
256// For details see MParContainer
257//
258Bool_t MJob::HasEnv(const char *name) const
259{
260 return IsEnvDefined(*fEnv, fEnvPrefix, name, fEnvDebug>2);//fEnv->Lookup(Form("%s%s", fEnvPrefix.Data(), name));
261}
262
263//------------------------------------------------------------------------
264//
265// Check fEnv for RadnomNumberGenerator. If it is empty or the
266// corresponding class does either not exist or not inherit from TRandom,
267// gRandom remains unchanged. Otherwise gRandom is set to a newly created
268// instance of this class.
269//
270// The second resource which is checked is RandomNumberSeedValue. If it
271// is empty (not given) the seed keeps unchanged. If a number is given
272// the seed value of gRandom is set accordingly. (0 means that
273// the seed value is set accoring to the time, see TRandom::SetSeed())
274//
275// If an error occured kFALSE is returned, kTRUE otherwise.
276//
277// For exmaple:
278// RandomNumberGenerator: TRandom3
279// RandomNumberSeedValue: 0
280//
281Bool_t MJob::InitRandomNumberGenerator() const
282{
283 const TString rng = GetEnv("RandomNumberGenerator", "");
284 if (!rng.IsNull())
285 {
286 TClass *cls = MParContainer::GetClass(rng, &gLog);
287 if (!cls)
288 return kFALSE;
289
290 if (!cls->InheritsFrom(TRandom::Class()))
291 {
292 *fLog << err << "ERROR - RandomNumberGenerator " << rng << " doesn't inherit from TRandom." << endl;
293 return kFALSE;
294 }
295
296 delete gRandom;
297 gRandom = static_cast<TRandom*>(cls->New());
298
299 *fLog << inf << "Random number generator " << rng << " initialized." << endl;
300 }
301
302 // Nothing: Keep seed value, 0 set time as seed value, val set seed
303 const TString seed = GetEnv("RandomNumberSeedValue", "");
304 if (!seed.IsNull())
305 {
306 if (!seed.IsAlnum())
307 {
308 *fLog << err << "ERROR - RandomNumberSeedValue not an integer: " << seed << endl;
309 return kFALSE;
310 }
311
312 gRandom->SetSeed(seed.Atoi());
313 *fLog << inf << "Random number seed value set to " << seed.Atoi() << endl;
314 }
315
316 return kTRUE;
317}
318
319//------------------------------------------------------------------------
320//
321// Check the resource file for
322// PathOut
323// PathIn
324// MaxEvents
325// Overwrite
326// EnvDebug
327// RandomNumberGenerator
328// RandomNumberSeedValue
329//
330// and call the virtual function CheckEnvLocal
331//
332Bool_t MJob::CheckEnv()
333{
334 if (!fEnv)
335 return kTRUE;
336
337 if (!InitRandomNumberGenerator())
338 return kFALSE;
339
340 TString p;
341 p = GetEnv("PathOut", "");
342 if (!p.IsNull())
343 SetPathOut(p);
344
345 p = GetEnv("PathIn", "");
346 if (!p.IsNull())
347 SetPathIn(p);
348
349 SetMaxEvents(GetEnv("MaxEvents", fMaxEvents));
350 SetOverwrite(GetEnv("Overwrite", fOverwrite));
351 SetEnvDebug( GetEnv("EnvDebug", fEnvDebug));
352
353 return CheckEnvLocal();
354}
355
356//------------------------------------------------------------------------
357//
358// Returns the result of c.ReadEnv(*fEnv, fEnvPrefix, fEnvDebug>2)
359// By adding the container first to a MParList it is ensured that
360// all levels are checked.
361//
362Bool_t MJob::CheckEnv(MParContainer &c) const
363{
364 if (!fEnv)
365 return kTRUE;
366
367 // Make sure that all levels are checked
368 MParList l;
369 l.AddToList(&c);
370 return l.ReadEnv(*fEnv, fEnvPrefix+".", fEnvDebug>2);
371}
372
373//------------------------------------------------------------------------
374//
375// Call the eventsloops ReadEnv and print untouched resources afterwards
376// if fEnvDebug>1
377//
378Bool_t MJob::SetupEnv(MEvtLoop &loop) const
379{
380 if (!fEnv)
381 return kTRUE;
382
383 *fLog << all << "Evaluating resources from: " << fEnv->GetRcName() << endl;
384
385 if (!loop.ReadEnv(*fEnv, fEnvPrefix, fEnvDebug>2))
386 return kFALSE;
387
388 if (fEnvDebug>1)
389 fEnv->PrintUntouched();
390
391 return kTRUE;
392}
393
394//------------------------------------------------------------------------
395//
396// Checks whether write permissions to fname exists including
397// the fOverwrite data member. Empty file names return kTRUE
398//
399Bool_t MJob::HasWritePermission(TString fname) const
400{
401 gSystem->ExpandPathName(fname);
402
403 const Bool_t exists = !gSystem->AccessPathName(fname, kFileExists);
404 if (!exists)
405 {
406 const TString dirname = gSystem->DirName(fname);
407
408 Long_t flags;
409 const Bool_t exists2 = !gSystem->GetPathInfo(dirname, 0, (Long_t*)0, &flags, 0);
410 if (!exists2)
411 {
412 *fLog << err << "ERROR - Directory " << dirname << " doesn't exist." << endl;
413 return kFALSE;
414 }
415
416 if ((flags&2)==0)
417 {
418 *fLog << err << "ERROR - " << dirname << " is not a directory." << endl;
419 return kFALSE;
420 }
421
422 const Bool_t write = !gSystem->AccessPathName(dirname, kWritePermission);
423 if (!write)
424 {
425 *fLog << err << "ERROR - No permission to write to directory " << dirname << endl;
426 return kFALSE;
427 }
428
429 return kTRUE;
430 }
431
432 Long_t flags;
433 gSystem->GetPathInfo(fname, 0, (Long_t*)0, &flags, 0);
434 if (flags&4)
435 {
436 *fLog << err << "ERROR - " << fname << " is not a regular file." << endl;
437 return kFALSE;
438 }
439
440 const Bool_t write = !gSystem->AccessPathName(fname, kWritePermission);
441 if (!write)
442 {
443 *fLog << err << "ERROR - No permission to write to " << fname << endl;
444 return kFALSE;
445 }
446
447 if (fOverwrite)
448 return kTRUE;
449
450 *fLog << err;
451 *fLog << "ERROR - File " << fname << " already exists and overwrite not allowed." << endl;
452
453 return kFALSE;
454}
455
456//------------------------------------------------------------------------
457//
458// Write containers in list to gFile. Returns kFALSE if no gFile or any
459// container couldn't be written. kTRUE otherwise.
460//
461Bool_t MJob::WriteContainer(TCollection &list) const
462{
463 if (!gFile)
464 {
465 *fLog << err << dbginf << "ERROR - No file open (gFile==0)" << endl;
466 return kFALSE;
467 }
468
469 TIter Next(&list);
470 TObject *o=0;
471 while ((o=Next()))
472 {
473 *fLog << inf << " - Writing " << MParContainer::GetDescriptor(*o) << "..." << flush;
474 if (o->Write(o->GetName())<=0)
475 {
476 *fLog << err << dbginf << "ERROR - Writing " << MParContainer::GetDescriptor(*o) << " to file " << gFile->GetName() << endl;
477 return kFALSE;
478 }
479 *fLog << "ok." << endl;
480 }
481 return kTRUE;
482}
483
484//------------------------------------------------------------------------
485//
486// Read containers in list into list from gFile
487// Returns kFALSE if no gFile or any container couldn't be read.
488//
489Bool_t MJob::ReadContainer(TCollection &list) const
490{
491 if (!gFile)
492 {
493 *fLog << err << dbginf << "ERROR - No file open (gFile==0)" << endl;
494 return kFALSE;
495 }
496
497 TIter Next(&list);
498 TObject *o=0;
499 while ((o=Next()))
500 {
501 *fLog << inf << " - Reading " << MParContainer::GetDescriptor(*o) << "..." << flush;
502 if (o->Read(o->GetName())<=0)
503 {
504 *fLog << err << dbginf << "ERROR - Reading " << MParContainer::GetDescriptor(*o) << " from file " << gFile->GetName() << endl;
505 return kFALSE;
506 }
507 *fLog << "ok." << endl;
508 }
509 return kTRUE;
510}
511
512//------------------------------------------------------------------------
513//
514// Write containers in cont to fPathOut+"/"+name, or fPathOut only
515// if name is empty.
516//
517Bool_t MJob::WriteContainer(TCollection &cont, const char *name, const char *option, const int compr) const
518{
519 if (fPathOut.IsNull())
520 {
521 *fLog << inf << "No output path specified via SetPathOut - no output written." << endl;
522 return kTRUE;
523 }
524
525 TString oname = CombinePath(fPathOut, name);
526
527 // In case the update-option is selected check whether
528 // the file is already open
529 if (TString(option).Contains("update", TString::kIgnoreCase))
530 {
531 TFile *file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(oname));
532 if (!file || !file->IsOpen() || file->IsZombie())
533 {
534 gSystem->ExpandPathName(oname);
535 file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(oname));
536 }
537
538 if (file && file->IsOpen() && !file->IsZombie())
539 {
540 *fLog << inf << "Updating open file " << oname << "." << endl;
541 file->cd();
542 return WriteContainer(cont);
543 }
544 }
545
546 *fLog << inf << "Writing to file " << oname << "." << endl;
547
548 TString title("File written by ");
549 title += fName;
550
551 // Open a new file with the defined option for writing
552 TFile file(oname, option, title, compr);
553 if (!file.IsOpen() || file.IsZombie())
554 {
555 *fLog << err << "ERROR - Couldn't open file " << oname << " for writing..." << endl;
556 return kFALSE;
557 }
558
559 return WriteContainer(cont);
560}
561
562//------------------------------------------------------------------------
563//
564// return kTRUE if no display is set.
565//
566// Write the display to the TFile with name name, options option and
567// compression level comp.
568//
569// If name IsNull fPathOut is assumed to contain the name, otherwise
570// name is appended to fPathOut. fPathOut might be null.
571//
572Bool_t MJob::WriteDisplay(const char *name, const char *option, const int compr) const
573{
574 if (!fDisplay)
575 return kTRUE;
576
577 TObjArray arr;
578 arr.Add((TObject*)(fDisplay));
579 return WriteContainer(arr, name, option, compr);
580}
581
582TString MJob::ExpandPath(TString fname)
583{
584 // empty
585 if (fname.IsNull())
586 return "";
587
588 // Expand path using environment
589 gSystem->ExpandPathName(fname);
590
591 // Absolute path
592 if (fname[0]=='/')
593 {
594 gLog << dbg << "MJob::ExpandPath - Path " << fname << " is absolute." << endl;
595 return fname;
596 }
597
598 // relative path to file and file could be found
599 if (!gSystem->AccessPathName(fname, kFileExists))
600 {
601 gLog << dbg << "MJob::ExpandPath - Relative path " << fname << " found..." << endl;
602 return fname;
603 }
604
605 // Now check gEnv and MARSSYS. gEnv can overwrite MARSSYS
606 TString path(gEnv ? gEnv->GetValue("Mars.Path", "$MARSSYS") : "$MARSSYS");
607
608 // Expand path using environment
609 gSystem->ExpandPathName(path);
610
611 // check if path ends with a slash
612 path = CombinePath(path, fname);
613
614 gLog << dbg << "MJob::ExpandPath - Filename expanded to " << path << endl;
615
616 // return new path
617 return path;
618}
619
620//------------------------------------------------------------------------
621//
622// Sorts the array.
623//
624void MJob::SortArray(TArrayI &arr)
625{
626 TArrayI idx(arr.GetSize());
627 TArrayI srt(arr);
628
629 TMath::Sort(arr.GetSize(), srt.GetArray(), idx.GetArray(), kFALSE);
630
631 for (int i=0; i<arr.GetSize(); i++)
632 arr[i] = srt[idx[i]];
633}
Note: See TracBrowser for help on using the repository browser.