Skip to content

Commit

Permalink
Merge pull request mantidproject#36361 from peterfpeterson/savediffca…
Browse files Browse the repository at this point in the history
…l_optional_calibration

SaveDiffCal - Add the ability for the calibration workspace to be optional
  • Loading branch information
KedoKudo committed Nov 6, 2023
2 parents 0960ee3 + ac1e300 commit c429785
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 30 deletions.
5 changes: 5 additions & 0 deletions Framework/DataHandling/inc/MantidDataHandling/SaveDiffCal.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@ class MANTID_DATAHANDLING_DLL SaveDiffCal final : public API::Algorithm {
void exec() override;
std::map<std::string, std::string> validateInputs() override;

void writeDoubleFieldZeros(H5::Group &group, const std::string &name);

void writeDoubleFieldFromTable(H5::Group &group, const std::string &name);
void writeIntFieldFromTable(H5::Group &group, const std::string &name);
void writeDetIdsfromSVWS(H5::Group &group, const std::string &name,
const DataObjects::SpecialWorkspace2D_const_sptr &ws);
void writeIntFieldFromSVWS(H5::Group &group, const std::string &name,
const DataObjects::SpecialWorkspace2D_const_sptr &ws);
void generateDetidToIndex();
void generateDetidToIndex(const DataObjects::SpecialWorkspace2D_const_sptr &ws);
bool tableHasColumn(const std::string &ColumnName) const;

// minimum of (CalibrationWorkspace_row_count,
Expand Down
140 changes: 117 additions & 23 deletions Framework/DataHandling/src/SaveDiffCal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ const std::string SaveDiffCal::summary() const { return "Saves a calibration fil
/** Initialize the algorithm's properties.
*/
void SaveDiffCal::init() {
declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("CalibrationWorkspace", "", Direction::Input),
declareProperty(std::make_unique<WorkspaceProperty<ITableWorkspace>>("CalibrationWorkspace", "", Direction::Input,
PropertyMode::Optional),
"An output workspace.");

declareProperty(std::make_unique<WorkspaceProperty<GroupingWorkspace>>("GroupingWorkspace", "", Direction::Input,
Expand All @@ -71,9 +72,7 @@ std::map<std::string, std::string> SaveDiffCal::validateInputs() {
std::map<std::string, std::string> result;

ITableWorkspace_const_sptr calibrationWS = getProperty("CalibrationWorkspace");
if (!bool(calibrationWS)) {
result["CalibrationWorkspace"] = "Cannot save empty table";
} else {
if (bool(calibrationWS)) {
size_t numRows = calibrationWS->rowCount();
if (numRows == 0) {
result["CalibrationWorkspace"] = "Cannot save empty table";
Expand All @@ -87,11 +86,26 @@ std::map<std::string, std::string> SaveDiffCal::validateInputs() {
result["MaskWorkspace"] = "Must have equal or less number of spectra as the table has rows";
}
}
} else {
GroupingWorkspace_const_sptr groupingWS = getProperty("GroupingWorkspace");
MaskWorkspace_const_sptr maskWS = getProperty("MaskWorkspace");

if ((!groupingWS) && (!maskWS)) {
const std::string msg("Failed to supply any input workspace");
result["CalibrationWorkspace"] = msg;
result["GroupingWorkspace"] = msg;
result["MaskWorkspace"] = msg;
}
}

return result;
}

void SaveDiffCal::writeDoubleFieldZeros(H5::Group &group, const std::string &name) {
std::vector<double> zeros(m_numValues, 0.);
H5Util::writeArray1D(group, name, zeros);
}

/**
* Create a dataset under a given group with a given name
* Use CalibrationWorkspace to retrieve the data
Expand All @@ -103,6 +117,20 @@ void SaveDiffCal::writeDoubleFieldFromTable(H5::Group &group, const std::string
auto column = m_calibrationWS->getColumn(name);
// Retrieve only the first m_numValues, not necessarily the whole column
auto data = column->numeric_fill<>(m_numValues);

// if the field is optional, check if it is all zeros
if (name != "difc") {
bool allZeros = true;
for (const auto &value : data) {
if (value != 0.) {
allZeros = false;
break;
}
}
if (allZeros)
return; // don't write the field
}

H5Util::writeArray1D(group, name, data);
}

Expand All @@ -120,10 +148,33 @@ void SaveDiffCal::writeIntFieldFromTable(H5::Group &group, const std::string &na
H5Util::writeArray1D(group, name, data);
}

/*
* Mantid::DataObjects::WorkspaceSingleValue/SpecialWorkspace2D is a parent to both GroupingWorkspace
* and MaskWorkspace
*/
void SaveDiffCal::writeDetIdsfromSVWS(H5::Group &group, const std::string &name,
const DataObjects::SpecialWorkspace2D_const_sptr &ws) {
if (!bool(ws))
throw std::runtime_error("Encountered null pointer in SaveDiffCal::writeDetIdsfromSVWS which should be impossible");

std::vector<int32_t> values;
for (size_t i = 0; i < m_numValues; ++i) {
const auto &detids = ws->getSpectrum(i).getDetectorIDs();
for (const auto &detid : detids) {
values.push_back(static_cast<int32_t>(detid));
}
}

H5Util::writeArray1D(group, name, values);
}

/**
* Create a dataset under a given group with a given name
* Use GroupingWorkspace or MaskWorkspace to retrieve the data.
*
* Mantid::DataObjects::WorkspaceSingleValue/SpecialWorkspace2D is a parent to both GroupingWorkspace
* and MaskWorkspace
*
* @param group :: group parent to the dataset
* @param name :: column name of the workspace, and name of the dataset
* @param ws :: pointer to GroupingWorkspace or MaskWorkspace
Expand Down Expand Up @@ -169,34 +220,63 @@ void SaveDiffCal::generateDetidToIndex() {
}
}

void SaveDiffCal::generateDetidToIndex(const DataObjects::SpecialWorkspace2D_const_sptr &ws) {
if (!bool(ws))
throw std::runtime_error(
"Encountered null pointer in SaveDiffCal::generateDetidToIndex which should be impossible");

m_detidToIndex.clear();

std::size_t index = 0;
for (size_t i = 0; i < m_numValues; ++i) {
const auto &detids = ws->getSpectrum(i).getDetectorIDs();
for (const auto &detid : detids) {
m_detidToIndex[static_cast<detid_t>(detid)] = index;
index++;
}
}
}

bool SaveDiffCal::tableHasColumn(const std::string &ColumnName) const {
const std::vector<std::string> names = m_calibrationWS->getColumnNames();
return std::any_of(names.cbegin(), names.cend(), [&ColumnName](const auto &name) { return name == ColumnName; });
if (m_calibrationWS) {
const std::vector<std::string> names = m_calibrationWS->getColumnNames();
return std::any_of(names.cbegin(), names.cend(), [&ColumnName](const auto &name) { return name == ColumnName; });
} else {
return false;
}
}

//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void SaveDiffCal::exec() {
m_calibrationWS = getProperty("CalibrationWorkspace");
this->generateDetidToIndex();

GroupingWorkspace_sptr groupingWS = getProperty("GroupingWorkspace");
if (bool(groupingWS) && groupingWS->isDetectorIDMappingEmpty())
groupingWS->buildDetectorIDMapping();

MaskWorkspace_const_sptr maskWS = getProperty("MaskWorkspace");

// initialize `m_numValues` as the minimum of (CalibrationWorkspace_row_count,
// GroupingWorkspace_histogram_count, MaskWorkspace_histogram_count)
m_numValues = m_calibrationWS->rowCount();
if (bool(groupingWS) && groupingWS->getNumberHistograms() < m_numValues) {
m_numValues = groupingWS->getNumberHistograms();
}
if (bool(maskWS) && maskWS->getNumberHistograms() < m_numValues) {
m_numValues = maskWS->getNumberHistograms();
// Get a starting number of values to work with that will be refined below
// THE ORDER OF THE IF/ELSE TREE MATTERS
m_numValues = std::numeric_limits<std::size_t>::max();
if (m_calibrationWS)
m_numValues = std::min(m_numValues, m_calibrationWS->rowCount());
if (groupingWS)
m_numValues = std::min(m_numValues, groupingWS->getNumberHistograms());
if (maskWS)
m_numValues = std::min(m_numValues, maskWS->getNumberHistograms());

// Initialize the mapping of detid to row number to make getting information
// from the table faster. ORDER MATTERS
if (m_calibrationWS) {
this->generateDetidToIndex();
} else if (groupingWS) {
this->generateDetidToIndex(groupingWS);
} else if (maskWS) {
this->generateDetidToIndex(maskWS);
}

if (groupingWS && groupingWS->isDetectorIDMappingEmpty())
groupingWS->buildDetectorIDMapping();

// delete the file if it already exists
std::string filename = getProperty("Filename");
if (Poco::File(filename).exists()) {
Expand All @@ -209,11 +289,25 @@ void SaveDiffCal::exec() {

// write the d-spacing to TOF conversion parameters for the selected pixels
// as datasets under the NXentry group
this->writeDoubleFieldFromTable(calibrationGroup, "difc");
this->writeDoubleFieldFromTable(calibrationGroup, "difa");
this->writeDoubleFieldFromTable(calibrationGroup, "tzero");
if (m_calibrationWS) {
this->writeDoubleFieldFromTable(calibrationGroup, "difc");
this->writeDoubleFieldFromTable(calibrationGroup, "difa");
this->writeDoubleFieldFromTable(calibrationGroup, "tzero");
} else {
writeDoubleFieldZeros(calibrationGroup, "difc");
// LoadDiffCal will set difa and tzero to zero if they are missing
}

// add the detid from which ever of these exists
if (m_calibrationWS) {
this->writeIntFieldFromTable(calibrationGroup, "detid");
} else if (groupingWS) {
this->writeDetIdsfromSVWS(calibrationGroup, "detid", groupingWS);
} else if (maskWS) {
this->writeDetIdsfromSVWS(calibrationGroup, "detid", maskWS);
}

this->writeIntFieldFromTable(calibrationGroup, "detid");
// the dasid is a legacy column that is not used by mantid but should be written if it exists
if (this->tableHasColumn("dasid")) // optional field
this->writeIntFieldFromTable(calibrationGroup, "dasid");
else
Expand Down
22 changes: 20 additions & 2 deletions Framework/DataHandling/test/SaveDiffCalTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ class SaveDiffCalTest : public CxxTest::TestSuite {
return wksp;
}

void test_no_wksp() {
// test that not supplying any workspaces is a problem
SaveDiffCal alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize());
TS_ASSERT(alg.isInitialized());
TS_ASSERT_THROWS_NOTHING(alg.setProperty("Filename", FILENAME));
TS_ASSERT_THROWS(alg.execute(), const std::runtime_error &);
TS_ASSERT(!alg.isExecuted());
}

void test_no_cal_wksp() {
Instrument_sptr inst = createInstrument();
GroupingWorkspace_sptr groupWS = createGrouping(inst);
Expand All @@ -98,8 +108,16 @@ class SaveDiffCalTest : public CxxTest::TestSuite {
TS_ASSERT_THROWS_NOTHING(alg.setProperty("GroupingWorkspace", groupWS));
TS_ASSERT_THROWS_NOTHING(alg.setProperty("MaskWorkspace", maskWS));
TS_ASSERT_THROWS_NOTHING(alg.setProperty("Filename", FILENAME));
TS_ASSERT_THROWS(alg.execute(), const std::runtime_error &);
TS_ASSERT(!alg.isExecuted());
TS_ASSERT_THROWS_NOTHING(alg.execute());
TS_ASSERT(alg.isExecuted());

// confirm that it exists
std::string filename = alg.getPropertyValue("Filename");
TS_ASSERT(Poco::File(filename).exists());

// cleanup
if (Poco::File(filename).exists())
Poco::File(filename).remove();
}

void test_empty_cal_wksp() {
Expand Down
11 changes: 6 additions & 5 deletions docs/source/algorithms/SaveDiffCal-v1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,24 +10,25 @@
Description
-----------

This algorithm saves a :ref:`diffraction calibration workspace
<DiffractionCalibrationWorkspace>`, ``MaskWorkspace``, and
``GroupingWorkspace`` to a HDF5 file.
This algorithm saves a :ref:`diffraction calibration workspace <DiffractionCalibrationWorkspace>`, ``MaskWorkspace``, and ``GroupingWorkspace`` to a HDF5 file.

The hierarchy of the HDF5 file is as follows:

| calibration
| detid
| dasid (only if present in CalibrationWorkspace)
| difa
| tzero
| difc
| difa (only if not all values are zero)
| tzero (only if not all values are zero)
| group
| use ("0" if detector is not successfully calibrated, "1" otherwise)
| offset (only if present in CalibrationWorkspace)
| instrument
| name
| instrument_source (absolute path to the instrument definition file)
This can be used in an alternate mode without a ``CalibrationWorkspace`` to write out the grouping workspace with the ``difc`` values all set to zero.

.. categories::

.. sourcelink::
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add ability to :ref:`SaveDiffCal <algm-SaveDiffCal>` to not supply a ``CalibrationWorkspace``. It can be used in this mode to save the grouping information.

0 comments on commit c429785

Please sign in to comment.