/** Convert X units from nano-secs to micro-secs and shift to start at m_tMin
* @param inputWs :: [input/output] workspace to convert
*/
void PhaseQuadMuon::convertToMicroSecs (API::MatrixWorkspace_sptr inputWs)
{
  for (size_t h=0; h<inputWs->getNumberHistograms(); h++)
  {
    auto spec = inputWs->getSpectrum(h);
    for (int t=0; t<m_nData+1; t++)
    {
     spec->dataX()[t] = spec->dataX()[t]/1000+m_tMin;
    }
  }
}
/** Loads, checks and passes back the values passed to the algorithm
 * @param whiteBeam1 :: A white beam vanadium spectrum that will be used to
 * check detector efficiency variations
 * @param whiteBeam2 :: The other white beam vanadium spectrum from the same
 * instrument to use for comparison
 * @param variation :: The maximum fractional variation above the median that is
 * allowed for god detectors
 * @param startWsIndex :: Index number of the first spectrum to use
 * @param endWsIndex :: Index number of the last spectrum to use
 * @throw invalid_argument if there is an incapatible property value and so the
 * algorithm can't continue
 */
void DetectorEfficiencyVariation::retrieveProperties(
    API::MatrixWorkspace_sptr &whiteBeam1,
    API::MatrixWorkspace_sptr &whiteBeam2, double &variation, int &startWsIndex,
    int &endWsIndex) {
  whiteBeam1 = getProperty("WhiteBeamBase");
  whiteBeam2 = getProperty("WhiteBeamCompare");
  if (whiteBeam1->getInstrument()->getName() !=
      whiteBeam2->getInstrument()->getName()) {
    throw std::invalid_argument("The two input white beam vanadium workspaces "
                                "must be from the same instrument");
  }
  int maxWsIndex = static_cast<int>(whiteBeam1->getNumberHistograms()) - 1;
  if (maxWsIndex !=
      static_cast<int>(whiteBeam2->getNumberHistograms()) -
          1) { // we would get a crash later on if this were not true
    throw std::invalid_argument("The input white beam vanadium workspaces must "
                                "be have the same number of histograms");
  }

  variation = getProperty("Variation");

  startWsIndex = getProperty("StartWorkspaceIndex");
  if ((startWsIndex < 0) || (startWsIndex > maxWsIndex)) {
    g_log.warning("StartWorkspaceIndex out of range, changed to 0");
    startWsIndex = 0;
  }
  endWsIndex = getProperty("EndWorkspaceIndex");
  if (endWsIndex == Mantid::EMPTY_INT())
    endWsIndex = maxWsIndex;
  if ((endWsIndex < 0) || (endWsIndex > maxWsIndex)) {
    g_log.warning(
        "EndWorkspaceIndex out of range, changed to max Workspace number");
    endWsIndex = maxWsIndex;
  }
  if ((endWsIndex < startWsIndex)) {
    g_log.warning(
        "EndWorkspaceIndex can not be less than the StartWorkspaceIndex, "
        "changed to max Workspace number");
    endWsIndex = maxWsIndex;
  }
}
Beispiel #3
0
    std::vector<std::vector<size_t> > DetectorDiagnostic::makeInstrumentMap(API::MatrixWorkspace_sptr countsWS)
    {
      std::vector<std::vector<size_t> > mymap;
      std::vector<size_t> single;

      for(size_t i=0;i < countsWS->getNumberHistograms();i++)
      {
        single.push_back(i);
      }
      mymap.push_back(single);
      return mymap;
    }
/***
 * This will ensure the spectrum numbers do not overlap by starting the second
 *on at the first + 1
 *
 * @param ws1 The first workspace supplied to the algorithm.
 * @param ws2 The second workspace supplied to the algorithm.
 * @param output The workspace that is going to be returned by the algorithm.
 */
void ConjoinWorkspaces::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1,
                                           API::MatrixWorkspace_const_sptr ws2,
                                           API::MatrixWorkspace_sptr output) {
  bool needsFix(false);

  if (this->getProperty("CheckOverlapping")) {
    // If CheckOverlapping is required, then either skip fixing spectrum number
    // or get stopped by an exception
    if (!m_overlapChecked)
      checkForOverlap(ws1, ws2, true);
    needsFix = false;
  } else {
    // It will be determined later whether spectrum number needs to be fixed.
    needsFix = true;
  }
  if (!needsFix)
    return;

  // is everything possibly ok?
  specid_t min;
  specid_t max;
  getMinMax(output, min, max);
  if (max - min >= static_cast<specid_t>(
                       output->getNumberHistograms())) // nothing to do then
    return;

  // information for remapping the spectra numbers
  specid_t ws1min;
  specid_t ws1max;
  getMinMax(ws1, ws1min, ws1max);

  // change the axis by adding the maximum existing spectrum number to the
  // current value
  for (size_t i = ws1->getNumberHistograms(); i < output->getNumberHistograms();
       i++) {
    specid_t origid;
    origid = output->getSpectrum(i)->getSpectrumNo();
    output->getSpectrum(i)->setSpectrumNo(origid + ws1max);
  }
}
Beispiel #5
0
/** Returns a given spectrum as a complex number
* @param inWS :: [input] The input workspace containing all the spectra
* @param spec :: [input] The spectrum of interest
* @param errors :: [input] If true, returns the errors, otherwise returns the
* counts
* @return : Spectrum 'spec' as a complex vector
*/
std::vector<double> MaxEnt::toComplex(const API::MatrixWorkspace_sptr &inWS,
                                      size_t spec, bool errors) {

  std::vector<double> result(inWS->blocksize() * 2);

  if (inWS->getNumberHistograms() % 2)
    throw std::invalid_argument(
        "Cannot convert input workspace to complex data");

  size_t nspec = inWS->getNumberHistograms() / 2;

  if (!errors) {
    for (size_t i = 0; i < inWS->blocksize(); i++) {
      result[2 * i] = inWS->readY(spec)[i];
      result[2 * i + 1] = inWS->readY(spec + nspec)[i];
    }
  } else {
    for (size_t i = 0; i < inWS->blocksize(); i++) {
      result[2 * i] = inWS->readE(spec)[i];
      result[2 * i + 1] = inWS->readE(spec + nspec)[i];
    }
  }
  return result;
}
Beispiel #6
0
/** Divide each bin by the width of its q bin.
 *  @param outputWS :: The output workspace
 *  @param qAxis ::    A vector of the q bin boundaries
 */
