ATLAS Offline Software
Loading...
Searching...
No Matches
PrunDriver.cxx File Reference
#include <EventLoopGrid/PrunDriver.h>
#include <EventLoop/Algorithm.h>
#include <EventLoop/ManagerData.h>
#include <EventLoop/ManagerStep.h>
#include <EventLoop/Job.h>
#include <EventLoop/MessageCheck.h>
#include <EventLoop/OutputStream.h>
#include <PathResolver/PathResolver.h>
#include <RootCoreUtils/Assert.h>
#include <RootCoreUtils/hadd.h>
#include <RootCoreUtils/ShellExec.h>
#include <SampleHandler/MetaObject.h>
#include <SampleHandler/Sample.h>
#include <SampleHandler/SampleGrid.h>
#include <SampleHandler/SampleHandler.h>
#include <SampleHandler/GridTools.h>
#include <TList.h>
#include <TPython.h>
#include <TROOT.h>
#include <TFile.h>
#include <TSystem.h>
#include <algorithm>
#include <any>
#include <array>
#include <cstdlib>
#include <filesystem>
#include <iostream>
#include <optional>
#include <set>
#include <sstream>
#include <string>
#include <vector>
#include <stdexcept>
#include <ranges>
#include "pool.h"
#include <mutex>

Go to the source code of this file.

Functions

 ClassImp (EL::PrunDriver) namespace
static JobState::Enum sampleState (SH::Sample *sample)
static JobState::Enum nextState (JobState::Enum state, Status::Enum status)
static SH::MetaObject defaultOpts ()
static std::mutex & logMutex ()
static bool downloadContainer (const std::string &name, const std::string &location)
static int callPythonOnSample (const char *macroFile, const char *func, SH::Sample *sample)
static Status::Enum submit (SH::Sample *const sample, const bool isFirstSample)
static Status::Enum checkPandaTask (SH::Sample *const sample)
static Status::Enum download (SH::Sample *const sample)
static Status::Enum merge (SH::Sample *const sample)
static void processTask (SH::Sample *const sample, const bool isFirstSample)
static void processAllInState (const SH::SampleHandler &sh, JobState::Enum state, const size_t nThreads)
static std::optional< std::string > gridNickname ()
static std::string formatOutputName (const SH::MetaObject &sampleMeta, const std::string &pattern)
static std::string outputFileNames (const EL::Job &job)
static void saveJobDef (const std::string &fileName, const EL::Job &job, const SH::SampleHandler &sh)
static SH::SampleHandler outputSH (const SH::SampleHandler &in, const std::string &outputLabel)

Function Documentation

◆ callPythonOnSample()

int callPythonOnSample ( const char * macroFile,
const char * func,
SH::Sample * sample )
static

Definition at line 203 of file PrunDriver.cxx.

205{
206 static std::mutex mutex;
207 std::lock_guard<std::mutex> lock(mutex);
208
209 static std::set<std::string> loadedMacros;
210 if (loadedMacros.insert(macroFile).second) {
211 TPython::LoadMacro(PathResolverFindCalibFile(macroFile).c_str());
212 }
213
214 TPython::Bind(sample, "ELG_SAMPLE");
215 std::any result;
216 const std::string code =
217 std::string("_anyresult = ROOT.std.make_any['int'](") + func + "(ELG_SAMPLE))";
218 TPython::Exec(code.c_str(), &result);
219 TPython::Bind(nullptr, "ELG_SAMPLE");
220 return std::any_cast<int>(result);
221}
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
STL class.

◆ checkPandaTask()

Status::Enum checkPandaTask ( SH::Sample *const sample)
static

Definition at line 256 of file PrunDriver.cxx.

257{
258 RCU_REQUIRE(sample);
259 RCU_REQUIRE(static_cast<int>(sample->meta()->castDouble("nc_jediTaskID",0, SH::MetaObject::CAST_NOCAST_DEFAULT)) > 100);
260
261 int ret = callPythonOnSample("EventLoopGrid/ELG_jediState.py", "ELG_jediState", sample);
262
263 if (ret == Status::DONE) return Status::DONE;
264 if (ret == Status::FAIL) return Status::FAIL;
265
266 // Value 90 corresponds to `running` state of the job
267 if (ret != 90) { sample->meta()->setString("nc_ELG_state_details", "task status other than done/finished/failed/running"); }
268 // Value 99 is returned if there is error in the script (import, missing ID)
269 if (ret == 99) {
270 sample->meta()->setString("nc_ELG_state_details",
271 "problem checking jedi task status");
272 }
273
274 return Status::PENDING;
275}
#define RCU_REQUIRE(x)
Definition Assert.h:196
static int callPythonOnSample(const char *macroFile, const char *func, SH::Sample *sample)
@ CAST_NOCAST_DEFAULT
cast and return the default value if the input has the wrong type
Definition MetaObject.h:70

