Example #1
0
 /**
  * Search each spectrum for y-values that are less than zero and reset
  * them to the supplied value.
  *
  * @param minWS A workspace of minimum values for each spectra.
  * @param value Reset negative values in the spectra to this number.
  * @param wksp The workspace to modify.
  * @param prog The progress.
  */
 void ResetNegatives::changeNegatives(MatrixWorkspace_const_sptr minWS, const double value, MatrixWorkspace_sptr wksp,
                                      Progress &prog)
 {
   int64_t nHist = wksp->getNumberHistograms();
   PARALLEL_FOR2(minWS, wksp)
   for (int64_t i = 0; i < nHist; i++)
   {
     PARALLEL_START_INTERUPT_REGION
     if (minWS->readY(i)[0] <= 0.) // quick check to see if there is a reason to bother
     {
       MantidVec & y = wksp->dataY(i);
       for (MantidVec::iterator it = y.begin(); it != y.end(); ++it)
       {
           if (*it < 0.) {
             *it = value;
           }
         else
           *it = fixZero(*it);
       }
     }
     prog.report();
     PARALLEL_END_INTERUPT_REGION
   }
   PARALLEL_CHECK_INTERUPT_REGION
 }
Example #2
0
/** Executes the algorithm
 */
void MultiplyRange::exec()
{
  // Get the input workspace and other properties
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  m_startBin = getProperty("StartBin");
  m_endBin = getProperty("EndBin");
  m_factor = getProperty("Factor");

  // A few checks on the input properties
  const int specSize = static_cast<int>(inputWS->blocksize());
  if ( isEmpty(m_endBin) ) m_endBin = specSize - 1;

  if ( m_endBin >= specSize )
  {
    g_log.error("EndBin out of range!");
    throw std::out_of_range("EndBin out of range!");
  }
  if ( m_endBin < m_startBin )
  {
    g_log.error("StartBin must be less than or equal to EndBin");
    throw std::out_of_range("StartBin must be less than or equal to EndBin");
  }

  // Only create the output workspace if it's different to the input one
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  if ( outputWS != inputWS )
  {
    outputWS = WorkspaceFactory::Instance().create(inputWS);
    setProperty("OutputWorkspace",outputWS);
  }

  // Get the count of histograms in the input workspace
  const int histogramCount = static_cast<int>(inputWS->getNumberHistograms());
  Progress progress(this,0.0,1.0,histogramCount);
  // Loop over spectra
  PARALLEL_FOR2(inputWS,outputWS)
  for (int i = 0; i < histogramCount; ++i)
  {
    PARALLEL_START_INTERUPT_REGION
    // Copy over the bin boundaries
    outputWS->setX(i,inputWS->refX(i));
    // Copy over the data
    outputWS->dataY(i) = inputWS->readY(i);
    outputWS->dataE(i) = inputWS->readE(i);
    MantidVec& newY = outputWS->dataY(i);
    MantidVec& newE = outputWS->dataE(i);

    // Now multiply the requested range
    std::transform(newY.begin()+m_startBin,newY.begin()+m_endBin+1,newY.begin()+m_startBin,
                     std::bind2nd(std::multiplies<double>(),m_factor));
    std::transform(newE.begin()+m_startBin,newE.begin()+m_endBin+1,newE.begin()+m_startBin,
                     std::bind2nd(std::multiplies<double>(),m_factor));

    progress.report();
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

}
Example #3
0
  /**
   * Creates QwtData using X and Y values from the workspace spectra.
   * @param ws :: Workspace with X and Y values to use
   * @param wsIndex :: Workspace index to use
   * @return Pointer to created QwtData
   */
  boost::shared_ptr<QwtData> curveDataFromWs(MatrixWorkspace_const_sptr ws, size_t wsIndex)
  {
    const double* x = &ws->readX(wsIndex)[0];
    const double* y = &ws->readY(wsIndex)[0];
    size_t size = ws->blocksize();

    return boost::make_shared<QwtArrayData>(x,y,size);
  }
Example #4
0
void SumRowColumn::exec()
{
  // First task is to integrate the input workspace
  MatrixWorkspace_const_sptr integratedWS = integrateWorkspace();

  const size_t numSpec = integratedWS->getNumberHistograms();
  // Check number of spectra is 128*128 or 192*192. Print warning if not.
  if (numSpec != 16384 && numSpec != 36864)
  {
    g_log.warning() << "The input workspace has " << numSpec << " spectra."
      << "This is not 128*128 or 192*192 - did you make a mistake?\n";
  }

  // This is the dimension if all rows/columns are included
  const int dim = static_cast<int>( std::sqrt(static_cast<double>(numSpec)) );

  // Check the column range properties
  int start = getProperty("HOverVMin");
  int end = getProperty("HOverVMax");
  if ( isEmpty(start) ) start = 0;
  if ( isEmpty(end) || end > dim-1 ) end = dim-1;
  if ( start > end )
  {
    g_log.error("H/V_Min must be less than H/V_Max");
    throw std::out_of_range("H/V_Min must be less than H/V_Max");
  }

  MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(integratedWS,1,dim,dim);
  // Remove the unit
  outputWS->getAxis(0)->unit().reset();

  // Get references to the vectors for the results
  MantidVec& X = outputWS->dataX(0);
  MantidVec& Y = outputWS->dataY(0);

  // Get the orientation
  const std::string orientation = getProperty("Orientation");
  const bool horizontal = ( orientation=="D_H" ? 1 : 0 );

  Progress progress(this,0,1,dim);
  for (int i = 0; i < dim; ++i)
  {
    // Copy X values
    X[i] = i;

    // Now loop over calculating Y's
    for (int j = start; j <= end; ++j)
    {
      const int index = ( horizontal ? ( i + j*dim) : ( i*dim + j) );
      Y[i] += integratedWS->readY(index)[0];
    }
  }

  setProperty("OutputWorkspace",outputWS);
}
Example #5
0
/**
 * Rebin the input quadrilateral to the output grid
 * @param inputQ The input polygon
 * @param inputWS The input workspace containing the input intensity values
 * @param i The index in the vertical axis direction that inputQ references
 * @param j The index in the horizontal axis direction that inputQ references
 * @param outputWS A pointer to the output workspace that accumulates the data
 * @param verticalAxis A vector containing the output vertical axis bin boundaries
 */
void Rebin2D::rebinToFractionalOutput(const Geometry::Quadrilateral & inputQ,
                                      MatrixWorkspace_const_sptr inputWS,
                                      const size_t i, const size_t j,
                                      RebinnedOutput_sptr outputWS,
                                      const std::vector<double> & verticalAxis)
{
    const MantidVec & X = outputWS->readX(0);
    size_t qstart(0), qend(verticalAxis.size()-1), en_start(0), en_end(X.size() - 1);
    if( !getIntersectionRegion(outputWS, verticalAxis, inputQ, qstart, qend, en_start, en_end)) return;

    for( size_t qi = qstart; qi < qend; ++qi )
    {
        const double vlo = verticalAxis[qi];
        const double vhi = verticalAxis[qi+1];
        for( size_t ei = en_start; ei < en_end; ++ei )
        {
            const V2D ll(X[ei], vlo);
            const V2D lr(X[ei+1], vlo);
            const V2D ur(X[ei+1], vhi);
            const V2D ul(X[ei], vhi);
            const Quadrilateral outputQ(ll, lr, ur, ul);

            double yValue = inputWS->readY(i)[j];
            if (boost::math::isnan(yValue))
            {
                continue;
            }
            try
            {
                ConvexPolygon overlap = intersectionByLaszlo(outputQ, inputQ);
                const double weight = overlap.area()/inputQ.area();
                yValue *=  weight;
                double eValue = inputWS->readE(i)[j] * weight;
                const double overlapWidth = overlap.largestX() - overlap.smallestX();
                // Don't do the overlap removal if already RebinnedOutput.
                // This wreaks havoc on the data.
                if(inputWS->isDistribution() && inputWS->id() != "RebinnedOutput")
                {
                    yValue *= overlapWidth;
                    eValue *= overlapWidth;
                }
                eValue *= eValue;
                PARALLEL_CRITICAL(overlap)
                {
                    outputWS->dataY(qi)[ei] += yValue;
                    outputWS->dataE(qi)[ei] += eValue;
                    outputWS->dataF(qi)[ei] += weight;
                }
            }
            catch(Geometry::NoIntersectionException &)
            {}
        }
    }
}
    /*
    Execute the transformtion. Generates an output IMDEventWorkspace.
    @return the constructed IMDEventWorkspace following the transformation.
    @param ws: Input MatrixWorkspace const shared pointer
    */
    IMDEventWorkspace_sptr ReflectometryTransformQxQz::execute(MatrixWorkspace_const_sptr inputWs) const
    {
      const size_t nbinsx = 10;
      const size_t nbinsz = 10;

      auto ws = boost::make_shared<MDEventWorkspace<MDLeanEvent<2>,2> >();
      MDHistoDimension_sptr qxDim = MDHistoDimension_sptr(new MDHistoDimension("Qx","qx","(Ang^-1)", static_cast<Mantid::coord_t>(m_qxMin), static_cast<Mantid::coord_t>(m_qxMax), nbinsx)); 
      MDHistoDimension_sptr qzDim = MDHistoDimension_sptr(new MDHistoDimension("Qz","qz","(Ang^-1)", static_cast<Mantid::coord_t>(m_qzMin), static_cast<Mantid::coord_t>(m_qzMax), nbinsz)); 

      ws->addDimension(qxDim);
      ws->addDimension(qzDim);

      // Set some reasonable values for the box controller
      BoxController_sptr bc = ws->getBoxController();
      bc->setSplitInto(2);
      bc->setSplitThreshold(10);

      // Initialize the workspace.
      ws->initialize();

      // Start with a MDGridBox.
      ws->splitBox();

      auto spectraAxis = inputWs->getAxis(1);
      for(size_t index = 0; index < inputWs->getNumberHistograms(); ++index)
      {
        auto counts = inputWs->readY(index);
        auto wavelengths = inputWs->readX(index);
        auto errors = inputWs->readE(index);
        const size_t nInputBins =  wavelengths.size() -1;
        const double theta_final = spectraAxis->getValue(index);
        m_QxCalculation.setThetaFinal(theta_final);
        m_QzCalculation.setThetaFinal(theta_final);
        //Loop over all bins in spectra 
        for(size_t binIndex = 0; binIndex < nInputBins; ++binIndex)
        {
          const double& wavelength = 0.5*(wavelengths[binIndex] + wavelengths[binIndex+1]);
          double _qx = m_QxCalculation.execute(wavelength);
          double _qz = m_QzCalculation.execute(wavelength);
          double centers[2] = {_qx, _qz};

          ws->addEvent(MDLeanEvent<2>(float(counts[binIndex]), float(errors[binIndex]*errors[binIndex]), centers));
        }
        ws->splitAllIfNeeded(NULL);
      }
      return ws;
    }
Example #7
0
void SaveNISTDAT::exec()
{
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  std::string filename = getPropertyValue("Filename");

  // prepare to save to file
  std::ofstream out_File(filename.c_str());
  if (!out_File)
  {
    g_log.error("Failed to open file:" + filename);
    throw Exception::FileError("Failed to open file:" , filename);
  }
  out_File << "Data columns Qx - Qy - I(Qx,Qy) - err(I)\r\n";
  out_File << "ASCII data\r\n";

  // Set up the progress reporting object
  Progress progress(this,0.0,1.0,2);
  progress.report("Save I(Qx,Qy)");

  if ( inputWS->axes() > 1 && inputWS->getAxis(1)->isNumeric() )
  {
    const Axis& axis = *inputWS->getAxis(1);
    for (size_t i = 0; i < axis.length()-1; i++)
    {
      const double qy = (axis(i)+axis(i+1))/2.0;
      const MantidVec& XIn = inputWS->readX(i);
      const MantidVec& YIn = inputWS->readY(i);
      const MantidVec& EIn = inputWS->readE(i);

      for ( size_t j = 0; j < XIn.size()-1; j++)
      {
        // Exclude NaNs
        if (YIn[j]==YIn[j])
        {
          out_File << (XIn[j]+XIn[j+1])/2.0;
          out_File << "  " << qy;
          out_File << "  " << YIn[j];
          out_File << "  " << EIn[j] << "\r\n";
        }
      }
    }
  }
  out_File.close();
  progress.report("Save I(Qx,Qy)");
}
void ExtractFFTSpectrum::exec()
{
  MatrixWorkspace_sptr inputWS = getProperty("InputWorkspace");
  MatrixWorkspace_sptr inputImagWS = getProperty("InputImagWorkspace");
  const int fftPart = getProperty("FFTPart");
  const int numHists = static_cast<int>(inputWS->getNumberHistograms());
  MatrixWorkspace_sptr outputWS = WorkspaceFactory::Instance().create(inputWS);

  Progress prog(this, 0.0, 1.0, numHists);

  PARALLEL_FOR1(outputWS)
  for ( int i = 0; i < numHists; i++ )
  {
    PARALLEL_START_INTERUPT_REGION

    IAlgorithm_sptr childFFT = createChildAlgorithm("FFT");
    childFFT->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWS);
    childFFT->setProperty<int>("Real", i);
    if( inputImagWS )
    {
      childFFT->setProperty<MatrixWorkspace_sptr>("InputImagWorkspace", inputImagWS);
      childFFT->setProperty<int>("Imaginary", i);
    }
    childFFT->execute();
    MatrixWorkspace_const_sptr fftTemp = childFFT->getProperty("OutputWorkspace");

    outputWS->dataE(i) = fftTemp->readE(fftPart);
    outputWS->dataY(i) = fftTemp->readY(fftPart);
    outputWS->dataX(i) = fftTemp->readX(fftPart);

    prog.report();

    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

  boost::shared_ptr<Kernel::Units::Label> lblUnit = boost::dynamic_pointer_cast<Kernel::Units::Label>(UnitFactory::Instance().create("Label"));
  lblUnit->setLabel("Time", "ns");
  outputWS->getAxis(0)->unit() = lblUnit;

  setProperty("OutputWorkspace", outputWS);
}
Example #9
0
void FlatBackground::exec()
{
  // Retrieve the input workspace
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  // Copy over all the data
  const int numHists = static_cast<int>(inputWS->getNumberHistograms());
  const int blocksize = static_cast<int>(inputWS->blocksize());

  // Get the required X range
  double startX,endX;
  this->checkRange(startX,endX);

  std::vector<int> specInds = getProperty("WorkspaceIndexList");
  // check if the user passed an empty list, if so all of spec will be processed
  this->getSpecInds(specInds, numHists);
 
  // Are we removing the background?
  const bool removeBackground =
    std::string(getProperty("outputMode")) == "Subtract Background";

  // Initialise the progress reporting object
  m_progress = new Progress(this,0.0,0.2,numHists); 

  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  // If input and output workspaces are not the same, create a new workspace for the output
  if (outputWS != inputWS )
  {
    outputWS = WorkspaceFactory::Instance().create(inputWS);
    PARALLEL_FOR2(inputWS,outputWS)
    for (int i = 0; i < numHists; ++i)
    {
      PARALLEL_START_INTERUPT_REGION
      outputWS->dataX(i) = inputWS->readX(i);
      outputWS->dataY(i) = inputWS->readY(i);
      outputWS->dataE(i) = inputWS->readE(i);
      m_progress->report();
      PARALLEL_END_INTERUPT_REGION
    }
    PARALLEL_CHECK_INTERUPT_REGION
  }
Example #10
0
 /**
  * Add -1.*minValue on each spectra.
  *
  * @param minWS A workspace of minimum values for each spectra. This is calculated in
  * the @see exec portion of the algorithm.
  * @param wksp The workspace to modify.
  * @param prog The progress.
  */
 void ResetNegatives::pushMinimum(MatrixWorkspace_const_sptr minWS, MatrixWorkspace_sptr wksp, Progress &prog)
 {
   int64_t nHist = minWS->getNumberHistograms();
   PARALLEL_FOR2(wksp, minWS)
   for (int64_t i = 0; i < nHist; i++)
   {
     PARALLEL_START_INTERUPT_REGION
     double minValue = minWS->readY(i)[0];
     if (minValue <= 0)
     {
       minValue *= -1.;
       MantidVec & y = wksp->dataY(i);
       for (MantidVec::iterator it = y.begin(); it != y.end(); ++it)
       {
         *it = fixZero(*it + minValue);
       }
     }
     prog.report();
     PARALLEL_END_INTERUPT_REGION
   }
   PARALLEL_CHECK_INTERUPT_REGION
 }
Example #11
0
IMDHistoWorkspace_sptr ReflectometryTransform::executeMDNormPoly(
    MatrixWorkspace_const_sptr inputWs) const {

  auto input_x_dim = inputWs->getXDimension();

  MDHistoDimension_sptr dim0 = MDHistoDimension_sptr(new MDHistoDimension(
      input_x_dim->getName(), input_x_dim->getDimensionId(),
      input_x_dim->getMDFrame(),
      static_cast<Mantid::coord_t>(input_x_dim->getMinimum()),
      static_cast<Mantid::coord_t>(input_x_dim->getMaximum()),
      input_x_dim->getNBins()));

  auto input_y_dim = inputWs->getYDimension();

  MDHistoDimension_sptr dim1 = MDHistoDimension_sptr(new MDHistoDimension(
      input_y_dim->getName(), input_y_dim->getDimensionId(),
      input_y_dim->getMDFrame(),
      static_cast<Mantid::coord_t>(input_y_dim->getMinimum()),
      static_cast<Mantid::coord_t>(input_y_dim->getMaximum()),
      input_y_dim->getNBins()));

  auto outWs = boost::make_shared<MDHistoWorkspace>(dim0, dim1);

  for (size_t nHistoIndex = 0; nHistoIndex < inputWs->getNumberHistograms();
       ++nHistoIndex) {
    const MantidVec X = inputWs->readX(nHistoIndex);
    const MantidVec Y = inputWs->readY(nHistoIndex);
    const MantidVec E = inputWs->readE(nHistoIndex);

    for (size_t nBinIndex = 0; nBinIndex < inputWs->blocksize(); ++nBinIndex) {
      auto value_index = outWs->getLinearIndex(nBinIndex, nHistoIndex);
      outWs->setSignalAt(value_index, Y[nBinIndex]);
      outWs->setErrorSquaredAt(value_index, E[nBinIndex] * E[nBinIndex]);
    }
  }
  return outWs;
}
Example #12
0
/**
 * Sets a new preview spectrum for the mini plot.
 *
 * @param value workspace index
 */
void ResNorm::previewSpecChanged(int value) {
  m_previewSpec = value;

  // Update vanadium plot
  if (m_uiForm.dsVanadium->isValid())
    m_uiForm.ppPlot->addSpectrum(
        "Vanadium", m_uiForm.dsVanadium->getCurrentDataName(), m_previewSpec);

  // Update fit plot
  std::string fitWsGroupName(m_pythonExportWsName + "_Fit_Workspaces");
  std::string fitParamsName(m_pythonExportWsName + "_Fit");
  if (AnalysisDataService::Instance().doesExist(fitWsGroupName)) {
    WorkspaceGroup_sptr fitWorkspaces =
        AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
            fitWsGroupName);
    ITableWorkspace_sptr fitParams =
        AnalysisDataService::Instance().retrieveWS<ITableWorkspace>(
            fitParamsName);
    if (fitWorkspaces && fitParams) {
      Column_const_sptr scaleFactors = fitParams->getColumn("Scaling");
      std::string fitWsName(fitWorkspaces->getItem(m_previewSpec)->name());
      MatrixWorkspace_const_sptr fitWs =
          AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
              fitWsName);

      MatrixWorkspace_sptr fit = WorkspaceFactory::Instance().create(fitWs, 1);
      fit->setX(0, fitWs->readX(1));
      fit->getSpectrum(0)->setData(fitWs->readY(1), fitWs->readE(1));

      for (size_t i = 0; i < fit->blocksize(); i++)
        fit->dataY(0)[i] /= scaleFactors->cell<double>(m_previewSpec);

      m_uiForm.ppPlot->addSpectrum("Fit", fit, 0, Qt::red);
    }
  }
}
Example #13
0
/**
 * Execution path for NormalisedPolygon Rebinning
 * @param inputWS : Workspace to be rebinned
 * @param vertexes : TableWorkspace for debugging purposes
 * @param dumpVertexes : determines whether vertexes will be written to for
 * debugging purposes or not
 * @param outputDimensions : used for the column headings for Dump Vertexes
 */
