Skip to content
Snippets Groups Projects
LoadISISNexus2.cpp 49.5 KiB
Newer Older
      "gd_prtn_chrg",
      static_cast<double>(rpb_dbl[7])); // good proton charge (uA.hour)
  runDetails.addProperty(
      "tot_prtn_chrg",
      static_cast<double>(rpb_dbl[8])); // total proton charge (uA.hour)
  runDetails.addProperty("goodfrm", rpb_int[9]); // good frames
  runDetails.addProperty("rawfrm", rpb_int[10]); // raw frames
  runDetails.addProperty(
      "dur_wanted",
      rpb_int[11]); // requested run duration (units as for "duration" above)
  runDetails.addProperty("dur_secs",
                         rpb_int[12]); // actual run duration in seconds
  runDetails.addProperty("mon_sum1", rpb_int[13]); // monitor sum 1
  runDetails.addProperty("mon_sum2", rpb_int[14]); // monitor sum 2
  runDetails.addProperty("mon_sum3", rpb_int[15]); // monitor sum 3

  // End date and time is stored separately in ISO format in the
  // "raw_data1/endtime" class
  char_data = entry.openNXChar("end_time");
  char_data.load();
  std::string end_time_iso = std::string(char_data(), 19);
  runDetails.addProperty("run_end", end_time_iso);

  char_data = entry.openNXChar("start_time");
  char_data.load();
  std::string start_time_iso = std::string(char_data(), 19);
  runDetails.addProperty("run_start", start_time_iso);

  runDetails.addProperty("rb_proposal", rpb_int[21]); // RB (proposal) number
  vms_compat.close();
}

/**
* Parse an ISO formatted date-time string into separate date and time strings
* @param datetime_iso :: The string containing the ISO formatted date-time
* @param date :: An output parameter containing the date from the original
* string or ??-??-???? if the format is unknown
* @param time :: An output parameter containing the time from the original
* string or ??-??-?? if the format is unknown
*/
void LoadISISNexus2::parseISODateTime(const std::string &datetime_iso,
                                      std::string &date,
                                      std::string &time) const {
  try {
    Poco::DateTime datetime_output;
    int timezone_diff(0);
    Poco::DateTimeParser::parse(Poco::DateTimeFormat::ISO8601_FORMAT,
                                datetime_iso, datetime_output, timezone_diff);
    date = Poco::DateTimeFormatter::format(datetime_output, "%d-%m-%Y",
                                           timezone_diff);
    time = Poco::DateTimeFormatter::format(datetime_output, "%H:%M:%S",
                                           timezone_diff);
  } catch (Poco::SyntaxException &) {
    date = "\?\?-\?\?-\?\?\?\?";
    time = "\?\?:\?\?:\?\?";
    g_log.warning() << "Cannot parse end time from entry in Nexus file.\n";
  }
}

/**
* Load data about the sample
*   @param local_workspace :: The workspace to load the logs to.
*   @param entry :: The Nexus entry
*/
void LoadISISNexus2::loadSampleData(
    DataObjects::Workspace2D_sptr &local_workspace, NXEntry &entry) {
  /// Sample geometry
  NXInt spb = entry.openNXInt("isis_vms_compat/SPB");
  // Just load the index we need, not the whole block. The flag is the third
  // value in
  spb.load(1, 2);
  int geom_id = spb[0];
  local_workspace->mutableSample().setGeometryFlag(spb[0]);

  NXFloat rspb = entry.openNXFloat("isis_vms_compat/RSPB");
  // Just load the indices we need, not the whole block. The values start from
  // the 4th onward
  rspb.load(3, 3);
  double thick(rspb[0]), height(rspb[1]), width(rspb[2]);
  local_workspace->mutableSample().setThickness(thick);
  local_workspace->mutableSample().setHeight(height);
  local_workspace->mutableSample().setWidth(width);

  g_log.debug() << "Sample geometry -  ID: " << geom_id
                << ", thickness: " << thick << ", height: " << height
                << ", width: " << width << "\n";
}