void SofQWCentre::makeDistribution(API::MatrixWorkspace_sptr outputWS,
                                   const std::vector<double> qAxis) {
  std::vector<double> widths(qAxis.size());
  std::adjacent_difference(qAxis.begin(), qAxis.end(), widths.begin());

  const size_t numQBins = outputWS->getNumberHistograms();
  for (size_t i = 0; i < numQBins; ++i) {
    auto &Y = outputWS->mutableY(i);
    auto &E = outputWS->mutableE(i);
    std::transform(Y.begin(), Y.end(), Y.begin(),
                   std::bind2nd(std::divides<double>(), widths[i + 1]));
    std::transform(E.begin(), E.end(), E.begin(),
                   std::bind2nd(std::divides<double>(), widths[i + 1]));
  }
}
Beispiel #7
0
void SaveFITS::writeFITSHeaderAxesSizes(const API::MatrixWorkspace_sptr img,
                                        std::ofstream &file) {
  const std::string sizeX = std::to_string(img->blocksize());
  const std::string sizeY = std::to_string(img->getNumberHistograms());

  const size_t fieldWidth = 20;
  std::stringstream axis1;
  axis1 << "NAXIS1  = " << std::setw(fieldWidth) << sizeX
        << " / length of data axis 1";
  writeFITSHeaderEntry(axis1.str(), file);

  std::stringstream axis2;
  axis2 << "NAXIS2  = " << std::setw(fieldWidth) << sizeY
        << " / length of data axis 2";
  writeFITSHeaderEntry(axis2.str(), file);
}
/** Fits each spectrum in the workspace to f(x) = A * sin( w * x + p)
* @param ws :: [input] The workspace to fit
* @param freq :: [input] Hint for the frequency (w)
* @param groupName :: [input] The name of the output workspace group
* @param resTab :: [output] Table workspace storing the asymmetries and phases
* @param resGroup :: [output] Workspace group storing the fitting results
*/
void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws,
                                         double freq, std::string groupName,
                                         API::ITableWorkspace_sptr &resTab,
                                         API::WorkspaceGroup_sptr &resGroup) {

  int nhist = static_cast<int>(ws->getNumberHistograms());

  // Create the fitting function f(x) = A * sin ( w * x + p )
  // The same function and initial parameters are used for each fit
  std::string funcStr = createFittingFunction(freq, true);

  // Set up results table
  resTab->addColumn("int", "Spectrum number");
  resTab->addColumn("double", "Asymmetry");
  resTab->addColumn("double", "Phase");

  // Loop through fitting all spectra individually
  const static std::string success = "success";
  for (int wsIndex = 0; wsIndex < nhist; wsIndex++) {
    reportProgress(wsIndex, nhist);
    auto fit = createChildAlgorithm("Fit");
    fit->initialize();
    fit->setPropertyValue("Function", funcStr);
    fit->setProperty("InputWorkspace", ws);
    fit->setProperty("WorkspaceIndex", wsIndex);
    fit->setProperty("CreateOutput", true);
    fit->setPropertyValue("Output", groupName);
    fit->execute();

    std::string status = fit->getProperty("OutputStatus");
    if (!fit->isExecuted() || status != success) {
      std::ostringstream error;
      error << "Fit failed for spectrum at workspace index " << wsIndex;
      error << ": " << status;
      throw std::runtime_error(error.str());
    }

    API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace");
    resGroup->addWorkspace(fitOut);
    API::ITableWorkspace_sptr tab = fit->getProperty("OutputParameters");
    // Now we have our fitting results stored in tab
    // but we need to extract the relevant information, i.e.
    // the detector phases (parameter 'p') and asymmetries ('A')
    const auto &spectrum = ws->getSpectrum(static_cast<size_t>(wsIndex));
    extractDetectorInfo(tab, resTab, spectrum.getSpectrumNo());
  }
}
Beispiel #9
0
/**
 * Validation of the inputs of the RingProfile algorithm. 
 *
 * Inside this method, the Workspace is considered a 2D Matrix, where each spectrum is
 * the rows of the matrix and have the variation in axis0. The columns of the matrix 
 * is the position of dataX(0)
 * 
 * The main validation are: 
 *  - the centre of the ring is inside the image it self.
 *  - The minimum ring is smaller than the limits of the image to allow 
 * @param inputWS: pointer to the input workspace
*/
void RingProfile::checkInputsForNumericWorkspace(const API::MatrixWorkspace_sptr inputWS){
  g_log.notice() << "CheckingInputs For Numeric Workspace" << std::endl; 

  // The Axis0 is defined by the values of readX inside the spectra of the workspace. 
  // The limits of this axis will be get by inspection of the readX vector taking the first 
  // and the last value. 
  
  // check that centre is inside the range available for the instrument
  const MantidVec & refX  = inputWS->readX(inputWS->getNumberHistograms()/2);  
  // get the limits of the axis 0 (X)
  double min_v_x, max_v_x;
  min_v_x = std::min(refX[0], refX[refX.size() -1]); 
  max_v_x = std::max(refX[0], refX[refX.size() -1]); 
  g_log.notice() << "Limits X = " << min_v_x << " " << max_v_x << std::endl;   
  // check centre is inside the X domain
  if ( centre_x < min_v_x || centre_x > max_v_x){
    std::stringstream s;
    s << "The input value for centre (X="<< centre_x << ") is outside the limits of the instrument ["
      << min_v_x << ", "<< max_v_x << "]" ; 
    throw std::invalid_argument(s.str());
  }        
  

  // The Axis1 is defined by the spectra inside the workspace. Its limits and values are given by the 
  // ws->getAxis(1)

  // get the limits of the axis1 (Y)
  API::NumericAxis *oldAxis2 = dynamic_cast<API::NumericAxis*>(inputWS->getAxis(1) );
  // we cannot have the positions in Y direction without a NumericAxis  
  if( !oldAxis2 ) 
    throw std::invalid_argument("Vertical axis is not a numeric axis. If it is a spectra axis try running ConvertSpectrumAxis first.");
  double min_v_y = std::min(oldAxis2->getMin(), oldAxis2->getMax()); 
  double max_v_y = std::max(oldAxis2->getMin(), oldAxis2->getMax()); 
  g_log.notice() << "Limits Y = " << min_v_y << " " << max_v_y << std::endl;   
  // check centre is inside the Y domain
  if (centre_y < min_v_y || centre_y > max_v_y){
    std::stringstream s; 
    s << "The input value for centre (Y=" << centre_y << ") is outside the limits of the instrument ["
      << min_v_y << ", " << max_v_y << "]" ;
    throw std::invalid_argument(s.str()); 
  }
  g_log.notice() << "Centre: " << centre_x << "  " << centre_y << std::endl; 
  // check minradius is inside the limits of the region of the instrument
  if (centre_x - min_radius > max_v_x || centre_x + min_radius < min_v_x || centre_y - min_radius > max_v_y || centre_y + min_radius < min_v_y)
    throw std::invalid_argument("The minimun radius is outside the region of the instrument");

}
Beispiel #10
0
/** This function will check how to group spectra when calculating median
 *
 *
 */
std::vector<std::vector<size_t>>
DetectorDiagnostic::makeMap(API::MatrixWorkspace_sptr countsWS) {
  std::multimap<Mantid::Geometry::ComponentID, size_t> mymap;

  Geometry::Instrument_const_sptr instrument = countsWS->getInstrument();
  if (m_parents == 0) {
    return makeInstrumentMap(*countsWS);
  }
  if (!instrument) {
    g_log.warning("Workspace has no instrument. LevelsUP is ignored");
    return makeInstrumentMap(*countsWS);
  }

  // check if not grouped. If grouped, it will throw
  if (countsWS->hasGroupedDetectors()) {
    throw std::runtime_error("Median detector test: not able to create "
                             "detector to spectra map. Try with LevelUp=0.");
  }

  for (size_t i = 0; i < countsWS->getNumberHistograms(); i++) {
    detid_t d = (*(countsWS->getSpectrum(i).getDetectorIDs().begin()));
    auto anc = instrument->getDetector(d)->getAncestors();
    if (anc.size() < static_cast<size_t>(m_parents)) {
      g_log.warning("Too many levels up. Will ignore LevelsUp");
      m_parents = 0;
      return makeInstrumentMap(*countsWS);
    }
    mymap.emplace(anc[m_parents - 1]->getComponentID(), i);
  }

  std::vector<std::vector<size_t>> speclist;

  std::multimap<Mantid::Geometry::ComponentID, size_t>::iterator m_it, s_it;
  for (m_it = mymap.begin(); m_it != mymap.end(); m_it = s_it) {
    Mantid::Geometry::ComponentID theKey = m_it->first;
    auto keyRange = mymap.equal_range(theKey);
    // Iterate over all map elements with key == theKey
    std::vector<size_t> speclistsingle;
    for (s_it = keyRange.first; s_it != keyRange.second; ++s_it) {
      speclistsingle.push_back(s_it->second);
    }
    speclist.push_back(std::move(speclistsingle));
  }

  return speclist;
}
Beispiel #11
0
/** Assuming that the input workspace is a Numeric Image where the pixel
 *positions depend on their
 *  relative position inside the workspace, this function extracts the position
 *of the first and last
 *  pixel of the image.
 *
 *  It is important that the input workspace must be a numeric image, and not an
 *instrument related workspace.
 *  The function will raise exception (std::invalid_argument) if an invalid
 *input is give.
 *
 *  @see RadiusSum::inputWorkspaceHasInstrumentAssociated for reference.
 *
 *  @param inWS reference to the workspace
 *  @return a list of values that defines the limits of the image in this order:
 *Xmin, Xmax, Ymin, Ymax
 */
