Beispiel #1
0
size_t MaskPeaksWorkspace::getWkspIndex(const detid2index_map &pixel_to_wi,
                                        Geometry::IComponent_const_sptr comp,
                                        const int x, const int y) {
  Geometry::RectangularDetector_const_sptr det =
      boost::dynamic_pointer_cast<const Geometry::RectangularDetector>(comp);
  if (det) {
    if (x >= det->xpixels() || x < 0 || y >= det->ypixels() || y < 0)
      return EMPTY_INT();
    if ((x >= det->xpixels()) ||
        (x < 0) // this check is unnecessary as callers are doing it too
        || (y >= det->ypixels()) ||
        (y < 0)) // but just to make debugging easier
    {
      std::stringstream msg;
      msg << "Failed to find workspace index for x=" << x << " y=" << y
          << "(max x=" << det->xpixels() << ", max y=" << det->ypixels() << ")";
      throw std::runtime_error(msg.str());
    }

    int pixelID = det->getAtXY(x, y)->getID();

    // Find the corresponding workspace index, if any
    auto wiEntry = pixel_to_wi.find(pixelID);
    if (wiEntry == pixel_to_wi.end()) {
      std::stringstream msg;
      msg << "Failed to find workspace index for x=" << x << " y=" << y;
      throw std::runtime_error(msg.str());
    }
    return wiEntry->second;
  } else {
    std::vector<Geometry::IComponent_const_sptr> children;
    boost::shared_ptr<const Geometry::ICompAssembly> asmb =
        boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(comp);
    asmb->getChildren(children, false);
    boost::shared_ptr<const Geometry::ICompAssembly> asmb2 =
        boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(children[0]);
    std::vector<Geometry::IComponent_const_sptr> grandchildren;
    asmb2->getChildren(grandchildren, false);
    int NROWS = static_cast<int>(grandchildren.size());
    int NCOLS = static_cast<int>(children.size());
    // Wish pixels and tubes start at 1 not 0
    if (x - 1 >= NCOLS || x - 1 < 0 || y - 1 >= NROWS || y - 1 < 0)
      return EMPTY_INT();
    std::string bankName = comp->getName();
    detid2index_map::const_iterator it =
        pixel_to_wi.find(findPixelID(bankName, x, y));
    if (it == pixel_to_wi.end())
      return EMPTY_INT();
    return (it->second);
  }
}
/* Set workspace->group ID map by detectors (range)
 *
 */
void LoadDetectorsGroupingFile::setByDetectors() {

  // 0. Check
  if (!m_instrument && m_groupDetectorsMap.size() > 0) {
    std::map<int, std::vector<detid_t>>::iterator mapiter;
    bool norecord = true;
    for (mapiter = m_groupDetectorsMap.begin();
         mapiter != m_groupDetectorsMap.end(); ++mapiter)
      if (mapiter->second.size() > 0) {
        norecord = false;
        g_log.error() << "Instrument is not specified in XML file. "
                      << "But tag 'detid' is used in XML file for Group "
                      << mapiter->first << ". It is not allowed. " << std::endl;
        break;
      }

    if (!norecord)
      throw std::invalid_argument(
          "XML definition involving detectors causes error");
  }

  // 1. Prepare
  const detid2index_map indexmap =
      m_groupWS->getDetectorIDToWorkspaceIndexMap(true);

  // 2. Set GroupingWorkspace
  for (auto &detectorMap : m_groupDetectorsMap) {
    g_log.debug() << "Group ID = " << detectorMap.first << std::endl;

    for (auto detid : detectorMap.second) {
      auto itx = indexmap.find(detid);

      if (itx != indexmap.end()) {
        size_t wsindex = itx->second;
        m_groupWS->dataY(wsindex)[0] = detectorMap.first;
      } else {
        g_log.error() << "Pixel w/ ID = " << detid << " Cannot Be Located"
                      << std::endl;
      }
    } // ENDFOR detid (in range)
  }   // ENDFOR each group ID

  return;
}
Beispiel #3
0
/**  Mask detectors or Unmask detectors
 *   @param indexmap: spectraId to spectraNum map used
 *                   in masking
 *   @param tomask:  true to mask, false to unmask
 *   @param singledetids: list of individual det ids to mask
 */
void LoadMask::processMaskOnDetectors(
    const detid2index_map &indexmap, bool tomask,
    const std::vector<detid_t> &singledetids) {
  // 1. Get index map
  // 2. Mask
  g_log.debug() << "Mask = " << tomask
                << "  Final Single IDs Size = " << singledetids.size() << '\n';

  for (auto detid : singledetids) {
    detid2index_map::const_iterator it;
    it = indexmap.find(detid);
    if (it != indexmap.end()) {
      size_t index = it->second;
      m_maskWS->mutableY(index)[0] = (tomask) ? 1 : 0;
    } else {
      g_log.warning() << "Pixel w/ ID = " << detid << " Cannot Be Located\n";
    }
  }
}
/** Calculate (all) detectors' offsets
  */