/**  Load logs from Nexus file. Logs are expected to be in
*   /raw_data_1/runlog group of the file. Call to this method must be done
*   within /raw_data_1 group.
*   @param ws :: The workspace to load the logs to.
*   @param entry :: Nexus entry
*/
void LoadISISNexus2::loadLogs(DataObjects::Workspace2D_sptr &ws,
                              NXEntry &entry) {
  IAlgorithm_sptr alg = createChildAlgorithm("LoadNexusLogs", 0.0, 0.5);
  alg->setPropertyValue("Filename", this->getProperty("Filename"));
  alg->setProperty<MatrixWorkspace_sptr>("Workspace", ws);
  try {
    alg->executeAsChildAlg();
  } catch (std::runtime_error &) {
    g_log.warning() << "Unable to load run logs. There will be no log "
                    << "data associated with this workspace\n";
    return;
  }
  // For ISIS Nexus only, fabricate an additional log containing an array of
  // proton charge information from the periods group.
  try {
    NXClass protonChargeClass = entry.openNXGroup("periods");
    NXFloat periodsCharge = protonChargeClass.openNXFloat("proton_charge");
    periodsCharge.load();
    size_t nperiods = periodsCharge.dim0();
    std::vector<double> chargesVector(nperiods);
    std::copy(periodsCharge(), periodsCharge() + nperiods,
              chargesVector.begin());
    ArrayProperty<double> *protonLogData =
        new ArrayProperty<double>("proton_charge_by_period", chargesVector);
    ws->mutableRun().addProperty(protonLogData);
  } catch (std::runtime_error &) {
    this->g_log.debug("Cannot read periods information from the nexus file. "
                      "This group may be absent.");
  }
  // Populate the instrument parameters.
  ws->populateInstrumentParameters();

  // Make log creator object and add the run status log
  m_logCreator.reset(
      new ISISRunLogs(ws->run(), m_detBlockInfo.numberOfPeriods));
  m_logCreator->addStatusLog(ws->mutableRun());
}