std::vector<double>
RadiusSum::getBoundariesOfNumericImage(API::MatrixWorkspace_sptr inWS) {

  // horizontal axis

  // get the pixel position in the horizontal axis from the middle of the image.
  const MantidVec &refX = inWS->readX(inWS->getNumberHistograms() / 2);

  double min_x, max_x;

  const double &first_x(refX[0]);
  const double &last_x(refX[refX.size() - 1]);
  if (first_x < last_x) {
    min_x = first_x;
    max_x = last_x;
  } else {
    min_x = last_x;
    max_x = first_x;
  }

  // vertical axis
  API::NumericAxis *verticalAxis =
      dynamic_cast<API::NumericAxis *>(inWS->getAxis(1));
  if (!verticalAxis)
    throw std::invalid_argument("Vertical axis is not a numeric axis. Can not "
                                "find the limits of the image.");

  double min_y, max_y;
  min_y = verticalAxis->getMin();
  max_y = verticalAxis->getMax();

  // check the assumption made that verticalAxis will provide the correct
  // answer.
  if (min_y > max_y) {
    throw std::logic_error("Failure to get the boundaries of this image. "
                           "Internal logic error. Please, inform MantidHelp");
  }

  std::vector<double> output(4); // output = {min_x, max_x, min_y, max_y}; not
                                 // supported in all compilers
  output[0] = min_x;
  output[1] = max_x;
  output[2] = min_y;
  output[3] = max_y;
  return output;
}
Beispiel #12
0
  /** If there is an overlap in spectrum numbers between ws1 and ws2,
   * then the spectrum numbers are reset as a simple 1-1 correspondence
   * with the workspace index.
   *
   * @param ws1 The first workspace supplied to the algorithm.
   * @param ws2 The second workspace supplied to the algorithm.
   * @param output The workspace that is going to be returned by the algorithm.
   */
  void AppendSpectra::fixSpectrumNumbers(API::MatrixWorkspace_const_sptr ws1, API::MatrixWorkspace_const_sptr ws2,
                                             API::MatrixWorkspace_sptr output)
  {
    specid_t ws1min;
    specid_t ws1max;
    getMinMax(ws1, ws1min, ws1max);

    specid_t ws2min;
    specid_t ws2max;
    getMinMax(ws2, ws2min, ws2max);

    // is everything possibly ok?
    if (ws2min > ws1max)
      return;

    // change the axis by adding the maximum existing spectrum number to the current value
    for (size_t i = 0; i < output->getNumberHistograms(); i++)
      output->getSpectrum(i)->setSpectrumNo( specid_t(i) );
  }
Beispiel #13
0
/**
 * The main method to calculate the ring profile for workspaces based on
 *instruments.
 *
 * It will iterate over all the spectrum inside the workspace.
 * For each spectrum, it will use the RingProfile::getBinForPixel method to
 *identify
 * where, in the output_bins, the sum of all the spectrum values should be
 *placed in.
 *
 * @param inputWS: pointer to the input workspace
 * @param output_bins: the reference to the vector to be filled with the
 *integration values
 */
void RingProfile::processInstrumentRingProfile(
    const API::MatrixWorkspace_sptr inputWS, std::vector<double> &output_bins) {

  for (int i = 0; i < static_cast<int>(inputWS->getNumberHistograms()); i++) {
    m_progress->report("Computing ring bins positions for detectors");
    // for the detector based, the positions will be taken from the detector
    // itself.
    try {
      Mantid::Geometry::IDetector_const_sptr det = inputWS->getDetector(i);

      // skip monitors
      if (det->isMonitor()) {
        continue;
      }

      // this part will be executed if the instrument is attached to the
      // workspace

      // get the bin position
      int bin_n = getBinForPixel(det);

      if (bin_n < 0) // -1 is the agreement for an invalid bin, or outside the
                     // ring being integrated
        continue;

      g_log.debug() << "Bin for the index " << i << " = " << bin_n
                    << " Pos = " << det->getPos() << std::endl;

      // get the reference to the spectrum
      auto spectrum_pt = inputWS->getSpectrum(i);
      const MantidVec &refY = spectrum_pt->dataY();
      // accumulate the values of this spectrum inside this bin
      for (size_t sp_ind = 0; sp_ind < inputWS->blocksize(); sp_ind++)
        output_bins[bin_n] += refY[sp_ind];

    } catch (Kernel::Exception::NotFoundError &ex) {
      g_log.information() << "It found that detector for " << i
                          << " is not valid. " << ex.what() << std::endl;
      continue;
    }
  }
}
Beispiel #14
0
/** Executes the algorithm
 *
 */
void SplineBackground::exec()
{

  API::MatrixWorkspace_sptr inWS = getProperty("InputWorkspace");
  int spec = getProperty("WorkspaceIndex");

  if (spec > static_cast<int>(inWS->getNumberHistograms()))
    throw std::out_of_range("WorkspaceIndex is out of range.");

  const MantidVec& X = inWS->readX(spec);
  const MantidVec& Y = inWS->readY(spec);
  const MantidVec& E = inWS->readE(spec);
  const bool isHistogram = inWS->isHistogramData();

  const int ncoeffs = getProperty("NCoeff");
  const int k = 4; // order of the spline + 1 (cubic)
  const int nbreak = ncoeffs - (k - 2);

  if (nbreak <= 0)
    throw std::out_of_range("Too low NCoeff");

  gsl_bspline_workspace *bw;
  gsl_vector *B;

  gsl_vector *c, *w, *x, *y;
  gsl_matrix *Z, *cov;
  gsl_multifit_linear_workspace *mw;
  double chisq;

  int n = static_cast<int>(Y.size());
  bool isMasked = inWS->hasMaskedBins(spec);
  std::vector<int> masked(Y.size());
  if (isMasked)
  {
    for(API::MatrixWorkspace::MaskList::const_iterator it=inWS->maskedBins(spec).begin();it!=inWS->maskedBins(spec).end();++it)
      masked[it->first] = 1;
    n -= static_cast<int>(inWS->maskedBins(spec).size());
  }

  if (n < ncoeffs)
  {
    g_log.error("Too many basis functions (NCoeff)");
    throw std::out_of_range("Too many basis functions (NCoeff)");
  }

  /* allocate a cubic bspline workspace (k = 4) */
  bw = gsl_bspline_alloc(k, nbreak);
  B = gsl_vector_alloc(ncoeffs);

  x = gsl_vector_alloc(n);
  y = gsl_vector_alloc(n);
  Z = gsl_matrix_alloc(n, ncoeffs);
  c = gsl_vector_alloc(ncoeffs);
  w = gsl_vector_alloc(n);
  cov = gsl_matrix_alloc(ncoeffs, ncoeffs);
  mw = gsl_multifit_linear_alloc(n, ncoeffs);

  /* this is the data to be fitted */
  int j = 0;
  for (MantidVec::size_type i = 0; i < Y.size(); ++i)
  {
    if (isMasked && masked[i]) continue;
    gsl_vector_set(x, j, (isHistogram ? (0.5*(X[i]+X[i+1])) : X[i])); // Middle of the bins, if a histogram
    gsl_vector_set(y, j, Y[i]);
    gsl_vector_set(w, j, E[i]>0.?1./(E[i]*E[i]):0.);

    ++j;
  }

  if (n != j)
  {
    gsl_bspline_free(bw);
    gsl_vector_free(B);
    gsl_vector_free(x);
    gsl_vector_free(y);
    gsl_matrix_free(Z);
    gsl_vector_free(c);
    gsl_vector_free(w);
    gsl_matrix_free(cov);
    gsl_multifit_linear_free(mw);

    throw std::runtime_error("Assertion failed: n != j");
  }

  double xStart = X.front();
  double xEnd =   X.back();

  /* use uniform breakpoints */
  gsl_bspline_knots_uniform(xStart, xEnd, bw);

  /* construct the fit matrix X */
  for (int i = 0; i < n; ++i)
  {
    double xi=gsl_vector_get(x, i);

    /* compute B_j(xi) for all j */
    gsl_bspline_eval(xi, B, bw);

    /* fill in row i of X */
    for (j = 0; j < ncoeffs; ++j)
    {
      double Bj = gsl_vector_get(B, j);
      gsl_matrix_set(Z, i, j, Bj);
    }
  }

  /* do the fit */
  gsl_multifit_wlinear(Z, w, y, c, cov, &chisq, mw);

  /* output the smoothed curve */
  API::MatrixWorkspace_sptr outWS = WorkspaceFactory::Instance().create(inWS,1,X.size(),Y.size());
  {
    outWS->getAxis(1)->setValue(0, inWS->getAxis(1)->spectraNo(spec));
    double xi, yi, yerr;
    for (MantidVec::size_type i=0;i<Y.size();i++)
    {
      xi = X[i];
      gsl_bspline_eval(xi, B, bw);
      gsl_multifit_linear_est(B, c, cov, &yi, &yerr);
      outWS->dataY(0)[i] = yi;
      outWS->dataE(0)[i] = yerr;
    }
    outWS->dataX(0) = X;
  }

  gsl_bspline_free(bw);
  gsl_vector_free(B);
  gsl_vector_free(x);
  gsl_vector_free(y);
  gsl_matrix_free(Z);
  gsl_vector_free(c);
  gsl_vector_free(w);
  gsl_matrix_free(cov);
  gsl_multifit_linear_free(mw);

  setProperty("OutputWorkspace",outWS);

}
/** Carries out the bin-by-bin normalization
 *  @param inputWorkspace The input workspace
 *  @param outputWorkspace The result workspace
 */