void GetDetOffsetsMultiPeaks::calculateDetectorsOffsets() {
  int nspec = static_cast<int>(m_inputWS->getNumberHistograms());

  // To get the workspace index from the detector ID
  const detid2index_map pixel_to_wi =
      m_maskWS->getDetectorIDToWorkspaceIndexMap(true);

  // Fit all the spectra with a gaussian
  Progress prog(this, 0, 1.0, nspec);

  // cppcheck-suppress syntaxError
    PRAGMA_OMP(parallel for schedule(dynamic, 1) )
    for (int wi = 0; wi < nspec; ++wi) {
      PARALLEL_START_INTERUPT_REGION

      std::vector<double> fittedpeakpositions, tofitpeakpositions;
      FitPeakOffsetResult offsetresult =
          calculatePeakOffset(wi, fittedpeakpositions, tofitpeakpositions);

      // Get the list of detectors in this pixel
      const std::set<detid_t> &dets =
          m_inputWS->getSpectrum(wi)->getDetectorIDs();

      // Most of the exec time is in FitSpectra, so this critical block should
      // not be a problem.
      PARALLEL_CRITICAL(GetDetOffsetsMultiPeaks_setValue) {
        // Use the same offset for all detectors from this pixel (in case of
        // summing pixels)
        std::set<detid_t>::iterator it;
        for (it = dets.begin(); it != dets.end(); ++it) {
          // Set value to output peak offset workspace
          m_outputW->setValue(*it, offsetresult.offset, offsetresult.fitSum);

          // Set value to output peak number workspace
          m_outputNP->setValue(*it, offsetresult.peakPosFittedSize,
                               offsetresult.chisqSum);

          // Set value to mask workspace
          const auto mapEntry = pixel_to_wi.find(*it);
          if (mapEntry == pixel_to_wi.end())
            continue;

          const size_t workspaceIndex = mapEntry->second;
          if (offsetresult.mask > 0.9) {
            // Being masked
            m_maskWS->maskWorkspaceIndex(workspaceIndex);
            m_maskWS->dataY(workspaceIndex)[0] = offsetresult.mask;
          } else {
            // Using the detector
            m_maskWS->dataY(workspaceIndex)[0] = offsetresult.mask;

            // check the average value of delta(d)/d.  if it is far off the
            // theorical value, output
            // FIXME - This warning should not appear by filtering out peaks
            // that are too wide or narrow.
            // TODO - Delete the if statement below if it is never triggered.
            if (m_hasInputResolution) {
              double pixelresolution = m_inputResolutionWS->readY(wi)[0];
              if (offsetresult.resolution > 10 * pixelresolution ||
                  offsetresult.resolution < 0.1 * pixelresolution)
                g_log.warning() << "Spectrum " << wi
                                << " delta(d)/d = " << offsetresult.resolution
                                << "\n";
            }
          }
        } // ENDFOR (detectors)

        // Report offset fitting result/status
        addInfoToReportWS(wi, offsetresult, tofitpeakpositions,
                          fittedpeakpositions);

      } // End of critical region

      prog.report();
      PARALLEL_END_INTERUPT_REGION
    }
    PARALLEL_CHECK_INTERUPT_REGION

    return;
}
/** Load a single bank into the workspace
 *
 * @param nexusfilename :: file to open
 * @param entry_name :: NXentry name
 * @param bankName :: NXdata bank name
 * @param WS :: workspace to modify
 * @param id_to_wi :: det ID to workspace index mapping
 */
