12 #include <io/CorsikaShowerFile.h>
13 #include <io/CorsikaShowerFileParticleIterator.h>
14 #include <io/CorsikaShowerFileGeometryProducer.h>
15 #include <io/CorsikaIOException.h>
16 #include <io/RawCorsikaFile.h>
17 #include <io/CorsikaBlock.h>
18 #include <io/CorsikaUtilities.h>
20 #include <evt/Event.h>
21 #include <evt/ShowerSimData.h>
22 #include <evt/GaisserHillas6Parameter.h>
23 #include <evt/AtmosphereParameters.h>
24 #include <evt/DefaultShowerGeometryProducer.h>
26 #include <utl/TabularStream.h>
27 #include <utl/ErrorLogger.h>
28 #include <utl/AugerUnits.h>
29 #include <utl/TabulatedFunction.h>
30 #include <utl/MathConstants.h>
32 #include <utl/PhysicalConstants.h>
33 #include <utl/PhysicalFunctions.h>
34 #include <utl/Reader.h>
35 #include <utl/String.h>
36 #include <utl/VParticleProperties.h>
37 #include <utl/ShowerParticleList.h>
38 #include <utl/ParticlePropertiesFactory.h>
39 #include <utl/Point.h>
40 #include <utl/UTMPoint.h>
42 #include <fwk/CentralConfig.h>
43 #include <fwk/CoordinateSystemRegistry.h>
45 #include <boost/format.hpp>
46 #include <boost/lexical_cast.hpp>
47 #include <boost/algorithm/string/trim.hpp>
48 #include <boost/algorithm/string/replace.hpp>
49 #include <boost/algorithm/string.hpp>
50 #include <boost/algorithm/string/case_conv.hpp>
51 #include <boost/filesystem.hpp>
52 #include <boost/regex.hpp>
69 using std::ostringstream;
70 using std::stringstream;
98 const double xm0 = xmax - x0;
99 return dEdXmax *
pow((x - x0) / xm0, xm0 / lambda) * exp((xmax - x)/lambda);
110 const double dEdXmax = par[0];
111 const double x0 = par[1];
112 const double xMax = par[2];
113 const double lambda = par[3];
115 for (
unsigned int i = 0, n =
GHFit::gProfile.fSlantDepth.size(); i < n; ++i) {
120 const double residual = dEdX - dEdXFct;
121 chi2 +=
Sqr(residual);
134 return str.find(what) != string::npos;
140 const unsigned int nColumns,
141 const unsigned int firstColumnWidth,
const unsigned int columnWidth)
143 using boost::algorithm::trim;
145 if (!nColumns || line.length() != firstColumnWidth + (nColumns - 1)*columnWidth) {
146 const string err =
"Line is too short to fix it.";
150 vector<string> res(nColumns);
151 res[0] = line.substr(0, firstColumnWidth);
153 unsigned int pos = firstColumnWidth;
154 for (
unsigned int i = 1; i < nColumns; ++i) {
155 res[i] = line.substr(pos, columnWidth);
165 delete fParticleIterator;
173 if (!branch || !*branch) {
174 WARNING(
"No Branch was passed for configuration.");
176 fObservationLevel = 1;
177 if (branch->
GetChild(
"CorsikaObservationLevel"))
178 branch->
GetChild(
"CorsikaObservationLevel").
GetData(fObservationLevel);
179 if (fObservationLevel < 1 || fObservationLevel > 10) {
181 err <<
"CORSIKA observation level must be within [1,10] and " << fObservationLevel <<
" is not allowed";
186 info <<
"Reading particles at observation level: " << fObservationLevel;
190 if (branch->
GetChild(
"UseRealisticMagneticDeclination"))
191 branch->
GetChild(
"UseRealisticMagneticDeclination").
GetData(fUseRealisticMagneticDeclination);
192 info <<
"Using magnetic field declination from time-dependent model "
193 "(If False, a hardcoded value (-4.233 deg) is taken or the value"
194 " specified in the .reas file (if used)): "
195 << fUseRealisticMagneticDeclination;
200 fRefCoordinateSystemName = bRef.
Get<
string>();
202 inf <<
"Core reference system: " << fRefCoordinateSystemName;
208 info <<
"Multi-core selection: ";
209 string entry = bMulti.
Get<
string>();
211 if (boost::to_lower_copy(entry) ==
"all") {
215 vector<string> range;
216 boost::split(strs, entry, boost::is_any_of(
","));
218 for (
const auto& it : strs) {
219 boost::split(range, it, boost::is_any_of(
"-"));
220 auto x = range.begin();
221 const int low = boost::lexical_cast<
int>(range[0]);
224 if (x != range.end())
225 high = boost::lexical_cast<int>(range[1]);
226 for (
int i = low; i <=
high; ++i) {
228 const string err =
"CORIKSA (multi) core counting start at 1.";
232 fMultiCoreSelection.push_back(i);
241 Open(fileName, mode, branch);
250 if (fRawFile.IsOpen())
252 for (
auto& cherFile : fCherenkovFile)
253 if (cherFile.second.IsOpen())
254 cherFile.second.Close();
257 const string msg =
"Cannot open file '" + fileName +
"' - Corsika files are read-only";
262 fOpenedAnything =
false;
263 bool foundShowerDefinition =
false;
268 warn <<
"No Branch was passed for configuration. Try to open file(s) based on " << fileName <<
".";
272 string base = fileName.substr(0, fileName.rfind(
"."));
273 boost::replace_last(base,
"RUN",
"DAT");
274 boost::replace_last(base,
"SIM",
"DAT");
276 if (ScanGroundFile(base, fRawFile, fPositionToRaw, fPositionOfEventTrailer, !foundShowerDefinition,
true) ==
eSuccess) {
277 foundShowerDefinition =
true;
278 fOpenedAnything =
true;
279 INFO(
string(
"Found: ") + base);
280 }
else if (ScanGroundFile(base +
".part", fRawFile, fPositionToRaw, fPositionOfEventTrailer, !foundShowerDefinition,
true) ==
eSuccess) {
281 foundShowerDefinition =
true;
282 fOpenedAnything =
true;
283 INFO(
string(
"Found: ") + base +
".part");
284 }
else if (ScanGroundFile(base +
".grdptcls", fRawFile, fPositionToRaw, fPositionOfEventTrailer, !foundShowerDefinition,
true) ==
eSuccess) {
285 foundShowerDefinition =
true;
286 fOpenedAnything =
true;
287 INFO(
string(
"Found: ") + base +
".grdptcls");
288 }
else if (ScanGroundFile(fileName, fRawFile, fPositionToRaw, fPositionOfEventTrailer, !foundShowerDefinition,
true) ==
eSuccess) {
289 foundShowerDefinition =
true;
290 fOpenedAnything =
true;
291 INFO(
string(
"Found: ") + fileName);
300 if (ScanLongFile(base +
".long") ==
eSuccess) {
301 fLongFile = base +
".long";
302 fReadLongFile =
true;
303 fOpenedAnything =
true;
304 INFO(
string(
"Found profile: ") + base +
".long");
308 if (ScanSteerFile(base +
".inp") ==
eSuccess) {
309 if (!fNumberOfEvents)
311 fSteerFile = base +
".inp";
312 fReadSteerFile =
true;
313 fOpenedAnything =
true;
314 foundShowerDefinition =
true;
315 INFO(
string(
"Found steerfile: ") + base +
".inp");
317 string testBase = base;
318 boost::replace_last(testBase,
"DAT",
"SIM");
319 if (ScanSteerFile(testBase +
".inp") ==
eSuccess) {
320 if (!fNumberOfEvents)
322 fSteerFile = testBase +
".inp";
323 fReadSteerFile =
true;
324 fOpenedAnything =
true;
325 foundShowerDefinition =
true;
326 INFO(
string(
"Found steerfile: ") + testBase +
".inp");
328 string testBase = base;
329 boost::replace_last(testBase,
"DAT",
"RUN");
330 if (ScanSteerFile(testBase +
".inp") ==
eSuccess) {
331 if (!fNumberOfEvents)
333 fSteerFile = testBase +
".inp";
334 fReadSteerFile =
true;
335 fOpenedAnything =
true;
336 foundShowerDefinition =
true;
337 INFO(
string(
"Found steerfile: ") + testBase +
".inp");
361 re = boost::regex(bRegex.
Get<
string>());
362 }
catch (
const boost::regex_error& e) {
363 const string err =
"Please make sure to specify valid regex expression in PatternRegex!";
371 const string err =
"InputMapping requires one of pattern_regex or pattern_path attribute!";
376 auto pattern = bPath.
Get<
string>();
377 boost::replace_all(pattern,
"\\",
"\\\\");
378 boost::replace_all(pattern,
"^",
"\\^");
379 boost::replace_all(pattern,
".",
"\\.");
380 boost::replace_all(pattern,
"$",
"\\$");
381 boost::replace_all(pattern,
"|",
"\\|");
382 boost::replace_all(pattern,
"(",
"\\(");
383 boost::replace_all(pattern,
")",
"\\)");
384 boost::replace_all(pattern,
"[",
"\\[");
385 boost::replace_all(pattern,
"]",
"\\]");
386 boost::replace_all(pattern,
"*",
"\\*");
387 boost::replace_all(pattern,
"+",
"\\+");
388 boost::replace_all(pattern,
"?",
"\\?");
389 boost::replace_all(pattern,
"/",
"\\/");
391 boost::replace_all(pattern,
"\\?",
".");
392 boost::replace_all(pattern,
"\\*",
"(.*)");
393 re = boost::regex(pattern);
396 vector<string> patterns;
399 if (boost::regex_match(fileName, what, re)) {
400 for (
int i = 1, n = what.size(); i < n; ++i)
401 patterns.push_back(what[i]);
403 const string err =
"Please make sure you specify valid regex/path expression! No match was found.";
407 }
catch (
const boost::regex_error& e) {
408 const string err =
"Please make sure you specify valid regex/path expression!";
416 const string name = mapping.
GetName();
417 string path = mapping.
Get<
string>();
419 for (
unsigned int i = 0; i < patterns.size(); ++i) {
420 ostringstream marker;
421 marker <<
'(' << i+1 <<
')';
422 boost::replace_all(path, marker.str(), patterns[i]);
427 inf <<
"Read " << name <<
" from file " << path;
431 if (name ==
"ProfileData") {
433 fReadLongFile =
true;
435 fOpenedAnything =
true;
437 }
else if (name ==
"GroundData") {
439 ScanGroundFile(path, fRawFile, fPositionToRaw, fPositionOfEventTrailer, !foundShowerDefinition);
440 foundShowerDefinition =
true;
441 fOpenedAnything =
true;
443 }
else if (name ==
"ShowerINFO") {
445 foundShowerDefinition =
true;
446 fOpenedAnything =
true;
450 while (getline(info, line)) {
453 if (line.find(
"energy_prim") == 0)
454 fShowerEnergy.push_back(stod(line.substr(13, line.length() - 13)));
455 if (line.find(
"theta_prim") == 0)
456 fShowerTheta.push_back(stod(line.substr(12, line.length() - 12)));
457 if (line.find(
"phi_prim") == 0)
458 fShowerPhi.push_back(stod(line.substr(11, line.length() - 11)));
461 const string err =
"this is not yet completely implemented";
465 }
else if (name ==
"ShowerDBASE") {
467 foundShowerDefinition =
true;
468 fOpenedAnything =
true;
470 ifstream dbase(path);
472 while (getline(dbase, line)) {
475 if (line.find(
"#energy_prim") == 0) {
477 boost::split(strs, line, boost::is_any_of(
"#"));
478 fShowerEnergy.push_back(stod(strs[1]));
479 fShowerTheta.push_back(stod(strs[3]));
480 fShowerPhi.push_back(stod(strs[5]));
485 const string err =
"this is not yet completely implemented";
489 }
else if (name ==
"TelescopeData") {
491 fOpenedAnything =
true;
494 if (fCherenkovFile.count(am)) {
496 err <<
"Already defined TelescopeData entry for attributes: ";
501 for (
const auto& iatt : am) {
502 err << comma <<
'"' << iatt.first <<
"\"=\"" << iatt.second <<
'"';
509 ScanGroundFile(path, fCherenkovFile[am], fPositionToCherenkovRaw[am], fPositionOfCherenkovEventTrailer[am], !foundShowerDefinition);
510 foundShowerDefinition =
true;
513 ERROR(
"unknown input mapping");
519 if (!fOpenedAnything) {
520 const string err =
"Did not open anything! Stop here.";
525 if (!foundShowerDefinition) {
526 const string err =
"No suited input file with primary shower data found. Cannot produce full MC evnets.";
541 for (
int i = 0; i < 5; ++i)
543 if (fAtmPars.fHLAY[0] < 0)
544 fAtmPars.fHLAY[0] = 0;
547 msg <<
"The current CORSIKA file was created using version " << header.
fVersion <<
". "
548 "The atmospheric layers are not defined! Using the values from US std. atmosphere.";
550 fAtmPars.fHLAY[0] = 0*
km;
551 fAtmPars.fHLAY[1] = 4*
km;
552 fAtmPars.fHLAY[2] = 10*
km;
553 fAtmPars.fHLAY[3] = 40*
km;
554 fAtmPars.fHLAY[4] = 100*
km;
556 for (
int i = 0; i < 5; ++i) {
560 fAtmPars.fZLAY[i] = GetDepthVsHeight(fAtmPars.fHLAY[i]);
562 INFO(
"Loaded atmosphere parameters:");
564 tab <<
"h[km]" <<
endc <<
"a[g/cm2]" <<
endc <<
"b[g/cm2]" <<
endc <<
"c[km]" <<
endr
566 for (
int i = 0; i < 5; ++i) {
569 tab << fAtmPars.fHLAY[i] /
km <<
endc
570 << fAtmPars.fAATM[i] / (
g/
cm2) <<
endc
571 << fAtmPars.fBATM[i] / (
g/
cm2) <<
endc
572 << fAtmPars.fCATM[i] /
km <<
endr;
579 const string msg =
"Inconsistent RunNumber found";
585 for (
int i = 0; i < 5; ++i) {
587 const string msg =
"Inconsistent Atmosphere HLAY found";
593 for (
int i = 0; i < 5; ++i) {
595 const string msg =
"Inconsistent Atmosphere AATM found";
600 const string msg =
"Inconsistent Atmosphere BATM found";
605 const string msg =
"Inconsistent Atmosphere CATM found";
632 msg <<
"NOTE: Offline does currently not support to read Cherenkov photons from ground particle files with optinos: "
633 "CEFFIC = " << chf.
IsCEFFIC() <<
", "
634 "CURVED = " << chf.
IsCURVED() <<
", "
642 inf <<
"Cherenkov option is available: "
644 "CEFFIC = " << chf.
IsCEFFIC() <<
", "
645 "CURVED = " << chf.
IsCURVED() <<
", "
647 "lambda = [" << fCherenkovBandwidthMin /
nanometer <<
", "
648 << fCherenkovBandwidthMax /
nanometer <<
"]";
655 const string msg =
"Inconsistent AARANG found";
659 if (fIdToPosition[
int(eh.
fEventNumber)] != eventsSoFar) {
660 const string msg =
"Inconsistent EventID found";
665 if (fIsSlant != chf.
IsSLANT()) {
666 const string msg =
"Inconsistent SLANT";
675 const string msg =
"Inconsistent CherWLmin found";
680 const string msg =
"Inconsistent CherWLmax found";
696 const bool noException)
701 if (!raw.
Open(name, noException))
705 unsigned int eventsSoFar = 0;
707 unsigned int blockIndex = 0;
708 bool foundEventHeader =
false;
709 bool foundRunHeader =
false;
723 foundEventHeader =
true;
724 positionToRaw.push_back(rawPosition - 1);
726 SetEventHeader(first, eventsSoFar, eh);
730 positionOfEventTrailer.push_back(rawPosition - 1);
733 SetRunHeader(first, RUNH);
734 foundRunHeader =
true;
737 if (blockIndex > 400 && !foundRunHeader) {
738 const string msg =
"Error scanning Corsika ground file: could not find run header";
742 if (blockIndex > 400 && !foundEventHeader)
746 if (!foundEventHeader) {
761 foundEventHeader =
true;
763 positionToRaw.push_back(rawPosition - 1);
765 SetEventHeader(first, eventsSoFar, eh);
768 positionOfEventTrailer.push_back(rawPosition - 1);
772 SetRunHeader(first, rh);
773 foundRunHeader =
true;
775 if (blockIndex > 400) {
776 if (!foundRunHeader) {
777 const string err =
"Error scanning thinned Corsika ground file: "
778 "could not find run header";
782 if (!foundEventHeader) {
783 const string err =
"Error scanning Corsika ground file: "
784 "could not find Event header";
792 const string err =
"Error scanning Corsika ground file: could not find run end";
798 if (positionToRaw.size() != positionOfEventTrailer.size()) {
799 const string err =
"Found different number of event-headers and -trailers";
806 if (eventsSoFar != fPositionToRaw.size()) {
808 err <<
"Found different number of events in Cherenkov file (" << eventsSoFar <<
") "
809 "compared to ground particle file (" << fPositionToRaw.size() <<
")";
815 fNumberOfEvents = positionToRaw.size();
824 if (fRawFile.IsOpen())
827 fPositionToRaw.clear();
828 fIdToPosition.clear();
830 delete fParticleIterator;
831 fParticleIterator =
nullptr;
842 const double magneticNorthDeclination = fUseRealisticMagneticDeclination ? 0 : fMagneticDeclination;
851 fCoordinateRotation + magneticNorthDeclination,
852 fUseRealisticMagneticDeclination
855 auto& shower =
event.GetSimShower();
858 const double cosZenith = cos(zenith);
864 const bool hasValidGHfit = (trailer.
fChi2 > 0 && trailer.
fChi2 < 1e13) && (nmax || xmax || x0);
868 shower.SetMuonNumber(trailer.
fMuons);
869 shower.SetGroundParticleCoordinateSystemZenith(zenith);
871 shower.SetGroundParticleCoordinateSystemAzimuth(
874 - fCoordinateRotation
876 shower.SetMinRadiusCut(rMin);
879 shower.SetShowerRunId(boost::lexical_cast<string>(header.
fRunNumber));
886 shower.SetMagneticFieldInclination(atan2(bz, bx));
887 shower.SetMagneticFieldStrength(
sqrt(bx * bx + bz * bz));
894 const double heightFirstInt = fabs(header.
fZFirst) *
cm;
899 double hReference = (header.
fZFirst < 0) ? hAtmBoundary : heightFirstInt;
903 shower.SetXFirst(header.
fFlagCurved ? GetSlantDepthCurved(heightObsLevel, zenith, heightFirstInt) :
904 GetDepthVsHeight(heightFirstInt) / fabs(cosZenith));
905 }
else if (cosZenith < 0) {
908 shower.SetXFirst(header.
fFlagCurved ? GetSlantDepthCurved(heightObsLevel, zenith, heightFirstInt) :
909 (875.6*(
g/
cm2) - GetDepthVsHeight(heightFirstInt)) / fabs(cosZenith));
914 info <<
"Primary = " << pid.get()->GetName() <<
", "
916 "Height of first interaction = " << heightFirstInt /
km <<
" km, "
917 "X_1 = " << shower.GetXFirst() / (
g/
cm2) <<
" g/cm2, "
918 "Zenith = " << zenith /
deg <<
" deg, "
919 "Azimuth = " << (header.
fPhi + 180*
deg)/
deg <<
" deg, "
922 "r_Min^thin = " << rMin /
cm <<
" cm";
927 if (fCoordinateRotation) {
929 info <<
"CORSIKA output is rotated by " << fCoordinateRotation /
deg <<
" deg with respect to CORSIKA USER GUIDE";
935 info <<
"CORSIKA output is on curved surface" << endl;
940 info <<
"Found simulated multi-core #" << iCore+1 <<
" "
941 "x=" << header.
fCoreX[iCore] / 100. <<
" m, "
942 "y=" << header.
fCoreY[iCore] / 100. <<
" m, "
943 "height=" << heightObsLevel /
m <<
" m ";
944 if (fMultiCoreSelection.empty() ||
945 find(fMultiCoreSelection.begin(), fMultiCoreSelection.end(), iCore+1) != fMultiCoreSelection.end()) {
946 info <<
" [selected]";
947 const UTMPoint utm(
Point(0,0,0, refCoordinateSystem), ReferenceEllipsoid::eWGS84);
948 const double origin_height = utm.
GetHeight();
949 const Point mcCore(header.
fCoreX[iCore]*
cm, header.
fCoreY[iCore]*cm, heightObsLevel-origin_height, refCoordinateSystem);
950 shower.AddSimCore(mcCore);
960 info <<
"CURVED version: ";
963 const double kREarth = 6.371315e6*
m;
965 timeShift = (
Sqr((kREarth + heightObsLevel) * cosZenith) +
966 Sqr(hReference - heightObsLevel) +
967 2 * (kREarth + heightObsLevel) * (hReference - heightObsLevel));
968 timeShift =
sqrt(timeShift);
969 timeShift -= (kREarth + heightObsLevel) * cosZenith;
973 timeShift = (hReference - heightObsLevel) / (cosZenith *
kSpeedOfLight);
975 info <<
"TimeShift to core: " << timeShift /
ns <<
" ns";
980 info <<
"The requested observation level: " << fObservationLevel
981 <<
" does not exist (max obs. level: "
983 "switching to level 1.";
984 fObservationLevel = 1;
990 msg <<
"The ratio of EM to hadron maximum weight is " << header.
fWMaxEM / header.
fWMaxHadronic <<
". "
991 "This is smaller than required to separate the EM contribution from local hadrons and "
992 "the rest of the cascade.";
996 if (header.
fVersion >= 6.9 && !shower.HasAtmosphereParameters()) {
997 shower.MakeAtmosphereParameters(
1007 if (hasValidGHfit) {
1013 gh.
SetXMax(xmax / fabs(cosZenith), 0);
1025 warn <<
"CORISKA shower with invalid GH fit: Xmax=" << xmax / cosZenith / (
g/
cm2) <<
" g/cm2, "
1026 "Nmax=" << nmax <<
", X0=" << x0 / cosZenith / (
g/
cm2) <<
" g/cm2, "
1027 "chi2/ndf=" << trailer.
fChi2;
1038 ERROR(
"Event not cleared - has SimShower. Cannot read CORSIKA.");
1042 bool haveGH =
false;
1044 bool setSimShowerAlready =
false;
1045 double timeShift = 0;
1048 if (fRawFile.IsOpen()) {
1050 if (fCurrentPosition >= fPositionToRaw.size()) {
1051 INFO(
"End of file");
1054 fRawFile.SeekTo(fPositionToRaw[fCurrentPosition]);
1060 if (!fRawFile.GetNextBlock(headerBlock)) {
1062 err <<
"Cannot read CORSIKA shower header for position "
1063 << fCurrentPosition;
1069 err <<
"First block at position " << fCurrentPosition
1070 <<
" is not event header";
1076 fRawFile.SeekTo(fPositionOfEventTrailer[fCurrentPosition]);
1078 if (!fRawFile.GetNextBlock(trailerBlock)) {
1080 err <<
"Cannot read CORSIKA shower trailer for position "
1081 << fCurrentPosition;
1087 err <<
"Block at position " << fCurrentPosition
1088 <<
" is not event trailer";
1094 if (!setSimShowerAlready) {
1095 SetHeaderTrailer(event, timeShift, gh, haveGH, zenith, header, trailer);
1096 setSimShowerAlready =
true;
1102 if (!fRawFile.GetNextBlockUnthinned(headerBlock)) {
1104 msg <<
"Cannot read CORSIKA shower header for position "
1105 << fCurrentPosition;
1111 msg <<
"First block at position " << fCurrentPosition
1112 <<
" is not event header";
1118 fRawFile.SeekTo(fPositionOfEventTrailer[fCurrentPosition]);
1120 if (!fRawFile.GetNextBlockUnthinned(trailerBlock)) {
1122 msg <<
"Cannot read CORSIKA shower trailer for position "
1123 << fCurrentPosition;
1129 msg <<
"BlockUnthinned at position " << fCurrentPosition
1130 <<
" is not event trailer";
1136 if (!setSimShowerAlready) {
1137 SetHeaderTrailer(event, timeShift, gh, haveGH, zenith, header, trailer);
1138 setSimShowerAlready =
true;
1143 delete fParticleIterator;
1149 fPositionToRaw[fCurrentPosition] + 1,
1161 for (
auto& it : fCherenkovFile) {
1167 FATAL(
"Try to read data from file that is not open.");
1171 if (fCurrentPosition >= fPositionToCherenkovRaw[am].size()) {
1172 INFO(
"End of file (Cherenkov)");
1175 file.
SeekTo(fPositionToCherenkovRaw[am][fCurrentPosition]);
1183 err <<
"Cannot read Cherenkov CORSIKA shower header for position "
1184 << fCurrentPosition;
1190 err <<
"First block at position " << fCurrentPosition
1191 <<
" is not cherenkov event header";
1197 file.
SeekTo(fPositionOfCherenkovEventTrailer[am][fCurrentPosition]);
1201 err <<
"Cannot read CORSIKA shower cherenkov trailer for position "
1202 << fCurrentPosition;
1208 err <<
"Block at position " << fCurrentPosition
1209 <<
" is not cherenkov event trailer";
1215 if (!setSimShowerAlready) {
1216 SetHeaderTrailer(event, timeShift, gh, haveGH, zenith, header, trailer);
1217 setSimShowerAlready =
true;
1225 err <<
"Cannot read Cherenkov CORSIKA shower header for position "
1226 << fCurrentPosition;
1232 err <<
"First block at position " << fCurrentPosition
1233 <<
" is not chernkov event header";
1239 file.
SeekTo(fPositionOfEventTrailer[fCurrentPosition]);
1244 err <<
"Cannot read CORSIKA shower cherenkov trailer for position "
1245 << fCurrentPosition;
1251 err <<
"Block at position " << fCurrentPosition
1252 <<
" is not cherenkov event trailer";
1258 if (!setSimShowerAlready) {
1259 SetHeaderTrailer(event, timeShift, gh, haveGH, zenith, header, trailer);
1260 setSimShowerAlready =
true;
1265 if (fCherenkovIterator.count(am))
1266 delete fCherenkovIterator[am];
1268 fCherenkovIterator[am] =
1273 fPositionToCherenkovRaw[am][fCurrentPosition] + 1,
1277 true, fCherenkovBandwidthMin, fCherenkovBandwidthMax);
1286 if (!setSimShowerAlready) {
1287 if (fReadSteerFile) {
1288 setSimShowerAlready =
true;
1289 const Status status = ReadSteerFile(event);
1291 INFO(
"Problem reading steering input");
1299 if (!setSimShowerAlready) {
1300 WARNING(
"No geometry information found while reading CORSIKA. ShowerSimData is filled only partially!");
1302 const double fieldDeclination = fUseRealisticMagneticDeclination ? 0 : fMagneticDeclination;
1309 if (fReadLongFile) {
1310 const Status status = ReadProfile(shower, zenith);
1312 INFO(
"End of file (profile)");
1319 ERROR(
"Found no (valid) GH fit in DAT file! No profile data available!");
1322 const double xmax = gh.
GetXMax();
1323 const double nmax = gh.
GetNMax();
1331 msg <<
"Nmax = " << nmax <<
", "
1332 "Xmax = " << xmax / (
g/
cm2) <<
" g/cm2, "
1333 "X0 = " << x0 / (
g/
cm2) <<
" g/cm2";
1347 ifstream corsikaSteer(fSteerFile.c_str());
1348 if (!corsikaSteer.is_open()) {
1350 msg <<
"Cannot open file " << fSteerFile <<
" - ERROR";
1355 string corsikaDataFileBase;
1357 double magneticFieldInclination = 0;
1358 double magneticFieldStrength = 0;
1359 double showerAzimuth = 0;
1360 double showerZenith = 0;
1361 int primaryParticleType = 0;
1362 double primaryEnergy = 0;
1363 double observationHeight = 0;
1366 while (getline(corsikaSteer, currLine)) {
1368 if (currLine.empty())
1371 const char firstChar = currLine.at(0);
1373 if (firstChar ==
'c' || firstChar ==
'C')
1377 stringstream ss(currLine);
1383 if (!(ss >> skip >> rn))
1385 corsikaDataFileBase = (format(
"DAT%06d") % rn).str();
1386 runNo = boost::lexical_cast<
string>(rn);
1388 }
else if (
Contains(currLine,
"MAGNET")) {
1393 if (!(ss >> skip >> bx >> bz))
1397 magneticFieldInclination = atan2(bz, bx);
1398 magneticFieldStrength =
sqrt(bx*bx + bz*bz);
1400 }
else if (
Contains(currLine,
"PHIP")) {
1405 if (!(ss >> skip >> showerAzimuth >> az2))
1407 if (showerAzimuth != az2) {
1409 "Cannot use CORSIKA azimuth because azimuth angle range in CORSIKA parameter file is not singular";
1415 }
else if (
Contains(currLine,
"THETAP")) {
1420 if (!(ss >> skip >> showerZenith >> zen2))
1422 if (showerZenith != zen2) {
1424 "Cannot use CORSIKA zenith because zenith angle range in CORSIKA parameter file is not singular";
1430 }
else if (
Contains(currLine,
"ERANGE")) {
1435 if (!(ss >> skip >> primaryEnergy >> en2))
1437 if (primaryEnergy != en2) {
1439 "Cannot use CORSIKA energy because energy angle range in CORSIKA parameter file is not singular";
1445 }
else if (
Contains(currLine,
"PRMPAR")) {
1448 if (!(ss >> skip >> primaryParticleType))
1451 }
else if (
Contains(currLine,
"ARRANG")) {
1456 if (!(ss >> skip >> fCoordinateRotation >> skip2))
1460 }
else if (
Contains(currLine,
"OBSLEV")) {
1464 if (!(ss >> skip >> observationHeight))
1473 const bool multiCore =
false;
1475 event.MakeSimShower(
1477 showerZenith, showerAzimuth + fCoordinateRotation,
1480 refCoordinateSystem,
1481 fMagneticDeclination,
1482 fUseRealisticMagneticDeclination
1497 auto& shower =
event.GetSimShower();
1499 shower.SetEnergy(primaryEnergy);
1500 shower.SetShowerRunId(runNo);
1501 shower.SetMagneticFieldInclination(magneticFieldInclination);
1502 shower.SetMagneticFieldStrength(magneticFieldStrength);
1503 shower.SetGroundParticleCoordinateSystemZenith(showerZenith);
1504 shower.SetGroundParticleCoordinateSystemAzimuth(
1507 - fCoordinateRotation
1528 ifstream longFile(name);
1529 if (!longFile.is_open())
1532 fNumberOfEvents = 0;
1535 while (getline(longFile, line))
1536 if (
Contains(line,
"LONGITUDINAL DISTRIBUTION IN"))
1545 const double zenith)
1549 const double cosZenith = cos(zenith);
1551 vector<string> lines;
1554 ifstream longFile(fLongFile.c_str());
1556 if (!longFile.is_open()) {
1557 const string info =
"Cannot read longitudinal-profile file '" + fLongFile +
"'.";
1562 unsigned int showerN = 0;
1564 while (getline(longFile, line)) {
1567 if (
Contains(line,
"LONGITUDINAL DISTRIBUTION IN")) {
1569 if (showerN > fCurrentPosition+1)
1572 if (showerN == fCurrentPosition+1)
1573 lines.push_back(line);
1576 const unsigned int nLines = lines.size();
1586 info <<
"Read " << nLines <<
" lines from '" << fLongFile <<
"' at position " << fCurrentPosition;
1590 typedef unsigned int (*ToUIntType)(
const string&);
1591 const ToUIntType ToUInt = &boost::lexical_cast<
unsigned int>;
1592 typedef double (*ToDType)(
const string&);
1593 const ToDType ToD = &boost::lexical_cast<
double>;;
1595 bool isProfileSlant =
false;
1596 unsigned int profileLength = 0;
1602 if (!(s1.size() == 12 && s1[0] ==
"LONGITUDINAL" && s1[1] ==
"DISTRIBUTION" &&
1603 s2.size() == 10 && s2[0] ==
"DEPTH" && s2[1] ==
"GAMMAS")) {
1604 const string err =
"Mismatch in particle distribution profile headers.";
1608 const unsigned int n = ToUInt(s1[3]);
1611 const string msg =
"Particle profiles are too short.";
1615 const string& type = s1[4];
1616 if (type !=
"SLANT" && type !=
"VERTICAL") {
1617 const string err =
"Unknown profile type '" + type +
"', (only 'VERTICAL' and 'SLANT' supported)";
1621 isProfileSlant = (type ==
"SLANT");
1622 const double slantFac = isProfileSlant ? 1 : 1 / fabs(cosZenith);
1623 const double dX = slantFac * ToD(s1[7]) * (
g/
cm2);
1625 vector<double> particleDistributionDepth;
1626 vector<double> particleDistributionCharge;
1627 vector<double> particleDistributionMuons;
1628 vector<double> particleDistributionGammas;
1629 vector<double> particleDistributionElectrons;
1630 vector<double> particleProductionCherenkov;
1631 for (
unsigned int j = 0; j < n; ++j) {
1636 if (s.size() != 10) {
1637 WARNING(
"Corrupted longitudinal particle distribution table detected; will try to fix it.");
1640 warn <<
"Fixed line: ";
1642 for (
const auto& sss : s) {
1643 warn << comma << sss;
1648 particleDistributionDepth.push_back(slantFac * ToD(s.at(0)) * (
g /
cm2));
1649 const double ch = ToD(s.at(7));
1650 particleDistributionCharge.push_back(ch);
1651 const double mu = ToD(s.at(4)) + ToD(s.at(5));
1652 particleDistributionMuons.push_back(mu);
1653 particleDistributionGammas.push_back(ToD(s.at(1)));
1654 const double e = ToD(s.at(2)) + ToD(s.at(3));
1655 particleDistributionElectrons.push_back(e);
1658 particleProductionCherenkov.push_back(
double(ToD(s.at(9)) / dX));
1662 const double normDepth = particleDistributionDepth.back();
1664 const double normCharge = particleDistributionCharge.back();
1665 const double normMuons = particleDistributionMuons.back();
1666 const double normGammas = particleDistributionGammas.back();
1667 const double normElectrons = particleDistributionElectrons.back();
1668 const double normCherenkov = particleProductionCherenkov.back();
1669 const double lastDepth = particleDistributionDepth.back();
1672 if (type ==
"SLANT" || zenith < 90*
deg) {
1674 for (
int j = 0; j < 2; ++j) {
1675 const double addDepth = lastDepth + dX * (j + 1);
1677 const double fac = nch / normN;
1678 const double addCharge = normCharge * fac;
1679 const double addMuons = normMuons * fac;
1680 const double addGammas = normGammas * fac;
1681 const double addElectrons = normElectrons * fac;
1682 const double addCherenkov = normCherenkov * fac;
1683 particleDistributionDepth.push_back(addDepth);
1684 particleDistributionCharge.push_back(addCharge);
1685 particleDistributionMuons.push_back(addMuons);
1686 particleDistributionGammas.push_back(addGammas);
1687 particleDistributionElectrons.push_back(addElectrons);
1688 particleProductionCherenkov.push_back(addCherenkov);
1691 if (type ==
"VERTICAL" && zenith > 90*
deg) {
1698 reverse(particleDistributionCharge.begin(), particleDistributionCharge.end());
1699 reverse(particleDistributionMuons.begin(), particleDistributionMuons.end());
1700 reverse(particleDistributionGammas.begin(), particleDistributionGammas.end());
1701 reverse(particleDistributionElectrons.begin(), particleDistributionElectrons.end());
1702 reverse(particleProductionCherenkov.begin(), particleProductionCherenkov.end());
1709 for (
unsigned int j = 0; j < n; ++j) {
1710 const double depth = particleDistributionDepth[j];
1711 chargeProfile.
PushBack(depth, particleDistributionCharge[j]);
1712 muonProfile.
PushBack(depth, particleDistributionMuons[j]);
1713 gammaProfile.
PushBack(depth, particleDistributionGammas[j]);
1714 electronProfile.
PushBack(depth, particleDistributionElectrons[j]);
1715 cherenkovProfile.
PushBack(depth, particleProductionCherenkov[j]);
1736 if (!(s1.size() == 13 && s1[0] ==
"LONGITUDINAL" && s1[1] ==
"ENERGY" &&
1737 s2.size() == 16 && s2[0] ==
"DEPTH" && s2[1] ==
"GAMMA")) {
1738 const string err =
"Mismatch in energy deposit profile headers.";
1742 const unsigned int n = ToUInt(s1[4]);
1744 const string msg =
"Energy deposit profile is too short.";
1748 const string& type = s1[5];
1749 if (type !=
"SLANT" && type !=
"VERTICAL") {
1750 const string err =
"Unknown profile type '" + type +
"', (only 'VERTICAL' and 'SLANT' supported)";
1754 if (isProfileSlant != (type ==
"SLANT")) {
1755 const string err =
"Energy deposit and particle profiles do not have the same inclination.";
1759 const double slantFac = isProfileSlant ? 1 : 1 / fabs(cosZenith);
1760 const double dX = slantFac * ToD(s1[8]) *
g/
cm2;
1767 const unsigned int groundRowsAtTheEnd = (isProfileSlant) ? 2 : 1;
1768 double energyDepositSum = 0;
1769 double electromagneticEnergyDeposit = 0;
1770 vector<double> energyDepositDepth;
1771 vector<double> energyDeposit;
1772 for (
unsigned int j = 0; j < n; ++j) {
1774 if (s.size() != 10) {
1775 WARNING(
"Corrupted longitudinal energy deposit table detected; will try to fix it.");
1778 warn <<
"Fixed line: ";
1780 for (
const auto& sss : s) {
1781 warn << comma << sss;
1786 energyDepositDepth.push_back(slantFac * ToD(s.at(0)) * (
g /
cm2));
1787 const double muCut = ToD(s.at(5)) *
GeV;
1788 const double hadCut = ToD(s.at(7)) *
GeV;
1789 const double nu = ToD(s.at(8)) *
GeV;
1790 const double sum = ToD(s.at(9)) *
GeV;
1793 const double muonFraction = 0.575;
1794 const double hadronFraction = 0.;
1795 const double de = sum - nu - muonFraction * muCut - hadronFraction * hadCut;
1796 energyDeposit.push_back(de / dX);
1797 if (j < n - groundRowsAtTheEnd)
1798 energyDepositSum += de;
1800 const double gamma = ToD(s.at(1)) *
GeV;
1801 const double emIon = ToD(s.at(2)) *
GeV;
1802 const double emCut = ToD(s.at(3)) *
GeV;
1803 const double muIon = ToD(s.at(4)) *
GeV;
1804 const double hadIon = ToD(s.at(6)) *
GeV;
1805 const double hadronGroundFraction = 0.390;
1806 const double groundEnergy =
1807 (1 - hadronGroundFraction) * hadCut + hadIon + muIon + emIon + emCut + gamma;
1808 energyDepositSum += groundEnergy;
1812 electromagneticEnergyDeposit += (ToD(s.at(1)) + ToD(s.at(2)) + ToD(s.at(3))) *
GeV;
1815 const double normDepth = energyDepositDepth[n - 3];
1818 const double normdEdX = energyDeposit[n - 3];
1820 for (
int j = 0; j < 2; ++j) {
1821 const int bin = n - 2 + j;
1822 const double depth = energyDepositDepth[bin];
1823 energyDeposit[bin] = normdEdX / normN *
1826 const double lastDepth = energyDepositDepth.back();
1828 if (type ==
"SLANT" || zenith < 90*
deg) {
1830 for (
int j = 0; j < 2; ++j) {
1831 const double addDepth = lastDepth + dX * (j + 1);
1833 const double adddEdX = normdEdX / normN * nch;
1834 energyDepositDepth.push_back(addDepth);
1835 energyDeposit.push_back(adddEdX);
1843 if (type ==
"VERTICAL" && zenith > 90*
deg)
1844 reverse(energyDeposit.begin(), energyDeposit.end());
1846 for (
unsigned int j = 0; j < n; ++j)
1847 dEdX.
PushBack(energyDepositDepth[j], energyDeposit[j]);
1849 for (
unsigned int i = 0; i < energyDepositDepth.size(); ++i) {
1857 if (!energyDeposit.empty() && !shower.
HasdEdX())
1863 const vector<string> s1 =
String::Split(i < nLines ? lines[i] :
"");
1864 const vector<string> s2 =
String::Split(i + 1 < nLines ? lines[i + 1] :
"");
1865 if (!(s1.size() > 5 && s1[0] ==
"FIT" && s1[1] ==
"OF" && s1[2] ==
"THE" && s1[3] ==
"HILLAS" &&
1866 s2.size() == 7 && s2[0] ==
"TO" && s2[1] ==
"LONGITUDINAL" && s2[2] ==
"DISTRIBUTION")) {
1867 WARNING(
"Native GH fit not found.");
1872 if (s3.size() != 8 || s3[0] !=
"PARAMETERS" || s3[1] !=
"=" ||
1873 s4.size() != 3 || s4[0] !=
"CHI**2/DOF" || s4[1] !=
"="
1875 const string err =
"Malformed fit of the Hillas curve.";
1882 if (isProfileSlant || zenith < 90*
deg) {
1883 const double slantFac = isProfileSlant ? 1 : 1 / fabs(cosZenith);
1884 const double nMax = ToD(s3.at(2));
1885 const double x0 = slantFac * ToD(s3.at(3)) *
g /
cm2;
1886 const double xMax = slantFac * ToD(s3.at(4)) *
g /
cm2;
1887 const double apar = ToD(s3.at(5)) *
g /
cm2;
1888 const double bpar = ToD(s3.at(6));
1889 const double cpar = ToD(s3.at(7)) / (
g /
cm2);
1890 const double chi2 = ToD(s4.at(2));
1891 if (chi2 <= 0 || chi2 * profileLength > 1e15) {
1893 err <<
"CORISKA shower with invalid GH fit: Xmax = " << xMax / (
g/
cm2) <<
" g/cm2, "
1894 "Nmax = " << nMax <<
", X0 = " << x0 / (
g/
cm2) <<
" g/cm2, chi2/ndf = " << chi2;
1897 const double a = slantFac * apar;
1898 const double b = slantFac * bpar;
1899 const double c = slantFac * cpar;
1909 info <<
"Nmax = " << nMax <<
", "
1910 "Xmax = " << xMax / (
g/
cm2) <<
" g/cm2, "
1911 "X0 = " << x0 / (
g/
cm2) <<
" g/cm2, "
1912 "zenith = " << acos(cosZenith) /
deg <<
" deg"
1913 << (isProfileSlant ?
" (SLANT DEPTH)" :
" (VERTICAL DEPTH)");
1918 }
else if (!isProfileSlant && zenith > 90*
deg) {
1923 TMinuit minuitdEdXGHFit(4);
1926 double arglist[2] = { 0 };
1929 const double index = std::distance(
1934 minuitdEdXGHFit.mnexcm(
"SET ERR", arglist, 1, ierflag);
1941 double lambdaFit = 70;
1943 minuitdEdXGHFit.mnparm(0,
"dEdXmax", dEdXmaxFit, 0.1 * fabs(dEdXmaxFit), 0, 0, ierflag);
1944 minuitdEdXGHFit.mnparm(1,
"X0", x0Fit, 1, -1000,
GHFit::gProfile.fSlantDepth[0] / (
g/
cm2), ierflag);
1945 minuitdEdXGHFit.mnparm(2,
"Xmax", xMaxFit, 20, 0, 0, ierflag);
1946 minuitdEdXGHFit.mnparm(3,
"lambda", lambdaFit, 5, 10, 150, ierflag);
1951 minuitdEdXGHFit.mnexcm(
"MIGRAD", arglist, 2, ierflag);
1959 minuitdEdXGHFit.mnstat(amin, edm, errdef, nvpar, nparx, icstat);
1961 double p[4] = { 0 };
1962 minuitdEdXGHFit.GetParameter(0, dEdXmaxFit, p[0]);
1963 minuitdEdXGHFit.GetParameter(1, x0Fit, p[1]);
1964 minuitdEdXGHFit.GetParameter(2, xMaxFit, p[2]);
1965 minuitdEdXGHFit.GetParameter(3, lambdaFit, p[3]);
1971 const double nMaxFit =
1975 const double x0 = x0Fit *
g/
cm2;
1976 const double xMax = xMaxFit *
g/
cm2;
1978 const double apar = lambdaFit *
g/
cm2;
1981 const double bpar = 0;
1982 const double cpar = 0;
1983 const double chi2 = minuitdEdXGHFit.fAmin;
1984 if (chi2 <= 0 || chi2 * profileLength > 1e15) {
1986 err <<
"CORISKA shower with invalid GH fit: Xmax = " << xMax / (
g/
cm2) <<
" g/cm2, "
1987 "Nmax = " << nMaxFit <<
", X0 = " << x0 / (
g/
cm2) <<
" g/cm2, chi2/ndf = " << chi2;
1990 const double a = apar;
1991 const double b = bpar;
1992 const double c = cpar;
2002 info <<
"Nmax = " << nMaxFit <<
", "
2003 "Xmax = " << xMax / (
g/
cm2) <<
" g/cm2, "
2004 "X0 = " << x0 / (
g/
cm2) <<
" g/cm2, "
2005 "zenith = " << acos(cosZenith) /
deg <<
" deg"
2006 << (isProfileSlant ?
" (SLANT DEPTH)" :
" (VERTICAL DEPTH)");
2034 const string msg =
"Cannot write to CorsikaShowerFile - read-only file";
2043 const auto it = fIdToPosition.find(eventId);
2044 if (it == fIdToPosition.end())
2046 return GotoPosition(it->second);
2053 if (position >= fNumberOfEvents)
2055 fCurrentPosition = position;
2063 if (fOpenedAnything)
2064 return fNumberOfEvents;
2066 const string msg =
"Cannot request number of events from closed file";
2076 return fParticleIterator;
2084 for (
int i = 0; i < 4; ++i)
2085 if (fAtmPars.fHLAY[i] <= height && height < fAtmPars.fHLAY[i + 1])
2086 return fAtmPars.fBATM[i] * exp(-height / fAtmPars.fCATM[i]) / fAtmPars.fCATM[i];
2087 if (height >= fAtmPars.fHLAY[4])
2088 return fAtmPars.fBATM[4] / fAtmPars.fCATM[4];
2100 if (fabs(height) > fAtmPars.fHLAY[4])
2102 else if (fabs(height) > fAtmPars.fHLAY[3])
2104 else if (fabs(height) > fAtmPars.fHLAY[2])
2106 else if (fabs(height) > fAtmPars.fHLAY[1])
2111 return fAtmPars.fAATM[section] + fAtmPars.fBATM[section] * exp(-height / fAtmPars.fCATM[section]);
2112 return fAtmPars.fAATM[section] - fAtmPars.fBATM[section] * (height / fAtmPars.fCATM[section]);
2120 using namespace Corsika;
2121 const double sinZenith = sin(theta);
2122 const double sinZenith2 = sinZenith * sinZenith;
2125 const double dX = 0.01 * (
g/
cm2);
2129 while (height < hAtmBoundary && height > hObs) {
2131 GetDensityVsHeight(height);
void SetHeaderTrailer(evt::Event &event, double &timeShift, evt::GaisserHillas6Parameter &gh, bool &haveGH, double &zenith, const Corsika::EventHeader &header, const Corsika::EventTrailer &trailer)
double GaisserHillas4ParameterFunction(const double x, const double dEdXmax, const double x0, const double xmax, const double lambda)
Status Read(evt::Event &event) override
read current event advance cursor by 1
Status ReadProfile(evt::ShowerSimData &shower, const double zenith)
vector< string > FixedColumnWidthSplit(const string &line, const unsigned int nColumns, const unsigned int firstColumnWidth, const unsigned int columnWidth)
constexpr T Sqr(const T &x)
Status ScanGroundFile(const std::string &name, Corsika::RawFile &raw, PositionVector &posEVTH, PositionVector &posEVTE, const bool first, const bool noException=false)
Collect information about ground file.
double GetDepthVsHeight(const double h) const
Return vertical atmospheric depth as a function of height, according to the parameters stored in the ...
void Write(const evt::Event &event) override
const evt::VGaisserHillasParameter & GetGHParameters() const
Get the Gaisser-Hillas parameters of the shower.
Class to hold and convert a point in geodetic coordinates.
Class to hold collection (x,y) points and provide interpolation between them.
Status ScanSteerFile(const std::string &name)
bool HasGroundParticles() const
bool HasSimShower() const
std::map< std::string, std::string > AttributeMap
Mode
Available open modes.
void SetXMax(const double xMax, const double error)
utl::ShowerParticleList & GetGroundCherenkov(const utl::AttributeMap &am)
#define INFO(message)
Macro for logging informational messages.
#define FATAL(message)
Macro for logging fatal messages.
void MakeGHParameters(const evt::VGaisserHillasParameter &ghPar)
Make the Gaisser-Hillas parameters of the shower.
const RunHeader & AsRunHeader() const
void PushBack(const double x, const double y)
Branch GetChild(const std::string &childName) const
Get child of this Branch by child name.
boost::shared_ptr< const VParticleProperties > ParticlePropertiesPtr
double pow(const double x, const unsigned int i)
void MakedEdX(const utl::TabulatedFunction &dEdX)
Make the energy deposit of the shower.
RWORD fLongitudinalPar[6]
virtual ~CorsikaShowerFile()
void reverse(double arr[], int count)
Status GotoPosition(const unsigned int position) override
goto by position in the file
bool GetNextBlock(Block &block)
Read one block and advance.
const EventTrailer & AsEventTrailer() const
bool IsEventHeader() const
constexpr double nanometer
void SetFileInterface(VShowerFileParticleIterator *const interface)
void SetB(const double b, const double error)
Interface class to access Shower Simulated parameters.
bool IsOpen() const
Check if the file is open.
AttributeMap GetAttributes() const
Get a map<string, string> containing all the attributes of this Branch.
Branch GetNextSibling() const
Get next sibling of this branch.
Status ScanLongFile(const std::string &name)
Read longitudinal profile.
void GH4ParamFitFunctiondEdxGH(int &, double *, double &f, double *par, int)
boost::shared_ptr< const CoordinateTransformer > CoordinateSystemPtr
Shared pointer for coordinate systems.
Class representing a document branch.
void MakeLongitudinalProfile(const utl::TabulatedFunction &lp, const ProfileType type=eCharged)
Make the longitudinal charge profile of the shower.
Status
Return code for seek operation.
bool HasGroundCherenkov(const utl::AttributeMap &am) const
void SetXZero(const double xZero, const double error)
void SetRunHeader(const bool first, const Corsika::RunHeader &header)
double GetHeight() const
Get the height.
Base for exceptions in the CORSIKA reader.
CorsikaShowerFileParticleIterator * GetCorsikaShowerFileParticleIterator() const
Get CorsikaShowerFileParticleIterator for testing.
void SetCalorimetricEnergy(const double energy)
Set the calorimetric energy of the shower.
virtual double Eval(const double depth) const =0
bool IsEventTrailer() const
void SetC(const double c, const double error)
void SetElectromagneticEnergy(const double energy)
Set the electromagnetic energy of the shower.
double CorsikaAzimuthToAuger(const double corsikaAzimuth, const double magneticFieldDeclination)
Returns the azimuth rotated from Corisika's system to Auger standard.
utl::ShowerParticleList & GetGroundParticles()
Get particle list Proxy.
class to format data in tabular form
#define WARNING(message)
Macro for logging warning messages.
void GetData(bool &b) const
Overloads of the GetData member template function.
std::string GetName() const
function to get the Branch name
void SetChiSquare(const double chi, const unsigned int ndof)
void MakeGroundParticles()
void MakeGroundCherenkov(const utl::AttributeMap &am)
bool GetNextBlockUnthinned(BlockUnthinned &block)
Read one block and advance.
void SeekTo(const PositionType position, const bool reset=false)
Seek to a given block, the next block will be thePosition.
Implementation of the VShowerFileParticleIterator for an Corsika generated shower file...
void SetNMax(const double nMax, const double error, const bool isEnergyDeposit=false)
bool HasdEdX() const
Check initialization of the energy deposit.
void SetA(const double a, const double error)
PositionType GetNextPosition() const
Number of the block read by the next call to GetNextBlock.
constexpr double kSpeedOfLight
void Open(const std::string &fileName, const Mode mode=eRead, utl::Branch *const b=nullptr) override
Status ReadSteerFile(evt::Event &event)
Read steering file.
bool Open(const std::string &name, const bool noException=false)
const double hAtmBoundary
bool Contains(const string &str, const string &what)
vector< double > fSlantDepth
int CorsikaToPDG(const int corsikaCode)
converters from CORSIKA to PDG particle codes
bool HasGHParameters() const
Check initialization of the Gaisser-Hillas parameters.
const EventHeader & AsEventHeader() const
double EnergyDeposit(const double age, const double enCut)
Parametrization for the average energy deposit per particle.
bool IsRunTrailer() const
utl::CoordinateSystemPtr Get(const std::string &id)
Get a well-known Coordinate System.
Branch GetFirstChild() const
Get first child of this Branch.
Status FindEvent(const unsigned int eventId) override
seek Event id set cursor there
void SetEventHeader(const bool first, const unsigned int eventsSoFar, const Corsika::EventHeader &eh)
int GetNEvents() override
vector< double > fEnergyDeposit
std::vector< Corsika::RawFile::PositionType > PositionVector
#define ERROR(message)
Macro for logging error messages.
double GetDensityVsHeight(const double height) const
Return the air density as a function of height, according to the parameters stored in the file...
Gaisser-Hillas with 6 parameters (CORSIKA)
double GetSlantDepthCurved(const double hObs, const double theta, const double h) const
Return slant atmospheric depth as a function of height, according to the parameters stored in the fil...
const double kEarthRadius
bool HasLongitudinalProfile(const ProfileType type=eCharged) const
Check initialization of the longitudinal profile.
unsigned long int PositionType
Class to hold the standard parameters used to specify an atmospheric profile.
static ObjectPtrType Create(const IdentifierType &id)
Create an object (0-argument constructor)
event trailer struct for Corsika files
vector< string > Split(const string &str, const char *const separators)