コード例 #1
0
/**Calculates the distance a neutron coming from the sample will have deviated
* from a
*  straight tragetory before hitting a detector. If calling this function many
* times
*  for the same detector you can call this function once, with waveLength=1, and
* use
*  the fact drop is proportional to wave length squared .This function has no
* knowledge
*  of which axis is vertical for a given instrument
*  @param ws :: workspace
*  @param det :: the detector that the neutron entered
*  @param waveLength :: the neutrons wave length in meters
*  @param extraLength :: additional length
*  @return the deviation in meters
*/
double GravitySANSHelper::gravitationalDrop(API::MatrixWorkspace_const_sptr ws,
                                            Geometry::IDetector_const_sptr det,
                                            const double waveLength,
                                            const double extraLength) const {
  using namespace PhysicalConstants;
  /// Pre-factor in gravity calculation: gm^2/2h^2
  static const double gm2_OVER_2h2 =
      g * NeutronMass * NeutronMass / (2.0 * h * h);

  const V3D samplePos = ws->getInstrument()->getSample()->getPos();
  const double pathLength = det->getPos().distance(samplePos) + extraLength;
  // Want L2 (sample-pixel distance) squared, times the prefactor g^2/h^2
  const double L2 = gm2_OVER_2h2 * std::pow(pathLength, 2);

  return waveLength * waveLength * L2;
}
コード例 #2
0
    /**
     * Set the new detector position given the r,theta and phi.
     * @param det :: A pointer to the detector
     * @param l2 :: A single l2
     * @param theta :: A single theta
     * @param phi :: A single phi
     */
    void UpdateInstrumentFromFile::setDetectorPosition(const Geometry::IDetector_const_sptr & det, const float l2,
                                                       const float theta, const float phi)
    {
      if( m_ignoreMonitors && det->isMonitor() ) return;

      Geometry::ParameterMap & pmap = m_workspace->instrumentParameters();
      Kernel::V3D pos;
      if (!m_ignorePhi)
      {
        pos.spherical(l2, theta, phi);
      }
      else
      {
        double r,t,p;
        det->getPos().getSpherical(r,t,p);
        pos.spherical(l2, theta, p);
      }
      Geometry::ComponentHelper::moveComponent(*det, pmap, pos, Geometry::ComponentHelper::Absolute);
    }
コード例 #3
0
ファイル: LoadILLSANS.cpp プロジェクト: liyulun/mantid
std::pair<double, double> LoadILLSANS::calculateQMaxQMin() {
  double min = std::numeric_limits<double>::max(),
         max = std::numeric_limits<double>::min();
  g_log.debug("Calculating Qmin Qmax...");
  std::size_t nHist = m_localWorkspace->getNumberHistograms();
  for (std::size_t i = 0; i < nHist; ++i) {
    Geometry::IDetector_const_sptr det = m_localWorkspace->getDetector(i);
    if (!det->isMonitor()) {
      const MantidVec &lambdaBinning = m_localWorkspace->readX(i);
      Kernel::V3D detPos = det->getPos();
      double r, theta, phi;
      detPos.getSpherical(r, theta, phi);
      double v1 = calculateQ(*(lambdaBinning.begin()), theta);
      double v2 = calculateQ(*(lambdaBinning.end() - 1), theta);
      // std::cout << "i=" << i << " theta="<<theta << " lambda_i=" <<
      // *(lambdaBinning.begin()) << " lambda_f=" << *(lambdaBinning.end()-1) <<
      // " v1=" << v1 << " v2=" << v2 << '\n';
      if (i == 0) {
        min = v1;
        max = v1;
      }
      if (v1 < min) {
        min = v1;
      }
      if (v2 < min) {
        min = v2;
      }
      if (v1 > max) {
        max = v1;
      }
      if (v2 > max) {
        max = v2;
      }
    } else
      g_log.debug() << "Detector " << i << " is a Monitor : " << det->getID()
                    << '\n';
  }

  g_log.debug() << "Calculating Qmin Qmax. Done : [" << min << "," << max
                << "]\n";

  return std::pair<double, double>(min, max);
}
コード例 #4
0
/**
 * This function calculates the exponential contribution to the He3 tube
 * efficiency.
 * @param spectraIndex :: the current index to calculate
 * @param idet :: the current detector pointer
 * @throw out_of_range if twice tube thickness is greater than tube diameter
 * @return the exponential contribution for the given detector
 */
