////////////////////////////////////////////////////////////////////
/// \class RAT::DU::EffectiveVelocity
///
/// \brief Return the total transit time given the effective group velocities
///
/// \author Phil G Jones
/// \author Rob Stainforth -- contact person
///
/// REVISION HISTORY:
/// - 21 July 2011 : New File.
/// - 2014-03-01 : P G Jones - refactor as part of ds review, moved from ds.
/// - 2014-07-14 J.R.Wilson - change name of scint volume to inner_av
/// - 2014-04-02 : M Mottram - updated to work with partial fill.
/// - 2023-27-12 : W Parker - allow different velocities at different event radii
///
///
/// \details This class loads effective velocity information from
/// the database and will calculate the transit time taken given
/// the loaded velocities.
/// It can be used in RAT, ROOT or external programs that link to
/// the libRATEvent library.
///
////////////////////////////////////////////////////////////////////
#ifndef __RAT_DU_EffectiveVelocity__
#define __RAT_DU_EffectiveVelocity__
#include
namespace RAT
{
namespace DU
{
class EffectiveVelocity : public TObject
{
public:
/// Called at the start of a run, loads from the database
void BeginOfRun();
/// Calculate the transit time by distance in the standard 3 SNO+ volumes
///
/// @param[in] distInInnerAV the distance in the scintillator (inner AV) volume
/// @param[in] distInAV the distance in the AV
/// @param[in] distInWater the distance in the water (cavity)
/// @param[in] nhits the nhits of the event
/// @param[in] eventRadius the radius of the event
/// @return the transit time
inline double CalcByDistance( const double distInInnerAV, const double distInAV, const double distInWater ) const;
inline double CalcByDistance( const double distInInnerAV, const double distInAV, const double distInWater, const int nhits ) const;
inline double CalcByDistance( const double distInInnerAV, const double distInAV, const double distInWater, const double eventRadius ) const;
inline double CalcByDistance( const double distInInnerAV, const double distInAV, const double distInWater, const int nhits, const double eventRadius ) const;
/// Get the inner_av volume effective velocity
///
/// @return the inner_av volume effective velocity
double GetInnerAVVelocity() const { return fInnerAVVelocity.at(0); }
/// Get the inner_av volume effective velocity for a given radius
///
/// @return the inner_av volume effective velocity
double GetInnerAVVelocity( const double eventRadius );
/// Get the av volume effective velocity
///
/// @return the av volume effective velocity
double GetAVVelocity() const { return fAVVelocity; }
/// Get the water volume effective velocity
///
/// @return the water volume effective velocity
double GetWaterVelocity() const { return fWaterVelocity; }
/// Get the offset time, represents transit time in PMTs
///
/// @return the offset time
double GetOffset() const { return fOffset; }
// This ROOT macro adds dictionary methods to this class.
// The number is 0 as this class is never, and should never be written to disc.
// It assumes this class has no virtual methods, use ClassDef if change this.
ClassDefNV( EffectiveVelocity, 0 );
private:
std::vector fInnerAVVelocity; ///< Effective target (inner_av) effective velocity
std::vector fInnerAVGradient; ///< Gradient for nhit scaling of inner_av effective velocity
std::vector fInnerAVOffset; ///< Offset for nhit scaling of inner_av effective velocity
double fAVVelocity; ///< Effective av effective velocity
double fWaterVelocity; ///< Effective water effective velocity
double fOffset; ///< Offset required from fit, time taken on average in PMT.
double fScaleInnerAVVel = false; ///< Gets set to true if want to scale effective velocity with nhits
unsigned int fNumberOfShells = 0; ///< Number of shells with different effective velocities
std::vector < std::pair > fRadialRanges; // Range of radii each velocity applies to
};
double
EffectiveVelocity::CalcByDistance( const double distInInnerAV,
const double distInAV,
const double distInWater ) const
{
return distInInnerAV / fInnerAVVelocity.at(0) + distInAV / fAVVelocity + distInWater / fWaterVelocity + fOffset;
}
double
EffectiveVelocity::CalcByDistance( const double distInInnerAV,
const double distInAV,
const double distInWater,
const int nhits ) const
{
if( nhits < 0){
warn << "EffectiveVelocity::CalcByDistance: Nhits is negative. Using non-nhit-scaled effective velocity for scintillator\n";
return CalcByDistance(distInInnerAV, distInAV, distInWater);
}
if( !fScaleInnerAVVel || fInnerAVGradient.size() == 0 || fInnerAVOffset.size() == 0 )
return CalcByDistance(distInInnerAV, distInAV, distInWater);
double innerAVVelocity = fInnerAVGradient.at(0) * nhits + fInnerAVOffset.at(0);
return distInInnerAV / innerAVVelocity + distInAV / fAVVelocity + distInWater / fWaterVelocity + fOffset;
}
double
EffectiveVelocity::CalcByDistance( const double distInInnerAV,
const double distInAV,
const double distInWater,
const double eventRadius ) const
{
if( !fScaleInnerAVVel || fNumberOfShells == 0 )
return CalcByDistance(distInInnerAV, distInAV, distInWater);
unsigned int shell_number = 0;
for(unsigned int i_shell = 0; i_shell < fNumberOfShells; i_shell++){
if( eventRadius >= fRadialRanges.at(i_shell).first &&
eventRadius < fRadialRanges.at(i_shell).second ) {
shell_number = i_shell;
break;
}
}
return distInInnerAV / fInnerAVVelocity.at(shell_number) + distInAV / fAVVelocity + distInWater / fWaterVelocity + fOffset;
}
double
EffectiveVelocity::CalcByDistance( const double distInInnerAV,
const double distInAV,
const double distInWater,
const int nhits,
const double eventRadius ) const
{
if( nhits < 0){
warn << "EffectiveVelocity::CalcByDistance: Nhits is negative. Using non-nhit-scaled effective velocity for scintillator\n";
return CalcByDistance(distInInnerAV, distInAV, distInWater);
}
if( !fScaleInnerAVVel )
return CalcByDistance(distInInnerAV, distInAV, distInWater, eventRadius);
if( fNumberOfShells == 0 )
return CalcByDistance(distInInnerAV, distInAV, distInWater, nhits);
unsigned int shell_number = 0;
for(unsigned int i_shell = 0; i_shell < fNumberOfShells; i_shell++){
if( eventRadius >= fRadialRanges.at(i_shell).first &&
eventRadius < fRadialRanges.at(i_shell).second ) {
shell_number = i_shell;
break;
}
}
double innerAVVelocity = fInnerAVGradient.at(shell_number) * nhits + fInnerAVOffset.at(shell_number);
return distInInnerAV / innerAVVelocity + distInAV / fAVVelocity + distInWater / fWaterVelocity + fOffset;
}
} // namespace DU
} // namespace RAT
#endif