REASH5File.cc
Go to the documentation of this file.
1 
9 #include "REASH5File.h"
10 
11 #include <evt/Event.h>
12 #include <evt/ShowerSimData.h>
13 #include <evt/SimRadioPulse.h>
14 #include <evt/RadioSimulation.h>
15 
16 #include <fwk/CoordinateSystemRegistry.h>
17 
18 #include <io/CorsikaUtilities.h>
19 #include <io/CorsikaShowerFile.h>
20 #include <io/REASH5File.h>
21 #include <io/REASIOException.h>
22 
23 #include <utl/AugerUnits.h>
24 #include <utl/ErrorLogger.h>
25 #include <utl/PhysicalConstants.h>
26 #include <utl/TimeStamp.h>
27 #include <utl/CoordinateSystem.h>
28 #include <utl/Point.h>
29 #include <utl/ReferenceEllipsoid.h>
30 #include <utl/UTMPoint.h>
31 #include <utl/UTCDateTime.h>
32 #include <utl/System.h>
33 #include <utl/Math.h>
34 
35 #include <det/Detector.h>
36 
37 #include <boost/lexical_cast.hpp>
38 
39 #include <cmath>
40 #include <cstdlib>
41 #include <dirent.h>
42 #include <iostream>
43 #include <iomanip>
44 #include <sstream>
45 #include <string.h>
46 #include <unistd.h>
47 #include <cstring>
48 
49 #include "H5Cpp.h"
50 
51 using namespace H5;
52 
53 using namespace utl;
54 using namespace evt;
55 using namespace revt;
56 using namespace io;
57 
58 using std::string;
59 using std::stringstream;
60 using std::ostringstream;
61 using std::istringstream;
62 using std::ifstream;
63 using std::vector;
64 using utl::micro; // also in std:: !!
65 
66 
67 namespace io {
68 
69  struct opdata {
73  };
74 
75 
76  // operator function
77  extern "C"
78  herr_t
79  REASH5File::AddObserver(hid_t loc_id, const char* const name, void* const operator_data)
80  {
81  opdata* const od = (opdata*)operator_data;
82  H5G_stat_t statbuf;
83 
84  /* Get type of the object and display its name and type.
85  * The name of the object is passed to this function by
86  * the Library. Some magic :-) */
87  H5Gget_objinfo(loc_id, name, false, &statbuf);
88  if (statbuf.type == H5G_DATASET) {
89  hid_t dataset_id = H5Dopen1(loc_id, name);
90  DataSet dataset(dataset_id);
91  Attribute position = dataset.openAttribute("position");
92  DataType type = position.getDataType();
93  double tmp[3] = { 0 };
94  position.read(type, &tmp);
95  // derotate antenna coordinates according to magnetic field declination
96  double rotX = cos(-od->magneticfielddeclination) * tmp[0] - sin(-od->magneticfielddeclination) * tmp[1];
97  double rotY = sin(-od->magneticfielddeclination) * tmp[0] + cos(-od->magneticfielddeclination) * tmp[1];
98  rotX *= cm; // REAS distances are given in cm
99  rotY *= cm; // REAS distances are given in cm
100  double zpos = tmp[2];
101  zpos *= cm; // REAS distances are given in cm
102  SimRadioPulse currpulse;
103  currpulse.SetRelativeCoordinates(-rotY, rotX, zpos - od->corecoordinateverticalinreassim); // set as east, north, vertical
104  TraceV3D& currtimeseries = currpulse.GetEfieldTimeSeries();
105 
106  DataSpace dataspace = dataset.getSpace();
107  // Get the number of dimensions in the dataspace.
108  // int rank = dataspace.getSimpleExtentNdims();
109  // Get the dimension size of each dimension in the dataspace and display them.
110  hsize_t dims_out[2] = { 0 };
111  /*int ndims =*/ dataspace.getSimpleExtentDims(dims_out, nullptr);
112  double data_out[dims_out[0]][dims_out[1]]; /* output buffer */
113 
114  dataset.read(data_out, PredType::NATIVE_DOUBLE, H5S_ALL, H5S_ALL);
115 
116  const double timestamp = data_out[0][0];
117  currpulse.SetStartTime(timestamp * second);
118 
119  double efield[3];
120  double rotefield[3];
121  double finalefield[3];
122  for (unsigned int j = 0; j < dims_out[0]; ++j) {
123 
124  const double conv = 2.99792458e10 * micro * volt / meter; // conversion from cgs units to microVolt/meter
125  efield[0] = data_out[j][1] * conv;
126  efield[1] = data_out[j][2] * conv;
127  efield[2] = data_out[j][3] * conv;
128 
129  // derotate the electric field for the magnetic field declination
130  rotefield[0] = cos(-od->magneticfielddeclination) * efield[0] - sin(-od->magneticfielddeclination) * efield[1];
131  rotefield[1] = sin(-od->magneticfielddeclination) * efield[0] + cos(-od->magneticfielddeclination) * efield[1];
132  rotefield[2] = efield[2];
133 
134  // construct a vector according to east, north, vertical convention of Offline
135  finalefield[0] = -rotefield[1];
136  finalefield[1] = rotefield[0];
137  finalefield[2] = rotefield[2];
138 
139  currtimeseries.PushBack(Vector3D(finalefield));
140  }
141 
142  currpulse.SetBinning(
143  (data_out[dims_out[0] - 1][0] * second - currpulse.GetStartTime()) /
144  double(currtimeseries.GetSize() - 1)
145  );
146 
147  od->radiosim->AddSimRadioPulse(currpulse);
148  }
149  return 0;
150  }
151 
152 
153  REASH5File::REASH5File(const std::string& fileName, const Mode mode, utl::Branch* const b) :
154  VEventFile(fileName, mode)
155  {
156  Open(fileName, mode, b);
157  }
158 
159 
161  {
162  //delete fReasH5;
163  delete fCorsikaShowerFile;
164  }
165 
166 
167  void
168  REASH5File::Open(const std::string& fileName, const Mode mode, utl::Branch* const /*b*/)
169  {
170  // make a copy of the file name, we might have to update it
171  const std::string ourFileName = fileName;
172 
173  if (mode != eRead) {
174  ostringstream msg;
175  msg << "Cannot open file " << fileName << " - REAS-H5 files are read-only";
176  ERROR(msg);
177  throw io::REASIOException(msg.str());
178  }
179 
180  fReasH5 = H5File(ourFileName.c_str(), H5F_ACC_RDONLY);
181  //if (!*fReasH5) {
182  // ostringstream msg;
183  // msg << "Cannot open file " << ourFileName << " - ERROR";
184  // ERROR(msg);
185  // throw io::REASIOException(msg.str());
186  //}
187 
188  ostringstream info;
189  info << "(Co)REAS simulation " << ourFileName << '\n';
190  INFO(info);
191 
192  const string basename = ourFileName.substr(0, ourFileName.size() - 5); // strip of extension ".reas"
193  const size_t pathlength = ourFileName.find_last_of("/"); // find last slash
194  string pathname;
195  string simname;
196 
197  if (pathlength >= ourFileName.size()) {
198  pathname = "./";
199  simname = basename;
200  } else {
201  pathname = ourFileName.substr(0, pathlength) + "/";
202  simname = basename.substr(pathname.size(), basename.size() - pathlength);
203  }
204 
205  // save the current directory
206  const unsigned int bufsize = 1024;
207  char dirbuf[bufsize];
208  if (!getcwd(dirbuf, bufsize)) {
209  ostringstream msg;
210  msg << "Buffer too small for reading out path.";
211  ERROR(msg);
212  throw io::REASIOException(msg.str());
213  }
214  fOrigDirectory = string(dirbuf);
215 
216  // save the REAS directory
217  fReasDirectory = pathname;
218  }
219 
220 
221  void
223  {
224  fReasH5.close();
225  if (fCorsikaShowerFile) {
227  delete fCorsikaShowerFile;
228  fCorsikaShowerFile = nullptr;
229  }
230  }
231 
232 
233  Status
235  {
236  // test if there are any more events in this file to read
237  if (fCurrentPosition >= (unsigned int)GetNEvents())
238  return eEOF;
239 
240  // change to directory with .reas file, should check for errors?
241  //std::cout << " dir " << fReasDirectory << std::endl;
242  int chdirerror = chdir(fReasDirectory.c_str());
243  if (chdirerror) {
244  ostringstream msg;
245  msg << "Unable to change to directory " << fReasDirectory;
246  ERROR(msg);
247  throw io::REASIOException(msg.str());
248  }
249 
250  INFO("Reading in CoREASH5File");
251 
252  if (event.HasSimShower()) {
253  ERROR("Event not cleared - has SimShower. Cannot read REASFile.");
254  return eFail;
255  }
256 
257  long selectedcorsikashower = 1;
258  //TimeStamp event_timestamp;
259  //string event_timestamp_str;
260 
261  //cout << "opening group CoREAS" << endl;
262  H5::Group group_coreas(fReasH5.openGroup("/CoREAS"));
263 
264  double corecoordinateverticalinreassim = ReadAttribute<double>(group_coreas, "CoreCoordinateVertical");
265  corecoordinateverticalinreassim *= utl::cm;
266  double corecoordinatenorthinreassim = ReadAttribute<double>(group_coreas, "CoreCoordinateNorth");
267  corecoordinatenorthinreassim *= utl::cm;
268  double corecoordinatewestinreassim = ReadAttribute<double>(group_coreas, "CoreCoordinateWest");
269  corecoordinatewestinreassim *= utl::cm;
270 
271  const string corsikafilepath = ReadAttribute<const char*>(group_coreas, "CorsikaFilePath");
272  const string corsikaparamfile = ReadAttribute<const char*>(group_coreas, "CorsikaParameterFile");
273 
274  const int runnumber = ReadAttribute<int>(group_coreas, "RunNumber");
275  const int eventnumber = ReadAttribute<int>(group_coreas, "EventNumber");
276 
277  unsigned int gpssecs = ReadAttribute<int>(group_coreas, "GPSSecs");
278  unsigned int gpsnanosecs = ReadAttribute<int>(group_coreas, "GPSNanoSecs");
279 
280  double corecoordinateeastinaugercs = ReadAttribute<double>(group_coreas, "CoreEastingOffline");
281  corecoordinateeastinaugercs *= utl::meter;
282  double corecoordinatenorthinaugercs = ReadAttribute<double>(group_coreas, "CoreNorthingOffline");
283  corecoordinatenorthinaugercs *= utl::meter;
284  double corecoordinateverticalinaugercs = ReadAttribute<double>(group_coreas, "CoreVerticalOffline");
285  corecoordinateverticalinaugercs *= utl::meter;
286 
287  // check for consistency of local core position in new conversion
288  if (corecoordinatenorthinreassim || corecoordinatewestinreassim) {
289  const string msg = "(Co)REAS local coordinate system has to be anchored at (0,0,z) "
290  "but the x and/or y coordinate is not 0";
291  ERROR(msg);
292  throw io::REASIOException(msg);
293  }
294 
295  double magneticfielddeclination = ReadAttribute<double>(group_coreas, "RotationAngleForMagfieldDeclination");
296  magneticfielddeclination *= degree;
297 
298  double distanceofshowermax = ReadAttribute<double>(group_coreas, "DistanceOfShowerMaximum");
299  distanceofshowermax *= utl::cm;
300 
301  // set the event (not revent) id
302  ostringstream tmpout;
303  tmpout << "(Co)REAS_r" << runnumber << "_e" << eventnumber;
304  event.GetHeader().SetId(tmpout.str());
305 
306  string offlineCoordinateSystem("Reference");
307  if (group_coreas.attrExists("OfflineCoordinateSystem")) { // OfflineCoordinateSystem optinal entry
308  offlineCoordinateSystem = ReadAttribute<const char*>(group_coreas, "OfflineCoordinateSystem");
309  }
310  const CoordinateSystemPtr cs = (offlineCoordinateSystem == "Reference") ?
311  det::Detector::GetInstance().GetReferenceCoordinateSystem() :
312  fwk::CoordinateSystemRegistry::Get(offlineCoordinateSystem);
313 
314  const Point core(corecoordinateeastinaugercs, corecoordinatenorthinaugercs,
315  corecoordinateverticalinaugercs, cs);
316 
317  // Second call the CorsikaShowerFile::Read function. This will initialize the SimShower and read all available data: geometry, longitudinal data, ground particles, etc.
318  // now use CORSIKA shower file reader to import shower geometry, longitudinal and, if available, particle file
319  // beware: REASFile reader currently has very inefficient strategy for importing CORSIKA files with multiple simulations
320  // explanation: calls of CorsikaShowerFile::Open() re-reads in particle file on each call
321 
322  // check if an open CorsikaShowerFile exists, if so close it
323  if (fCorsikaShowerFile) {
325  delete fCorsikaShowerFile;
326  fCorsikaShowerFile = nullptr;
327  }
328 
329  fCorsikaShowerFile = new CorsikaShowerFile(corsikafilepath+corsikaparamfile, eRead);
330  fCorsikaShowerFile->SetMagneticFieldDeclination(-magneticfielddeclination); // this is WEST=-EAST convention
331 
332  bool corsikaazimuth = true; // default case (only case for REAS3) is use of corsika azimuth also in REAS
333 
334  if (eSuccess == fCorsikaShowerFile->GotoPosition(selectedcorsikashower - 1)) { // is the CORSIKA position really counted from zero here or from one (as in REAS)?
335  if (eSuccess == fCorsikaShowerFile->Read(event)) { // read in particle file
336  if (!corsikaazimuth) {
337  const string msg = "REAS simulations with particle file must not have azimuth override set";
338  ERROR(msg);
339  throw io::REASIOException(msg);
340  }
341  #warning RU: the following check is logical not 100% identical to before
342  if (selectedcorsikashower != 1) {
343  const string msg =
344  "(Co)REAS simulations without particle file must not have "
345  "multiple CORSIKA simulations in one CORSIKA run";
346  ERROR(msg);
347  throw io::REASIOException(msg);
348  }
349  }
350  } else {
351  const string msg =
352  "(Co)REAS simulations could not initialize sim shower. No CORSIKA files found";
353  ERROR(msg);
354  throw io::REASIOException(msg);
355  }
356  // finished reading CORSIKA basic data
357  // now the SimShower is initialized
358 
359  ShowerSimData& shower = event.GetSimShower();
360  shower.SetMagneticFieldDeclination(-magneticfielddeclination); // yes, since we want "WEST=-EAST" angle
361  shower.SetShowerNumber(selectedcorsikashower); // from REAS
362  shower.SetDistanceOfShowerMaximum(distanceofshowermax); // from REAS
363 
364  if (shower.HasRadioSimulation()) {
365  //fixme TH: need proper error handling if radio simulation already present
366  WARNING("Event not cleared - has RadioSimulation");
367  // what is the consequence of this? could lead to multiple antenna pulses for same positions!?
368  } else
369  shower.MakeRadioSimulation();
370 
371  RadioSimulation& radiosim = shower.GetRadioSimulation();
372 
373  radiosim.SetCorePosition(core);
374  //std::cout << "setting core position to " << core.GetX(cs) << ", " << core.GetY(cs) << ", "
375  // << core.GetZ(cs) << " in coordinate system " << OfflineCoordinateSystem << std::endl;
376 
377  // CORSIKA read-in is done, set event number and time stamp of the radio simulation
378  radiosim.SetEventNumber(eventnumber);
379  radiosim.SetRunNumber(runnumber);
380  if (gpssecs || gpsnanosecs)
381  radiosim.SetEventTime(TimeStamp(gpssecs, gpsnanosecs));
382 
383  struct opdata oooptdata;
384  oooptdata.corecoordinateverticalinreassim = corecoordinateverticalinreassim;
385  oooptdata.magneticfielddeclination = magneticfielddeclination;
386  oooptdata.radiosim = &radiosim;
387  H5Giterate(fReasH5.getId(), "/CoREAS/observers/", nullptr, AddObserver, (void*)&oooptdata);
389 
390  chdirerror = chdir(fOrigDirectory.c_str()); // change back to original directory
391  if (chdirerror) {
392  ostringstream msg;
393  msg << "Unable to change to directory " << fOrigDirectory;
394  ERROR(msg);
395  throw io::REASIOException(msg.str());
396  }
397 
398  return eSuccess;
399  }
400 
401 
402  void
403  REASH5File::Write(const evt::Event& /*event*/)
404  {
405  const string msg = "Cannot write to REASH5File - read-only file";
406  ERROR(msg);
407  throw io::REASIOException(msg);
408  }
409 
410 
411  Status
412  REASH5File::FindEvent(const unsigned int eventId)
413  {
414  // REAS shower don't have event ids
415  return GotoPosition(eventId);
416  }
417 
418 
419  Status
420  REASH5File::GotoPosition(const unsigned int position)
421  {
422  if (position > (unsigned int) GetNEvents())
423  return eFail;
424  else {
425  //fCurrentPosition = position;
426  return eSuccess;
427  }
428  }
429 
430 
431  /*
432  int
433  REASH5File::NextEntry()
434  {
435  ++fCurrentPosition;
436  return fCurrentPosition - 1;
437  }
438  */
439 
440 
441  int
443  {
444  return 1; // there is currently one event in a REAS file (hard-coded)
445  /*if (fShowerTree)
446  return int(fShowerTree->GetEntries());
447  else {
448  string msg = "Cannot request number of events from NULL tree";
449  ERROR(msg);
450  throw REASIOException(msg);
451  }*/
452  }
453 
454 }
Status Read(evt::Event &event) override
read current event advance cursor by 1
Definition: REASH5File.cc:234
Status Read(evt::Event &event) override
read current event advance cursor by 1
void SetCorePosition(const utl::Point &core)
Set the core position of the RadioSimulation using an utl::Point.
void SetMagneticFieldDeclination(const double magneticFieldDeclination)
Set the declination of the Earth&#39;s magnetic field used in CORSIKA/REAS simulation.
double magneticfielddeclination
Definition: REASH5File.cc:70
const double degree
Point object.
Definition: Point.h:32
static herr_t AddObserver(hid_t loc_id, const char *const name, void *const operator_data)
Definition: REASH5File.cc:79
void SetStartTime(const double starttime)
Definition: SimRadioPulse.h:41
void MakeRadioSimulation()
Make the RadioSimulation.
Data structure for simulated Radio pulses.
Definition: SimRadioPulse.h:29
bool HasSimShower() const
Data structure for a radio simulation (including several SimRadioPulses)
void SetBinning(const double samplingtime)
Definition: SimRadioPulse.h:36
Mode
Available open modes.
Definition: IoCodes.h:16
const double meter
Definition: GalacticUnits.h:29
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
bool HasRadioSimulation() const
Check initialization of the RadioSimulation.
utl::SVector< 3, double > Vector3D
Definition: Trace-fwd.h:32
void SetRunNumber(const int runnum)
Set the run number of the RadioSimulation.
unsigned int fCurrentPosition
Definition: REASH5File.h:68
Status GotoPosition(const unsigned int position) override
goto by position in the file
CorsikaShowerFile * fCorsikaShowerFile
Definition: REASH5File.h:74
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
void SetEventNumber(const int eventnum)
Set the event number of the RadioSimulation.
Interface class to access Shower Simulated parameters.
Definition: ShowerSimData.h:49
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Class representing a document branch.
Definition: Branch.h:107
Status
Return code for seek operation.
Definition: IoCodes.h:24
void SetMagneticFieldDeclination(const double d)
void SetEventTime(const utl::TimeStamp &t)
Set the event time of the RadioSimulation.
RadioSimulation & GetRadioSimulation()
Get the radio simulation data.
virtual ~REASH5File()
Definition: REASH5File.cc:160
const double second
Definition: GalacticUnits.h:32
constexpr double meter
Definition: AugerUnits.h:81
Base for exceptions in the REAS reader.
Read data from the output of CORSIKA.
SizeType GetSize() const
Definition: Trace.h:156
double corecoordinateverticalinreassim
Definition: REASH5File.cc:71
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
void AddSimRadioPulse(const SimRadioPulse &rp)
Add a radio pulse to the RadioSimulation.
std::string fReasDirectory
Definition: REASH5File.h:72
Template class for a FADC data or calibrated data container. Use the typedefs (TraceD, TraceI, etc.) defined in Trace-fwd.h.
Definition: Trace-fwd.h:19
void SetRelativeCoordinates(double northing, double easting, double height)
Definition: SimRadioPulse.h:56
void SetShowerNumber(const int sid)
Definition: ShowerSimData.h:75
constexpr double cm
Definition: AugerUnits.h:117
void SetDistanceOfShowerMaximum(const double parDistance)
Set the geometrical distance of the shower maximum from the core.
constexpr double micro
Definition: AugerUnits.h:65
void Close() override
Definition: REASH5File.cc:222
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
H5::H5File fReasH5
Definition: REASH5File.h:70
RadioSimulation * radiosim
Definition: REASH5File.cc:72
void Write(const evt::Event &event) override
Definition: REASH5File.cc:403
void PushBack(const T &value)
Insert a single value at the end.
Definition: Trace.h:119
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
const utl::TraceV3D & GetEfieldTimeSeries() const
Get the Trace of the simulated electric field.
Definition: SimRadioPulse.h:44
int GetNEvents() override
Definition: REASH5File.cc:442
Status FindEvent(const unsigned int eventId) override
seek Event id set cursor there
Definition: REASH5File.cc:412
const double volt
Definition: GalacticUnits.h:38
double GetStartTime() const
Get the timestamp of the first sample.
Definition: SimRadioPulse.h:39
void Open(const std::string &fileName, const Mode mode=eRead, utl::Branch *const b=nullptr) override
Definition: REASH5File.cc:168
Status GotoPosition(const unsigned int position) override
goto by position in the file
Definition: REASH5File.cc:420
std::string fOrigDirectory
Definition: REASH5File.h:71

, generated on Tue Sep 26 2023.