void LoadTOFRawNexus::loadBank(const std::string &nexusfilename,
                               const std::string &entry_name,
                               const std::string &bankName,
                               API::MatrixWorkspace_sptr WS,
                               const detid2index_map &id_to_wi) {
  g_log.debug() << "Loading bank " << bankName << std::endl;
  // To avoid segfaults on RHEL5/6 and Fedora
  m_fileMutex.lock();

  // Navigate to the point in the file
  auto file = new ::NeXus::File(nexusfilename);
  file->openGroup(entry_name, "NXentry");
  file->openGroup("instrument", "NXinstrument");
  file->openGroup(bankName, "NXdetector");

  size_t m_numPixels = 0;
  std::vector<uint32_t> pixel_id;

  if (!m_assumeOldFile) {
    // Load the pixel IDs
    file->readData("pixel_id", pixel_id);
    m_numPixels = pixel_id.size();
    if (m_numPixels == 0) {
      file->close();
      m_fileMutex.unlock();
      g_log.warning() << "Invalid pixel_id data in " << bankName << std::endl;
      return;
    }
  } else {
    // Load the x and y pixel offsets
    std::vector<float> xoffsets;
    std::vector<float> yoffsets;
    file->readData("x_pixel_offset", xoffsets);
    file->readData("y_pixel_offset", yoffsets);

    m_numPixels = xoffsets.size() * yoffsets.size();
    if (0 == m_numPixels) {
      file->close();
      m_fileMutex.unlock();
      g_log.warning() << "Invalid (x,y) offsets in " << bankName << std::endl;
      return;
    }

    size_t bankNum = 0;
    if (bankName.size() > 4) {
      if (bankName.substr(0, 4) == "bank") {
        bankNum = boost::lexical_cast<size_t>(bankName.substr(4));
        bankNum--;
      } else {
        file->close();
        m_fileMutex.unlock();
        g_log.warning() << "Invalid bank number for " << bankName << std::endl;
        return;
      }
    }

    // All good, so construct the pixel ID listing
    size_t numX = xoffsets.size();
    size_t numY = yoffsets.size();

    for (size_t i = 0; i < numX; i++) {
      for (size_t j = 0; j < numY; j++) {
        pixel_id.push_back(
            static_cast<uint32_t>(j + numY * (i + numX * bankNum)));
      }
    }
  }

  size_t iPart = 0;
  if (m_spec_max != Mantid::EMPTY_INT()) {
    uint32_t ifirst = pixel_id[0];
    range_check out_range(m_spec_min, m_spec_max, id_to_wi);
    auto newEnd = std::remove_if(pixel_id.begin(), pixel_id.end(), out_range);
    pixel_id.erase(newEnd, pixel_id.end());
    // check if beginning or end of array was erased
    if (ifirst != pixel_id[0])
      iPart = m_numPixels - pixel_id.size();
    m_numPixels = pixel_id.size();
    if (m_numPixels == 0) {
      file->close();
      m_fileMutex.unlock();
      g_log.warning() << "No pixels from " << bankName << std::endl;
      return;
    };
  }
  // Load the TOF vector
  std::vector<float> tof;
  file->readData(m_axisField, tof);
  size_t m_numBins = tof.size() - 1;
  if (tof.size() <= 1) {
    file->close();
    m_fileMutex.unlock();
    g_log.warning() << "Invalid " << m_axisField << " data in " << bankName
                    << std::endl;
    return;
  }

  // Make a shared pointer
  MantidVecPtr Xptr;
  MantidVec &X = Xptr.access();
  X.resize(tof.size(), 0);
  X.assign(tof.begin(), tof.end());

  // Load the data. Coerce ints into double.
  std::string errorsField = "";
  std::vector<double> data;
  file->openData(m_dataField);
  file->getDataCoerce(data);
  if (file->hasAttr("errors"))
    file->getAttr("errors", errorsField);
  file->closeData();

  // Load the errors
  bool hasErrors = !errorsField.empty();
  std::vector<double> errors;
  if (hasErrors) {
    try {
      file->openData(errorsField);
      file->getDataCoerce(errors);
      file->closeData();
    } catch (...) {
      g_log.information() << "Error loading the errors field, '" << errorsField
                          << "' for bank " << bankName
                          << ". Will use sqrt(counts). " << std::endl;
      hasErrors = false;
    }
  }

  /*if (data.size() != m_numBins * m_numPixels)
  { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '"
  << m_dataField << "' data in " << bankName << std::endl; return; }
  if (hasErrors && (errors.size() != m_numBins * m_numPixels))
  { file->close(); m_fileMutex.unlock(); g_log.warning() << "Invalid size of '"
  << errorsField << "' errors in " << bankName << std::endl; return; }
*/
  // Have all the data I need
  m_fileMutex.unlock();
  file->close();

  for (size_t i = iPart; i < iPart + m_numPixels; i++) {
    // Find the workspace index for this detector
    detid_t pixelID = pixel_id[i - iPart];
    size_t wi = id_to_wi.find(pixelID)->second;

    // Set the basic info of that spectrum
    ISpectrum *spec = WS->getSpectrum(wi);
    spec->setSpectrumNo(specid_t(wi + 1));
    spec->setDetectorID(pixel_id[i - iPart]);
    // Set the shared X pointer
    spec->setX(X);

    // Extract the Y
    MantidVec &Y = spec->dataY();
    Y.assign(data.begin() + i * m_numBins, data.begin() + (i + 1) * m_numBins);

    MantidVec &E = spec->dataE();

    if (hasErrors) {
      // Copy the errors from the loaded document
      E.assign(errors.begin() + i * m_numBins,
               errors.begin() + (i + 1) * m_numBins);
    } else {
      // Now take the sqrt(Y) to give E
      E = Y;
      std::transform(E.begin(), E.end(), E.begin(), (double (*)(double))sqrt);
    }
  }

  // Done!
}
/*
 * Convert Componenet -> Detector IDs -> Workspace Indices -> set group ID
 */
void LoadDetectorsGroupingFile::setByComponents() {

  // 0. Check
  if (!m_instrument) {
    std::map<int, std::vector<std::string>>::iterator mapiter;
    bool norecord = true;
    for (mapiter = m_groupComponentsMap.begin();
         mapiter != m_groupComponentsMap.end(); ++mapiter) {
      if (mapiter->second.size() > 0) {
        g_log.error() << "Instrument is not specified in XML file.  "
                      << "But tag 'component' is used in XML file for Group "
                      << mapiter->first << " It is not allowed" << std::endl;
        norecord = false;
        break;
      }
    }
    if (!norecord)
      throw std::invalid_argument(
          "XML definition involving component causes error");
  }

  // 1. Prepare
  const detid2index_map indexmap =
      m_groupWS->getDetectorIDToWorkspaceIndexMap(true);

  // 2. Set
  for (auto &componentMap : m_groupComponentsMap) {
    g_log.debug() << "Group ID = " << componentMap.first << " With "
                  << componentMap.second.size() << " Components" << std::endl;

    for (auto &name : componentMap.second) {

      // a) get component
      Geometry::IComponent_const_sptr component =
          m_instrument->getComponentByName(name);

      // b) component -> component assembly --> children (more than detectors)
      boost::shared_ptr<const Geometry::ICompAssembly> asmb =
          boost::dynamic_pointer_cast<const Geometry::ICompAssembly>(component);
      std::vector<Geometry::IComponent_const_sptr> children;
      asmb->getChildren(children, true);

      g_log.debug() << "Component Name = " << name
                    << "  Component ID = " << component->getComponentID()
                    << "Number of Children = " << children.size() << std::endl;

      for (auto child : children) {
        // c) convert component to detector
        Geometry::IDetector_const_sptr det =
            boost::dynamic_pointer_cast<const Geometry::IDetector>(child);

        if (det) {
          // Component is DETECTOR:
          int32_t detid = det->getID();
          auto itx = indexmap.find(detid);
          if (itx != indexmap.end()) {
            size_t wsindex = itx->second;
            m_groupWS->dataY(wsindex)[0] = componentMap.first;
          } else {
            g_log.error() << "Pixel w/ ID = " << detid << " Cannot Be Located"
                          << std::endl;
          }
        } // ENDIF Detector

      } // ENDFOR (children of component)
    }   // ENDFOR (component)

  } // ENDFOR GroupID

  return;
}
Beispiel #7
0
/**
 * Read Event Data
 * @param eventEntries map of the file entries that have events
 * @param nxFile Reads data from inside first top entry
 * @return Names of workspaces to include in the output group
 */
