]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWGLF/FORWARD/trains/GridHelper.C
Remove code to dump Job IDs and stages until merged into trunk of AliAnalysisAlien
[u/mrichter/AliRoot.git] / PWGLF / FORWARD / trains / GridHelper.C
CommitLineData
fdfd93b4 1/**
2 * @file GridHelper.C
3 * @author Christian Holm Christensen <cholm@master.hehi.nbi.dk>
4 * @date Tue Oct 16 19:01:27 2012
5 *
6 * @brief Grid Analysis Helper
7 *
8 * @ingroup pwglf_forward_trains_helper
9 *
10 */
11#ifndef GRIDHELPER_C
12#define GRIDHELPER_C
13#include "PluginHelper.C"
14#ifndef __CINT__
15# include <TUrl.h>
16# include <TString.h>
17# include <TGrid.h>
18# include <AliAnalysisManager.h>
19# include <AliAnalysisAlien.h>
20#else
21class TUrl;
22class AliAnalysisAlien;
23#endif
24
25// ===================================================================
26/**
27 * Handle analysis on an the Grid
28 *
29 * This helper is triggered by a URL of the form
30 *
31 * @code
32 * alien:///<directory>[?<options>][#<pattern>]
33 * @endcode
34 * where
35 * <dl>
36 * <dt>&lt;directory@gt;</dt>
37 * <dd>Grid directory that holds the data</dd>
38 * <dt>&lt;treeName@gt;</dt>
39 * <dd>Tree to loop over</dd>
40 * <dt>&lt;options@gt;</dt>
41 * <dd>List of options separated by an &amp;
42 * <dl>
43 * <dt><tt>storage=&lt;url&gt;</tt></dt>
44 * <dd>Specify a non-default storage location for special output
45 * (e.g., AOD trees). &lt;url&gt; should be a valid XRootd
46 * server URI accessible to the slaves - e.g.,
47 * <tt>root://lxplus.cern.ch:10930//tmp</tt>.</dd>
48 * <dt><tt>mode=[default,rec,sim,train,custom]</tt></dt>
49 * <dd>Set the AliROOT mode. If not specified <tt>default</tt>
50 * is assumed</tt>. See also CreateAliROOTPar</dd>
51 * <dt><tt>par</tt></dt>
52 * <dd> Use PAR files</dd>
53 * <dt><tt>runs=[list or file]</tt></dt>
54 * <dd>Comma separated list of run numbers, or file(s) containing
55 * run numbers</dd>
56 * <dt><tt>oper=[FULL,TERMINATE,SUBMIT,OFFLINE,TEST]</tt></dt>
57 * <dd>How to run the analysis</dd>
58 * <dt><tt>split=&lt;N&gt;</tt></dt>
59 * <dd>Maximum number of files per split</dd>
60 * <dt><tt>merge=&lt;N&gt;</tt></dt>
61 * <dd>Maximum number of files per merger</dd>
62 * <dt><tt>mc</tt></dt>
63 * <dd>Scan also for MC files (<tt>galice.root</tt>,
64 * <tt>Kinematics.root</tt>, and <tt>TrackRefs.root</tt>) when
65 * scanning &lt;datadir&gt;</dd>
66 * <dt><tt>pattern=&lt;GLOB&gt;</tt></dt>
67 * <dd>Shell glob pattern that files must check when scanning
68 * &lt;datadir&gt;</dd>
69 * </dl>
70 * </dd>
71 * </dl>
72 *
73 * @ingroup pwglf_forward_trains_helper
74 */
75struct GridHelper : public PluginHelper
76{
77 /**
78 * Constructor
79 *
80 * @param url Url
81 * @param opts Options
82 */
83 GridHelper(const TUrl& url, Int_t verbose)
9201c66b 84 : PluginHelper(url, verbose), fRuns()
fdfd93b4 85 {
86 fOptions.Add("oper", "FULL|TERMINATE|SUBMIT", "Analysis operation", "FULL");
a80dde0d 87 fOptions.Add("split", "N|max", "Max number of files before split","max");
88 fOptions.Add("merge", "N|max", "Max number of files for merge", "max");
89 fOptions.Add("run", "RUNS", "Range, list, and/or file of runs");
90 fOptions.Add("pattern","GLOB", "File/directory name pattern");
91 fOptions.Add("alien", "VERSION","Alien API version", "V1.1x");
92 fOptions.Add("concat", "Concatenate all runs");
b7a63753 93 fOptions.Add("ttl", "N|max", "Time to live", "max");
fdfd93b4 94 }
9201c66b 95 GridHelper(const GridHelper& o)
96 : PluginHelper(o), fRuns()
97 {}
98 GridHelper& operator=(const GridHelper& o)
99 {
100 if (&o == this) return *this;
101 PluginHelper::operator=(o);
102 return *this;
103 }
fdfd93b4 104 virtual ~GridHelper() {}
105 /**
106 * Get the mode identifier
107 *
108 * @return Always kProof
109 */
110 virtual UShort_t Mode() const { return kGrid; }
111 /**
112 * Get the mode string used for AliAnalysisManager::StartAnalysis
113 */
114 virtual const char* ModeString() const { return "grid"; }
115 /**
116 * Set-up done before task set-ups
117 *
118 * @return true on success
119 */
120 virtual UShort_t Operation() const
121 {
122 if (!fOptions.Has("oper")) return kFull;
123 const TString& oper = fOptions.Get("oper");
124 if (oper.EqualTo("FULL", TString::kIgnoreCase)) return kFull;
125 else if (oper.EqualTo("OFFLINE", TString::kIgnoreCase)) return kOffline;
126 else if (oper.EqualTo("SUBMIT", TString::kIgnoreCase)) return kSubmit;
127 else if (oper.EqualTo("TERMINATE", TString::kIgnoreCase)) return kTerminate;
128 else if (oper.EqualTo("TEST", TString::kIgnoreCase)) return kTest;
129 return kFull;
130 }
9201c66b 131 void StoreRun(Int_t r)
132 {
133 TObject* o = new TObject;
134 o->SetUniqueID(r);
135 fRuns.Add(o);
136 }
fdfd93b4 137 /**
138 * Read run numbers
139 *
140 * @return Number of registered runs
141 */
142 virtual Int_t RegisterRuns()
143 {
144 if (!fOptions.Find("run")) {
145 Error("GridHelper::RegisterRuns", "No runs specified");
146 return -1;
147 }
148 Int_t nRuns = 0;
a80dde0d 149 TString runs = fOptions.Get("run");
08275d05 150 TObjArray* tokens = runs.Tokenize(",+.");
fdfd93b4 151 TObjString* part = 0;
152 TIter next(tokens);
153 Bool_t range = false;
154 Bool_t individual = false;
85f21ab4 155 // Info("GridHelper::RegisterRuns", "Runs specified are %s", runs.Data());
fdfd93b4 156 while ((part = static_cast<TObjString*>(next()))) {
157 TString& s = part->String();
158 if (s.Contains("-")) { // Run range
159 if (range) {
160 Warning("GridHelper::RegisterRuns", "Run range already specified, "
161 "ignoring %s", s.Data());
162 continue;
163 }
164 if (individual) {
165 Warning("GridHelper::RegisterRuns",
166 "Run ranges and individual run specs do not mix, "
167 "ignoring %s", s.Data());
168 continue;
169 }
170 TObjArray* ranges = s.Tokenize("-");
171 if (ranges->GetEntriesFast() > 2) {
172 Warning("GridHelper::RegisterRuns", "Invalid run range: %s",
173 s.Data());
174 ranges->Delete();
175 continue;
176 }
177 Int_t first = static_cast<TObjString*>(ranges->At(0))->String().Atoi();
178 Int_t last = static_cast<TObjString*>(ranges->At(1))->String().Atoi();
179 nRuns = last-first+1;
85f21ab4 180 // Info("GridHelper::RegisterRuns", "Run range %d -> %d", first, last);
fdfd93b4 181 fHandler->SetRunRange(first, last);
182 ranges->Delete();
183 range = true;
9201c66b 184 for (Int_t r = first; r <= last; r++) StoreRun(r);
fdfd93b4 185 continue;
186 }
187 if (s.IsDigit()) { // single run
188 if (range) {
189 Warning("GridHelper::RegisterRuns",
190 "Run ranges and individual run specs do not mix, "
191 "ignoring %s", s.Data());
192 continue;
193 }
85f21ab4 194 // Info("GridHandler::RegisterRuns", "Adding run %s", s.Data());
9201c66b 195 fHandler->AddRunNumber(s.Atoi());
196 StoreRun(s.Atoi());
fdfd93b4 197 nRuns++;
198 individual = true;
199 continue;
200 }
a80dde0d 201 if (range) {
202 Warning("GridHelper::RegisterRuns", "Run ranges and list file "
203 "do not mix, ignoring %s", s.Data());
204 continue;
205 }
fdfd93b4 206
207 // We assume this part is a file
85f21ab4 208 // Info("GridHelper::RegisterRuns", "Reading runs from %s", s.Data());
fdfd93b4 209 std::ifstream in(s.Data());
210 if (!in) {
a54cc77b 211 s.Prepend("../");
212 in.open(s.Data());
213 if (!in) {
214 Warning("GridHelper::RegisterRuns", "Failed to open %s", s.Data());
215 continue;
216 }
fdfd93b4 217 }
218 while (!in.eof()) {
219 Int_t r;
220 in >> r;
85f21ab4 221 // Info("GridHelper::RegisterRuns", "Read %d, adding", r);
fdfd93b4 222 fHandler->AddRunNumber(r);
9201c66b 223 StoreRun(r);
fdfd93b4 224 nRuns++;
225 Char_t c;
226 in >> c;
227 if (in.bad()) break;
228 }
229 individual = true;
230 in.close();
231 }
232 return nRuns;
233 }
234 /**
235 * Executed before setting up tasks
236 *
237 * @return true on success
238 */
239 virtual Bool_t PreSetup()
240 {
241 if (!PluginHelper::PreSetup()) return false;
a80dde0d 242
243 // --- Add system library dir to load path -----------------------
244 gSystem->AddDynamicPath("/usr/lib");
fdfd93b4 245
246 // --- Open a connection to the grid -----------------------------
a80dde0d 247 if (!TGrid::Connect(Form("%s://", fUrl.GetProtocol()))) {
248 Error("GridHelper::PreSetup", "Failed to connect to AliEN");
249 return false;
250 }
fdfd93b4 251 if (!gGrid || !gGrid->IsConnected()) {
252 Error("GridHelper::PreSetup", "Failed to connect to AliEN");
253 return false;
254 }
255
256 return true;
257 }
258 /**
259 * Set-up done after the task set-ups
260 *
261 * @return true on success
262 */
263 virtual Bool_t PostSetup()
264 {
85f21ab4 265 // Info("GridHelper::PostSetup", "Calling super.PostSetup");
fdfd93b4 266 if (!PluginHelper::PostSetup()) return false;
267
a80dde0d 268 // --- API version -----------------------------------------------
269 fHandler->SetAPIVersion(fOptions.Get("alien"));
270
271 // --- Get the name ----------------------------------------------
85f21ab4 272 // Info("GridHelper", "Proceeding with plugin setup");
fdfd93b4 273 AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
274 TString name(mgr->GetName());
275
276 // --- Set the operation to do (TEST, SUBMIT, TERMINATE, FULL) ---
277 TString operation("FULL");
278 if (fOptions.Has("oper")) operation = fOptions.Get("oper");
279 fHandler->SetRunMode(operation);
280
a80dde0d 281 // --- Add the run numbers ---------------------------------------
a54cc77b 282 fHandler->SetRunPrefix(fOptions.Has("mc") ? "%d" : "%09d");
a80dde0d 283 Int_t nRun = RegisterRuns();
284
fdfd93b4 285 // --- Do not test copying ---------------------------------------
286 fHandler->SetCheckCopy(false);
287
288 // --- Set output to be per run ----------------------------------
289 fHandler->SetOutputToRunNo(true);
290
291 // --- Set the job tag -------------------------------------------
292 fHandler->SetJobTag(name);
293
294 // --- Set number of test files - used in test mode only ---------
295 fHandler->SetNtestFiles(1);
296
297 // --- Set the Time-To-Live --------------------------------------
b7a63753 298 if (fOptions.Has("ttl")) {
299 if (!fOptions.Get("ttl").EqualTo("max")) {
300 fHandler->SetTTL(fOptions.AsInt("ttl"));
301 }
302 }
fdfd93b4 303
304 // --- Re-submit failed jobs as long as the ratio of failed jobs -
305 // --- is this percentage.
306 fHandler->SetMasterResubmitThreshold(95);
307
308 // --- Set the input format --------------------------------------
309 fHandler->SetInputFormat("xml-single");
310
311 // --- Set names of generated files ------------------------------
312 fHandler->SetAnalysisMacro(Form("%s.C", name.Data()));
313 fHandler->SetJDLName(Form("%s.jdl", name.Data()));
314 fHandler->SetExecutable(Form("%s.sh", name.Data()));
315
316 // ---- Set the job price !? -------------------------------------
317 fHandler->SetPrice(1);
318
319 // --- Set whether to merge via JDL ------------------------------
320 fHandler->SetMergeViaJDL(true);
321
322 // --- Fast read otion -------------------------------------------
323 fHandler->SetFastReadOption(false);
324
325 // --- Whether to overwrite existing output ----------------------
326 fHandler->SetOverwriteMode(true);
327
328 // --- Set the executable binary name and options ----------------
329 fHandler->SetExecutableCommand("aliroot -b -q -x");
330
331 // --- Split by storage element - must be lower case! ------------
332 fHandler->SetSplitMode("se");
333
334 // --- How much to split -----------------------------------------
335 if (fOptions.Has("split")) {
336 if (!fOptions.Get("split").EqualTo("max")) {
a80dde0d 337 fHandler->SetSplitMaxInputFileNumber(fOptions.AsInt("split"));
fdfd93b4 338 }
339 }
fdfd93b4 340 // --- Merge parameters ------------------------------------------
341 if (fOptions.Has("merge")) {
342 if (!fOptions.Get("merge").EqualTo("max")) {
a80dde0d 343 fHandler->SetMaxMergeFiles(fOptions.AsInt("merge"));
fdfd93b4 344 }
345 }
346 fHandler->SetMergeExcludes("AliAOD.root *EventStat*.root "
347 "*event_stat*.root");
a80dde0d 348
349 // --- Set number of runs per master - 1 or all ------------------
350 fHandler->SetNrunsPerMaster(fOptions.Has("concat") ? nRun+1 : 1);
351
352
353 // --- Enable default outputs ------------------------------------
354 fHandler->SetDefaultOutputs(true);
fdfd93b4 355
356 // --- Keep log files ------------------------------------------
357 fHandler->SetKeepLogs();
358
359 // --- Set the working directory to be the trains name (with -----
360 // --- special characters replaced by '_' and the date appended),
361 // --- and also set the output directory (relative to working
362 // --- directory)
363 fHandler->SetGridWorkingDir(name.Data());
364 fHandler->SetGridOutputDir("output");
365 fHandler->SetGridDataDir(fUrl.GetFile());
366
367 // --- Get the tree name and set the file pattern ----------------
368 TString pattern;
369 if (fOptions.Has("pattern")) pattern = fOptions.Get("pattern");
370 else {
371 TString treeName(fUrl.GetAnchor());
372 if (treeName.IsNull()) {
373 Warning("GridHelper::PreSetup", "No tree name specified, assuming T");
374 treeName = "T";
375 }
376 if (treeName.EqualTo("esdTree")) pattern = "AliESD";
377 else if (treeName.EqualTo("aodTree")) pattern = "AliAOD";
378 }
379 fHandler->SetDataPattern(pattern);
fdfd93b4 380
381 // --- Loop over defined containers in the analysis manager, and -
382 // --- declare these as outputs
383 TString listOfAODs = "";
384 TString listOfHists = "";
85f21ab4 385 TString listOfTerms = "";
fdfd93b4 386
85f21ab4 387 TObjArray* outs[] = { mgr->GetOutputs(), mgr->GetParamOutputs(), 0 };
388 TObjArray** out = outs;
389 while (*out) {
390 AliAnalysisDataContainer* cont = 0;
391 TIter nextCont(*out);
392 while ((cont = static_cast<AliAnalysisDataContainer*>(nextCont()))) {
393 TString outName(cont->GetFileName());
394 Bool_t term = (*out == outs[1]);
395 TString& list = (outName == "default" ? listOfAODs :
396 !term ? listOfHists : listOfTerms);
397 if (outName == "default") {
398 if (!mgr->GetOutputEventHandler()) continue;
399
400 outName = mgr->GetOutputEventHandler()->GetOutputFileName();
401 }
85f21ab4 402 if (list.Contains(outName)) continue;
403 if (!list.IsNull()) list.Append(",");
404 list.Append(outName);
fdfd93b4 405 }
85f21ab4 406 out++;
fdfd93b4 407 }
85f21ab4 408 TString extra = mgr->GetExtraFiles();
409 if (!extra.IsNull()) {
fdfd93b4 410 if (!listOfAODs.IsNull()) listOfAODs.Append("+");
fdfd93b4 411 extra.ReplaceAll(" ", ",");
412 listOfAODs.Append(extra);
413 }
414
08275d05 415#if 0
fdfd93b4 416 Int_t nReplica = 2;
417 TString outArchive = Form("stderr, stdout@disk=%d", nReplica);
418 if (!listOfHists.IsNull())
419 outArchive.Append(Form(" hist_archive.zip:%s@disk=%d",
420 listOfHists.Data(), nReplica));
421 if (!listOfAODs.IsNull())
422 outArchive.Append(Form(" aod_archive.zip:%s@disk=%d",
423 listOfAODs.Data(), nReplica));
08275d05 424 // Disabled for now
425 // plugin->SetOutputArchive(outArchive);
426#endif
427
fdfd93b4 428 if (listOfAODs.IsNull() && listOfHists.IsNull())
429 Fatal("PostSetup", "No outputs defined");
85f21ab4 430 if (!listOfTerms.IsNull())
431 fHandler->SetTerminateFiles(listOfTerms);
fdfd93b4 432
433 return true;
434 };
435 /**
436 * Start the analysis
437 *
438 * @param nEvents Number of events to analyse
439 *
440 * @return The return value of AliAnalysisManager::StartAnalysis
441 */
442 virtual Long64_t Run(Long64_t nEvents=-1)
443 {
444 AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
85f21ab4 445 if (nEvents == 0) return 0;
446 Long64_t ret = mgr->StartAnalysis("grid", nEvents);
08275d05 447
a4923b29 448#if 0
08275d05 449 std::ofstream outJobs(Form("%s.jobid", mgr->GetName()));
88e0fd04 450 //outJobs << fHandler->GetGridJobIDs() << std::endl;
08275d05 451 outJobs.close();
452
453 std::ofstream outStages(Form("%s.stage", mgr->GetName()));
88e0fd04 454 // outStages << fHandler->GetGridStages() << std::endl;
08275d05 455 outStages.close();
a4923b29 456#endif
85f21ab4 457 return ret;
fdfd93b4 458 }
459 /**
460 * Link an auxilary file to working directory
461 *
462 * @param name Name of the file
463 *
464 * @return true on success
465 */
ddcc1bbd 466 virtual Bool_t AuxFile(const TString& name, bool copy=false)
fdfd93b4 467 {
ddcc1bbd 468 if (!Helper::AuxFile(name, copy)) return false;
fdfd93b4 469 // We need to add this file as an additional 'library', so that the
470 // file is uploaded to the users Grid working directory.
471 fHandler->AddAdditionalLibrary(gSystem->BaseName(name.Data()));
472 return true;
473 }
474 /**
475 * Get the output (directory)
476 *
477 */
478 virtual TString OutputPath() const
479 {
480 TString ret;
481 if (!fHandler) {
482 Warning("GridHelper::OutputLocation", "No AliEn handler");
483 return ret;
484 }
485 ret = fHandler->GetGridOutputDir();
486 if (ret.BeginsWith("/")) return ret;
487
488 AliAnalysisManager* mgr = AliAnalysisManager::GetAnalysisManager();
489 if (!mgr) {
490 Warning("GridHelper::OutputLocation", "No analysis manager");
491 return ret;
492 }
493 ret.Prepend(Form("%s/", mgr->GetName()));
494 if (gGrid)
495 ret.Prepend(Form("%s/", gGrid->GetHomeDirectory()));
496
497 return ret;
498 }
499 /**
500 * @return URL help string
501 */
502 virtual const Char_t* UrlHelp() const
503 {
504 return "alien:///<datadir>[?<options>][#<treeName>]";
505 }
506 /**
507 * @return Short description
508 */
509 virtual const char* Desc() const { return "AliEn"; }
a80dde0d 510 /**
511 * Write auxillary ROOT (and possible shell) script for more
512 * (post-)processing e.g., terminate
513 *
514 * @param escaped Escaped name
515 * @param asShellScript also save as shell script
516 */
517 void AuxSave(const TString& escaped,
08275d05 518 Bool_t /*asShellScript*/)
a80dde0d 519 {
520 // Write plug-in to file
521 TFile* plug = TFile::Open(Form("%s_plugin.root", escaped.Data()),
522 "RECREATE");
523 fHandler->Write("plugin");
524 plug->Close();
525
85f21ab4 526 TIter nextLib(&fExtraLibs);
527 TObjString* lib = 0;
528 TString libs;
529 while ((lib = static_cast<TObjString*>(nextLib()))) {
530 if (!libs.IsNull()) libs.Append(" ");
531 libs.Append(lib->String());
532 }
533 TIter nextPar(&fExtraPars);
534 TObjString* par = 0;
535 TString pars;
536 while ((par = static_cast<TObjString*>(nextPar()))) {
537 if (!pars.IsNull()) pars.Append(" ");
538 pars.Append(par->String());
539 }
540 TIter nextSrc(&fExtraSrcs);
541 TObjString* src = 0;
542 TString srcs;
543 while ((src = static_cast<TObjString*>(nextSrc()))) {
544 if (!srcs.IsNull()) srcs.Append(" ");
545 srcs.Append(src->String());
546 }
547 TString macDir("$ALICE_ROOT/PWGLF/FORWARD/trains");
9201c66b 548 std::ofstream t("Terminate.C");
549 if (!t) {
a80dde0d 550 Error("GridHelper::AuxSave", "Failed to make terminate ROOT script");
551 return;
552 }
85f21ab4 553
554 t << "// Generated by GridHelper\n"
555 << "Bool_t Terminate()\n"
556 << "{\n"
557 << " TString name = \"" << escaped << "\";\n"
558 << " TString libs = \"" << libs << "\";\n"
559 << " TString pars = \"" << pars << "\";\n"
560 << " TString srcs = \"" << srcs << "\";\n\n"
561 << " gROOT->LoadMacro(\"" << macDir << "/GridTerminate.C\");\n\n"
562 << " return GridTerminate(name,libs,pars,srcs);\n"
563 << "}\n"
564 << "// EOF\n"
565 << std::endl;
566 t.close();
567
568 TString runs;
569 TString format(fOptions.Has("mc") ? "%d" : "%09d");
570 if (fOptions.Has("concat")) {
571 Int_t first = fRuns.First()->GetUniqueID();
572 Int_t last = fRuns.Last()->GetUniqueID();
573 TString fmt(format);
574 fmt.Append("_");
575 fmt.Append(format);
576 if (!runs.IsNull()) runs.Append(" ");
577 runs.Append(TString::Format(fmt, first, last));
578 }
579 else {
580 TIter next(&fRuns);
581 TObject* o = 0;
582 while ((o = next())) {
583 if (!runs.IsNull()) runs.Append(" ");
584 runs.Append(Form(format, o->GetUniqueID()));
585 }
586 }
587
588 std::ofstream d("Download.C");
589 if (!d) {
590 Error("GridHelper::AuxSave", "Failed to make ROOT script Download.C");
591 return;
592 }
593 d << "// Generated by GridHelper\n"
594 << "void Download()\n"
595 << "{\n"
596 << " TString base = \"" << fUrl.GetProtocol() << "://"
597 << OutputPath() << "\";\n"
598 << " TString runs = \"" << runs << "\";\n\n"
599 << " gROOT->LoadMacro(\"" << macDir << "/GridDownload.C\");\n\n"
600 << " GridDownload(base, runs);\n"
601 << "}\n"
602 << "// EOF\n"
603 << std::endl;
604 d.close();
08275d05 605
606 std::ofstream w("Watch.C");
607 if (!w) {
608 Error("GridHelper::AuxSave", "Failed to make ROOT script Watch.C");
85f21ab4 609 return;
610 }
08275d05 611 w << "// Generated by GridHelper\n"
612 << "void Watch(Int_t delay=5*60)\n"
a80dde0d 613 << "{\n"
08275d05 614 << " TString name = \"" << escaped << "\";\n"
615 << " gROOT->LoadMacro(\"" << macDir << "/GridWatch.C+g\");\n\n"
616 << " GridWatch(name,delay);\n"
a80dde0d 617 << "}\n"
a80dde0d 618 << "// EOF\n"
85f21ab4 619 << std::endl;
08275d05 620 w.close();
85f21ab4 621
a80dde0d 622 }
9201c66b 623 TList fRuns;
fdfd93b4 624};
625#endif
626//
627// EOF
628//