MatrixWorkspace_sptr ReflectometryTransform::executeNormPoly(
    MatrixWorkspace_const_sptr inputWS,
    boost::shared_ptr<Mantid::DataObjects::TableWorkspace> &vertexes,
    bool dumpVertexes, std::string outputDimensions) const {
  MatrixWorkspace_sptr temp = WorkspaceFactory::Instance().create(
      "RebinnedOutput", m_d1NumBins, m_d0NumBins, m_d0NumBins);
  RebinnedOutput_sptr outWS = boost::static_pointer_cast<RebinnedOutput>(temp);

  const double widthD0 = (m_d0Max - m_d0Min) / double(m_d0NumBins);
  const double widthD1 = (m_d1Max - m_d1Min) / double(m_d1NumBins);

  std::vector<double> xBinsVec;
  std::vector<double> zBinsVec;
  VectorHelper::createAxisFromRebinParams({m_d1Min, widthD1, m_d1Max},
                                          zBinsVec);
  VectorHelper::createAxisFromRebinParams({m_d0Min, widthD0, m_d0Max},
                                          xBinsVec);

  // Put the correct bin boundaries into the workspace
  auto verticalAxis = new BinEdgeAxis(zBinsVec);
  outWS->replaceAxis(1, verticalAxis);
  for (size_t i = 0; i < zBinsVec.size() - 1; ++i)
    outWS->setX(i, xBinsVec);

  verticalAxis->title() = m_d1Label;

  // Prepare the required theta values
  DetectorAngularCache cache = initAngularCaches(inputWS.get());
  m_theta = cache.thetas;
  m_thetaWidths = cache.thetaWidths;

  const size_t nHistos = inputWS->getNumberHistograms();
  const size_t nBins = inputWS->blocksize();

  // Holds the spectrum-detector mapping
  std::vector<specnum_t> specNumberMapping;
  std::vector<detid_t> detIDMapping;
  // Create a table for the output if we want to debug vertex positioning
  addColumnHeadings(vertexes, outputDimensions);
  for (size_t i = 0; i < nHistos; ++i) {
    IDetector_const_sptr detector = inputWS->getDetector(i);
    if (!detector || detector->isMasked() || detector->isMonitor()) {
      continue;
    }

    // Compute polygon points
    const double theta = m_theta[i];
    const double thetaWidth = m_thetaWidths[i];
    const double thetaHalfWidth = 0.5 * thetaWidth;
    const double thetaLower = theta - thetaHalfWidth;
    const double thetaUpper = theta + thetaHalfWidth;

    const MantidVec &X = inputWS->readX(i);
    const MantidVec &Y = inputWS->readY(i);
    const MantidVec &E = inputWS->readE(i);
    for (size_t j = 0; j < nBins; ++j) {
      const double lamLower = X[j];
      const double lamUpper = X[j + 1];
      const double signal = Y[j];
      const double error = E[j];

      auto inputQ =
          m_calculator->createQuad(lamUpper, lamLower, thetaUpper, thetaLower);
      FractionalRebinning::rebinToFractionalOutput(inputQ, inputWS, i, j, outWS,
                                                   zBinsVec);
      // Find which qy bin this point lies in
      const auto qIndex =
          std::upper_bound(zBinsVec.begin(), zBinsVec.end(), inputQ[0].Y()) -
          zBinsVec.begin();
      if (qIndex != 0 && qIndex < static_cast<int>(zBinsVec.size())) {
        // Add this spectra-detector pair to the mapping
        specNumberMapping.push_back(
            outWS->getSpectrum(qIndex - 1).getSpectrumNo());
        detIDMapping.push_back(detector->getID());
      }
      // Debugging
      if (dumpVertexes) {
        writeRow(vertexes, inputQ[0], i, j, signal, error);
        writeRow(vertexes, inputQ[1], i, j, signal, error);
        writeRow(vertexes, inputQ[2], i, j, signal, error);
        writeRow(vertexes, inputQ[3], i, j, signal, error);
      }
    }
  }
  outWS->finalize();
  FractionalRebinning::normaliseOutput(outWS, inputWS);
  // Set the output spectrum-detector mapping
  SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping);
  outWS->updateSpectraUsing(outputDetectorMap);
  outWS->getAxis(0)->title() = m_d0Label;
  outWS->setYUnit("");
  outWS->setYUnitLabel("Intensity");

  return outWS;
}
Example #14
0
/**
  @ throw invalid_argument if the workspaces are not mututially compatible
*/
void Q1D2::exec()
{
  m_dataWS = getProperty("DetBankWorkspace");
  MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj");
  MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj");
  MatrixWorkspace_const_sptr wavePixelAdj = getProperty("WavePixelAdj");
  const bool doGravity = getProperty("AccountForGravity");
  m_doSolidAngle = getProperty("SolidAngleWeighting");

  //throws if we don't have common binning or another incompatibility
  Qhelper helper;
  helper.examineInput(m_dataWS, waveAdj, pixelAdj);
  // FIXME: how to examine the wavePixelAdj? 
  g_log.debug() << "All input workspaces were found to be valid\n";
  // normalization as a function of wavelength (i.e. centers of x-value bins)
  double const * const binNorms = waveAdj ? &(waveAdj->readY(0)[0]) : NULL;
  // error on the wavelength normalization
  double const * const binNormEs = waveAdj ? &(waveAdj->readE(0)[0]) : NULL;

  //define the (large number of) data objects that are going to be used in all iterations of the loop below

  // this will become the output workspace from this algorithm
  MatrixWorkspace_sptr outputWS = setUpOutputWorkspace(getProperty("OutputBinning"));

  const MantidVec & QOut = outputWS->readX(0);
  MantidVec & YOut = outputWS->dataY(0);
  MantidVec & EOutTo2 = outputWS->dataE(0);
  // normalisation that is applied to counts in each Q bin
  MantidVec normSum(YOut.size(), 0.0);
  // the error on the normalisation
  MantidVec normError2(YOut.size(), 0.0);

  const int numSpec = static_cast<int>(m_dataWS->getNumberHistograms());
  Progress progress(this, 0.05, 1.0, numSpec+1);

  PARALLEL_FOR3(m_dataWS, outputWS, pixelAdj)
  for (int i = 0; i < numSpec; ++i)
  {
    PARALLEL_START_INTERUPT_REGION
    // Get the pixel relating to this spectrum
    IDetector_const_sptr det;
    try {
      det = m_dataWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "Workspace index " << i << " (SpectrumIndex = " << m_dataWS->getSpectrum(i)->getSpectrumNo() << ") has no detector assigned to it - discarding" << std::endl;
      // Catch if no detector. Next line tests whether this happened - test placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a catch
      // in an openmp block.
    }
    // If no detector found or if detector is masked shouldn't be included skip onto the next spectrum
    if ( !det || det->isMonitor() || det->isMasked() )
    {
      continue;
    }

    //get the bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for
    //const size_t wavStart = waveLengthCutOff(i);
    const size_t wavStart = helper.waveLengthCutOff(m_dataWS, getProperty("RadiusCut"), getProperty("WaveCut"), i);
    if (wavStart >=  m_dataWS->readY(i).size())
    {
      // all the spectra in this detector are out of range
      continue;
    }
    
    const size_t numWavbins = m_dataWS->readY(i).size()-wavStart;
    // make just one call to new to reduce CPU overhead on each thread, access to these 
    // three "arrays" is via iterators
    MantidVec _noDirectUseStorage_(3*numWavbins);
    //normalization term
    MantidVec::iterator norms = _noDirectUseStorage_.begin();
    // the error on these weights, it contributes to the error calculation on the output workspace
    MantidVec::iterator normETo2s = norms + numWavbins;
    // the Q values calculated from input wavelength workspace
    MantidVec::iterator QIn = normETo2s + numWavbins;

    // the weighting for this input spectrum that is added to the normalization
    calculateNormalization(wavStart, i, pixelAdj, wavePixelAdj, binNorms, binNormEs, norms, normETo2s);

    // now read the data from the input workspace, calculate Q for each bin
    convertWavetoQ(i, doGravity, wavStart, QIn);

    // Pointers to the counts data and it's error
    MantidVec::const_iterator YIn = m_dataWS->readY(i).begin()+wavStart;
    MantidVec::const_iterator EIn = m_dataWS->readE(i).begin()+wavStart;

    //when finding the output Q bin remember that the input Q bins (from the convert to wavelength) start high and reduce
    MantidVec::const_iterator loc = QOut.end();
    // sum the Q contributions from each individual spectrum into the output array
    const MantidVec::const_iterator end = m_dataWS->readY(i).end();
    for( ; YIn != end; ++YIn, ++EIn, ++QIn, ++norms, ++normETo2s)
    {
      //find the output bin that each input y-value will fall into, remembering there is one more bin boundary than bins
      getQBinPlus1(QOut, *QIn, loc);
      // ignore counts that are out of the output range
      if ( (loc != QOut.begin()) && (loc != QOut.end()) )
      {
        // the actual Q-bin to add something to
        const size_t bin = loc - QOut.begin() - 1;
        PARALLEL_CRITICAL(q1d_counts_sum)
        {
          YOut[bin] += *YIn;
          normSum[bin] += *norms;
          //these are the errors squared which will be summed and square rooted at the end
          EOutTo2[bin] += (*EIn)*(*EIn);
          normError2[bin] += *normETo2s;
        }
      }
    }
    
    PARALLEL_CRITICAL(q1d_spectra_map)
    {
      progress.report("Computing I(Q)");

      // Add up the detector IDs in the output spectrum at workspace index 0
      const ISpectrum * inSpec = m_dataWS->getSpectrum(i);
      ISpectrum * outSpec = outputWS->getSpectrum(0);
      outSpec->addDetectorIDs( inSpec->getDetectorIDs() );
    }

    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

  bool doOutputParts = getProperty("OutputParts");
  if (doOutputParts)
  {
      MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWS);
      ws_sumOfCounts->dataX(0) = outputWS->dataX(0);
      ws_sumOfCounts->dataY(0) = outputWS->dataY(0);
      for (size_t i = 0; i < outputWS->dataE(0).size(); i++)
      {
        ws_sumOfCounts->dataE(0)[i] = sqrt(outputWS->dataE(0)[i]);
      }      

      MatrixWorkspace_sptr ws_sumOfNormFactors = WorkspaceFactory::Instance().create(outputWS);
      ws_sumOfNormFactors->dataX(0) = outputWS->dataX(0);
      for (size_t i = 0; i < ws_sumOfNormFactors->dataY(0).size(); i++)
      {
        ws_sumOfNormFactors->dataY(0)[i] = normSum[i];
        ws_sumOfNormFactors->dataE(0)[i] = sqrt(normError2[i]);
      }

      helper.outputParts(this, ws_sumOfCounts, ws_sumOfNormFactors);
  }


  progress.report("Normalizing I(Q)");
  //finally divide the number of counts in each output Q bin by its weighting
  normalize(normSum, normError2, YOut, EOutTo2);

  outputWS->updateSpectraUsingMap();

  setProperty("OutputWorkspace",outputWS);
}
Example #15
0
/** Executes the algorithm
 *
 *  @throw runtime_error Thrown if algorithm cannot execute
 */
