14 #include "cetlib_except/exception.h" 22 #include "boost/math/special_functions/ellint_1.hpp" 23 #include "boost/math/special_functions/ellint_3.hpp" 30 const bool doReflectedLight,
31 const bool includeAnodeReflections,
32 const bool useXeAbsorption)
33 : fGeom{*(lar::providerFrom<geo::Geometry>())}
49 mf::LogInfo(
"SemiAnalyticalModel") <<
"Initializing Semi-analytical model." << std::endl;
52 mf::LogInfo(
"SemiAnalyticalModel") <<
"Using VUV visibility parameterization";
58 fradius = VUVHitsParams.get<
double>(
"PMT_radius", 10.16);
65 <<
"Both isFlatPDCorr/isFlatPDCorrLat and isDomePDCorr parameters are " 66 "false, at least one type of parameterisation is required for the " 67 "semi-analytic light simulation." 71 fGHvuvpars_flat = VUVHitsParams.get<std::vector<std::vector<double>>>(
"GH_PARS_flat");
73 fborder_corr_flat = VUVHitsParams.get<std::vector<std::vector<double>>>(
"GH_border_flat");
75 if (fIsFlatPDCorrLat) {
77 VUVHitsParams.get<std::vector<std::vector<double>>>(
"GH_PARS_flat_lateral");
79 VUVHitsParams.get<std::vector<double>>(
"GH_border_angulo_flat_lateral");
81 VUVHitsParams.get<std::vector<std::vector<double>>>(
"GH_border_flat_lateral");
84 fGHvuvpars_dome = VUVHitsParams.get<std::vector<std::vector<double>>>(
"GH_PARS_dome");
86 fborder_corr_dome = VUVHitsParams.get<std::vector<std::vector<double>>>(
"GH_border_dome");
91 mf::LogInfo(
"SemiAnalyticalModel") <<
"Using VIS (reflected) visibility parameterization";
98 VISHitsParams.get<std::vector<std::vector<std::vector<double>>>>(
"VIS_correction_flat");
104 VISHitsParams.get<std::vector<std::vector<std::vector<double>>>>(
"VIS_correction_dome");
115 mf::LogInfo(
"SemiAnalyticalModel") <<
"Using anode reflections parameterization";
123 VISHitsParams.get<std::vector<std::vector<std::vector<double>>>>(
"VIS_correction_flat");
126 if (fIsFlatPDCorrLat) {
128 VISHitsParams.get<std::vector<double>>(
"VIS_distances_x_flat_lateral");
130 VISHitsParams.get<std::vector<double>>(
"VIS_distances_r_flat_lateral");
132 "VIS_correction_flat_lateral");
146 mf::LogInfo(
"SemiAnalyticalModel") <<
"Semi-analytical model initialized." << std::endl;
152 std::map<double, double> abs_length_spectrum =
153 lar::providerFrom<detinfo::LArPropertiesService>()->AbsLengthSpectrum();
154 std::vector<double> x_v, y_v;
155 for (
auto elem : abs_length_spectrum) {
156 x_v.push_back(elem.first);
157 y_v.push_back(elem.second);
159 double vuv_absorption_length;
161 vuv_absorption_length =
164 vuv_absorption_length =
166 if (vuv_absorption_length <= 0) {
168 <<
"Error: VUV Absorption Length is 0 or negative.\n";
170 return vuv_absorption_length;
178 DetectedVisibilities.resize(
fNOpDets);
181 DetectedVisibilities[OpDet] = 0.;
195 const double distance = relative.R();
198 cosine =
std::abs(relative.Z()) / distance;
200 cosine =
std::abs(relative.Y()) / distance;
202 cosine =
std::abs(relative.X()) / distance;
205 double solid_angle = 0.;
207 if (opDet.
type == 0) {
214 else if (opDet.
type == 1) {
218 else if (opDet.
type == 2) {
219 const double zy_offset = std::sqrt(relative.Y() * relative.Y() + relative.Z() * relative.Z());
220 const double x_distance =
std::abs(relative.X());
225 <<
"Error: Invalid optical detector shape requested - configuration " 226 "error in semi-analytical model, only rectangular, dome or disk " 227 "optical detectors are supported." 233 double visibility_geo =
250 double pars_ini[4] = {0, 0, 0, 0};
280 <<
"Error: flat optical detectors are found, but parameters are " 281 "missing - configuration error in semi-analytical model." 297 <<
"Error: Invalid optical detector shape requested or corrections are " 298 "missing - configuration error in semi-analytical model." 303 pars_ini[0] = pars_ini[0] + s1 *
r;
304 pars_ini[1] = pars_ini[1] + s2 *
r;
305 pars_ini[2] = pars_ini[2] + s3 *
r;
306 pars_ini[3] = pars_ini[3];
312 return GH_correction * visibility_geo / cosine;
318 std::vector<double>& ReflDetectedVisibilities,
320 bool AnodeMode)
const 329 Dims plane_dimensions;
341 ScintPoint_relative.SetCoordinates(
std::abs(ScintPoint.X() - plane_depth),
354 double distance_cathode =
std::abs(plane_depth - ScintPoint.X());
357 (solid_angle_cathode / (4. *
CLHEP::pi));
362 double pars_ini[4] = {0, 0, 0, 0};
377 <<
"Error: flat optical detector VUV correction required for reflected " 378 "semi-analytic hits. - configuration error in semi-analytical model." 383 pars_ini[0] = pars_ini[0] + s1 *
r;
384 pars_ini[1] = pars_ini[1] + s2 *
r;
385 pars_ini[2] = pars_ini[2] + s3 *
r;
386 pars_ini[3] = pars_ini[3];
389 double GH_correction =
Gaisser_Hillas(distance_cathode, pars_ini);
390 const double cathode_visibility_rec = GH_correction * cathode_visibility_geo;
393 const geo::Point_t hotspot = {plane_depth, ScintPoint.Y(), ScintPoint.Z()};
394 ReflDetectedVisibilities.resize(
fNOpDets);
397 ReflDetectedVisibilities[OpDet] = 0.;
401 ReflDetectedVisibilities[OpDet] =
408 const double cathode_visibility,
410 bool AnodeMode)
const 426 const double distance_vis = emission_relative.R();
430 cosine_vis =
std::abs(emission_relative.Z()) / distance_vis;
433 cosine_vis =
std::abs(emission_relative.Y()) / distance_vis;
436 cosine_vis =
std::abs(emission_relative.X()) / distance_vis;
441 double solid_angle_detector = 0.;
443 if (opDet.
type == 0) {
448 solid_angle_detector =
452 else if (opDet.
type == 1) {
456 else if (opDet.
type == 2) {
457 const double zy_offset = std::sqrt(emission_relative.Y() * emission_relative.Y() +
458 emission_relative.Z() * emission_relative.Z());
459 const double x_distance =
std::abs(emission_relative.X());
464 <<
"Error: Invalid optical detector shape requested - configuration " 465 "error in semi-analytical model, only rectangular, dome or disk " 466 "optical detectors are supported." 471 double visibility_geo = (solid_angle_detector / (2. *
CLHEP::pi)) *
482 double d_c =
std::abs(ScintPoint.X() - plane_depth);
483 double border_correction = 0;
504 <<
"Error: Invalid optical detector shape requested or corrections " 505 "are missing - configuration error in semi-analytical model." 516 <<
"Error: Invalid optical detector shape requested or corrections are " 517 "missing - configuration error in semi-analytical model." 524 return border_correction * visibility_geo / cosine_vis;
531 double X_mu_0 = par[3];
532 double Normalization = par[0];
533 double Diff = par[1] - X_mu_0;
534 double Term = std::pow((x - X_mu_0) / Diff, Diff / par[2]);
535 double Exponential = std::exp((par[1] - x) / par[2]);
537 return (Normalization * Term * Exponential);
544 if (b <= 0. || d < 0. || h <= 0.)
return 0.;
545 const double leg2 = (b +
d) * (b + d);
546 const double aa = std::sqrt(h * h / (h * h + leg2));
548 double bb = 2. * std::sqrt(b * d / (h * h + leg2));
549 double cc = 4. * b * d / leg2;
557 catch (std::domain_error&
e) {
560 <<
"Elliptic Integral in Disk_SolidAngle() given parameters " 562 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
563 <<
"\nRelax condition and carry on.";
568 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters " 570 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
582 catch (std::domain_error&
e) {
585 <<
"Elliptic Integral in Disk_SolidAngle() given parameters " 587 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"\nException message: " << e.what()
588 <<
"\nRelax condition and carry on.";
593 <<
"Elliptic Integral inside Disk_SolidAngle() given parameters " 595 <<
"\nbb: " << bb <<
"\ncc: " << cc <<
"Exception message: " << e.what();
610 const double d)
const 612 double aa = a / (2. *
d);
613 double bb = b / (2. *
d);
614 double aux = (1. + aa * aa + bb * bb) / ((1. + aa * aa) * (1. + bb * bb));
620 int OpDetOrientation)
const 629 if (OpDetOrientation == 2) {
634 else if (OpDetOrientation == 1) {
650 double A = d1 - o.
h * .5;
659 if ((d1 <= o.
h * .5) && (
std::abs(v.Z()) <= o.
w * .5)) {
660 double A = -d1 + o.
h * .5;
670 double A = d1 - o.
h * .5;
680 double A = -d1 + o.
h * .5;
706 constexpr
double par0[9] = {0., 0., 0., 0., 0., 0.597542, 1.00872, 1.46993, 2.04221};
707 constexpr
double par1[9] = {
708 0., 0., 0.19569, 0.300449, 0.555598, 0.854939, 1.39166, 2.19141, 2.57732};
709 const double delta_theta = 10.;
710 int j = int(theta / delta_theta);
714 const double d_break = 5 * b;
716 if (distance >= d_break) {
717 double R_apparent_far = b - par1[j];
718 double ratio_square = (R_apparent_far * R_apparent_far) / (distance * distance);
719 return (2 *
CLHEP::pi * (1 - std::sqrt(1 - ratio_square)));
722 double R_apparent_close = b - par0[j];
723 double ratio_square = (R_apparent_close * R_apparent_close) / (distance * distance);
724 return (2 *
CLHEP::pi * (1 - std::sqrt(1 - ratio_square)));
737 if (((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
std::abs(OpDetPoint.X()) > 10. &&
746 std::vector<SemiAnalyticalModel::OpticalDetector> opticalDetector;
760 else if (opDet.
isBar()) {
767 length = opDet.
Width();
771 height = opDet.
Width();
783 opticalDetector.emplace_back(
786 return opticalDetector;
std::vector< double > fvis_distances_x_dome
std::vector< std::vector< double > > fborder_corr_flat_lateral
Point_t GetCathodeCenter() const
unsigned int NTPC(CryostatID const &cryoid=cryostat_zero) const
Returns the total number of TPCs in the specified cryostat.
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
static std::vector< geo::BoxBoundedGeo > extractActiveLArVolume(geo::GeometryCore const &geom)
Utilities related to art service access.
double VISVisibility(geo::Point_t const &ScintPoint, OpticalDetector const &opDet, const double cathode_visibility, geo::Point_t const &hotspot, bool AnodeMode=false) const
Encapsulate the construction of a single cyostat.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
bool isOpDetInSameTPC(geo::Point_t const &ScintPoint, geo::Point_t const &OpDetPoint) const
Point_t const & GetCenter() const
Returns the centre of the wire plane in world coordinates [cm].
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
bool isBar() const
Returns whether the detector shape is a bar (TGeoBBox).
double VUVVisibility(geo::Point_t const &ScintPoint, OpticalDetector const &opDet) const
double fFieldCageTransparencyCathode
const bool fIncludeAnodeReflections
geo::PlaneGeo const & FirstPlane() const
Returns the first wire plane (the closest to TPC center).
double Rectangle_SolidAngle(const double a, const double b, const double d) const
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::vector< std::vector< std::vector< double > > > fvispars_dome
static constexpr bool isDefinitelyGreaterThan(TReal a, TReal b, TReal tolerance=std::numeric_limits< TReal >::epsilon())
const larg4::ISTPC fISTPC
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
std::vector< std::vector< double > > fGHvuvpars_flat_lateral
std::vector< double > fvis_distances_r_flat
const TVector3 fcathode_centre
const std::vector< geo::BoxBoundedGeo > fActiveVolumes
std::vector< std::vector< double > > fborder_corr_dome
double VUVAbsorptionLength() const
TPCGeo const & TPC(TPCID const &tpcid=tpc_zero) const
Returns the specified TPC.
bool isSphere() const
Returns whether the detector shape is a hemisphere (TGeoSphere).
Access the description of detector geometry.
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
geo::GeometryCore const & fGeom
SemiAnalyticalModel(const fhicl::ParameterSet &VUVHits, const fhicl::ParameterSet &VISHits, const bool doReflectedLight=false, const bool includeAnodeReflections=false, const bool useXeAbsorption=false)
double fFieldCageTransparencyLateral
boost::math::policies::policy< boost::math::policies::promote_double< false > > noLDoublePromote
const bool fUseXeAbsorption
double fast_acos(double xin)
std::vector< double > fborder_corr_angulo_flat
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)
std::vector< double > fvis_distances_r_dome
bool fApplyFieldCageTransparency
std::vector< double > fborder_corr_angulo_dome
std::vector< std::vector< std::vector< double > > > fvispars_flat_lateral
Test of util::counter and support utilities.
double Gaisser_Hillas(const double x, const double *par) const
std::vector< double > fvis_distances_x_flat_lateral
unsigned int NOpDets() const
Number of OpDets in the whole detector.
Encapsulate the geometry of an optical detector.
geo::Point_t const & GetCenter() const
const bool fDoReflectedLight
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
General LArSoft Utilities.
std::vector< std::vector< double > > fGHvuvpars_flat
void detectedDirectVisibilities(std::vector< double > &DetectedVisibilities, geo::Point_t const &ScintPoint) const
double fanode_plane_depth
double Omega_Dome_Model(const double distance, const double theta) const
std::vector< std::vector< double > > fGHvuvpars_dome
double Disk_SolidAngle(const double d, const double h, const double b) const
static constexpr bool isApproximatelyEqual(TReal a, TReal b, TReal tolerance=std::numeric_limits< TReal >::epsilon())
std::vector< double > fvis_distances_x_flat
double fvuv_absorption_length
void detectedReflectedVisibilities(std::vector< double > &ReflDetectedVisibilities, geo::Point_t const &ScintPoint, bool AnodeMode=false) const
static constexpr bool isDefinitelyLessThan(TReal a, TReal b, TReal tolerance=std::numeric_limits< TReal >::epsilon())
std::vector< std::vector< std::vector< double > > > fvispars_flat
std::vector< double > fvis_distances_r_flat_lateral
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
constexpr T pi()
Returns the constant pi (up to 35 decimal digits of precision)
std::vector< OpticalDetector > opticalDetectors() const
const TVector3 fanode_centre
const std::vector< OpticalDetector > fOpDetector
double fAnodeReflectivity
std::vector< std::vector< double > > fborder_corr_flat
double interpolate(const std::vector< double > &xData, const std::vector< double > &yData, const double x, const bool extrapolate, size_t i)
static constexpr bool isApproximatelyZero(TReal a, TReal tolerance=std::numeric_limits< TReal >::epsilon())
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
std::vector< double > fborder_corr_angulo_flat_lateral