double LoadISISNexus2::dblSqrt(double in) { return sqrt(in); }
/**Method takes input parameters which describe  monitor loading and analyze
*them against spectra/monitor block information in the file.
* The result is the option if monitors can  be loaded together with spectra or
*mast be treated separately
* and additional information on how to treat monitor spectra.
*
*@param entry                :: entry to the NeXus file, opened at root folder
*@param spectrum_index       :: array of spectra indexes of the data present in
*the file
*@param ndets                :: size of the spectrum index array
*@param n_vms_compat_spectra :: number of data entries containing common time
*bins (e.g. all spectra, or all spectra and monitors or some spectra (this is
*not fully supported)
*@param monitors             :: map connecting monitor spectra ID against
*monitor group name in the file.
*@param excludeMonitors      :: input property indicating if it is requested to
*exclude monitors from the target workspace
*@param separateMonitors     :: input property indicating if it is requested to
*load monitors separately (and exclude them from target data workspace this way)
*
*@param OvelapMonitors       :: output property containing the list of monitors
*ID for monitors, which are also included with spectra.
*@return excludeMonitors     :: indicator if monitors should or mast be excluded
*from the main data workspace if they can not be loaded with the data
*                               (contain different number of time channels)
*
*/
bool LoadISISNexus2::findSpectraDetRangeInFile(
    NXEntry &entry, boost::shared_array<int> &spectrum_index, int64_t ndets,
    int64_t n_vms_compat_spectra, std::map<int64_t, std::string> &monitors,
    bool excludeMonitors, bool separateMonitors,
    std::map<int64_t, std::string> &OvelapMonitors) {
  OvelapMonitors.clear();
  size_t nmons = monitors.size();

  if (nmons > 0) {
    NXInt chans = entry.openNXInt(m_monitors.begin()->second + "/data");

    m_monBlockInfo = DataBlock(chans);
    m_monBlockInfo.numberOfSpectra = nmons; // each monitor is in separate group
                                            // so number of spectra is equal to
                                            // number of groups.

    // identify monitor ID range.
    for (auto &monitor : monitors) {
      int64_t mon_id = static_cast<int64_t>(monitor.first);
      if (m_monBlockInfo.spectraID_min > mon_id)
        m_monBlockInfo.spectraID_min = mon_id;
      if (m_monBlockInfo.spectraID_max < mon_id)
        m_monBlockInfo.spectraID_max = mon_id;
    if (m_monBlockInfo.spectraID_max - m_monBlockInfo.spectraID_min + 1 !=
        static_cast<int64_t>(nmons)) {
      g_log.warning() << "When trying to find the range of monitor spectra: "
                         "non-consequent monitor ID-s in the monitor block. "
                         "Unexpected situation for the loader\n";
    // at this stage we assume that the only going to load monitors
    m_loadBlockInfo = m_monBlockInfo;
  }

  if (ndets == 0) {
    separateMonitors = false; // only monitors in the main workspace. No
                              // detectors. Will be loaded in the main workspace
    // Possible function exit point
    return separateMonitors;
  }

  // detectors are present in the file
  NXData nxData = entry.openNXData("detector_1");
  NXInt data = nxData.openIntData();

  m_detBlockInfo = DataBlock(data);
  // We assume again that this spectrum list ID increase monotonically
  m_detBlockInfo.spectraID_min = spectrum_index[0];
  m_detBlockInfo.spectraID_max = spectrum_index[ndets - 1];
  if (m_detBlockInfo.spectraID_max - m_detBlockInfo.spectraID_min + 1 !=
      static_cast<int64_t>(m_detBlockInfo.numberOfSpectra)) {
    g_log.warning() << "When trying to find the range of monitor spectra:  "
                       "non-consequent spectra ID-s in the detectors block. "
                       "Unexpected situation for the loader\n";
  }

  m_loadBlockInfo = m_detBlockInfo;

  // now we are analyzing what is actually going or can be loaded

  bool removeMonitors = excludeMonitors || separateMonitors;
  if (((m_detBlockInfo.numberOfPeriods != m_monBlockInfo.numberOfPeriods) ||
       (m_detBlockInfo.numberOfChannels != m_monBlockInfo.numberOfChannels)) &&
      nmons > 0) {
    // detectors and monitors have different characteristics. Can be loaded only
    // to separate workspaces.
    if (!removeMonitors) {
      g_log.warning() << " Performing separate loading as can not load spectra "
                         "and monitors in the single workspace:\n";
      g_log.warning() << " Monitors data contain :"
                      << m_monBlockInfo.numberOfChannels
                      << " time channels and: "
                      << m_monBlockInfo.numberOfPeriods << " period(s)\n";
      g_log.warning() << " Spectra  data contain :"
                      << m_detBlockInfo.numberOfChannels
                      << " time channels and: "
                      << m_detBlockInfo.numberOfPeriods << " period(s)\n";
    separateMonitors = true;
    removeMonitors = true;
  }

  int64_t spectraID_min =
      std::min(m_monBlockInfo.spectraID_min, m_detBlockInfo.spectraID_min);
  int64_t spectraID_max =
      std::max(m_monBlockInfo.spectraID_max, m_detBlockInfo.spectraID_max);
  size_t totNumOfSpectra =
      m_monBlockInfo.numberOfSpectra + m_detBlockInfo.numberOfSpectra;
  if (!removeMonitors) {
    m_loadBlockInfo.numberOfSpectra = totNumOfSpectra;
    m_loadBlockInfo.spectraID_min = spectraID_min;
    m_loadBlockInfo.spectraID_max = spectraID_max;
  }
  if (separateMonitors)
    m_loadBlockInfo = m_detBlockInfo;

  // verify integrity of the monitor and detector information

  if ((totNumOfSpectra == static_cast<size_t>(n_vms_compat_spectra)) &&
      (spectraID_max - spectraID_min + 1 ==
       static_cast<int64_t>(n_vms_compat_spectra))) {
    // all information written in the file is correct, there are no spurious
    // spectra and detectors & monitors form continuous block on HDD
    return separateMonitors;
  }

  // something is wrong and we need to analyze spectra map.  Currently we can
  // identify and manage the case when all monitor's spectra are written
  // together with detectors
  // make settings for this situation
  m_detBlockInfo.numberOfSpectra -= m_monBlockInfo.numberOfSpectra;
  m_loadBlockInfo.numberOfSpectra -= m_monBlockInfo.numberOfSpectra;

  std::map<int64_t, std::string> remaining_monitors;
  if (removeMonitors) {
    for (auto &monitor : monitors) {
      if (monitor.first >= m_detBlockInfo.spectraID_min &&
          monitor.first <= m_detBlockInfo.spectraID_max) { // monitors ID-s are
        // included with spectra
        // ID-s -- let's try not
        // to load it twice.
        OvelapMonitors.insert(monitor);
        remaining_monitors.insert(monitor);
  }
  monitors.swap(remaining_monitors);
  return separateMonitors;
}
} // namespace DataHandling
} // namespace Mantid