void MaxMin::exec()
{
  // Try and retrieve the optional properties
  m_MinRange = getProperty("RangeLower");
  m_MaxRange = getProperty("RangeUpper");
  m_MinSpec = getProperty("StartWorkspaceIndex");
  m_MaxSpec = getProperty("EndWorkspaceIndex");
  showMin = getProperty("ShowMin");

  // Get the input workspace
  MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace");

  const int numberOfSpectra = static_cast<int>(localworkspace->getNumberHistograms());

  // Check 'StartSpectrum' is in range 0-numberOfSpectra
  if ( m_MinSpec > numberOfSpectra )
  {
    g_log.warning("StartSpectrum out of range! Set to 0.");
    m_MinSpec = 0;
  }
  if ( isEmpty(m_MaxSpec) ) m_MaxSpec = numberOfSpectra-1;
  if ( m_MaxSpec > numberOfSpectra-1 || m_MaxSpec < m_MinSpec )
  {
    g_log.warning("EndSpectrum out of range! Set to max detector number");
    m_MaxSpec = numberOfSpectra;
  }
  if ( m_MinRange > m_MaxRange )
  {
    g_log.warning("Range_upper is less than Range_lower. Will integrate up to frame maximum.");
    m_MaxRange = 0.0;
  }

  // Create the 1D workspace for the output
  MatrixWorkspace_sptr outputWorkspace = API::WorkspaceFactory::Instance().create(localworkspace,m_MaxSpec-m_MinSpec+1,2,1);


  Progress progress(this,0,1,(m_MaxSpec-m_MinSpec+1));
  PARALLEL_FOR2(localworkspace,outputWorkspace)
  // Loop over spectra
  for (int i = m_MinSpec; i <= m_MaxSpec; ++i)
  {
    PARALLEL_START_INTERUPT_REGION
    int newindex=i-m_MinSpec;
    // Copy over spectrum and detector number info
    outputWorkspace->getSpectrum(newindex)->copyInfoFrom(*localworkspace->getSpectrum(i));

    // Retrieve the spectrum into a vector
    const MantidVec& X = localworkspace->readX(i);
    const MantidVec& Y = localworkspace->readY(i);

    // Find the range [min,max]
    MantidVec::const_iterator lowit, highit;
    if (m_MinRange == EMPTY_DBL()) lowit=X.begin();
    else lowit=std::lower_bound(X.begin(),X.end(),m_MinRange);

    if (m_MaxRange == EMPTY_DBL()) highit=X.end();
    else highit=std::find_if(lowit,X.end(),std::bind2nd(std::greater<double>(),m_MaxRange));

    // If range specified doesn't overlap with this spectrum then bail out
    if ( lowit == X.end() || highit == X.begin() ) continue;

    --highit; // Upper limit is the bin before, i.e. the last value smaller than MaxRange

    MantidVec::difference_type distmin=std::distance(X.begin(),lowit);
    MantidVec::difference_type distmax=std::distance(X.begin(),highit);

    MantidVec::const_iterator maxY;
    // Find the max/min element
    if (showMin==true)
    {
      maxY=std::min_element(Y.begin()+distmin,Y.begin()+distmax);
    }
    else
    {
      maxY=std::max_element(Y.begin()+distmin,Y.begin()+distmax);
    }
    MantidVec::difference_type d=std::distance(Y.begin(),maxY);
    // X boundaries for the max/min element
    outputWorkspace->dataX(newindex)[0]=*(X.begin()+d);
    outputWorkspace->dataX(newindex)[1]=*(X.begin()+d+1); //This is safe since X is of dimension Y+1
    outputWorkspace->dataY(newindex)[0]=*maxY;
    progress.report();
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

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

  return;
}
void SANSSolidAngleCorrection::exec() {
  // Reduction property manager
  const std::string reductionManagerName = getProperty("ReductionProperties");
  boost::shared_ptr<PropertyManager> reductionManager;
  if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) {
    reductionManager =
        PropertyManagerDataService::Instance().retrieve(reductionManagerName);
  } else {
    reductionManager = boost::make_shared<PropertyManager>();
    PropertyManagerDataService::Instance().addOrReplace(reductionManagerName,
                                                        reductionManager);
  }

  // If the solid angle algorithm isn't in the reduction properties, add it
  if (!reductionManager->existsProperty("SolidAngleAlgorithm")) {
    AlgorithmProperty *algProp = new AlgorithmProperty("SolidAngleAlgorithm");
    algProp->setValue(toString());
    reductionManager->declareProperty(algProp);
  }

  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  DataObjects::EventWorkspace_const_sptr inputEventWS =
      boost::dynamic_pointer_cast<const EventWorkspace>(inputWS);
  if (inputEventWS)
    return execEvent();

  // Now create the output workspace
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  if (outputWS != inputWS) {
    outputWS = WorkspaceFactory::Instance().create(inputWS);
    outputWS->isDistribution(true);
    outputWS->setYUnit("");
    outputWS->setYUnitLabel("Steradian");
    setProperty("OutputWorkspace", outputWS);
  }

  const int numHists = static_cast<int>(inputWS->getNumberHistograms());
  Progress progress(this, 0.0, 1.0, numHists);

  // Number of X bins
  const int xLength = static_cast<int>(inputWS->readY(0).size());

  PARALLEL_FOR2(outputWS, inputWS)
  for (int i = 0; i < numHists; ++i) {
    PARALLEL_START_INTERUPT_REGION
    outputWS->dataX(i) = inputWS->readX(i);

    IDetector_const_sptr det;
    try {
      det = inputWS->getDetector(i);
    } catch (Exception::NotFoundError &) {
      g_log.warning() << "Spectrum index " << i
                      << " has no detector assigned to it - discarding"
                      << std::endl;
      // Catch if no detector. Next line tests whether this happened - test
      // placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a
      // catch
      // in an openmp block.
    }
    // If no detector found, skip onto the next spectrum
    if (!det)
      continue;

    // Skip if we have a monitor or if the detector is masked.
    if (det->isMonitor() || det->isMasked())
      continue;

    const MantidVec &YIn = inputWS->readY(i);
    const MantidVec &EIn = inputWS->readE(i);

    MantidVec &YOut = outputWS->dataY(i);
    MantidVec &EOut = outputWS->dataE(i);

    // Compute solid angle correction factor
    const bool is_tube = getProperty("DetectorTubes");
    const double tanTheta = tan(inputWS->detectorTwoTheta(det));
    const double theta_term = sqrt(tanTheta * tanTheta + 1.0);
    double corr;
    if (is_tube) {
      const double tanAlpha = tan(getYTubeAngle(det, inputWS));
      const double alpha_term = sqrt(tanAlpha * tanAlpha + 1.0);
      corr = alpha_term * theta_term * theta_term;
    } else {
      corr = theta_term * theta_term * theta_term;
    }

    // Correct data for all X bins
    for (int j = 0; j < xLength; j++) {
      YOut[j] = YIn[j] * corr;
      EOut[j] = fabs(EIn[j] * corr);
    }
    progress.report("Solid Angle Correction");
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION
  setProperty("OutputMessage", "Solid angle correction applied");
}
Example #17
0
/** Executes the algorithm
 *
 *  @throw runtime_error Thrown if algorithm cannot execute
 */
void Fit1D::exec() {

  // Custom initialization
  prepare();

  // check if derivative defined in derived class
  bool isDerivDefined = true;
  gsl_matrix *M = NULL;
  try {
    const std::vector<double> inTest(m_parameterNames.size(), 1.0);
    std::vector<double> outTest(m_parameterNames.size());
    const double xValuesTest = 0;
    JacobianImpl J;
    M = gsl_matrix_alloc(m_parameterNames.size(), 1);
    J.setJ(M);
    // note nData set to zero (last argument) hence this should avoid further
    // memory problems
    functionDeriv(&(inTest.front()), &J, &xValuesTest, 0);
  } catch (Exception::NotImplementedError &) {
    isDerivDefined = false;
  }
  gsl_matrix_free(M);

  // Try to retrieve optional properties
  int histNumber = getProperty("WorkspaceIndex");
  const int maxInterations = getProperty("MaxIterations");

  // Get the input workspace
  MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace");

  // number of histogram is equal to the number of spectra
  const size_t numberOfSpectra = localworkspace->getNumberHistograms();
  // Check that the index given is valid
  if (histNumber >= static_cast<int>(numberOfSpectra)) {
    g_log.warning("Invalid Workspace index given, using first Workspace");
    histNumber = 0;
  }

  // Retrieve the spectrum into a vector
  const MantidVec &XValues = localworkspace->readX(histNumber);
  const MantidVec &YValues = localworkspace->readY(histNumber);
  const MantidVec &YErrors = localworkspace->readE(histNumber);

  // Read in the fitting range data that we were sent
  double startX = getProperty("StartX");
  double endX = getProperty("EndX");
  // check if the values had been set, otherwise use defaults
  if (isEmpty(startX)) {
    startX = XValues.front();
    modifyStartOfRange(startX); // does nothing by default but derived class may
                                // provide a more intelligent value
  }
  if (isEmpty(endX)) {
    endX = XValues.back();
    modifyEndOfRange(endX); // does nothing by default but derived class may
                            // previde a more intelligent value
  }

  int m_minX;
  int m_maxX;

  // Check the validity of startX
  if (startX < XValues.front()) {
    g_log.warning("StartX out of range! Set to start of frame.");
    startX = XValues.front();
  }
  // Get the corresponding bin boundary that comes before (or coincides with)
  // this value
  for (m_minX = 0; XValues[m_minX + 1] < startX; ++m_minX) {
  }

  // Check the validity of endX and get the bin boundary that come after (or
  // coincides with) it
  if (endX >= XValues.back() || endX < startX) {
    g_log.warning("EndX out of range! Set to end of frame");
    endX = XValues.back();
    m_maxX = static_cast<int>(YValues.size());
  } else {
    for (m_maxX = m_minX; XValues[m_maxX] < endX; ++m_maxX) {
    }
  }

  afterDataRangedDetermined(m_minX, m_maxX);

  // create and populate GSL data container warn user if l_data.n < l_data.p
  // since as a rule of thumb this is required as a minimum to obtained
  // 'accurate'
  // fitting parameter values.

  FitData l_data(this, getProperty("Fix"));

  l_data.n =
      m_maxX -
      m_minX; // m_minX and m_maxX are array index markers. I.e. e.g. 0 & 19.
  if (l_data.n == 0) {
    g_log.error("The data set is empty.");
    throw std::runtime_error("The data set is empty.");
  }
  if (l_data.n < l_data.p) {
    g_log.error(
        "Number of data points less than number of parameters to be fitted.");
    throw std::runtime_error(
        "Number of data points less than number of parameters to be fitted.");
  }
  l_data.X = new double[l_data.n];
  l_data.sigmaData = new double[l_data.n];
  l_data.forSimplexLSwrap = new double[l_data.n];
  l_data.parameters = new double[nParams()];

  // check if histogram data in which case use mid points of histogram bins

  const bool isHistogram = localworkspace->isHistogramData();
  for (unsigned int i = 0; i < l_data.n; ++i) {
    if (isHistogram)
      l_data.X[i] =
          0.5 * (XValues[m_minX + i] +
                 XValues[m_minX + i + 1]); // take mid-point if histogram bin
    else
      l_data.X[i] = XValues[m_minX + i];
  }

  l_data.Y = &YValues[m_minX];

  // check that no error is negative or zero
  for (unsigned int i = 0; i < l_data.n; ++i) {
    if (YErrors[m_minX + i] <= 0.0) {
      l_data.sigmaData[i] = 1.0;
    } else
      l_data.sigmaData[i] = YErrors[m_minX + i];
  }

  // create array of fitted parameter. Take these to those input by the user.
  // However, for doing the
  // underlying fitting it might be more efficient to actually perform the
  // fitting on some of other
  // form of the fitted parameters. For instance, take the Gaussian sigma
  // parameter. In practice it
  // in fact more efficient to perform the fitting not on sigma but 1/sigma^2.
  // The methods
  // modifyInitialFittedParameters() and modifyFinalFittedParameters() are used
  // to allow for this;
  // by default these function do nothing.

  m_fittedParameter.clear();
  for (size_t i = 0; i < nParams(); i++) {
    m_fittedParameter.push_back(getProperty(m_parameterNames[i]));
  }
  modifyInitialFittedParameters(
      m_fittedParameter); // does nothing except if overwritten by derived class
  for (size_t i = 0; i < nParams(); i++) {
    l_data.parameters[i] = m_fittedParameter[i];
  }

  // set-up initial guess for fit parameters

  gsl_vector *initFuncArg;
  initFuncArg = gsl_vector_alloc(l_data.p);

  for (size_t i = 0, j = 0; i < nParams(); i++) {
    if (l_data.active[i])
      gsl_vector_set(initFuncArg, j++, m_fittedParameter[i]);
  }

  // set-up GSL container to be used with GSL simplex algorithm

  gsl_multimin_function gslSimplexContainer;
  gslSimplexContainer.n = l_data.p; // n here refers to number of parameters
  gslSimplexContainer.f = &gsl_costFunction;
  gslSimplexContainer.params = &l_data;

  // set-up GSL least squares container

  gsl_multifit_function_fdf f;
  f.f = &gsl_f;
  f.df = &gsl_df;
  f.fdf = &gsl_fdf;
  f.n = l_data.n;
  f.p = l_data.p;
  f.params = &l_data;

  // set-up remaining GSL machinery for least squared

  const gsl_multifit_fdfsolver_type *T = gsl_multifit_fdfsolver_lmsder;
  gsl_multifit_fdfsolver *s = NULL;
  if (isDerivDefined) {
    s = gsl_multifit_fdfsolver_alloc(T, l_data.n, l_data.p);
    gsl_multifit_fdfsolver_set(s, &f, initFuncArg);
  }

  // set-up remaining GSL machinery to use simplex algorithm

  const gsl_multimin_fminimizer_type *simplexType =
      gsl_multimin_fminimizer_nmsimplex;
  gsl_multimin_fminimizer *simplexMinimizer = NULL;
  gsl_vector *simplexStepSize = NULL;
  if (!isDerivDefined) {
    simplexMinimizer = gsl_multimin_fminimizer_alloc(simplexType, l_data.p);
    simplexStepSize = gsl_vector_alloc(l_data.p);
    gsl_vector_set_all(simplexStepSize,
                       1.0); // is this always a sensible starting step size?
    gsl_multimin_fminimizer_set(simplexMinimizer, &gslSimplexContainer,
                                initFuncArg, simplexStepSize);
  }

  // finally do the fitting

  int iter = 0;
  int status;
  double finalCostFuncVal;
  double dof = static_cast<double>(
      l_data.n - l_data.p); // dof stands for degrees of freedom

  // Standard least-squares used if derivative function defined otherwise
  // simplex
  Progress prog(this, 0.0, 1.0, maxInterations);
  if (isDerivDefined) {

    do {
      iter++;
      status = gsl_multifit_fdfsolver_iterate(s);

      if (status) // break if error
        break;

      status = gsl_multifit_test_delta(s->dx, s->x, 1e-4, 1e-4);
      prog.report();
    } while (status == GSL_CONTINUE && iter < maxInterations);

    double chi = gsl_blas_dnrm2(s->f);
    finalCostFuncVal = chi * chi / dof;

    // put final converged fitting values back into m_fittedParameter
    for (size_t i = 0, j = 0; i < nParams(); i++)
      if (l_data.active[i])
        m_fittedParameter[i] = gsl_vector_get(s->x, j++);
  } else {
    do {
      iter++;
      status = gsl_multimin_fminimizer_iterate(simplexMinimizer);

      if (status) // break if error
        break;

      double size = gsl_multimin_fminimizer_size(simplexMinimizer);
      status = gsl_multimin_test_size(size, 1e-2);
      prog.report();
    } while (status == GSL_CONTINUE && iter < maxInterations);

    finalCostFuncVal = simplexMinimizer->fval / dof;

    // put final converged fitting values back into m_fittedParameter
    for (unsigned int i = 0, j = 0; i < m_fittedParameter.size(); i++)
      if (l_data.active[i])
        m_fittedParameter[i] = gsl_vector_get(simplexMinimizer->x, j++);
  }

  modifyFinalFittedParameters(
      m_fittedParameter); // do nothing except if overwritten by derived class

  // Output summary to log file

  std::string reportOfFit = gsl_strerror(status);

  g_log.information() << "Iteration = " << iter << "\n"
                      << "Status = " << reportOfFit << "\n"
                      << "Chi^2/DoF = " << finalCostFuncVal << "\n";
  for (size_t i = 0; i < m_fittedParameter.size(); i++)
    g_log.information() << m_parameterNames[i] << " = " << m_fittedParameter[i]
                        << "  \n";

  // also output summary to properties

  setProperty("OutputStatus", reportOfFit);
  setProperty("OutputChi2overDoF", finalCostFuncVal);
  for (size_t i = 0; i < m_fittedParameter.size(); i++)
    setProperty(m_parameterNames[i], m_fittedParameter[i]);

  std::string output = getProperty("Output");
  if (!output.empty()) {
    // calculate covariance matrix if derivatives available

    gsl_matrix *covar(NULL);
    std::vector<double> standardDeviations;
    std::vector<double> sdExtended;
    if (isDerivDefined) {
      covar = gsl_matrix_alloc(l_data.p, l_data.p);
      gsl_multifit_covar(s->J, 0.0, covar);

      int iPNotFixed = 0;
      for (size_t i = 0; i < nParams(); i++) {
        sdExtended.push_back(1.0);
        if (l_data.active[i]) {
          sdExtended[i] = sqrt(gsl_matrix_get(covar, iPNotFixed, iPNotFixed));
          iPNotFixed++;
        }
      }
      modifyFinalFittedParameters(sdExtended);
      for (size_t i = 0; i < nParams(); i++)
        if (l_data.active[i])
          standardDeviations.push_back(sdExtended[i]);

      declareProperty(
          new WorkspaceProperty<API::ITableWorkspace>(
              "OutputNormalisedCovarianceMatrix", "", Direction::Output),
          "The name of the TableWorkspace in which to store the final "
          "covariance matrix");
      setPropertyValue("OutputNormalisedCovarianceMatrix",
                       output + "_NormalisedCovarianceMatrix");

      Mantid::API::ITableWorkspace_sptr m_covariance =
          Mantid::API::WorkspaceFactory::Instance().createTable(
              "TableWorkspace");
      m_covariance->addColumn("str", "Name");
      std::vector<std::string>
          paramThatAreFitted; // used for populating 1st "name" column
      for (size_t i = 0; i < nParams(); i++) {
        if (l_data.active[i]) {
          m_covariance->addColumn("double", m_parameterNames[i]);
          paramThatAreFitted.push_back(m_parameterNames[i]);
        }
      }

      for (size_t i = 0; i < l_data.p; i++) {

        Mantid::API::TableRow row = m_covariance->appendRow();
        row << paramThatAreFitted[i];
        for (size_t j = 0; j < l_data.p; j++) {
          if (j == i)
            row << 1.0;
          else {
            row << 100.0 * gsl_matrix_get(covar, i, j) /
                       sqrt(gsl_matrix_get(covar, i, i) *
                            gsl_matrix_get(covar, j, j));
          }
        }
      }

      setProperty("OutputNormalisedCovarianceMatrix", m_covariance);
    }

    declareProperty(new WorkspaceProperty<API::ITableWorkspace>(
                        "OutputParameters", "", Direction::Output),
                    "The name of the TableWorkspace in which to store the "
                    "final fit parameters");
    declareProperty(
        new WorkspaceProperty<MatrixWorkspace>("OutputWorkspace", "",
                                               Direction::Output),
        "Name of the output Workspace holding resulting simlated spectrum");

    setPropertyValue("OutputParameters", output + "_Parameters");
    setPropertyValue("OutputWorkspace", output + "_Workspace");

    // Save the final fit parameters in the output table workspace
    Mantid::API::ITableWorkspace_sptr m_result =
        Mantid::API::WorkspaceFactory::Instance().createTable("TableWorkspace");
    m_result->addColumn("str", "Name");
    m_result->addColumn("double", "Value");
    if (isDerivDefined)
      m_result->addColumn("double", "Error");
    Mantid::API::TableRow row = m_result->appendRow();
    row << "Chi^2/DoF" << finalCostFuncVal;

    for (size_t i = 0; i < nParams(); i++) {
      Mantid::API::TableRow row = m_result->appendRow();
      row << m_parameterNames[i] << m_fittedParameter[i];
      if (isDerivDefined && l_data.active[i]) {
        // perhaps want to scale standard deviations with sqrt(finalCostFuncVal)
        row << sdExtended[i];
      }
    }
    setProperty("OutputParameters", m_result);

    // Save the fitted and simulated spectra in the output workspace
    MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");
    int iSpec = getProperty("WorkspaceIndex");
    const MantidVec &inputX = inputWorkspace->readX(iSpec);
    const MantidVec &inputY = inputWorkspace->readY(iSpec);

    int histN = isHistogram ? 1 : 0;
    Mantid::DataObjects::Workspace2D_sptr ws =
        boost::dynamic_pointer_cast<Mantid::DataObjects::Workspace2D>(
            Mantid::API::WorkspaceFactory::Instance().create(
                "Workspace2D", 3, l_data.n + histN, l_data.n));
    ws->setTitle("");
    ws->getAxis(0)->unit() =
        inputWorkspace->getAxis(0)
            ->unit(); //    UnitFactory::Instance().create("TOF");

    for (int i = 0; i < 3; i++)
      ws->dataX(i)
          .assign(inputX.begin() + m_minX, inputX.begin() + m_maxX + histN);

    ws->dataY(0).assign(inputY.begin() + m_minX, inputY.begin() + m_maxX);

    MantidVec &Y = ws->dataY(1);
    MantidVec &E = ws->dataY(2);

    double *lOut =
        new double[l_data.n]; // to capture output from call to function()
    modifyInitialFittedParameters(m_fittedParameter); // does nothing except if
                                                      // overwritten by derived
                                                      // class
    function(&m_fittedParameter[0], lOut, l_data.X, l_data.n);
    modifyInitialFittedParameters(m_fittedParameter); // reverse the effect of
    // modifyInitialFittedParameters - if any

    for (unsigned int i = 0; i < l_data.n; i++) {
      Y[i] = lOut[i];
      E[i] = l_data.Y[i] - Y[i];
    }

    delete[] lOut;

    setProperty("OutputWorkspace",
                boost::dynamic_pointer_cast<MatrixWorkspace>(ws));

    if (isDerivDefined)
      gsl_matrix_free(covar);
  }

  // clean up dynamically allocated gsl stuff

  if (isDerivDefined)
    gsl_multifit_fdfsolver_free(s);
  else {
    gsl_vector_free(simplexStepSize);
    gsl_multimin_fminimizer_free(simplexMinimizer);
  }

  delete[] l_data.X;
  delete[] l_data.sigmaData;
  delete[] l_data.forSimplexLSwrap;
  delete[] l_data.parameters;
  gsl_vector_free(initFuncArg);

  return;
}
Example #18
0
/**
 * This function deals with the logic necessary for summing a Workspace2D.
 * @param localworkspace The input workspace for summing.
 * @param outSpec The spectrum for the summed output.
 * @param progress The progress indicator.
 * @param numSpectra The number of spectra contributed to the sum.
 * @param numMasked The spectra dropped from the summations because they are
 * masked.
 * @param numZeros The number of zero bins in histogram workspace or empty
 * spectra for event workspace.
 */
void SumSpectra::doWorkspace2D(MatrixWorkspace_const_sptr localworkspace,
                               ISpectrum *outSpec, Progress &progress,
                               size_t &numSpectra, size_t &numMasked,
                               size_t &numZeros) {
  // Get references to the output workspaces's data vectors
  MantidVec &YSum = outSpec->dataY();
  MantidVec &YError = outSpec->dataE();

  MantidVec Weight;
  std::vector<size_t> nZeros;
  if (m_calculateWeightedSum) {
    Weight.assign(YSum.size(), 0);
    nZeros.assign(YSum.size(), 0);
  }
  numSpectra = 0;
  numMasked = 0;
  numZeros = 0;

  // Loop over spectra
  std::set<int>::iterator it;
  // for (int i = m_minSpec; i <= m_maxSpec; ++i)
  for (it = this->m_indices.begin(); it != this->m_indices.end(); ++it) {
    int i = *it;
    // Don't go outside the range.
    if ((i >= this->m_numberOfSpectra) || (i < 0)) {
      g_log.error() << "Invalid index " << i
                    << " was specified. Sum was aborted.\n";
      break;
    }

    try {
      // Get the detector object for this spectrum
      Geometry::IDetector_const_sptr det = localworkspace->getDetector(i);
      // Skip monitors, if the property is set to do so
      if (!m_keepMonitors && det->isMonitor())
        continue;
      // Skip masked detectors
      if (det->isMasked()) {
        numMasked++;
        continue;
      }
    } catch (...) {
      // if the detector not found just carry on
    }
    numSpectra++;

    // Retrieve the spectrum into a vector
    const MantidVec &YValues = localworkspace->readY(i);
    const MantidVec &YErrors = localworkspace->readE(i);
    if (m_calculateWeightedSum) {
      for (int k = 0; k < this->m_yLength; ++k) {
        if (YErrors[k] != 0) {
          double errsq = YErrors[k] * YErrors[k];
          YError[k] += errsq;
          Weight[k] += 1. / errsq;
          YSum[k] += YValues[k] / errsq;
        } else {
          nZeros[k]++;
        }
      }
    } else {
      for (int k = 0; k < this->m_yLength; ++k) {
        YSum[k] += YValues[k];
        YError[k] += YErrors[k] * YErrors[k];
      }
    }

    // Map all the detectors onto the spectrum of the output
    outSpec->addDetectorIDs(localworkspace->getSpectrum(i)->getDetectorIDs());

    progress.report();
  }

  if (m_calculateWeightedSum) {
    numZeros = 0;
    for (size_t i = 0; i < Weight.size(); i++) {
      if (nZeros[i] == 0)
        YSum[i] *= double(numSpectra) / Weight[i];
      else
        numZeros += nZeros[i];
    }
  }
}
Example #19
0
void SANSDirectBeamScaling::exec()
{
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");
  const double beamRadius = getProperty("BeamRadius");
  const double attTrans = getProperty("AttenuatorTransmission");
  const double attTransErr = getProperty("AttenuatorTransmissionError");

  // Extract the required spectra into separate workspaces
  std::vector<detid_t> udet;
  std::vector<size_t> index;
  udet.push_back(getProperty("BeamMonitor"));
  // Convert UDETs to workspace indices
  inputWS->getIndicesFromDetectorIDs(udet,index);
  if (index.size() < 1)
  {
    g_log.debug() << "inputWS->getIndicesFromDetectorIDs() returned empty\n";
    throw std::invalid_argument("Could not find the incident beam monitor spectra\n");
  }

  const int64_t numHists = inputWS->getNumberHistograms();
  Progress progress(this,0.0,1.0,numHists);

  // Number of X bins
  const int64_t xLength = inputWS->readY(0).size();

  // Monitor counts
  double monitor = 0.0;
  const MantidVec& MonIn = inputWS->readY(index[0]);
  for (int64_t j = 0; j < xLength; j++)
    monitor += MonIn[j];

  const V3D sourcePos = inputWS->getInstrument()->getSource()->getPos();
  double counts = 0.0;
  double error = 0.0;
  int nPixels = 0;

  // Sample-detector distance for the contributing pixels
  double sdd = 0.0;

  for (int64_t i = 0; i < int64_t(numHists); ++i)
  {
    IDetector_const_sptr det;
    try {
      det = inputWS->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      continue;
    }

    // Skip if we have a monitor or if the detector is masked.
    if ( det->isMonitor() || det->isMasked() ) continue;

    const MantidVec& YIn = inputWS->readY(i);
    const MantidVec& EIn = inputWS->readE(i);

    // Sum up all the counts
    V3D pos = det->getPos() - V3D(sourcePos.X(), sourcePos.Y(), 0.0);
    const double pixelDistance = pos.Z();
    pos.setZ(0.0);
    if (pos.norm() <= beamRadius) {
      // Correct data for all X bins
      for (int64_t j = 0; j < xLength; j++)
      {
        counts += YIn[j];
        error += EIn[j]*EIn[j];
      }
      nPixels += 1;
      sdd += pixelDistance;
    }
    progress.report("Absolute Scaling");
  }
  // Get the average SDD for the counted pixels, and transform to mm.
  sdd = sdd/nPixels*1000.0;
  error = std::sqrt(error);

  // Transform from m to mm
  double sourceAperture = getProperty("SourceApertureRadius");
  sourceAperture *= 1000.0;
  // Transform from m to mm
  double sampleAperture = getProperty("SampleApertureRadius");
  sampleAperture *= 1000.0;
  //TODO: replace this by some meaningful value
  const double KCG2FluxPerMon_SUGAR = 1.0;

  // Solid angle correction scale in 1/(cm^2)/steradian
  double solidAngleCorrScale = sdd/(M_PI*sourceAperture*sampleAperture);
  solidAngleCorrScale = solidAngleCorrScale*solidAngleCorrScale*100.0;

  // Scaling factor in n/(monitor count)/(cm^2)/steradian
  double scale = counts/monitor*solidAngleCorrScale/KCG2FluxPerMon_SUGAR;
  double scaleErr = std::abs(error/monitor)*solidAngleCorrScale/KCG2FluxPerMon_SUGAR;

  scaleErr = std::abs(scale/attTrans)*sqrt( (scaleErr/scale)*(scaleErr/scale) +(attTransErr/attTrans)*(attTransErr/attTrans) );
  scale /= attTrans;

  std::vector<double> output;
  output.push_back(scale);
  output.push_back(scaleErr);
  setProperty("ScaleFactor", output);
}
Example #20
0
		/** Executes the rebin algorithm
		*
		*  @throw runtime_error Thrown if
		*/
		void Rebunch::exec()
		{
			// retrieve the properties
			int n_bunch=getProperty("NBunch");

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

			bool dist = inputW->isDistribution();

			// workspace independent determination of length
                        int histnumber = static_cast<int>(inputW->size()/inputW->blocksize());

			/*
			const std::vector<double>& Xold = inputW->readX(0);
			const std::vector<double>& Yold = inputW->readY(0);
			int size_x=Xold.size();
			int size_y=Yold.size();
			*/
                        int size_x = static_cast<int>(inputW->readX(0).size());
                        int size_y = static_cast<int>(inputW->readY(0).size());

			//signal is the same length for histogram and point data
			int ny=(size_y/n_bunch);
			if(size_y%n_bunch >0)ny+=1;
			// default is for hist
			int nx=ny+1;
			bool point=false;
			if (size_x==size_y)
			{
				point=true;
				nx=ny;
			}

			// make output Workspace the same type is the input, but with new length of signal array
			API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(inputW,histnumber,nx,ny);

            int progress_step = histnumber / 100;
            if (progress_step == 0) progress_step = 1;
			PARALLEL_FOR2(inputW,outputW)
			for (int hist=0; hist <  histnumber;hist++)
			{
				PARALLEL_START_INTERUPT_REGION
				// Ensure that axis information are copied to the output workspace if the axis exists
			        try
				{
				  outputW->getAxis(1)->spectraNo(hist)=inputW->getAxis(1)->spectraNo(hist);
				}
				catch( Exception::IndexError& )
				{ 
				  // Not a Workspace2D
				}

				// get const references to input Workspace arrays (no copying)
				const MantidVec& XValues = inputW->readX(hist);
				const MantidVec& YValues = inputW->readY(hist);
				const MantidVec& YErrors = inputW->readE(hist);

				//get references to output workspace data (no copying)
				MantidVec& XValues_new=outputW->dataX(hist);
				MantidVec& YValues_new=outputW->dataY(hist);
				MantidVec& YErrors_new=outputW->dataE(hist);

				// output data arrays are implicitly filled by function
				if(point)
				{
					rebunch_point(XValues,YValues,YErrors,XValues_new,YValues_new,YErrors_new,n_bunch);
				}
				else
				{
					rebunch_hist(XValues,YValues,YErrors,XValues_new,YValues_new,YErrors_new,n_bunch, dist);
				}

				if (hist % progress_step == 0)
				{
				  progress(double(hist)/histnumber);
				  interruption_point();
				}
				PARALLEL_END_INTERUPT_REGION
			}
			PARALLEL_CHECK_INTERUPT_REGION
			outputW->isDistribution(dist);

			// Copy units
			if (outputW->getAxis(0)->unit().get())
			  outputW->getAxis(0)->unit() = inputW->getAxis(0)->unit();
			try
			{
			  if (inputW->getAxis(1)->unit().get())
			    outputW->getAxis(1)->unit() = inputW->getAxis(1)->unit();
			}
			catch(Exception::IndexError&) {
			  // OK, so this isn't a Workspace2D
			}

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

			return;
		}
Example #21
0
  //----------------------------------------------------------------------------------------------
  /// @copydoc Mantid::API::Algorithm::exec()
  void ResetNegatives::exec()
  {
    MatrixWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
    MatrixWorkspace_sptr outputWS = this->getProperty("OutputWorkspace");

    // get the minimum for each spectrum
    IAlgorithm_sptr alg = this->createChildAlgorithm("Min", 0., .1);
    alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputWS);
    alg->executeAsChildAlg();
    MatrixWorkspace_const_sptr minWS = alg->getProperty("OutputWorkspace");

    // determine if there is anything to do
    int64_t nHist = static_cast<int64_t>(minWS->getNumberHistograms());
    bool hasNegative = false;
    for (int64_t i = 0; i < nHist; i++)
    {
      if (minWS->readY(i)[0] < 0)
      {
        hasNegative = true;
      }
      break;
    }

    // get out early if there is nothing to do
    if (!hasNegative)
    {
      g_log.information() << "No values are negative. Copying InputWorkspace to OutputWorkspace\n";
      if (inputWS != outputWS)
      {
        IAlgorithm_sptr alg = this->createChildAlgorithm("CloneWorkspace", .1, 1.);
        alg->setProperty<Workspace_sptr>("InputWorkspace", inputWS);
        alg->executeAsChildAlg();

        Workspace_sptr temp = alg->getProperty("OutputWorkspace");
        setProperty("OutputWorkspace", boost::dynamic_pointer_cast<MatrixWorkspace>(temp));
      }
      return;
    }

    // sort the event list to make it fast and thread safe
    DataObjects::EventWorkspace_const_sptr eventWS
                 = boost::dynamic_pointer_cast<const DataObjects::EventWorkspace>( inputWS );
    if (eventWS)
      eventWS->sortAll(DataObjects::TOF_SORT, NULL);

    Progress prog(this, .1, 1., 2*nHist);

    // generate output workspace - copy X and dY
    outputWS = API::WorkspaceFactory::Instance().create(inputWS);
    PARALLEL_FOR2(inputWS,outputWS)
    for (int64_t i = 0; i < nHist; i++)
    {
      PARALLEL_START_INTERUPT_REGION
      outputWS->dataY(i) = inputWS->readY(i);
      outputWS->dataE(i) = inputWS->readE(i);
      outputWS->setX(i, inputWS->refX(i)); // share the pointer more
      prog.report();
      PARALLEL_END_INTERUPT_REGION
    }
    PARALLEL_CHECK_INTERUPT_REGION

    // do the actual work
    if (this->getProperty("AddMinimum"))
    {
        this->pushMinimum(minWS, outputWS, prog);
    }
    else
    {
      this->changeNegatives(minWS, this->getProperty("ResetValue"), outputWS, prog);
    }

    setProperty("OutputWorkspace",outputWS);
  }
