Program Listing for File scan.cxx

↰ Return to documentation for file (dx2/scan.cxx)

#include "dx2/scan.hpp"

Scan::Scan(std::array<int, 2> image_range, std::array<double, 2> oscillation)
    : image_range_{image_range} {
  num_images_ = image_range_[1] - image_range_[0] + 1;
  oscillation_start_ = oscillation[0];
  oscillation_width_ = oscillation[1];
}

Scan::Scan(json scan_data) {
  // minimal required keys are image range and ["properties"]:"oscillation"
  std::vector<std::string> required_keys = {"image_range", "properties"};
  for (const auto &key : required_keys) {
    if (scan_data.find(key) == scan_data.end()) {
      throw std::invalid_argument("Key " + key +
                                  " is missing from the input scan JSON");
    }
  }
  image_range_ = scan_data["image_range"];
  num_images_ = image_range_[1] - image_range_[0] + 1;
  if (scan_data["properties"].find("oscillation") ==
      scan_data["properties"].end()) {
    throw std::invalid_argument(
        "Key oscillation is missing from the input scan['properties'] JSON");
  }
  std::vector<double> oscillation;
  json osc_array = scan_data["properties"]["oscillation"];
  // Just read the first two oscillation values as that is all that is needed
  if (osc_array.size() < 1) {
    // Unlikely to happen but check anyway for safety.
    throw std::invalid_argument(
        "scan['properties']['oscillation'] has no values in the scan JSON");
  } else if (osc_array.size() == 1) {
    // SSX scans just have a single oscillation value (the start angle, usually
    // 0). Therefore by convention the oscillation width is 0. The dials/dxtbx
    // output should probably be changed to have two oscillation values both of
    // zero as a consistent model.
    oscillation.push_back(osc_array[0]);
    oscillation_start_ = oscillation[0];
    oscillation_width_ = 0;
  } else {
    // Typical rotation scan.
    for (json::iterator it = osc_array.begin(); it != osc_array.begin() + 2;
         ++it) {
      oscillation.push_back(*it);
    }
    oscillation_start_ = oscillation[0];
    oscillation_width_ = oscillation[1] - oscillation[0];
  }
}

json Scan::to_json() const {
  json scan_data;
  scan_data["image_range"] = image_range_;
  scan_data["batch_offset"] = 0; // We MUST NOT use batch offsets in dx2,
                                 // written out here for compatibility
  std::vector<double> oscillation_array(num_images_);
  for (int i = 0; i < num_images_; i++) {
    oscillation_array[i] = oscillation_start_ + oscillation_width_ * i;
  }
  json properties;
  properties["oscillation"] = oscillation_array;
  if (oscillation_array.size() == 1) {
    properties["oscillation_width"] = 0;
  }
  scan_data["properties"] = properties;
  // FIXME for dials compatibility, do we need exposure times and epochs arrays,
  // also valid_image_ranges empty dict?
  return scan_data;
}

std::array<int, 2> Scan::get_image_range() const { return image_range_; }

std::array<double, 2> Scan::get_oscillation() const {
  return {oscillation_start_, oscillation_width_};
}