From c981f715515883b128ea926fa3411b59be2712ce Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 21 Jul 2023 15:36:16 +0100 Subject: [PATCH 01/20] Add a probe enum --- src/dxtbx/model/beam.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 9903341ec..beae21fca 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -24,6 +24,9 @@ namespace dxtbx { namespace model { using scitbx::vec3; + // probe type enumeration + enum probe { xray = 1, electron = 2, neutron = 3 }; + /** Base class for beam objects */ class BeamBase { public: @@ -385,6 +388,7 @@ namespace dxtbx { namespace model { double flux_; double transmission_; scitbx::af::shared > s0_at_scan_points_; + probe probe_; }; /** Print beam information */ From bae2822adddf66ffaa1c4b88926f7ca093d14585 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 21 Jul 2023 15:42:24 +0100 Subject: [PATCH 02/20] get_probe accessor --- src/dxtbx/model/beam.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index beae21fca..4d49b01cf 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -47,6 +47,7 @@ namespace dxtbx { namespace model { virtual std::size_t get_num_scan_points() const = 0; virtual scitbx::af::shared > get_s0_at_scan_points() const = 0; virtual vec3 get_s0_at_scan_point(std::size_t index) const = 0; + virtual probe get_probe() const = 0; virtual void set_direction(vec3 direction) = 0; virtual void set_wavelength(double wavelength) = 0; @@ -292,6 +293,10 @@ namespace dxtbx { namespace model { return s0_at_scan_points_[index]; } + probe get_probe() const { + return probe_; + } + void reset_scan_points() { s0_at_scan_points_.clear(); } From 6eea2fd78a43eb0cdc87be2c0253fedaaf71455c Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 21 Jul 2023 16:03:14 +0100 Subject: [PATCH 03/20] probe-->Probe, and export to Python. So now, can do from dxtbx.model.beam import Probe --- src/dxtbx/model/beam.h | 8 ++++---- src/dxtbx/model/beam.py | 4 ++-- src/dxtbx/model/boost_python/beam.cc | 6 ++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 4d49b01cf..0769f53ed 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -25,7 +25,7 @@ namespace dxtbx { namespace model { using scitbx::vec3; // probe type enumeration - enum probe { xray = 1, electron = 2, neutron = 3 }; + enum Probe { xray = 1, electron = 2, neutron = 3 }; /** Base class for beam objects */ class BeamBase { @@ -47,7 +47,7 @@ namespace dxtbx { namespace model { virtual std::size_t get_num_scan_points() const = 0; virtual scitbx::af::shared > get_s0_at_scan_points() const = 0; virtual vec3 get_s0_at_scan_point(std::size_t index) const = 0; - virtual probe get_probe() const = 0; + virtual Probe get_probe() const = 0; virtual void set_direction(vec3 direction) = 0; virtual void set_wavelength(double wavelength) = 0; @@ -293,7 +293,7 @@ namespace dxtbx { namespace model { return s0_at_scan_points_[index]; } - probe get_probe() const { + Probe get_probe() const { return probe_; } @@ -393,7 +393,7 @@ namespace dxtbx { namespace model { double flux_; double transmission_; scitbx::af::shared > s0_at_scan_points_; - probe probe_; + Probe probe_; }; /** Print beam information */ diff --git a/src/dxtbx/model/beam.py b/src/dxtbx/model/beam.py index 870dd9c4b..f128e85a1 100644 --- a/src/dxtbx/model/beam.py +++ b/src/dxtbx/model/beam.py @@ -7,9 +7,9 @@ import libtbx.phil try: - from ..dxtbx_model_ext import Beam + from ..dxtbx_model_ext import Beam, Probe except ModuleNotFoundError: - from dxtbx_model_ext import Beam # type: ignore + from dxtbx_model_ext import Beam, Probe # type: ignore beam_phil_scope = libtbx.phil.parse( """ diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index bf709d526..a9b77751a 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -17,6 +17,7 @@ #include #include #include +#include namespace dxtbx { namespace model { namespace boost_python { namespace beam_detail { @@ -224,6 +225,11 @@ namespace dxtbx { namespace model { namespace boost_python { void export_beam() { using namespace beam_detail; + enum_("Probe") + .value("xray", xray) + .value("electron", electron) + .value("neutron", neutron); + class_("BeamBase", no_init) .def("get_sample_to_source_direction", &BeamBase::get_sample_to_source_direction) .def("set_direction", &BeamBase::set_direction) From eb22c37cc0852f9edd3105050fc4ee28d27c7772 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 21 Jul 2023 16:08:40 +0100 Subject: [PATCH 04/20] Export get_probe Note the value is uninitialized! --- src/dxtbx/model/boost_python/beam.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index a9b77751a..f528d8902 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -260,6 +260,7 @@ namespace dxtbx { namespace model { namespace boost_python { .def("set_s0_at_scan_points", &Beam_set_s0_at_scan_points_from_list) .def("get_s0_at_scan_points", &BeamBase::get_s0_at_scan_points) .def("get_s0_at_scan_point", &BeamBase::get_s0_at_scan_point) + .def("get_probe", &BeamBase::get_probe) .def("reset_scan_points", &BeamBase::reset_scan_points) .def("rotate_around_origin", &rotate_around_origin, From 2b79fd8f6dbb72f351549b072421c66d548e9906 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 21 Jul 2023 16:15:48 +0100 Subject: [PATCH 05/20] Ensure probe_ is initialized. Now we get: >>> from dxtbx.model.beam import Beam >>> b=Beam() >>> b.get_probe() dxtbx_model_ext.Probe.xray --- src/dxtbx/model/beam.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 0769f53ed..876d482cf 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -86,7 +86,8 @@ namespace dxtbx { namespace model { polarization_normal_(0.0, 1.0, 0.0), polarization_fraction_(0.999), flux_(0), - transmission_(1.0) {} + transmission_(1.0), + probe_(Probe::xray) {} /** * @param s0 The incident beam vector. From 6979e25aecf1a7e03ffd1884f443a4daabb670be Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 21 Jul 2023 16:34:19 +0100 Subject: [PATCH 06/20] Add set_probe and export. Now this works: >>> from dxtbx.model.beam import Beam >>> b=Beam() >>> b.get_probe() dxtbx_model_ext.Probe.xray >>> from dxtbx.model.beam import Probe >>> b.set_probe(Probe.neutron) >>> b.get_probe() dxtbx_model_ext.Probe.neutron --- src/dxtbx/model/beam.h | 5 +++++ src/dxtbx/model/boost_python/beam.cc | 1 + 2 files changed, 6 insertions(+) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 876d482cf..406b6ed52 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -63,6 +63,7 @@ namespace dxtbx { namespace model { virtual void set_transmission(double transmission) = 0; virtual void set_s0_at_scan_points( const scitbx::af::const_ref > &s0) = 0; + virtual void set_probe(Probe probe) = 0; virtual void reset_scan_points() = 0; virtual bool is_similar_to(const BeamBase &rhs, @@ -298,6 +299,10 @@ namespace dxtbx { namespace model { return probe_; } + void set_probe(Probe probe) { + probe_ = probe; + } + void reset_scan_points() { s0_at_scan_points_.clear(); } diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index f528d8902..370a22b28 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -261,6 +261,7 @@ namespace dxtbx { namespace model { namespace boost_python { .def("get_s0_at_scan_points", &BeamBase::get_s0_at_scan_points) .def("get_s0_at_scan_point", &BeamBase::get_s0_at_scan_point) .def("get_probe", &BeamBase::get_probe) + .def("set_probe", &BeamBase::set_probe) .def("reset_scan_points", &BeamBase::reset_scan_points) .def("rotate_around_origin", &rotate_around_origin, From e5c88399296552d07ebb184684705eb331b5af52 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 10:02:21 +0100 Subject: [PATCH 07/20] Ensure probe is initialised by the other constructors too --- src/dxtbx/model/beam.h | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 406b6ed52..ac161411f 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -99,7 +99,8 @@ namespace dxtbx { namespace model { polarization_normal_(0.0, 1.0, 0.0), polarization_fraction_(0.999), flux_(0), - transmission_(1.0) { + transmission_(1.0), + probe_(Probe::xray) { DXTBX_ASSERT(s0.length() > 0); wavelength_ = 1.0 / s0.length(); direction_ = -s0.normalize(); @@ -116,7 +117,8 @@ namespace dxtbx { namespace model { polarization_normal_(0.0, 1.0, 0.0), polarization_fraction_(0.999), flux_(0), - transmission_(1.0) { + transmission_(1.0), + probe_(Probe::xray) { DXTBX_ASSERT(direction.length() > 0); direction_ = direction.normalize(); } @@ -132,7 +134,8 @@ namespace dxtbx { namespace model { polarization_normal_(0.0, 1.0, 0.0), polarization_fraction_(0.999), flux_(0), - transmission_(1.0) { + transmission_(1.0), + probe_(Probe::xray) { DXTBX_ASSERT(s0.length() > 0); wavelength_ = 1.0 / s0.length(); direction_ = -s0.normalize(); @@ -154,7 +157,8 @@ namespace dxtbx { namespace model { polarization_normal_(0.0, 1.0, 0.0), polarization_fraction_(0.999), flux_(0), - transmission_(1.0) { + transmission_(1.0), + probe_(Probe::xray) { DXTBX_ASSERT(direction.length() > 0); direction_ = direction.normalize(); } @@ -183,7 +187,8 @@ namespace dxtbx { namespace model { polarization_normal_(polarization_normal), polarization_fraction_(polarization_fraction), flux_(flux), - transmission_(transmission) { + transmission_(transmission), + probe_(Probe::xray) { DXTBX_ASSERT(direction.length() > 0); direction_ = direction.normalize(); } From 48c096df385c2835984a52c8ec1c4484e86e1634 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 10:16:45 +0100 Subject: [PATCH 08/20] Incorporate probe into equality and similarity checks --- src/dxtbx/model/beam.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index ac161411f..55d0b603a 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -343,7 +343,8 @@ namespace dxtbx { namespace model { angle_safe(polarization_normal_, rhs.get_polarization_normal())) <= eps && std::abs(polarization_fraction_ - rhs.get_polarization_fraction()) - <= eps; + <= eps + && (probe_ == rhs.get_probe()); } bool is_similar_to(const BeamBase &rhs, @@ -380,7 +381,8 @@ namespace dxtbx { namespace model { angle_safe(polarization_normal_, rhs.get_polarization_normal())) <= polarization_normal_tolerance && std::abs(polarization_fraction_ - rhs.get_polarization_fraction()) - <= polarization_fraction_tolerance; + <= polarization_fraction_tolerance + && (probe_ == rhs.get_probe()); } bool operator!=(const BeamBase &rhs) const { From 899b166748c520281f85916423f1b9f10b64fae9 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 11:03:53 +0100 Subject: [PATCH 09/20] Add get_probe_name method so that the NeXus probe name can be returned for each of the defined probe values --- src/dxtbx/model/beam.h | 18 ++++++++++++++++++ src/dxtbx/model/boost_python/beam.cc | 1 + 2 files changed, 19 insertions(+) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 55d0b603a..f3f1ed6a2 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -48,6 +49,7 @@ namespace dxtbx { namespace model { virtual scitbx::af::shared > get_s0_at_scan_points() const = 0; virtual vec3 get_s0_at_scan_point(std::size_t index) const = 0; virtual Probe get_probe() const = 0; + virtual std::string get_probe_name() const = 0; virtual void set_direction(vec3 direction) = 0; virtual void set_wavelength(double wavelength) = 0; @@ -304,6 +306,21 @@ namespace dxtbx { namespace model { return probe_; } + std::string get_probe_name() const { + // Return a name that matches NeXus definitions from + // https://manual.nexusformat.org/classes/base_classes/NXsource.html + switch (probe_) { + case xray: + return std::string("x-ray"); + case electron: + return std::string("electron"); + case neutron: + return std::string("neutron"); + default: + return std::string("unknown"); + } + } + void set_probe(Probe probe) { probe_ = probe; } @@ -412,6 +429,7 @@ namespace dxtbx { namespace model { /** Print beam information */ inline std::ostream &operator<<(std::ostream &os, const Beam &b) { os << "Beam:\n"; + os << " probe: " << b.get_probe_name() << "\n"; os << " wavelength: " << b.get_wavelength() << "\n"; os << " sample to source direction : " << b.get_sample_to_source_direction().const_ref() << "\n"; diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index 370a22b28..6892813e9 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -261,6 +261,7 @@ namespace dxtbx { namespace model { namespace boost_python { .def("get_s0_at_scan_points", &BeamBase::get_s0_at_scan_points) .def("get_s0_at_scan_point", &BeamBase::get_s0_at_scan_point) .def("get_probe", &BeamBase::get_probe) + .def("get_probe_name", &BeamBase::get_probe_name) .def("set_probe", &BeamBase::set_probe) .def("reset_scan_points", &BeamBase::reset_scan_points) .def("rotate_around_origin", From 463391b6964f7a494854e26cef349ab9fa0646d4 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 13:46:23 +0100 Subject: [PATCH 10/20] Include the probe in to/from dict methods and pickle suite. --- src/dxtbx/model/beam.h | 6 ++++-- src/dxtbx/model/beam.py | 4 ++++ src/dxtbx/model/boost_python/beam.cc | 15 +++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index f3f1ed6a2..b34b31ba0 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -174,6 +174,7 @@ namespace dxtbx { namespace model { * @param polarization_fraction The polarization fraction * @param flux The beam flux * @param transmission The beam transmission + * @param probe The probe value */ Beam(vec3 direction, double wavelength, @@ -182,7 +183,8 @@ namespace dxtbx { namespace model { vec3 polarization_normal, double polarization_fraction, double flux, - double transmission) + double transmission, + Probe probe) : wavelength_(wavelength), divergence_(divergence), sigma_divergence_(sigma_divergence), @@ -190,7 +192,7 @@ namespace dxtbx { namespace model { polarization_fraction_(polarization_fraction), flux_(flux), transmission_(transmission), - probe_(Probe::xray) { + probe_(probe) { DXTBX_ASSERT(direction.length() > 0); direction_ = direction.normalize(); } diff --git a/src/dxtbx/model/beam.py b/src/dxtbx/model/beam.py index f128e85a1..376b8f0ae 100644 --- a/src/dxtbx/model/beam.py +++ b/src/dxtbx/model/beam.py @@ -101,6 +101,10 @@ def from_dict(d, t=None): joint.update(d) # Create the model from the joint dictionary + if "probe" in joint: + joint["probe"] = Probe.values[joint["probe"]] + else: + joint["probe"] = Probe.xray return Beam.from_dict(joint) @staticmethod diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index 6892813e9..8ad5f6964 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -41,7 +41,8 @@ namespace dxtbx { namespace model { namespace boost_python { obj.get_polarization_normal(), obj.get_polarization_fraction(), obj.get_flux(), - obj.get_transmission()); + obj.get_transmission(), + obj.get_probe()); } static boost::python::tuple getstate(boost::python::object obj) { @@ -108,6 +109,7 @@ namespace dxtbx { namespace model { namespace boost_python { double polarization_fraction, double flux, double transmission, + Probe probe, bool deg) { Beam *beam = NULL; if (deg) { @@ -118,7 +120,8 @@ namespace dxtbx { namespace model { namespace boost_python { polarization_normal, polarization_fraction, flux, - transmission); + transmission, + probe); } else { beam = new Beam(sample_to_source, wavelength, @@ -127,7 +130,8 @@ namespace dxtbx { namespace model { namespace boost_python { polarization_normal, polarization_fraction, flux, - transmission); + transmission, + probe); } return beam; } @@ -189,6 +193,7 @@ namespace dxtbx { namespace model { namespace boost_python { result["polarization_fraction"] = obj.get_polarization_fraction(); result["flux"] = obj.get_flux(); result["transmission"] = obj.get_transmission(); + result["probe"] = obj.get_probe(); if (obj.get_num_scan_points() > 0) { boost::python::list l; scitbx::af::shared > s0_at_scan_points = obj.get_s0_at_scan_points(); @@ -213,7 +218,8 @@ namespace dxtbx { namespace model { namespace boost_python { obj.get("polarization_normal", vec3(0.0, 1.0, 0.0))), boost::python::extract(obj.get("polarization_fraction", 0.999)), boost::python::extract(obj.get("flux", 0)), - boost::python::extract(obj.get("transmission", 1))); + boost::python::extract(obj.get("transmission", 1)), + boost::python::extract(obj.get("probe", Probe::xray))); if (obj.has_key("s0_at_scan_points")) { boost::python::list s0_at_scan_points = boost::python::extract(obj["s0_at_scan_points"]); @@ -307,6 +313,7 @@ namespace dxtbx { namespace model { namespace boost_python { arg("polarization_fraction"), arg("flux"), arg("transmission"), + arg("probe") = Probe::xray, arg("deg") = true))) .def("__str__", &beam_to_string) .def("to_dict", &to_dict) From 0b08c5db08f4a485d94dd07acb751b08f02049fb Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 14:09:47 +0100 Subject: [PATCH 11/20] Add probe to make_polarized_beam, and fix longstanding bug in that method --- src/dxtbx/model/beam.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dxtbx/model/beam.py b/src/dxtbx/model/beam.py index 376b8f0ae..2436af348 100644 --- a/src/dxtbx/model/beam.py +++ b/src/dxtbx/model/beam.py @@ -153,6 +153,7 @@ def make_polarized_beam( sigma_divergence=None, flux=None, transmission=None, + probe=Probe.xray, ): assert polarization assert 0.0 <= polarization_fraction <= 1.0 @@ -177,6 +178,7 @@ def make_polarized_beam( float(polarization_fraction), float(flux), float(transmission), + probe, ) elif unit_s0: assert wavelength @@ -189,17 +191,23 @@ def make_polarized_beam( float(polarization_fraction), float(flux), float(transmission), + probe, ) else: assert s0 + sum_sq_s0 = s0[0] ** 2 + s0[1] ** 2 + s0[2] ** 2 + assert sum_sq_s0 > 0 + wavelength = 1.0 / math.sqrt(sum_sq_s0) return Beam( tuple(map(float, s0)), + wavelength, float(divergence), float(sigma_divergence), tuple(map(float, polarization)), float(polarization_fraction), float(flux), float(transmission), + probe, ) @staticmethod From f5e5441fbd1333ea57c4558de90f96f9fd121162 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 14:15:31 +0100 Subject: [PATCH 12/20] Set electron probe for various 3D ED format classes --- src/dxtbx/format/FormatGatanDM4.py | 2 ++ src/dxtbx/format/FormatMRC.py | 2 ++ src/dxtbx/format/FormatSMVTimePix_SU.py | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/dxtbx/format/FormatGatanDM4.py b/src/dxtbx/format/FormatGatanDM4.py index d5cb31181..acb93f1ef 100644 --- a/src/dxtbx/format/FormatGatanDM4.py +++ b/src/dxtbx/format/FormatGatanDM4.py @@ -21,6 +21,7 @@ ) from dxtbx.format.Format import Format from dxtbx.format.FormatMultiImage import FormatMultiImage +from dxtbx.model.beam import Probe def read_tag(f, byteorder): @@ -358,6 +359,7 @@ def _beam(self): wavelength=wavelength, polarization=(0, 1, 0), polarization_fraction=0.5, + probe=Probe.electron, ) def _scan(self): diff --git a/src/dxtbx/format/FormatMRC.py b/src/dxtbx/format/FormatMRC.py index 0b9b06226..b7d9b30bb 100644 --- a/src/dxtbx/format/FormatMRC.py +++ b/src/dxtbx/format/FormatMRC.py @@ -19,6 +19,7 @@ from dxtbx.format.Format import Format from dxtbx.format.FormatMultiImage import FormatMultiImage from dxtbx.model import ScanFactory +from dxtbx.model.beam import Probe logger = logging.getLogger("dials") @@ -226,6 +227,7 @@ def _beam(self): wavelength=wavelength, polarization=(0, 1, 0), polarization_fraction=0.5, + probe=Probe.electron, ) diff --git a/src/dxtbx/format/FormatSMVTimePix_SU.py b/src/dxtbx/format/FormatSMVTimePix_SU.py index 223061836..b3492ff56 100644 --- a/src/dxtbx/format/FormatSMVTimePix_SU.py +++ b/src/dxtbx/format/FormatSMVTimePix_SU.py @@ -12,6 +12,7 @@ from scitbx import matrix from dxtbx.format.FormatSMV import FormatSMV +from dxtbx.model.beam import Probe from dxtbx.model.detector import Detector @@ -76,6 +77,7 @@ def _beam(self): wavelength=wavelength, polarization=(0, 1, 0), polarization_fraction=0.5, + probe=Probe.electron, ) def _scan(self): From 9f2400ad2cb1fc796e16e4f4ecf7982c6dbc4e3e Mon Sep 17 00:00:00 2001 From: David Waterman Date: Mon, 24 Jul 2023 16:24:38 +0100 Subject: [PATCH 13/20] News --- newsfragments/xxx.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/xxx.feature diff --git a/newsfragments/xxx.feature b/newsfragments/xxx.feature new file mode 100644 index 000000000..0ff6b0846 --- /dev/null +++ b/newsfragments/xxx.feature @@ -0,0 +1 @@ +The ``Beam`` model now has a ``probe`` value to keep track of the type of radiation. From 823b075aac0c9d5192b06904feefcb3365462a92 Mon Sep 17 00:00:00 2001 From: DiamondLightSource-build-server Date: Mon, 24 Jul 2023 15:32:56 +0000 Subject: [PATCH 14/20] Rename newsfragments/xxx.feature to newsfragments/647.feature --- newsfragments/{xxx.feature => 647.feature} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename newsfragments/{xxx.feature => 647.feature} (100%) diff --git a/newsfragments/xxx.feature b/newsfragments/647.feature similarity index 100% rename from newsfragments/xxx.feature rename to newsfragments/647.feature From d2cf031c5ceaebb218d15acf7ec363fe86a53327 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Wed, 2 Aug 2023 17:11:14 +0100 Subject: [PATCH 15/20] Add probe to PolychromaticBeam --- src/dxtbx/model/beam.h | 17 +++++++++++++---- src/dxtbx/model/boost_python/beam.cc | 15 +++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index b6083f592..799c7f45c 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -423,11 +423,11 @@ namespace dxtbx { namespace model { double polarization_fraction_; double flux_; double transmission_; + Probe probe_; private: double wavelength_; scitbx::af::shared > s0_at_scan_points_; - Probe probe_; }; /** Print beam information */ @@ -457,6 +457,7 @@ namespace dxtbx { namespace model { set_polarization_fraction(0.5); set_flux(0); set_transmission(1.0); + set_probe(Probe::xray); } /** @@ -471,6 +472,7 @@ namespace dxtbx { namespace model { set_polarization_fraction(0.5); set_flux(0); set_transmission(1.0); + set_probe(Probe::xray); } /** @@ -489,6 +491,7 @@ namespace dxtbx { namespace model { set_polarization_fraction(0.5); set_flux(0); set_transmission(1.0); + set_probe(Probe::xray); } /** @@ -499,6 +502,7 @@ namespace dxtbx { namespace model { * @param polarization_fraction The polarization fraction * @param flux The beam flux * @param transmission The beam transmission + * @param probe The probe value */ PolychromaticBeam(vec3 direction, double divergence, @@ -506,7 +510,8 @@ namespace dxtbx { namespace model { vec3 polarization_normal, double polarization_fraction, double flux, - double transmission) { + double transmission, + Probe probe) { DXTBX_ASSERT(direction.length() > 0); direction_ = direction.normalize(); set_divergence(divergence); @@ -515,6 +520,7 @@ namespace dxtbx { namespace model { set_polarization_fraction(polarization_fraction); set_flux(flux); set_transmission(transmission); + set_probe(probe); } double get_wavelength() const { @@ -569,7 +575,8 @@ namespace dxtbx { namespace model { angle_safe(polarization_normal_, rhs.get_polarization_normal())) <= eps && std::abs(polarization_fraction_ - rhs.get_polarization_fraction()) - <= eps; + <= eps + && (probe_ == rhs.get_probe()); } bool is_similar_to(const BeamBase &rhs, @@ -593,13 +600,15 @@ namespace dxtbx { namespace model { angle_safe(polarization_normal_, rhs.get_polarization_normal())) <= polarization_normal_tolerance && std::abs(polarization_fraction_ - rhs.get_polarization_fraction()) - <= polarization_fraction_tolerance; + <= polarization_fraction_tolerance + && (probe_ == rhs.get_probe()); } }; /** Print beam information */ inline std::ostream &operator<<(std::ostream &os, const PolychromaticBeam &b) { os << "Beam:\n"; + os << " probe: " << b.get_probe_name() << "\n"; os << " sample to source direction : " << b.get_sample_to_source_direction().const_ref() << "\n"; os << " divergence: " << b.get_divergence() << "\n"; diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index 173fc96d4..98ca40957 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -247,7 +247,8 @@ namespace dxtbx { namespace model { namespace boost_python { obj.get_polarization_normal(), obj.get_polarization_fraction(), obj.get_flux(), - obj.get_transmission()); + obj.get_transmission(), + obj.get_probe()); } }; @@ -277,6 +278,7 @@ namespace dxtbx { namespace model { namespace boost_python { double polarization_fraction, double flux, double transmission, + Probe probe, bool deg) { PolychromaticBeam *beam = NULL; if (deg) { @@ -286,7 +288,8 @@ namespace dxtbx { namespace model { namespace boost_python { polarization_normal, polarization_fraction, flux, - transmission); + transmission, + probe); } else { beam = new PolychromaticBeam(direction, divergence, @@ -294,7 +297,8 @@ namespace dxtbx { namespace model { namespace boost_python { polarization_normal, polarization_fraction, flux, - transmission); + transmission, + probe); } return beam; } @@ -310,6 +314,7 @@ namespace dxtbx { namespace model { namespace boost_python { result["polarization_fraction"] = obj.get_polarization_fraction(); result["flux"] = obj.get_flux(); result["transmission"] = obj.get_transmission(); + result["probe"] = obj.get_probe(); return result; } @@ -323,7 +328,8 @@ namespace dxtbx { namespace model { namespace boost_python { obj.get("polarization_normal", vec3(0.0, 1.0, 0.0))), boost::python::extract(obj.get("polarization_fraction", 0.999)), boost::python::extract(obj.get("flux", 0)), - boost::python::extract(obj.get("transmission", 1))); + boost::python::extract(obj.get("transmission", 1)), + boost::python::extract(obj.get("probe", Probe::xray))); return b; } @@ -442,6 +448,7 @@ namespace dxtbx { namespace model { namespace boost_python { arg("polarization_fraction"), arg("flux"), arg("transmission"), + arg("probe") = Probe::xray, arg("deg") = true))) .def("__str__", &PolychromaticBeam_to_string) .def("to_dict", &to_dict) From 7f0e28905c6f364f1e7a39649e117c54a7d0bbd7 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Wed, 2 Aug 2023 17:43:17 +0100 Subject: [PATCH 16/20] Fixes for tests --- src/dxtbx/model/beam.py | 6 ++++-- tests/model/test_beam.py | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/dxtbx/model/beam.py b/src/dxtbx/model/beam.py index 10741b433..5ae08b3d5 100644 --- a/src/dxtbx/model/beam.py +++ b/src/dxtbx/model/beam.py @@ -8,9 +8,9 @@ import libtbx.phil try: - from ..dxtbx_model_ext import Beam, Probe, PolychromaticBeam + from ..dxtbx_model_ext import Beam, PolychromaticBeam, Probe except ModuleNotFoundError: - from dxtbx_model_ext import Beam, Probe, PolychromaticBeam # type: ignore + from dxtbx_model_ext import Beam, PolychromaticBeam, Probe # type: ignore Vec3Float = Tuple[float, float, float] @@ -181,6 +181,7 @@ def make_polychromatic_beam( polarization_fraction: float = 0.5, flux: float = 0.0, transmission: float = 1.0, + probe=Probe.xray, deg: bool = True, ) -> PolychromaticBeam: return PolychromaticBeam( @@ -191,6 +192,7 @@ def make_polychromatic_beam( float(polarization_fraction), float(flux), float(transmission), + probe, bool(deg), ) diff --git a/tests/model/test_beam.py b/tests/model/test_beam.py index 2f83a790c..48a6eb5a1 100644 --- a/tests/model/test_beam.py +++ b/tests/model/test_beam.py @@ -6,7 +6,7 @@ from scitbx import matrix from dxtbx.model import Beam, PolychromaticBeam -from dxtbx.model.beam import BeamFactory, beam_phil_scope +from dxtbx.model.beam import BeamFactory, Probe, beam_phil_scope def test_setting_direction_and_wavelength(): @@ -222,6 +222,7 @@ def test_make_polychromatic_beam(): polarization_fraction = 0.65 transmission = 0.5 flux = 0.75 + probe = Probe.neutron beam = BeamFactory.make_polychromatic_beam( direction=direction, @@ -231,6 +232,7 @@ def test_make_polychromatic_beam(): polarization_fraction=polarization_fraction, transmission=transmission, flux=flux, + probe=probe, ) assert beam.get_sample_to_source_direction() == pytest.approx((0.0, 0.0, 1.0)) @@ -240,6 +242,7 @@ def test_make_polychromatic_beam(): assert beam.get_polarization_fraction() == pytest.approx(0.65) assert beam.get_transmission() == pytest.approx(0.5) assert beam.get_flux() == pytest.approx(0.75) + assert beam.get_probe() == Probe.neutron def test_polychromatic_beam_wavelength_guards(): @@ -266,5 +269,5 @@ def test_polychromatic_beam_str(): beam = PolychromaticBeam() assert ( beam.__str__() - == "Beam:\n sample to source direction : {0,0,1}\n divergence: 0\n sigma divergence: 0\n polarization normal: {0,1,0}\n polarization fraction: 0.5\n flux: 0\n transmission: 1\n" + == "Beam:\n probe: x-ray\n sample to source direction : {0,0,1}\n divergence: 0\n sigma divergence: 0\n polarization normal: {0,1,0}\n polarization fraction: 0.5\n flux: 0\n transmission: 1\n" ) From 1f3c257296796dd3c4f1432c58c914a0d5078d6e Mon Sep 17 00:00:00 2001 From: davidmcdonagh Date: Thu, 3 Aug 2023 13:01:20 +0100 Subject: [PATCH 17/20] Added get_probe_from_name to Beam. Added Probe to beam_phil_scope. Changed Probe in .expt files to be human readable. --- src/dxtbx/model/beam.h | 16 ++++++++++++++++ src/dxtbx/model/beam.py | 10 ++++++++-- src/dxtbx/model/boost_python/beam.cc | 12 ++++++++---- tests/model/test_beam.py | 12 ++++++++++++ 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index 799c7f45c..fe2fda864 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -323,6 +323,22 @@ namespace dxtbx { namespace model { } } + static Probe get_probe_from_name(const std::string probe) { + // Return a Probe matched to NeXus definitions from + // https://manual.nexusformat.org/classes/base_classes/NXsource.html + + if (probe == "x-ray") { + return Probe::xray; + } else if (probe == "electron") { + return Probe::electron; + } else if (probe == "neutron") { + return Probe::neutron; + } + + DXTBX_ERROR("Unknown probe " + probe); + return Probe::xray; + } + void set_probe(Probe probe) { probe_ = probe; } diff --git a/src/dxtbx/model/beam.py b/src/dxtbx/model/beam.py index 5ae08b3d5..4cd19be32 100644 --- a/src/dxtbx/model/beam.py +++ b/src/dxtbx/model/beam.py @@ -25,6 +25,11 @@ .help = "Override the beam type" .short_caption = "beam_type" + probe = *x-ray electron neutron + .type = choice + .help = "Override the beam probe" + .short_caption = "beam_probe" + wavelength = None .type = float .help = "Override the beam wavelength" @@ -111,6 +116,7 @@ def from_phil( beam.set_transmission(params.beam.transmission) if params.beam.flux is not None: beam.set_flux(params.beam.flux) + beam.set_probe(Beam.get_probe_from_name(params.beam.probe)) return beam @@ -131,9 +137,9 @@ def from_dict(dict: dict, template: dict = None) -> Beam | PolychromaticBeam: # Create the model from the joint dictionary if "probe" in joint: - joint["probe"] = Probe.values[joint["probe"]] + joint["probe"] = joint["probe"] else: - joint["probe"] = Probe.xray + joint["probe"] = Beam.get_probe_name(Probe.xray) if joint.get("__id__") == "polychromatic": return PolychromaticBeam.from_dict(joint) diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index 98ca40957..e5024d9d5 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -196,7 +196,7 @@ namespace dxtbx { namespace model { namespace boost_python { result["polarization_fraction"] = obj.get_polarization_fraction(); result["flux"] = obj.get_flux(); result["transmission"] = obj.get_transmission(); - result["probe"] = obj.get_probe(); + result["probe"] = obj.get_probe_name(); if (obj.get_num_scan_points() > 0) { boost::python::list l; scitbx::af::shared > s0_at_scan_points = obj.get_s0_at_scan_points(); @@ -222,7 +222,8 @@ namespace dxtbx { namespace model { namespace boost_python { boost::python::extract(obj.get("polarization_fraction", 0.999)), boost::python::extract(obj.get("flux", 0)), boost::python::extract(obj.get("transmission", 1)), - boost::python::extract(obj.get("probe", Probe::xray))); + Beam::get_probe_from_name( + boost::python::extract(obj.get("probe", "x-ray")))); if (obj.has_key("s0_at_scan_points")) { boost::python::list s0_at_scan_points = boost::python::extract(obj["s0_at_scan_points"]); @@ -314,7 +315,7 @@ namespace dxtbx { namespace model { namespace boost_python { result["polarization_fraction"] = obj.get_polarization_fraction(); result["flux"] = obj.get_flux(); result["transmission"] = obj.get_transmission(); - result["probe"] = obj.get_probe(); + result["probe"] = obj.get_probe_name(); return result; } @@ -329,7 +330,8 @@ namespace dxtbx { namespace model { namespace boost_python { boost::python::extract(obj.get("polarization_fraction", 0.999)), boost::python::extract(obj.get("flux", 0)), boost::python::extract(obj.get("transmission", 1)), - boost::python::extract(obj.get("probe", Probe::xray))); + Beam::get_probe_from_name( + boost::python::extract(obj.get("probe", "x-ray")))); return b; } @@ -424,6 +426,8 @@ namespace dxtbx { namespace model { namespace boost_python { .def("to_dict", &to_dict) .def("from_dict", &from_dict, return_value_policy()) .staticmethod("from_dict") + .def("get_probe_from_name", &Beam::get_probe_from_name) + .staticmethod("get_probe_from_name") .def_pickle(BeamPickleSuite()); class_, bases >( diff --git a/tests/model/test_beam.py b/tests/model/test_beam.py index 48a6eb5a1..40659f4d4 100644 --- a/tests/model/test_beam.py +++ b/tests/model/test_beam.py @@ -102,6 +102,18 @@ def test_from_phil(): assert b3.get_polarization_fraction() == 0.5 assert b3.get_polarization_normal() == (1.0, 0.0, 0.0) + params3 = beam_phil_scope.fetch( + parse( + """ + beam { + probe = electron + } + """ + ) + ).extract() + b4 = BeamFactory.from_phil(params3, reference) + assert b4.get_probe() == Probe.electron + def test_scan_varying(): direction = matrix.col((0.013142, 0.002200, 1.450476)) From 4312daf256975efa3f7e359b7d11e00f791afdf1 Mon Sep 17 00:00:00 2001 From: davidmcdonagh Date: Thu, 3 Aug 2023 14:48:33 +0100 Subject: [PATCH 18/20] Added more typehints for beam.py. Added empty PolychromaticBeam constructor at the Python level. Fixed typo in Beam.from_dict. --- src/dxtbx/dxtbx_model_ext.pyi | 4 ++++ src/dxtbx/model/beam.py | 12 +++++------- src/dxtbx/model/boost_python/beam.cc | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/dxtbx/dxtbx_model_ext.pyi b/src/dxtbx/dxtbx_model_ext.pyi index 4eb5e1530..8a4a85934 100644 --- a/src/dxtbx/dxtbx_model_ext.pyi +++ b/src/dxtbx/dxtbx_model_ext.pyi @@ -22,6 +22,8 @@ from scitbx.array_family import shared as flex_shared # Attempt to use the stub typing for flex-inheritance from scitbx.array_family.flex import FlexPlain +from dxtbx_model_ext import Probe # type: ignore + # TypeVar for the set of Experiment models that can be joint-accepted # - profile, imageset and scalingmodel are handled as 'object' TExperimentModel = TypeVar( @@ -113,6 +115,8 @@ class Beam(BeamBase): @staticmethod def from_dict(data: Dict) -> Beam: ... def to_dict(self) -> Dict: ... + @staticmethod + def get_probe_from_name(name: str) -> Probe: ... class PolychromaticBeam(Beam): @overload diff --git a/src/dxtbx/model/beam.py b/src/dxtbx/model/beam.py index 4cd19be32..a7360e9e5 100644 --- a/src/dxtbx/model/beam.py +++ b/src/dxtbx/model/beam.py @@ -79,7 +79,7 @@ class BeamFactory: @staticmethod def from_phil( params: libtbx.phil.scope_extract, - reference: Beam | PolychromaticBeam = None, + reference: Beam | PolychromaticBeam | None = None, ) -> Beam | PolychromaticBeam: """ Convert the phil parameters into a beam model @@ -136,10 +136,8 @@ def from_dict(dict: dict, template: dict = None) -> Beam | PolychromaticBeam: joint.update(dict) # Create the model from the joint dictionary - if "probe" in joint: - joint["probe"] = joint["probe"] - else: - joint["probe"] = Beam.get_probe_name(Probe.xray) + if "probe" not in joint: + joint["probe"] = "x-ray" if joint.get("__id__") == "polychromatic": return PolychromaticBeam.from_dict(joint) @@ -187,7 +185,7 @@ def make_polychromatic_beam( polarization_fraction: float = 0.5, flux: float = 0.0, transmission: float = 1.0, - probe=Probe.xray, + probe: Probe = Probe.xray, deg: bool = True, ) -> PolychromaticBeam: return PolychromaticBeam( @@ -214,7 +212,7 @@ def make_polarized_beam( sigma_divergence: float = None, flux: float = None, transmission: float = None, - probe=Probe.xray, + probe: Probe = Probe.xray, ) -> Beam: assert polarization assert 0.0 <= polarization_fraction <= 1.0 diff --git a/src/dxtbx/model/boost_python/beam.cc b/src/dxtbx/model/boost_python/beam.cc index e5024d9d5..86cdab927 100644 --- a/src/dxtbx/model/boost_python/beam.cc +++ b/src/dxtbx/model/boost_python/beam.cc @@ -432,6 +432,7 @@ namespace dxtbx { namespace model { namespace boost_python { class_, bases >( "PolychromaticBeam") + .def(init()) .def("__init__", make_constructor( &make_PolychromaticBeam, default_call_policies(), (arg("direction")))) From f467e484365532069133634246c8f78862730ea0 Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 4 Aug 2023 14:27:02 +0100 Subject: [PATCH 19/20] Update src/dxtbx/model/beam.h Co-authored-by: Nicholas Devenish --- src/dxtbx/model/beam.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index fe2fda864..db4a93ef2 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -319,7 +319,7 @@ namespace dxtbx { namespace model { case neutron: return std::string("neutron"); default: - return std::string("unknown"); + DXTBX_ERROR("Unknown probe type"); } } From 827e494a516800a8ea4b6e8badbdfd9ae0af869c Mon Sep 17 00:00:00 2001 From: David Waterman Date: Fri, 4 Aug 2023 14:27:13 +0100 Subject: [PATCH 20/20] Update src/dxtbx/model/beam.h Co-authored-by: Nicholas Devenish --- src/dxtbx/model/beam.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dxtbx/model/beam.h b/src/dxtbx/model/beam.h index db4a93ef2..6df5325d1 100644 --- a/src/dxtbx/model/beam.h +++ b/src/dxtbx/model/beam.h @@ -336,7 +336,6 @@ namespace dxtbx { namespace model { } DXTBX_ERROR("Unknown probe " + probe); - return Probe::xray; } void set_probe(Probe probe) {