Example #22
0
void Qxy::exec()
{
  MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");
  MatrixWorkspace_const_sptr waveAdj = getProperty("WavelengthAdj");
  MatrixWorkspace_const_sptr pixelAdj = getProperty("PixelAdj");
  const bool doGravity = getProperty("AccountForGravity");
  const bool doSolidAngle = getProperty("SolidAngleWeighting");

  //throws if we don't have common binning or another incompatibility
  Qhelper helper;
  helper.examineInput(inputWorkspace, waveAdj, pixelAdj);
  g_log.debug() << "All input workspaces were found to be valid\n";

  // Create the output Qx-Qy grid
  MatrixWorkspace_sptr outputWorkspace = this->setUpOutputWorkspace(inputWorkspace);

  // Will also need an identically-sized workspace to hold the solid angle/time bin masked weight
  MatrixWorkspace_sptr weights = WorkspaceFactory::Instance().create(outputWorkspace);
  // Copy the X values from the output workspace to the solidAngles one
  cow_ptr<MantidVec> axis;
  axis.access() = outputWorkspace->readX(0);
  for ( size_t i = 0; i < weights->getNumberHistograms(); ++i ) weights->setX(i,axis);
  
  const size_t numSpec = inputWorkspace->getNumberHistograms();
  const size_t numBins = inputWorkspace->blocksize();
  
  // the samplePos is often not (0, 0, 0) because the instruments components are moved to account for the beam centre
  const V3D samplePos = inputWorkspace->getInstrument()->getSample()->getPos();
  
  // Set the progress bar (1 update for every one percent increase in progress)
  Progress prog(this, 0.05, 1.0, numSpec);

//  PARALLEL_FOR2(inputWorkspace,outputWorkspace)
  for (int64_t i = 0; i < int64_t(numSpec); ++i)
  {
//    PARALLEL_START_INTERUPT_REGION
    // Get the pixel relating to this spectrum
    IDetector_const_sptr det;
    try {
      det = inputWorkspace->getDetector(i);
    } catch (Exception::NotFoundError&) {
      g_log.warning() << "Spectrum index " << i << " has no detector assigned to it - discarding" << std::endl;
      // Catch if no detector. Next line tests whether this happened - test placed
      // outside here because Mac Intel compiler doesn't like 'continue' in a catch
      // in an openmp block.
    }
    // If no detector found or if it's masked or a monitor, skip onto the next spectrum
    if ( !det || det->isMonitor() || det->isMasked() ) continue;
    
    //get the bins that are included inside the RadiusCut/WaveCutcut off, those to calculate for
    const size_t wavStart = helper.waveLengthCutOff(inputWorkspace, getProperty("RadiusCut"), getProperty("WaveCut"), i);
    if (wavStart >=  inputWorkspace->readY(i).size())
    {
      // all the spectra in this detector are out of range
      continue;
    }


    V3D detPos = det->getPos()-samplePos;
      
    // these will be re-calculated if gravity is on but without gravity there is no need
    double phi = atan2(detPos.Y(),detPos.X());
    double a = cos(phi);
    double b = sin(phi);
    double sinTheta = sin( inputWorkspace->detectorTwoTheta(det)/2.0 );

    // Get references to the data for this spectrum
    const MantidVec& X = inputWorkspace->readX(i);
    const MantidVec& Y = inputWorkspace->readY(i);
    const MantidVec& E = inputWorkspace->readE(i);
 
    const MantidVec& axis = outputWorkspace->readX(0);

    // the solid angle of the detector as seen by the sample is used for normalisation later on
    double angle = det->solidAngle(samplePos);

    // some bins are masked completely or partially, the following vector will contain the fractions
    MantidVec maskFractions;
    if ( inputWorkspace->hasMaskedBins(i) )
    {
      // go through the set and convert it to a vector
      const MatrixWorkspace::MaskList& mask = inputWorkspace->maskedBins(i);
      maskFractions.resize(numBins, 1.0);
      MatrixWorkspace::MaskList::const_iterator it, itEnd(mask.end());
      for (it = mask.begin(); it != itEnd; ++it)
      {
        // The weight for this masked bin is 1 minus the degree to which this bin is masked
        maskFractions[it->first] -= it->second;
      }
    }
    double maskFraction(1);
    
    // this object is not used if gravity correction is off, but it is only constructed once per spectrum
    GravitySANSHelper grav;
    if (doGravity)
    {
      grav = GravitySANSHelper(inputWorkspace, det);
    }

    
    for (int j = static_cast<int>(numBins)-1; j >= static_cast<int>(wavStart); --j)
    {
      if( j < 0 ) break; // Be careful with counting down. Need a better fix but this will work for now
      const double binWidth = X[j+1]-X[j];
      // Calculate the wavelength at the mid-point of this bin
      const double wavLength = X[j]+(binWidth)/2.0;
      
      if (doGravity)
      {
        // SANS instruments must have their y-axis pointing up, show the detector position as where the neutron would be without gravity
        sinTheta = grav.calcComponents(wavLength, a, b);
      }

      // Calculate |Q| for this bin
      const double Q = 4.0*M_PI*sinTheta/wavLength;

      // Now get the x & y components of Q.
      const double Qx = a*Q;
      // Test whether they're in range, if not go to next spectrum.
      if ( Qx < axis.front() || Qx >= axis.back() ) break;
      const double Qy = b*Q;
      if ( Qy < axis.front() || Qy >= axis.back() ) break;
      // Find the indices pointing to the place in the 2D array where this bin's contents should go
      const MantidVec::difference_type xIndex = std::upper_bound(axis.begin(),axis.end(),Qx) - axis.begin() - 1;
      const int yIndex = static_cast<int>(
        std::upper_bound(axis.begin(),axis.end(),Qy) - axis.begin() - 1);
//      PARALLEL_CRITICAL(qxy)    /* Write to shared memory - must protect */
      {
        // the data will be copied to this bin in the output array
        double & outputBinY = outputWorkspace->dataY(yIndex)[xIndex];
        double & outputBinE = outputWorkspace->dataE(yIndex)[xIndex];

        if ( boost::math::isnan(outputBinY))
        {
          outputBinY = outputBinE = 0;
        }
        // Add the contents of the current bin to the 2D array.
        outputBinY += Y[j];
        // add the errors in quadranture
        outputBinE = std::sqrt( (outputBinE*outputBinE) + (E[j]*E[j]) );
        
        // account for masked bins
        if ( ! maskFractions.empty() )
        {
          maskFraction = maskFractions[j];
        }
        // add the total weight for this bin in the weights workspace, 
        // in an equivalent bin to where the data was stored

        // first take into account the product of contributions to the weight which have
        // no errors
        double weight = 0.0;
        if(doSolidAngle)
          weight = maskFraction*angle; 
        else
          weight = maskFraction;
        
        // then the product of contributions which have errors, i.e. optional 
        // pixelAdj and waveAdj contributions

        if (pixelAdj && waveAdj)
        {
          weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0]*waveAdj->readY(0)[j];
          const double pixelYSq = pixelAdj->readY(i)[0]*pixelAdj->readY(i)[0];
          const double pixelESq = pixelAdj->readE(i)[0]*pixelAdj->readE(i)[0]; 
          const double waveYSq = waveAdj->readY(0)[j]*waveAdj->readY(0)[j];
          const double waveESq = waveAdj->readE(0)[j]*waveAdj->readE(0)[j];
          // add product of errors from pixelAdj and waveAdj (note no error on weight is assumed)   
          weights->dataE(yIndex)[xIndex] += weight*weight*(waveESq*pixelYSq + pixelESq*waveYSq);
        }
        else if (pixelAdj)
        {
          weights->dataY(yIndex)[xIndex] += weight*pixelAdj->readY(i)[0];
          const double pixelE = weight*pixelAdj->readE(i)[0]; 
          // add error from pixelAdj
          weights->dataE(yIndex)[xIndex] += pixelE*pixelE;
        }
        else if(waveAdj)
        {
          weights->dataY(yIndex)[xIndex] += weight*waveAdj->readY(0)[j];
          const double waveE = weight*waveAdj->readE(0)[j]; 
          // add error from waveAdj
          weights->dataE(yIndex)[xIndex] += waveE*waveE;
        }
        else
          weights->dataY(yIndex)[xIndex] += weight;
        

      }
    } // loop over single spectrum
    
    prog.report("Calculating Q");

//    PARALLEL_END_INTERUPT_REGION
  } // loop over all spectra
