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