std::vector<std::string> LoadMcStas::readEventData(
    const std::map<std::string, std::string> &eventEntries,
    ::NeXus::File &nxFile) {

  // vector to store output workspaces
  std::vector<std::string> scatteringWSNames;

  std::string filename = getPropertyValue("Filename");
  auto entries = nxFile.getEntries();
  const bool errorBarsSetTo1 = getProperty("ErrorBarsSetTo1");

  // will assume that each top level entry contain one mcstas
  // generated IDF and any event data entries within this top level
  // entry are data collected for that instrument
  // This code for loading the instrument is for now adjusted code from
  // ExperimentalInfo.

  // Close data folder and go back to top level. Then read and close the
  // Instrument folder.
  nxFile.closeGroup();

  Geometry::Instrument_sptr instrument;

  // Initialize progress reporting
  int reports = 2;
  const double progressFractionInitial = 0.1;
  Progress progInitial(this, 0.0, progressFractionInitial, reports);

  std::string instrumentXML;
  progInitial.report("Loading instrument");
  try {
    nxFile.openGroup("instrument", "NXinstrument");
    nxFile.openGroup("instrument_xml", "NXnote");
    nxFile.readData("data", instrumentXML);
    nxFile.closeGroup();
    nxFile.closeGroup();
  } catch (...) {
    g_log.warning()
        << "\nCould not find the instrument description in the Nexus file:"
        << filename << " Ignore eventdata from the Nexus file\n";
    return scatteringWSNames;
    ;
  }

  try {
    std::string instrumentName = "McStas";
    Geometry::InstrumentDefinitionParser parser(filename, instrumentName,
                                                instrumentXML);
    std::string instrumentNameMangled = parser.getMangledName();

    // Check whether the instrument is already in the InstrumentDataService
    if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) {
      // If it does, just use the one from the one stored there
      instrument =
          InstrumentDataService::Instance().retrieve(instrumentNameMangled);
    } else {
      // Really create the instrument
      instrument = parser.parseXML(nullptr);
      // Add to data service for later retrieval
      InstrumentDataService::Instance().add(instrumentNameMangled, instrument);
    }
  } catch (Exception::InstrumentDefinitionError &e) {
    g_log.warning()
        << "When trying to read the instrument description in the Nexus file: "
        << filename << " the following error is reported: " << e.what()
        << " Ignore eventdata from the Nexus file\n";
    return scatteringWSNames;
    ;
  } catch (...) {
    g_log.warning()
        << "Could not parse instrument description in the Nexus file: "
        << filename << " Ignore eventdata from the Nexus file\n";
    return scatteringWSNames;
    ;
  }
  // Finished reading Instrument. Then open new data folder again
  nxFile.openGroup("data", "NXdetector");

  // create and prepare an event workspace ready to receive the mcstas events
  progInitial.report("Set up EventWorkspace");
  EventWorkspace_sptr eventWS(new EventWorkspace());
  // initialize, where create up front number of eventlists = number of
  // detectors
  eventWS->initialize(instrument->getNumberDetectors(), 1, 1);
  // Set the units
  eventWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
  eventWS->setYUnit("Counts");
  // set the instrument
  eventWS->setInstrument(instrument);
  // assign detector ID to eventlists

  std::vector<detid_t> detIDs = instrument->getDetectorIDs();

  for (size_t i = 0; i < instrument->getNumberDetectors(); i++) {
    eventWS->getSpectrum(i).addDetectorID(detIDs[i]);
    // spectrum number are treated as equal to detector IDs for McStas data
    eventWS->getSpectrum(i).setSpectrumNo(detIDs[i]);
  }
  // the one is here for the moment for backward compatibility
  eventWS->rebuildSpectraMapping(true);

  bool isAnyNeutrons = false;
  // to store shortest and longest recorded TOF
  double shortestTOF(0.0);
  double longestTOF(0.0);

  // create vector container all the event output workspaces needed
  const size_t numEventEntries = eventEntries.size();
  std::string nameOfGroupWS = getProperty("OutputWorkspace");
  const auto eventDataTotalName = "EventData_" + nameOfGroupWS;
  std::vector<std::pair<EventWorkspace_sptr, std::string>> allEventWS = {
      {eventWS, eventDataTotalName}};
  // if numEventEntries > 1 also create separate event workspaces
  const bool onlySummedEventWorkspace =
      getProperty("OutputOnlySummedEventWorkspace");
  if (!onlySummedEventWorkspace && numEventEntries > 1) {
    for (const auto &eventEntry : eventEntries) {
      const std::string &dataName = eventEntry.first;
      // create container to hold partial event data
      // plus the name users will see for it
      const auto ws_name = dataName + "_" + nameOfGroupWS;
      allEventWS.emplace_back(eventWS->clone(), ws_name);
    }
  }

  Progress progEntries(this, progressFractionInitial, 1.0, numEventEntries * 2);

  // Refer to entry in allEventWS. The first non-summed workspace index is 1
  auto eventWSIndex = 1u;
  // Loop over McStas event data components
  for (const auto &eventEntry : eventEntries) {
    const std::string &dataName = eventEntry.first;
    const std::string &dataType = eventEntry.second;

    // open second level entry
    nxFile.openGroup(dataName, dataType);
    std::vector<double> data;
    nxFile.openData("events");
    progEntries.report("read event data from nexus");

    // Need to take into account that the nexus readData method reads a
    // multi-column data entry
    // into a vector
    // The number of data column for each neutron is here hardcoded to (p, x,
    // y,  n, id, t)
    // Thus  we have
    // column  0 : p 	neutron wight
    // column  1 : x 	x coordinate
    // column  2 : y 	y coordinate
    // column  3 : n 	accumulated number of neutrons
    // column  4 : id 	pixel id
    // column  5 : t 	time

    // get info about event data
    ::NeXus::Info id_info = nxFile.getInfo();
    if (id_info.dims.size() != 2) {
      g_log.error() << "Event data in McStas nexus file not loaded. Expected "
                       "event data block to be two dimensional\n";
      return scatteringWSNames;
      ;
    }
    int64_t nNeutrons = id_info.dims[0];
    int64_t numberOfDataColumn = id_info.dims[1];
    if (nNeutrons && numberOfDataColumn != 6) {
      g_log.error() << "Event data in McStas nexus file expecting 6 columns\n";
      return scatteringWSNames;
      ;
    }
    if (!isAnyNeutrons && nNeutrons > 0)
      isAnyNeutrons = true;

    std::vector<int64_t> start(2);
    std::vector<int64_t> step(2);

    // read the event data in blocks. 1 million event is 1000000*6*8 doubles
    // about 50Mb
    int64_t nNeutronsInBlock = 1000000;
    int64_t nOfFullBlocks = nNeutrons / nNeutronsInBlock;
    int64_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock;
    // sum over number of blocks + 1 to cover the remainder
    for (int64_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) {
      if (iBlock == nOfFullBlocks) {
        // read remaining neutrons
        start[0] = nOfFullBlocks * nNeutronsInBlock;
        start[1] = 0;
        step[0] = nRemainingNeutrons;
        step[1] = numberOfDataColumn;
      } else {
        // read neutrons in a full block
        start[0] = iBlock * nNeutronsInBlock;
        start[1] = 0;
        step[0] = nNeutronsInBlock;
        step[1] = numberOfDataColumn;
      }
      const int64_t nNeutronsForthisBlock =
          step[0]; // number of neutrons read for this block
      data.resize(nNeutronsForthisBlock * numberOfDataColumn);

      // Check that the type is what it is supposed to be
      if (id_info.type == ::NeXus::FLOAT64) {
        nxFile.getSlab(&data[0], start, step);
      } else {
        g_log.warning()
            << "Entry event field is not FLOAT64! It will be skipped.\n";
        continue;
      }

      // populate workspace with McStas events
      const detid2index_map detIDtoWSindex_map =
          allEventWS[0].first->getDetectorIDToWorkspaceIndexMap(true);

      progEntries.report("read event data into workspace");
      for (int64_t in = 0; in < nNeutronsForthisBlock; in++) {
        const int detectorID =
            static_cast<int>(data[4 + numberOfDataColumn * in]);
        const double detector_time = data[5 + numberOfDataColumn * in] *
                                     1.0e6; // convert to microseconds
        if (in == 0 && iBlock == 0) {
          shortestTOF = detector_time;
          longestTOF = detector_time;
        } else {
          if (detector_time < shortestTOF)
            shortestTOF = detector_time;
          if (detector_time > longestTOF)
            longestTOF = detector_time;
        }

        const size_t workspaceIndex =
            detIDtoWSindex_map.find(detectorID)->second;

        int64_t pulse_time = 0;
        auto weightedEvent = WeightedEvent();
        if (errorBarsSetTo1) {
          weightedEvent = WeightedEvent(detector_time, pulse_time,
                                        data[numberOfDataColumn * in], 1.0);
        } else {
          weightedEvent = WeightedEvent(
              detector_time, pulse_time, data[numberOfDataColumn * in],
              data[numberOfDataColumn * in] * data[numberOfDataColumn * in]);
        }
        allEventWS[0].first->getSpectrum(workspaceIndex) += weightedEvent;
        if (!onlySummedEventWorkspace && numEventEntries > 1) {
          allEventWS[eventWSIndex].first->getSpectrum(workspaceIndex) +=
              weightedEvent;
        }
      }
      eventWSIndex++;
    } // end reading over number of blocks of an event dataset

    nxFile.closeData();
    nxFile.closeGroup();

  } // end reading over number of event datasets

  // Create a default TOF-vector for histogramming, for now just 2 bins
  // 2 bins is the standard. However for McStas simulation data it may make
  // sense to
  // increase this number for better initial visual effect

  auto axis = HistogramData::BinEdges{shortestTOF - 1, longestTOF + 1};

  // ensure that specified name is given to workspace (eventWS) when added to
  // outputGroup
  for (auto eventWS : allEventWS) {
    const auto ws = eventWS.first;
    ws->setAllX(axis);
    AnalysisDataService::Instance().addOrReplace(eventWS.second, ws);
    scatteringWSNames.emplace_back(eventWS.second);
  }
  return scatteringWSNames;
}
Beispiel #8
0
/**
 * Computed the normalization for the input workspace. Results are stored in
 * m_normWS
 * @param otherValues
 * @param affineTrans
 */
