228 string fileDescriptor;
230 JFileRecorder <JTYPELIST<JAAnetTypes_t, JMetaTypes_t, JRootTypes_t>::typelist>
outputFile;
231 JLimit_t& numberOfEvents = inputFile.getLimit();
233 JCalibration_t calibrationFile;
258 JParser<> zap(
"Main program to simulate detector response to muons and showers.");
261 zap[
'F'] =
make_field(fileDescriptor,
"file name descriptor for CDF tables");
267 zap[
'T'] =
make_field(Tmax_s,
"dynamical update time [s]") = 100.0;
268 zap[
's'] =
make_field(writeEMShowers,
"store generated EM showers in event");
269 zap[
'N'] =
make_field(numberOfHits,
"minimum number of hits to output event") = 1;
270 zap[
'U'] =
make_field(factor,
"scaling factor applied to light yields") = 1.0;
276 catch(
const exception &error) {
277 FATAL(error.what() << endl);
284 const JMeta meta(argc, argv);
286 const double Zbed = 0.0;
291 if (fileDescriptor !=
"") {
292 CDF.push_back(JCDF_t(fileDescriptor, DIRECT_LIGHT_FROM_MUON));
293 CDF.push_back(JCDF_t(fileDescriptor, SCATTERED_LIGHT_FROM_MUON));
294 CDF.push_back(JCDF_t(fileDescriptor, DIRECT_LIGHT_FROM_DELTARAYS));
295 CDF.push_back(JCDF_t(fileDescriptor, SCATTERED_LIGHT_FROM_DELTARAYS));
297 CDG.push_back(JCDG_t(fileDescriptor, DIRECT_LIGHT_FROM_EMSHOWER));
298 CDG.push_back(JCDG_t(fileDescriptor, SCATTERED_LIGHT_FROM_EMSHOWER));
301 double maximal_road_width = 0.0;
302 double maximal_distance = 0.0;
304 for (
size_t i = 0; i != CDF.size(); ++i) {
306 DEBUG(
"Range CDF["<< CDF[i].type <<
"] " << CDF[i].function.intensity.getXmax() <<
" m" << endl);
308 maximal_road_width = max(maximal_road_width, CDF[i].function.intensity.getXmax());
311 for (
size_t i = 0; i != CDG.size(); ++i) {
313 DEBUG(
"Range CDG["<< CDG[i].type <<
"] " << CDG[i].function.intensity.getXmax() <<
" m" << endl);
316 maximal_road_width = max(maximal_road_width, CDG[i].function.intensity.getXmax());
319 maximal_distance = max(maximal_distance, CDG[i].function.intensity.getXmax());
322 NOTICE(
"Maximal road width [m] " << maximal_road_width << endl);
323 NOTICE(
"Maximal distance [m] " << maximal_distance << endl);
326 if (detectorFile ==
"" || inputFile.empty()) {
327 STATUS(
"Nothing to be done." << endl);
337 STATUS(
"Load detector... " << flush);
339 load(detectorFile, master.detector);
347 unique_ptr<JDynamics> dynamics;
349 if (!calibrationFile.empty()) {
353 dynamics.reset(
new JDynamics(master.detector, Tmax_s));
355 dynamics->load(calibrationFile);
357 catch(
const exception& error) {
362 const JDetector&
detector = (dynamics ? dynamics->getDetector() : master.detector);
369 STATUS(
"Setting up radiation tables... " << flush);
376 const JRadiation calcium (JSeaWater::Ca.Z, JSeaWater::Ca.A, 40, 0.01, 0.1, 0.1);
377 const JRadiation magnesium(JSeaWater::Mg.Z, JSeaWater::Mg.A, 40, 0.01, 0.1, 0.1);
378 const JRadiation potassium(JSeaWater::K .Z, JSeaWater::K .A, 40, 0.01, 0.1, 0.1);
379 const JRadiation sulphur (JSeaWater::S .Z, JSeaWater::S .A, 40, 0.01, 0.1, 0.1);
382 shared_ptr<JRadiation> Hydrogen (make_shared<JRadiationFunction>(hydrogen, 300, 0.2, 1.0e11));
383 shared_ptr<JRadiation> Oxygen (make_shared<JRadiationFunction>(oxygen, 300, 0.2, 1.0e11));
384 shared_ptr<JRadiation> Chlorine (make_shared<JRadiationFunction>(chlorine, 300, 0.2, 1.0e11));
385 shared_ptr<JRadiation> Sodium (make_shared<JRadiationFunction>(sodium, 300, 0.2, 1.0e11));
387 shared_ptr<JRadiation> Calcium (make_shared<JRadiationFunction>(calcium, 300, 0.2, 1.0e11));
388 shared_ptr<JRadiation> Magnesium(make_shared<JRadiationFunction>(magnesium,300, 0.2, 1.0e11));
389 shared_ptr<JRadiation> Potassium(make_shared<JRadiationFunction>(potassium,300, 0.2, 1.0e11));
390 shared_ptr<JRadiation> Sulphur (make_shared<JRadiationFunction>(sulphur, 300, 0.2, 1.0e11));
428 radiation.push_back(make_shared<JDeltaRaysSource>(200,
DENSITY_SEA_WATER, parameters.Tmin_GeV));
435 ionization.push_back(make_shared<JACoeffSource>(Calcium,
DENSITY_SEA_WATER * JSeaWater::Ca()));
436 ionization.push_back(make_shared<JACoeffSource>(Magnesium,
DENSITY_SEA_WATER * JSeaWater::Mg()));
437 ionization.push_back(make_shared<JACoeffSource>(Potassium,
DENSITY_SEA_WATER * JSeaWater::K()));
438 ionization.push_back(make_shared<JACoeffSource>(Sulphur,
DENSITY_SEA_WATER * JSeaWater::S()));
449 if (cylinder.
getZmin() < Zbed) {
453 NOTICE(
"Light generation volume: " << cylinder << endl);
461 header = inputFile.getHeader();
477 buffer.
detector.rbegin()->filename = detectorFile;
481 offset +=
Vec(cylinder.
getX(), cylinder.
getY(), 0.0);
518 copy(buffer, header);
524 NOTICE(
"Offset applied to true tracks is: " << offset << endl);
526 TH1D job(
"job", NULL, 400, 0.5, 400.5);
527 TProfile cpu(
"cpu", NULL, 16, 0.0, 8.0);
528 TProfile2D rms(
"rms", NULL, 16, 0.0, 8.0, 251, -0.5, 250.5);
529 TProfile2D rad(
"rad", NULL, 16, 0.0, 8.0, 251, -0.5, 250.5);
542 const double epsilon = 1.0e-6;
549 STATUS(
"event: " << setw(10) << in.getCounter() <<
'\r');
DEBUG(endl);
553 Evt* evt = in.next();
556 track->pos += offset;
561 event.mc_hits.clear();
566 FATAL(
"Monte Carlo event time undefined." << endl);
578 for (vector<Trk>::const_iterator track = evt->
mc_trks.begin(); track != evt->
mc_trks.end(); ++track) {
580 if (!track->is_finalstate()) {
596 double Zmin = intersection.first;
597 double Zmax = intersection.second;
599 if (Zmax - Zmin <= parameters.Dmin_m) {
603 JVertex vertex(0.0, track->t, track->E);
605 if (track->pos.z < Zbed) {
607 if (track->dir.z > 0.0)
608 vertex.
step(
gRock, (Zbed - track->pos.z) / track->dir.z);
613 if (vertex.
getZ() < Zmin) {
614 vertex.
step(gWater, Zmin - vertex.
getZ());
617 if (vertex.
getRange() <= parameters.Dmin_m) {
625 if (subdetector.empty()) {
633 while (vertex.
getE() >= parameters.Emin_GeV && vertex.
getZ() < Zmax) {
635 const int N = radiation.size();
640 for (
int i = 0; i != N; ++i) {
641 ls += li[i] = radiation[i]->getInverseInteractionLength(vertex.
getE());
648 for (
size_t i = 0; i != ionization.size(); ++i) {
649 As += ionization[i]->getA(vertex.
getE());
652 double step = gRandom->Exp(1.0) /
ls;
655 if (vertex.
getE() < parameters.Emax_GeV) {
656 if (parameters.Dmax_m < range) {
657 range = parameters.Dmax_m;
664 rms.Fill(log10(vertex.
getE()), (Double_t) 0, ts*ts);
668 vertex.
step(As, min(step,range));
674 if (vertex.
getE() >= parameters.Emin_GeV) {
676 double y = gRandom->Uniform(
ls);
678 for (
int i = 0; i != N; ++i) {
684 Es = radiation[i]->getEnergyOfShower(vertex.
getE());
685 ts = radiation[i]->getThetaRMS(vertex.
getE(), Es);
689 rms.Fill(log10(vertex.
getE()), (Double_t) radiation[i]->getID(), ts*ts);
690 rad.Fill(log10(vertex.
getE()), (Double_t) radiation[i]->getID(), Es);
698 vertex.
applyEloss(getRandomDirection(T2), Es);
700 muon.push_back(vertex);
711 muon.push_back(vertex);
718 make_predicate(&
Trk::id, track->id));
720 if (trk != event.
mc_trks.end()) {
721 trk->len = (muon.rbegin()->getZ() < Zmax ? +1 : -1) * (muon.rbegin()->getZ() - muon.begin()->getZ());
725 for (JDetector::const_iterator module = subdetector.begin(); module != subdetector.end(); ++module) {
727 if (module->empty()) {
731 const double z0 = muon.begin()->getZ();
732 const double t0 = muon.begin()->getT();
733 const double Z =
module->getZ() - module->getX() / getTanThetaC();
735 if (Z >= muon.begin()->getZ() && Z <= muon.rbegin()->getZ()) {
737 const JVector2D pos = muon.getPosition(Z);
738 const double R = hypot(module->getX() - pos.
getX(),
739 module->getY() - pos.
getY());
741 for (
size_t i = 0; i != CDF.size(); ++i) {
743 if (R < CDF[i].integral.getXmax()) {
753 const double NPE = CDF[i].integral.getNPE(R) *
module->size() * factor * W;
754 const size_t N = getPoisson(NPE);
760 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
762 const double R = hypot(pmt->getX() - pos.
getX(),
763 pmt->getY() - pos.
getY());
764 const double theta = pi.
constrain(pmt->getTheta());
765 const double phi = pi.
constrain(fabs(pmt->getPhi()));
767 npe.push_back(CDF[i].function.getNPE(R, theta, phi) * factor * W);
772 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
774 const double R = hypot(pmt->getX() - pos.
getX(),
775 pmt->getY() - pos.
getY());
776 const double Z = pmt->getZ() - z0;
777 const double theta = pi.
constrain(pmt->getTheta());
778 const double phi = pi.
constrain(fabs(pmt->getPhi()));
780 size_t n0 = min(ns[
distance(module->begin(),pmt)], parameters.Nmax_PMT);
782 job.Fill((
double) (100 + CDF[i].type), (
double) n0);
786 const double t1 = CDF[i].function.getTime(R, theta, phi, gRandom->Rndm());
789 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
793 t0 + (R * getTanThetaC() + Z) / C + t1,
800 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
801 job.Fill((
double) (300 + CDF[i].type));
805 catch(
const exception& error) {
806 job.Fill((
double) (200 + CDF[i].type));
813 for (JTrack::const_iterator vertex = muon.begin(); vertex != muon.end(); ++vertex) {
815 const double Es = vertex->
getEs();
817 if (Es >= parameters.Ecut_GeV) {
819 const double z0 = vertex->
getZ();
820 const double t0 = vertex->
getT();
823 int origin = track->id;
825 if (writeEMShowers) {
826 origin =
event.mc_trks.size() + 1;
829 int number_of_hits = 0;
831 JDetectorSubset_t::range_type range = subdetector.getRange(z0 - maximal_distance,
832 z0 + maximal_distance);
834 for (JDetector::const_iterator module = range.begin(); module != range.end(); ++module) {
836 if (module->empty()) {
840 const double R = hypot(module->getX() - vertex->
getX(),
841 module->getY() - vertex->
getY());
842 const double Z =
module->getZ() - z0 - DZ;
843 const double D = sqrt(R*R + Z*Z);
844 const double cd = Z / D;
846 for (
size_t i = 0; i != CDG.size(); ++i) {
848 if (D < CDG[i].integral.getXmax()) {
852 const double NPE = CDG[i].integral.getNPE(D, cd) * Es * module->size() * factor;
853 const size_t N = getPoisson(NPE);
859 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
861 const double R = hypot(pmt->getX() - vertex->
getX(),
862 pmt->getY() - vertex->
getY());
863 const double Z = pmt->getZ() - z0 - DZ;
864 const double D = sqrt(R*R + Z*Z);
865 const double cd = Z / D;
866 const double theta = pi.
constrain(pmt->getTheta());
867 const double phi = pi.
constrain(fabs(pmt->getPhi()));
869 npe.push_back(CDG[i].function.getNPE(D, cd, theta, phi) * Es * factor);
874 for (JModule::const_iterator pmt = module->begin(); pmt != module->end(); ++pmt) {
876 const double R = hypot(pmt->getX() - vertex->
getX(),
877 pmt->getY() - vertex->
getY());
878 const double theta = pi.
constrain(pmt->getTheta());
879 const double phi = pi.
constrain(fabs(pmt->getPhi()));
881 size_t n0 = min(ns[
distance(module->begin(),pmt)], parameters.Nmax_PMT);
883 job.Fill((
double) (100 + CDG[i].type), (
double) n0);
888 const double Z = pmt->getZ() - z0 - dz;
889 const double D = sqrt(R*R + Z*Z);
890 const double cd = Z / D;
892 const double t1 = CDG[i].function.getTime(D, cd, theta, phi, gRandom->Rndm());
895 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
904 number_of_hits += n1;
908 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
909 job.Fill((
double) (300 + CDG[i].type));
913 catch(
const exception& error) {
914 job.Fill((
double) (200 + CDG[i].type));
920 if (writeEMShowers && number_of_hits != 0) {
922 event.mc_trks.push_back(
JTrk_t(origin,
925 track->pos + track->dir * vertex->
getZ(),
933 }
else if (track->len > 0.0) {
941 const double z0 = 0.0;
942 const double z1 = z0 + track->len;
943 const double t0 = track->t;
944 const double E = track->E;
950 for (JDetector::const_iterator module =
detector.begin(); module !=
detector.end(); ++module) {
952 if (module->empty()) {
958 const double R = pos.
getX();
963 R > maximal_road_width) {
967 for (
size_t i = 0; i != CDF.size(); ++i) {
979 if (R < CDF[i].integral.getXmax()) {
983 const double NPE = CDF[i].integral.getNPE(R) *
module->size() * factor * W;
984 const size_t N = getPoisson(NPE);
994 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
996 const double R = pmt->getX();
997 const double theta = pi.
constrain(pmt->getTheta());
998 const double phi = pi.
constrain(fabs(pmt->getPhi()));
1000 npe.push_back(CDF[i].function.getNPE(R, theta, phi) * factor * W);
1005 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
1007 const double R = pmt->getX();
1008 const double Z = pmt->getZ() - z0;
1009 const double theta = pi.
constrain(pmt->getTheta());
1010 const double phi = pi.
constrain(fabs(pmt->getPhi()));
1012 size_t n0 = min(ns[
distance(buffer.cbegin(),pmt)], parameters.Nmax_PMT);
1014 job.Fill((
double) (120 + CDF[i].type), (
double) n0);
1018 const double t1 = CDF[i].function.getTime(R, theta, phi, gRandom->Rndm());
1021 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
1025 t0 + (R * getTanThetaC() + Z) / C + t1,
1032 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
1033 job.Fill((
double) (320 + CDF[i].type));
1037 catch(
const exception& error) {
1038 job.Fill((
double) (220 + CDF[i].type));
1044 if (!buffer.empty()) {
1058 double E = track->E;
1063 catch(
const exception& error) {
1064 ERROR(error.what() << endl);
1067 E =
pythia(track->type, E);
1071 const double z0 = 0.0;
1072 const double t0 = track->t;
1079 for (JDetector::const_iterator module =
detector.begin(); module !=
detector.end(); ++module) {
1081 if (module->empty()) {
1087 const double R = pos.
getX();
1088 const double Z = pos.
getZ() - z0 - DZ;
1089 const double D = sqrt(R*R + Z*Z);
1090 const double cd = Z / D;
1092 for (
size_t i = 0; i != CDG.size(); ++i) {
1094 if (D < CDG[i].integral.getXmax()) {
1098 const double NPE = CDG[i].integral.getNPE(D, cd) * E * module->size() * factor;
1099 const size_t N = getPoisson(NPE);
1109 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
1111 const double R = pmt->getX();
1112 const double Z = pmt->getZ() - z0 - DZ;
1113 const double D = sqrt(R*R + Z*Z);
1114 const double cd = Z / D;
1115 const double theta = pi.
constrain(pmt->getTheta());
1116 const double phi = pi.
constrain(fabs(pmt->getPhi()));
1118 npe.push_back(CDG[i].function.getNPE(D, cd, theta, phi) * E * factor);
1123 for (JModule::const_iterator pmt = buffer.begin(); pmt != buffer.end(); ++pmt) {
1125 const double theta = pi.
constrain(pmt->getTheta());
1126 const double phi = pi.
constrain(fabs(pmt->getPhi()));
1128 size_t n0 = min(ns[
distance(buffer.cbegin(),pmt)], parameters.Nmax_PMT);
1130 job.Fill((
double) (140 + CDG[i].type), (
double) n0);
1135 const double Z = pmt->getZ() - z0 - dz;
1136 const double D = sqrt(R*R + Z*Z);
1137 const double cd = Z / D;
1139 const double t1 = CDG[i].function.getTime(D, cd, theta, phi, gRandom->Rndm());
1142 mc_hits.push_back(
JHit_t(mc_hits.size() + 1,
1146 t0 + (dz + D * getIndexOfRefraction()) / C + t1,
1153 if (std::accumulate(npe.begin(), npe.end(), 0.0) > NPE) {
1154 job.Fill((
double) (340 + CDG[i].type));
1158 catch(
const exception& error) {
1159 job.Fill((
double) (240 + CDG[i].type));
1165 if (!buffer.empty()) {
1176 if (!mc_hits.empty()) {
1178 mc_hits.
merge(parameters.Tmax_ns);
1180 event.mc_hits.resize(mc_hits.size());
1182 copy(mc_hits.begin(), mc_hits.end(), event.
mc_hits.begin());
1188 cpu.Fill(log10(
get_neutrino(event).E), (
double) timer() * 1.0e-3);
1191 if (event.
mc_hits.size() >= numberOfHits) {