//  PARALLEL_CHECK_INTERUPT_REGION

  // take sqrt of error weight values
  // left to be executed here for computational efficiency
  size_t numHist = weights->getNumberHistograms();
  for (size_t i = 0; i < numHist; i++)
  {
    for (size_t j = 0; j < weights->dataE(i).size(); j++)
    {
      weights->dataE(i)[j] = sqrt(weights->dataE(i)[j]);
    } 
  }

  bool doOutputParts = getProperty("OutputParts");
  if (doOutputParts)
  {
    // copy outputworkspace before it gets further modified
    MatrixWorkspace_sptr ws_sumOfCounts = WorkspaceFactory::Instance().create(outputWorkspace);
    for (size_t i = 0; i < ws_sumOfCounts->getNumberHistograms(); i++)
    {
      ws_sumOfCounts->dataX(i) = outputWorkspace->dataX(i);
      ws_sumOfCounts->dataY(i) = outputWorkspace->dataY(i);
      ws_sumOfCounts->dataE(i) = outputWorkspace->dataE(i);
    }  

    helper.outputParts(this, ws_sumOfCounts, weights);
  }

  // Divide the output data by the solid angles
  outputWorkspace /= weights;
  outputWorkspace->isDistribution(true);

  
  // Count of the number of empty cells
  MatrixWorkspace::const_iterator wsIt(*outputWorkspace);
  int emptyBins = 0;
  for (;wsIt != wsIt.end(); ++wsIt)
  {
      if (wsIt->Y() < 1.0e-12) ++emptyBins;
  }
  // Log the number of empty bins
  g_log.notice() << "There are a total of " << emptyBins << " (" 
                 << (100*emptyBins)/(outputWorkspace->size()) << "%) empty Q bins.\n"; 
}
Example #23
0
void EQSANSMonitorTOF::exec()
{
  MatrixWorkspace_const_sptr inputWS = getProperty("InputWorkspace");

  // Now create the output workspace
  MatrixWorkspace_sptr outputWS = getProperty("OutputWorkspace");
  if ( outputWS != inputWS )
  {
    outputWS = WorkspaceFactory::Instance().create(inputWS);
    setProperty("OutputWorkspace",outputWS);
  }

  // Get the nominal sample-to-detector distance (in mm)
  // const double MD = MONITORPOS/1000.0;

  // Get the monitor
  const std::vector<detid_t> monitor_list = inputWS->getInstrument()->getMonitors();
  if (monitor_list.size() != 1) {
    g_log.error() << "EQSANS workspace does not have exactly ones monitor! This should not happen" << std::endl;
  }
  IDetector_const_sptr mon;
  try {
    mon = inputWS->getInstrument()->getDetector(monitor_list[0]);
  } catch (Exception::NotFoundError&) {
    g_log.error() << "Spectrum index " << monitor_list[0] << " has no detector assigned to it - discarding" << std::endl;
    return;
  }

  // Get the source to monitor distance in mm
  double source_z = inputWS->getInstrument()->getSource()->getPos().Z();
  double monitor_z = mon->getPos().Z();
  double source_to_monitor = (monitor_z - source_z)*1000.0;

  // Calculate the frame width
  double frequency = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("frequency"))->getStatistics().mean;
  double tof_frame_width = 1.0e6/frequency;

  // Determine whether we need frame skipping or not by checking the chopper speed
  bool frame_skipping = false;
  const double chopper_speed = dynamic_cast<TimeSeriesProperty<double>*>(inputWS->run().getLogData("Speed1"))->getStatistics().mean;
  if (std::fabs(chopper_speed-frequency/2.0)<1.0) frame_skipping = true;

  // Get TOF offset
  // this is the call to the chopper code to say where
  // the start of the data frame is relative to the native facility frame
  double frame_tof0 = getTofOffset(inputWS, frame_skipping, source_to_monitor);

  // Calculate the frame width
  // none of this changes in response to just looking at the monitor
  double tmp_frame_width = frame_skipping ? tof_frame_width * 2.0 : tof_frame_width;
  double frame_offset=0.0;
  if (frame_tof0 >= tmp_frame_width) frame_offset = tmp_frame_width * ( (int)( frame_tof0/tmp_frame_width ) );

  // Find the new binning first
  const MantidVec XIn = inputWS->readX(0); // Copy here to avoid holding on to reference for too long (problem with managed workspaces)

  // Since we are swapping the low-TOF and high-TOF regions around the cutoff value,
  // there is the potential for having an overlap between the two regions. We exclude
  // the region beyond a single frame by considering only the first 1/60 sec of the
  // TOF histogram. (Bins 1 to 1666, as opposed to 1 to 2000)
  const int nTOF = static_cast<int>(XIn.size());

  // Loop through each bin to find the cutoff where the TOF distribution wraps around
  int cutoff = 0;
  double threshold = frame_tof0-frame_offset;
  int tof_bin_range = 0;
  double frame = 1000000.0/frequency;
  for (int i=0; i<nTOF; i++)
  {
      if (XIn[i] < threshold) cutoff = i;
      if (XIn[i] < frame) tof_bin_range = i;
  }
  g_log.information() << "Cutoff=" << cutoff << "; Threshold=" << threshold << std::endl;
  g_log.information() << "Low TOFs: old = [" << (cutoff+1) << ", " << (tof_bin_range-2) << "]  ->  new = [0, " << (tof_bin_range-3-cutoff) << "]" << std::endl;
  g_log.information() << "High bin boundary of the Low TOFs: old = " << tof_bin_range-1 << "; new = " << (tof_bin_range-2-cutoff) << std::endl;
  g_log.information() << "High TOFs: old = [0, " << (cutoff-1) << "]  ->  new = [" << (tof_bin_range-1-cutoff) << ", " << (tof_bin_range-2) << "]" << std::endl;
  g_log.information() << "Overlap: new = [" << (tof_bin_range-1) << ", " << (nTOF-2) << "]" << std::endl;

  // Keep a copy of the input data since we may end up overwriting it
  // if the input workspace is equal to the output workspace.
  // This is necessary since we are shuffling around the TOF bins.
  MantidVec YCopy = MantidVec(inputWS->readY(0));
  MantidVec& YIn = YCopy;
  MantidVec ECopy = MantidVec(inputWS->readE(0));
  MantidVec& EIn = ECopy;

  MantidVec& XOut = outputWS->dataX(0);
  MantidVec& YOut = outputWS->dataY(0);
  MantidVec& EOut = outputWS->dataE(0);

  // Here we modify the TOF according to the offset we calculated.
  // Since this correction will change the order of the TOF bins,
  // we do it in sequence so that we obtain a valid distribution
  // as our result (with increasing TOF values).

  // Move up the low TOFs
  for (int i=0; i<cutoff; i++)
  {
    XOut[i+tof_bin_range-1-cutoff] = XIn[i] + frame_offset + tmp_frame_width;
    YOut[i+tof_bin_range-1-cutoff] = YIn[i];
    EOut[i+tof_bin_range-1-cutoff] = EIn[i];
  }

  // Get rid of extra bins
  for (int i=tof_bin_range-1; i<nTOF-1; i++)
  {
    XOut[i] = XOut[i-1]+10.0;
    YOut[i] = 0.0;
    EOut[i] = 0.0;
  }
  XOut[nTOF-1] = XOut[nTOF-2]+10.0;

  // Move down the high TOFs
  for (int i=cutoff+1; i<tof_bin_range-1; i++)
  {
    XOut[i-cutoff-1] = XIn[i] + frame_offset;
    YOut[i-cutoff-1] = YIn[i];
    EOut[i-cutoff-1] = EIn[i];
  }
  // Don't forget the low boundary
  XOut[tof_bin_range-2-cutoff] = XIn[tof_bin_range] + frame_offset;

  // Zero out the cutoff bin, which no longer makes sense because
  // len(x) = len(y)+1
  YOut[tof_bin_range-2-cutoff] = 0.0;
  EOut[tof_bin_range-2-cutoff] = 0.0;

  setProperty("OutputWorkspace",outputWS);
}
Example #24
0
void SofQWCentre::exec() {
  using namespace Geometry;

  MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");

  // Do the full check for common binning
  if (!WorkspaceHelpers::commonBoundaries(inputWorkspace)) {
    g_log.error(
        "The input workspace must have common binning across all spectra");
    throw std::invalid_argument(
        "The input workspace must have common binning across all spectra");
  }

  std::vector<double> verticalAxis;
  MatrixWorkspace_sptr outputWorkspace = setUpOutputWorkspace(
      inputWorkspace, getProperty("QAxisBinning"), verticalAxis);
  setProperty("OutputWorkspace", outputWorkspace);

  // Holds the spectrum-detector mapping
  std::vector<specnum_t> specNumberMapping;
  std::vector<detid_t> detIDMapping;

  m_EmodeProperties.initCachedValues(*inputWorkspace, this);
  int emode = m_EmodeProperties.m_emode;

  // Get a pointer to the instrument contained in the workspace
  Instrument_const_sptr instrument = inputWorkspace->getInstrument();

  // Get the distance between the source and the sample (assume in metres)
  IComponent_const_sptr source = instrument->getSource();
  IComponent_const_sptr sample = instrument->getSample();
  V3D beamDir = sample->getPos() - source->getPos();
  beamDir.normalize();

  try {
    double l1 = source->getDistance(*sample);
    g_log.debug() << "Source-sample distance: " << l1 << '\n';
  } catch (Exception::NotFoundError &) {
    g_log.error("Unable to calculate source-sample distance");
    throw Exception::InstrumentDefinitionError(
        "Unable to calculate source-sample distance",
        inputWorkspace->getTitle());
  }

  // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV))
  const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass *
                           PhysicalConstants::meV * 1e-20 /
                           (PhysicalConstants::h * PhysicalConstants::h);

  // Loop over input workspace bins, reassigning data to correct bin in output
  // qw workspace
  const size_t numHists = inputWorkspace->getNumberHistograms();
  const size_t numBins = inputWorkspace->blocksize();
  Progress prog(this, 0.0, 1.0, numHists);
  for (int64_t i = 0; i < int64_t(numHists); ++i) {
    try {
      // Now get the detector object for this histogram
      IDetector_const_sptr spectrumDet = inputWorkspace->getDetector(i);
      if (spectrumDet->isMonitor())
        continue;

      const double efixed = m_EmodeProperties.getEFixed(*spectrumDet);

      // For inelastic scattering the simple relationship q=4*pi*sinTheta/lambda
      // does not hold. In order to
      // be completely general we must calculate the momentum transfer by
      // calculating the incident and final
      // wave vectors and then use |q| = sqrt[(ki - kf)*(ki - kf)]
      DetectorGroup_const_sptr detGroup =
          boost::dynamic_pointer_cast<const DetectorGroup>(spectrumDet);
      std::vector<IDetector_const_sptr> detectors;
      if (detGroup) {
        detectors = detGroup->getDetectors();
      } else {
        detectors.push_back(spectrumDet);
      }

      const size_t numDets = detectors.size();
      const double numDets_d = static_cast<double>(
          numDets); // cache to reduce number of static casts
      const MantidVec &Y = inputWorkspace->readY(i);
      const MantidVec &E = inputWorkspace->readE(i);
      const MantidVec &X = inputWorkspace->readX(i);

      // Loop over the detectors and for each bin calculate Q
      for (size_t idet = 0; idet < numDets; ++idet) {
        IDetector_const_sptr det = detectors[idet];
        // Calculate kf vector direction and then Q for each energy bin
        V3D scatterDir = (det->getPos() - sample->getPos());
        scatterDir.normalize();
        for (size_t j = 0; j < numBins; ++j) {
          const double deltaE = 0.5 * (X[j] + X[j + 1]);
          // Compute ki and kf wave vectors and therefore q = ki - kf
          double ei(0.0), ef(0.0);
          if (emode == 1) {
            ei = efixed;
            ef = efixed - deltaE;
            if (ef < 0) {
              std::string mess =
                  "Energy transfer requested in Direct mode exceeds incident "
                  "energy.\n Found for det ID: " +
                  std::to_string(idet) + " bin No " + std::to_string(j) +
                  " with Ei=" + boost::lexical_cast<std::string>(efixed) +
                  " and energy transfer: " +
                  boost::lexical_cast<std::string>(deltaE);
              throw std::runtime_error(mess);
            }
          } else {
            ei = efixed + deltaE;
            ef = efixed;
            if (ef < 0) {
              std::string mess =
                  "Incident energy of a neutron is negative. Are you trying to "
                  "process Direct data in Indirect mode?\n Found for det ID: " +
                  std::to_string(idet) + " bin No " + std::to_string(j) +
                  " with efied=" + boost::lexical_cast<std::string>(efixed) +
                  " and energy transfer: " +
                  boost::lexical_cast<std::string>(deltaE);
              throw std::runtime_error(mess);
            }
          }

          if (ei < 0)
            throw std::runtime_error(
                "Negative incident energy. Check binning.");

          const V3D ki = beamDir * sqrt(energyToK * ei);
          const V3D kf = scatterDir * (sqrt(energyToK * (ef)));
          const double q = (ki - kf).norm();

          // Test whether it's in range of the Q axis
          if (q < verticalAxis.front() || q > verticalAxis.back())
            continue;
          // Find which q bin this point lies in
          const MantidVec::difference_type qIndex =
              std::upper_bound(verticalAxis.begin(), verticalAxis.end(), q) -
              verticalAxis.begin() - 1;

          // Add this spectra-detector pair to the mapping
          specNumberMapping.push_back(
              outputWorkspace->getSpectrum(qIndex).getSpectrumNo());
          detIDMapping.push_back(det->getID());

          // And add the data and it's error to that bin, taking into account
          // the number of detectors contributing to this bin
          outputWorkspace->dataY(qIndex)[j] += Y[j] / numDets_d;
          // Standard error on the average
          outputWorkspace->dataE(qIndex)[j] =
              sqrt((pow(outputWorkspace->readE(qIndex)[j], 2) + pow(E[j], 2)) /
                   numDets_d);
        }
      }

    } catch (Exception::NotFoundError &) {
      // Get to here if exception thrown when calculating distance to detector
      // Presumably, if we get to here the spectrum will be all zeroes anyway
      // (from conversion to E)
      continue;
    }
    prog.report();
  }

  // If the input workspace was a distribution, need to divide by q bin width
  if (inputWorkspace->isDistribution())
    this->makeDistribution(outputWorkspace, verticalAxis);

  // Set the output spectrum-detector mapping
  SpectrumDetectorMapping outputDetectorMap(specNumberMapping, detIDMapping);
  outputWorkspace->updateSpectraUsing(outputDetectorMap);
}
Example #25
0
/** Executes the regroup algorithm
 *
 *  @throw runtime_error Thrown if
 */