void MDNormSCD::calculateNormalization(
    const std::vector<coord_t> &otherValues,
    const Kernel::Matrix<coord_t> &affineTrans) {
  API::MatrixWorkspace_const_sptr integrFlux = getProperty("FluxWorkspace");
  integrFlux->getXMinMax(m_kiMin, m_kiMax);
  API::MatrixWorkspace_const_sptr solidAngleWS =
      getProperty("SolidAngleWorkspace");

  const auto &exptInfoZero = *(m_inputWS->getExperimentInfo(0));
  typedef Kernel::PropertyWithValue<std::vector<double>> VectorDoubleProperty;
  auto *rubwLog =
      dynamic_cast<VectorDoubleProperty *>(exptInfoZero.getLog("RUBW_MATRIX"));
  if (!rubwLog) {
    throw std::runtime_error(
        "Wokspace does not contain a log entry for the RUBW matrix."
        "Cannot continue.");
  } else {
    Kernel::DblMatrix rubwValue(
        (*rubwLog)()); // includes the 2*pi factor but not goniometer for now :)
    m_rubw = exptInfoZero.run().getGoniometerMatrix() * rubwValue;
    m_rubw.Invert();
  }
  const double protonCharge = exptInfoZero.run().getProtonCharge();

  auto instrument = exptInfoZero.getInstrument();
  std::vector<detid_t> detIDs = instrument->getDetectorIDs(true);
  // Prune out those that are part of a group and simply leave the head of the
  // group
  detIDs = removeGroupedIDs(exptInfoZero, detIDs);

  // Mappings
  const int64_t ndets = static_cast<int64_t>(detIDs.size());
  const detid2index_map fluxDetToIdx =
      integrFlux->getDetectorIDToWorkspaceIndexMap();
  const detid2index_map solidAngDetToIdx =
      solidAngleWS->getDetectorIDToWorkspaceIndexMap();

  auto prog = make_unique<API::Progress>(this, 0.3, 1.0, ndets);
  PARALLEL_FOR1(integrFlux)
  for (int64_t i = 0; i < ndets; i++) {
    PARALLEL_START_INTERUPT_REGION

    const auto detID = detIDs[i];
    double theta(0.0), phi(0.0);
    bool skip(false);
    try {
      auto spectrum = getThetaPhi(detID, exptInfoZero, theta, phi);
      if (spectrum->isMonitor() || spectrum->isMasked())
        continue;
    } catch (
        std::exception &) // detector might not exist or has no been included
                          // in grouping
    {
      skip = true; // Intel compiler has a problem with continue inside a catch
                   // inside openmp...
    }
    if (skip)
      continue;

    // Intersections
    auto intersections = calculateIntersections(theta, phi);
    if (intersections.empty())
      continue;

    // get the flux spetrum number
    size_t wsIdx = fluxDetToIdx.find(detID)->second;
    // Get solid angle for this contribution
    double solid =
        solidAngleWS->readY(solidAngDetToIdx.find(detID)->second)[0] *
        protonCharge;

    // -- calculate integrals for the intersection --
    // momentum values at intersections
    auto intersectionsBegin = intersections.begin();
    std::vector<double> xValues(intersections.size()),
        yValues(intersections.size());
    {
      // copy momenta to xValues
      auto x = xValues.begin();
      for (auto it = intersectionsBegin; it != intersections.end(); ++it, ++x) {
        *x = (*it)[3];
      }
    }
    // calculate integrals at momenta from xValues by interpolating between
    // points in spectrum sp
    // of workspace integrFlux. The result is stored in yValues
    calcIntegralsForIntersections(xValues, *integrFlux, wsIdx, yValues);

    // Compute final position in HKL
    const size_t vmdDims = intersections.front().size();
    // pre-allocate for efficiency and copy non-hkl dim values into place
    std::vector<coord_t> pos(vmdDims + otherValues.size());
    std::copy(otherValues.begin(), otherValues.end(),
              pos.begin() + vmdDims - 1);
    pos.push_back(1.);

    for (auto it = intersectionsBegin + 1; it != intersections.end(); ++it) {
      const auto &curIntSec = *it;
      const auto &prevIntSec = *(it - 1);
      // the full vector isn't used so compute only what is necessary
      double delta = curIntSec[3] - prevIntSec[3];
      if (delta < 1e-07)
        continue; // Assume zero contribution if difference is small

      // Average between two intersections for final position
      std::transform(curIntSec.getBareArray(),
                     curIntSec.getBareArray() + vmdDims - 1,
                     prevIntSec.getBareArray(), pos.begin(),
                     VectorHelper::SimpleAverage<coord_t>());
      std::vector<coord_t> posNew = affineTrans * pos;
      size_t linIndex = m_normWS->getLinearIndexAtCoord(posNew.data());
      if (linIndex == size_t(-1))
        continue;

      // index of the current intersection
      size_t k = static_cast<size_t>(std::distance(intersectionsBegin, it));
      // signal = integral between two consecutive intersections
      double signal = (yValues[k] - yValues[k - 1]) * solid;

      PARALLEL_CRITICAL(updateMD) {
        signal += m_normWS->getSignalAt(linIndex);
        m_normWS->setSignalAt(linIndex, signal);
      }
    }
    prog->report();

    PARALLEL_END_INTERUPT_REGION
  }
  PARALLEL_CHECK_INTERUPT_REGION
}
Beispiel #9
0
/**
 * Return the confidence with with this algorithm can load the file
 * @param eventEntries map of the file entries that have events
 * @param outputGroup pointer to the workspace group
 * @param nxFile Reads data from inside first first top entry
 */
