13 #include "cetlib_except/exception.h" 
   14 #include "messagefacility/MessageLogger/MessageLogger.h" 
   21 #include "boost/math/special_functions/ellint_1.hpp" 
   22 #include "boost/math/special_functions/ellint_3.hpp" 
   27   fVUVHitsParams(VUVHits)
 
   28   , fVISHitsParams(VISHits)
 
   29   , fISTPC{*(lar::providerFrom<geo::Geometry>())}
 
   30   , 
fGeom{*(lar::providerFrom<geo::Geometry>())}
 
   32   , fActiveVolumes(fISTPC.extractActiveLArVolume(
fGeom))
 
   33   , fcathode_centre{
fGeom.TPC(0, 0).GetCathodeCenter().X(),
 
   34                     fActiveVolumes[0].CenterY(),
 
   35                     fActiveVolumes[0].CenterZ()}
 
   36   , fanode_centre{
fGeom.TPC(0, 0).FirstPlane().GetCenter().X(),
 
   37                   fActiveVolumes[0].CenterY(),
 
   38                   fActiveVolumes[0].CenterZ()}
 
   39   , nOpDets(
fGeom.NOpDets())
 
   40   , fvuv_absorption_length(VUVAbsorptionLength())
 
   41   , fDoReflectedLight(doReflectedLight)
 
   42   , fIncludeAnodeReflections(includeAnodeReflections)
 
   45   mf::LogInfo(
"SemiAnalyticalModel") << 
"Semi-analytical model initialized." << std::endl;
 
   66     else if (opDet.
isBar()) {
 
   88   mf::LogInfo(
"SemiAnalyticalModel") << 
"Using VUV visibility parameterization";
 
  100     throw cet::exception(
"SemiAnalyticalModel")
 
  101       << 
"Both isFlatPDCorr/isFlatPDCorrLat and isDomePDCorr parameters are false, at least one type of parameterisation is required for the semi-analytic light simulation." << 
"\n";
 
  108   if (fIsFlatPDCorrLat) {
 
  122     mf::LogInfo(
"SemiAnalyticalModel") << 
"Using VIS (reflected) visibility parameterization";
 
  144     mf::LogInfo(
"SemiAnalyticalModel") << 
"Using anode reflections parameterization";
 
  154     if (fIsFlatPDCorrLat) {
 
  172   std::map<double, double> abs_length_spectrum = lar::providerFrom<detinfo::LArPropertiesService>()->
AbsLengthSpectrum();
 
  173   std::vector<double> x_v, y_v;
 
  174   for (
auto elem : abs_length_spectrum) {
 
  175     x_v.push_back(elem.first);
 
  176     y_v.push_back(elem.second);
 
  178   int vuv_absorption_length = std::round(
interpolate(x_v, y_v, 9.7, 
false)); 
 
  179   if (vuv_absorption_length <= 0){
 
  180     throw cet::exception(
"SemiAnalyticalModel")
 
  181       << 
"Error: VUV Absorption Length is 0 or negative.\n";
 
  183   return vuv_absorption_length;
 
  192   DetectedVisibilities.resize(
nOpDets);
 
  195       DetectedVisibilities[OpDet] = 0.;
 
  204     DetectedVisibilities[OpDet] = 
VUVVisibility(ScintPoint, op);;
 
  213   const double distance = relative.R();
 
  216   else cosine = 
std::abs(relative.X()) / distance;
 
  219   double solid_angle = 0.;
 
  221   if (opDet.
type == 0) {
 
  227   else if (opDet.
type == 1) {
 
  231   else if (opDet.
type == 2) {
 
  232     const double zy_offset = std::sqrt(relative.Y() * relative.Y() + relative.Z() * relative.Z());
 
  233     const double x_distance = 
std::abs(relative.X());
 
  237     throw cet::exception(
"SemiAnalyticalModel")
 
  238       << 
"Error: Invalid optical detector shape requested - configuration error in semi-analytical model, only rectangular, dome or disk optical detectors are supported." << 
"\n";
 
  253   double pars_ini[4] = {0, 0, 0, 0};
 
  254   double s1 = 0; 
double s2 = 0; 
double s3 = 0;
 
  277       throw cet::exception(
"SemiAnalyticalModel")
 
  278         << 
"Error: flat optical detectors are found, but parameters are missing - configuration error in semi-analytical model." << 
"\n";
 
  292     throw cet::exception(
"SemiAnalyticalModel")
 
  293       << 
"Error: Invalid optical detector shape requested or corrections are missing - configuration error in semi-analytical model." << 
"\n";
 
  297   pars_ini[0] = pars_ini[0] + s1 * 
r;
 
  298   pars_ini[1] = pars_ini[1] + s2 * 
r;
 
  299   pars_ini[2] = pars_ini[2] + s3 * 
r;
 
  300   pars_ini[3] = pars_ini[3];
 
  312   return GH_correction * visibility_geo / cosine;
 
  320                                                    bool AnodeMode)
 const 
  328   Dims plane_dimensions;
 
  347   double distance_cathode = 
std::abs(plane_depth - ScintPoint.X());
 
  354   double pars_ini[4] = {0, 0, 0, 0};
 
  355   double s1 = 0; 
double s2 = 0; 
double s3 = 0;
 
  366     throw cet::exception(
"SemiAnalyticalModel")
 
  367       << 
"Error: flat optical detector VUV correction required for reflected semi-analytic hits. - configuration error in semi-analytical model." << 
"\n";
 
  371   pars_ini[0] = pars_ini[0] + s1 * 
r;
 
  372   pars_ini[1] = pars_ini[1] + s2 * 
r;
 
  373   pars_ini[2] = pars_ini[2] + s3 * 
r;
 
  374   pars_ini[3] = pars_ini[3];
 
  377   double GH_correction = 
Gaisser_Hillas(distance_cathode, pars_ini);
 
  378   const double cathode_visibility_rec = GH_correction * cathode_visibility_geo;
 
  381   const geo::Point_t hotspot = {plane_depth, ScintPoint.Y(), ScintPoint.Z()};
 
  382   ReflDetectedVisibilities.resize(
nOpDets);
 
  385       ReflDetectedVisibilities[OpDet] = 0.;
 
  394     ReflDetectedVisibilities[OpDet] = 
VISVisibility(ScintPoint, op, cathode_visibility_rec, hotspot, AnodeMode);
 
  400                                    const double cathode_visibility, 
geo::Point_t const& hotspot,
 
  401                                    bool AnodeMode)
 const 
  415   const double distance_vis = emission_relative.R();
 
  419     cosine_vis = 
std::abs(emission_relative.Y()) / distance_vis;
 
  422     cosine_vis = 
std::abs(emission_relative.X()) / distance_vis;
 
  427   double solid_angle_detector = 0.;
 
  429   if (opDet.
type == 0) {
 
  437   else if (opDet.
type == 1) {
 
  441   else if (opDet.
type == 2) {
 
  442     const double zy_offset = std::sqrt(emission_relative.Y() * emission_relative.Y() +
 
  443                                        emission_relative.Z() * emission_relative.Z());
 
  444     const double x_distance = 
std::abs(emission_relative.X());
 
  448     throw cet::exception(
"SemiAnalyticalModel")
 
  449       << 
"Error: Invalid optical detector shape requested - configuration error in semi-analytical model, only rectangular, dome or disk optical detectors are supported." << 
"\n";
 
  453   double visibility_geo = (solid_angle_detector / (2. * 
CLHEP::pi)) *
 
  459   double d_c = 
std::abs(ScintPoint.X() - plane_depth);       
 
  460   double border_correction = 0;
 
  468       throw cet::exception(
"SemiAnalyticalModel")
 
  469         << 
"Error: Invalid optical detector shape requested or corrections are missing - configuration error in semi-analytical model." << 
"\n";
 
  475     throw cet::exception(
"SemiAnalyticalModel")
 
  476       << 
"Error: Invalid optical detector shape requested or corrections are missing - configuration error in semi-analytical model." << 
"\n";
 
  488   return border_correction * visibility_geo / cosine_vis;
 
  496   double X_mu_0 = par[3];
 
  497   double Normalization = par[0];
 
  498   double Diff = par[1] - X_mu_0;
 
  499   double Term = std::pow((x - X_mu_0) / Diff, Diff / par[2]);
 
  500   double Exponential = 
std::exp((par[1] - x) / par[2]);
 
  502   return (Normalization * Term * Exponential);
 
  510   if (b <= 0. || d < 0. || h <= 0.) 
return 0.;
 
  511   const double leg2 = (b + d) * (b + d);
 
  512   const double aa = std::sqrt(h * h / (h * h + leg2));
 
  513   if (isApproximatelyZero(d)) { 
return 2. * 
CLHEP::pi * (1. - aa); }
 
  514   double bb = 2. * std::sqrt(b * d / (h * h + leg2));
 
  515   double cc = 4. * b * d / leg2;
 
  517   if (isDefinitelyGreaterThan(d, b)) {
 
  523     catch (std::domain_error& 
e) {
 
  524       if (isApproximatelyEqual(d, b, 1e-9)) {
 
  525         mf::LogWarning(
"SemiAnalyticalModel")
 
  526           << 
"Elliptic Integral in Disk_SolidAngle() given parameters " 
  528           << 
"\nbb: " << bb << 
"\ncc: " << cc << 
"\nException message: " << e.what()
 
  529           << 
"\nRelax condition and carry on.";
 
  533         mf::LogError(
"SemiAnalyticalModel")
 
  534           << 
"Elliptic Integral inside Disk_SolidAngle() given parameters " 
  536           << 
"\nbb: " << bb << 
"\ncc: " << cc << 
"Exception message: " << e.what();
 
  541   if (isDefinitelyLessThan(d, b)) {
 
  548     catch (std::domain_error& 
e) {
 
  549       if (isApproximatelyEqual(d, b, 1e-9)) {
 
  550         mf::LogWarning(
"SemiAnalyticalModel")
 
  551           << 
"Elliptic Integral in Disk_SolidAngle() given parameters " 
  553           << 
"\nbb: " << bb << 
"\ncc: " << cc << 
"\nException message: " << e.what()
 
  554           << 
"\nRelax condition and carry on.";
 
  558         mf::LogError(
"SemiAnalyticalModel")
 
  559           << 
"Elliptic Integral inside Disk_SolidAngle() given parameters " 
  561           << 
"\nbb: " << bb << 
"\ncc: " << cc << 
"Exception message: " << e.what();
 
  566   if (isApproximatelyEqual(d, b)) {
 
  577   double aa = a / (2. * d);
 
  578   double bb = b / (2. * d);
 
  579   double aux = (1. + aa * aa + bb * bb) / ((1. + aa * aa) * (1. + bb * bb));
 
  592   if (OpDetOrientation == 1) {
 
  603   if (isApproximatelyZero(d1) && isApproximatelyZero(v.Z())) {
 
  606   if (isDefinitelyGreaterThan(d1, o.
h * .5) && isDefinitelyGreaterThan(
std::abs(v.Z()), o.
w * .5)) {
 
  607     double A = d1 - o.
h * .5;
 
  616   if ((d1 <= o.
h * .5) && (
std::abs(v.Z()) <= o.
w * .5)) {
 
  617     double A = -d1 + o.
h * .5;
 
  626   if (isDefinitelyGreaterThan(d1, o.
h * .5) && (
std::abs(v.Z()) <= o.
w * .5)) {
 
  627     double A = d1 - o.
h * .5;
 
  636   if ((d1 <= o.
h * .5) && isDefinitelyGreaterThan(
std::abs(v.Z()), o.
w * .5)) {
 
  637     double A = -d1 + o.
h * .5;
 
  664   double par0[9] = {0., 0., 0., 0., 0., 0.597542, 1.00872, 1.46993, 2.04221};
 
  665   double par1[9] = {0, 0, 0.19569, 0.300449, 0.555598, 0.854939, 1.39166, 2.19141, 2.57732};
 
  666   const double delta_theta = 10.; 
 
  667   int j = int(theta/delta_theta);
 
  671   const double d_break = 5*b; 
 
  673   if(distance >= d_break) {
 
  674     double R_apparent_far = b - par1[j];
 
  675     double ratio_square = (R_apparent_far*R_apparent_far)/(distance*distance);
 
  676     return  (2*
CLHEP::pi * (1 - std::sqrt(1 - ratio_square)));
 
  679     double R_apparent_close = b - par0[j];
 
  680     double ratio_square = (R_apparent_close*R_apparent_close)/(distance*distance);
 
  681     return (2*
CLHEP::pi * (1 - std::sqrt(1 - ratio_square)));
 
  694   if (((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
 
  705   double negate = double(x < 0);
 
  707   x -= double(x > 1.0) * (x - 1.0); 
 
  708   double ret = -0.0187293;
 
  710   ret = ret + 0.0742610;
 
  712   ret = ret - 0.2121144;
 
  714   ret = ret + 1.5707288;
 
  715   ret = ret * std::sqrt(1.0 - x);
 
  716   ret = ret - 2. * negate * ret;
 
  717   return negate * 3.14159265358979 + ret;
 
  727                                  const std::vector<double>& yData,
 
  733     size_t size = xData.size();
 
  734     if (x >= xData[size - 2]) { 
 
  738       while (x > xData[i + 1])
 
  742   double xL = xData[i];
 
  743   double xR = xData[i + 1];
 
  744   double yL = yData[i];
 
  745   double yR = yData[i + 1]; 
 
  747     if (x < xL) 
return yL;
 
  748     if (x > xR) 
return yL;
 
  750   const double dydx = (yR - yL) / (xR - xL); 
 
  751   return yL + dydx * (x - xL);               
 
  756                                   const std::vector<double>& rDistances,
 
  760                                   const size_t k)
 const 
  763   const size_t nbins_r = parameters[
k].size();
 
  764   std::vector<double> interp_vals(nbins_r, 0.0);
 
  767     size_t size = xDistances.size();
 
  768     if (x >= xDistances[size - 2])
 
  771       while (x > xDistances[idx + 1])
 
  774     for (
size_t i = 0; i < nbins_r; ++i) {
 
  783   double border_correction = 
interpolate(rDistances, interp_vals, r, 
false);
 
  784   return border_correction;
 
std::vector< double > fvis_distances_r_dome
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space. 
std::vector< double > fvis_distances_r_flat_lateral
double Gaisser_Hillas(const double x, const double *par) const 
void detectedDirectVisibilities(std::vector< double > &DetectedVisibilities, geo::Point_t const &ScintPoint) const 
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const 
Returns the geo::OpDetGeo object for the given detector number. 
Utilities related to art service access. 
std::vector< std::vector< double > > fborder_corr_dome
Encapsulate the construction of a single cyostat. 
process_name opflash particleana ie x
double interpolate2(const std::vector< double > &xDistances, const std::vector< double > &rDistances, const std::vector< std::vector< std::vector< double >>> ¶meters, const double x, const double r, const size_t k) const 
std::vector< std::vector< std::vector< double > > > fvispars_flat_lateral
double VUVVisibility(geo::Point_t const &ScintPoint, OpticalDetector const &opDet) const 
double Omega_Dome_Model(const double distance, const double theta) const 
const TVector3 fcathode_centre
bool isBar() const 
Returns whether the detector shape is a bar (TGeoBBox). 
std::vector< std::vector< double > > fGHvuvpars_flat
std::vector< std::vector< double > > fGHvuvpars_dome
geo::GeometryCore const & fGeom
std::vector< double > fvis_distances_r_flat
std::vector< double > fOpDetHeight
std::size_t size(FixedBins< T, C > const &) noexcept
void GetCenter(double *xyz, double localz=0.0) const 
const TVector3 fanode_centre
std::vector< std::vector< double > > fborder_corr_flat_lateral
const fhicl::ParameterSet fVUVHitsParams
std::vector< std::vector< std::vector< double > > > fvispars_flat
double fast_acos(double x) const 
bool fApplyFieldCageTransparency
double fFieldCageTransparencyCathode
void detectedReflectedVisibilities(std::vector< double > &ReflDetectedVisibilities, geo::Point_t const &ScintPoint, bool AnodeMode=false) const 
bool isSphere() const 
Returns whether the detector shape is a hemisphere (TGeoSphere). 
const bool fDoReflectedLight
auto vector(Vector const &v)
Returns a manipulator which will print the specified array. 
Access the description of detector geometry. 
double Rectangle_SolidAngle(const double a, const double b, const double d) const 
const fhicl::ParameterSet fVISHitsParams
BEGIN_PROLOG AbsLengthSpectrum
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop. 
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode. 
std::vector< double > fvis_distances_x_flat
boost::math::policies::policy< boost::math::policies::promote_double< false > > noLDoublePromote
double interpolate(const std::vector< double > &xData, const std::vector< double > &yData, double x, bool extrapolate, size_t i=0) const 
Test of util::counter and support utilities. 
std::vector< double > fvis_distances_x_flat_lateral
std::vector< geo::Point_t > fOpDetCenter
std::vector< double > fOpDetLength
const int fvuv_absorption_length
std::vector< double > fborder_corr_angulo_flat_lateral
std::vector< std::vector< double > > fborder_corr_flat
std::vector< std::vector< double > > fGHvuvpars_flat_lateral
double fAnodeReflectivity
Encapsulate the geometry of an optical detector. 
int VUVAbsorptionLength() const 
std::vector< int > fOpDetType
std::vector< double > fborder_corr_angulo_dome
bool isOpDetInSameTPC(geo::Point_t const &ScintPoint, geo::Point_t const &OpDetPoint) const 
std::vector< double > fvis_distances_x_dome
const std::vector< geo::BoxBoundedGeo > fActiveVolumes
double Disk_SolidAngle(const double d, const double h, const double b) const 
double fanode_plane_depth
SemiAnalyticalModel(fhicl::ParameterSet VUVHits, fhicl::ParameterSet VISHits, bool doReflectedLight=false, bool includeAnodeReflections=false)
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. 
std::vector< double > fborder_corr_angulo_flat
std::vector< int > fOpDetOrientation
art framework interface to geometry description 
double fFieldCageTransparencyLateral
std::vector< std::vector< std::vector< double > > > fvispars_dome
double VISVisibility(geo::Point_t const &ScintPoint, OpticalDetector const &opDet, const double cathode_visibility, geo::Point_t const &hotspot, bool AnodeMode=false) const 
const bool fIncludeAnodeReflections