void NormaliseToMonitor::normaliseBinByBin(
    const API::MatrixWorkspace_sptr &inputWorkspace,
    API::MatrixWorkspace_sptr &outputWorkspace) {
  EventWorkspace_sptr inputEvent =
      boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);

  // Only create output workspace if different to input one
  if (outputWorkspace != inputWorkspace) {
    if (inputEvent) {
      outputWorkspace = inputWorkspace->clone();
    } else
      outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace);
  }
  auto outputEvent =
      boost::dynamic_pointer_cast<EventWorkspace>(outputWorkspace);

  // Get hold of the monitor spectrum
  const auto &monX = m_monitor->binEdges(0);
  auto monY = m_monitor->counts(0);
  auto monE = m_monitor->countStandardDeviations(0);
  // Calculate the overall normalization just the once if bins are all matching
  if (m_commonBins)
    this->normalisationFactor(monX, monY, monE);

  const size_t numHists = inputWorkspace->getNumberHistograms();
  auto specLength = inputWorkspace->blocksize();
  // Flag set when a division by 0 is found
  bool hasZeroDivision = false;
  Progress prog(this, 0.0, 1.0, numHists);
  // Loop over spectra
  PARALLEL_FOR_IF(
      Kernel::threadSafe(*inputWorkspace, *outputWorkspace, *m_monitor))
  for (int64_t i = 0; i < int64_t(numHists); ++i) {
    PARALLEL_START_INTERUPT_REGION
    prog.report();

    const auto &X = inputWorkspace->binEdges(i);
    // If not rebinning, just point to our monitor spectra, otherwise create new
    // vectors

    auto Y = (m_commonBins ? monY : Counts(specLength));
    auto E = (m_commonBins ? monE : CountStandardDeviations(specLength));

    if (!m_commonBins) {
      // ConvertUnits can give X vectors of all zeros - skip these, they cause
      // problems
      if (X.back() == 0.0 && X.front() == 0.0)
        continue;
      // Rebin the monitor spectrum to match the binning of the current data
      // spectrum
      VectorHelper::rebinHistogram(
          monX.rawData(), monY.mutableRawData(), monE.mutableRawData(),
          X.rawData(), Y.mutableRawData(), E.mutableRawData(), false);
      // Recalculate the overall normalization factor
      this->normalisationFactor(X, Y, E);
    }

    if (inputEvent) {
      // ----------------------------------- EventWorkspace
      // ---------------------------------------
      EventList &outEL = outputEvent->getSpectrum(i);
      outEL.divide(X.rawData(), Y.mutableRawData(), E.mutableRawData());
    } else {
      // ----------------------------------- Workspace2D
      // ---------------------------------------
      auto &YOut = outputWorkspace->mutableY(i);
      auto &EOut = outputWorkspace->mutableE(i);
      const auto &inY = inputWorkspace->y(i);
      const auto &inE = inputWorkspace->e(i);
      outputWorkspace->mutableX(i) = inputWorkspace->x(i);

      // The code below comes more or less straight out of Divide.cpp
      for (size_t k = 0; k < specLength; ++k) {
        // Get the input Y's
        const double leftY = inY[k];
        const double rightY = Y[k];

        if (rightY == 0.0) {
          hasZeroDivision = true;
        }

        // Calculate result and store in local variable to avoid overwriting
        // original data if
        // output workspace is same as one of the input ones
        const double newY = leftY / rightY;

        if (fabs(rightY) > 1.0e-12 && fabs(newY) > 1.0e-12) {
          const double lhsFactor = (inE[k] < 1.0e-12 || fabs(leftY) < 1.0e-12)
                                       ? 0.0
                                       : pow((inE[k] / leftY), 2);
          const double rhsFactor =
              E[k] < 1.0e-12 ? 0.0 : pow((E[k] / rightY), 2);
          EOut[k] = std::abs(newY) * sqrt(lhsFactor + rhsFactor);
        }

        // Now store the result
        YOut[k] = newY;
      } // end Workspace2D case
    }   // end loop over current spectrum

    PARALLEL_END_INTERUPT_REGION
  } // end loop over spectra
  PARALLEL_CHECK_INTERUPT_REGION
  if (hasZeroDivision) {
    g_log.warning() << "Division by zero in some of the bins.\n";
  }
}
Beispiel #16
0
std::vector<std::vector<size_t>>
DetectorDiagnostic::makeInstrumentMap(API::MatrixWorkspace_sptr countsWS) {
  return {
      {boost::counting_iterator<std::size_t>(0),
       boost::counting_iterator<std::size_t>(countsWS->getNumberHistograms())}};
}
/** Forms the quadrature phase signal (squashogram)
 * @param ws :: [input] workspace containing the measured spectra
 * @param phase :: [input] table workspace containing the detector phases
 * @param n0 :: [input] vector containing the normalization constants
 * @return :: workspace containing the quadrature phase signal
 */