void Regroup::exec()
{
  // retrieve the properties
  std::vector<double> rb_params=getProperty("Params");

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

  // can work only if all histograms have the same boundaries
  if (!API::WorkspaceHelpers::commonBoundaries(inputW))
  {
    g_log.error("Histograms with different boundaries");
    throw std::runtime_error("Histograms with different boundaries");
  }

  bool dist = inputW->isDistribution();

  int histnumber = static_cast<int>(inputW->getNumberHistograms());
  MantidVecPtr XValues_new;
  const MantidVec & XValues_old = inputW->readX(0);
  std::vector<int> xoldIndex;// indeces of new x in XValues_old
  // create new output X axis
  int ntcnew = newAxis(rb_params,XValues_old,XValues_new.access(),xoldIndex);

  // make output Workspace the same type is the input, but with new length of signal array
  API::MatrixWorkspace_sptr outputW = API::WorkspaceFactory::Instance().create(inputW,histnumber,ntcnew,ntcnew-1);

  int progress_step = histnumber / 100;
  if (progress_step == 0) progress_step = 1;
  for (int hist=0; hist <  histnumber;hist++)
  {
    // get const references to input Workspace arrays (no copying)
    const MantidVec& XValues = inputW->readX(hist);
    const MantidVec& YValues = inputW->readY(hist);
    const MantidVec& YErrors = inputW->readE(hist);

    //get references to output workspace data (no copying)
    MantidVec& YValues_new=outputW->dataY(hist);
    MantidVec& YErrors_new=outputW->dataE(hist);

    // output data arrays are implicitly filled by function
    rebin(XValues,YValues,YErrors,xoldIndex,YValues_new,YErrors_new, dist);

    outputW->setX(hist,XValues_new);

    if (hist % progress_step == 0)
    {
        progress(double(hist)/histnumber);
        interruption_point();
    }
  }

  outputW->isDistribution(dist);

  // Copy units
  if (outputW->getAxis(0)->unit().get())
    outputW->getAxis(0)->unit() = inputW->getAxis(0)->unit();
  try
  {
    if (inputW->getAxis(1)->unit().get())
      outputW->getAxis(1)->unit() = inputW->getAxis(1)->unit();
   }
  catch(Exception::IndexError) {
    // OK, so this isn't a Workspace2D
  }

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

  return;
}
Example #26
0
void SmoothData::exec()
{
  // Get the input properties
  MatrixWorkspace_const_sptr inputWorkspace = getProperty("InputWorkspace");

  int npts = getProperty("NPoints");
  // Number of smoothing points must always be an odd number, so add 1 if it isn't.
  if (!(npts%2))
  {
    g_log.information("Adding 1 to number of smoothing points, since it must always be odd");
    ++npts;
  }

  // Check that the number of points in the smoothing isn't larger than the spectrum length
  const int vecSize = static_cast<int>(inputWorkspace->blocksize());
  if ( npts >= vecSize )
  {
    g_log.error("The number of averaging points requested is larger than the spectrum length");
    throw std::out_of_range("The number of averaging points requested is larger than the spectrum length");
  }
  const int halfWidth = (npts-1)/2;

  // Create the output workspace
  MatrixWorkspace_sptr outputWorkspace = WorkspaceFactory::Instance().create(inputWorkspace);

  Progress progress(this,0.0,1.0,inputWorkspace->getNumberHistograms());
  PARALLEL_FOR2(inputWorkspace,outputWorkspace)
  // Loop over all the spectra in the workspace
  for (int i = 0; i < static_cast<int>(inputWorkspace->getNumberHistograms()); ++i)
  {
    PARALLEL_START_INTERUPT_REGION
    // Copy the X data over. Preserves data sharing if present in input workspace.
    outputWorkspace->setX(i,inputWorkspace->refX(i));

    // Now get references to the Y & E vectors in the input and output workspaces
    const MantidVec &Y = inputWorkspace->readY(i);
    const MantidVec &E = inputWorkspace->readE(i);
    MantidVec &newY = outputWorkspace->dataY(i);
    MantidVec &newE = outputWorkspace->dataE(i);

    // Use total to help hold our moving average
    double total = 0.0, totalE = 0.0;
    // First push the values ahead of the current point onto total
    for (int i = 0; i < halfWidth; ++i)
    {
      if ( Y[i] == Y[i] ) total += Y[i]; // Exclude if NaN
      totalE += E[i]*E[i];
    }
    // Now calculate the smoothed values for the 'end' points, where the number contributing
    // to the smoothing will be less than NPoints
    for (int j = 0; j <= halfWidth; ++j)
    {
      const int index = j+halfWidth;
      if ( Y[index] == Y[index] ) total += Y[index]; // Exclude if NaN
      newY[j] = total/(index+1);
      totalE += E[index]*E[index];
      newE[j] = sqrt(totalE)/(index+1);
    }
    // This is the main part, where each data point is the average of NPoints points centred on the
    // current point. Note that the statistical error will be reduced by sqrt(npts) because more
    // data is now contributing to each point.
    for (int k = halfWidth+1; k < vecSize-halfWidth; ++k)
    {
      const int kp = k+halfWidth;
      const int km = k-halfWidth-1;
      total += (Y[kp]!=Y[kp] ? 0.0 : Y[kp]) - (Y[km]!=Y[km] ? 0.0 : Y[km]); // Exclude if NaN
      newY[k] = total/npts;
      totalE += E[kp]*E[kp] - E[km]*E[km];
      // Use of a moving average can lead to rounding error where what should be 
      // zero actually comes out as a tiny negative number - bad news for sqrt so protect
      newE[k] = std::sqrt(std::abs(totalE))/npts;
    }
    // This deals with the 'end' at the tail of each spectrum
    for (int l = vecSize-halfWidth; l < vecSize; ++l)
    {
      const int index = l-halfWidth;
      total -= (Y[index-1]!=Y[index-1] ? 0.0 : Y[index-1]); // Exclude if NaN
      newY[l] = total/(vecSize-index);
      totalE -= E[index-1]*E[index-1];
      newE[l] = std::sqrt(std::abs(totalE))/(vecSize-index);
    }
    progress.report();
    PARALLEL_END_INTERUPT_REGION
  } // Loop over spectra
  PARALLEL_CHECK_INTERUPT_REGION

  // Set the output workspace to its property
  setProperty("OutputWorkspace", outputWorkspace);
}