Пример #1
0
/** Read the specified number of entries from input file into the
*  the array that is passed
*  @param[in] nEntries the number of numbers to read
*  @param[out] output the contents of this will be replaced by the data read from the file
*/
void LoadRKH::readNumEntrys(const int nEntries, MantidVec & output)
{
    output.resize(nEntries);
    for( int i = 0; i < nEntries; ++i )
    {
        m_fileIn >> output[i];
    }
}
Пример #2
0
/** Load the event_workspace field
 *
 * @param wksp_cls
 * @param progressStart
 * @param progressRange
 * @return
 */
API::MatrixWorkspace_sptr LoadNexusProcessed::loadEventEntry(NXData & wksp_cls, NXDouble & xbins,
    const double& progressStart, const double& progressRange)
{
  NXDataSetTyped<int64_t> indices_data = wksp_cls.openNXDataSet<int64_t>("indices");
  indices_data.load();
  boost::shared_array<int64_t> indices = indices_data.sharedBuffer();
  int numspec = indices_data.dim0()-1;

  int num_xbins = xbins.dim0();
  if (num_xbins < 2) num_xbins = 2;
  EventWorkspace_sptr ws = boost::dynamic_pointer_cast<EventWorkspace>
  (WorkspaceFactory::Instance().create("EventWorkspace", numspec, num_xbins, num_xbins-1));

  // Set the YUnit label
  ws->setYUnit(indices_data.attributes("units"));
  std::string unitLabel = indices_data.attributes("unit_label");
  if (unitLabel.empty()) unitLabel = indices_data.attributes("units");
  ws->setYUnitLabel(unitLabel);

  //Handle optional fields.
  // TODO: Handle inconsistent sizes
  boost::shared_array<int64_t> pulsetimes;
  if (wksp_cls.isValid("pulsetime"))
  {
    NXDataSetTyped<int64_t> pulsetime = wksp_cls.openNXDataSet<int64_t>("pulsetime");
    pulsetime.load();
    pulsetimes = pulsetime.sharedBuffer();
  }

  boost::shared_array<double> tofs;
  if (wksp_cls.isValid("tof"))
  {
    NXDouble tof = wksp_cls.openNXDouble("tof");
    tof.load();
    tofs = tof.sharedBuffer();
  }

  boost::shared_array<float> error_squareds;
  if (wksp_cls.isValid("error_squared"))
  {
    NXFloat error_squared = wksp_cls.openNXFloat("error_squared");
    error_squared.load();
    error_squareds = error_squared.sharedBuffer();
  }

  boost::shared_array<float> weights;
  if (wksp_cls.isValid("weight"))
  {
    NXFloat weight = wksp_cls.openNXFloat("weight");
    weight.load();
    weights = weight.sharedBuffer();
  }

  // What type of event lists?
  EventType type = TOF;
  if (tofs && pulsetimes && weights && error_squareds)
    type = WEIGHTED;
  else if ((tofs && weights && error_squareds))
    type = WEIGHTED_NOTIME;
  else if (pulsetimes && tofs)
    type = TOF;
  else
    throw std::runtime_error("Could not figure out the type of event list!");

  // Create all the event lists
  PARALLEL_FOR_NO_WSP_CHECK()
  for (int wi=0; wi < numspec; wi++)
  {
    PARALLEL_START_INTERUPT_REGION
    int64_t index_start = indices[wi];
    int64_t index_end = indices[wi+1];
    if (index_end >= index_start)
    {
      EventList & el = ws->getEventList(wi);
      el.switchTo(type);

      // Allocate all the required memory
      el.reserve(index_end - index_start);
      el.clearDetectorIDs();

      for (long i=index_start; i<index_end; i++)
      switch (type)
      {
      case TOF:
        el.addEventQuickly( TofEvent( tofs[i], DateAndTime(pulsetimes[i])) );
        break;
      case WEIGHTED:
        el.addEventQuickly( WeightedEvent( tofs[i], DateAndTime(pulsetimes[i]), weights[i], error_squareds[i]) );
        break;
      case WEIGHTED_NOTIME:
        el.addEventQuickly( WeightedEventNoTime( tofs[i], weights[i], error_squareds[i]) );
        break;
      }

      // Set the X axis
      if (this->m_shared_bins)
        el.setX(this->m_xbins);
      else
      {
        MantidVec x;
        x.resize(xbins.dim0());
        for (int i=0; i < xbins.dim0(); i++)
          x[i] = xbins(wi, i);
        el.setX(x);
      }
    }

    progress(progressStart + progressRange*(1.0/numspec));
    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION

  // Clean up some stuff
  ws->doneAddingEventLists();

  return ws;
}
Пример #3
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"; 
}
Пример #4
0
/** Reads the header information from a file containing 2D data
*  @param[in] initalLine the second line in the file
*  @param[out] outWrksp the workspace that the data will be writen to
*  @param[out] axis0Data x-values for the workspace
*  @return a progress bar object
*  @throw NotFoundError if there is compulsulary data is missing from the file
*  @throw invalid_argument if there is an inconsistency in the header information
*/
Progress LoadRKH::read2DHeader(const std::string & initalLine, MatrixWorkspace_sptr & outWrksp, MantidVec & axis0Data)
{
    const std::string XUnit(readUnit(initalLine));

    std::string fileLine;
    std::getline(m_fileIn, fileLine);
    const std::string YUnit(readUnit(fileLine));

    std::getline(m_fileIn, fileLine);
    const std::string intensityUnit(readUnit(fileLine));

    // the next line should contain just "1", but I'm not enforcing that
    std::getline(m_fileIn, fileLine);
    std::string title;
    std::getline(m_fileIn, title);

    std::getline(m_fileIn, fileLine);
    boost::trim(fileLine);
    const int nAxis0Boundaries = boost::lexical_cast<int>(fileLine);
    axis0Data.resize(nAxis0Boundaries);
    readNumEntrys(nAxis0Boundaries, axis0Data);

    std::getline(m_fileIn, fileLine);
    boost::trim(fileLine);
    int nAxis1Boundaries;
    try
    {
        nAxis1Boundaries = boost::lexical_cast<int>(fileLine);
    }
    catch(boost::bad_lexical_cast &)
    {
        // using readNumEntrys() above broke the sequence of getline()s and so try again in case we just read the end of a line
        std::getline(m_fileIn, fileLine);
        boost::trim(fileLine);
        nAxis1Boundaries = boost::lexical_cast<int>(fileLine);
    }
    MantidVec axis1Data(nAxis1Boundaries);
    readNumEntrys(nAxis1Boundaries, axis1Data);

    std::getline(m_fileIn, fileLine);
    // check for the file pointer being left at the end of a line
    if ( fileLine.size() < 5 )
    {
        std::getline(m_fileIn, fileLine);
    }
    Poco::StringTokenizer wsDimensions(fileLine, " ",
                                       Poco::StringTokenizer::TOK_TRIM);
    if ( wsDimensions.count() < 2 )
    {
        throw Exception::NotFoundError("Input file", "dimensions");
    }
    const int nAxis0Values = boost::lexical_cast<int>(wsDimensions[0]);
    const int nAxis1Values = boost::lexical_cast<int>(wsDimensions[1]);

    Progress prog(this, 0.05, 1.0, 2*nAxis1Values);

    // we now have all the data we need to create the output workspace
    outWrksp = WorkspaceFactory::Instance().create(
                   "Workspace2D", nAxis1Values, nAxis0Boundaries, nAxis0Values);
    outWrksp->getAxis(0)->unit() = UnitFactory::Instance().create(XUnit);
    outWrksp->setYUnitLabel(intensityUnit);

    NumericAxis* const axis1 = new Mantid::API::NumericAxis(nAxis1Boundaries);
    axis1->unit() = Mantid::Kernel::UnitFactory::Instance().create(YUnit);
    outWrksp->replaceAxis(1, axis1);
    for ( int i = 0; i < nAxis1Boundaries; ++i )
    {
        axis1->setValue(i, axis1Data[i]);
    }


    outWrksp->setTitle(title);
    // move over the next line which is there to help with loading from Fortran routines
    std::getline(m_fileIn, fileLine);

    return prog;
}
Пример #5
0
/**
 * Get a data array covering the specified range of data, at the specified
 * resolution.  NOTE: The calling code is responsible for deleting the
 * DataArray that is constructed in and returned by this method.
 *
 * @param xMin    Left edge of region to be covered.
 * @param xMax    Right edge of region to be covered.
 * @param yMin    Bottom edge of region to be covered.
 * @param yMax    Top edge of region to be covered.
 * @param numRows Number of rows to return. If the number of rows is less
 *                than the actual number of data rows in [yMin,yMax], the
 *                data will be subsampled, and only the specified number
 *                of rows will be returned.
 * @param numCols The specrum data will be rebinned using the specified
 *                number of colums.
 * @param isLogX  Flag indicating whether or not the data should be
 *                binned logarithmically.
 */