double He3TubeEfficiency::calculateExponential(std::size_t spectraIndex, Geometry::IDetector_const_sptr idet)
{
  // Get the parameters for the current associated tube
  double pressure = this->getParameter("TubePressure", spectraIndex,
      "tube_pressure", idet);
  double tubethickness = this->getParameter("TubeThickness", spectraIndex,
      "tube_thickness", idet);
  double temperature = this->getParameter("TubeTemperature", spectraIndex,
      "tube_temperature", idet);

  double detRadius(0.0);
  Kernel::V3D detAxis;
  this->getDetectorGeometry(idet, detRadius, detAxis);
  double detDiameter = 2.0 * detRadius;
  double twiceTubeThickness = 2.0 * tubethickness;

  // now get the sin of the angle, it's the magnitude of the cross product of
  // unit vector along the detector tube axis and a unit vector directed from
  // the sample to the detector center
  Kernel::V3D vectorFromSample = idet->getPos() - this->samplePos;
  vectorFromSample.normalize();
  Kernel::Quat rot = idet->getRotation();
  // rotate the original cylinder object axis to get the detector axis in the
  // actual instrument
  rot.rotate(detAxis);
  detAxis.normalize();
  // Scalar product is quicker than cross product
  double cosTheta = detAxis.scalar_prod(vectorFromSample);
  double sinTheta = std::sqrt(1.0 - cosTheta * cosTheta);

  const double straight_path = detDiameter - twiceTubeThickness;
  if (std::fabs(straight_path - 0.0) < TOL)
  {
    throw std::out_of_range("Twice tube thickness cannot be greater than "\
        "or equal to the tube diameter");
  }

  const double pathlength = straight_path / sinTheta;
  return EXP_SCALAR_CONST * (pressure / temperature) * pathlength;
}
コード例 #5
0
/**Calculates the distance a neutron coming from the sample will have deviated
* from a
*  straight tragetory before hitting a detector. If calling this function many
* times
*  for the same detector you can call this function once, with waveLength=1, and
* use
*  the fact drop is proportional to wave length squared .This function has no
* knowledge
*  of which axis is vertical for a given instrument
*  @param ws :: workspace
*  @param det :: the detector that the neutron entered
*  @param waveLength :: the neutrons wave length in meters
*  @param extraLength :: additional length
*  @return the deviation in meters
*/
double GravitySANSHelper::gravitationalDrop(API::MatrixWorkspace_const_sptr ws,
        Geometry::IDetector_const_sptr det,
        const double waveLength,
        const double extraLength) const {
    using namespace PhysicalConstants;
    /// Pre-factor in gravity calculation: gm^2/2h^2
    static const double gm2_OVER_2h2 =
        g * NeutronMass * NeutronMass / (2.0 * h * h);

    const V3D samplePos = ws->getInstrument()->getSample()->getPos();

    // Perform a path length correction if an Lextra is specified.
    // The correction is Lcorr^2 = (L + Lextra)^2 -(LExtra)^2
    const auto pathLengthWithExtraLength =
        det->getPos().distance(samplePos) + extraLength;
    const auto pathLengthSquared =
        std::pow(pathLengthWithExtraLength, 2) - std::pow(extraLength, 2);

    // Want L2 (sample-pixel distance) squared, times the prefactor g^2/h^2
    const double L2 = gm2_OVER_2h2 * pathLengthSquared;

    return waveLength * waveLength * L2;
}
コード例 #6
0
/** method to cacluate the detectors parameters and add them to the detectors
*averages
*@param spDet    -- shared pointer to the Mantid Detector
*@param Observer -- sample position or the centre of the polar system of
*coordinates to calculate detector's parameters.
*/
void AvrgDetector::addDetInfo(const Geometry::IDetector_const_sptr &spDet,
                              const Kernel::V3D &Observer) {
  m_nComponents++;
  Kernel::V3D detPos = spDet->getPos();
  Kernel::V3D toDet = (detPos - Observer);

  double dist2Det, Polar, Azimut, ringPolar, ringAzim;
  // identify the detector' position in the beam coordinate system:
  toDet.getSpherical(dist2Det, Polar, Azimut);
  if (m_nComponents <= 1) {
    m_FlightPathSum = dist2Det;
    m_PolarSum = Polar;
    m_AzimutSum = Azimut;

    m_AzimBase = Polar;
    m_PolarBase = Azimut;
    ringPolar = Polar;
    ringAzim = Azimut;
  } else {
    ringPolar = nearAngle(m_AzimBase, Polar);
    ringAzim = nearAngle(m_PolarBase, Azimut);
    m_FlightPathSum += dist2Det;
    m_PolarSum += ringPolar;
    m_AzimutSum += ringAzim;
  }

  // centre of the azimuthal ring (the ring  detectors form around the beam)
  Kernel::V3D ringCentre(0, 0, toDet.Z());

  // Get the bounding box
  Geometry::BoundingBox bbox;
  std::vector<Kernel::V3D> coord(3);

  Kernel::V3D er(0, 1, 0), e_th,
      ez(0, 0, 1); // ez along beamline, which is always oz;
  if (dist2Det)
    er = toDet / dist2Det; // direction to the detector
  Kernel::V3D e_tg =
      er.cross_prod(ez); // tangential to the ring and anticloakwise;
  e_tg.normalize();
  // make orthogonal -- projections are calculated in this coordinate system
  ez = e_tg.cross_prod(er);

  coord[0] = er;   // new X
  coord[1] = ez;   // new y
  coord[2] = e_tg; // new z
  bbox.setBoxAlignment(ringCentre, coord);

  spDet->getBoundingBox(bbox);

  // linear extensions of the bounding box orientied tangentially to the equal
  // scattering angle circle
  double azimMin = bbox.zMin();
  double azimMax = bbox.zMax();
  double polarMin = bbox.yMin(); // bounding box has been rotated according to
                                 // coord above, so z is along e_tg
  double polarMax = bbox.yMax();

  if (m_useSphericalSizes) {
    if (dist2Det == 0)
      dist2Det = 1;

    // convert to angular units
    double polarHalfSize =
        rad2deg * atan2(0.5 * (polarMax - polarMin), dist2Det);
    double azimHalfSize = rad2deg * atan2(0.5 * (azimMax - azimMin), dist2Det);

    polarMin = ringPolar - polarHalfSize;
    polarMax = ringPolar + polarHalfSize;
    azimMin = ringAzim - azimHalfSize;
    azimMax = ringAzim + azimHalfSize;
  }
  if (m_AzimMin > azimMin)
    m_AzimMin = azimMin;
  if (m_AzimMax < azimMax)
    m_AzimMax = azimMax;

  if (m_PolarMin > polarMin)
    m_PolarMin = polarMin;
  if (m_PolarMax < polarMax)
    m_PolarMax = polarMax;
}
コード例 #7
0
ファイル: LoadDspacemap.cpp プロジェクト: spaceyatom/mantid
/**
 * Make a map of the conversion factors between tof and D-spacing
 * for all pixel IDs in a workspace.
 * map vulcan should contain the module/module and stack/stack offset
 *
 * @param vulcan :: map between detector ID and vulcan correction factor.
 * @param offsetsWS :: OffsetsWorkspace to be filled.
 */