◆ ClassImp()

ClassImp ( EL::PrunDriver )
Author
Alexander Madsen
Nils Krumnack

Definition at line 52 of file PrunDriver.cxx.

54 {
55 namespace JobState {
56 static const unsigned int NSTATES = 6;
57 enum Enum { INIT=0, RUN=1, DOWNLOAD=2, MERGE=3, FINISHED=4, FAILED=5 };
58 static const char* name[NSTATES] =
59 { "INIT", "RUNNING", "DOWNLOAD", "MERGE", "FINISHED", "FAILED" };
60 Enum parse(const std::string& what)
61 {
62 for (unsigned int i = 0; i != NSTATES; ++i) {
63 if (what == name[i]) { return static_cast<Enum>(i); }
64 }
65 throw std::runtime_error("PrunDriver.cxx: Failed to parse job state string");
66 }
67 }
68
69 // When changing the values in the enum make sure
70 // corresponding values in `data/ELG_jediState.py` script
71 // are changed accordingly
72 namespace Status {
73 enum Enum { DONE=0, PENDING=1, FAIL=2 };
74 }
75
76 struct TransitionRule {
77 JobState::Enum fromState;
78 Status::Enum status;
79 JobState::Enum toState;
80 };
81
82 struct TmpCd {
83 const std::string origDir;
84 TmpCd(const std::string & dir)
85 : origDir(gSystem->pwd())
86 {
87 gSystem->cd(dir.c_str());
88 }
89 ~TmpCd()
90 {
91 gSystem->cd(origDir.c_str());
92 }
93 };
94}
#define INIT(__TYPE)
std::map< std::string, std::string, std::less<> > parse(const std::string &list)
Status
Athena specific StatusCode values.
status
Definition merge.py:16

◆ defaultOpts()

SH::MetaObject defaultOpts ( )
static

Definition at line 131 of file PrunDriver.cxx.

132{
134 o.setString("nc_nGBPerJob", "MAX");
135 o.setString("nc_mergeOutput", "true");
136 o.setString("nc_cmtConfig", gSystem->ExpandPathName("$AnalysisBase_PLATFORM"));
137 o.setString("nc_useAthenaPackages", "true");
138 const std::string mergestr = "elg_merge jobdef.root %OUT %IN";
139 o.setString("nc_mergeScript", mergestr);
140 return o;
141}
A class that manages meta-data to be associated with an object.
Definition MetaObject.h:48
void setString(const std::string &name, const std::string &value)
set the meta-data string with the given name

◆ download()

Status::Enum download ( SH::Sample *const sample)
static

Definition at line 277 of file PrunDriver.cxx.

278{
279 RCU_REQUIRE(sample);
280 using namespace EL::msgEventLoop;
281
282 // This can run on several download threads at once; the shared message stream
283 // is not thread-safe, so serialize the logging (see logMutex()).
284 {
285 std::lock_guard<std::mutex> lock(logMutex());
286 ANA_MSG_INFO("Downloading output from: " << sample->name() << "...");
287 }
288
289 std::string container = sample->meta()->castString("nc_outDS", "", SH::MetaObject::CAST_NOCAST_DEFAULT);
290 RCU_ASSERT(not container.empty());
291 if (container[container.size()-1] == '/') {
292 container.resize(container.size() - 1);
293 }
294 container += "_hist/";
295
296 bool downloadOk = downloadContainer(container, "elg/download/" + container);
297
298 if (not downloadOk) {
299 std::lock_guard<std::mutex> lock(logMutex());
300 ANA_MSG_ERROR("Failed to download one or more files");
301 sample->meta()->setString("nc_ELG_state_details",
302 "error, check log for details");
303 return Status::PENDING;
304 }
305
306 return Status::DONE;
307}
#define RCU_ASSERT(x)
Definition Assert.h:210
#define ANA_MSG_ERROR(xmsg,...)
Macro printing error messages.
#define ANA_MSG_INFO(xmsg,...)
Macro printing info messages.
static bool downloadContainer(const std::string &name, const std::string &location)
static std::mutex & logMutex()
const SG::AuxVectorData * container() const
Return the container holding this element.

