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