void LoadDspacemap::CalculateOffsetsFromVulcanFactors(
    std::map<detid_t, double> &vulcan,
    Mantid::DataObjects::OffsetsWorkspace_sptr offsetsWS) {
  // Get a pointer to the instrument contained in the workspace
  // At this point, instrument VULCAN has been created?
  Instrument_const_sptr instrument = offsetsWS->getInstrument();

  g_log.notice() << "Name of instrument = " << instrument->getName()
                 << std::endl;
  g_log.notice() << "Input map (dict):  size = " << vulcan.size() << std::endl;

  // To get all the detector ID's
  detid2det_map allDetectors;
  instrument->getDetectors(allDetectors);

  detid2det_map::const_iterator it;
  int numfinds = 0;
  g_log.notice() << "Input number of detectors = " << allDetectors.size()
                 << std::endl;

  // Get detector information
  double l1, beamline_norm;
  Kernel::V3D beamline, samplePos;
  instrument->getInstrumentParameters(l1, beamline, beamline_norm, samplePos);

  /*** A survey of parent detector
  std::map<detid_t, bool> parents;
  for (it = allDetectors.begin(); it != allDetectors.end(); it++){
    int32_t detid = it->first;

    // def boost::shared_ptr<const Mantid::Geometry::IDetector>
  IDetector_const_sptr;

    std::string parentname =
  it->second->getParent()->getComponentID()->getName();
    g_log.notice() << "Name = " << parentname << std::endl;
    // parents.insert(parentid, true);
  }
  ***/

  /*** Here some special configuration for VULCAN is hard-coded here!
   *   Including (1) Super-Parent Information
   ***/
  Kernel::V3D referencePos;
  detid_t anydetinrefmodule = 21 * 1250 + 5;

  std::map<detid_t, Geometry::IDetector_const_sptr>::iterator det_iter =
      allDetectors.find(anydetinrefmodule);

  if (det_iter == allDetectors.end()) {
    throw std::invalid_argument("Any Detector ID is Instrument's detector");
  }
  referencePos = det_iter->second->getParent()->getPos();
  double refl2 = referencePos.norm();
  double halfcosTwoThetaRef =
      referencePos.scalar_prod(beamline) / (refl2 * beamline_norm);
  double sinThetaRef = sqrt(0.5 - halfcosTwoThetaRef);
  double difcRef = sinThetaRef * (l1 + refl2) / CONSTANT;

  // Loop over all detectors in instrument to find the offset
  for (it = allDetectors.begin(); it != allDetectors.end(); ++it) {
    int detectorID = it->first;
    Geometry::IDetector_const_sptr det = it->second;
    double offset = 0.0;

    // Find the vulcan factor;
    double vulcan_factor = 0.0;
    std::map<detid_t, double>::const_iterator vulcan_iter =
        vulcan.find(detectorID);
    if (vulcan_iter != vulcan.end()) {
      vulcan_factor = vulcan_iter->second;
      numfinds++;
    }

    // g_log.notice() << "Selected Detector with ID = " << detectorID << "  ID2
    // = " << id2 << std::endl; proved to be same

    double intermoduleoffset = 0;
    double interstackoffset = 0;

    detid_t intermoduleid = detid_t(detectorID / 1250) * 1250 + 1250 - 2;
    vulcan_iter = vulcan.find(intermoduleid);
    if (vulcan_iter == vulcan.end()) {
      g_log.error() << "Cannot find inter-module offset ID = " << intermoduleid
                    << std::endl;
    } else {
      intermoduleoffset = vulcan_iter->second;
    }

    detid_t interstackid = detid_t(detectorID / 1250) * 1250 + 1250 - 1;
    vulcan_iter = vulcan.find(interstackid);
    if (vulcan_iter == vulcan.end()) {
      g_log.error() << "Cannot find inter-module offset ID = " << intermoduleid
                    << std::endl;
    } else {
      interstackoffset = vulcan_iter->second;
    }

    /***  This is the previous way to correct upon DIFC[module center pixel]
    // The actual factor is 10^(-value_in_the_file)
    vulcan_factor = pow(10.0,-vulcan_factor);
    // At this point, tof_corrected = vulcan_factor * tof_input
    // So this is the offset
    offset = vulcan_factor - 1.0;
    ***/

    /*** New approach to correct based on DIFC of each pixel
     *   Equation:  offset = DIFC^(pixel)/DIFC^(parent)*(1+vulcan_offset)-1
     *   offset should be close to 0
     ***/
    // 1. calculate DIFC
    Kernel::V3D detPos;
    detPos = det->getPos();

    // Now detPos will be set with respect to samplePos
    detPos -= samplePos;
    double l2 = detPos.norm();
    double halfcosTwoTheta =
        detPos.scalar_prod(beamline) / (l2 * beamline_norm);
    double sinTheta = sqrt(0.5 - halfcosTwoTheta);
    double difc_pixel = sinTheta * (l1 + l2) / CONSTANT;

    // Kernel::V3D parentPos = det->getParent()->getPos();
    // parentPos -= samplePos;
    // double l2parent = parentPos.norm();
    // double halfcosTwoThetaParent = parentPos.scalar_prod(beamline)/(l2 *
    // beamline_norm);
    // double sinThetaParent = sqrt(0.5 - halfcosTwoThetaParent);
    // double difc_parent = sinThetaParent*(l1+l2parent)/CONSTANT;

    /*** Offset Replicate Previous Result
    offset = difc_pixel/difc_parent*(pow(10.0, -vulcan_factor))-1.0;
    ***/

    offset =
        difc_pixel / difcRef * (pow(10.0, -(vulcan_factor + intermoduleoffset +
                                            interstackoffset))) -
        1.0;

    // Save in the map
    try {
      offsetsWS->setValue(detectorID, offset);

      if (intermoduleid != 27498 && intermoduleid != 28748 &&
          intermoduleid != 29998 && intermoduleid != 33748 &&
          intermoduleid != 34998 && intermoduleid != 36248) {
        g_log.error() << "Detector ID = " << detectorID
                      << "  Inter-Module ID = " << intermoduleid << std::endl;
        throw std::invalid_argument("Indexing error!");
      }

    } catch (std::invalid_argument &) {
      g_log.notice() << "Misses Detector ID = " << detectorID << std::endl;
    }
  } // for

  g_log.notice() << "Number of matched detectors =" << numfinds << std::endl;
}
コード例 #8
0
  /** Execute the algorithm.
   */
  void ModifyDetectorDotDatFile::exec()
  {
    std::string inputFilename = getPropertyValue("InputFilename");
    std::string outputFilename = getPropertyValue("OutputFilename");

    Workspace_sptr ws1 = getProperty("InputWorkspace");
    ExperimentInfo_sptr ws = boost::dynamic_pointer_cast<ExperimentInfo>(ws1);

    // Check instrument
    Instrument_const_sptr inst = ws->getInstrument();
    if (!inst) throw std::runtime_error("No instrument in the Workspace. Cannot modify detector dot dat file");

    // Open files
    std::ifstream in;
    in.open( inputFilename.c_str());
    if(!in) {
        throw Exception::FileError("Can't open input file", inputFilename);
    }
    std::ofstream out;
    out.open( outputFilename.c_str());
    if(!out) {
        in.close();
        throw Exception::FileError("Can't open output file", outputFilename);
    }

    // Read first line, modify it and put into output file
    std::string str;
    getline( in, str );
    out << str << " and modified by MANTID algorithm ModifyDetectorDotDatFile \n";

    // Read second line to check number of detectors and columns
    int detectorCount, numColumns;
    getline( in, str );
    std::istringstream header2(str);
    header2 >> detectorCount >> numColumns;
    out << str << "\n";
    // check that we have at least 1 detector and six columns
    if( detectorCount < 1 || numColumns < 6) {
          out.close();
          in.close();
          throw Exception::FileError("Incompatible file format found when reading line 2 in the input file", inputFilename);
    }

    // Copy column title line
    getline( in, str );
    out << str << "\n";

    int i=0;

    // Format details
    int pOffset = 3; // Precision of Offset
    int pOther = 5; // Precision of Other floats
    int wDet = 9; // Field width of Detector ID
    int wOff = 8; // Field width of Offset
    int wRad = 10; // Field width of Radius
    int wCode = 6; // Field width of Code
    int wAng = 12; // Field width of angles

    // Read input file line by line, modify line as necessary and put line into output file
    while( getline( in, str ) ){

       std::istringstream istr(str);
    
       detid_t detID;
       double offset;
       int code;
       float dump; // ignored data

       if (str.empty() || str[0] == '#')
       { // comments and empty lines are allowed and just copied
           out << str << "\n";
           continue;
       }

       // First six columns in the file, the detector ID and a code for the type of detector CODE = 3 (psd gas tube)
       istr >> detID >> offset >> dump >> code >> dump >> dump;

       if( code == 3 ){
          // This is detector will look for it in workspace and if found use its position
          Geometry::IDetector_const_sptr det = ws->getDetectorByID( detID );
          if( det ) {
              V3D pos = det->getPos();
              double l2;
              double theta;
              double phi;
              pos.getSpherical ( l2, theta, phi ); 
              std::streampos width = istr.tellg(); // Amount of string to replace
              // Some experimenting with line manipulation
              std::ostringstream oss;
              oss  << std::fixed << std::right ;
              oss.precision(pOffset);
              oss << std::setw(wDet) << detID << std::setw(wOff) << offset;
              oss.precision(pOther);
              oss << std::setw(wRad) << l2 << std::setw(wCode) << code << std::setw(wAng) << theta << std::setw(wAng) << phi ;
              std::string prefix = oss.str();
              std::string suffix = str.substr( width, std::string::npos );
              out << prefix << suffix << "\n";
              i++;
          } else {  // Detector not found, don't modify
              out << str << "\n";
          }
       } else {
       // We do not modify any other type of line
          out << str << "\n";
       }
    }

    out.close();
    in.close();

  }
