grid scan: say how the stationary spindle angle is stated, and pin it
A grid scan is a set of stills at a stationary spindle, and the angle it stood at is what relates one grid to another taken elsewhere on the circle. Users were finding an all-zero omega in the file and concluding the angle could not be recorded at all. It already can, and has since the goniometer and the grid scan stopped being alternatives: send the axis with step 0 and its start angle, and that angle is written per image into the NXmx sample chain, read back by reader/, and taken by dials.import as a set of stills. Measured on a generated 12-image grid: the placeholder file carries omega = 0 x 12, the same file with the axis sent at step 0 carries omega = 90 x 12, and dials.import reports "still: 1, sweep: 0" for both. Nothing in the code needed changing, so nothing was; what was missing was that nobody could tell, and that no test held the behaviour down. So: the API and the HDF5 documentation now say it in as many words, and three tests pin the three legs the value crosses - the OpenAPI request (which used to drop the grid scan whenever an axis was present, unpinned until now), the CBOR start message, and the file round trip. Also corrects a claim two comments and the HDF5 page were making. NXmx can express "no rotation" perfectly well - a sample may depend_on "." - so the placeholder is not there for the standard's sake. It is there because dxtbx cannot read a sample chain of translations alone: strip the rotation axis from a grid scan master and dials.import dies in get_dxtbx_goniometer with a matmul dimension mismatch. Recorded so nobody removes the placeholder on the strength of the standard. One thing the change does not fix, because it cannot: a stationary angle is invisible to DIALS when a grid scan is present. dxtbx picks the first varying axis as the scan axis, which is a grid translation, so the oscillation reads (0, 0); and with exactly one rotation axis in the chain it builds a single-axis goniometer whose fixed rotation is the identity, never consulting the angle. The same angle IS visible when it is the only candidate (oscillation reads (90, 0)) or when a Smargon head puts a second rotation axis in the chain (the setting rotation then carries it). The value is in the file and correct either way.
This commit is contained in:
@@ -8,7 +8,9 @@
|
||||
#include "../common/NetworkAddressConvert.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "Dataset_settings.h"
|
||||
#include "Dataset_settings_smargon.h"
|
||||
#include "../broker/OpenAPIConvert.h"
|
||||
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
@@ -1238,3 +1240,25 @@ TEST_CASE("DiffractionExperiment_SmargonChiReadoutNoise", "[DiffractionExperimen
|
||||
REQUIRE(noisy.GetValues().size() == zero.GetValues().size());
|
||||
CHECK(noisy.GetValues().at(0) == Catch::Approx(zero.GetValues().at(0)).margin(1e-6));
|
||||
}
|
||||
|
||||
// A grid scan and a goniometer axis are not alternatives: a grid is collected at a stationary
|
||||
// spindle, and the axis sent with step 0 is what states the angle it stood at. The request used to
|
||||
// drop the grid scan whenever an axis was present, and nothing pinned it.
|
||||
TEST_CASE("DiffractionExperiment_GridScanAtStationaryAxis", "[DiffractionExperiment]") {
|
||||
org::openapitools::server::model::Dataset_settings model;
|
||||
from_json(nlohmann::json::parse(R"({
|
||||
"images_per_trigger": 12,
|
||||
"beam_x_pxl": 512.0, "beam_y_pxl": 256.0,
|
||||
"detector_distance_mm": 150.0, "incident_energy_keV": 12.4,
|
||||
"grid_scan": {"n_fast": 4, "step_x_um": 20.0, "step_y_um": 20.0},
|
||||
"goniometer": {"name": "omega", "start": 90.0, "step": 0.0, "vector": [-1, 0, 0]}
|
||||
})"), model);
|
||||
|
||||
const auto settings = Convert(model);
|
||||
REQUIRE(settings.GetGridScan().has_value());
|
||||
CHECK(settings.GetGridScan()->GetNFast() == 4);
|
||||
REQUIRE(settings.GetGoniometer().has_value());
|
||||
CHECK(settings.GetGoniometer()->GetName() == "omega");
|
||||
CHECK(!settings.GetGoniometer()->IsScanning());
|
||||
CHECK(settings.GetGoniometer()->GetStart_deg() == Catch::Approx(90.0f));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user