source: trunk/FACT++/src/DataWriteFits2.cc@ 20011

Last change on this file since 20011 was 19389, checked in by tbretz, 6 years ago
As NIGHT is bound to the observatory location, write a new keywork OBSERVAT which corresponds to PRESET_OBSERVATORY.
File size: 12.0 KB
Line 
1#include "DataWriteFits2.h"
2
3#include <boost/filesystem.hpp>
4
5#include "HeadersFAD.h"
6#include "EventBuilder.h"
7
8#include "externals/factofits.h"
9#include "externals/DrsCalib.h"
10
11#ifdef HAVE_NOVA
12#include "externals/nova.h"
13#endif
14
15using namespace std;
16
17DataWriteFits2::DataWriteFits2(const std::string &path, uint64_t night, uint32_t runid, MessageImp &imp)
18 : DataProcessorImp(path, night, runid, imp)
19{
20 fFile = std::make_shared<ofits>();
21}
22
23DataWriteFits2::DataWriteFits2(const std::string &path, uint64_t night, uint32_t runid, const DrsCalibration &cal, MessageImp &imp)
24 : DataProcessorImp(path, night, runid, imp)
25{
26 factofits *file = new factofits;
27 file->SetDrsCalibration(cal);
28 fFile = std::shared_ptr<ofits>(file);
29}
30
31void DataWriteFits2::WriteHeader(const RUN_HEAD &h, const FAD::RunDescription &d)
32{
33 const int16_t realRoiTM = (h.NroiTM >= 2*h.Nroi && h.Nroi<=512) ? h.Nroi : 0;
34
35 fFile->AddColumnInt("EventNum", "uint32", "FAD board event counter");
36 fFile->AddColumnInt("TriggerNum", "uint32", "FTM board trigger counter");
37 fFile->AddColumnShort("TriggerType", "uint16", "FTM board trigger type");
38 fFile->AddColumnInt("NumBoards", "uint32", "Number of connected boards");
39 fFile->AddColumnInt(2, "UnixTimeUTC", "uint32", "Unix time seconds and microseconds");
40 fFile->AddColumnInt(NBOARDS, "BoardTime", "uint32", "Board internal time counter");
41 fFile->AddColumnShort(NPIX, "StartCellData", "uint16", "DRS4 start cell of readout");
42 fFile->AddColumnShort(NTMARK, "StartCellTimeMarker", "uint16", "DRS4 start cell of readout time marker");
43
44 vector<uint16_t> processing(2);
45 processing[0] = FITS::kFactSmoothing;
46 processing[1] = FITS::kFactHuffman16;
47
48 const FITS::Compression comp(processing, FITS::kOrderByRow);
49
50 fFile->AddColumnShort(comp, h.NPix*h.Nroi, "Data", "int16", "Digitized data");
51 fFile->AddColumnShort(comp, h.NTm*realRoiTM, "TimeMarker", "int16", "Digitized time marker - if available");
52
53 const size_t sz = (h.NPix*h.Nroi + h.NTm*realRoiTM)*2;
54 if (fFile->GetBytesPerRow()-sz+4!=sizeof(EVENT))
55 {
56 ostringstream str;
57 str << "The EVENT structure size (" << sizeof(EVENT) << ") doesn't match the described FITS row (";
58 str << fFile->GetBytesPerRow()-sz+4 << ")";
59 throw runtime_error(str.str());
60 }
61
62 // =============== Default keys for all files ================
63 fFile->SetDefaultKeys();
64 fFile->SetInt("NIGHT", GetNight(), "Night as int");
65#ifdef HAVE_NOVA
66 fFile->SetStr("OBSERVAT", Nova::LnLatPosn::preset(), "Observatory name (see nova.h)");
67#endif
68
69 // ================ Header keys for raw-data =================
70 fFile->SetInt("BLDVER", h.Version, "Builder version");
71 fFile->SetInt("RUNID", GetRunId(), "Run number");
72 fFile->SetInt("NBOARD", h.NBoard, "Number of acquisition boards");
73 fFile->SetInt("NPIX", h.NPix, "Number of pixels");
74 fFile->SetInt("NTMARK", h.NTm, "Number of time marker channels");
75 fFile->SetInt("NCELLS", 1024, "Maximum number of slices per pixels");
76 fFile->SetInt("NROI", h.Nroi, "Number of slices per pixels");
77 fFile->SetInt("NROITM", realRoiTM, "Number of slices per time-marker");
78
79 const uint16_t realOffset = (h.NroiTM > h.Nroi) ? h.NroiTM - 2*h.Nroi : 0;
80 fFile->SetInt("TMSHIFT", realOffset, "Shift of marker readout w.r.t. to data");
81
82 //FIXME should we also put the start and stop time of the received data ?
83 //now the events header related variables
84 fFile->SetStr("CAMERA", "MGeomCamFACT", "MARS camera geometry class");
85 fFile->SetStr("DAQ", "DRS4", "Data acquisition type");
86 fFile->SetInt("ADCRANGE", 2000, "Dynamic range in mV");
87 fFile->SetInt("ADC", 12, "Resolution in bits");
88 fFile->SetStr("RUNTYPE", d.name, "File type according to FAD configuration");
89
90 // Write a single key for:
91 // -----------------------
92 // Start package flag
93 // package length
94 // version number
95 // status
96 // Prescaler
97
98 // Write 40 keys for (?)
99 // Phaseshift
100 // DAC
101
102 for (int i=0; i<h.NBoard; i++)
103 {
104 const PEVNT_HEADER &hh = h.FADhead[i];
105
106 ostringstream sout;
107 sout << "Board " << setw(2) << i<< ": ";
108
109 const string num = to_string(i);
110
111 // Header values whihc won't change during the run
112 fFile->SetInt("ID"+num, hh.board_id, sout.str()+"Board ID");
113 fFile->SetInt("FWVER"+num, hh.version_no, sout.str()+"Firmware Version");
114 fFile->SetHex("DNA"+num, hh.DNA, sout.str()+"Unique FPGA device identifier (DNA)");
115 }
116
117 // FIXME: Calculate average ref clock frequency
118 for (int i=0; i<h.NBoard; i++)
119 {
120 const PEVNT_HEADER &hh = h.FADhead[i];
121 if (hh.start_package_flag==0)
122 continue;
123
124 fFile->SetInt("BOARD", i, "Board number for RUN, PRESC, PHASE and DAC");
125 fFile->SetInt("PRESC", hh.trigger_generator_prescaler, "Trigger generator prescaler");
126 fFile->SetInt("PHASE", (int16_t)hh.adc_clock_phase_shift, "ADC clock phase shift");
127
128 for (int j=0; j<8; j++)
129 {
130 ostringstream dac, cmt;
131 dac << "DAC" << j;
132 cmt << "Command value for " << dac.str();
133 fFile->SetInt(dac.str(), hh.dac[j], cmt.str());
134 }
135
136 break;
137 }
138
139 double avg = 0;
140 int cnt = 0;
141 for (int i=0; i<h.NBoard; i++)
142 {
143 const PEVNT_HEADER &hh = h.FADhead[i];
144
145 if (hh.start_package_flag==0)
146 continue;
147
148 avg += hh.REFCLK_frequency;
149 cnt ++;
150 }
151
152 // FIXME: I cannot write a double! WHY?
153 fFile->SetFloat("REFCLK", avg/cnt*2.048, "Average reference clock frequency in Hz");
154
155 fFile->SetBool("DRSCALIB", GetDrsStep()>=0, "This file belongs to a DRS calibration");
156 if (GetDrsStep()>=0)
157 fFile->SetInt("DRSSTEP", GetDrsStep(), "Step of the DRS calibration");
158
159 fTstart[0] = h.RunTime;
160 fTstart[1] = h.RunUsec;
161
162 fTstop[0] = 0;
163 fTstop[1] = 0;
164
165 fTriggerCounter.fill(0);
166
167 WriteFooter();
168
169 fFile->WriteTableHeader("Events");
170};
171
172// --------------------------------------------------------------------------
173//
174//! DataWriteFits constructor. This is the one that should be used, not the default one (parameter-less)
175//! @param runid This parameter should probably be removed. I first thought it was the run number, but apparently it is not
176//! @param h a pointer to the RUN_HEAD structure that contains the informations relative to this run
177//
178bool DataWriteFits2::Open(const RUN_HEAD &h, const FAD::RunDescription &d)
179{
180 //Form filename, based on runid and run-type
181 fFileName = FormFileName(dynamic_pointer_cast<factofits>(fFile)?"fits.fz":"fits");
182
183 if (boost::filesystem::exists(fFileName))
184 {
185 Error("ofits - file '"+fFileName+"' already exists.");
186 return false;
187 }
188
189 zofits *fits = dynamic_cast<zofits*>(fFile.get());
190 if (fits)
191 {
192 const uint32_t nrpt = zofits::DefaultNumRowsPerTile();
193
194 // Maximum number of events if taken with 100Hz
195 // (If no limit requested, maxtime is 24*60*60)
196 const uint32_t ntime = d.maxtime*100/nrpt;
197
198 // Maximum number of events if taken as number
199 // (If no limit requested, maxevts is INT32_MAX)
200 const uint32_t nevts = d.maxevt/nrpt+1;
201
202 // get the minimum of all three
203 uint32_t num = zofits::DefaultMaxNumTiles();
204 if (ntime<num)
205 num = ntime;
206 if (nevts<num)
207 num = nevts;
208
209 fits->SetNumTiles(num);
210 }
211
212 try
213 {
214 fFile->open(fFileName.c_str());
215 }
216 catch (const exception &e)
217 {
218 Error("ofits::open() failed for '"+fFileName+"': "+e.what());
219 return false;
220 }
221
222 if (!(*fFile))
223 {
224 ostringstream str;
225 str << "ofstream::open() failed for '" << fFileName << "': " << strerror(errno) << " [errno=" << errno << "]";
226 Error(str);
227 return false;
228 }
229
230 try
231 {
232 WriteHeader(h, d);
233 }
234 catch (const exception &e)
235 {
236 Error("ofits - Writing header failed for '"+fFileName+"': "+e.what());
237 return false;
238 }
239
240 if (!(*fFile))
241 {
242 ostringstream str;
243 str << "ofstream::write() failed for '" << fFileName << "': " << strerror(errno) << " [errno=" << errno << "]";
244 Error(str);
245 return false;
246 }
247
248 return true;
249}
250
251// --------------------------------------------------------------------------
252//
253//! This writes one event to the file
254//! @param e the pointer to the EVENT
255//
256bool DataWriteFits2::WriteEvt(const EVT_CTRL2 &evt)
257{
258 // Remember the counter of the last written event
259 fTriggerCounter = evt.triggerCounter;
260
261 // Remember the time of the last event
262 fTstop[0] = evt.time.tv_sec;
263 fTstop[1] = evt.time.tv_usec;
264
265 const EVENT &e = *evt.fEvent;
266
267 const int realRoiTM = (e.RoiTM > e.Roi) ? e.Roi : 0;
268 const size_t sz = sizeof(EVENT) + sizeof(e.StartPix)*e.Roi+sizeof(e.StartTM)*realRoiTM; //ETIENNE from RoiTm to Roi
269
270 try
271 {
272 fFile->WriteRow(reinterpret_cast<const char*>(&e)+4, sz-4);
273 }
274 catch (const exception &ex)
275 {
276 Error("ofits::WriteRow failed for '"+fFileName+"': "+ex.what());
277 return false;
278 }
279
280 if (!(*fFile))
281 {
282 ostringstream str;
283 str << "fstream::write() failed for '" << fFileName << "': " << strerror(errno) << " [errno=" << errno << "]";
284 Error(str);
285 return false;
286 }
287
288 return true;
289}
290
291void DataWriteFits2::WriteFooter()
292{
293 //FIXME shouldn't we convert start and stop time to MjD first ?
294 //FIXME shouldn't we also add an MjD reference ?
295
296 const Time start(fTstart[0], fTstart[1]);
297 const Time stop (fTstop[0], fTstop[1]);
298
299 fFile->SetInt("TSTARTI", uint32_t(floor(start.UnixDate())),
300 "Time when first evt received (integral part)");
301 fFile->SetFloat("TSTARTF", fmod(start.UnixDate(), 1),
302 "Time when first evt received (fractional part)");
303 fFile->SetInt("TSTOPI", uint32_t(floor(stop.UnixDate())),
304 "Time when last evt received (integral part)");
305 fFile->SetFloat("TSTOPF", fmod(stop.UnixDate(), 1),
306 "Time when last evt received (fractional part)");
307 fFile->SetStr("DATE-OBS", start.Iso(),
308 "Time when first event received");
309 fFile->SetStr("DATE-END", stop.Iso(),
310 "Time when last event received");
311
312 fFile->SetInt("NTRG", fTriggerCounter[0], "No of physics triggered events");
313 fFile->SetInt("NTRGPED", fTriggerCounter[1], "No of pure pedestal triggered events");
314 fFile->SetInt("NTRGLPE", fTriggerCounter[2], "No of external light pulser triggered events");
315 fFile->SetInt("NTRGTIM", fTriggerCounter[3], "No of time calibration triggered events");
316 fFile->SetInt("NTRGLPI", fTriggerCounter[4], "No of internal light pulser triggered events");
317 fFile->SetInt("NTRGEXT1", fTriggerCounter[5], "No of triggers from ext1 triggered events");
318 fFile->SetInt("NTRGEXT2", fTriggerCounter[6], "No of triggers from ext2 triggered events");
319 fFile->SetInt("NTRGMISC", fTriggerCounter[7], "No of all other triggered events");
320}
321
322// --------------------------------------------------------------------------
323//
324//! Closes the file, and before this it write the TAIL data
325//! @param rt the pointer to the RUN_TAIL data structure
326//
327bool DataWriteFits2::Close(const EVT_CTRL2 &)
328{
329 if (!fFile->is_open())
330 {
331 Error("DataWriteFits2::Close() called but file '"+fFileName+"' not open.");
332 return false;
333 }
334
335 try
336 {
337 WriteFooter();
338 }
339 catch (const exception &e)
340 {
341 Error("ofits - Setting footer key values failed for '"+fFileName+"': "+e.what());
342 return false;
343 }
344
345 try
346 {
347 fFile->close();
348 }
349 catch (const exception &e)
350 {
351 Error("ofits::close() failed for '"+fFileName+"': "+e.what());
352 return false;
353 }
354
355 if (!(*fFile))
356 {
357 ostringstream str;
358 str << "ofstream::close() failed for '" << fFileName << "': " << strerror(errno) << " [errno=" << errno << "]";
359 Error(str);
360 return false;
361 }
362
363 return true;
364}
Note: See TracBrowser for help on using the repository browser.