DataArray_const_sptr MatrixWSDataSource::getDataArray( double xMin,    double  xMax,
                                                       double yMin,    double  yMax,
                                                       size_t numRows, size_t  numCols,
                                                       bool   isLogX )
{
  /* Since we're rebinning, the columns can be arbitrary */
  /* but rows must be aligned to get whole spectra */
  size_t first_row;
  SVUtils::CalculateInterval( m_totalYMin, m_totalYMax, m_totalRows,
                              first_row, yMin, yMax, numRows );

  std::vector<float> newData(numRows * numCols);

  MantidVec xScale;
  xScale.resize(numCols + 1);
  if ( isLogX )
  {
    for ( size_t i = 0; i < numCols+1; i++ )
    {
      xScale[i] = xMin * exp ( (double)i / (double)numCols * log(xMax/xMin) );
    }
  }
  else
  {
    double dx = (xMax - xMin) / ((double)numCols + 1.0);
    for ( size_t i = 0; i < numCols+1; i++ )
    {
      xScale[i] = xMin + (double)i * dx;
    }
  }

  // Choose spectra from required range of spectrum indexes
  double yStep = (yMax - yMin) / (double)numRows;
  double dYIndex;

  MantidVec yVals;
  MantidVec err;
  yVals.resize(numCols);
  err.resize(numCols);
  size_t index = 0;
  for ( size_t i = 0; i < numRows; i++ )
  {
    double midY = yMin + ((double)i + 0.5) * yStep;
    SVUtils::Interpolate( m_totalYMin, m_totalYMax,         midY,
                          0.0,         (double)m_totalRows, dYIndex );
    size_t sourceRow = (size_t)dYIndex;
    yVals.clear();
    err.clear();
    yVals.resize(numCols, 0);
    err.resize(numCols, 0);

    m_matWs->generateHistogram( sourceRow, xScale, yVals, err, true );
    for ( size_t col = 0; col < numCols; col++ )
    {
      newData[index] = (float)yVals[col];
      index++;
    }
  }

  // The calling code is responsible for deleting the DataArray when it is done with it
  DataArray_const_sptr newDataArray( new DataArray( xMin, xMax, yMin, yMax,
                                                    isLogX,
                                                    numRows, numCols,
                                                    newData) );

  return newDataArray;
}