◆ downloadContainer()

bool downloadContainer ( const std::string & name,
const std::string & location )
static

Definition at line 154 of file PrunDriver.cxx.

156{
157 using namespace EL::msgEventLoop;
158 RCU_ASSERT(not name.empty());
159 RCU_ASSERT(name[name.size()-1] == '/');
160 RCU_ASSERT(not location.empty());
161
162 try {
163 std::error_code ec;
164 std::filesystem::create_directories(location, ec);
165 if (ec) {
166 std::lock_guard<std::mutex> lock(logMutex());
167 ANA_MSG_ERROR("Failed to create directory " << location << ": " << ec.message());
168 return false;
169 }
170
171 std::vector<std::string> datasets;
172 for (auto& entry : SH::rucioListDids (name))
173 {
174 if (entry.type == "CONTAINER" || entry.type == "DIDType.CONTAINER")
175 datasets.push_back (entry.name);
176 }
177
178 auto downloadResult = SH::rucioDownloadList (location, datasets);
179 for (const auto& result : downloadResult)
180 {
181 if (result.notDownloaded != 0)
182 return false;
183 }
184 } catch (const std::exception& e) {
185 std::lock_guard<std::mutex> lock(logMutex());
186 ANA_MSG_ERROR("Failed to download " << name << ": " << e.what());
187 return false;
188 }
189 return true;
190}
std::vector< RucioDownloadResult > rucioDownloadList(const std::string &location, const std::vector< std::string > &datasets)
run rucio-download with multiple datasets
std::vector< RucioListDidsEntry > rucioListDids(const std::string &dataset)
run rucio-list-dids for the given dataset

◆ formatOutputName()

std::string formatOutputName ( const SH::MetaObject & sampleMeta,
const std::string & pattern )
static

Definition at line 490 of file PrunDriver.cxx.

492{
493 const std::string sampleName = sampleMeta.castString("sample_name");
494 RCU_REQUIRE(not pattern.empty());
495 using namespace EL::msgEventLoop;
496
497 TString out = pattern.c_str();
498
499 // Handle case of no proxy; will create a proxy later in the submission
500 const std::optional<std::string> nickname = gridNickname();
501 if (not nickname.has_value()){
502 ANA_MSG_WARNING( "No proxy available - cannot use nickname yet. Will try a late replacement.");
503 } else {
504 out.ReplaceAll("%nickname%", *nickname);
505 }
506
507 out.ReplaceAll("%in:name%", sampleName);
508
509 std::stringstream ss(sampleName);
510 std::string item;
511 int field = 0;
512 while(std::getline(ss, item, '.')) {
513 std::stringstream sskey;
514 sskey << "%in:name[" << ++field << "]%";
515 out.ReplaceAll(sskey.str(), item);
516 }
517 while (out.Index("%in:") != -1) {
518 int i1 = out.Index("%in:");
519 int i2 = out.Index("%", i1+1);
520 if (i2 == -1) {
521 ANA_MSG_ERROR("malformed output name pattern, unterminated %in: token in \""
522 << out.Data() << "\"");
523 break;
524 }
525 TString metaName = out(i1+4, i2-i1-4);
526 out.ReplaceAll("%in:"+metaName+"%",
527 sampleMeta.castString(std::string(metaName.Data())));
528 }
529 out.ReplaceAll("/", "");
530 return out.Data();
531}
#define ANA_MSG_WARNING(xmsg,...)
Macro printing warning messages.
static Double_t ss
static std::optional< std::string > gridNickname()
std::string castString(const std::string &name, const std::string &def_val="", CastMode mode=CAST_ERROR_THROW) const
the meta-data string with the given name

◆ gridNickname()

std::optional< std::string > gridNickname ( )
static

Definition at line 467 of file PrunDriver.cxx.

468{
469 static std::optional<std::string> cached;
470 if (cached.has_value()) { return cached; }
471
472 std::any result;
473 const char* code =
474 "try:\n"
475 " from pandatools import PsubUtils\n"
476 " _nick = str(PsubUtils.getNickname())\n"
477 "except Exception:\n"
478 " _nick = ''\n"
479 "_anyresult = ROOT.std.make_any['std::string'](_nick)\n";
480 TPython::Exec(code, &result);
481 const std::string nickname = std::any_cast<std::string>(result);
482
483 // An empty result means the lookup failed; a very long one is panda's
484 // "no proxy" message rather than an actual nickname.
485 if (nickname.empty() || nickname.length() > 20) { return std::nullopt; }
486 cached = nickname;
487 return cached;
488}
cached(func)
Decorator to cache function return value.
Definition cached.py:6