コード例 #9
0
    /**
     * Updates from a more generic ascii file
     * @param filename :: The input filename
     */
    void UpdateInstrumentFromFile::updateFromAscii(const std::string & filename)
    {
      AsciiFileHeader header;
      const bool isSpectrum = parseAsciiHeader(header);

      Geometry::Instrument_const_sptr inst = m_workspace->getInstrument();
      // Throws for multiple detectors
      const spec2index_map specToIndex(m_workspace->getSpectrumToWorkspaceIndexMap());

      std::ifstream datfile(filename.c_str(), std::ios_base::in);
      const int skipNLines = getProperty("SkipFirstNLines");
      std::string line;
      int lineCount(0);
      while(lineCount < skipNLines)
      {
        std::getline(datfile,line);
        ++lineCount;
      }

      std::vector<double> colValues(header.colCount - 1, 0.0);
      while(std::getline(datfile,line))
      {
        boost::trim(line);
        std::istringstream is(line);
        // Column 0 should be ID/spectrum number
        int32_t detOrSpec(-1000);
        is >> detOrSpec;
        // If first thing read is not a number then skip the line
        if(is.fail())
        {
          g_log.debug() << "Skipping \"" << line << "\". Cannot interpret as list of numbers.\n";
          continue;
        }

        Geometry::IDetector_const_sptr det;
        try
        {
          if(isSpectrum)
          {
            auto it = specToIndex.find(detOrSpec);
            if(it != specToIndex.end())
            {
              const size_t wsIndex = it->second;
              det = m_workspace->getDetector(wsIndex);
            }
            else
            {
              g_log.debug() << "Skipping \"" << line << "\". Spectrum is not in workspace.\n";
              continue;
            }
          }
          else
          {
            det = inst->getDetector(detOrSpec);
          }
        }
        catch(Kernel::Exception::NotFoundError&)
        {
          g_log.debug() << "Skipping \"" << line << "\". Spectrum in workspace but cannot find associated detector.\n";
          continue;
        }

        // Special cases for detector r,t,p. Everything else is
        // attached as an detector parameter
        double R(0.0),theta(0.0), phi(0.0);
        for(size_t i = 1; i < header.colCount; ++i)
        {
          double value(0.0);
          is >> value;
          if(i < header.colCount - 1 && is.eof())
          {
            //If stringstream is at EOF & we are not at the last column then
            // there aren't enought columns in the file
            throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - "
                          "File contains fewer than expected number of columns, check AsciiHeader property.");
          }

          if(i == header.rColIdx) R = value;
          else if(i == header.thetaColIdx) theta = value;
          else if(i == header.phiColIdx) phi = value;
          else if(header.detParCols.count(i) == 1)
          {
            Geometry::ParameterMap & pmap = m_workspace->instrumentParameters();
            pmap.addDouble(det->getComponentID(), header.colToName[i],value);
          }
        }
        // Check stream state. stringstream::EOF should have been reached, if not then there is still more to
        // read and the file has more columns than the header indicated
        if(!is.eof())
        {
          throw std::runtime_error("UpdateInstrumentFromFile::updateFromAscii - "
              "File contains more than expected number of columns, check AsciiHeader property.");
        }

        // If not supplied use current values
        double r,t,p;
        det->getPos().getSpherical(r,t,p);
        if(header.rColIdx == 0) R = r;
        if(header.thetaColIdx == 0) theta = t;
        if(header.phiColIdx == 0) phi = p;

        setDetectorPosition(det, static_cast<float>(R), static_cast<float>(theta), static_cast<float>(phi));
      }
    }