API::MatrixWorkspace_sptr
PhaseQuadMuon::squash(const API::MatrixWorkspace_sptr &ws,
                      const API::ITableWorkspace_sptr &phase,
                      const std::vector<double> &n0) {

  // Poisson limit: below this number we consider we don't have enough
  // statistics
  // to apply sqrt(N). This is an arbitrary number used in the original code
  // provided by scientists
  const double poissonLimit = 30.;

  // Muon life time in microseconds
  const double muLife = PhysicalConstants::MuonLifetime * 1e6;

  const size_t nspec = ws->getNumberHistograms();

  if (n0.size() != nspec) {
    throw std::invalid_argument("Invalid normalization constants");
  }

  auto names = phase->getColumnNames();
  for (auto &name : names) {
    std::transform(name.begin(), name.end(), name.begin(), ::tolower);
  }
  auto phaseIndex = findName(phaseNames, names);
  auto asymmetryIndex = findName(asymmNames, names);

  // Get the maximum asymmetry
  double maxAsym = 0.;
  for (size_t h = 0; h < nspec; h++) {
    if (phase->Double(h, asymmetryIndex) > maxAsym &&
        phase->Double(h, asymmetryIndex) != ASYMM_ERROR) {
      maxAsym = phase->Double(h, asymmetryIndex);
    }
  }

  if (maxAsym == 0.0) {
    throw std::invalid_argument("Invalid detector asymmetries");
  }
  std::vector<bool> emptySpectrum;
  emptySpectrum.reserve(nspec);
  std::vector<double> aj, bj;
  {
    // Calculate coefficients aj, bj

    double sxx = 0.;
    double syy = 0.;
    double sxy = 0.;
    for (size_t h = 0; h < nspec; h++) {
      emptySpectrum.push_back(
          std::all_of(ws->y(h).begin(), ws->y(h).end(),
                      [](double value) { return value == 0.; }));
      if (!emptySpectrum[h]) {
        const double asym = phase->Double(h, asymmetryIndex) / maxAsym;
        const double phi = phase->Double(h, phaseIndex);
        const double X = n0[h] * asym * cos(phi);
        const double Y = n0[h] * asym * sin(phi);
        sxx += X * X;
        syy += Y * Y;
        sxy += X * Y;
      }
    }

    const double lam1 = 2 * syy / (sxx * syy - sxy * sxy);
    const double mu1 = 2 * sxy / (sxy * sxy - sxx * syy);
    const double lam2 = 2 * sxy / (sxy * sxy - sxx * syy);
    const double mu2 = 2 * sxx / (sxx * syy - sxy * sxy);
    for (size_t h = 0; h < nspec; h++) {
      if (emptySpectrum[h]) {
        aj.push_back(0.0);
        bj.push_back(0.0);
      } else {
        const double asym = phase->Double(h, asymmetryIndex) / maxAsym;
        const double phi = phase->Double(h, phaseIndex);
        const double X = n0[h] * asym * cos(phi);
        const double Y = n0[h] * asym * sin(phi);
        aj.push_back((lam1 * X + mu1 * Y) * 0.5);
        bj.push_back((lam2 * X + mu2 * Y) * 0.5);
      }
    }
  }

  const size_t npoints = ws->blocksize();
  // Create and populate output workspace
  API::MatrixWorkspace_sptr ows =
      API::WorkspaceFactory::Instance().create(ws, 2, npoints + 1, npoints);

  // X
  ows->setSharedX(0, ws->sharedX(0));
  ows->setSharedX(1, ws->sharedX(0));

  // Phase quadrature
  auto &realY = ows->mutableY(0);
  auto &imagY = ows->mutableY(1);
  auto &realE = ows->mutableE(0);
  auto &imagE = ows->mutableE(1);

  const auto xPointData = ws->histogram(0).points();
  // First X value
  const double X0 = xPointData.front();

  // calculate exponential decay outside of the loop
  std::vector<double> expDecay = xPointData.rawData();
  std::transform(expDecay.begin(), expDecay.end(), expDecay.begin(),
                 [X0, muLife](double x) { return exp(-(x - X0) / muLife); });

  for (size_t i = 0; i < npoints; i++) {
    for (size_t h = 0; h < nspec; h++) {
      if (!emptySpectrum[h]) {
        // (X,Y,E) with exponential decay removed
        const double X = ws->x(h)[i];
        const double exponential = n0[h] * exp(-(X - X0) / muLife);
        const double Y = ws->y(h)[i] - exponential;
        const double E =
            (ws->y(h)[i] > poissonLimit) ? ws->e(h)[i] : sqrt(exponential);

        realY[i] += aj[h] * Y;
        imagY[i] += bj[h] * Y;
        realE[i] += aj[h] * aj[h] * E * E;
        imagE[i] += bj[h] * bj[h] * E * E;
      }
    }
    realE[i] = sqrt(realE[i]);
    imagE[i] = sqrt(imagE[i]);

    // Regain exponential decay
    realY[i] /= expDecay[i];
    imagY[i] /= expDecay[i];
    realE[i] /= expDecay[i];
    imagE[i] /= expDecay[i];
  }

  // New Y axis label
  ows->setYUnit("Asymmetry");

  return ows;
}
/** Fits each spectrum in the workspace to f(x) = A * sin( w * x + p)
 * @param ws :: [input] The workspace to fit
 * @param freq :: [input] Hint for the frequency (w)
 * @param groupName :: [input] The name of the output workspace group
 * @param resTab :: [output] Table workspace storing the asymmetries and phases
 * @param resGroup :: [output] Workspace group storing the fitting results
 */