◆ logMutex()

std::mutex & logMutex ( )
static

Definition at line 148 of file PrunDriver.cxx.

149{
150 static std::mutex mutex;
151 return mutex;
152}

◆ merge()

Status::Enum merge ( SH::Sample *const sample)
static

Definition at line 309 of file PrunDriver.cxx.

310{
311 RCU_REQUIRE(sample);
312 // The MERGE state is always processed single-threaded, so the logging here
313 // needs no serialization (unlike download(), see logMutex()).
314 using namespace EL::msgEventLoop;
315
316 std::string container = sample->meta()->castString("nc_outDS", "", SH::MetaObject::CAST_NOCAST_DEFAULT);
317 RCU_ASSERT(not container.empty());
318 if (container[container.size()-1] == '/') {
319 container.resize(container.size() - 1);
320 }
321 container += "_hist/";
322 const std::string dir = "elg/download/" + container;
323
324 const std::string fileName = "hist-output.root";
325
326 const std::string target = Form("hist-%s.root", sample->name().c_str());
327
328 // Collect the per-job output files, i.e. those whose name contains
329 // ".hist-output.root" (matching the old `find -name "*.hist-output.root*"`).
330 namespace fs = std::filesystem;
331 const std::string needle = "." + fileName;
332 std::vector<std::string> files;
333 std::error_code ec;
334 for (fs::recursive_directory_iterator it(dir, ec), end; it != end; it.increment(ec)) {
335 if (ec) { break; }
336 if (it->is_regular_file() &&
337 it->path().filename().string().find(needle) != std::string::npos) {
338 files.push_back(it->path().string());
339 }
340 }
341
342 std::sort(files.begin(), files.end());
343 // Duplicates are not expected (the directory scan never lists a file twice),
344 // but drop them with a real runtime check rather than a side-effecting assert.
345 std::vector<std::string> duplicates;
346 for (size_t i = 1; i < files.size(); ++i) {
347 if (files[i] == files[i - 1]) { duplicates.push_back(files[i]); }
348 }
349 if (not duplicates.empty()) {
350 std::ostringstream dup;
351 for (const std::string& name : duplicates) { dup << ' ' << name; }
352 ANA_MSG_WARNING("Ignoring duplicate input file(s) for merging:" << dup.str());
353 files.erase(std::unique(files.begin(), files.end()), files.end());
354 }
355
356 if (not files.size()) {
357 ANA_MSG_ERROR("Found no input files for merging! "
358 "Requeueing sample for download...");
359 sample->meta()->setString("nc_ELG_state_details", "retry, files were lost");
360 return Status::FAIL;
361 }
362
363 try {
364 RCU::hadd(target.c_str(), files);
365 } catch (...) {
366 sample->meta()->setString("nc_ELG_state_details",
367 "error, check log for details");
368 fs::remove(target, ec);
369 return Status::PENDING;
370 }
371
372 // Remove the merged inputs and the (now empty) download tree.
373 for (const std::string& file : files) {
374 fs::remove(file, ec);
375 if (ec) {
376 ANA_MSG_WARNING("Failed to remove merged input " << file << ": " << ec.message());
377 }
378 }
379 fs::remove_all(dir, ec);
380 if (ec) {
381 ANA_MSG_WARNING("Failed to remove download directory " << dir << ": " << ec.message());
382 }
383
384 return Status::DONE;
385}
static Double_t fs
std::vector< std::string > files
file names and file pointers
Definition hcg.cxx:52
void hadd(const std::string &output_file, const std::vector< std::string > &input_files, unsigned max_files)
effects: perform the hadd functionality guarantee: basic failures: out of memory III failures: i/o er...
Definition hadd.cxx:29
DataModel_detail::iterator< DVL > unique(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of unique for DataVector/List.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TFile * file

◆ nextState()

JobState::Enum nextState ( JobState::Enum state,
Status::Enum status )
static

Definition at line 104 of file PrunDriver.cxx.

105{
106 RCU_REQUIRE(state != JobState::FINISHED);
107 RCU_REQUIRE(state != JobState::FAILED);
108 static constexpr std::array<TransitionRule, 12> TABLE =
109 {{
110 {JobState::INIT, Status::DONE, JobState::RUN},
111 {JobState::INIT, Status::PENDING, JobState::INIT},
112 {JobState::INIT, Status::FAIL, JobState::FAILED},
113 {JobState::RUN, Status::DONE, JobState::DOWNLOAD},
114 {JobState::RUN, Status::PENDING, JobState::RUN},
115 {JobState::RUN, Status::FAIL, JobState::FAILED},
116 {JobState::DOWNLOAD, Status::DONE, JobState::MERGE},
117 {JobState::DOWNLOAD, Status::PENDING, JobState::DOWNLOAD},
118 {JobState::DOWNLOAD, Status::FAIL, JobState::FAILED},
119 {JobState::MERGE, Status::DONE, JobState::FINISHED},
120 {JobState::MERGE, Status::PENDING, JobState::MERGE},
121 {JobState::MERGE, Status::FAIL, JobState::DOWNLOAD}
122 }};
123 for (const TransitionRule& rule : TABLE) {
124 if (rule.fromState == state && rule.status == status) {
125 return rule.toState;
126 }
127 }
128 throw std::logic_error("PrunDriver.cxx: Missing state transition rule");
129}

◆ outputFileNames()

std::string outputFileNames ( const EL::Job & job)
static

Definition at line 533 of file PrunDriver.cxx.

534{
535 std::string out = "hist:hist-output.root";
536 for (EL::Job::outputIter os = job.outputBegin(),
537 end = job.outputEnd(); os != end; ++os) {
538 const std::string name = os->label() + ".root";
539 const std::string ds =
540 os->options()->castString(EL::OutputStream::optContainerSuffix);
541 out += "," + (ds.empty() ? name : ds + ":" + name);
542 }
543 return out;
544}
const OutputStream * outputIter
Definition Job.h:139
static const std::string optContainerSuffix

◆ outputSH()

SH::SampleHandler outputSH ( const SH::SampleHandler & in,
const std::string & outputLabel )
static

Definition at line 571 of file PrunDriver.cxx.

573{
575 const std::string outputFile = "*" + outputLabel + ".root*";
576 const std::string outDSSuffix = '_' + outputLabel + ".root/";
577 for (SH::Sample* const sample : in) {
578 auto outSample = std::make_unique<SH::SampleGrid>(sample->name());
579 const std::string outputDS = sample->meta()->castString("nc_outDS", "", SH::MetaObject::CAST_NOCAST_DEFAULT) + outDSSuffix;
580 outSample->meta()->setString("nc_grid", outputDS);
581 outSample->meta()->setString("nc_grid_filter", outputFile);
582 out.add(std::move(outSample));
583 }
584 out.fetch(in);
585 return out;
586}
const std::string outputLabel
A class that manages a list of Sample objects.
a base class that manages a set of files belonging to a particular data set and the associated meta-d...
Definition Sample.h:49

◆ processAllInState()

void processAllInState ( const SH::SampleHandler & sh,
JobState::Enum state,
const size_t nThreads )
static

Definition at line 418 of file PrunDriver.cxx.

420{
421 RCU_REQUIRE(sh.size());
422
423 WorkList workList;
424
425 bool isFirstSample = true;
426 for (SH::Sample* const sample : sh) {
427 if (sampleState(sample) == state) {
428 workList.push_back([sample, isFirstSample, state]()->void{
429 if (state == JobState::INIT) {
430 // INIT is always processed single-threaded, so let an exception
431 // (e.g. the deliberate tarball-creation abort in submit()) propagate
432 // and stop the submission.
433 processTask(sample, isFirstSample);
434 } else {
435 // On a worker thread an escaping exception would call std::terminate.
436 // Record it against the sample and mark it FAILED so the pool
437 // finishes processing the remaining samples.
438 try {
439 processTask(sample, isFirstSample);
440 } catch (const std::exception& e) {
441 using namespace EL::msgEventLoop;
442 {
443 std::lock_guard<std::mutex> lock(logMutex());
444 ANA_MSG_ERROR ("Exception while processing " << sample->name()
445 << ": " << e.what());
446 }
447 sample->meta()->setString ("nc_ELG_state_details",
448 std::string ("exception: ") + e.what());
449 sample->meta()->setString ("nc_ELG_state",
450 JobState::name[JobState::FAILED]);
451 }
452 }
453 });
454 // Change boolean to false as already processed one sample
455 isFirstSample = false;
456 }
457 }
458 process(workList, nThreads);
459}
std::vector< WorkUnit > WorkList
static JobState::Enum sampleState(SH::Sample *sample)
static void processTask(SH::Sample *const sample, const bool isFirstSample)
const std::string process

◆ processTask()

void processTask ( SH::Sample *const sample,
const bool isFirstSample )
static

Definition at line 387 of file PrunDriver.cxx.

388{
389 RCU_REQUIRE(sample);
390
391 JobState::Enum state = sampleState(sample);
392
393 sample->meta()->setString("nc_ELG_state_details", "");
394
395 Status::Enum status = Status::PENDING;
396 switch (state) {
397 case JobState::INIT:
398 status = submit(sample, isFirstSample);
399 break;
400 case JobState::RUN:
401 status = checkPandaTask(sample);
402 break;
403 case JobState::DOWNLOAD:
404 status = download(sample);
405 break;
406 case JobState::MERGE:
407 status = merge(sample);
408 break;
409 case JobState::FINISHED:
410 case JobState::FAILED:
411 break;
412 }
413
414 state = nextState(state, status);
415 sample->meta()->setString("nc_ELG_state", JobState::name[state]);
416}
static Status::Enum submit(SH::Sample *const sample, const bool isFirstSample)
static JobState::Enum nextState(JobState::Enum state, Status::Enum status)
static Status::Enum checkPandaTask(SH::Sample *const sample)
static Status::Enum download(SH::Sample *const sample)
Definition merge.py:1

◆ sampleState()

JobState::Enum sampleState ( SH::Sample * sample)
static

Definition at line 96 of file PrunDriver.cxx.

97{
98 RCU_REQUIRE(sample);
99 static const std::string defaultState = JobState::name[JobState::INIT];
100 std::string label = sample->meta()->castString ("nc_ELG_state", defaultState, SH::MetaObject::CAST_NOCAST_DEFAULT);
101 return JobState::parse(label);
102}
std::string label(const std::string &format, int i)
Definition label.h:19

◆ saveJobDef()

void saveJobDef ( const std::string & fileName,
const EL::Job & job,
const SH::SampleHandler & sh )
static

Definition at line 547 of file PrunDriver.cxx.

550{
551 TFile file(fileName.c_str(), "RECREATE");
552 TList outputs;
553 outputs.SetOwner(true);
554 for (EL::Job::outputIter o = job.outputBegin(); o !=job.outputEnd(); ++o)
555 outputs.Add(o->Clone());
556 file.WriteTObject(&job.jobConfig(), "jobConfig", "SingleKey");
557 file.WriteTObject(&outputs, "outputs", "SingleKey");
558 bool haveDefault = false;
559 for (SH::Sample* const sample : sh) {
560 const SH::MetaObject& meta = *(sample->meta());
561 file.WriteObject(&meta, meta.castString("sample_name").c_str());
562 if (!haveDefault)
563 {
564 file.WriteObject (&meta, "defaultMetaObject");
565 haveDefault = true;
566 }
567 }
568}
-diff

◆ submit()

Status::Enum submit ( SH::Sample *const sample,
const bool isFirstSample )
static

Definition at line 223 of file PrunDriver.cxx.

224{
225 RCU_REQUIRE(sample);
226 using namespace EL::msgEventLoop;
227
228 ANA_MSG_INFO( "Submitting " << sample->name() << "..." );
229
230 int ret = callPythonOnSample("EventLoopGrid/ELG_prun.py", "ELG_prun", sample);
231
232 // Tarball is created for the first sample to be submitted
233 // then the tarball is simply reused for the other samples
234 // If the returned value is 1 it implies the tarball creation failed
235 // See EventLoopGrid/data/ELG_prun.py script
236 // Abort any further processing as the tarball was not succesfully created
237 if (isFirstSample && ret == 1){
238 ANA_MSG_ERROR("Failed to create tarball");
239 throw std::runtime_error("PrunDriver.cxx: aborting due to tarball creation issue");
240 }
241
242 if (ret < 100) {
243 sample->meta()->setString("nc_ELG_state_details",
244 "problem submitting");
245 return Status::FAIL;
246 }
247
248 sample->meta()->setDouble("nc_jediTaskID", ret);
249
250 // Let's also tell people about their task ID
251 ANA_MSG_INFO( "Task submitted; jediTaskID=" << ret );
252
253 return Status::DONE;
254}