jfjoch_viewer: Better display (to be tested) of pixel refine
Build Packages / Unit tests (push) Failing after 1s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 25m52s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 29m5s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 29m54s
Build Packages / build:rpm (rocky8) (push) Successful in 31m55s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 32m12s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 32m48s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 35m27s
Build Packages / Generate python client (push) Successful in 25s
Build Packages / build:rpm (rocky9) (push) Successful in 31m59s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m36s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 24m8s
Build Packages / XDS test (neggia plugin) (push) Successful in 17m46s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 21m36s
Build Packages / XDS test (durin plugin) (push) Successful in 19m40s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 19m38s
Build Packages / DIALS test (push) Successful in 26m30s

This commit is contained in:
2026-06-09 16:28:17 +02:00
parent 6c85aaba2b
commit efe882f4b6
10 changed files with 282 additions and 4 deletions
@@ -993,6 +993,122 @@ std::vector<float> PixelRefine::PredictImage(const AzimuthalIntegrationProfile &
return img;
}
template<class T>
std::vector<float> PixelRefine::ChiSquaredImage(const T *image,
const AzimuthalIntegrationProfile &profile,
BraggPrediction &prediction,
const PixelRefineData &data) const {
std::vector<float> img(xpixel * ypixel, 0.0f);
const double lambda = data.geom.GetWavelength_A();
const double pixel_size = data.geom.GetPixelSize_mm();
const auto azim_result = profile.GetResult();
const auto azim_std = profile.GetStd();
const auto &pixel_to_bin = mapping.GetPixelToBin();
const auto &corrections = mapping.Corrections();
const int total_bin_count = static_cast<int>(azim_result.size());
const double angle_rad = data.angle_deg * M_PI / 180.0;
const int radius = data.shoebox_radius;
const double bw = data.bandwidth;
auto recip_area = [&](double x, double y) -> double {
const Coord qx = data.geom.DetectorToRecip(x + 0.5, y) - data.geom.DetectorToRecip(x - 0.5, y);
const Coord qy = data.geom.DetectorToRecip(x, y + 0.5) - data.geom.DetectorToRecip(x, y - 0.5);
return (qx % qy).Length();
};
auto bandwidth_radial_sq = [&](double d) -> double {
if (bw <= 0.0 || d <= 0.0)
return 0.0;
const double bl = bw * lambda;
return bl * bl / (2.0 * d * d * d * d);
};
double beam[2], dist_mm, detector_rot[2], rot_vec[3];
double latt_vec0[3], latt_vec1[3], latt_vec2[3];
BuildParameterBlocks(data, beam, dist_mm, detector_rot, rot_vec, latt_vec0, latt_vec1, latt_vec2);
DiffractionExperiment exp_iter = experiment;
exp_iter.BeamX_pxl(data.geom.GetBeamX_pxl())
.BeamY_pxl(data.geom.GetBeamY_pxl())
.DetectorDistance_mm(data.geom.GetDetectorDistance_mm())
.PoniRot1_rad(data.geom.GetPoniRot1_rad())
.PoniRot2_rad(data.geom.GetPoniRot2_rad());
const BraggPredictionSettings settings_prediction{
.high_res_A = experiment.GetBraggIntegrationSettings().GetDMinLimit_A(),
.max_hkl = 100,
.centering = data.centering,
.bandwidth_sigma = static_cast<float>(data.bandwidth)
};
const int nrefl = prediction.Calc(exp_iter, data.latt, settings_prediction);
const auto &predicted = prediction.GetReflections();
for (int ri = 0; ri < nrefl; ++ri) {
const auto &refl = predicted[ri];
const auto it = reference_data.find(hkl_key_generator(refl));
if (it == reference_data.end())
continue;
const double Itrue = it->second;
const double R_bw_sq = bandwidth_radial_sq(refl.d);
const int min_y = std::max<int>(refl.predicted_y - radius, 0);
const int max_y = std::min<int>(refl.predicted_y + radius, ypixel - 1);
const int min_x = std::max<int>(refl.predicted_x - radius, 0);
const int max_x = std::min<int>(refl.predicted_x + radius, xpixel - 1);
for (int y = min_y; y <= max_y; ++y) {
for (int x = min_x; x <= max_x; ++x) {
const size_t npixel = xpixel * y + x;
const int azim_bin = pixel_to_bin[npixel];
// Same gating as Run(): only pixels that actually enter the fit.
if (azim_bin >= total_bin_count)
continue;
if (image[npixel] == std::numeric_limits<T>::max())
continue;
if (std::is_signed_v<T> && (image[npixel] == std::numeric_limits<T>::min()))
continue;
const double correction = corrections[npixel];
const double Ibkg = azim_result[azim_bin];
const double Ibkg_sigma = azim_std[azim_bin];
const double raw = static_cast<double>(image[npixel]);
const double Iobs = raw * correction;
double var = correction * std::max(Iobs, 0.0) + Ibkg_sigma * Ibkg_sigma;
if (!(var > 1.0))
var = 1.0;
const double weight = 1.0 / std::sqrt(var);
PixelObs obs{
.x = static_cast<double>(x),
.y = static_cast<double>(y),
.Iobs = Iobs,
.Ibkg = Ibkg,
.weight = weight,
.A_recip = recip_area(x, y),
.angle_rad = angle_rad
};
PixelResidual pr(obs, Itrue, lambda, pixel_size,
refl.h, refl.k, refl.l, R_bw_sq, data.crystal_system);
double Ipred = 0.0;
if (pr.Model(beam, &dist_mm, detector_rot, rot_vec,
latt_vec0, latt_vec1, latt_vec2,
&data.scale_factor, &data.B_factor, data.R, Ipred)) {
// residual_i = (I_pred - I_obs) * weight (== Ceres residual);
// its square is this pixel's contribution to the cost.
const double rw = (Ipred - Iobs) * weight;
img[npixel] += static_cast<float>(rw * rw);
}
}
}
}
return img;
}
// Explicit instantiations for the supported (uncompressed) image pixel types.
template void PixelRefine::Run<int8_t>(const int8_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, PixelRefineData &);
template void PixelRefine::Run<int16_t>(const int16_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, PixelRefineData &);
@@ -1000,3 +1116,10 @@ template void PixelRefine::Run<int32_t>(const int32_t *, const AzimuthalIntegrat
template void PixelRefine::Run<uint8_t>(const uint8_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, PixelRefineData &);
template void PixelRefine::Run<uint16_t>(const uint16_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, PixelRefineData &);
template void PixelRefine::Run<uint32_t>(const uint32_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, PixelRefineData &);
template std::vector<float> PixelRefine::ChiSquaredImage<int8_t>(const int8_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, const PixelRefineData &) const;
template std::vector<float> PixelRefine::ChiSquaredImage<int16_t>(const int16_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, const PixelRefineData &) const;
template std::vector<float> PixelRefine::ChiSquaredImage<int32_t>(const int32_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, const PixelRefineData &) const;
template std::vector<float> PixelRefine::ChiSquaredImage<uint8_t>(const uint8_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, const PixelRefineData &) const;
template std::vector<float> PixelRefine::ChiSquaredImage<uint16_t>(const uint16_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, const PixelRefineData &) const;
template std::vector<float> PixelRefine::ChiSquaredImage<uint32_t>(const uint32_t *, const AzimuthalIntegrationProfile &, BraggPrediction &, const PixelRefineData &) const;