Tell a Smargon head position from the spindle by equipment_component
The reader recognised chi and phi by name. phi is an ordinary spindle name in MX, so a file whose rotation axis is called phi had it read back as a head position as well as the spindle - and writing that experiment out again threw, because the sample chain then tried to create phi twice. In the other direction a still with a head position had chi, its alphabetically first stationary axis, adopted as the goniometer. Both are now settled by the file: the axes jfjoch writes for a Smargon carry equipment_component="smargon", the reader takes a head position only from a tagged axis, and skips tagged axes when looking for the spindle. NXmx defines equipment_component as an identifier of the component of the equipment a transformation belongs to, which is what this is; there is no "equipment" attribute in NeXus at all. Adds HDF5Object::AttrExists, since the tag is absent on every file from anywhere else. The two tests assert on the written file - the axis length and the attribute - because the reader cannot see either: it does not look at a shape, and it did not look at the tag. That is the same gap that let the one-image shape through. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VfYvJT5Nb71suJCowRBn5z
This commit is contained in:
@@ -609,8 +609,23 @@ HDF5MetadataSource::OpenResult HDF5MetadataSource::Open(const std::string &filen
|
||||
// recorded as "phi" back as stills, silently. Prefer an axis that actually turns; fall back
|
||||
// to a stationary one, which still says where the head was.
|
||||
if (master_file->Exists("/entry/sample/transformations")) {
|
||||
// A Smargon chi/phi is tagged with equipment_component - it is a head position, not the
|
||||
// spindle. Recognised by that tag and not by name: phi is an ordinary spindle name in MX,
|
||||
// so a file from anywhere else must not have its rotation axis read back as a head
|
||||
// position, nor its spindle mistaken for one here.
|
||||
auto is_smargon_axis = [this](const std::string &name) {
|
||||
const std::string dname = "/entry/sample/transformations/" + name;
|
||||
if (!master_file->Exists(dname))
|
||||
return false;
|
||||
HDF5DataSet axis(*master_file, dname);
|
||||
return axis.AttrExists("equipment_component")
|
||||
&& (axis.ReadAttrStr("equipment_component") == "smargon");
|
||||
};
|
||||
|
||||
std::optional<GoniometerAxis> stationary;
|
||||
for (const auto &name: master_file->FindLeafs("/entry/sample/transformations")) {
|
||||
if (is_smargon_axis(name))
|
||||
continue;
|
||||
auto axis = ReadAxis(master_file.get(), name);
|
||||
if (!axis.has_value())
|
||||
continue;
|
||||
@@ -628,8 +643,11 @@ HDF5MetadataSource::OpenResult HDF5MetadataSource::Open(const std::string &filen
|
||||
// chi and phi are ordinary stationary axes in the file; the settings still keep them in
|
||||
// their own Smargon field, so put them back there. Without this a re-opened file lost
|
||||
// the head position entirely - nothing in reader/ read it.
|
||||
const auto chi = ReadAxis(master_file.get(), "chi");
|
||||
const auto phi = ReadAxis(master_file.get(), "phi");
|
||||
std::optional<GoniometerAxis> chi, phi;
|
||||
if (is_smargon_axis("chi"))
|
||||
chi = ReadAxis(master_file.get(), "chi");
|
||||
if (is_smargon_axis("phi"))
|
||||
phi = ReadAxis(master_file.get(), "phi");
|
||||
if (chi.has_value() || phi.has_value()) {
|
||||
SmargonPosition smargon;
|
||||
if (chi.has_value()) {
|
||||
|
||||
Reference in New Issue
Block a user