GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TMidasFile.cxx
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <cstdio>
4#include <cstring>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <cerrno>
9#include <cassert>
10#include <cstdlib>
11
12#ifdef HAVE_ZLIB
13#include <zlib.h>
14#endif
15
16#include "TString.h"
17
18#include "TMidasFile.h"
19#include "TMidasEvent.h"
20#include "TRunInfo.h"
22#include "TGRSIMnemonic.h"
23#include "GRSIDataVersion.h"
24
26#ifdef HAS_XML
27 : fOdb(nullptr)
28#endif
29{
30 // Default Constructor
31 uint32_t endian = 0x12345678;
32 fDoByteSwap = *reinterpret_cast<char*>(&endian) != 0x78;
33}
34
35TMidasFile::TMidasFile(const char* filename, TRawFile::EOpenType open_type) : TMidasFile()
36{
37 bool status = false;
38 switch(open_type) {
39 case TRawFile::EOpenType::kRead: status = Open(filename); break;
40 case TRawFile::EOpenType::kWrite: status = OutOpen(filename); break;
41 }
42 if(!status) {
43 std::stringstream str;
44 str << RED << "Failed to create midas file \"" << filename << "\": " << fLastError << RESET_COLOR << std::endl;
45 throw std::runtime_error(str.str());
46 }
47}
48
50{
51 // Default dtor. It closes the read in midas file as well as the output midas file.
52 Close();
53 OutClose();
54}
55
56std::string TMidasFile::Status(bool)
57{
58 std::stringstream str;
59 str << HIDE_CURSOR << " Processing event " << fCurrentEventNumber << " have processed " << std::setprecision(2) << static_cast<double>(BytesRead()) / 1000000. << "MB/" << static_cast<double>(FileSize()) / 1000000. << " MB " << SHOW_CURSOR << "\r";
60 return str.str();
61}
62
63static int hasSuffix(const char* name, const char* suffix)
64{
65 // Checks to see if midas file has suffix.
66 const char* s = strstr(name, suffix);
67 if(s == nullptr) {
68 return 0;
69 }
70
71 return static_cast<int>((s - name) + strlen(suffix) == strlen(name));
72}
73
74/// Open a midas .mid file with given file name.
75///
76/// Remote files can be accessed using these special file names:
77/// - pipein://command - read data produced by given command, see examples below
78/// - ssh://username\@hostname/path/file.mid - read remote file through an ssh pipe
79/// - ssh://username\@hostname/path/file.mid.gz and file.mid.bz2 - same for compressed files
80/// - dccp://path/file.mid (also file.mid.gz and file.mid.bz2) - read data from dcache, requires dccp in the PATH
81///
82/// Examples:
83/// - ./event_dump.exe /ladd/data9/t2km11/data/run02696.mid.gz - read normal compressed file
84/// - ./event_dump.exe ssh://ladd09//ladd/data9/t2km11/data/run02696.mid.gz - read compressed file through ssh to ladd09
85/// (note double "/")
86/// - ./event_dump.exe pipein://"cat /ladd/data9/t2km11/data/run02696.mid.gz | gzip -dc" - read data piped from a
87/// command or script (note quotes)
88/// - ./event_dump.exe pipein://"gzip -dc /ladd/data9/t2km11/data/run02696.mid.gz" - another way to read compressed
89/// files
90/// - ./event_dump.exe dccp:///pnfs/triumf.ca/data/t2km11/aug2008/run02837.mid.gz - read file directly from a dcache
91/// pool (note triple "/")
92///
93/// \param[in] filename The file to open.
94/// \returns "true" for succes, "false" for error, use GetLastError() to see why
95bool TMidasFile::Open(const char* filename)
96{
97 if(fFile > 0) {
98 Close();
99 }
100
101 Filename(filename);
102
103 std::string pipe;
104
105 std::ifstream in(GetFilename(), std::ifstream::in | std::ifstream::binary);
106 in.seekg(0, std::ifstream::end);
107 FileSize(in.tellg());
108 in.close();
109
110 // Do we need these?
111 // signal(SIGPIPE,SIG_IGN); // crash if reading from closed pipe
112 // signal(SIGXFSZ,SIG_IGN); // crash if reading from file >2GB without O_LARGEFILE
113
114 if(strncmp(filename, "ssh://", 6) == 0) {
115 const char* name = filename + 6;
116 const char* s = strstr(name, "/");
117
118 if(s == nullptr) {
119 fLastErrno = -1;
120 fLastError.assign("TMidasFile::Open: Invalid ssh:// URI. Should be: ssh://user@host/file/path/...");
121 return false;
122 }
123
124 const char* remoteFile = s + 1;
125
126 std::string remoteHost;
127 for(s = name; *s != '/'; s++) {
128 remoteHost += *s;
129 }
130
131 pipe = "ssh -e none -T -x -n ";
132 pipe += remoteHost;
133 pipe += " dd if=";
134 pipe += remoteFile;
135 pipe += " bs=1024k";
136
137 if(hasSuffix(remoteFile, ".gz") != 0) {
138 pipe += " | gzip -dc";
139 } else if(hasSuffix(remoteFile, ".bz2") != 0) {
140 pipe += " | bzip2 -dc";
141 }
142 } else if(strncmp(filename, "dccp://", 7) == 0) {
143 const char* name = filename + 7;
144
145 pipe = "dccp ";
146 pipe += name;
147 pipe += " /dev/fd/1";
148
149 if(hasSuffix(filename, ".gz") != 0) {
150 pipe += " | gzip -dc";
151 } else if(hasSuffix(filename, ".bz2") != 0) {
152 pipe += " | bzip2 -dc";
153 }
154 } else if(strncmp(filename, "pipein://", 9) == 0) {
155 pipe = filename + 9;
156#if 0 // read compressed files using the zlib library
157 } else if(hasSuffix(filename, ".gz")) {
158 pipe = "gzip -dc ";
159 pipe += filename;
160#endif
161 } else if(hasSuffix(filename, ".bz2") != 0) {
162 pipe = "bzip2 -dc ";
163 pipe += filename;
164 }
165 // Note: We cannot use "cat" in a similar way to offload, and must open it directly.
166 // "cat" ends immediately on end-of-file, making live histograms impossible.
167 // "tail -fn +1" has the opposite problem, and will never end, stalling in read().
168
169 if(pipe.length() > 0) {
170 fprintf(stderr, "TMidasFile::Open: Reading from pipe: %s\n", pipe.c_str());
171 fPoFile = popen(pipe.c_str(), "r");
172
173 if(fPoFile == nullptr) {
174 fLastErrno = errno;
175 fLastError.assign(std::strerror(errno));
176 return false;
177 }
178
179 fFile = fileno(reinterpret_cast<FILE*>(fPoFile));
180 } else {
181#ifndef O_LARGEFILE
182#define O_LARGEFILE 0
183#endif
184
185 fFile = open(filename, O_RDONLY | O_LARGEFILE);
186
187 if(fFile <= 0) {
188 fLastErrno = errno;
189 fLastError.assign(std::strerror(errno));
190 return false;
191 }
192
193 if(hasSuffix(filename, ".gz") != 0) {
194// this is a compressed file
195#ifdef HAVE_ZLIB
196 fGzFile = new gzFile;
197 (*(gzFile*)fGzFile) = gzdopen(fFile, "rb");
198 if((*(gzFile*)fGzFile) == nullptr) {
199 fLastErrno = -1;
200 fLastError.assign("zlib gzdopen() error");
201 return false;
202 }
203#else
204 fLastErrno = -1;
205 fLastError.assign("Do not know how to read compressed MIDAS files");
206 return false;
207#endif
208 }
209 }
210
211 // setup TChannel to use our mnemonics
212 TChannel::SetMnemonicClass(TGRSIMnemonic::Class());
213
214 // read ODB from file
215 if(fOdbEvent == nullptr) { fOdbEvent = std::make_shared<TMidasEvent>(); }
217
218 SetFileOdb();
221 TRunInfo::SetLibraryVersion(GRSIDATA_RELEASE);
222
223 auto* detInfo = new TGRSIDetectorInformation();
225
226 return true;
227}
228
229bool TMidasFile::OutOpen(const char* filename)
230{
231 /// Open a midas .mid file for OUTPUT with given file name.
232 ///
233 /// Remote files not yet implemented
234 ///
235 /// \param [in] filename The file to open.
236 /// \returns "true" for succes, "false" for error, use GetLastError() to see why
237
238 if(fOutFile > 0) {
239 OutClose();
240 }
241
242 fOutFilename = filename;
243
244 std::cout << "Attempting normal open of file " << filename << std::endl;
245 // fOutFile = open(filename, O_CREAT | O_WRONLY | O_LARGEFILE , S_IRUSR| S_IWUSR | S_IRGRP | S_IROTH );
246 // fOutFile = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
247 fOutFile = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0644);
248
249 if(fOutFile <= 0) {
250 fLastErrno = errno;
251 fLastError.assign(std::strerror(errno));
252 return false;
253 }
254
255 std::cout << "Opened output file " << filename << "; return fOutFile is " << fOutFile << std::endl;
256
257 if(hasSuffix(filename, ".gz") != 0) {
258 // this is a compressed file
259#ifdef HAVE_ZLIB
260 fOutGzFile = new gzFile;
261 *(gzFile*)fOutGzFile = gzdopen(fOutFile, "wb");
262 if((*(gzFile*)fOutGzFile) == nullptr) {
263 fLastErrno = -1;
264 fLastError.assign("zlib gzdopen() error");
265 return false;
266 }
267 std::cout << "Opened gz file successfully" << std::endl;
268 if(true) {
269 if(gzsetparams(*(gzFile*)fOutGzFile, 1, Z_DEFAULT_STRATEGY) != Z_OK) {
270 std::cout << "Cannot set gzparams" << std::endl;
271 fLastErrno = -1;
272 fLastError.assign("zlib gzsetparams() error");
273 return false;
274 }
275 std::cout << "setparams for gz file successfully" << std::endl;
276 }
277#else
278 fLastErrno = -1;
279 fLastError.assign("Do not know how to write compressed MIDAS files");
280 return false;
281#endif
282 }
283 return true;
284}
285
286static int readpipe(int fd, char* buf, int length)
287{
288 int count = 0;
289 while(length > 0) {
290 int rd = read(fd, buf, length);
291 if(rd > 0) {
292 buf += rd;
293 length -= rd;
294 count += rd;
295 } else if(rd == 0) {
296 return count;
297 } else {
298 return -1;
299 }
300 }
301 return count;
302}
303
304/// \param [in] event shared Pointer to an empty TMidasEvent
305/// \returns "true" for success, "false" for failure, see GetLastError() to see why
306///
307/// EDITED FROM THE ORIGINAL TO RETURN TOTAL SUCESSFULLY BYTES READ INSTEAD OF TRUE/FALSE, PCB
308///
309int TMidasFile::Read(std::shared_ptr<TRawEvent> event)
310{
311 if(event == nullptr) {
312 return -1;
313 }
314 std::shared_ptr<TMidasEvent> midasEvent = std::static_pointer_cast<TMidasEvent>(event);
315 if(BufferSize() < sizeof(TMidas_EVENT_HEADER)) {
317 }
318
319 if(BufferSize() < sizeof(TMidas_EVENT_HEADER)) {
320 return 0;
321 }
322
323 midasEvent->Clear();
324 memcpy(reinterpret_cast<char*>(midasEvent->GetEventHeader()), BufferData(), sizeof(TMidas_EVENT_HEADER));
325 if(fDoByteSwap) {
326 std::cout << "Swapping bytes" << std::endl;
327 midasEvent->SwapBytesEventHeader();
328 }
329 if(!midasEvent->IsGoodSize()) {
330 fLastErrno = -1;
331 fLastError.assign("Invalid event size");
332 return 0;
333 }
334
335 size_t event_size = midasEvent->GetDataSize();
336 size_t total_size = sizeof(TMidas_EVENT_HEADER) + event_size;
337
338 if(BufferSize() < total_size) {
339 ReadMoreBytes(total_size - BufferSize());
340 }
341
342 if(BufferSize() < total_size) {
343 return 0;
344 }
345
346 memcpy(midasEvent->GetData(), BufferData() + sizeof(TMidas_EVENT_HEADER), event_size);
347 midasEvent->SwapBytes(false);
348
349 size_t bytesRead = BufferSize();
350 IncrementBytesRead(bytesRead);
352 ClearBuffer();
353
354 return bytesRead;
355}
356
357void TMidasFile::Skip(size_t nofEvents)
358{
359 TMidasEvent ev;
360 for(size_t i = 0; i < nofEvents; ++i) {
361 // if we don't have enough data left for a header, we try and read more
362 if(BufferSize() < sizeof(TMidas_EVENT_HEADER)) {
364 }
365
366 // if we don't have enough data to read the header we are done
367 if(BufferSize() < sizeof(TMidas_EVENT_HEADER)) {
368 return;
369 }
370
371 ev.Clear();
372 // copy the header
373 memcpy(reinterpret_cast<char*>(ev.GetEventHeader()), BufferData(), sizeof(TMidas_EVENT_HEADER));
374 if(fDoByteSwap) {
375 std::cout << "Swapping bytes" << std::endl;
377 }
378 if(!ev.IsGoodSize()) {
379 fLastErrno = -1;
380 fLastError.assign("Invalid event size");
381 return;
382 }
383
384 // check if this event is the end-of-run event
385 if((ev.GetEventHeader()->fEventId & 0xffff) == 0x8001) {
386 // we simply return here so that the next event read is the end-of-run event
387 return;
388 }
389
390 size_t event_size = ev.GetDataSize();
391 size_t total_size = sizeof(TMidas_EVENT_HEADER) + event_size;
392
393 // try and read the total event if we don't already have it in the buffer
394 if(BufferSize() < total_size) {
395 ReadMoreBytes(total_size - BufferSize());
396 }
397
398 // if we don't have enough data to read the whole event we are done
399 if(BufferSize() < total_size) {
400 return;
401 }
402
403 //increment our counters and clear the buffer
404 size_t bytesRead = BufferSize();
405 IncrementBytesRead(bytesRead);
407 ClearBuffer();
408 }
409}
410
412{
413 size_t initial_size = BufferSize();
414 ResizeBuffer(initial_size + bytes);
415 size_t rd = 0;
416 if(fGzFile != nullptr) {
417#ifdef HAVE_ZLIB
418 rd = gzread(*(gzFile*)fGzFile, BufferData() + initial_size, bytes);
419#else
420 assert(!"Cannot get here");
421#endif
422 } else {
423 rd = readpipe(fFile, BufferData() + initial_size, bytes);
424 }
425
426 ResizeBuffer(initial_size + rd);
427
428 if(rd == 0) {
429 fLastErrno = 0;
430 fLastError.assign("EOF");
431 } else if(rd != bytes) {
432 fLastErrno = errno;
433 fLastError.assign(std::strerror(errno));
434 }
435}
436
437void TMidasFile::FillBuffer(const std::shared_ptr<TMidasEvent>& midasEvent, Option_t*)
438{
439 // Fills a buffer to be written to a midas file.
440
441 // Not the prettiest way to do this but it works.
442 // It seems to be filling in the wrong order of bits, but this does it correctly
443 // There is a byte swap happening at some point in this process. Might have to put something
444 // in here that protects against "Endian-ness"
445 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetEventId() & 0xFF));
446 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetEventId() >> 8));
447
448 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetTriggerMask() & 0xFF));
449 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetTriggerMask() >> 8));
450
451 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetSerialNumber() & 0xFF));
452 fWriteBuffer.push_back(static_cast<char>((midasEvent->GetSerialNumber() >> 8) & 0xFF));
453 fWriteBuffer.push_back(static_cast<char>((midasEvent->GetSerialNumber() >> 16) & 0xFF));
454 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetSerialNumber() >> 24));
455
456 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetTimeStamp() & 0xFF));
457 fWriteBuffer.push_back(static_cast<char>((midasEvent->GetTimeStamp() >> 8) & 0xFF));
458 fWriteBuffer.push_back(static_cast<char>((midasEvent->GetTimeStamp() >> 16) & 0xFF));
459 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetTimeStamp() >> 24));
460
461 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetDataSize() & 0xFF));
462 fWriteBuffer.push_back(static_cast<char>((midasEvent->GetDataSize() >> 8) & 0xFF));
463 fWriteBuffer.push_back(static_cast<char>((midasEvent->GetDataSize() >> 16) & 0xFF));
464 fWriteBuffer.push_back(static_cast<char>(midasEvent->GetDataSize() >> 24));
465
466 for(size_t i = 0; i < midasEvent->GetDataSize(); i++) {
467 fWriteBuffer.push_back(midasEvent->GetData()[i]);
468 }
469
470 fCurrentBufferSize += midasEvent->GetDataSize() + sizeof(TMidas_EVENT_HEADER);
471
472 if(fWriteBuffer.size() > fMaxBufferSize) {
473 WriteBuffer();
474 }
475}
476
478{
479 // Writes a buffer of TMidasEvents to the output file.
480 int wr = -2;
481
482 if(fOutGzFile != nullptr) {
483#ifdef HAVE_ZLIB
484 wr = gzwrite(*(gzFile*)fOutGzFile, fWriteBuffer.data(), fCurrentBufferSize);
485#else
486 assert(!"Cannot get here");
487#endif
488 } else {
489 wr = write(fOutFile, fWriteBuffer.data(), fCurrentBufferSize);
490 }
492 fWriteBuffer.clear();
493
494 return wr != 0;
495}
496
497bool TMidasFile::Write(const std::shared_ptr<TMidasEvent>& midasEvent, Option_t* opt)
498{
499 // Writes an individual TMidasEvent to the output TMidasFile. This will
500 // write to a zipped file if the output file is defined as a zipped file.
501 int wr = -2;
502
503 if(fOutGzFile != nullptr) {
504#ifdef HAVE_ZLIB
505 wr = gzwrite(*(gzFile*)fOutGzFile, (char*)midasEvent->GetEventHeader(), sizeof(TMidas_EVENT_HEADER));
506#else
507 assert(!"Cannot get here");
508#endif
509 } else {
510 wr = write(fOutFile, reinterpret_cast<char*>(midasEvent->GetEventHeader()), sizeof(TMidas_EVENT_HEADER));
511 }
512
513 if(wr != sizeof(TMidas_EVENT_HEADER)) {
514 std::cout << "TMidasFile: error on write event header, return " << wr << ", size requested " << sizeof(TMidas_EVENT_HEADER) << std::endl;
515 return false;
516 }
517
518 if(strncmp(opt, "q", 1) != 0) {
519 std::cout << "Written event header to outfile , return is " << wr << std::endl;
520 }
521
522 if(fOutGzFile != nullptr) {
523#ifdef HAVE_ZLIB
524 wr = gzwrite(*(gzFile*)fOutGzFile, (char*)midasEvent->GetData(), midasEvent->GetDataSize());
525#else
526 assert(!"Cannot get here");
527#endif
528 } else {
529 wr = write(fOutFile, midasEvent->GetData(), midasEvent->GetDataSize());
530 }
531
532 if(strncmp(opt, "q", 1) != 0) {
533 std::cout << "Written event to outfile , return is " << wr << std::endl;
534 }
535
536 return wr != 0;
537}
538
540{
541 // Sets the maximum buffer size for the TMidasEvents to be written to
542 // an output TMidasFile.
543 fMaxBufferSize = maxsize;
544}
545
547{
548 // Closes the input midas file. Use OutClose() to close the output
549 // Midas File.
550 if(fPoFile != nullptr) {
551 pclose(reinterpret_cast<FILE*>(fPoFile));
552 }
553 fPoFile = nullptr;
554#ifdef HAVE_ZLIB
555 if(fGzFile) gzclose(*(gzFile*)fGzFile);
556 fGzFile = nullptr;
557#endif
558 if(fFile > 0) {
559 close(fFile);
560 }
561
562 fFile = -1;
563 Filename("");
564}
565
567{
568 // Closes the output midas file. Use Close() to close the read-in midas file
569
570 if(static_cast<unsigned int>(!fWriteBuffer.empty()) != 0u) {
571 WriteBuffer();
572 }
573#ifdef HAVE_ZLIB
574 if(fOutGzFile) {
575 gzflush(*(gzFile*)fOutGzFile, Z_FULL_FLUSH);
576 gzclose(*(gzFile*)fOutGzFile);
577 }
578 fOutGzFile = nullptr;
579#endif
580 if(fOutFile > 0) {
581 close(fOutFile);
582 }
583 fOutFile = -1;
584 fOutFilename = "";
585}
586
588{
589 // Parse the run number from the current TMidasFile. This assumes a format of
590 // run#####_###.mid or run#####.mid.
591 if(Filename().length() == 0) {
592 return 0;
593 }
594 std::size_t foundslash = Filename().rfind('/');
595 std::size_t found = Filename().rfind(".mid");
596 if(found == std::string::npos) {
597 return 0;
598 }
599 std::size_t found2 = Filename().rfind('-');
600 if((found2 < foundslash && foundslash != std::string::npos) || found2 == std::string::npos) {
601 found2 = Filename().rfind('_');
602 }
603 if(found2 < foundslash && foundslash != std::string::npos) {
604 found2 = std::string::npos;
605 }
606 std::string temp;
607 if(found2 == std::string::npos || Filename().compare(found2 + 4, 4, ".mid") != 0) {
608 temp = Filename().substr(found - 5, 5);
609 } else {
610 temp = Filename().substr(found - 9, 5);
611 }
612 return atoi(temp.c_str());
613}
614
616{
617 // Parse the sub run number from the current TMidasFile. This assumes a format of
618 // run#####_###.mid or run#####.mid.
619 if(Filename().empty()) {
620 return -1;
621 }
622 std::size_t foundslash = Filename().rfind('/');
623 std::size_t found = Filename().rfind('-');
624 if((found < foundslash && foundslash != std::string::npos) || found == std::string::npos) {
625 found = Filename().rfind('_');
626 }
627 if(found < foundslash && foundslash != std::string::npos) {
628 found = std::string::npos;
629 }
630 if(found != std::string::npos) {
631 std::string temp = Filename().substr(found + 1, 3);
632 return atoi(temp.c_str());
633 }
634 return -1;
635}
636
638{
639#ifdef HAS_XML
640 // check if we have already set the TChannels....
641 //
642 delete fOdb;
643 fOdb = nullptr;
644
645 if(TGRSIOptions::Get()->IgnoreFileOdb()) {
646 std::cout << DYELLOW << "\tskipping odb information stored in file." << RESET_COLOR << std::endl;
647 return;
648 }
649
650 try {
651 fOdb = new TXMLOdb(fOdbEvent->GetData(), fOdbEvent->GetDataSize());
652 } catch(std::exception& e) {
653 std::cout << "Got exception '" << e.what() << "' trying to read " << fOdbEvent->GetDataSize() << " bytes (or words?) from:" << std::endl;
654 std::cout << fOdbEvent->GetData() << std::endl;
655 throw e;
656 }
658
659 SetRunInfo(fOdbEvent->GetTimeStamp());
660
661 // Check for EPICS variables
662 SetEPICSOdb();
663
664 if(TGRSIOptions::Get()->IgnoreOdbChannels()) {
665 std::cout << DYELLOW << "\tskipping odb channel information stored in file." << RESET_COLOR << std::endl;
666 return;
667 }
668
669 // Check to see if we are running a GRIFFIN or TIGRESS experiment
670 TXMLNode* node = fOdb->FindPath("/Experiment");
671 if(!node->HasChildren()) {
672 return;
673 }
674 node = node->GetChildren();
675 std::string expt;
676 while(true) {
677 std::string key = fOdb->GetNodeName(node);
678 if(key == "Name") {
679 expt = node->GetText();
680 break;
681 }
682 if(!node->HasNextNode()) {
683 break;
684 }
685 node = node->GetNextNode();
686 }
687 if(expt == "tigress") {
688 SetTIGOdb();
689 } else if(expt.find("grif") != std::string::npos) {
690 // for GRIFFIN the experiment name might be griffin, grifstor, grifalt, etc.
691 SetGRIFFOdb();
692 } else if(expt == "tigdaq") { //New TIGRESS DAQ
693 SetTIGDAQOdb();
694 } else {
695 std::cerr << RED << "Unknown experiment name \"" << expt << "\", ODB won't be read!" << RESET_COLOR << std::endl;
696 }
697#endif
698}
699
700void TMidasFile::SetRunInfo(uint32_t time)
701{
702#ifdef HAS_XML
703 TXMLNode* node = fOdb->FindPath("/Runinfo/Start time binary");
704 if(node != nullptr) {
705 std::stringstream str(node->GetText());
706 unsigned int odbTime = 0;
707 str >> odbTime;
708 if(TRunInfo::SubRunNumber() == 0 && time != odbTime) {
709 std::cout << "Warning, ODB start time of first subrun (" << odbTime << ") does not match midas time of first event in this subrun (" << time << ")!" << std::endl;
710 }
712 }
713
714 node = fOdb->FindPath("/Experiment/Run parameters/Run Title");
715 if(node != nullptr) {
716 TRunInfo::SetRunTitle(node->GetText());
717 std::cout << "Title: " << DBLUE << node->GetText() << RESET_COLOR << std::endl;
718 }
719
720 if(node != nullptr) {
721 node = fOdb->FindPath("/Experiment/Run parameters/Comment");
722 TRunInfo::SetRunComment(node->GetText());
723 std::cout << "Comment: " << DBLUE << node->GetText() << RESET_COLOR << std::endl;
724 }
725#endif
726}
727
729{
730#ifdef HAS_XML
731 TXMLNode* node = fOdb->FindPath("/Equipment/Epics/Settings/Names");
732 std::vector<std::string> names = fOdb->ReadStringArray(node);
734#endif
735}
736
738{
739#ifdef HAS_XML
740 // get calibrations
741 // check if we can find new /DAQ/PSC path, otherwise default back to old /DAQ/MSC path
742 std::string path = "/DAQ/PSC";
743 std::string temp;
744 if(fOdb->FindPath(path.c_str()) != nullptr) {
745 std::cout << "using GRIFFIN path to analyzer info: " << path << "..." << std::endl;
746
747 temp = path;
748 temp.append("/PSC");
749 } else {
750 path = "/DAQ/MSC";
751 std::cout << "using GRIFFIN path to analyzer info: " << path << "..." << std::endl;
752
753 temp = path;
754 temp.append("/MSC");
755 }
756 TXMLNode* node = fOdb->FindPath(temp.c_str());
757 std::vector<int> address = fOdb->ReadIntArray(node);
758
759 temp = path;
760 temp.append("/chan");
761 node = fOdb->FindPath(temp.c_str());
762 std::vector<std::string> names = fOdb->ReadStringArray(node);
763
764 temp = path;
765 temp.append("/datatype");
766 node = fOdb->FindPath(temp.c_str());
767 std::vector<int> type = fOdb->ReadIntArray(node);
768 if(type.empty()) {
769 // failed to read array from /DAQ/<P/M>SC/datatype, so try to read /DAQ/<P/M>SC/DetType
770 temp = path;
771 temp.append("/DetType");
772 node = fOdb->FindPath(temp.c_str());
773 type = fOdb->ReadIntArray(node);
774 std::cout << "failed to find ODB path " << path << "/datatype, using " << type.size() << " entries from " << path << "/DetType instead" << std::endl;
775 }
776
777 temp = path;
778 temp.append("/gain");
779 node = fOdb->FindPath(temp.c_str());
780 std::vector<double> gains = fOdb->ReadDoubleArray(node);
781
782 temp = path;
783 temp.append("/offset");
784 node = fOdb->FindPath(temp.c_str());
785 std::vector<double> offsets = fOdb->ReadDoubleArray(node);
786
787 // DAQ has quadratic terms in ODB from November 2019
788 temp = path;
789 temp.append("/quadratic");
790 node = fOdb->FindPath(temp.c_str());
791 std::vector<double> quads = fOdb->ReadDoubleArray(node);
792
793 temp = path;
794 temp.append("/digitizer");
795 node = fOdb->FindPath(temp.c_str());
796 std::vector<std::string> digitizer = fOdb->ReadStringArray(node);
797
798 if((address.size() == names.size()) && (names.size() == gains.size()) && (gains.size() == offsets.size()) &&
799 (offsets.size() == type.size())) {
800 // all good. We ignore the digitizer size as this information is not present for all data
801 // Also ignoring quad terms as this will only be present in future data - S. Gillespie
802 for(size_t x = 0; x < address.size(); x++) {
803 TChannel* tempChan = TChannel::GetChannel(address.at(x), false); // names.at(x).c_str());
804 if(tempChan == nullptr) {
805 tempChan = new TChannel();
806 }
807 tempChan->SetName(names.at(x).c_str());
808 tempChan->SetAddress(address.at(x));
810
811 tempChan->AddENGCoefficient(static_cast<Float_t>(offsets.at(x)));
812 tempChan->AddENGCoefficient(static_cast<Float_t>(gains.at(x)));
813 if(x < quads.size()) {
814 tempChan->AddENGCoefficient(static_cast<Float_t>(quads.at(x))); //Assuming this means quad terms won't be added if not there.
815 }
816 if(x < digitizer.size()) {
818 }
819 // TChannel::UpdateChannel(tempChan);
820 TChannel::AddChannel(tempChan, "overwrite");
821 }
822 std::cout << TChannel::GetNumberOfChannels() << "\t TChannels created." << std::endl;
823 } else {
824 std::cout << BG_WHITE DRED << "problem parsing odb data, arrays are different sizes, channels not set." << RESET_COLOR << std::endl;
825 }
826
827 // get cycle information
828 // "/Experiment/Edit on start/PPG Cycle" is a link to the PPG cycle used (always "/PPG/Current"???)
829 // "/PPG/Current" gives the current PPG cycle used, e.g. 146Cs_S1468
830 // "/PPG/Cycles/146Cs_S1468" then has four PPGcodes and four durations
831 node = fOdb->FindPath("/PPG/Current");
832 if(node == nullptr) {
833 std::cerr << R"(Failed to find "/PPG/Current" in ODB!)" << std::endl;
834 return;
835 }
836
837 if(!node->HasChildren()) {
838 std::cout << "Node has no children, can't read ODB cycle" << std::endl;
839 return;
840 }
841 std::string currentCycle = "/PPG/Cycles/";
842 currentCycle.append(node->GetChildren()->GetContent());
843 temp = currentCycle;
844 temp.append("/PPGcodes");
845 node = fOdb->FindPath(temp.c_str());
846 if(node == nullptr) {
847 std::cerr << R"(Failed to find ")" << temp << R"(" in ODB!)" << std::endl;
848 return;
849 }
850 std::vector<int> tmpCodes = fOdb->ReadIntArray(node);
851 // the codes are 32bit with the 16 high bits being the same as the 16 low bits
852 // we check this and only keep the low 16 bits
853 std::vector<int16_t> ppgCodes;
854 for(auto& code : tmpCodes) {
855 if(((code >> 16) & 0xffff) != (code & 0xffff)) {
856 std::cout << DRED << "Found ppg code in the ODB with high bits (0x" << std::hex << (code >> 16)
857 << ") != low bits (" << (code & 0xffff) << std::dec << ")" << RESET_COLOR << std::endl;
858 }
859 ppgCodes.push_back(code & 0xffff);
860 }
861 temp = currentCycle;
862 temp.append("/durations");
863 node = fOdb->FindPath(temp.c_str());
864 if(node == nullptr) {
865 std::cerr << R"(Failed to find ")" << temp << R"(" in ODB!)" << std::endl;
866 return;
867 }
868 std::vector<int> durations = fOdb->ReadIntArray(node);
869
870 if(durations.size() != ppgCodes.size()) {
871 std::cerr << "Mismatching sizes of ppg codes (" << ppgCodes.size() << ") and duration (" << durations.size() << ")" << std::endl;
872 return;
873 }
874
875 TPPG::Get()->SetOdbCycle(ppgCodes, durations);
876#endif
877}
878
880{
881#ifdef HAS_XML
882 std::string typepath = "/Equipment/Trigger/settings/Detector Settings";
883 std::map<int, std::pair<std::string, std::string>> typemap;
884 TXMLNode* typenode = fOdb->FindPath(typepath.c_str());
885 int typecounter = 0;
886 if(typenode->HasChildren()) {
887 TXMLNode* typechild = typenode->GetChildren();
888 while(true) {
889 std::string tname = fOdb->GetNodeName(typechild);
890 if(tname.length() > 0 && typechild->HasChildren()) {
891 typecounter++;
892 TXMLNode* grandchild = typechild->GetChildren();
893 while(true) {
894 std::string grandchildname = fOdb->GetNodeName(grandchild);
895 if(grandchildname.compare(0, 7, "Digitis") == 0) {
896 std::string dname = grandchild->GetText();
897 typemap[typecounter] = std::make_pair(tname, dname);
898 break;
899 }
900 if(!grandchild->HasNextNode()) {
901 break;
902 }
903 grandchild = grandchild->GetNextNode();
904 }
905 }
906 if(!typechild->HasNextNode()) {
907 break;
908 }
909 typechild = typechild->GetNextNode();
910 }
911 }
912
913 std::string path = "/Analyzer/Shared Parameters/Config";
914 TXMLNode* test = fOdb->FindPath(path.c_str());
915 if(test == nullptr) {
916 path.assign("/Analyzer/Parameters/Cathode/Config"); // the old path to the useful odb info.
917 }
918 std::cout << "using TIGRESS path to analyzer info: " << path << "..." << std::endl;
919
920 std::string temp = path;
921 temp.append("/FSCP");
922 TXMLNode* node = fOdb->FindPath(temp.c_str());
923 std::vector<int> address = fOdb->ReadIntArray(node);
924
925 temp = path;
926 temp.append("/Name");
927 node = fOdb->FindPath(temp.c_str());
928 std::vector<std::string> names = fOdb->ReadStringArray(node);
929
930 temp = path;
931 temp.append("/Type");
932 node = fOdb->FindPath(temp.c_str());
933 std::vector<int> type = fOdb->ReadIntArray(node);
934
935 temp = path;
936 temp.append("/g");
937 node = fOdb->FindPath(temp.c_str());
938 std::vector<double> gains = fOdb->ReadDoubleArray(node);
939
940 temp = path;
941 temp.append("/o");
942 node = fOdb->FindPath(temp.c_str());
943 std::vector<double> offsets = fOdb->ReadDoubleArray(node);
944
945 // if( (address.size() == names.size()) && (names.size() == gains.size()) && (gains.size() == offsets.size()) &&
946 // offsets.size() == type.size() ) {
947 if((address.size() == gains.size()) && (gains.size() == offsets.size()) && offsets.size() == type.size()) {
948 // all good.
949 } else {
950 std::cout << BG_WHITE DRED << "problem parsing odb data, arrays are different sizes, channels not set." << RESET_COLOR << std::endl;
951 std::cout << DRED << "\taddress.size() = " << address.size() << RESET_COLOR << std::endl;
952 std::cout << DRED << "\tnames.size() = " << names.size() << RESET_COLOR << std::endl;
953 std::cout << DRED << "\tgains.size() = " << gains.size() << RESET_COLOR << std::endl;
954 std::cout << DRED << "\toffsets.size() = " << offsets.size() << RESET_COLOR << std::endl;
955 std::cout << DRED << "\ttype.size() = " << type.size() << RESET_COLOR << std::endl;
956 return;
957 }
958
959 for(size_t x = 0; x < address.size(); x++) {
960 TChannel* tempChan = TChannel::GetChannel(address.at(x), false); // names.at(x).c_str());
961 if(tempChan == nullptr) {
962 tempChan = new TChannel();
963 }
964 if(x < names.size()) {
965 tempChan->SetName(names.at(x).c_str());
966 }
967 tempChan->SetAddress(address.at(x));
969 int temp_integration = 0;
970 if(type.at(x) != 0) {
971 tempChan->SetDigitizerType(TPriorityValue<std::string>(typemap[type.at(x)].second, EPriority::kRootFile));
972 if(strcmp(tempChan->GetDigitizerTypeString(), "Tig64") ==
973 0) { // TODO: maybe use enumerations via GetDigitizerType()
974 temp_integration = 25;
975 } else if(strcmp(tempChan->GetDigitizerTypeString(), "Tig10") == 0) {
976 temp_integration = 125;
977 }
978 }
979 tempChan->SetIntegration(TPriorityValue<int>(temp_integration, EPriority::kRootFile));
980 tempChan->AddENGCoefficient(static_cast<Float_t>(offsets.at(x)));
981 tempChan->AddENGCoefficient(static_cast<Float_t>(gains.at(x)));
982
983 TChannel::AddChannel(tempChan, "overwrite");
984 }
985 std::cout << TChannel::GetNumberOfChannels() << "\t TChannels created." << std::endl;
986#endif
987}
988
989void TMidasFile::SetTIGDAQOdb() // Basically a copy of the GRIFFIN one without the PPG (as we don't have one) and digitizer <P/M>SC key which is not in TIGDAQ
990{
991#ifdef HAS_XML
992 // get calibrations
993 // check if we can find new /DAQ/PSC path, otherwise default back to old /DAQ/MSC path
994 std::string path = "/DAQ/PSC";
995 std::string temp;
996 if(fOdb->FindPath(path.c_str()) != nullptr) {
997 std::cout << "using TIGRESS path to analyzer info: " << path << "..." << std::endl;
998
999 temp = path;
1000 temp.append("/PSC");
1001 } else {
1002 path = "/DAQ/MSC";
1003 std::cout << "using TIGRESS path to analyzer info: " << path << "..." << std::endl;
1004
1005 temp = path;
1006 temp.append("/MSC");
1007 }
1008 TXMLNode* node = fOdb->FindPath(temp.c_str());
1009 std::vector<int> address = fOdb->ReadIntArray(node);
1010
1011 temp = path;
1012 temp.append("/chan");
1013 node = fOdb->FindPath(temp.c_str());
1014 std::vector<std::string> names = fOdb->ReadStringArray(node);
1015
1016 temp = path;
1017 temp.append("/datatype");
1018 node = fOdb->FindPath(temp.c_str());
1019 std::vector<int> type = fOdb->ReadIntArray(node);
1020 if(type.empty()) {
1021 // failed to read array from <path>/datatype, so try to read <path>/DetType
1022 temp = path;
1023 temp.append("/DetType");
1024 node = fOdb->FindPath(temp.c_str());
1025 type = fOdb->ReadIntArray(node);
1026 std::cout << "failed to find ODB path " << path << "/datatype, using " << type.size() << " entries from " << path << "/DetType instead" << std::endl;
1027 }
1028
1029 temp = path;
1030 temp.append("/gain");
1031 node = fOdb->FindPath(temp.c_str());
1032 std::vector<double> gains = fOdb->ReadDoubleArray(node);
1033
1034 temp = path;
1035 temp.append("/offset");
1036 node = fOdb->FindPath(temp.c_str());
1037 std::vector<double> offsets = fOdb->ReadDoubleArray(node);
1038
1039 // DAQ has quadratic terms in ODB from November 2019
1040 temp = path;
1041 temp.append("/quadratic");
1042 node = fOdb->FindPath(temp.c_str());
1043 std::vector<double> quads = fOdb->ReadDoubleArray(node);
1044
1045 temp = path;
1046 temp.append("/digitizer");
1047 node = fOdb->FindPath(temp.c_str());
1048 std::vector<std::string> digitizer = fOdb->ReadStringArray(node);
1049
1050 if((address.size() == names.size()) && (names.size() == gains.size()) && (gains.size() == offsets.size()) && (gains.size() == offsets.size()) &&
1051 (offsets.size() == type.size())) {
1052 // Only data without quad terms is mine so they will always be present - S. Gillespie
1053 for(size_t x = 0; x < address.size(); x++) {
1054 TChannel* tempChan = TChannel::GetChannel(address.at(x), false); // names.at(x).c_str());
1055 if(tempChan == nullptr) {
1056 tempChan = new TChannel();
1057 }
1058 tempChan->SetName(names.at(x).c_str());
1059 tempChan->SetAddress(address.at(x));
1061
1062 tempChan->AddENGCoefficient(static_cast<Float_t>(offsets.at(x)));
1063 tempChan->AddENGCoefficient(static_cast<Float_t>(gains.at(x)));
1064 if(x < quads.size()) { tempChan->AddENGCoefficient(static_cast<Float_t>(quads.at(x))); } //Assuming this means quad terms won't be added if not there.
1065 }
1066 std::cout << TChannel::GetNumberOfChannels() << "\t TChannels created." << std::endl;
1067 } else {
1068 std::cout << BG_WHITE DRED << "problem parsing odb data, arrays are different sizes, channels not set." << RESET_COLOR << std::endl;
1069 }
1070#endif
1071}
1072
1073// end
#define SHOW_CURSOR
Definition Globals.h:33
#define DYELLOW
Definition Globals.h:16
#define BG_WHITE
Definition Globals.h:24
#define DRED
Definition Globals.h:18
#define DBLUE
Definition Globals.h:15
#define RED
Definition Globals.h:9
#define HIDE_CURSOR
Definition Globals.h:32
#define RESET_COLOR
Definition Globals.h:5
const Double_t s
#define O_LARGEFILE
static int readpipe(int fd, char *buf, int length)
static int hasSuffix(const char *name, const char *suffix)
static void SetMnemonicClass(const TClassRef &cls)
Definition TChannel.h:80
static void DeleteAllChannels()
Definition TChannel.cxx:273
void SetAddress(unsigned int tmpadd)
Definition TChannel.cxx:540
static TChannel * GetChannel(unsigned int temp_address, bool warn=false)
Definition TChannel.cxx:459
void SetIntegration(const TPriorityValue< int > &tmp)
Definition TChannel.h:149
void SetNumber(const TPriorityValue< int > &tmp)
Definition TChannel.h:139
void AddENGCoefficient(Float_t temp, size_t range=0)
Definition TChannel.h:204
const char * GetDigitizerTypeString() const
Definition TChannel.h:173
void SetName(const char *tmpName) override
Definition TChannel.cxx:244
static void AddChannel(TChannel *, Option_t *opt="")
Definition TChannel.cxx:285
static size_t GetNumberOfChannels()
Definition TChannel.h:68
void SetDigitizerType(const TPriorityValue< std::string > &tmp)
static void SetEpicsNameList(const std::vector< std::string > &names)
static TGRSIOptions * Get(int argc=0, char **argv=nullptr)
Do not use!
MIDAS event.
Definition TMidasEvent.h:35
TMidas_EVENT_HEADER * GetEventHeader()
return pointer to the event header
void Clear(Option_t *opt="") override
clear event for reuse
bool IsGoodSize() const
validate the event length
uint32_t GetDataSize() const override
return the event size
void SwapBytesEventHeader()
convert event header between little-endian (Linux-x86) and big endian (MacOS-PPC)
Reader for MIDAS .mid files.
Definition TMidasFile.h:32
bool OutOpen(const char *filename)
Open output file.
void SetTIGDAQOdb()
void OutClose()
Close output file.
std::string fLastError
error string from last errno
Definition TMidasFile.h:112
std::string Status(bool long_file_description=true) override
bool Open(const char *filename) override
Open input file.
uint32_t fCurrentBufferSize
Definition TMidasFile.h:108
void SetMaxBufferSize(int maxsize)
~TMidasFile() override
destructor
void SetRunInfo(uint32_t time)
int Read(std::shared_ptr< TRawEvent > event) override
Read one event from the file.
std::string fOutFilename
name of the currently open file
Definition TMidasFile.h:105
int GetSubRunNumber() override
TXMLOdb * fOdb
Definition TMidasFile.h:102
void * fOutGzFile
zlib compressed output file reader
Definition TMidasFile.h:121
std::vector< char > fWriteBuffer
Definition TMidasFile.h:107
int fCurrentEventNumber
Definition TMidasFile.h:113
bool Write(const std::shared_ptr< TMidasEvent > &midasEvent, Option_t *opt="")
Write one event to the output file.
void SetEPICSOdb()
int fFile
open input file descriptor
Definition TMidasFile.h:117
void Skip(size_t nofEvents) override
Skip nofEvents from the file.
void SetFileOdb()
void Close() override
Close input file.
bool WriteBuffer()
bool fDoByteSwap
"true" if file has to be byteswapped
Definition TMidasFile.h:115
void FillBuffer(const std::shared_ptr< TMidasEvent > &midasEvent, Option_t *opt="")
TMidasFile()
default constructor
void * fGzFile
zlib compressed input file reader
Definition TMidasFile.h:118
void SetTIGOdb()
int fOutFile
open output file descriptor
Definition TMidasFile.h:120
void SetGRIFFOdb()
uint32_t fMaxBufferSize
Definition TMidasFile.h:109
int fLastErrno
errno from the last operation
Definition TMidasFile.h:111
void ReadMoreBytes(size_t bytes)
std::shared_ptr< TMidasEvent > fOdbEvent
Definition TMidasFile.h:98
void * fPoFile
popen() input file reader
Definition TMidasFile.h:119
int GetRunNumber() override
void SetOdbCycle(std::vector< int16_t > ppgCodes, std::vector< int > durations)
Definition TPPG.h:197
void ClearBuffer()
Definition TRawFile.h:71
virtual const char * GetFilename() const
Get the name of this file.
Definition TRawFile.h:56
size_t BufferSize() const
Definition TRawFile.h:69
char * BufferData()
Definition TRawFile.h:70
virtual size_t FileSize()
Definition TRawFile.h:63
virtual std::string Filename() const
Get the name of this file.
Definition TRawFile.h:66
void IncrementBytesRead(size_t val=1)
Definition TRawFile.h:62
virtual size_t BytesRead()
Definition TRawFile.h:61
void ResizeBuffer(size_t newSize)
Definition TRawFile.h:72
static void SetRunComment(const char *run_comment)
Definition TRunInfo.h:214
static void SetRunStart(double tmp)
Definition TRunInfo.h:222
static int SubRunNumber()
Definition TRunInfo.h:202
static void SetRunInfo(int runnum=0, int subrunnum=-1)
Definition TRunInfo.cxx:135
static void ClearLibraryVersion()
Definition TRunInfo.h:172
static void SetDetectorInformation(TDetectorInformation *inf)
Definition TRunInfo.h:271
static void SetLibraryVersion(const char *ver)
Definition TRunInfo.h:173
static void SetRunTitle(const char *run_title)
Definition TRunInfo.h:210
static TPPG * Get(bool verbose=false)
Definition TSingleton.h:33
std::vector< std::string > ReadStringArray(TXMLNode *node)
Definition TXMLOdb.cxx:169
const char * GetNodeName(TXMLNode *)
Definition TXMLOdb.cxx:105
std::vector< double > ReadDoubleArray(TXMLNode *node)
Definition TXMLOdb.cxx:219
TXMLNode * FindPath(const char *path, TXMLNode *node=nullptr)
Definition TXMLOdb.cxx:67
std::vector< int > ReadIntArray(TXMLNode *node)
Definition TXMLOdb.cxx:127
uint16_t fEventId
event id