void CalMuonDetectorPhases::fitWorkspace(const API::MatrixWorkspace_sptr &ws,
                                         double freq, std::string groupName,
                                         API::ITableWorkspace_sptr resTab,
                                         API::WorkspaceGroup_sptr &resGroup) {

  int nhist = static_cast<int>(ws->getNumberHistograms());

  // Create the fitting function f(x) = A * sin ( w * x + p )
  // The same function and initial parameters are used for each fit
  std::string funcStr = createFittingFunction(freq, true);

  // Set up results table
  resTab->addColumn("int", "Spectrum number");
  resTab->addColumn("double", "Asymmetry");
  resTab->addColumn("double", "Phase");

  const auto &indexInfo = ws->indexInfo();

  // Loop through fitting all spectra individually
  const static std::string success = "success";
  for (int wsIndex = 0; wsIndex < nhist; wsIndex++) {
    reportProgress(wsIndex, nhist);
    const auto &yValues = ws->y(wsIndex);
    auto emptySpectrum = std::all_of(yValues.begin(), yValues.end(),
                                     [](double value) { return value == 0.; });
    if (emptySpectrum) {
      g_log.warning("Spectrum " + std::to_string(wsIndex) + " is empty");
      TableWorkspace_sptr tab = boost::make_shared<TableWorkspace>();
      tab->addColumn("str", "Name");
      tab->addColumn("double", "Value");
      tab->addColumn("double", "Error");
      for (int j = 0; j < 4; j++) {
        API::TableRow row = tab->appendRow();
        if (j == PHASE_ROW) {
          row << "dummy" << 0.0 << 0.0;
        } else {
          row << "dummy" << ASYMM_ERROR << 0.0;
        }
      }

      extractDetectorInfo(*tab, *resTab, indexInfo.spectrumNumber(wsIndex));

    } else {
      auto fit = createChildAlgorithm("Fit");
      fit->initialize();
      fit->setPropertyValue("Function", funcStr);
      fit->setProperty("InputWorkspace", ws);
      fit->setProperty("WorkspaceIndex", wsIndex);
      fit->setProperty("CreateOutput", true);
      fit->setPropertyValue("Output", groupName);
      fit->execute();

      std::string status = fit->getProperty("OutputStatus");
      if (!fit->isExecuted()) {
        std::ostringstream error;
        error << "Fit failed for spectrum at workspace index " << wsIndex;
        error << ": " << status;
        throw std::runtime_error(error.str());
      } else if (status != success) {
        g_log.warning("Fit failed for spectrum at workspace index " +
                      std::to_string(wsIndex) + ": " + status);
      }

      API::MatrixWorkspace_sptr fitOut = fit->getProperty("OutputWorkspace");
      resGroup->addWorkspace(fitOut);
      API::ITableWorkspace_sptr tab = fit->getProperty("OutputParameters");
      // Now we have our fitting results stored in tab
      // but we need to extract the relevant information, i.e.
      // the detector phases (parameter 'p') and asymmetries ('A')
      extractDetectorInfo(*tab, *resTab, indexInfo.spectrumNumber(wsIndex));
    }
  }
}
Beispiel #19
0
API::MatrixWorkspace_sptr
CreateFloodWorkspace::removeBackground(API::MatrixWorkspace_sptr ws) {
  g_log.information() << "Remove background "
                      << getPropertyValue(Prop::BACKGROUND) << '\n';
  auto fitWS = transpose(ws);
  auto const &x = fitWS->x(0);

  // Define the fitting interval
  double startX = getProperty(Prop::START_X);
  double endX = getProperty(Prop::END_X);
  std::vector<double> excludeFromFit;
  if (isDefault(Prop::START_X)) {
    startX = x.front();
  } else {
    excludeFromFit.push_back(x.front());
    excludeFromFit.push_back(startX);
  }
  if (isDefault(Prop::END_X)) {
    endX = x.back();
  } else {
    excludeFromFit.push_back(endX);
    excludeFromFit.push_back(x.back());
  }

  // Exclude any bad detectors.
  for (auto i : m_excludedSpectra) {
    excludeFromFit.push_back(i);
    excludeFromFit.push_back(i);
  }

  std::string const function = getBackgroundFunction();

  // Fit the data to determine unwanted background
  auto alg = createChildAlgorithm("Fit", 0.9, 0.99);
  alg->setProperty("Function", function);
  alg->setProperty("InputWorkspace", fitWS);
  alg->setProperty("WorkspaceIndex", 0);
  if (!excludeFromFit.empty()) {
    alg->setProperty("Exclude", excludeFromFit);
  }
  alg->setProperty("Output", "fit");
  alg->execute();

  IFunction_sptr func = alg->getProperty("Function");
  g_log.information() << "Background function parameters:\n";
  for (size_t i = 0; i < func->nParams(); ++i) {
    g_log.information() << "    " << func->parameterName(i) << ": "
                        << func->getParameter(i) << '\n';
  }

  // Divide the workspace by the fitted curve to remove the background
  // and scale to values around 1
  MatrixWorkspace_sptr bkgWS = alg->getProperty("OutputWorkspace");
  auto const &bkg = bkgWS->y(1);
  auto const nHisto = static_cast<int>(ws->getNumberHistograms());
  PARALLEL_FOR_IF(Kernel::threadSafe(*ws, *bkgWS))
  for (int i = 0; i < nHisto; ++i) {
    PARALLEL_START_INTERUPT_REGION
    auto const xVal = x[i];
    if (isExcludedSpectrum(xVal)) {
      ws->mutableY(i)[0] = VERY_BIG_VALUE;
      ws->mutableE(i)[0] = 0.0;
    } else if (xVal >= startX && xVal <= endX) {
      auto const background = bkg[i];
      if (background <= 0.0) {
        throw std::runtime_error(
            "Background is expected to be positive, found value " +
            std::to_string(background) + " at spectrum with workspace index " +
            std::to_string(i));
      }
      ws->mutableY(i)[0] /= background;
      ws->mutableE(i)[0] /= background;
    } else {
      ws->mutableY(i)[0] = 1.0;
      ws->mutableE(i)[0] = 0.0;
    }
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

  // Remove the logs
  ws->setSharedRun(make_cow<Run>());

  return ws;
}
Beispiel #20
0
/** Forms the quadrature phase signal (squashogram)
* @param ws :: [input] workspace containing the measured spectra
* @param phase :: [input] table workspace containing the detector phases
* @param n0 :: [input] vector containing the normalization constants
* @return :: workspace containing the quadrature phase signal
*/
API::MatrixWorkspace_sptr
PhaseQuadMuon::squash(const API::MatrixWorkspace_sptr &ws,
                      const API::ITableWorkspace_sptr &phase,
                      const std::vector<double> &n0) {

  // Poisson limit: below this number we consider we don't have enough
  // statistics
  // to apply sqrt(N). This is an arbitrary number used in the original code
  // provided by scientists
  double poissonLimit = 30.;

  size_t nspec = ws->getNumberHistograms();
  size_t npoints = ws->blocksize();

  // Muon life time in microseconds
  double muLife = PhysicalConstants::MuonLifetime * 1e6;

  if (n0.size() != nspec) {
    throw std::invalid_argument("Invalid normalization constants");
  }

  // Get the maximum asymmetry
  double maxAsym = 0.;
  for (size_t h = 0; h < nspec; h++) {
    if (phase->Double(h, 1) > maxAsym) {
      maxAsym = phase->Double(h, 1);
    }
  }
  if (maxAsym == 0.0) {
    throw std::invalid_argument("Invalid detector asymmetries");
  }

  std::vector<double> aj, bj;
  {
    // Calculate coefficients aj, bj

    double sxx = 0;
    double syy = 0;
    double sxy = 0;

    for (size_t h = 0; h < nspec; h++) {
      double asym = phase->Double(h, 1) / maxAsym;
      double phi = phase->Double(h, 2);
      double X = n0[h] * asym * cos(phi);
      double Y = n0[h] * asym * sin(phi);
      sxx += X * X;
      syy += Y * Y;
      sxy += X * Y;
    }

    double lam1 = 2 * syy / (sxx * syy - sxy * sxy);
    double mu1 = 2 * sxy / (sxy * sxy - sxx * syy);
    double lam2 = 2 * sxy / (sxy * sxy - sxx * syy);
    double mu2 = 2 * sxx / (sxx * syy - sxy * sxy);
    for (size_t h = 0; h < nspec; h++) {
      double asym = phase->Double(h, 1) / maxAsym;
      double phi = phase->Double(h, 2);
      double X = n0[h] * asym * cos(phi);
      double Y = n0[h] * asym * sin(phi);
      aj.push_back((lam1 * X + mu1 * Y) * 0.5);
      bj.push_back((lam2 * X + mu2 * Y) * 0.5);
    }
  }

  // First X value
  double X0 = ws->x(0).front();

  // Create and populate output workspace
  API::MatrixWorkspace_sptr ows = API::WorkspaceFactory::Instance().create(
      "Workspace2D", 2, npoints + 1, npoints);

  // X
  ows->setSharedX(0, ws->sharedX(0));
  ows->setSharedX(1, ws->sharedX(0));

  // Phase quadrature
  auto &realY = ows->mutableY(0);
  auto &imagY = ows->mutableY(1);
  auto &realE = ows->mutableE(0);
  auto &imagE = ows->mutableE(1);

  for (size_t i = 0; i < npoints; i++) {
    for (size_t h = 0; h < nspec; h++) {

      // (X,Y,E) with exponential decay removed
      const double X = ws->x(h)[i];
      const double Y = ws->y(h)[i] - n0[h] * exp(-(X - X0) / muLife);
      const double E = (ws->y(h)[i] > poissonLimit)
                           ? ws->e(h)[i]
                           : sqrt(n0[h] * exp(-(X - X0) / muLife));

      realY[i] += aj[h] * Y;
      imagY[i] += bj[h] * Y;
      realE[i] += aj[h] * aj[h] * E * E;
      imagE[i] += bj[h] * bj[h] * E * E;
    }
    realE[i] = sqrt(realE[i]);
    imagE[i] = sqrt(imagE[i]);

    // Regain exponential decay
    const double X = ws->getSpectrum(0).x()[i];
    const double e = exp(-(X - X0) / muLife);
    realY[i] /= e;
    imagY[i] /= e;
    realE[i] /= e;
    imagE[i] /= e;
  }

  return ows;
}
Beispiel #21
0
/**
 * Validation of the inputs of the RingProfile algorithm.
 *
 * Inside this method, the Workspace is considered an instrument based
 *instrument. Each spectrum
 * has a detector associated which has a position in the 3D space.
 *
 * The main validation are:
 *  - the centre of the ring is inside the image it self.
 *  - The minimum ring is smaller than the limits of the image to allow
 *
 * @param inputWS: the input workspace
*/
void RingProfile::checkInputsForSpectraWorkspace(
    const API::MatrixWorkspace_sptr inputWS) {
  try {
    // finding the limits of the instrument
    double first_x, first_y, first_z;
    size_t i = 0;
    while (true) {
      i++;
      if (i >= inputWS->getNumberHistograms())
        throw std::invalid_argument(
            "Did not find any non monitor detector position");

      auto det = inputWS->getDetector(i);
      if (det->isMonitor())
        continue;
      first_x = det->getPos().X();
      first_y = det->getPos().Y();
      first_z = det->getPos().Z();
      break;
    }

    double last_x, last_y, last_z;
    i = inputWS->getNumberHistograms() - 1;
    while (true) {
      i--;
      if (i == 0)
        throw std::invalid_argument(
            "There is no region defined for the instrument of this workspace");

      auto det = inputWS->getDetector(i);
      if (det->isMonitor())
        continue;
      last_x = det->getPos().X();
      last_y = det->getPos().Y();
      last_z = det->getPos().Z();
      break;
    }

    double xMax, yMax, zMax;
    double xMin, yMin, zMin;
    xMax = std::max(first_x, last_x);
    yMax = std::max(first_y, last_y);
    zMax = std::max(first_z, last_z);
    xMin = std::min(first_x, last_x);
    yMin = std::min(first_y, last_y);
    zMin = std::min(first_z, last_z);

    std::stringstream limits_s;
    limits_s << "([" << xMin << ", " << xMax << "], [" << yMin << ", " << yMax
             << "], [" << zMin << ", " << zMax << "])";
    g_log.debug() << "The limits for the instrument is : " << limits_s.str()
                  << std::endl;
    int xOutside = 0, yOutside = 0, zOutside = 0;
    if (centre_x < xMin || centre_x > xMax)
      xOutside = 1;
    if (centre_y < yMin || centre_y > yMax)
      yOutside = 1;
    if (centre_z < zMin || centre_z > zMax)
      zOutside = 1;
    int summed = xOutside + yOutside + zOutside;
    // if at least 2 are outside, the centre is considered outside the box.
    if (summed >= 2) {
      std::stringstream s;
      s << "The defined centre (" << centre_x << ", " << centre_y << ", "
        << centre_z
        << ") is outside the limits of the detectors inside this instrument: "
        << limits_s.str();
      throw std::invalid_argument(s.str());
    }

    xOutside = yOutside = zOutside = 0;
    if (centre_x - min_radius > xMax || centre_x + min_radius < xMin)
      xOutside = 1;
    if (centre_y - min_radius > yMax || centre_y + min_radius < yMin)
      yOutside = 1;
    if (centre_z - min_radius > zMax || centre_z + min_radius < zMin)
      zOutside = 1;

    summed = xOutside + yOutside + zOutside;

    if (summed >= 2) {
      std::stringstream s;
      s << "The defined minRadius make the inner ring outside the limits of "
           "the detectors inside this instrument: " << limits_s.str();
      throw std::invalid_argument(s.str());
    }

  } catch (Kernel::Exception::NotFoundError &) {
    throw std::invalid_argument("Invalid input workspace. This workspace does "
                                "not has detectors to get the positions "
                                "from. ");
  }
}
Beispiel #22
0
/** Assuming that the workspace has an instrument associated with it from which
 *the pixel positions has to be taken,
 *  this function extracts the position of the first and last valid pixel
 *(detector) and return a list of values
 *  giving the boundaries of the instrument.
 *
 * @param inWS Input Workspace
 * @return a list of values that defines the limits of the image in this order:
 *Xmin, Xmax, Ymin, Ymax, Zmin, Zmax
 */
std::vector<double>
RadiusSum::getBoundariesOfInstrument(API::MatrixWorkspace_sptr inWS) {

  // This function is implemented based in the following assumption:
  //   - The workspace is composed by spectrum with associated spectrum No which
  //   is associated to one detector or monitor
  //   - The first spectrum No (non monitor) is associated with one detector
  //   while the last spectrum No (non monitor)
  //     is associated with one detector.
  //   - They are in complete oposite direction.
  //
  //   Consider the following 'image' (where the ID is the number and the
  //   position is where it is displayed)
  //
  //    1  2  3
  //    4  5  6
  //    7  8  9
  //   10 11 12
  //
  //    In this image, the assumption is true, because, we can derive the
  //    boundaries of the image looking just to the
  //    ids 1 and 12.
  //
  //    But the following image:
  //
  //   1  2  3       6  5  4
  //   6  5  4       1  2  3
  //   7  8  9      12 11 10
  //  12 11 12       7  8  9
  //
  //   Although valid 'IDF' instrument, fail the assumption, and will return
  //   wrong values.
  //   Bear in mind these words if you face problems with the return of the
  //   boundaries of one instrument
  //

  double first_x, first_y, first_z;
  size_t i = 0;
  while (true) {
    i++;
    if (i >= inWS->getNumberHistograms())
      throw std::invalid_argument("Did not find any non monitor detector. "
                                  "Failed to identify the boundaries of this "
                                  "instrument.");

    auto det = inWS->getDetector(i);
    if (det->isMonitor())
      continue;
    // get the position of the first valid (non-monitor) detector.
    first_x = det->getPos().X();
    first_y = det->getPos().Y();
    first_z = det->getPos().Z();
    break;
  }

  double last_x, last_y, last_z;
  i = inWS->getNumberHistograms() - 1;
  while (true) {
    i--;
    if (i == 0)
      throw std::invalid_argument("There is no region defined for the "
                                  "instrument of this workspace. Failed to "
                                  "identify the boundaries of this instrument");

    auto det = inWS->getDetector(i);
    if (det->isMonitor())
      continue;
    // get the last valid detector position
    last_x = det->getPos().X();
    last_y = det->getPos().Y();
    last_z = det->getPos().Z();
    break;
  }

  // order the values
  double xMax, yMax, zMax;
  double xMin, yMin, zMin;
  xMax = std::max(first_x, last_x);
  yMax = std::max(first_y, last_y);
  zMax = std::max(first_z, last_z);
  xMin = std::min(first_x, last_x);
  yMin = std::min(first_y, last_y);
  zMin = std::min(first_z, last_z);

  std::vector<double> output(6); // output  = {xMin, xMax, yMin, yMax, zMin,
                                 // zMax }; not supported in all compilers
  output[0] = xMin;
  output[1] = xMax;
  output[2] = yMin;
  output[3] = yMax;
  output[4] = zMin;
  output[5] = zMax;

  return output;
}
Beispiel #23
0
/** Carries out the bin-by-bin normalisation
 *  @param inputWorkspace The input workspace
 *  @param outputWorkspace The result workspace
 */
void NormaliseToMonitor::normaliseBinByBin(API::MatrixWorkspace_sptr inputWorkspace,
                                           API::MatrixWorkspace_sptr& outputWorkspace)
{ 
  EventWorkspace_sptr inputEvent = boost::dynamic_pointer_cast<EventWorkspace>(inputWorkspace);
  EventWorkspace_sptr outputEvent;

  // Only create output workspace if different to input one
  if (outputWorkspace != inputWorkspace )
  {
    if (inputEvent)
    {
      //Make a brand new EventWorkspace
      outputEvent = boost::dynamic_pointer_cast<EventWorkspace>(
          API::WorkspaceFactory::Instance().create("EventWorkspace", inputEvent->getNumberHistograms(), 2, 1));
      //Copy geometry and data
      API::WorkspaceFactory::Instance().initializeFromParent(inputEvent, outputEvent, false);
      outputEvent->copyDataFrom( (*inputEvent) );
      outputWorkspace = boost::dynamic_pointer_cast<MatrixWorkspace>(outputEvent);
    }
    else
      outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace);
  }

  // Get hold of the monitor spectrum
  const MantidVec& monX = m_monitor->readX(0);
  MantidVec& monY = m_monitor->dataY(0);
  MantidVec& monE = m_monitor->dataE(0);
  // Calculate the overall normalisation just the once if bins are all matching
  if (m_commonBins) this->normalisationFactor(m_monitor->readX(0),&monY,&monE);


  const size_t numHists = inputWorkspace->getNumberHistograms();
  MantidVec::size_type specLength = inputWorkspace->blocksize();
  Progress prog(this,0.0,1.0,numHists);
  // Loop over spectra
  PARALLEL_FOR3(inputWorkspace,outputWorkspace,m_monitor)
  for (int64_t i = 0; i < int64_t(numHists); ++i)
  {
    PARALLEL_START_INTERUPT_REGION
    prog.report();

    const MantidVec& X = inputWorkspace->readX(i);
    // If not rebinning, just point to our monitor spectra, otherwise create new vectors
    MantidVec* Y = ( m_commonBins ? &monY : new MantidVec(specLength) );
    MantidVec* E = ( m_commonBins ? &monE : new MantidVec(specLength) );

    if (!m_commonBins)
    {
      // ConvertUnits can give X vectors of all zeroes - skip these, they cause problems
      if (X.back() == 0.0 && X.front() == 0.0) continue;
      // Rebin the monitor spectrum to match the binning of the current data spectrum
      VectorHelper::rebinHistogram(monX,monY,monE,X,*Y,*E,false);
      // Recalculate the overall normalisation factor
      this->normalisationFactor(X,Y,E);
    }

    if (inputEvent)
    {
      // ----------------------------------- EventWorkspace ---------------------------------------
      EventList & outEL = outputEvent->getEventList(i);
      outEL.divide(X, *Y, *E);
    }
    else
    {
      // ----------------------------------- Workspace2D ---------------------------------------
      const MantidVec& inY = inputWorkspace->readY(i);
      const MantidVec& inE = inputWorkspace->readE(i);
      MantidVec& YOut = outputWorkspace->dataY(i);
      MantidVec& EOut = outputWorkspace->dataE(i);
      outputWorkspace->dataX(i) = inputWorkspace->readX(i);
      // The code below comes more or less straight out of Divide.cpp
      for (MantidVec::size_type k = 0; k < specLength; ++k)
      {
        // Get references to the input Y's
        const double& leftY = inY[k];
        const double& rightY = (*Y)[k];

        // Calculate result and store in local variable to avoid overwriting original data if
        // output workspace is same as one of the input ones
        const double newY = leftY/rightY;

        if (fabs(rightY)>1.0e-12 && fabs(newY)>1.0e-12)
        {
          const double lhsFactor = (inE[k]<1.0e-12|| fabs(leftY)<1.0e-12) ? 0.0 : pow((inE[k]/leftY),2);
          const double rhsFactor = (*E)[k]<1.0e-12 ? 0.0 : pow(((*E)[k]/rightY),2);
          EOut[k] = std::abs(newY) * sqrt(lhsFactor+rhsFactor);
        }

        // Now store the result
        YOut[k] = newY;
      } // end Workspace2D case
    } // end loop over current spectrum

    if (!m_commonBins) { delete Y; delete E; }
    PARALLEL_END_INTERUPT_REGION
  } // end loop over spectra
  PARALLEL_CHECK_INTERUPT_REGION
}
Beispiel #24
0
/** Executes the algorithm
 *
 *  @throw Exception::FileError If the grouping file cannot be opened or read successfully
 *  @throw runtime_error If unable to run one of the sub-algorithms successfully
 */
