#include "DataWriteFits.h" #include "FAD.h" #include "Converter.h" using namespace std; DataWriteFits::~DataWriteFits() { Close(); delete fConv; } template void DataWriteFits::WriteKey(const string &name, const int idx, const T &value, const string &comment) { ostringstream str; str << name << idx; ostringstream com; com << "Board " << setw(2) << idx << ": " << comment; fFile.WriteKey(str.str(), value, com.str()); } // -------------------------------------------------------------------------- // //! DataWriteFits constructor. This is the one that should be used, not the default one (parameter-less) //! @param runid This parameter should probably be removed. I first thought it was the run number, but apparently it is not //! @param h a pointer to the RUN_HEAD structure that contains the informations relative to this run // bool DataWriteFits::Open(RUN_HEAD* h) { if (fConv) { Error("DataWriteFits::Open called twice."); return false; } fFile.AddColumn('I', "EventNum"); fFile.AddColumn('I', "TriggerNum"); fFile.AddColumn('S', "TriggerType"); fFile.AddColumn('I', "NumBoards"); fFile.AddColumn('C', "Errors", 4); fFile.AddColumn('I', "SoftTrig"); fFile.AddColumn('I', "PCTime", 2); fFile.AddColumn('I', "BoardTime", NBOARDS); fFile.AddColumn('S', "StartCellData", NPIX); fFile.AddColumn('S', "StartCellTimeMarker", NTMARK); fFile.AddColumn('S', "Data", h->NPix*h->Nroi); fFile.AddColumn('S', "TimeMarker", h->NTm*h->NroiTM); // Write length of physical pipeline (1024) fConv = new Converter(Converter::ToFormat(fFile.GetColumnTypes())); const size_t sz = (h->NPix*h->Nroi + h->NTm*h->NroiTM)*2; if (fConv->GetSize()-sz+4!=sizeof(EVENT)) { ostringstream str; str << "The EVENT structure size (" << sizeof(EVENT) << ") doesn't match the described FITS row ("; str << fConv->GetSize()-sz+4 << ")"; Error(str); return false; } //Form filename, based on runid and run-type fFileName = FormFileName("fits"); if (!fFile.OpenFile(fFileName)) return false; if (!fFile.OpenTable("Events")) return false; if (!fFile.WriteDefaultKeys("fadctrl")) return false; Info("==> TODO: Write sampling frequency..."); //write header data //first the "standard" keys try { fFile.WriteKey("BLDVER", h->Version, "Builder version"); fFile.WriteKey("RUNID", GetRunId(), "Run number"); fFile.WriteKey("RUNTYPE", h->RunType, "Type of run"); fFile.WriteKey("NBOARD", h->NBoard, "Number of acquisition boards"); fFile.WriteKey("NPIX", h->NPix, "Number of pixels"); fFile.WriteKey("NTMARK", h->NTm, "Number of Time marks"); fFile.WriteKey("NROI", h->Nroi, "Number of slices per pixels"); fFile.WriteKey("NROITM", h->NroiTM, "Number of slices per time-marker"); //FIXME should we also put the start and stop time of the received data ? //now the events header related variables fFile.WriteKey("CAMERA", "MGeomCamFACT", ""); fFile.WriteKey("DAQ", "DRS4", ""); fFile.WriteKey("ADCRANGE", 2000, "Dynamic range in mV"); fFile.WriteKey("ADC", 12, "Resolution in bits"); // Write a single key for: // ----------------------- // Start package flag // package length // version number // status // Prescaler // Write 40 kays for (?) // Phaseshift // DAC for (int i=0; iNBoard; i++) { const PEVNT_HEADER &hh = h->FADhead[i]; // Header values whihc won't change during the run WriteKey("ID", i, hh.board_id, "Board ID"); WriteKey("DNA", i, hh.DNA, "DNA"); WriteKey("FWVER", i, hh.version_no, "Firmware Version"); } // FIXME: Calculate average ref clock frequency for (int i=0; iNBoard; i++) { const PEVNT_HEADER &hh = h->FADhead[i]; if (hh.start_package_flag==0) continue; fFile.WriteKey("RUN", hh.runnumber, "Run number"); fFile.WriteKey("PRESC", hh.trigger_generator_prescaler, "Trigger generator prescaler"); fFile.WriteKey("PHASE", hh.adc_clock_phase_shift, "ADC clock phase shift"); for (int j=0; j<8; j++) { ostringstream dac; dac << "DAC" << j; fFile.WriteKey(dac.str(), hh.dac[j], "DAC command value"); } break; } double avg = 0; int cnt = 0; for (int i=0; iNBoard; i++) { const PEVNT_HEADER &hh = h->FADhead[i]; if (hh.start_package_flag==0) continue; avg += hh.REFCLK_frequency; cnt ++; } fFile.WriteKey("REFCLK", avg/cnt, "Average reference clock frequency in Hz"); } catch (const CCfits::FitsException &e) { Error("CCfits::Table::addKey failed in "+fFileName+"': "+e.message()); return false; } //Last but not least, add header keys that will be updated when closing the file return WriteFooter(NULL); } // -------------------------------------------------------------------------- // //! This writes one event to the file //! @param e the pointer to the EVENT // bool DataWriteFits::WriteEvt(EVENT *e) { if (!fFile.AddRow()) return false; const size_t sz = sizeof(EVENT) + sizeof(e->StartPix)*e->Roi+sizeof(e->StartTM)*e->RoiTM; const vector data = fConv->ToFits(reinterpret_cast(e)+4, sz-4); return fFile.WriteData(data.data(), data.size()); } bool DataWriteFits::WriteFooter(RUN_TAIL *rt) { try { /* fFile.WriteKey("NBEVTOK", rt ? rt->nEventsOk : uint32_t(0), "How many events were written"); fFile.WriteKey("NBEVTREJ", rt ? rt->nEventsRej : uint32_t(0), "How many events were rejected by SW-trig"); fFile.WriteKey("NBEVTBAD", rt ? rt->nEventsBad : uint32_t(0), "How many events were rejected by Error"); */ //FIXME shouldn't we convert start and stop time to MjD first ? //FIXME shouldn't we also add an MjD reference ? fFile.WriteKey("TSTART", rt ? rt->PCtime0 : uint32_t(0), "Time when first event received"); fFile.WriteKey("TSTOP", rt ? rt->PCtimeX : uint32_t(0), "Time when last event received"); } catch (const CCfits::FitsException &e) { Error("CCfits::Table::addKey failed in '"+fFile.GetName()+"': "+e.message()); return false; } return true; } // -------------------------------------------------------------------------- // //! Closes the file, and before this it write the TAIL data //! @param rt the pointer to the RUN_TAIL data structure // bool DataWriteFits::Close(RUN_TAIL *rt) { if (!fFile.IsOpen()) return false; WriteFooter(rt); fFile.Close(); return true; }