390 cout <<
"JBeaconSimulator version " <<
JBSversion << endl
394 string detectorFile ;
396 JModuleLocation source_location ;
399 unsigned int nscatmax ;
400 unsigned long int nphotons ;
402 double opening_angle_deg ;
403 double beacon_theta_deg ;
404 double beacon_phi_deg ;
410 double target_step_size_deg ;
411 double tangential_step_size_deg ;
426 zap[
"N-integration-samples"] =
make_field(nsamples) = 1e6 ;
428 zap[
"write-paths"] =
make_field(write_paths) ;
430 zap[
"opening-angle"] =
make_field(opening_angle_deg) = 45 ;
431 zap[
"beacon-theta-deg"] =
make_field(beacon_theta_deg) = 56.2893-15 ;
432 zap[
"beacon-phi-deg"] =
make_field(beacon_phi_deg) = -59.9998 ;
437 zap[
"stepsizes"] =
make_field(stepsizes) = empty_vector ;
438 zap[
"target-step-size-deg"] =
make_field(target_step_size_deg) = 1.0 ;
439 zap[
"tangential-step-size-deg"] =
make_field(tangential_step_size_deg) = 1.0 ;
440 zap[
"no-remapping"] =
make_field(no_remapping) ;
442 if (zap.
read(argc, argv) != 0)
exit(1) ;
444 catch(
const exception &error) {
445 cerr << error.what() << endl ;
452 extensions.push_back(
".root") ;
453 extensions.push_back(
".paths") ;
455 size_t pos = ofname.find(*it) ;
456 if( pos != string::npos ) {
457 ofname = ofname.substr(0,pos) ;
464 const int ndefvals = 6 ;
465 double defvals[ndefvals] = { 8, 5, 4, 3, 2, 1 } ;
466 while( stepsizes.size()<nscatmax ) {
467 double val = defvals[min(ndefvals-1,(
int)stepsizes.size())] ;
468 stepsizes.push_back(val) ;
475 load(detectorFile, detector);
478 cout <<
"FATAL ERROR: could not open detector file '" << detectorFile <<
"'." ;
485 gRandom =
new TRandom3(0) ;
488 const double DOM_radius = 0.2159 ;
497 JAxis3D source_axis(
getBeaconAxis(source_module,DOM_radius+0.00001,beacon_theta_deg*M_PI/180,beacon_phi_deg*M_PI/180) ) ;
500 cout <<
"SOURCE (NANOBEACON)" << endl
501 <<
"Positioned on string " << source_location.getString() <<
" floor " << source_location.getFloor()
502 <<
" (DOM center @ " <<
getDOMcenter(source_module) <<
")" << endl
503 <<
"Position in local DOM coordinates: theta = "
504 << beacon_theta_deg <<
" deg, "
505 <<
"phi = " << beacon_phi_deg <<
" deg" << endl
506 <<
"distance w.r.t. DOM center = " << (source_axis.getPosition()-
getDOMcenter(source_module)).getLength() <<
" m" << endl
507 <<
"unit vector from DOM center to beacon position = " <<
JVersor3D(source_axis.getPosition()-
getDOMcenter(source_module)) << endl
508 <<
"beam direction = " << source_axis.getDirection() << endl
509 <<
"beam opening angle = " << opening_angle_deg <<
" deg" << endl
510 <<
"surface normal = " << surface_normal << endl
514 if( target_pmt.size() != 3 ) {
515 cerr <<
"FATAL ERROR: provide a target PMT in the format "
516 <<
"\"string floor daq_channel\"." << endl ;
522 if( target_pmt[2]<0 || target_pmt[2]>30 ) {
523 cerr <<
"FATAL ERROR: invalid target pmt index ("
524 << target_pmt[2] <<
")" << endl ;
529 JModuleLocation target_location(target_pmt[0],target_pmt[1]) ;
531 JAxis3D target_axis(
getDOMcenter(target_module), target_module.getPMT(target_pmt[2]).getDirection() ) ;
535 opening_angle_deg*M_PI/180,
541 cout <<
"PHYSICS" << endl ;
543 cout <<
"Henyey-Greenstein scattering length = " << lHG <<
" [m], g = " << gHG << endl ;
545 cout <<
"Rayleigh scattering length = " << lR <<
" [m], a = " << aR << endl ;
547 cout <<
"Absorption length = " << Labs <<
" [m]" << endl ;
551 const double water_depth = 3000 ;
552 const double pressure = 0.1*water_depth ;
554 const double nbwavelength = 470 ;
555 const double index_of_refraction = jd.getIndexOfRefractionGroup(nbwavelength) ;
557 cout <<
"Assuming speed of light in water = " << cw <<
" [m/ns]" << endl ;
567 cout <<
"TARGET" << endl ;
568 const double pmt_opening_angle_deg = 30 ;
569 const double pmt_opening_angle_rad = pmt_opening_angle_deg*M_PI/180.0 ;
570 const double pmt_ctmin = cos(0.5*pmt_opening_angle_rad) ;
571 cout <<
"DOM: string " << target_pmt[0]
572 <<
", floor " << target_pmt[1]
574 <<
"Target radius = " << DOM_radius <<
" [m]" << endl
576 if( useTracker ) cout <<
"all 31 PMTs" ;
577 else cout <<
"PMT " << target_pmt[2] <<
", direction = " << target_axis.getDirection() ;
579 <<
"PMTs are simulated as spherical caps" << endl
580 <<
"PMT opening angle = " << pmt_opening_angle_deg <<
" deg." << endl
592 trg =
new JPMTTarget(target_axis,pmt_opening_angle_rad,DOM_radius) ;
595 unsigned long int n_generated_photons = nphotons ;
598 cout <<
"Generating photon paths by photon tracking" << endl ;
604 cout <<
"Photon hits: " << paths.size() <<
" / " << n_generated_photons << endl ;
619 cout <<
"WARNING: coordinate remapping is deactivated!" << endl ;
623 int nsteps_save = 250 ;
624 int nsteps_burn_in = 10*nsteps_save ;
625 for(
int nscat=0 ; nscat<=(int)nscatmax ; ++nscat ) {
626 cout <<
"nscat = " << nscat << endl ;
628 double stepsize = 1 ;
629 if( nscat>0 && (
int)stepsizes.size()>=nscat ) stepsize = stepsizes[nscat-1] ;
632 if( nscat != 0 ) cout <<
"step size = " << stepsize <<
" [m]" << endl ;
637 cout <<
"path = " << endl ;
640 cout <<
"start_rho = " << start_rho << endl ;
641 if( start_rho == 0 ) {
642 cout <<
"No possible photon path found with nscat = " << nscat <<
". Skipping nscat = " << nscat <<
"." << endl
643 <<
"WARNING: note that this does not necessarily mean there are no such paths, simply that the search algorithm could not find one." << endl
659 nsteps_burn_in, nsteps_save ) ;
663 cout <<
"Accepted " << naccepted <<
" / " << nsteps <<
" steps (" << mpg.
getFractionAccepted()*100.0 <<
"%)" << endl
666 cout <<
"NOTE: as a rule of thumb, the optimal value is around ~23% (this can be achieved by modifying the various step sizes)" << endl ;
668 paths.insert(paths.end(), these_paths.begin(), these_paths.end()) ;
671 if( these_paths.size() == 0 ) {
672 cerr <<
"Something went wrong. The MCMC generator returned no paths." << endl ;
676 cout <<
"Creating JMarkovEnsembleIntegrator" << endl ;
679 cout <<
"Integrating" << endl ;
682 Pscat[nscat] =
getMean(result) ;
683 Perr[nscat] =
getSigma(result) / sqrt(nsamples) ;
685 integrators.push_back(jmi) ;
691 if( paths.size()==0 ) {
692 cerr <<
"FATAL ERROR: no paths were generated!" << endl ;
699 unsigned int npaths = paths.size() ;
704 for(
unsigned int i=0; i<npaths; ++i ) {
705 path_lengths[i] = paths[i].getLength() ;
706 xs[i] = paths[i].back().getX() ;
707 ys[i] = paths[i].back().getY() ;
708 zs[i] = paths[i].back().getZ() ;
709 int nscat = paths[i].size()-2 ;
710 if( nscat>(
int)nscatmax ) nscatmax = nscat ;
733 for(
unsigned int i=0; i<npaths; ++i ) {
738 for(
unsigned int pmt=0 ;
pmt<31 ; ++
pmt ) {
739 double ct = target_module.getPMT(
pmt).getDirection().
getDot(hit_direction) ;
740 if( ct>pmt_ctmin ) hitPMTs.push_back(
pmt) ;
742 if( hitPMTs.size()==1 ) {
743 PMT_is_hit[i] = hitPMTs[0] ;
744 ++nHitsPerPMT[ hitPMTs[0] ] ;
746 if( hitPMTs.size()>1 ) {
747 cerr <<
"FATAL ERROR: hit " << hitPMTs.size() <<
" PMTs simultaneously" << endl ;
753 if( nHitsPerPMT[
pmt]>0 ) {
754 cout <<
"PMT" << setw(2) <<
pmt <<
": " << setw(15) << nHitsPerPMT[
pmt] <<
" hits" << endl ;
761 const double dt = 0.1 ;
762 const unsigned int margin = 5 ;
763 double Lmin = *min_element(path_lengths.begin(),path_lengths.end() ) ;
764 double Lmax = *max_element(path_lengths.begin(),path_lengths.end() ) ;
765 double tmin = floor( Lmin / cw - margin ) ;
766 double tmax = ceil( Lmax / cw + margin ) ;
767 int nbinst = (int) round( (tmax-tmin)/dt ) ;
773 pmtfront = target_pmt[2] ;
774 pmtback = target_pmt[2]+1 ;
777 for(
int pmt=pmtfront ;
pmt<pmtback ; ++
pmt ) {
780 sprintf( fname,
"%s_PMT%i.root", ofname.c_str(),
pmt ) ;
781 TFile*
f =
new TFile(fname,
"recreate") ;
784 TH1D hpulse(
"hpulse",
"Instantaneous flash pulse profile;time since flash [ns];hit probability / ns",
787 for(
int nscat=0 ; nscat<=(int)nscatmax ; ++nscat ) {
789 sprintf(hname,
"hpulse_nscat%i",nscat) ;
790 hpulse_per_nscat[nscat] =
new TH1D(hname,
"Instantaneous flash pulse profile;time since flash [ns];hit probability / ns",
793 TH2D hXY(
"hXY",
"hit position;X;Y",
796 hXY.SetOption(
"colz") ;
797 TH2D hXZ(
"hXZ",
"hit position;X;Z",
800 hXZ.SetOption(
"colz") ;
801 TH2D hYZ(
"hYZ",
"hit position;Y;Z",
804 hYZ.SetOption(
"colz") ;
805 TH1D hnscat(
"hnscat",
";N_{scat};probability",nscatmax+2,-0.5,nscatmax+1.5) ;
807 TH3D hregion(
"hregion",
"Photon paths;X;Y;Z",
820 for(
unsigned int i=0 ; i<npaths ; ++i ) {
823 paths_to_write.push_back(paths[i]) ;
825 const double path_length = paths[i].getLength() ;
826 double t = path_length/cw ;
827 int nscat = paths[i].size()-2 ;
830 if( useTracker ) w = 1.0 / n_generated_photons ;
831 else w = Pscat[nscat] / n_generated_photons ;
834 hnscat.Fill(nscat,w) ;
835 hpulse_per_nscat[nscat]->Fill(t,w) ;
837 hXY.Fill(xs[i],ys[i],w) ;
838 hXZ.Fill(xs[i],zs[i],w) ;
839 hYZ.Fill(ys[i],zs[i],w) ;
841 if( paths.size()<10000 ) {
842 const double dl = 0.001 ;
843 const double dw = w*dl/path_length ;
844 double l_along_seg = 0.5*dl ;
846 for(
int nv=0; nv<(int)paths[i].size()-1; ++nv ) {
847 double seg_length = paths[i][nv+1].getDistance(paths[i][nv]) ;
848 JVersor3D seg_dir( paths[i][nv+1] - paths[i][nv] ) ;
849 while( l_along_seg<seg_length ) {
851 hregion.Fill( pos.getX(), pos.getY(), pos.getZ(), dw ) ;
853 cerr <<
"Woohoooo" << endl ;
859 l_along_seg -= seg_length ;
865 hregion.Scale(1e20) ;
869 char path_fname[500] ;
870 sprintf( path_fname,
"%s_PMT%i.paths", ofname.c_str(),
pmt ) ;
871 cout <<
"Writing paths." << endl ;
878 for( Int_t bin=1 ; bin<=hnscat.GetNbinsX() ; ++bin ) {
879 double val = hnscat.GetBinContent(bin) ;
880 double nentries = max(1.0, val*n_generated_photons ) ;
881 hnscat.SetBinError(bin, sqrt(nentries)/n_generated_photons) ;
887 for(
int nscat=0 ; nscat<=(int)nscatmax ; ++nscat ) {
888 Int_t bin = hnscat.GetXaxis()->FindBin(nscat) ;
889 double val = hnscat.GetBinContent(bin) ;
890 double err = Perr[nscat]/Pscat[nscat]*val ;
891 hnscat.SetBinError(bin,err) ;
896 hpulse.Scale(1.0/dt) ;
897 for(
int nscat=0 ; nscat<=(int)nscatmax ; ++nscat ) {
898 hpulse_per_nscat[nscat]->Scale(1.0/dt) ;
903 TH1D* hpulse_cum = (TH1D*) hpulse.Clone(
"hpulse_cum") ;
904 hpulse_cum->GetYaxis()->SetTitle(
"cumulative hit probability") ;
905 for( Int_t bin=1 ; bin<=hpulse_cum->GetNbinsX() ; ++bin ) {
906 double val = hpulse_cum->GetBinContent(bin-1) ;
907 val += hpulse_cum->GetBinContent(bin) * hpulse_cum->GetXaxis()->GetBinWidth(bin) ;
908 hpulse_cum->SetBinContent(bin,val) ;
913 f->mkdir(
"EnsembleIntegratorHistograms")->cd() ;
915 (*it)->writeHistograms() ;
921 cout <<
"Output in '" << fname <<
"'." << endl ;
923 cout <<
"Done!" << endl ;
Utility class to parse command line options.
The JMarkovPhotonTracker generates ensembles of photon paths by tracking photons from a source to a t...
The JMarkovPathGenerator generates ensembles of photon paths using a Markov Chain Monte Carlo (MCMC)...
Data structure for a composite optical module.
JAxis3D getBeaconAxis(const JModule &dom, double r, double beacon_theta, double beacon_phi)
Get the position and orientation of the nanobeacon on a DOM.
void setRadius(double _r)
void writePaths(string ofname, vector< JPhotonPath > paths)
Implementation of dispersion for water in deep sea.
double getSigma(vector< double > &v)
get standard deviation of vector content
Router for direct addressing of module data in detector data structure.
Implementation of the JTargetModel class that represents a spherically symmetric target.
int getNsteps()
get the number of Markov steps taken in the last call to generateEnsemble (after burn-in) ...
std::vector< JPhotonPath > trackPhotons(unsigned long int n, JSourceModel *src, JScatteringModel *sm, JTargetModel *trg, double lambda_abs)
Track n photons.
Implementation of JMarkovEnsembleIntegrator interface with 1D histograms.
void setPosition(JPosition3D &_pos)
double getMean(vector< double > &v)
get mean of vector content
void setCoordinateRemapping(bool val=true)
activate or deactive coordinate remapping
int getNacceptedSteps()
get the number of accepted steps taken during the last call to generateEnsemble (after burn-in) ...
esac $JPP_DIR examples JDetector JTransitTime o $OUTPUT_FILE n N $NPE T $TTS_NS d $DEBUG for HISTOGRAM in tts tt2 pmt
Implementation of the JScatteringModel interface with scattering according to the Henyey-Greenstein f...
void setTangentialStepSize_deg(double val)
Set the average step size theta in degrees for steps in the tangential direction for the scattering v...
Implementation of the JScatteringModel interface with Rayleigh scattering.
Finds photon paths from a nanobeacon source to a target PMT that have a non-zero probability.
const JPosition3D & getPosition() const
std::vector< JPhotonPath > generateEnsemble(int n, const JPhotonPath &start_path, JSourceModel *src, JScatteringModel *sm, JTargetModel *trg, double lambda_abs, int nsteps_burn_in, int nsteps_save)
Generate an ensemble of n paths with a fixed number of scatterings by MCMC-sampling the given scatter...
string getString()
get a string with the path vertex positions
Implementation of the JSourceModel class that represents a directed source with a flat intensity dist...
Data structure for vector in three dimensions.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
double getFractionAccepted_radial()
get the fraction of steps that were accepted when a radial step was performed during the last call to...
double getFractionAccepted()
get the fraction of accepted steps during the last call to generateEnsemble (after burn-in) ...
void setPosition(JPosition3D &_pos)
double getY() const
Get y position.
void load(const JString &file_name, JDetector &detector)
Load detector from input file.
Implementation of the JTargetModel class that represents a single PMT on a DOM.
double getFractionAccepted_tangential()
get the fraction of steps that were accepted when a tangential step was performed during the last cal...
then print u2 $script< option > print u2 Possible continue
JPosition3D getDOMcenter(const JModule &dom)
Returns a good guess of where the actual center of the DOM is based on the PMT positions and directio...
Implementation of the JScatteringModel interface with that combines two scattering models into one ef...
int read(const int argc, const char *const argv[])
Parse the program's command line options.
double getX() const
Get x position.
Virtual base class for a scattering model.
Virtual base class for a light detector ("photon target").
double getDot(const JVersor3D &versor) const
Get dot product.
void printResult(vector< double > &v)
Data structure for position in three dimensions.
JPhotonPath solve(int nscat, const JDirectedSource *src, const JPMTTarget *trg)
void setRadialStepSize_m(double val)
set the average step size in [m] in the radial direction for the scattering vertices ...
Data structure for normalised vector in three dimensions.
double getPhotonPathProbabilityDensity(JPhotonPath &p, JSourceModel *src, JScatteringModel *sm, JTargetModel *trg, double lambda_abs)
Return the probability density for a photon path with the given ingredients.
double getZ() const
Get z position.
const JModule & getModule(const JDetector &detector, const JModuleLocation &location)
find module with a given string and floor number
vector< double > integrate(int N, int nscat, JSourceModel *src, JScatteringModel *sm, JTargetModel *trg, double lambda_abs)
Integrate with N samples.
void setTargetStepSize_deg(double val)
set the average step size in degrees for the impact point on the target