GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TGRSIint.cxx
Go to the documentation of this file.
1#include "TGRSIint.h"
2
3#include "GRootGuiFactory.h"
4#include "GVersion.h"
5#include "Getline.h"
6#include "Globals.h"
7#include "TGRSIOptions.h"
8#include "TGRSIUtilities.h"
9#include "GValue.h"
10#include "GCanvas.h"
11
12#include "StoppableThread.h"
13#include "TAnalysisHistLoop.h"
14#include "TAnalysisWriteLoop.h"
15#include "TDataLoop.h"
16#include "TDetBuildingLoop.h"
17#include "TEventBuildingLoop.h"
18#include "TFragHistLoop.h"
19#include "TFragWriteLoop.h"
21#include "TFragmentChainLoop.h"
22#include "ArgParser.h"
23#include "TUnpackingLoop.h"
24#include "TParsingDiagnostics.h"
25#include "TSortingDiagnostics.h"
26#include "TParserLibrary.h"
27
28#include "GRootCommands.h"
29#include "TRunInfo.h"
30
31#include "TROOT.h"
32#include "TSystem.h"
33#include "TTimer.h"
34#include "TInterpreter.h"
35#include "TGHtmlBrowser.h"
36//#include <pstream.h>
37
38#include <thread>
39#include <utility>
40
41#include <pwd.h>
42
44
45TEnv* TGRSIint::fGRSIEnv = nullptr;
46
47void ReadTheNews();
48
49TChain* gFragment = nullptr;
50TChain* gAnalysis = nullptr;
51
52TGRSIint* TGRSIint::instance(int argc, char** argv, void*, int, bool, const char* appClassName)
53{
54 /// Singleton constructor instance
55 if(fTGRSIint == nullptr) {
56 fTGRSIint = new TGRSIint(argc, argv, nullptr, 0, true, appClassName);
58 }
59 return fTGRSIint;
60}
61
62TGRSIint::TGRSIint(int argc, char** argv, void*, int, bool noLogo, const char* appClassName)
63 : TRint(appClassName, &fFakeArgc, argv, nullptr, 0, noLogo), fKeepAliveTimer(nullptr),
64 main_thread_id(std::this_thread::get_id()), fIsTabComplete(false), fAllowedToTerminate(true), fRootFilesOpened(0),
65 fRawFilesOpened(0)
66{
67 /// Singleton constructor
68 fGRSIEnv = gEnv;
69
70 GetSignalHandler()->Remove();
71 auto* interruptHandler = new TGRSIInterruptHandler();
72 interruptHandler->Add();
73
74 try {
75 TGRSIOptions* opt = TGRSIOptions::Get(argc, argv);
76 if(opt->ShouldExit()) {
77 exit(0);
78 }
79 } catch(ParseError& e) {
80 exit(1);
81 }
82
83 PrintLogo(TGRSIOptions::Get()->ShowLogo());
84 SetPrompt("GRSI [%d] ");
85 std::string grsipath = getenv("GRSISYS");
86 gInterpreter->AddIncludePath(Form("%s/include", grsipath.c_str()));
87}
88
90{
91 /// Applies options from TGRSIOptions. This include things such as batch sorting,
92 /// reading material, and logo. Also includes the setup of what to do with mid
93 /// and root files that are input.
95
96 if(opt->Batch()) {
97 MakeBatch();
98 }
99
100 bool missing_raw_file = !AllFilesExist(opt->InputFiles());
101
103
104 if(opt->ReadingMaterial()) {
105 std::thread fnews = std::thread(ReadTheNews);
106 fnews.detach();
107 }
108
109 ////////////////////////////////////////////////////////
110 ////////////////////////////////////////////////////////
111 ////// Start of redoing section ///////
112 ////////////////////////////////////////////////////////
113 ////////////////////////////////////////////////////////
114
115 // load parser library if provided
116 if(!opt->ParserLibrary().empty()) {
117 try {
119 } catch(std::runtime_error& e) {
120 // if we failed to load the library, try to continue w/o it
121 std::cerr << DRED << e.what() << RESET_COLOR << std::endl;
122 }
123 }
124
126 TRunInfo::SetVersion(GRSI_RELEASE);
127
129 TRunInfo::SetFullVersion(GRSI_GIT_COMMIT);
130
132 TRunInfo::SetDate(GRSI_GIT_COMMIT_TIME);
133
134 for(const auto& rawFile : opt->InputFiles()) {
135 OpenRawFile(rawFile);
136 }
137
138 for(const auto& filename : opt->RootInputFiles()) {
139 // this will populate gChain if able.
140 // TChannels from the root file will be loaded as file is opened.
141 // GValues from the root file will be loaded as file is opened.
142 OpenRootFile(filename);
143 }
144
146
147 if(opt->StartGui()) {
148 StartGUI();
149 }
150
151 for(const auto& filename : opt->MacroInputFiles()) {
152 RunMacroFile(filename);
153 }
154
155 std::cout << StoppableThread::AllThreadHeader() << std::endl;
157 if(opt->CloseAfterSort()) {
158 int exit_status = missing_raw_file ? 1 : 0;
159 Terminate(exit_status);
160 }
161}
162
164{
165 /// Outputs the thread status until all of the threads are complete.
166 int iter = 0;
168 std::this_thread::sleep_for(std::chrono::seconds(1));
169
170 // We need to process events in case a different thread is asking for a file to be opened.
171 // However, if there is no stdin, ProcessEvents() will call Terminate().
172 // This prevents the terminate from taking effect while in this context.
173 fAllowedToTerminate = false;
174 gSystem->ProcessEvents();
175 fAllowedToTerminate = true;
176
177 ++iter;
178 if(TGRSIOptions::Get()->StatusInterval() > 0 && iter % TGRSIOptions::Get()->StatusInterval() == 0) {
179 std::cout << "\r" << StoppableThread::AllThreadStatus() << std::endl;
180 }
181 std::cout << "\r" << StoppableThread::AllThreadProgress() << std::flush;
182 }
183 std::cout << std::endl;
184}
185
187{
188 /// Handles terminal input via TRint
189 return TRint::HandleTermInput();
190}
191
192void TGRSIint::Terminate(Int_t status)
193{
194 /// Kills all of the threads if the process is allowed to terminate. This
195 /// sends an error to TSortingDiagnostics if an analysis tree is being created
197 std::cout << "Not allowed to terminate, sorry!" << std::endl;
198 return;
199 }
200
204
205 if(TGRSIOptions::Get()->MakeAnalysisTree()) {
207 }
208
209 if((clock() % 60) == 0) {
210 std::cout << "DING!" << std::flush;
211 gSystem->Sleep(500); // 500 ms
212 std::cout << "\r \r" << std::flush;
213 }
214
215 TSeqCollection* canvases = gROOT->GetListOfCanvases();
216 while(canvases->GetEntries() > 0) {
217 static_cast<GCanvas*>(canvases->At(0))->Close();
218 }
219
220 // clean up singletons
224 TPPG::Delete();
225
226 // close/detroy all opened raw files
227 for(auto* file : fRawFiles) {
229 }
230
232
233 TRint::Terminate(status);
234}
235
236Int_t TGRSIint::TabCompletionHook(char* buf, int* pLoc, std::ostream& out)
237{
238 /// Tries to do a tab completion. Returns false if unsuccsessful
239 fIsTabComplete = true;
240 auto result = TRint::TabCompletionHook(buf, pLoc, out);
241 fIsTabComplete = false;
242 return result;
243}
244
245Long_t TGRSIint::ProcessLine(const char* inputLine, Bool_t sync, Int_t* error)
246{
247 /// This takes over the native root command line. There are two main reasons for this
248 /// 1. To keep the command line thread-safe.
249 /// 2. To block TCanvas from opening, and to instead use our GCanvas.
250
251 // If you print while fIsTabComplete is true, you will break tab complete.
252 // Any diagnostic print statements should be done after this if statement.
253 if(fIsTabComplete) {
254 Long_t res = TRint::ProcessLine(inputLine, sync, error);
255 return res;
256 }
257
258 // loop over the input line and replace all instances of "TCanvas" with "GCanvas"
259 std::string line(inputLine);
260 size_t pos = 0;
261 while((pos = line.find("TCanvas", pos)) != std::string::npos) {
262 line[pos] = 'G';
263 }
264
265 if(std::this_thread::get_id() != main_thread_id) {
266 return DelayedProcessLine(line);
267 }
268
269 return TRint::ProcessLine(line.c_str(), sync, error);
270}
271
273{
274 /// Opens a random wikipedia page for your enjoyment
275#ifdef __APPLE__
276 gROOT->ProcessLine(".! open http://en.wikipedia.org/wiki/Special:Random > /dev/null 2>&1;");
277#else
278 gROOT->ProcessLine(".! xdg-open http://en.wikipedia.org/wiki/Special:Random > /dev/null 2>&1;");
279#endif
280}
281
282void TGRSIint::PrintLogo(bool print)
283{
284 /// Prints the GRSISort logo to terminal
285 if(print) {
286#ifdef LINUX
287 const std::string& ref = ProgramName();
288 const unsigned int reflength = ref.length() - 78;
289#else
290 const std::string& ref = "Sorting Program for Online and Offline Nuclear Data";
291 const unsigned int reflength = 53;
292#endif
293
294 const unsigned int width = reflength + (reflength % 2);
295 printf("\t*%s*\n", std::string(width, '*').c_str());
296 printf("\t*%*s%*s*\n", width / 2 + 4, "GRSI Sort", width / 2 - 4, "");
297 printf("\t*%*s%*s*\n", width / 2 + 12, "a remake of GRSI SPOON", width / 2 - 12, "");
298 printf("\t*%*s%*s*\n", width / 2 + reflength / 2, ref.c_str(), width / 2 - reflength / 2, "");
299 printf("\t*%*s%*s*\n", width / 2 + 14, "A lean, mean sorting machine", width / 2 - 14, "");
300 printf("\t*%*s%*s*\n", width / 2 + 9, "version " GRSI_RELEASE, width / 2 - 9, "");
301 printf("\t*%s*\n", std::string(width, '*').c_str());
302 } else {
303 std::cout << "\tgrsisort version " << GRSI_RELEASE << std::endl;
304 }
305}
306
307TFile* TGRSIint::OpenRootFile(const std::string& filename, Option_t* opt)
308{
309 /// Opens root files provided on the command line. Also tells you where these files
310 /// are stored (ie _file0). If these files are analysis or fragment trees, they are
311 /// automatically chained into chains called gFragment and gAnalysis. Once this is
312 /// complete, the TChannels, GValues and RunInfo are also read in.
313 TString sopt(opt);
314 sopt.ToLower();
315
316 TFile* file = nullptr;
317 if(sopt.Contains("recreate") || sopt.Contains("new")) {
318 // We are being asked to make a new file.
319 file = new TFile(filename.c_str(), "RECREATE");
320 if(file != nullptr && file->IsOpen()) {
321 // Give access to the file inside the interpreter.
322 const char* command = Form("TFile* _file%i = (TFile*)%luL;", fRootFilesOpened, reinterpret_cast<unsigned long>(file));
323 TRint::ProcessLine(command);
325 } else {
326 std::cout << "Could not create " << filename << std::endl;
327 }
328 } else {
329 // Open an already existing file.
330 file = new TFile(filename.c_str(), opt);
331 if(file != nullptr && file->IsOpen()) {
332 // Give access to the file inside the interpreter.
333 const char* command = Form("TFile* _file%i = (TFile*)%luL;", fRootFilesOpened, reinterpret_cast<unsigned long>(file));
334 TRint::ProcessLine(command);
335 std::cout << "\tfile " << BLUE << file->GetName() << RESET_COLOR << " opened as " << BLUE << "_file"
336 << fRootFilesOpened << RESET_COLOR << std::endl;
337
338 // If FragmentTree exists, add the file to the chain.
339 if(file->FindObjectAny("FragmentTree") != nullptr) {
340 if(gFragment == nullptr) {
341 // TODO: Once we have a notifier set up
342 gFragment = new TChain("FragmentChain");
343 // gFragment->SetNotify(GrutNotifier::Get());
344 }
345 std::cout << "file " << file->GetName() << " added to gFragment." << std::endl;
346 gFragment->AddFile(file->GetName(), TTree::kMaxEntries, "FragmentTree");
347 }
348
349 // If AnalysisTree exists, add the file to the chain.
350 if(file->FindObjectAny("AnalysisTree") != nullptr) {
351 if(gAnalysis == nullptr) {
352 gAnalysis = new TChain("AnalysisChain");
353 // TODO: Once we have a notifier set up
354 // gAnalysis->SetNotify(GrutNotifier::Get());
355 }
356 std::cout << "file " << file->GetName() << " added to gAnalysis." << std::endl;
357 gAnalysis->AddFile(file->GetName(), TTree::kMaxEntries, "AnalysisTree");
358 }
359
360 if(file->FindObjectAny("Channel") != nullptr) {
361 // not necessary to do anything as FindObjectAny already seems to call the streamer?
362 // file->Get("Channel"); // this calls TChannel::Streamer
363 }
364 if(file->FindObjectAny("Values") != nullptr) {
365 file->Get("Values");
366 }
368 } else {
369 std::cout << "Could not open " << filename << std::endl;
370 }
371 }
372
373 AddFileToGUI(file);
375
376 return file;
377}
378
379TRawFile* TGRSIint::OpenRawFile(const std::string& filename)
380{
381 /// Opens Raw input file and stores them in _raw if successfuly opened.
382 if(!FileExists(filename.c_str())) {
383 std::cerr << R"(File ")" << filename << R"(" does not exist)" << std::endl;
384 return nullptr;
385 }
386
387 // create new raw file
388 try {
389 auto* file = TParserLibrary::Get()->CreateRawFile(filename);
390 fRawFiles.push_back(file);
391
392 if(file != nullptr) {
393 const char* command = Form("TRawFile* _raw%i = (TRawFile*)%luL;", fRawFilesOpened, reinterpret_cast<unsigned long>(file));
394 ProcessLine(command);
395
396 std::cout << "\tfile " << BLUE << filename << RESET_COLOR << " opened as "
397 << BLUE << "_raw" << fRawFilesOpened << RESET_COLOR << std::endl;
398 }
400 return file;
401 } catch(std::runtime_error& e) {
402 std::cout << e.what();
403 }
404 return nullptr;
405}
406
408{
409 /// Finds all of the files input as well as flags provided and makes all
410 /// of the decisions about what to sort and what order to open everything up
411 /// in. This also creates the output files. Starts the threads and gets the
412 /// sorting going. This is really the brains of the command line sorting routine.
414
415 // Determining which parts of the pipeline need to be set up.
416
417 bool missingRawFile = false;
418 for(const auto& filename : opt->InputFiles()) {
419 if(!FileExists(filename.c_str())) {
420 missingRawFile = true;
421 std::cerr << "File not found: " << filename << std::endl;
422 }
423 }
424
425 // Which input files do we have
426 bool hasRawFile = !opt->InputFiles().empty() && opt->SortRaw() && !missingRawFile && !fRawFiles.empty();
427 bool hasInputFragmentTree = gFragment != nullptr; // && opt->SortRoot();
428 bool hasInputAnalysisTree = gAnalysis != nullptr; // && opt->SortRoot();
429
430 // Which output files are could possibly be made
431 bool ableToWriteFragmentHistograms = ((hasRawFile || hasInputFragmentTree) && !opt->FragmentHistogramLib().empty());
432 bool ableToWriteFragmentTree = (hasRawFile && !missingRawFile);
433 bool ableToWriteAnalysisHistograms = ((hasRawFile || hasInputFragmentTree || hasInputAnalysisTree) &&
434 !opt->AnalysisHistogramLib().empty());
435 bool ableToWriteAnalysisTree = (ableToWriteFragmentTree || hasInputFragmentTree);
436
437 // Which output files will we make
438 bool writeFragmentHistograms = (ableToWriteFragmentHistograms && opt->MakeHistos());
439 bool writeFragmentTree = ableToWriteFragmentTree && opt->WriteFragmentTree();
440 bool writeAnalysisHistograms = (ableToWriteAnalysisHistograms && opt->MakeHistos()); // TODO: make it so we aren't always trying to generate both frag and analysis histograms
441 bool writeAnalysisTree = (ableToWriteAnalysisTree && opt->MakeAnalysisTree());
442
443 // Which steps need to be performed to get from the inputs to the outputs
444 bool selfStopping = opt->CloseAfterSort();
445
446 bool readFromRaw = (hasRawFile && (writeFragmentHistograms || writeFragmentTree ||
447 writeAnalysisHistograms || writeAnalysisTree));
448
449 bool readFromFragmentTree = (hasInputFragmentTree && (writeFragmentHistograms || writeAnalysisHistograms || writeAnalysisTree));
450
451 bool generateAnalysisData = ((readFromRaw || readFromFragmentTree) && (writeAnalysisHistograms || writeAnalysisTree));
452
453 bool readFromAnalysisTree = (hasInputAnalysisTree && (writeAnalysisHistograms || writeAnalysisTree) && !generateAnalysisData);
454
455 // Extract the run number and sub run number from whatever we were given
456 int runNumber = 0;
457 int subRunNumber = 0;
458 if(readFromRaw) {
459 runNumber = fRawFiles[0]->GetRunNumber();
460 subRunNumber = fRawFiles[0]->GetSubRunNumber();
461 } else if(readFromFragmentTree) {
462 const auto* run_title = gFragment->GetListOfFiles()->At(0)->GetTitle();
463 runNumber = GetRunNumber(run_title);
464 subRunNumber = GetSubRunNumber(run_title);
465 } else if(readFromAnalysisTree) {
466 const auto* run_title = gAnalysis->GetListOfFiles()->At(0)->GetTitle();
467 runNumber = GetRunNumber(run_title);
468 subRunNumber = GetSubRunNumber(run_title);
469 }
470
471 // Choose output file names for the 4 possible output files
472 std::string outputFragmentTreeFilename = opt->OutputFragmentFile();
473 if(outputFragmentTreeFilename.empty()) {
474 if(subRunNumber == -1) {
475 outputFragmentTreeFilename = Form("fragment%05i.root", runNumber);
476 } else {
477 outputFragmentTreeFilename = Form("fragment%05i_%03i.root", runNumber, subRunNumber);
478 }
479 }
480
481 std::string outputFragmentHistFilename = opt->OutputFragmentHistogramFile();
482 if(outputFragmentHistFilename.empty()) {
483 if(subRunNumber == -1) {
484 outputFragmentHistFilename = Form("hist_fragment%05i.root", runNumber);
485 } else {
486 outputFragmentHistFilename = Form("hist_fragment%05i_%03i.root", runNumber, subRunNumber);
487 }
488 }
489
490 std::string outputDiagnosticsFilename = opt->OutputDiagnosticsFile();
491 if(outputDiagnosticsFilename.empty()) {
492 if(subRunNumber == -1) {
493 outputDiagnosticsFilename = Form("diagnostics%05i.root", runNumber);
494 } else {
495 outputDiagnosticsFilename = Form("diagnostics%05i_%03i.root", runNumber, subRunNumber);
496 }
497 }
498
499 std::string outputAnalysisTreeFilename = opt->OutputAnalysisFile();
500 if(outputAnalysisTreeFilename.empty()) {
501 if(subRunNumber == -1) {
502 if(opt->UseRnTuple()) {
503 outputAnalysisTreeFilename = Form("rntuple%05i.root", runNumber);
504 } else {
505 outputAnalysisTreeFilename = Form("analysis%05i.root", runNumber);
506 }
507 } else {
508 if(opt->UseRnTuple()) {
509 outputAnalysisTreeFilename = Form("rntuple%05i_%03i.root", runNumber, subRunNumber);
510 } else {
511 outputAnalysisTreeFilename = Form("analysis%05i_%03i.root", runNumber, subRunNumber);
512 }
513 }
514 }
515
516 std::string output_analysis_hist_filename = opt->OutputAnalysisHistogramFile();
517 if(output_analysis_hist_filename.empty()) {
518 if(subRunNumber == -1) {
519 output_analysis_hist_filename = Form("hist_analysis%05i.root", runNumber);
520 } else {
521 output_analysis_hist_filename = Form("hist_analysis%05i_%03i.root", runNumber, subRunNumber);
522 }
523 }
524
525 if(readFromAnalysisTree) {
526 std::cerr << "Reading from analysis tree not currently supported" << std::endl;
527 }
528
529 ////////////////////////////////////////////////////
530 //////////// Setting up the loops ////////////////
531 ////////////////////////////////////////////////////
532
533 if(!writeFragmentHistograms && !writeFragmentTree && !writeAnalysisHistograms && !writeAnalysisTree) {
534 // We still might want to read the calibration, values, or run info files
535 for(const auto& cal_filename : opt->CalInputFiles()) {
536 TChannel::ReadCalFile(cal_filename.c_str());
537 }
538 for(const auto& val_filename : opt->ValInputFiles()) {
539 GValue::ReadValFile(val_filename.c_str());
540 }
541 for(const auto& info_filename : opt->ExternalRunInfo()) {
542 TRunInfo::ReadInfoFile(info_filename.c_str());
543 }
544 return;
545 }
546 // Set the width of the status and each column
549
550 // Different queues that can show up
551 std::vector<std::shared_ptr<ThreadsafeQueue<std::shared_ptr<const TFragment>>>> fragmentQueues;
552 std::vector<std::shared_ptr<ThreadsafeQueue<std::shared_ptr<TEpicsFrag>>>> scalerQueues;
553 std::vector<std::shared_ptr<ThreadsafeQueue<std::shared_ptr<TUnpackedEvent>>>> analysisQueues;
554
555 // The different loops that can run
556 TDataLoop* dataLoop = nullptr;
557 TUnpackingLoop* unpackLoop = nullptr;
558 TFragmentChainLoop* fragmentChainLoop = nullptr;
559 TEventBuildingLoop* eventBuildingLoop = nullptr;
560 TDetBuildingLoop* detBuildingLoop = nullptr;
561
562 // If needed, read from the raw file
563 if(readFromRaw) {
564 if(fRawFiles.size() > 1) {
565 std::cerr << "I'm going to ignore all but first .mid" << std::endl;
566 }
567
568 dataLoop = TDataLoop::Get("1_input_loop", fRawFiles[0]);
569 dataLoop->SetSelfStopping(selfStopping);
570
571 unpackLoop = TUnpackingLoop::Get("2_unpack_loop");
572 unpackLoop->InputQueue() = dataLoop->OutputQueue();
573 }
574
575 // If needed, read from the fragment tree
576 if(readFromFragmentTree) {
577 fragmentChainLoop = TFragmentChainLoop::Get("1_chain_loop", gFragment);
578 fragmentChainLoop->SetSelfStopping(selfStopping);
579 }
580
581 // if I am passed any calibrations, lets load those, this
582 // will overwrite any with the same address previously read in.
583 for(const auto& cal_filename : opt->CalInputFiles()) {
584 TChannel::ReadCalFile(cal_filename.c_str());
585 }
586 // Set the run number and sub-run number
587 if(!fRawFiles.empty()) {
589 } else {
591 }
592
593 for(const auto& val_filename : opt->ValInputFiles()) {
594 GValue::ReadValFile(val_filename.c_str());
595 }
596 for(const auto& info_filename : opt->ExternalRunInfo()) {
597 TRunInfo::ReadInfoFile(info_filename.c_str());
598 }
599
601 if(TRunInfo::GetDetectorInformation() != nullptr) {
602 // call DetectorInformation::Set again, in case the calibration files we've loaded now changed things
604 event_build_mode = TRunInfo::GetDetectorInformation()->BuildMode();
605 } else {
606 std::cout << "no detector information, can't set build mode" << std::endl;
607 }
608
609 // If requested, write the fragment histograms
610 if(writeFragmentHistograms) {
611 TFragHistLoop* loop = TFragHistLoop::Get("3_frag_hist_loop");
612 loop->SetOutputFilename(outputFragmentHistFilename);
613 if(unpackLoop != nullptr) {
614 loop->InputQueue() = unpackLoop->AddGoodOutputQueue();
615 }
616 if(fragmentChainLoop != nullptr) {
617 loop->InputQueue() = fragmentChainLoop->AddOutputQueue();
618 }
619 fragmentQueues.push_back(loop->InputQueue());
620 }
621
622 // If requested, write the fragment tree
623 if(writeFragmentTree) {
624 TFragWriteLoop* loop = TFragWriteLoop::Get("4_frag_write_loop", outputFragmentTreeFilename);
625 fNewFragmentFile = outputFragmentTreeFilename;
626 if(unpackLoop != nullptr) {
627 loop->InputQueue() = unpackLoop->AddGoodOutputQueue(TGRSIOptions::Get()->FragmentWriteQueueSize());
628 loop->BadInputQueue() = unpackLoop->BadOutputQueue();
629 loop->ScalerInputQueue() = unpackLoop->ScalerOutputQueue();
630 scalerQueues.push_back(loop->ScalerInputQueue());
631 }
632 if(fragmentChainLoop != nullptr) {
633 loop->InputQueue() = fragmentChainLoop->AddOutputQueue();
634 }
635 fragmentQueues.push_back(loop->InputQueue());
636 } else if(opt->CreateFragmentDiagnostics() && writeAnalysisTree) {
637 // we only have the diagnostics loop running if requested and we write an analysis tree as we write to the same output file
638 TFragDiagnosticsLoop* loop = TFragDiagnosticsLoop::Get("4_frag_diag_loop", outputDiagnosticsFilename);
639 if(unpackLoop != nullptr) {
640 loop->InputQueue() = unpackLoop->AddGoodOutputQueue(TGRSIOptions::Get()->FragmentWriteQueueSize());
641 }
642 if(fragmentChainLoop != nullptr) {
643 loop->InputQueue() = fragmentChainLoop->AddOutputQueue();
644 }
645 fragmentQueues.push_back(loop->InputQueue());
646 }
647
648 // If needed, generate the individual detectors from the TFragments
649 if(generateAnalysisData) {
651 eventBuildingLoop = TEventBuildingLoop::Get("5_event_build_loop", event_build_mode, TGRSIOptions::AnalysisOptions()->BuildWindow());
652 eventBuildingLoop->SetSortDepth(opt->SortDepth());
653 if(unpackLoop != nullptr) {
654 eventBuildingLoop->InputQueue() = unpackLoop->AddGoodOutputQueue();
655 }
656 if(fragmentChainLoop != nullptr) {
657 eventBuildingLoop->InputQueue() = fragmentChainLoop->AddOutputQueue();
658 }
659 fragmentQueues.push_back(eventBuildingLoop->InputQueue());
660
661 detBuildingLoop = TDetBuildingLoop::Get("6_det_build_loop");
662 detBuildingLoop->InputQueue() = eventBuildingLoop->OutputQueue();
663 }
664
665 // If requested, write the analysis histograms
666 if(writeAnalysisHistograms) {
667 TAnalysisHistLoop* loop = TAnalysisHistLoop::Get("7_analysis_hist_loop");
668 loop->SetOutputFilename(output_analysis_hist_filename);
669 if(detBuildingLoop != nullptr) { // TODO: This needs to be extended to being able to read from an analysis tree
670 loop->InputQueue() = detBuildingLoop->AddOutputQueue();
671 } else {
672 std::cerr << DRED << "Error, writing analysis histograms is enabled, but no detector building loop was found!"
673 << RESET_COLOR << std::endl;
674 exit(1);
675 }
676
677 analysisQueues.push_back(loop->InputQueue());
678 }
679
680 // If requested, write the analysis tree
681 if(writeAnalysisTree) {
682 auto* loop = TAnalysisWriteLoop::Get("8_analysis_write_loop", outputAnalysisTreeFilename);
683 loop->InputQueue() = detBuildingLoop->AddOutputQueue(TGRSIOptions::Get()->AnalysisWriteQueueSize());
684 if(TGRSIOptions::Get()->SeparateOutOfOrder()) {
685 loop->OutOfOrderQueue() = eventBuildingLoop->OutOfOrderQueue();
686 }
687 analysisQueues.push_back(loop->InputQueue());
688 }
689
691}
692
693void TGRSIint::RunMacroFile(const std::string& filename)
694{
695 /// Runs a macro file. This happens when a .C file is provided on the command line
696 if(FileExists(filename.c_str())) {
697 const char* command = Form(".x %s", filename.c_str());
698 ProcessLine(command);
699 } else {
700 // check if commandline arguments were supplied
701 size_t beginning_pos = filename.find_first_of('(');
702 if(beginning_pos != std::string::npos && filename.back() == ')') {
703 std::string trueFilename = filename.substr(0, beginning_pos);
704 std::string arguments = filename.substr(beginning_pos, std::string::npos);
705 if(FileExists(trueFilename.c_str())) {
706 const char* command = Form(".L %s", trueFilename.c_str());
707 ProcessLine(command);
708 command = Form("%s%s", trueFilename.substr(0, filename.find_first_of('.')).c_str(), arguments.c_str());
709 ProcessLine(command);
710 } else {
711 std::cerr << R"(File ")" << trueFilename << R"(" does not exist)" << std::endl;
712 }
713 } else {
714 std::cerr << R"(File ")" << filename << R"(" does not exist)" << std::endl;
715 }
716 }
717}
718
720{
721 /// Loads root graphics in unless -b is used for batch mode.
722 if(gROOT->IsBatch()) {
723 return;
724 }
725 // force Canvas to load, this ensures global GUI Factory ptr exists.
726 gROOT->LoadClass("TCanvas", "Gpad");
727 gGuiFactory = new GRootGuiFactory();
728}
729
730void TGRSIint::PrintHelp(bool print)
731{
732 /// Prints the help. Not sure this is used anymore.
733 if(print) {
734 std::cout << DRED << BG_WHITE << " Sending Help!! " << RESET_COLOR << std::endl;
735 new TGHtmlBrowser(gSystem->ExpandPathName("${GRSISYS}/README.html"));
736 }
737}
738
740{
741 /// When ctrl-c is pressed, this takes over. This can be used in the future
742 /// for safe cleanup.
744 std::cout << std::endl
745 << DRED << BG_WHITE << " Control-c was pressed in interactive mode. " << RESET_COLOR << std::endl;
746 exit(1);
747 }
748 static int timesPressed = 0;
749 timesPressed++;
750 switch(timesPressed) {
751 case 1:
752 std::cout << std::endl
753 << DRED << BG_WHITE << " Control-c was pressed, terminating input loop. " << RESET_COLOR << std::endl;
755 break;
756 case 2:
757 std::cout << std::endl
758 << DRED << BG_WHITE << " Control-c was pressed, stopping all queues. " << RESET_COLOR << std::endl;
760 break;
761 default:
762 std::cout << std::endl
763 << DRED << BG_WHITE << " No you shutup! " << RESET_COLOR << std::endl;
764 exit(1);
765 }
766 return true;
767}
768
769// These variables are to be accessed only from DelayedProcessLine
770// and DelayedProcessLine_Action, nowhere else.
771// These are used to pass information between the two functions.
772// DelayedProcessLine_Action() should ONLY be called from a TTimer running
773// on the main thread. DelayedProcessLine may ONLY be called
774// from inside ProcessLine().
775namespace {
779std::condition_variable g__NewResult;
780
783
786} // namespace
787
788Long_t TGRSIint::DelayedProcessLine(std::string command)
789{
790 std::lock_guard<std::mutex> any_command_lock(g__CommandWaitingMutex);
791
792 g__LineToProcess = std::move(command);
793 g__CommandFinished = false;
794 g__ProcessingNeeded = true;
795 TTimer::SingleShot(0, "TGRSIint", this, "DelayedProcessLine_Action()");
796
797 std::unique_lock<std::mutex> lock(g__ResultListMutex);
798 while(!g__CommandFinished) {
799 g__NewResult.wait(lock);
800 }
801
802 return g__CommandResult;
803}
804
806{
807 std::string message;
808 {
809 std::lock_guard<std::mutex> lock(g__CommandListMutex);
810 if(!g__ProcessingNeeded) {
811 return;
812 }
813 message = g__LineToProcess;
814 }
815
816 Long_t result = ProcessLine(message.c_str());
817 Getlinem(EGetLineMode::kInit, (static_cast<TRint*>(gApplication))->GetPrompt());
818
819 {
820 std::lock_guard<std::mutex> lock(g__ResultListMutex);
821 g__CommandResult = result;
822 g__CommandFinished = true;
823 g__ProcessingNeeded = false;
824 }
825
826 g__NewResult.notify_one();
827}
void AddFileToGUI(TFile *file)
void StartGUI()
#define BG_WHITE
Definition Globals.h:24
#define DRED
Definition Globals.h:18
#define BLUE
Definition Globals.h:6
#define RESET_COLOR
Definition Globals.h:5
const std::string & ProgramName()
int GetRunNumber(const std::string &)
bool FileExists(const char *filename)
bool AllFilesExist(const std::vector< std::string > &filenames)
int GetSubRunNumber(const std::string &)
void ReadTheNews()
Definition TGRSIint.cxx:272
static int ReadValFile(const char *filename="", Option_t *opt="replace")
Definition GValue.cxx:194
static void StopAll()
static void ClearAllQueues()
static std::string AllThreadStatus()
static size_t StatusWidth()
static std::string AllThreadProgress()
static std::string AllThreadHeader()
static bool AnyThreadRunning()
static void SendStop()
static void ResumeAll()
static size_t ColumnWidth()
void SetOutputFilename(const std::string &name)
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< TUnpackedEvent > > > & InputQueue()
static TAnalysisHistLoop * Get(std::string name="")
void Print(Option_t *opt="") const override
static TAnalysisWriteLoop * Get(std::string name="", std::string outputFilename="")
static void DeleteAllChannels()
Definition TChannel.cxx:282
static Int_t ReadCalFile(std::ifstream &infile)
static TDataLoop * Get(std::string name="", TRawFile *source=nullptr)
Definition TDataLoop.cxx:16
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< TRawEvent > > > & OutputQueue()
Definition TDataLoop.h:37
void SetSelfStopping(bool self_stopping)
Definition TDataLoop.h:60
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< TUnpackedEvent > > > & AddOutputQueue(size_t maxSize=50000)
std::shared_ptr< ThreadsafeQueue< std::vector< std::shared_ptr< const TFragment > > > > & InputQueue()
static TDetBuildingLoop * Get(std::string name="")
virtual TEventBuildingLoop::EBuildMode BuildMode() const
Set the detector information based on the available TChannels.
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & OutOfOrderQueue()
std::shared_ptr< ThreadsafeQueue< std::vector< std::shared_ptr< const TFragment > > > > & OutputQueue()
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & InputQueue()
static TEventBuildingLoop * Get(std::string name="", EBuildMode mode=EBuildMode::kTimestamp, uint64_t buildWindow=2000)
void SetSortDepth(unsigned int val)
static TFragDiagnosticsLoop * Get(std::string name="", std::string fOutputFilename="")
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & InputQueue()
static TFragHistLoop * Get(std::string name="")
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & InputQueue()
void SetOutputFilename(const std::string &name)
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TBadFragment > > > & BadInputQueue()
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & InputQueue()
static TFragWriteLoop * Get(std::string name="", std::string fOutputFilename="")
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< TEpicsFrag > > > & ScalerInputQueue()
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & AddOutputQueue()
void SetSelfStopping(bool self_stopping)
static TFragmentChainLoop * Get(std::string name="", TChain *chain=nullptr)
bool Notify() override
Definition TGRSIint.cxx:739
const std::vector< std::string > & RootInputFiles() const
bool MakeAnalysisTree() const
bool SortRaw() const
static TGRSIOptions * Get(int argc=0, char **argv=nullptr)
Do not use!
bool WriteFragmentTree() const
const std::vector< std::string > & InputFiles() const
const std::string & OutputFragmentHistogramFile() const
const std::vector< std::string > & ExternalRunInfo() const
bool CreateFragmentDiagnostics() const
std::string AnalysisHistogramLib() const
const std::string & OutputAnalysisHistogramFile() const
static TAnalysisOptions * AnalysisOptions()
const std::vector< std::string > & ValInputFiles() const
bool StartGui() const
int SortDepth() const
bool Batch() const
bool CloseAfterSort() const
bool MakeHistos() const
bool UseRnTuple() const
bool ShouldExit() const
const std::vector< std::string > & CalInputFiles() const
const std::string & OutputDiagnosticsFile() const
bool ReadingMaterial() const
void ParserLibrary(std::string &library)
const std::vector< std::string > & MacroInputFiles() const
std::string FragmentHistogramLib() const
const std::string & OutputFragmentFile() const
const std::string & OutputAnalysisFile() const
void SetupPipeline()
Definition TGRSIint.cxx:407
TRawFile * OpenRawFile(const std::string &filename)
Definition TGRSIint.cxx:379
int TabCompletionHook(char *, int *, std::ostream &) override
Definition TGRSIint.cxx:236
static void PrintHelp(bool)
Definition TGRSIint.cxx:730
int fRawFilesOpened
Number of Raw Files opened.
Definition TGRSIint.h:91
Long_t DelayedProcessLine(std::string command)
Definition TGRSIint.cxx:788
std::thread::id main_thread_id
Main sorting thread id.
Definition TGRSIint.h:85
TGRSIint(int argc, char **argv, void *options=nullptr, int numOptions=0, bool noLogo=false, const char *appClassName="grsisort")
Definition TGRSIint.cxx:62
static TGRSIint * fTGRSIint
Static pointer (singleton)
Definition TGRSIint.h:47
TFile * OpenRootFile(const std::string &filename, Option_t *opt="read")
Definition TGRSIint.cxx:307
std::vector< TRawFile * > fRawFiles
List of Raw files opened.
Definition TGRSIint.h:94
static void LoadGROOTGraphics()
Definition TGRSIint.cxx:719
void DelayedProcessLine_Action()
Definition TGRSIint.cxx:805
std::string fNewFragmentFile
New fragment file name.
Definition TGRSIint.h:92
void RunMacroFile(const std::string &filename)
Definition TGRSIint.cxx:693
bool fAllowedToTerminate
Flag for shutting down GRSISort.
Definition TGRSIint.h:89
static TGRSIint * instance(int argc=0, char **argv=nullptr, void *options=nullptr, int numOptions=-1, bool noLogo=false, const char *appClassName="grsisort")
Definition TGRSIint.cxx:52
bool fIsTabComplete
Flag for tab completion hook.
Definition TGRSIint.h:88
int fRootFilesOpened
Number of ROOT files opened.
Definition TGRSIint.h:90
void LoopUntilDone()
Definition TGRSIint.cxx:163
static TEnv * fGRSIEnv
GRSI environment.
Definition TGRSIint.h:44
void PrintLogo(bool) override
Definition TGRSIint.cxx:282
Long_t ProcessLine(const char *line, Bool_t sync=kFALSE, Int_t *error=nullptr) override
Definition TGRSIint.cxx:245
void Terminate(Int_t status=0) override
Definition TGRSIint.cxx:192
void ApplyOptions()
Definition TGRSIint.cxx:89
bool HandleTermInput() override
Definition TGRSIint.cxx:186
void Load(bool quiet=false)
if necessary loads shared object library and sets/initializes all other functions
void DestroyRawFile(TRawFile *file)
TRawFile * CreateRawFile(const std::string &file)
Reader for raw files.
Definition TRawFile.h:31
static void ClearVersion()
Definition TRunInfo.h:142
static void SetDate(const char *ver)
Definition TRunInfo.h:167
static void SetFullVersion(const char *ver)
Definition TRunInfo.h:155
static Bool_t ReadInfoFile(const char *filename="")
Definition TRunInfo.cxx:174
static void ClearFullVersion()
Definition TRunInfo.h:154
static void ClearDate()
Definition TRunInfo.h:166
static void SetRunInfo(int runnum=0, int subrunnum=-1)
Definition TRunInfo.cxx:135
static void SetVersion(const char *ver)
Definition TRunInfo.h:143
static Bool_t ReadInfoFromFile(TFile *tempf=nullptr)
Definition TRunInfo.cxx:15
static TDetectorInformation * GetDetectorInformation()
Definition TRunInfo.h:286
static TParserLibrary * Get(bool verbose=false)
Definition TSingleton.h:33
void Print(Option_t *opt="") const override
static TUnpackingLoop * Get(std::string name="")
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TFragment > > > & AddGoodOutputQueue(size_t maxSize=50000)
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< TRawEvent > > > & InputQueue()
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< TEpicsFrag > > > & ScalerOutputQueue()
std::shared_ptr< ThreadsafeQueue< std::shared_ptr< const TBadFragment > > > & BadOutputQueue()
TChain * gAnalysis
Definition TGRSIint.cxx:50
TChain * gFragment
Definition TGRSIint.cxx:49
std::condition_variable g__NewResult
Definition TGRSIint.cxx:779