void LoadMcStas::readEventData(
    const std::map<std::string, std::string> &eventEntries,
    WorkspaceGroup_sptr &outputGroup, ::NeXus::File &nxFile) {
  std::string filename = getPropertyValue("Filename");
  auto entries = nxFile.getEntries();

  // will assume that each top level entry contain one mcstas
  // generated IDF and any event data entries within this top level
  // entry are data collected for that instrument
  // This code for loading the instrument is for now adjusted code from
  // ExperimentalInfo.

  // Close data folder and go back to top level. Then read and close the
  // Instrument folder.
  nxFile.closeGroup();

  Geometry::Instrument_sptr instrument;

  // Initialize progress reporting
  int reports = 2;
  const double progressFractionInitial = 0.1;
  Progress progInitial(this, 0.0, progressFractionInitial, reports);

  try {
    nxFile.openGroup("instrument", "NXinstrument");
    std::string instrumentXML;
    nxFile.openGroup("instrument_xml", "NXnote");
    nxFile.readData("data", instrumentXML);
    nxFile.closeGroup();
    nxFile.closeGroup();

    progInitial.report("Loading instrument");

    Geometry::InstrumentDefinitionParser parser;
    std::string instrumentName = "McStas";
    parser.initialize(filename, instrumentName, instrumentXML);
    std::string instrumentNameMangled = parser.getMangledName();

    // Check whether the instrument is already in the InstrumentDataService
    if (InstrumentDataService::Instance().doesExist(instrumentNameMangled)) {
      // If it does, just use the one from the one stored there
      instrument =
          InstrumentDataService::Instance().retrieve(instrumentNameMangled);
    } else {
      // Really create the instrument
      instrument = parser.parseXML(NULL);
      // Add to data service for later retrieval
      InstrumentDataService::Instance().add(instrumentNameMangled, instrument);
    }
  } catch (...) {
    // Loader should not stop if there is no IDF.xml
    g_log.warning()
        << "\nCould not find the instrument description in the Nexus file:"
        << filename << " Ignore evntdata from data file" << std::endl;
    return;
  }
  // Finished reading Instrument. Then open new data folder again
  nxFile.openGroup("data", "NXdetector");

  // create and prepare an event workspace ready to receive the mcstas events
  progInitial.report("Set up EventWorkspace");
  EventWorkspace_sptr eventWS(new EventWorkspace());
  // initialize, where create up front number of eventlists = number of
  // detectors
  eventWS->initialize(instrument->getNumberDetectors(), 1, 1);
  // Set the units
  eventWS->getAxis(0)->unit() = UnitFactory::Instance().create("TOF");
  eventWS->setYUnit("Counts");
  // set the instrument
  eventWS->setInstrument(instrument);
  // assign detector ID to eventlists

  std::vector<detid_t> detIDs = instrument->getDetectorIDs();

  for (size_t i = 0; i < instrument->getNumberDetectors(); i++) {
    eventWS->getEventList(i).addDetectorID(detIDs[i]);
    // spectrum number are treated as equal to detector IDs for McStas data
    eventWS->getEventList(i).setSpectrumNo(detIDs[i]);
  }
  // the one is here for the moment for backward compatibility
  eventWS->rebuildSpectraMapping(true);

  bool isAnyNeutrons = false;
  // to store shortest and longest recorded TOF
  double shortestTOF(0.0);
  double longestTOF(0.0);

  const size_t numEventEntries = eventEntries.size();
  Progress progEntries(this, progressFractionInitial, 1.0, numEventEntries * 2);
  for (auto eit = eventEntries.begin(); eit != eventEntries.end(); ++eit) {
    std::string dataName = eit->first;
    std::string dataType = eit->second;

    // open second level entry
    nxFile.openGroup(dataName, dataType);
    std::vector<double> data;
    nxFile.openData("events");
    progEntries.report("read event data from nexus");

    // Need to take into account that the nexus readData method reads a
    // multi-column data entry
    // into a vector
    // The number of data column for each neutron is here hardcoded to (p, x,
    // y,  n, id, t)
    // Thus  we have
    // column  0 : p 	neutron wight
    // column  1 : x 	x coordinate
    // column  2 : y 	y coordinate
    // column  3 : n 	accumulated number of neutrons
    // column  4 : id 	pixel id
    // column  5 : t 	time

    // get info about event data
    ::NeXus::Info id_info = nxFile.getInfo();
    if (id_info.dims.size() != 2) {
      g_log.error() << "Event data in McStas nexus file not loaded. Expected "
                       "event data block to be two dimensional" << std::endl;
      return;
    }
    int64_t nNeutrons = id_info.dims[0];
    int64_t numberOfDataColumn = id_info.dims[1];
    if (nNeutrons && numberOfDataColumn != 6) {
      g_log.error() << "Event data in McStas nexus file expecting 6 columns"
                    << std::endl;
      return;
    }
    if (isAnyNeutrons == false && nNeutrons > 0)
      isAnyNeutrons = true;

    std::vector<int64_t> start(2);
    std::vector<int64_t> step(2);

    // read the event data in blocks. 1 million event is 1000000*6*8 doubles
    // about 50Mb
    int64_t nNeutronsInBlock = 1000000;
    int64_t nOfFullBlocks = nNeutrons / nNeutronsInBlock;
    int64_t nRemainingNeutrons = nNeutrons - nOfFullBlocks * nNeutronsInBlock;
    // sum over number of blocks + 1 to cover the remainder
    for (int64_t iBlock = 0; iBlock < nOfFullBlocks + 1; iBlock++) {
      if (iBlock == nOfFullBlocks) {
        // read remaining neutrons
        start[0] = nOfFullBlocks * nNeutronsInBlock;
        start[1] = 0;
        step[0] = nRemainingNeutrons;
        step[1] = numberOfDataColumn;
      } else {
        // read neutrons in a full block
        start[0] = iBlock * nNeutronsInBlock;
        start[1] = 0;
        step[0] = nNeutronsInBlock;
        step[1] = numberOfDataColumn;
      }
      const int64_t nNeutronsForthisBlock =
          step[0]; // number of neutrons read for this block
      data.resize(nNeutronsForthisBlock * numberOfDataColumn);

      // Check that the type is what it is supposed to be
      if (id_info.type == ::NeXus::FLOAT64) {
        nxFile.getSlab(&data[0], start, step);
      } else {
        g_log.warning()
            << "Entry event field is not FLOAT64! It will be skipped.\n";
        continue;
      }

      // populate workspace with McStas events
      const detid2index_map detIDtoWSindex_map =
          eventWS->getDetectorIDToWorkspaceIndexMap(true);

      progEntries.report("read event data into workspace");
      for (int64_t in = 0; in < nNeutronsForthisBlock; in++) {
        const int detectorID =
            static_cast<int>(data[4 + numberOfDataColumn * in]);
        const double detector_time = data[5 + numberOfDataColumn * in] *
                                     1.0e6; // convert to microseconds
        if (in == 0 && iBlock == 0) {
          shortestTOF = detector_time;
          longestTOF = detector_time;
        } else {
          if (detector_time < shortestTOF)
            shortestTOF = detector_time;
          if (detector_time > longestTOF)
            longestTOF = detector_time;
        }

        const size_t workspaceIndex =
            detIDtoWSindex_map.find(detectorID)->second;

        int64_t pulse_time = 0;
        // eventWS->getEventList(workspaceIndex) +=
        // TofEvent(detector_time,pulse_time);
        // eventWS->getEventList(workspaceIndex) += TofEvent(detector_time);
        eventWS->getEventList(workspaceIndex) += WeightedEvent(
            detector_time, pulse_time, data[numberOfDataColumn * in], 1.0);
      }
    } // end reading over number of blocks of an event dataset

    // nxFile.getData(data);
    nxFile.closeData();
    nxFile.closeGroup();

  } // end reading over number of event datasets

  // Create a default TOF-vector for histogramming, for now just 2 bins
  // 2 bins is the standard. However for McStas simulation data it may make
  // sense to
  // increase this number for better initial visual effect
  Kernel::cow_ptr<MantidVec> axis;
  MantidVec &xRef = axis.access();
  xRef.resize(2, 0.0);
  // if ( nNeutrons > 0)
  if (isAnyNeutrons) {
    xRef[0] = shortestTOF - 1; // Just to make sure the bins hold it all
    xRef[1] = longestTOF + 1;
  }
  // Set the binning axis
  eventWS->setAllX(axis);

  // ensure that specified name is given to workspace (eventWS) when added to
  // outputGroup
  std::string nameOfGroupWS = getProperty("OutputWorkspace");
  std::string nameUserSee = std::string("EventData_") + nameOfGroupWS;
  std::string extraProperty =
      "Outputworkspace_dummy_" +
      boost::lexical_cast<std::string>(m_countNumWorkspaceAdded);
  declareProperty(new WorkspaceProperty<Workspace>(extraProperty, nameUserSee,
                                                   Direction::Output));
  setProperty(extraProperty, boost::static_pointer_cast<Workspace>(eventWS));
  m_countNumWorkspaceAdded++; // need to increment to ensure extraProperty are
                              // unique

  outputGroup->addWorkspace(eventWS);
}
int PeakIntegration::fitneighbours(int ipeak, std::string det_name, int x0,
                                   int y0, int idet, double qspan,
                                   PeaksWorkspace_sptr &Peaks,
                                   const detid2index_map &pixel_to_wi) {
  UNUSED_ARG(ipeak);
  UNUSED_ARG(det_name);
  UNUSED_ARG(x0);
  UNUSED_ARG(y0);
  Geometry::IPeak &peak = Peaks->getPeak(ipeak);
  // Number of slices
  int TOFmax = 0;

  IAlgorithm_sptr slice_alg = createChildAlgorithm("IntegratePeakTimeSlices");
  slice_alg->setProperty<MatrixWorkspace_sptr>("InputWorkspace", inputW);
  std::ostringstream tab_str;
  tab_str << "LogTable" << ipeak;

  slice_alg->setPropertyValue("OutputWorkspace", tab_str.str());
  slice_alg->setProperty<PeaksWorkspace_sptr>("Peaks", Peaks);
  slice_alg->setProperty("PeakIndex", ipeak);
  slice_alg->setProperty("PeakQspan", qspan);

  int nPixels = std::max<int>(0, getProperty("NBadEdgePixels"));

  slice_alg->setProperty("NBadEdgePixels", nPixels);
  slice_alg->executeAsChildAlg();
  Mantid::API::MemoryManager::Instance().releaseFreeMemory();

  MantidVec &Xout = outputW->dataX(idet);
  MantidVec &Yout = outputW->dataY(idet);
  MantidVec &Eout = outputW->dataE(idet);
  TableWorkspace_sptr logtable = slice_alg->getProperty("OutputWorkspace");

  peak.setIntensity(slice_alg->getProperty("Intensity"));
  peak.setSigmaIntensity(slice_alg->getProperty("SigmaIntensity"));

  TOFmax = static_cast<int>(logtable->rowCount());
  for (int iTOF = 0; iTOF < TOFmax; iTOF++) {
    Xout[iTOF] = logtable->getRef<double>(std::string("Time"), iTOF);
    if (m_IC) // Ikeda-Carpenter fit
    {
      Yout[iTOF] = logtable->getRef<double>(std::string("TotIntensity"), iTOF);
      Eout[iTOF] =
          logtable->getRef<double>(std::string("TotIntensityError"), iTOF);
    } else {
      Yout[iTOF] = logtable->getRef<double>(std::string("ISAWIntensity"), iTOF);
      Eout[iTOF] =
          logtable->getRef<double>(std::string("ISAWIntensityError"), iTOF);
    }
  }

  outputW->getSpectrum(idet)->clearDetectorIDs();
  // Find the pixel ID at that XY position on the rectangular detector
  int pixelID = peak.getDetectorID(); // det->getAtXY(x0,y0)->getID();

  // Find the corresponding workspace index, if any
  auto wiEntry = pixel_to_wi.find(pixelID);
  if (wiEntry != pixel_to_wi.end()) {
    size_t wi = wiEntry->second;
    // Set detectorIDs
    outputW->getSpectrum(idet)
        ->addDetectorIDs(inputW->getSpectrum(wi)->getDetectorIDs());
  }

  return TOFmax - 1;
}