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 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 if(TGRSIOptions::Get()->IgnoreOdbChannels()) {
669 std::cout << DYELLOW << "\tskipping odb channel information stored in file." << RESET_COLOR << std::endl;
670 return;
671 }
672
673 // Check to see if we are running a GRIFFIN or TIGRESS experiment
674 TXMLNode* node = fOdb->FindPath("/Experiment");
675 if(!node->HasChildren()) {
676 return;
677 }
678 node = node->GetChildren();
679 std::string expt;
680 while(true) {
681 std::string key = fOdb->GetNodeName(node);
682 if(key == "Name") {
683 expt = node->GetText();
684 break;
685 }
686 if(!node->HasNextNode()) {
687 break;
688 }
689 node = node->GetNextNode();
690 }
691 if(expt == "tigress") {
692 SetTIGOdb();
693 } else if(expt.find("grif") != std::string::npos) {
694 // for GRIFFIN the experiment name might be griffin, grifstor, grifalt, etc.
695 SetGRIFFOdb();
696 } else if(expt == "tigdaq") { //New TIGRESS DAQ
697 SetTIGDAQOdb();
698 } else {
699 std::cerr << RED << "Unknown experiment name \"" << expt << "\", ODB won't be read!" << RESET_COLOR << std::endl;
700 }
701#endif
702}
703
704void TMidasFile::SetRunInfo(uint32_t time)
705{
706#ifdef HAS_XML
707 TXMLNode* node = fOdb->FindPath("/Runinfo/Start time binary");
708 if(node != nullptr) {
709 std::stringstream str(node->GetText());
710 unsigned int odbTime = 0;
711 str >> odbTime;
712 if(TRunInfo::SubRunNumber() == 0 && time != odbTime) {
713 std::cout << "Warning, ODB start time of first subrun (" << odbTime << ") does not match midas time of first event in this subrun (" << time << ")!" << std::endl;
714 }
716 }
717
718 node = fOdb->FindPath("/Experiment/Run parameters/Run Title");
719 if(node != nullptr) {
720 TRunInfo::SetRunTitle(node->GetText());
721 std::cout << "Title: " << DBLUE << node->GetText() << RESET_COLOR << std::endl;
722 }
723
724 if(node != nullptr) {
725 node = fOdb->FindPath("/Experiment/Run parameters/Comment");
726 TRunInfo::SetRunComment(node->GetText());
727 std::cout << "Comment: " << DBLUE << node->GetText() << RESET_COLOR << std::endl;
728 }
729#endif
730}
731
733{
734#ifdef HAS_XML
735 TXMLNode* node = fOdb->FindPath("/Equipment/Epics/Settings/Names");
736 std::vector<std::string> names = fOdb->ReadStringArray(node);
738#endif
739}
740
742{
743#ifdef HAS_XML
744 // get calibrations
745 // check if we can find new /DAQ/PSC path, otherwise default back to old /DAQ/MSC path
746 std::string path = "/DAQ/PSC";
747 std::string temp;
748 if(fOdb->FindPath(path.c_str()) != nullptr) {
749 std::cout << "using GRIFFIN path to analyzer info: " << path << "..." << std::endl;
750
751 temp = path;
752 temp.append("/PSC");
753 } else {
754 path = "/DAQ/MSC";
755 std::cout << "using GRIFFIN path to analyzer info: " << path << "..." << std::endl;
756
757 temp = path;
758 temp.append("/MSC");
759 }
760 TXMLNode* node = fOdb->FindPath(temp.c_str());
761 std::vector<int> address = fOdb->ReadIntArray(node);
762
763 temp = path;
764 temp.append("/chan");
765 node = fOdb->FindPath(temp.c_str());
766 std::vector<std::string> names = fOdb->ReadStringArray(node);
767
768 temp = path;
769 temp.append("/datatype");
770 node = fOdb->FindPath(temp.c_str());
771 std::vector<int> type = fOdb->ReadIntArray(node);
772 if(type.empty()) {
773 // failed to read array from /DAQ/<P/M>SC/datatype, so try to read /DAQ/<P/M>SC/DetType
774 temp = path;
775 temp.append("/DetType");
776 node = fOdb->FindPath(temp.c_str());
777 type = fOdb->ReadIntArray(node);
778 std::cout << "failed to find ODB path " << path << "/datatype, using " << type.size() << " entries from " << path << "/DetType instead" << std::endl;
779 }
780
781 temp = path;
782 temp.append("/gain");
783 node = fOdb->FindPath(temp.c_str());
784 std::vector<double> gains = fOdb->ReadDoubleArray(node);
785
786 temp = path;
787 temp.append("/offset");
788 node = fOdb->FindPath(temp.c_str());
789 std::vector<double> offsets = fOdb->ReadDoubleArray(node);
790
791 // DAQ has quadratic terms in ODB from November 2019
792 temp = path;
793 temp.append("/quadratic");
794 node = fOdb->FindPath(temp.c_str());
795 std::vector<double> quads = fOdb->ReadDoubleArray(node);
796
797 temp = path;
798 temp.append("/digitizer");
799 node = fOdb->FindPath(temp.c_str());
800 std::vector<std::string> digitizer = fOdb->ReadStringArray(node);
801
802 if((address.size() == names.size()) && (names.size() == gains.size()) && (gains.size() == offsets.size()) &&
803 (offsets.size() == type.size())) {
804 // all good. We ignore the digitizer size as this information is not present for all data
805 // Also ignoring quad terms as this will only be present in future data - S. Gillespie
806 for(size_t x = 0; x < address.size(); x++) {
807 TChannel* tempChan = TChannel::GetChannel(address.at(x), false); // names.at(x).c_str());
808 if(tempChan == nullptr) {
809 tempChan = new TChannel();
810 }
811 tempChan->SetName(names.at(x).c_str());
812 tempChan->SetAddress(address.at(x));
814
815 tempChan->AddENGCoefficient(static_cast<Float_t>(offsets.at(x)));
816 tempChan->AddENGCoefficient(static_cast<Float_t>(gains.at(x)));
817 if(x < quads.size()) {
818 tempChan->AddENGCoefficient(static_cast<Float_t>(quads.at(x))); //Assuming this means quad terms won't be added if not there.
819 }
820 if(x < digitizer.size()) {
822 }
823 // TChannel::UpdateChannel(tempChan);
824 TChannel::AddChannel(tempChan, "overwrite");
825 }
826 std::cout << TChannel::GetNumberOfChannels() << "\t TChannels created." << std::endl;
827 } else {
828 std::cout << BG_WHITE DRED << "problem parsing odb data, arrays are different sizes, channels not set." << RESET_COLOR << std::endl;
829 }
830
831 // get cycle information
832 // "/Experiment/Edit on start/PPG Cycle" is a link to the PPG cycle used (always "/PPG/Current"???)
833 // "/PPG/Current" gives the current PPG cycle used, e.g. 146Cs_S1468
834 // "/PPG/Cycles/146Cs_S1468" then has four PPGcodes and four durations
835 node = fOdb->FindPath("/PPG/Current");
836 if(node == nullptr) {
837 std::cerr << R"(Failed to find "/PPG/Current" in ODB!)" << std::endl;
838 return;
839 }
840
841 if(!node->HasChildren()) {
842 std::cout << "Node has no children, can't read ODB cycle" << std::endl;
843 return;
844 }
845 std::string currentCycle = "/PPG/Cycles/";
846 currentCycle.append(node->GetChildren()->GetContent());
847 temp = currentCycle;
848 temp.append("/PPGcodes");
849 node = fOdb->FindPath(temp.c_str());
850 if(node == nullptr) {
851 std::cerr << R"(Failed to find ")" << temp << R"(" in ODB!)" << std::endl;
852 return;
853 }
854 std::vector<int> tmpCodes = fOdb->ReadIntArray(node);
855 // the codes are 32bit with the 16 high bits being the same as the 16 low bits
856 // we check this and only keep the low 16 bits
857 std::vector<int16_t> ppgCodes;
858 for(auto& code : tmpCodes) {
859 if(((code >> 16) & 0xffff) != (code & 0xffff)) {
860 std::cout << DRED << "Found ppg code in the ODB with high bits (0x" << std::hex << (code >> 16)
861 << ") != low bits (" << (code & 0xffff) << std::dec << ")" << RESET_COLOR << std::endl;
862 }
863 ppgCodes.push_back(code & 0xffff);
864 }
865 temp = currentCycle;
866 temp.append("/durations");
867 node = fOdb->FindPath(temp.c_str());
868 if(node == nullptr) {
869 std::cerr << R"(Failed to find ")" << temp << R"(" in ODB!)" << std::endl;
870 return;
871 }
872 std::vector<int> durations = fOdb->ReadIntArray(node);
873
874 if(durations.size() != ppgCodes.size()) {
875 std::cerr << "Mismatching sizes of ppg codes (" << ppgCodes.size() << ") and duration (" << durations.size() << ")" << std::endl;
876 return;
877 }
878
879 TPPG::Get()->SetOdbCycle(ppgCodes, durations);
880#endif
881}
882
884{
885#ifdef HAS_XML
886 std::string typepath = "/Equipment/Trigger/settings/Detector Settings";
887 std::map<int, std::pair<std::string, std::string>> typemap;
888 TXMLNode* typenode = fOdb->FindPath(typepath.c_str());
889 int typecounter = 0;
890 if(typenode->HasChildren()) {
891 TXMLNode* typechild = typenode->GetChildren();
892 while(true) {
893 std::string tname = fOdb->GetNodeName(typechild);
894 if(tname.length() > 0 && typechild->HasChildren()) {
895 typecounter++;
896 TXMLNode* grandchild = typechild->GetChildren();
897 while(true) {
898 std::string grandchildname = fOdb->GetNodeName(grandchild);
899 if(grandchildname.compare(0, 7, "Digitis") == 0) {
900 std::string dname = grandchild->GetText();
901 typemap[typecounter] = std::make_pair(tname, dname);
902 break;
903 }
904 if(!grandchild->HasNextNode()) {
905 break;
906 }
907 grandchild = grandchild->GetNextNode();
908 }
909 }
910 if(!typechild->HasNextNode()) {
911 break;
912 }
913 typechild = typechild->GetNextNode();
914 }
915 }
916
917 std::string path = "/Analyzer/Shared Parameters/Config";
918 TXMLNode* test = fOdb->FindPath(path.c_str());
919 if(test == nullptr) {
920 path.assign("/Analyzer/Parameters/Cathode/Config"); // the old path to the useful odb info.
921 }
922 std::cout << "using TIGRESS path to analyzer info: " << path << "..." << std::endl;
923
924 std::string temp = path;
925 temp.append("/FSCP");
926 TXMLNode* node = fOdb->FindPath(temp.c_str());
927 std::vector<int> address = fOdb->ReadIntArray(node);
928
929 temp = path;
930 temp.append("/Name");
931 node = fOdb->FindPath(temp.c_str());
932 std::vector<std::string> names = fOdb->ReadStringArray(node);
933
934 temp = path;
935 temp.append("/Type");
936 node = fOdb->FindPath(temp.c_str());
937 std::vector<int> type = fOdb->ReadIntArray(node);
938
939 temp = path;
940 temp.append("/g");
941 node = fOdb->FindPath(temp.c_str());
942 std::vector<double> gains = fOdb->ReadDoubleArray(node);
943
944 temp = path;
945 temp.append("/o");
946 node = fOdb->FindPath(temp.c_str());
947 std::vector<double> offsets = fOdb->ReadDoubleArray(node);
948
949 // if( (address.size() == names.size()) && (names.size() == gains.size()) && (gains.size() == offsets.size()) &&
950 // offsets.size() == type.size() ) {
951 if((address.size() == gains.size()) && (gains.size() == offsets.size()) && offsets.size() == type.size()) {
952 // all good.
953 } else {
954 std::cout << BG_WHITE DRED << "problem parsing odb data, arrays are different sizes, channels not set." << RESET_COLOR << std::endl;
955 std::cout << DRED << "\taddress.size() = " << address.size() << RESET_COLOR << std::endl;
956 std::cout << DRED << "\tnames.size() = " << names.size() << RESET_COLOR << std::endl;
957 std::cout << DRED << "\tgains.size() = " << gains.size() << RESET_COLOR << std::endl;
958 std::cout << DRED << "\toffsets.size() = " << offsets.size() << RESET_COLOR << std::endl;
959 std::cout << DRED << "\ttype.size() = " << type.size() << RESET_COLOR << std::endl;
960 return;
961 }
962
963 for(size_t x = 0; x < address.size(); x++) {
964 TChannel* tempChan = TChannel::GetChannel(address.at(x), false); // names.at(x).c_str());
965 if(tempChan == nullptr) {
966 tempChan = new TChannel();
967 }
968 if(x < names.size()) {
969 tempChan->SetName(names.at(x).c_str());
970 }
971 tempChan->SetAddress(address.at(x));
973 int temp_integration = 0;
974 if(type.at(x) != 0) {
975 tempChan->SetDigitizerType(TPriorityValue<std::string>(typemap[type.at(x)].second, EPriority::kRootFile));
976 if(strcmp(tempChan->GetDigitizerTypeString(), "Tig64") ==
977 0) { // TODO: maybe use enumerations via GetDigitizerType()
978 temp_integration = 25;
979 } else if(strcmp(tempChan->GetDigitizerTypeString(), "Tig10") == 0) {
980 temp_integration = 125;
981 }
982 }
983 tempChan->SetIntegration(TPriorityValue<int>(temp_integration, EPriority::kRootFile));
984 tempChan->AddENGCoefficient(static_cast<Float_t>(offsets.at(x)));
985 tempChan->AddENGCoefficient(static_cast<Float_t>(gains.at(x)));
986
987 TChannel::AddChannel(tempChan, "overwrite");
988 }
989 std::cout << TChannel::GetNumberOfChannels() << "\t TChannels created." << std::endl;
990#endif
991}
992
993void 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
994{
995#ifdef HAS_XML
996 // get calibrations
997 // check if we can find new /DAQ/PSC path, otherwise default back to old /DAQ/MSC path
998 std::string path = "/DAQ/PSC";
999 std::string temp;
1000 if(fOdb->FindPath(path.c_str()) != nullptr) {
1001 std::cout << "using TIGRESS path to analyzer info: " << path << "..." << std::endl;
1002
1003 temp = path;
1004 temp.append("/PSC");
1005 } else {
1006 path = "/DAQ/MSC";
1007 std::cout << "using TIGRESS path to analyzer info: " << path << "..." << std::endl;
1008
1009 temp = path;
1010 temp.append("/MSC");
1011 }
1012 TXMLNode* node = fOdb->FindPath(temp.c_str());
1013 std::vector<int> address = fOdb->ReadIntArray(node);
1014
1015 temp = path;
1016 temp.append("/chan");
1017 node = fOdb->FindPath(temp.c_str());
1018 std::vector<std::string> names = fOdb->ReadStringArray(node);
1019
1020 temp = path;
1021 temp.append("/datatype");
1022 node = fOdb->FindPath(temp.c_str());
1023 std::vector<int> type = fOdb->ReadIntArray(node);
1024 if(type.empty()) {
1025 // failed to read array from <path>/datatype, so try to read <path>/DetType
1026 temp = path;
1027 temp.append("/DetType");
1028 node = fOdb->FindPath(temp.c_str());
1029 type = fOdb->ReadIntArray(node);
1030 std::cout << "failed to find ODB path " << path << "/datatype, using " << type.size() << " entries from " << path << "/DetType instead" << std::endl;
1031 }
1032
1033 temp = path;
1034 temp.append("/gain");
1035 node = fOdb->FindPath(temp.c_str());
1036 std::vector<double> gains = fOdb->ReadDoubleArray(node);
1037
1038 temp = path;
1039 temp.append("/offset");
1040 node = fOdb->FindPath(temp.c_str());
1041 std::vector<double> offsets = fOdb->ReadDoubleArray(node);
1042
1043 // DAQ has quadratic terms in ODB from November 2019
1044 temp = path;
1045 temp.append("/quadratic");
1046 node = fOdb->FindPath(temp.c_str());
1047 std::vector<double> quads = fOdb->ReadDoubleArray(node);
1048
1049 temp = path;
1050 temp.append("/digitizer");
1051 node = fOdb->FindPath(temp.c_str());
1052 std::vector<std::string> digitizer = fOdb->ReadStringArray(node);
1053
1054 if((address.size() == names.size()) && (names.size() == gains.size()) && (gains.size() == offsets.size()) && (gains.size() == offsets.size()) &&
1055 (offsets.size() == type.size())) {
1056 // Only data without quad terms is mine so they will always be present - S. Gillespie
1057 for(size_t x = 0; x < address.size(); x++) {
1058 TChannel* tempChan = TChannel::GetChannel(address.at(x), false); // names.at(x).c_str());
1059 if(tempChan == nullptr) {
1060 tempChan = new TChannel();
1061 }
1062 tempChan->SetName(names.at(x).c_str());
1063 tempChan->SetAddress(address.at(x));
1065
1066 tempChan->AddENGCoefficient(static_cast<Float_t>(offsets.at(x)));
1067 tempChan->AddENGCoefficient(static_cast<Float_t>(gains.at(x)));
1068 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.
1069 TChannel::AddChannel(tempChan, "overwrite");
1070 }
1071 std::cout << TChannel::GetNumberOfChannels() << "\t TChannels created." << std::endl;
1072 } else {
1073 std::cout << BG_WHITE DRED << "problem parsing odb data, arrays are different sizes, channels not set." << RESET_COLOR << std::endl;
1074 }
1075#endif
1076}
1077
1078// 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:277
void SetAddress(unsigned int tmpadd)
Definition TChannel.cxx:549
static TChannel * GetChannel(unsigned int temp_address, bool warn=false)
Definition TChannel.cxx:468
void SetIntegration(const TPriorityValue< int > &tmp)
Definition TChannel.h:144
void SetNumber(const TPriorityValue< int > &tmp)
Definition TChannel.h:134
void AddENGCoefficient(Float_t temp, size_t range=0)
Definition TChannel.h:199
const char * GetDigitizerTypeString() const
Definition TChannel.h:168
void SetName(const char *tmpName) override
Definition TChannel.cxx:248
static void AddChannel(TChannel *, Option_t *opt="")
Definition TChannel.cxx:289
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:170
const char * GetNodeName(TXMLNode *)
Definition TXMLOdb.cxx:106
std::vector< double > ReadDoubleArray(TXMLNode *node)
Definition TXMLOdb.cxx:220
TXMLNode * FindPath(const char *path, TXMLNode *node=nullptr)
Definition TXMLOdb.cxx:68
std::vector< int > ReadIntArray(TXMLNode *node)
Definition TXMLOdb.cxx:128
uint16_t fEventId
event id