コード例 #10
0
ファイル: SetScalingPSD.cpp プロジェクト: nimgould/mantid
/** Read the scaling information from a file (e.g. merlin_detector.sca) or from
 * the RAW file (.raw)
 *  @param scalingFile :: Name of scaling file .sca
 *  @param truepos :: V3D vector of actual positions as read from the file
 *  @return False if unable to open file, True otherwise
 */
bool SetScalingPSD::processScalingFile(const std::string &scalingFile,
                                       std::vector<Kernel::V3D> &truepos) {
  // Read the scaling information from a text file (.sca extension) or from a
  // raw file (.raw)
  // This is really corrected positions as (r,theta,phi) for each detector
  // Compare these with the instrument values to determine the change in
  // position and the scaling
  // which may be necessary for each pixel if in a tube.
  // movePos is used to updated positions
  std::map<int, Kernel::V3D> posMap;
  std::map<int, double> scaleMap;
  std::map<int, double>::iterator its;

  Instrument_const_sptr instrument = m_workspace->getInstrument();
  if (scalingFile.find(".sca") != std::string::npos ||
      scalingFile.find(".SCA") != std::string::npos) {
    // read a .sca text format file
    // format consists of a short header followed by one line per detector

    std::ifstream sFile(scalingFile.c_str());
    if (!sFile) {
      g_log.error() << "Unable to open scaling file " << scalingFile
                    << std::endl;
      return false;
    }
    std::string str;
    getline(sFile,
            str); // skip header line should be <filename> generated by <prog>
    int detectorCount;
    getline(sFile, str); // get detector count line
    std::istringstream istr(str);
    istr >> detectorCount;
    if (detectorCount < 1) {
      g_log.error("Bad detector count in scaling file");
      throw std::runtime_error("Bad detector count in scaling file");
    }
    truepos.reserve(detectorCount);
    getline(sFile, str); // skip title line
    int detIdLast = -10;
    Kernel::V3D truPosLast, detPosLast;

    Progress prog(this, 0.0, 0.5, detectorCount);
    // Now loop through lines, one for each detector/monitor. The latter are
    // ignored.

    while (getline(sFile, str)) {
      if (str.empty() || str[0] == '#')
        continue;
      std::istringstream istr(str);

      // read 6 values from the line to get the 3 (l2,theta,phi) of interest
      int detIndex, code;
      double l2, theta, phi, offset;
      istr >> detIndex >> offset >> l2 >> code >> theta >> phi;

      // sanity check on angles - l2 should be +ve but sample file has a few -ve
      // values
      // on monitors
      if (theta > 181.0 || theta < -1 || phi < -181 || phi > 181) {
        g_log.error("Position angle data out of range in .sca file");
        throw std::runtime_error(
            "Position angle data out of range in .sca file");
      }
      Kernel::V3D truPos;
      // use abs as correction file has -ve l2 for first few detectors
      truPos.spherical(fabs(l2), theta, phi);
      truepos.push_back(truPos);
      //
      Geometry::IDetector_const_sptr det;
      try {
        det = instrument->getDetector(detIndex);
      } catch (Kernel::Exception::NotFoundError &) {
        continue;
      }
      Kernel::V3D detPos = det->getPos();
      Kernel::V3D shift = truPos - detPos;

      // scaling applied to dets that are not monitors and have sequential IDs
      if (detIdLast == detIndex - 1 && !det->isMonitor()) {
        Kernel::V3D diffI = detPos - detPosLast;
        Kernel::V3D diffT = truPos - truPosLast;
        double scale = diffT.norm() / diffI.norm();
        Kernel::V3D scaleDir = diffT / diffT.norm();
        // Wish to store the scaling in a map, if we already have a scaling
        // for this detector (i.e. from the other side) we average the two
        // values. End of tube detectors only have one scaling estimate.
        scaleMap[detIndex] = scale;
        its = scaleMap.find(detIndex - 1);
        if (its == scaleMap.end())
          scaleMap[detIndex - 1] = scale;
        else
          its->second = 0.5 * (its->second + scale);
        // std::cout << detIndex << scale << scaleDir << std::endl;
      }
      detIdLast = detIndex;
      detPosLast = detPos;
      truPosLast = truPos;
      posMap[detIndex] = shift;
      //
      prog.report();
    }
  } else if (scalingFile.find(".raw") != std::string::npos ||