220 string fileDescriptor;
222 JFileRecorder <JTYPELIST<JAAnetTypes_t, JMetaTypes_t, JRootTypes_t>::typelist>
outputFile;
223 JLimit_t& numberOfEvents = inputFile.getLimit();
247 JParser<> zap(
"Main program to simulate detector response to muons and showers.");
250 zap[
'F'] =
make_field(fileDescriptor,
"file name descriptor for CDF tables");
255 zap[
's'] =
make_field(writeEMShowers,
"store generated EM showers in event");
256 zap[
'N'] =
make_field(numberOfHits,
"minimum number of hits to output event") = 1;
257 zap[
'U'] =
make_field(factor,
"scaling factor applied to light yields") = 1.0;
263 catch(
const exception &error) {
264 FATAL(error.what() << endl);
268 gRandom->SetSeed(seed);
271 const JMeta meta(argc, argv);
273 const double Zbed = 0.0;
278 CDF.push_back(JCDF_t(fileDescriptor, DIRECT_LIGHT_FROM_MUON));
279 CDF.push_back(JCDF_t(fileDescriptor, SCATTERED_LIGHT_FROM_MUON));
280 CDF.push_back(JCDF_t(fileDescriptor, DIRECT_LIGHT_FROM_DELTARAYS));
281 CDF.push_back(JCDF_t(fileDescriptor, SCATTERED_LIGHT_FROM_DELTARAYS));
283 CDG.push_back(JCDG_t(fileDescriptor, DIRECT_LIGHT_FROM_EMSHOWER));
284 CDG.push_back(JCDG_t(fileDescriptor, SCATTERED_LIGHT_FROM_EMSHOWER));
287 double maximal_road_width = 0.0;
288 double maximal_distance = 0.0;
290 for (
size_t i = 0; i != CDF.size(); ++i) {
292 DEBUG(
"Range CDF["<< CDF[i].type <<
"] " << CDF[i].function.intensity.getXmax() <<
" m" << endl);
294 maximal_road_width = max(maximal_road_width, CDF[i].function.intensity.getXmax());
297 for (
size_t i = 0; i != CDG.size(); ++i) {
299 DEBUG(
"Range CDG["<< CDG[i].type <<
"] " << CDG[i].function.intensity.getXmax() <<
" m" << endl);
302 maximal_road_width = max(maximal_road_width, CDG[i].function.intensity.getXmax());
305 maximal_distance = max(maximal_distance, CDG[i].function.intensity.getXmax());
308 NOTICE(
"Maximal road width [m] " << maximal_road_width << endl);
309 NOTICE(
"Maximal distance [m] " << maximal_distance << endl);
312 if (detectorFile ==
"" || inputFile.empty()) {
313 STATUS(
"Nothing to be done." << endl);
321 STATUS(
"Load detector... " << flush);
333 for (JDetector::iterator module =
detector.begin(); module !=
detector.end(); ) {
334 if (!module->empty())
337 module = detector.erase(module);
345 STATUS(
"Setting up radiation tables... " << flush);
347 const JRadiation hydrogen ( 1.0, 1.0, 40, 0.01, 0.1, 0.1);
348 const JRadiation oxygen ( 8.0, 16.0, 40, 0.01, 0.1, 0.1);
349 const JRadiation chlorine (17.0, 35.5, 40, 0.01, 0.1, 0.1);
350 const JRadiation sodium (11.0, 23.0, 40, 0.01, 0.1, 0.1);
352 const JRadiation calcium (20.0, 40.0, 40, 0.01, 0.1, 0.1);
353 const JRadiation magnesium(12.0, 24.3, 40, 0.01, 0.1, 0.1);
354 const JRadiation potassium(19.0, 39.0, 40, 0.01, 0.1, 0.1);
355 const JRadiation sulphur (16.0, 32.0, 40, 0.01, 0.1, 0.1);
423 if (cylinder.
getZmin() < Zbed) {
427 NOTICE(
"Light generation volume: " << cylinder << endl);
435 header = inputFile.getHeader();
437 JHead buffer(header);
451 buffer.
detector.rbegin()->filename = detectorFile;
455 offset +=
Vec(cylinder.
getX(), cylinder.
getY(), 0.0);
492 copy(buffer, header);
498 NOTICE(
"Offset applied to true tracks is: " << offset << endl);
500 TH1D job(
"job", NULL, 400, 0.5, 400.5);
501 TProfile cpu(
"cpu", NULL, 16, 0.0, 8.0);
502 TProfile2D rms(
"rms", NULL, 16, 0.0, 8.0, 201, -0.5, 200.5);
503 TProfile2D rad(
"rad", NULL, 16, 0.0, 8.0, 201, -0.5, 200.5);
516 const double epsilon = 1.0e-6;
523 STATUS(
"event: " << setw(10) << in.getCounter() <<
'\r');
DEBUG(endl);
527 Evt* evt = in.next();
530 track->pos += offset;
535 event.mc_hits.clear();
542 for (vector<Trk>::const_iterator track = evt->
mc_trks.begin(); track != evt->
mc_trks.end(); ++track) {
544 if (!track->is_finalstate()) {
560 double Zmin = intersection.first;
561 double Zmax = intersection.second;
563 if (Zmax - Zmin <= parameters.Dmin_m) {
567 JVertex vertex(0.0, track->t, track->E);
569 if (track->pos.z < Zbed) {
571 if (track->dir.z > 0.0)
572 vertex.
step(
gRock, (Zbed - track->pos.z) / track->dir.z);
577 if (vertex.
getZ() < Zmin) {
578 vertex.
step(gWater, Zmin - vertex.
getZ());
581 if (vertex.
getRange() <= parameters.Dmin_m) {
589 if (subdetector.empty()) {
597 while (vertex.
getE() >= parameters.Emin_GeV && vertex.
getZ() < Zmax) {
599 const int N = radiation.size();
604 for (
int i = 0; i != N; ++i) {
605 ls += li[i] = radiation[i]->getInverseInteractionLength(vertex.
getE());
610 for (
size_t i = 0; i != ionization.size(); ++i) {
611 As += ionization[i]->getA(vertex.
getE());
614 double step = gRandom->Exp(1.0) /
ls;
617 if (vertex.
getE() < parameters.Emax_GeV) {
618 if (parameters.Dmax_m < range) {
619 range = parameters.Dmax_m;
626 rms.Fill(log10(vertex.
getE()), (Double_t) 0, ts*ts);
630 vertex.
step(As, min(step,range));
636 if (vertex.
getE() >= parameters.Emin_GeV) {
638 double y = gRandom->Uniform(
ls);
640 for (
int i = 0; i != N; ++i) {
646 Es = radiation[i]->getEnergyOfShower(vertex.
getE());
647 ts = radiation[i]->getThetaRMS(vertex.
getE(), Es);
651 rms.Fill(log10(vertex.
getE()), (Double_t) radiation[i]->getID(), ts*ts);
652 rad.Fill(log10(vertex.
getE()), (Double_t) radiation[i]->getID(), Es);
660 vertex.
applyEloss(getRandomDirection(T2), Es);
662 muon.push_back(vertex);
671 muon.push_back(vertex);
678 make_predicate(&
Trk::id, track->id));
680 if (trk != event.
mc_trks.end()) {
681 trk->len = (muon.rbegin()->getZ() < Zmax ? +1 : -1) * (muon.rbegin()->getZ() - muon.begin()->getZ());
685 for (JDetector::const_iterator module = subdetector.begin(); module != subdetector.end(); ++module) {
687 const double z0 = muon.begin()->getZ();
688 const double t0 = muon.begin()->getT();
689 const double Z =
module->getZ() - module->getX() / getTanThetaC();
691 if (Z >= muon.begin()->getZ() && Z <= muon.rbegin()->getZ()) {
693 const JVector2D pos = muon.getPosition(Z);
694 const double R = hypot(module->getX() - pos.
getX(),
695 module->getY() - pos.
getY());
697 for (
size_t i = 0; i != CDF.size(); ++i) {
699 if (R < CDF[i].integral.getXmax()) {
709 const double NPE = CDF[i].integral.getNPE(R) *
module->size() * factor * W;
710 const size_t N = getPoisson(NPE);
716 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
718 const double R = hypot(pmt->getX() - pos.
getX(),
719 pmt->getY() - pos.
getY());
720 const double theta = pi.
constrain(pmt->getTheta());
721 const double phi = pi.
constrain(fabs(pmt->getPhi()));
723 npe.push_back(CDF[i].function.getNPE(R, theta, phi) * factor * W);
728 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
730 const double R = hypot(pmt->getX() - pos.
getX(),
731 pmt->getY() - pos.
getY());
732 const double Z = pmt->getZ() - z0;
733 const double theta = pi.
constrain(pmt->getTheta());
734 const double phi = pi.
constrain(fabs(pmt->getPhi()));
736 size_t n0 = min(
ns[
distance(module->begin(),pmt)], parameters.Nmax_PMT);
738 job.Fill((
double) (100 + CDF[i].type), (
double) n0);
742 const double t1 = CDF[i].function.getTime(R, theta, phi, gRandom->Rndm());
745 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
749 t0 + (R * getTanThetaC() + Z) / C + t1,
756 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
757 job.Fill((
double) (300 + CDF[i].type));
761 catch(
const exception& error) {
762 job.Fill((
double) (200 + CDF[i].type));
769 for (JTrack::const_iterator vertex = muon.begin(); vertex != muon.end(); ++vertex) {
771 const double Es = vertex->
getEs();
773 if (Es >= parameters.Ecut_GeV) {
775 const double z0 = vertex->
getZ();
776 const double t0 = vertex->
getT();
779 int origin = track->id;
781 if (writeEMShowers) {
782 origin =
event.mc_trks.size() + 1;
785 int number_of_hits = 0;
787 JDetectorSubset_t::range_type range = subdetector.getRange(z0 - maximal_distance,
788 z0 + maximal_distance);
790 for (JDetector::const_iterator module = range.begin(); module != range.end(); ++module) {
792 const double R = hypot(module->getX() - vertex->
getX(),
793 module->getY() - vertex->
getY());
794 const double Z =
module->getZ() - z0 - DZ;
795 const double D = sqrt(R*R + Z*Z);
796 const double cd = Z / D;
798 for (
size_t i = 0; i != CDG.size(); ++i) {
800 if (D < CDG[i].integral.getXmax()) {
804 const double NPE = CDG[i].integral.getNPE(D, cd) * Es * module->size() * factor;
805 const size_t N = getPoisson(NPE);
811 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
813 const double R = hypot(pmt->getX() - vertex->
getX(),
814 pmt->getY() - vertex->
getY());
815 const double Z = pmt->getZ() - z0 - DZ;
816 const double D = sqrt(R*R + Z*Z);
817 const double cd = Z / D;
818 const double theta = pi.
constrain(pmt->getTheta());
819 const double phi = pi.
constrain(fabs(pmt->getPhi()));
821 npe.push_back(CDG[i].function.getNPE(D, cd, theta, phi) * Es * factor);
826 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
828 const double R = hypot(pmt->getX() - vertex->
getX(),
829 pmt->getY() - vertex->
getY());
830 const double theta = pi.
constrain(pmt->getTheta());
831 const double phi = pi.
constrain(fabs(pmt->getPhi()));
833 size_t n0 = min(
ns[
distance(module->begin(),pmt)], parameters.Nmax_PMT);
835 job.Fill((
double) (100 + CDG[i].type), (
double) n0);
840 const double Z = pmt->getZ() - z0 - dz;
841 const double D = sqrt(R*R + Z*Z);
842 const double cd = Z / D;
844 const double t1 = CDG[i].function.getTime(D, cd, theta, phi, gRandom->Rndm());
847 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
856 number_of_hits += n1;
860 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
861 job.Fill((
double) (300 + CDG[i].type));
865 catch(
const exception& error) {
866 job.Fill((
double) (200 + CDG[i].type));
872 if (writeEMShowers && number_of_hits != 0) {
874 event.mc_trks.push_back(
JTrk_t(origin,
877 track->pos + track->dir * vertex->
getZ(),
885 }
else if (track->len > 0.0) {
893 const double z0 = 0.0;
894 const double z1 = z0 + track->len;
895 const double t0 = track->t;
896 const double E = track->E;
902 for (JDetector::const_iterator module =
detector.begin(); module !=
detector.end(); ++module) {
906 const double R = pos.
getX();
911 R > maximal_road_width) {
915 for (
size_t i = 0; i != CDF.size(); ++i) {
927 if (R < CDF[i].integral.getXmax()) {
931 const double NPE = CDF[i].integral.getNPE(R) *
module->size() * factor * W;
932 const size_t N = getPoisson(NPE);
942 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
944 const double R = pmt->getX();
945 const double theta = pi.
constrain(pmt->getTheta());
946 const double phi = pi.
constrain(fabs(pmt->getPhi()));
948 npe.push_back(CDF[i].function.getNPE(R, theta, phi) * factor * W);
953 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
955 const double R = pmt->getX();
956 const double Z = pmt->getZ() - z0;
957 const double theta = pi.
constrain(pmt->getTheta());
958 const double phi = pi.
constrain(fabs(pmt->getPhi()));
960 size_t n0 = min(
ns[
distance(buffer.cbegin(),pmt)], parameters.Nmax_PMT);
962 job.Fill((
double) (120 + CDF[i].type), (
double) n0);
966 const double t1 = CDF[i].function.getTime(R, theta, phi, gRandom->Rndm());
969 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
973 t0 + (R * getTanThetaC() + Z) / C + t1,
980 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
981 job.Fill((
double) (320 + CDF[i].type));
985 catch(
const exception& error) {
986 job.Fill((
double) (220 + CDF[i].type));
992 if (!buffer.empty()) {
1006 double E = track->E;
1011 catch(
const exception& error) {
1012 ERROR(error.what() << endl);
1015 E =
pythia(track->type, E);
1019 const double z0 = 0.0;
1020 const double t0 = track->t;
1027 for (JDetector::const_iterator module =
detector.begin(); module !=
detector.end(); ++module) {
1031 const double R = pos.
getX();
1032 const double Z = pos.
getZ() - z0 - DZ;
1033 const double D = sqrt(R*R + Z*Z);
1034 const double cd = Z / D;
1036 for (
size_t i = 0; i != CDG.size(); ++i) {
1038 if (D < CDG[i].integral.getXmax()) {
1042 const double NPE = CDG[i].integral.getNPE(D, cd) * E * module->size() * factor;
1043 const size_t N = getPoisson(NPE);
1053 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
1055 const double R = pmt->getX();
1056 const double Z = pmt->getZ() - z0 - DZ;
1057 const double D = sqrt(R*R + Z*Z);
1058 const double cd = Z / D;
1059 const double theta = pi.
constrain(pmt->getTheta());
1060 const double phi = pi.
constrain(fabs(pmt->getPhi()));
1062 npe.push_back(CDG[i].function.getNPE(D, cd, theta, phi) * E * factor);
1067 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
1069 const double theta = pi.
constrain(pmt->getTheta());
1070 const double phi = pi.
constrain(fabs(pmt->getPhi()));
1072 size_t n0 = min(
ns[
distance(buffer.cbegin(),pmt)], parameters.Nmax_PMT);
1074 job.Fill((
double) (140 + CDG[i].type), (
double) n0);
1079 const double Z = pmt->getZ() - z0 - dz;
1080 const double D = sqrt(R*R + Z*Z);
1081 const double cd = Z / D;
1083 const double t1 = CDG[i].function.getTime(D, cd, theta, phi, gRandom->Rndm());
1086 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
1090 t0 + (dz + D * getIndexOfRefraction()) / C + t1,
1097 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
1098 job.Fill((
double) (340 + CDG[i].type));
1102 catch(
const exception& error) {
1103 job.Fill((
double) (240 + CDG[i].type));
1109 if (!buffer.empty()) {
1120 if (!mc_hits.empty()) {
1122 mc_hits.
merge(parameters.Tmax_ns);
1124 event.mc_hits.resize(mc_hits.size());
1126 copy(mc_hits.begin(), mc_hits.end(), event.
mc_hits.begin());
1135 if (event.
mc_hits.size() >= numberOfHits) {