389int main(  
int argc, 
char** argv ) {
 
  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 
 
  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]) ;
 
  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 ; 
 
  556  const double cw = JTOOLS::getSpeedOfLight() / index_of_refraction ;
 
  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 ) {
 
  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 ;
 
  752    for( 
int pmt=0 ; pmt<31 ; ++pmt ) {
 
  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 ) {
 
  821      if( PMT_is_hit[i] != pmt ) continue ;
 
  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 ;