void DiffractionFocussing::exec()
{
  // retrieve the properties
  std::string groupingFileName=getProperty("GroupingFileName");

  // Get the input workspace
  MatrixWorkspace_sptr inputW = getProperty("InputWorkspace");

  bool dist = inputW->isDistribution();

  //do this first to check that a valid file is available before doing any work
  std::multimap<int64_t,int64_t> detectorGroups;// <group, UDET>
  if (!readGroupingFile(groupingFileName, detectorGroups))
  {
    throw Exception::FileError("Error reading .cal file",groupingFileName);
  }

  //Convert to d-spacing units
  API::MatrixWorkspace_sptr tmpW = convertUnitsToDSpacing(inputW);

  //Rebin to a common set of bins
  RebinWorkspace(tmpW);

  std::set<int64_t> groupNumbers;
  for(std::multimap<int64_t,int64_t>::const_iterator d = detectorGroups.begin();d!=detectorGroups.end();d++)
  {
    if (groupNumbers.find(d->first) == groupNumbers.end())
    {
      groupNumbers.insert(d->first);
    }
  }

  int iprogress = 0;
  int iprogress_count = static_cast<int>(groupNumbers.size());
  int iprogress_step = iprogress_count / 100;
  if (iprogress_step == 0) iprogress_step = 1;
  std::vector<int64_t> resultIndeces;
  for(std::set<int64_t>::const_iterator g = groupNumbers.begin();g!=groupNumbers.end();g++)
  {
    if (iprogress++ % iprogress_step == 0)
    {
      progress(0.68 + double(iprogress)/iprogress_count/3);
    }
    std::multimap<int64_t,int64_t>::const_iterator from = detectorGroups.lower_bound(*g);
    std::multimap<int64_t,int64_t>::const_iterator to =   detectorGroups.upper_bound(*g);
    std::vector<detid_t> detectorList;
    for(std::multimap<int64_t,int64_t>::const_iterator d = from;d!=to;d++)
      detectorList.push_back(static_cast<detid_t>(d->second));
    // Want version 1 of GroupDetectors here
    API::IAlgorithm_sptr childAlg = createSubAlgorithm("GroupDetectors",-1.0,-1.0,true,1);
    childAlg->setProperty("Workspace", tmpW);
    childAlg->setProperty< std::vector<detid_t> >("DetectorList",detectorList);
    childAlg->executeAsSubAlg();
    try
    {
      // get the index of the combined spectrum
      int ri = childAlg->getProperty("ResultIndex");
      if (ri >= 0)
      {
        resultIndeces.push_back(ri);
      }
    }
    catch(...)
    {
      throw std::runtime_error("Unable to get Properties from GroupDetectors sub-algorithm");
    }
  }

  // Discard left-over spectra, but print warning message giving number discarded
  int discarded = 0;
  const int64_t oldHistNumber = tmpW->getNumberHistograms();
  API::Axis *spectraAxis = tmpW->getAxis(1);
  for(int64_t i=0; i < oldHistNumber; i++)
    if ( spectraAxis->spectraNo(i) >= 0 && find(resultIndeces.begin(),resultIndeces.end(),i) == resultIndeces.end())
    {
      ++discarded;
    }
  g_log.warning() << "Discarded " << discarded << " spectra that were not assigned to any group" << std::endl;

  // Running GroupDetectors leads to a load of redundant spectra
  // Create a new workspace that's the right size for the meaningful spectra and copy them in
  int64_t newSize = tmpW->blocksize();
  API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(tmpW,resultIndeces.size(),newSize+1,newSize);
  // Copy units
  outputW->getAxis(0)->unit() = tmpW->getAxis(0)->unit();
  outputW->getAxis(1)->unit() = tmpW->getAxis(1)->unit();

  API::Axis *spectraAxisNew = outputW->getAxis(1);

  for(int64_t hist=0; hist < static_cast<int64_t>(resultIndeces.size()); hist++)
  {
    int64_t i = resultIndeces[hist];
    double spNo = static_cast<double>(spectraAxis->spectraNo(i));
    MantidVec &tmpE = tmpW->dataE(i);
    MantidVec &outE = outputW->dataE(hist);
    MantidVec &tmpY = tmpW->dataY(i);
    MantidVec &outY = outputW->dataY(hist);
    MantidVec &tmpX = tmpW->dataX(i);
    MantidVec &outX = outputW->dataX(hist);
    outE.assign(tmpE.begin(),tmpE.end());
    outY.assign(tmpY.begin(),tmpY.end());
    outX.assign(tmpX.begin(),tmpX.end());
    spectraAxisNew->setValue(hist,spNo);
    spectraAxis->setValue(i,-1);
  }

  progress(1.);

  outputW->isDistribution(dist);

  // Assign it to the output workspace property
  setProperty("OutputWorkspace",outputW);

  return;
}