From 580ab5e858b540be629fdb0d4288110ad91670b8 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Thu, 6 Nov 2025 16:14:24 +0100 Subject: [PATCH 01/16] fix: added virtual bindings + small bugfix --- src/extensions/reflectionprofile_ext.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index d6c7eb6..7780e03 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -54,7 +54,7 @@ class ReflectionProfileWrap : REAL GetFullProfileWidth( const REAL relativeIntensity, const REAL xcenter, - const REAL h, const REAL k, const REAL l) + const REAL h, const REAL k, const REAL l) const { bp::override f = this->get_override("GetFullProfileWidth"); return f(relativeIntensity, xcenter, h, k, l); @@ -68,7 +68,7 @@ class ReflectionProfileWrap : void XMLInput(istream& is, const XMLCrystTag& tag) { - bp::override f = this->get_override("GetProfile"); + bp::override f = this->get_override("XMLInput"); f(is, tag); } }; @@ -80,9 +80,27 @@ void wrap_reflectionprofile() { class_, boost::noncopyable>( "ReflectionProfile") - // TODO add pure_virtual bindings to the remaining public methods .def("CreateCopy", pure_virtual(&ReflectionProfile::CreateCopy), return_value_policy()) + .def( + "GetProfile", + pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL&, REAL, REAL, REAL) const) + &ReflectionProfile::GetProfile), + (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), + bp::arg("k"), bp::arg("l"))) + .def("GetFullProfileWidth", + pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL) const) + &ReflectionProfile::GetFullProfileWidth), + (bp::arg("relativeIntensity"), bp::arg("xcenter"), + bp::arg("h"), bp::arg("k"), bp::arg("l"))) + .def("XMLOutput", + pure_virtual((void (ReflectionProfile::*)(ostream&, int) const) + &ReflectionProfile::XMLOutput), + (bp::arg("os"), bp::arg("indent"))) + .def("XMLInput", + pure_virtual((void (ReflectionProfile::*)(istream&, const XMLCrystTag&)) + &ReflectionProfile::XMLInput), + (bp::arg("is"), bp::arg("tag"))) ; } From dc9f8ba394f8c1561e117b6dad99a3f6617291b1 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Thu, 6 Nov 2025 16:14:55 +0100 Subject: [PATCH 02/16] fix: missing definition of ScatteringData --- src/extensions/powderpatterndiffraction_ext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/extensions/powderpatterndiffraction_ext.cpp b/src/extensions/powderpatterndiffraction_ext.cpp index dbb39ab..dce8d56 100644 --- a/src/extensions/powderpatterndiffraction_ext.cpp +++ b/src/extensions/powderpatterndiffraction_ext.cpp @@ -25,6 +25,7 @@ #include #include +#include namespace bp = boost::python; using namespace boost::python; From 7253d990bdd73cc2c8a8452c99fb95bcd6b9872d Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Thu, 6 Nov 2025 16:40:05 +0100 Subject: [PATCH 03/16] fix: formatting --- .../powderpatterndiffraction_ext.cpp | 118 +++++++++--------- src/extensions/reflectionprofile_ext.cpp | 89 ++++++------- 2 files changed, 98 insertions(+), 109 deletions(-) diff --git a/src/extensions/powderpatterndiffraction_ext.cpp b/src/extensions/powderpatterndiffraction_ext.cpp index dce8d56..6acb5c9 100644 --- a/src/extensions/powderpatterndiffraction_ext.cpp +++ b/src/extensions/powderpatterndiffraction_ext.cpp @@ -1,21 +1,21 @@ /***************************************************************************** -* -* pyobjcryst -* -* File coded by: Vincent Favre-Nicolin -* -* See AUTHORS.txt for a list of people who contributed. -* See LICENSE.txt for license information. -* -****************************************************************************** -* -* boost::python bindings to ObjCryst::PowderPatternDiffraction. -* -* Changes from ObjCryst::PowderPatternDiffraction -* -* Other Changes -* -*****************************************************************************/ + * + * pyobjcryst + * + * File coded by: Vincent Favre-Nicolin + * + * See AUTHORS.txt for a list of people who contributed. + * See LICENSE.txt for license information. + * + ****************************************************************************** + * + * boost::python bindings to ObjCryst::PowderPatternDiffraction. + * + * Changes from ObjCryst::PowderPatternDiffraction + * + * Other Changes + * + *****************************************************************************/ #include #include @@ -25,56 +25,52 @@ #include #include -#include +#include namespace bp = boost::python; using namespace boost::python; using namespace ObjCryst; - void wrap_powderpatterndiffraction() { - enum_("ReflectionProfileType") - .value("PROFILE_GAUSSIAN", PROFILE_GAUSSIAN) - .value("PROFILE_LORENTZIAN", PROFILE_LORENTZIAN) - .value("PROFILE_PSEUDO_VOIGT", PROFILE_PSEUDO_VOIGT) - .value("PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT", - PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT) - .value("PROFILE_PEARSON_VII", PROFILE_PEARSON_VII) - ; + enum_("ReflectionProfileType") + .value("PROFILE_GAUSSIAN", PROFILE_GAUSSIAN) + .value("PROFILE_LORENTZIAN", PROFILE_LORENTZIAN) + .value("PROFILE_PSEUDO_VOIGT", PROFILE_PSEUDO_VOIGT) + .value("PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT", + PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT) + .value("PROFILE_PEARSON_VII", PROFILE_PEARSON_VII); - class_ >( - "PowderPatternDiffraction", no_init) - .def("GetPowderPatternCalc", - &PowderPatternDiffraction::GetPowderPatternCalc, - return_value_policy()) - .def("SetReflectionProfilePar", - &PowderPatternDiffraction::SetReflectionProfilePar, - (bp::arg("type")=PROFILE_PSEUDO_VOIGT, - bp::arg("fwhmCagliotiW")=1e-6, - bp::arg("fwhmCagliotiU")=0, - bp::arg("fwhmCagliotiV")=0, - bp::arg("eta0")=0.5, bp::arg("eta1")=0)) - .def("GetProfile", - (ReflectionProfile& (PowderPatternDiffraction::*)()) - &PowderPatternDiffraction::GetProfile, - return_internal_reference<>()) - .def("SetExtractionMode", - &PowderPatternDiffraction::SetExtractionMode, - (bp::arg("extract")=true, bp::arg("init")=false)) - .def("GetExtractionMode", - &PowderPatternDiffraction::GetExtractionMode) - .def("ExtractLeBail", - &PowderPatternDiffraction::ExtractLeBail, - (bp::arg("nbcycle")=1)) - .def("SetCrystal", - &PowderPatternDiffraction::SetCrystal, - bp::arg("crystal"), - with_custodian_and_ward<1, 2>()) - .def("GetNbReflBelowMaxSinThetaOvLambda", - &PowderPatternDiffraction::GetNbReflBelowMaxSinThetaOvLambda) - .def("GetFhklObsSq", &PowderPatternDiffraction::GetFhklObsSq, - return_value_policy()) - ; + class_>( + "PowderPatternDiffraction", no_init) + .def("GetPowderPatternCalc", + &PowderPatternDiffraction::GetPowderPatternCalc, + return_value_policy()) + .def("SetReflectionProfilePar", + &PowderPatternDiffraction::SetReflectionProfilePar, + (bp::arg("type") = PROFILE_PSEUDO_VOIGT, + bp::arg("fwhmCagliotiW") = 1e-6, + bp::arg("fwhmCagliotiU") = 0, + bp::arg("fwhmCagliotiV") = 0, + bp::arg("eta0") = 0.5, bp::arg("eta1") = 0)) + .def("GetProfile", + (ReflectionProfile & (PowderPatternDiffraction::*)()) & PowderPatternDiffraction::GetProfile, + return_internal_reference<>()) + .def("SetExtractionMode", + &PowderPatternDiffraction::SetExtractionMode, + (bp::arg("extract") = true, bp::arg("init") = false)) + .def("GetExtractionMode", + &PowderPatternDiffraction::GetExtractionMode) + .def("ExtractLeBail", + &PowderPatternDiffraction::ExtractLeBail, + (bp::arg("nbcycle") = 1)) + .def("SetCrystal", + &PowderPatternDiffraction::SetCrystal, + bp::arg("crystal"), + with_custodian_and_ward<1, 2>()) + .def("GetNbReflBelowMaxSinThetaOvLambda", + &PowderPatternDiffraction::GetNbReflBelowMaxSinThetaOvLambda) + .def("GetFhklObsSq", &PowderPatternDiffraction::GetFhklObsSq, + return_value_policy()); } diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index 7780e03..a54b08e 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -1,21 +1,21 @@ /***************************************************************************** -* -* pyobjcryst -* -* File coded by: Vincent Favre-Nicolin -* -* See AUTHORS.txt for a list of people who contributed. -* See LICENSE.txt for license information. -* -****************************************************************************** -* -* boost::python bindings to ObjCryst::ReflectionProfile. -* -* Changes from ObjCryst::ReflectionProfile -* -* Other Changes -* -*****************************************************************************/ + * + * pyobjcryst + * + * File coded by: Vincent Favre-Nicolin + * + * See AUTHORS.txt for a list of people who contributed. + * See LICENSE.txt for license information. + * + ****************************************************************************** + * + * boost::python bindings to ObjCryst::ReflectionProfile. + * + * Changes from ObjCryst::ReflectionProfile + * + * Other Changes + * + *****************************************************************************/ #include #include @@ -30,77 +30,70 @@ namespace bp = boost::python; using namespace boost::python; using namespace ObjCryst; -namespace { - -class ReflectionProfileWrap : - public ReflectionProfile, public wrapper +namespace { - public: + class ReflectionProfileWrap : public ReflectionProfile, public wrapper + { + public: // Pure virtual functions - ReflectionProfile* CreateCopy() const + ReflectionProfile *CreateCopy() const { return this->get_override("CreateCopy")(); } CrystVector_REAL GetProfile( - const CrystVector_REAL& x, const REAL xcenter, - const REAL h, const REAL k, const REAL l) const + const CrystVector_REAL &x, const REAL xcenter, + const REAL h, const REAL k, const REAL l) const { bp::override f = this->get_override("GetProfile"); return f(x, xcenter, h, k, l); } REAL GetFullProfileWidth( - const REAL relativeIntensity, const REAL xcenter, - const REAL h, const REAL k, const REAL l) const + const REAL relativeIntensity, const REAL xcenter, + const REAL h, const REAL k, const REAL l) const { bp::override f = this->get_override("GetFullProfileWidth"); return f(relativeIntensity, xcenter, h, k, l); } - void XMLOutput(ostream& os, int indent) const + void XMLOutput(ostream &os, int indent) const { bp::override f = this->get_override("XMLOutput"); f(os, indent); } - void XMLInput(istream& is, const XMLCrystTag& tag) + void XMLInput(istream &is, const XMLCrystTag &tag) { bp::override f = this->get_override("XMLInput"); f(is, tag); } -}; - -} // namespace + }; +} // namespace void wrap_reflectionprofile() { class_, boost::noncopyable>( - "ReflectionProfile") + "ReflectionProfile") .def("CreateCopy", - pure_virtual(&ReflectionProfile::CreateCopy), - return_value_policy()) + pure_virtual(&ReflectionProfile::CreateCopy), + return_value_policy()) .def( "GetProfile", - pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL&, REAL, REAL, REAL) const) - &ReflectionProfile::GetProfile), + pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), bp::arg("l"))) .def("GetFullProfileWidth", - pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL) const) - &ReflectionProfile::GetFullProfileWidth), - (bp::arg("relativeIntensity"), bp::arg("xcenter"), - bp::arg("h"), bp::arg("k"), bp::arg("l"))) + pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL) const) & ReflectionProfile::GetFullProfileWidth), + (bp::arg("relativeIntensity"), bp::arg("xcenter"), + bp::arg("h"), bp::arg("k"), bp::arg("l"))) .def("XMLOutput", - pure_virtual((void (ReflectionProfile::*)(ostream&, int) const) - &ReflectionProfile::XMLOutput), - (bp::arg("os"), bp::arg("indent"))) + pure_virtual((void (ReflectionProfile::*)(ostream &, int) const) & ReflectionProfile::XMLOutput), + (bp::arg("os"), bp::arg("indent"))) .def("XMLInput", - pure_virtual((void (ReflectionProfile::*)(istream&, const XMLCrystTag&)) - &ReflectionProfile::XMLInput), - (bp::arg("is"), bp::arg("tag"))) - ; + pure_virtual((void (ReflectionProfile::*)(istream &, const XMLCrystTag &))&ReflectionProfile::XMLInput), + (bp::arg("is"), bp::arg("tag"))); } From 0f2194ab42b29a8fbbdbeeb58984449d31da3fe1 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Thu, 6 Nov 2025 17:48:53 +0100 Subject: [PATCH 04/16] feat: allow build outside of conda env --- setup.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 243ed54..2ed4bf8 100644 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ import glob import os import sys +import sysconfig from ctypes.util import find_library from pathlib import Path @@ -21,7 +22,7 @@ def get_boost_libraries(): # the names we'll search for - major, minor = sys.version_info[:2] + major, minor = sys.version_info.major, sys.version_info.minor candidates = [ f"boost_python{major}{minor}", f"boost_python{major}", @@ -50,19 +51,19 @@ def get_boost_libraries(): def get_env_config(): conda_prefix = os.environ.get("CONDA_PREFIX") - if not conda_prefix: - raise EnvironmentError( - "CONDA_PREFIX environment variable is not set. " - "Please activate your conda environment before running setup.py." - ) - if os.name == "nt": - inc = Path(conda_prefix) / "Library" / "include" - lib = Path(conda_prefix) / "Library" / "lib" - else: - inc = Path(conda_prefix) / "include" - lib = Path(conda_prefix) / "lib" - - return {"include_dirs": [str(inc)], "library_dirs": [str(lib)]} + if conda_prefix: + if os.name == "nt": + inc = Path(conda_prefix) / "Library" / "include" + lib = Path(conda_prefix) / "Library" / "lib" + else: + inc = Path(conda_prefix) / "include" + lib = Path(conda_prefix) / "lib" + return {"include_dirs": [str(inc)], "library_dirs": [str(lib)]} + + # no conda env: fallback to system/venv Python include/lib dirs + py_inc = sysconfig.get_paths().get("include") + libdir = sysconfig.get_config_var("LIBDIR") or "/usr/lib" + return {"include_dirs": [p for p in [py_inc] if p], "library_dirs": [libdir]} def create_extensions(): From 7d3a2250dd52c6c261121470c7efe5077347fbcf Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Fri, 7 Nov 2025 14:47:27 +0100 Subject: [PATCH 05/16] fix: wrong type and number of args in wrapper --- src/extensions/reflectionprofile_ext.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index a54b08e..b27897c 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -53,7 +53,7 @@ namespace REAL GetFullProfileWidth( const REAL relativeIntensity, const REAL xcenter, - const REAL h, const REAL k, const REAL l) const + const REAL h, const REAL k, const REAL l) { bp::override f = this->get_override("GetFullProfileWidth"); return f(relativeIntensity, xcenter, h, k, l); @@ -83,11 +83,11 @@ void wrap_reflectionprofile() return_value_policy()) .def( "GetProfile", - pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), + pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), bp::arg("l"))) .def("GetFullProfileWidth", - pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL) const) & ReflectionProfile::GetFullProfileWidth), + pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL, const REAL) const) & ReflectionProfile::GetFullProfileWidth), (bp::arg("relativeIntensity"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), bp::arg("l"))) .def("XMLOutput", @@ -96,4 +96,4 @@ void wrap_reflectionprofile() .def("XMLInput", pure_virtual((void (ReflectionProfile::*)(istream &, const XMLCrystTag &))&ReflectionProfile::XMLInput), (bp::arg("is"), bp::arg("tag"))); -} +} \ No newline at end of file From a468e229eed4a1d0b31fb815a4d24f30f8e33a5b Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Fri, 7 Nov 2025 15:00:53 +0100 Subject: [PATCH 06/16] Revert "fix: formatting" for clarity in PR. This reverts commit 7253d990bdd73cc2c8a8452c99fb95bcd6b9872d. --- .../powderpatterndiffraction_ext.cpp | 118 +++++++++--------- src/extensions/reflectionprofile_ext.cpp | 71 ++++++----- 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/src/extensions/powderpatterndiffraction_ext.cpp b/src/extensions/powderpatterndiffraction_ext.cpp index 6acb5c9..dce8d56 100644 --- a/src/extensions/powderpatterndiffraction_ext.cpp +++ b/src/extensions/powderpatterndiffraction_ext.cpp @@ -1,21 +1,21 @@ /***************************************************************************** - * - * pyobjcryst - * - * File coded by: Vincent Favre-Nicolin - * - * See AUTHORS.txt for a list of people who contributed. - * See LICENSE.txt for license information. - * - ****************************************************************************** - * - * boost::python bindings to ObjCryst::PowderPatternDiffraction. - * - * Changes from ObjCryst::PowderPatternDiffraction - * - * Other Changes - * - *****************************************************************************/ +* +* pyobjcryst +* +* File coded by: Vincent Favre-Nicolin +* +* See AUTHORS.txt for a list of people who contributed. +* See LICENSE.txt for license information. +* +****************************************************************************** +* +* boost::python bindings to ObjCryst::PowderPatternDiffraction. +* +* Changes from ObjCryst::PowderPatternDiffraction +* +* Other Changes +* +*****************************************************************************/ #include #include @@ -25,52 +25,56 @@ #include #include -#include +#include namespace bp = boost::python; using namespace boost::python; using namespace ObjCryst; + void wrap_powderpatterndiffraction() { - enum_("ReflectionProfileType") - .value("PROFILE_GAUSSIAN", PROFILE_GAUSSIAN) - .value("PROFILE_LORENTZIAN", PROFILE_LORENTZIAN) - .value("PROFILE_PSEUDO_VOIGT", PROFILE_PSEUDO_VOIGT) - .value("PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT", - PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT) - .value("PROFILE_PEARSON_VII", PROFILE_PEARSON_VII); + enum_("ReflectionProfileType") + .value("PROFILE_GAUSSIAN", PROFILE_GAUSSIAN) + .value("PROFILE_LORENTZIAN", PROFILE_LORENTZIAN) + .value("PROFILE_PSEUDO_VOIGT", PROFILE_PSEUDO_VOIGT) + .value("PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT", + PROFILE_PSEUDO_VOIGT_FINGER_COX_JEPHCOAT) + .value("PROFILE_PEARSON_VII", PROFILE_PEARSON_VII) + ; - class_>( - "PowderPatternDiffraction", no_init) - .def("GetPowderPatternCalc", - &PowderPatternDiffraction::GetPowderPatternCalc, - return_value_policy()) - .def("SetReflectionProfilePar", - &PowderPatternDiffraction::SetReflectionProfilePar, - (bp::arg("type") = PROFILE_PSEUDO_VOIGT, - bp::arg("fwhmCagliotiW") = 1e-6, - bp::arg("fwhmCagliotiU") = 0, - bp::arg("fwhmCagliotiV") = 0, - bp::arg("eta0") = 0.5, bp::arg("eta1") = 0)) - .def("GetProfile", - (ReflectionProfile & (PowderPatternDiffraction::*)()) & PowderPatternDiffraction::GetProfile, - return_internal_reference<>()) - .def("SetExtractionMode", - &PowderPatternDiffraction::SetExtractionMode, - (bp::arg("extract") = true, bp::arg("init") = false)) - .def("GetExtractionMode", - &PowderPatternDiffraction::GetExtractionMode) - .def("ExtractLeBail", - &PowderPatternDiffraction::ExtractLeBail, - (bp::arg("nbcycle") = 1)) - .def("SetCrystal", - &PowderPatternDiffraction::SetCrystal, - bp::arg("crystal"), - with_custodian_and_ward<1, 2>()) - .def("GetNbReflBelowMaxSinThetaOvLambda", - &PowderPatternDiffraction::GetNbReflBelowMaxSinThetaOvLambda) - .def("GetFhklObsSq", &PowderPatternDiffraction::GetFhklObsSq, - return_value_policy()); + class_ >( + "PowderPatternDiffraction", no_init) + .def("GetPowderPatternCalc", + &PowderPatternDiffraction::GetPowderPatternCalc, + return_value_policy()) + .def("SetReflectionProfilePar", + &PowderPatternDiffraction::SetReflectionProfilePar, + (bp::arg("type")=PROFILE_PSEUDO_VOIGT, + bp::arg("fwhmCagliotiW")=1e-6, + bp::arg("fwhmCagliotiU")=0, + bp::arg("fwhmCagliotiV")=0, + bp::arg("eta0")=0.5, bp::arg("eta1")=0)) + .def("GetProfile", + (ReflectionProfile& (PowderPatternDiffraction::*)()) + &PowderPatternDiffraction::GetProfile, + return_internal_reference<>()) + .def("SetExtractionMode", + &PowderPatternDiffraction::SetExtractionMode, + (bp::arg("extract")=true, bp::arg("init")=false)) + .def("GetExtractionMode", + &PowderPatternDiffraction::GetExtractionMode) + .def("ExtractLeBail", + &PowderPatternDiffraction::ExtractLeBail, + (bp::arg("nbcycle")=1)) + .def("SetCrystal", + &PowderPatternDiffraction::SetCrystal, + bp::arg("crystal"), + with_custodian_and_ward<1, 2>()) + .def("GetNbReflBelowMaxSinThetaOvLambda", + &PowderPatternDiffraction::GetNbReflBelowMaxSinThetaOvLambda) + .def("GetFhklObsSq", &PowderPatternDiffraction::GetFhklObsSq, + return_value_policy()) + ; } diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index b27897c..b92a903 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -1,21 +1,21 @@ /***************************************************************************** - * - * pyobjcryst - * - * File coded by: Vincent Favre-Nicolin - * - * See AUTHORS.txt for a list of people who contributed. - * See LICENSE.txt for license information. - * - ****************************************************************************** - * - * boost::python bindings to ObjCryst::ReflectionProfile. - * - * Changes from ObjCryst::ReflectionProfile - * - * Other Changes - * - *****************************************************************************/ +* +* pyobjcryst +* +* File coded by: Vincent Favre-Nicolin +* +* See AUTHORS.txt for a list of people who contributed. +* See LICENSE.txt for license information. +* +****************************************************************************** +* +* boost::python bindings to ObjCryst::ReflectionProfile. +* +* Changes from ObjCryst::ReflectionProfile +* +* Other Changes +* +*****************************************************************************/ #include #include @@ -30,22 +30,23 @@ namespace bp = boost::python; using namespace boost::python; using namespace ObjCryst; -namespace -{ +namespace { - class ReflectionProfileWrap : public ReflectionProfile, public wrapper - { +class ReflectionProfileWrap : + public ReflectionProfile, public wrapper +{ public: + // Pure virtual functions - ReflectionProfile *CreateCopy() const + ReflectionProfile* CreateCopy() const { return this->get_override("CreateCopy")(); } CrystVector_REAL GetProfile( - const CrystVector_REAL &x, const REAL xcenter, - const REAL h, const REAL k, const REAL l) const + const CrystVector_REAL& x, const REAL xcenter, + const REAL h, const REAL k, const REAL l) const { bp::override f = this->get_override("GetProfile"); return f(x, xcenter, h, k, l); @@ -59,28 +60,29 @@ namespace return f(relativeIntensity, xcenter, h, k, l); } - void XMLOutput(ostream &os, int indent) const + void XMLOutput(ostream& os, int indent) const { bp::override f = this->get_override("XMLOutput"); f(os, indent); } - void XMLInput(istream &is, const XMLCrystTag &tag) + void XMLInput(istream& is, const XMLCrystTag& tag) { bp::override f = this->get_override("XMLInput"); f(is, tag); } - }; +}; + +} // namespace -} // namespace void wrap_reflectionprofile() { class_, boost::noncopyable>( - "ReflectionProfile") + "ReflectionProfile") .def("CreateCopy", - pure_virtual(&ReflectionProfile::CreateCopy), - return_value_policy()) + pure_virtual(&ReflectionProfile::CreateCopy), + return_value_policy()) .def( "GetProfile", pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), @@ -91,9 +93,10 @@ void wrap_reflectionprofile() (bp::arg("relativeIntensity"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), bp::arg("l"))) .def("XMLOutput", - pure_virtual((void (ReflectionProfile::*)(ostream &, int) const) & ReflectionProfile::XMLOutput), - (bp::arg("os"), bp::arg("indent"))) + pure_virtual((void (ReflectionProfile::*)(ostream&, int) const) + &ReflectionProfile::XMLOutput), + (bp::arg("os"), bp::arg("indent"))) .def("XMLInput", pure_virtual((void (ReflectionProfile::*)(istream &, const XMLCrystTag &))&ReflectionProfile::XMLInput), (bp::arg("is"), bp::arg("tag"))); -} \ No newline at end of file +} From 53198ab846a0abbaadb4aacfdd245e4b2f3786ab Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:18:40 +0000 Subject: [PATCH 07/16] [pre-commit.ci] auto fixes from pre-commit hooks --- setup.py | 5 ++++- src/extensions/powderpatterndiffraction_ext.cpp | 2 +- src/extensions/reflectionprofile_ext.cpp | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 2ed4bf8..26c8f7d 100644 --- a/setup.py +++ b/setup.py @@ -63,7 +63,10 @@ def get_env_config(): # no conda env: fallback to system/venv Python include/lib dirs py_inc = sysconfig.get_paths().get("include") libdir = sysconfig.get_config_var("LIBDIR") or "/usr/lib" - return {"include_dirs": [p for p in [py_inc] if p], "library_dirs": [libdir]} + return { + "include_dirs": [p for p in [py_inc] if p], + "library_dirs": [libdir], + } def create_extensions(): diff --git a/src/extensions/powderpatterndiffraction_ext.cpp b/src/extensions/powderpatterndiffraction_ext.cpp index dce8d56..50ca04b 100644 --- a/src/extensions/powderpatterndiffraction_ext.cpp +++ b/src/extensions/powderpatterndiffraction_ext.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include namespace bp = boost::python; using namespace boost::python; diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index b92a903..a9504e4 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -54,7 +54,7 @@ class ReflectionProfileWrap : REAL GetFullProfileWidth( const REAL relativeIntensity, const REAL xcenter, - const REAL h, const REAL k, const REAL l) + const REAL h, const REAL k, const REAL l) { bp::override f = this->get_override("GetFullProfileWidth"); return f(relativeIntensity, xcenter, h, k, l); From 81eaccd90e863f066efdc43bb776c33d293f706d Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Wed, 12 Nov 2025 15:40:20 +0100 Subject: [PATCH 08/16] fix: formatting --- src/extensions/reflectionprofile_ext.cpp | 69 ++++++++++++------------ 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index a9504e4..0a34b9d 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -1,21 +1,21 @@ /***************************************************************************** -* -* pyobjcryst -* -* File coded by: Vincent Favre-Nicolin -* -* See AUTHORS.txt for a list of people who contributed. -* See LICENSE.txt for license information. -* -****************************************************************************** -* -* boost::python bindings to ObjCryst::ReflectionProfile. -* -* Changes from ObjCryst::ReflectionProfile -* -* Other Changes -* -*****************************************************************************/ + * + * pyobjcryst + * + * File coded by: Vincent Favre-Nicolin + * + * See AUTHORS.txt for a list of people who contributed. + * See LICENSE.txt for license information. + * + ****************************************************************************** + * + * boost::python bindings to ObjCryst::ReflectionProfile. + * + * Changes from ObjCryst::ReflectionProfile + * + * Other Changes + * + *****************************************************************************/ #include #include @@ -30,23 +30,22 @@ namespace bp = boost::python; using namespace boost::python; using namespace ObjCryst; -namespace { - -class ReflectionProfileWrap : - public ReflectionProfile, public wrapper +namespace { - public: + class ReflectionProfileWrap : public ReflectionProfile, public wrapper + { + public: // Pure virtual functions - ReflectionProfile* CreateCopy() const + ReflectionProfile *CreateCopy() const { return this->get_override("CreateCopy")(); } CrystVector_REAL GetProfile( - const CrystVector_REAL& x, const REAL xcenter, - const REAL h, const REAL k, const REAL l) const + const CrystVector_REAL &x, const REAL xcenter, + const REAL h, const REAL k, const REAL l) const { bp::override f = this->get_override("GetProfile"); return f(x, xcenter, h, k, l); @@ -60,29 +59,28 @@ class ReflectionProfileWrap : return f(relativeIntensity, xcenter, h, k, l); } - void XMLOutput(ostream& os, int indent) const + void XMLOutput(ostream &os, int indent) const { bp::override f = this->get_override("XMLOutput"); f(os, indent); } - void XMLInput(istream& is, const XMLCrystTag& tag) + void XMLInput(istream &is, const XMLCrystTag &tag) { bp::override f = this->get_override("XMLInput"); f(is, tag); } -}; - -} // namespace + }; +} // namespace void wrap_reflectionprofile() { class_, boost::noncopyable>( - "ReflectionProfile") + "ReflectionProfile") .def("CreateCopy", - pure_virtual(&ReflectionProfile::CreateCopy), - return_value_policy()) + pure_virtual(&ReflectionProfile::CreateCopy), + return_value_policy()) .def( "GetProfile", pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), @@ -93,9 +91,8 @@ void wrap_reflectionprofile() (bp::arg("relativeIntensity"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), bp::arg("l"))) .def("XMLOutput", - pure_virtual((void (ReflectionProfile::*)(ostream&, int) const) - &ReflectionProfile::XMLOutput), - (bp::arg("os"), bp::arg("indent"))) + pure_virtual((void (ReflectionProfile::*)(ostream &, int) const) & ReflectionProfile::XMLOutput), + (bp::arg("os"), bp::arg("indent"))) .def("XMLInput", pure_virtual((void (ReflectionProfile::*)(istream &, const XMLCrystTag &))&ReflectionProfile::XMLInput), (bp::arg("is"), bp::arg("tag"))); From 83e6f3f0f92f3ab1a1c1f138f5cc92358bc7b97f Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Wed, 12 Nov 2025 15:44:24 +0100 Subject: [PATCH 09/16] tests: added placeholders for ReflectionProfile unit tests --- tests/test_reflectionprofile.py | 56 +++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/test_reflectionprofile.py diff --git a/tests/test_reflectionprofile.py b/tests/test_reflectionprofile.py new file mode 100644 index 0000000..8781237 --- /dev/null +++ b/tests/test_reflectionprofile.py @@ -0,0 +1,56 @@ +""" +Unit tests for pyobjcryst.reflectionprofile bindings. + +TODO: +- ReflectionProfile.GetProfile +- ReflectionProfile.GetFullProfileWidth +- ReflectionProfile.XMLOutput / XMLInput +- ReflectionProfile.CreateCopy +""" + +import unittest +import pytest +import numpy as np + +from pyobjcryst.powderpattern import PowderPattern + + +class TestReflectionProfile(unittest.TestCase): + """Tests for ReflectionProfile methods""" + + @pytest.fixture(autouse=True) + def prepare_fixture(self, loadcifdata): + self.loadcifdata = loadcifdata + + def setUp(self): + """Set up a ReflectionProfile instance for testing.""" + x = np.linspace(0, 40, 8001) + c = self.loadcifdata("paracetamol.cif") + + self.pp = PowderPattern() + self.pp.SetWavelength(0.7) + self.pp.SetPowderPatternX(np.deg2rad(x)) + self.pp.SetPowderPatternObs(np.ones_like(x)) + + self.ppd = self.pp.AddPowderPatternDiffraction(c) + + self.profile = self.ppd.GetProfile() + + def test_get_computed_profile(self): + assert True + + def test_get_profile_width(self): + assert True + + def test_create_copy(self): + assert True + + def test_xml_input(self): + assert True + + def test_xml_output(self): + assert True + + +if __name__ == "__main__": + unittest.main() From 304c05e5fe7fe06deddf964229e9eb85a418f2b3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 12 Nov 2025 14:46:22 +0000 Subject: [PATCH 10/16] [pre-commit.ci] auto fixes from pre-commit hooks --- tests/test_reflectionprofile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_reflectionprofile.py b/tests/test_reflectionprofile.py index 8781237..10e539a 100644 --- a/tests/test_reflectionprofile.py +++ b/tests/test_reflectionprofile.py @@ -1,5 +1,4 @@ -""" -Unit tests for pyobjcryst.reflectionprofile bindings. +"""Unit tests for pyobjcryst.reflectionprofile bindings. TODO: - ReflectionProfile.GetProfile @@ -9,14 +8,15 @@ """ import unittest -import pytest + import numpy as np +import pytest from pyobjcryst.powderpattern import PowderPattern class TestReflectionProfile(unittest.TestCase): - """Tests for ReflectionProfile methods""" + """Tests for ReflectionProfile methods.""" @pytest.fixture(autouse=True) def prepare_fixture(self, loadcifdata): From f9b114aaaf2d2219c2273a2405afdbe118e76c21 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Fri, 21 Nov 2025 00:41:58 +0100 Subject: [PATCH 11/16] feat: helper to convert python sequences to CrystVector * GetProfile now accepts numpy arrays as the `x` argument --- src/extensions/reflectionprofile_ext.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index 0a34b9d..61d1134 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -22,6 +22,8 @@ #include #undef B0 +#include "helpers.hpp" // assignCrystVector helper for numpy/sequence inputs + #include #include @@ -72,6 +74,16 @@ namespace } }; + // Accept python sequences/ndarrays for x and forward to the C++ API. + CrystVector_REAL _GetProfile( + const ReflectionProfile &rp, bp::object x, const REAL xcenter, + const REAL h, const REAL k, const REAL l) + { + CrystVector_REAL cvx; + assignCrystVector(cvx, x); + return rp.GetProfile(cvx, xcenter, h, k, l); + } + } // namespace void wrap_reflectionprofile() @@ -83,9 +95,13 @@ void wrap_reflectionprofile() return_value_policy()) .def( "GetProfile", - pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), + pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), bp::arg("l"))) + .def( + "GetProfile", &_GetProfile, + (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), + bp::arg("l"))) .def("GetFullProfileWidth", pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL, const REAL) const) & ReflectionProfile::GetFullProfileWidth), (bp::arg("relativeIntensity"), bp::arg("xcenter"), From 3280325c7325ad93bf89b7d25bdca1a708e66185 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Fri, 21 Nov 2025 00:44:14 +0100 Subject: [PATCH 12/16] feat: added unit tests for ReflectionProfile methods --- tests/test_reflectionprofile.py | 70 ++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/tests/test_reflectionprofile.py b/tests/test_reflectionprofile.py index 10e539a..d70d31d 100644 --- a/tests/test_reflectionprofile.py +++ b/tests/test_reflectionprofile.py @@ -13,6 +13,7 @@ import pytest from pyobjcryst.powderpattern import PowderPattern +from pyobjcryst.refinableobj import RefinableObj class TestReflectionProfile(unittest.TestCase): @@ -24,7 +25,7 @@ def prepare_fixture(self, loadcifdata): def setUp(self): """Set up a ReflectionProfile instance for testing.""" - x = np.linspace(0, 40, 8001) + x = np.linspace(0, 40, 1000) c = self.loadcifdata("paracetamol.cif") self.pp = PowderPattern() @@ -37,19 +38,76 @@ def setUp(self): self.profile = self.ppd.GetProfile() def test_get_computed_profile(self): - assert True + """Sample a profile slice and verify broadening lowers the peak height.""" + x = self.pp.GetPowderPatternX() + hkl = (1, 0, 0) + window = x[100:200] + xcenter = float(window[len(window) // 2]) + + prof_default = self.profile.GetProfile(window, xcenter, *hkl) + self.assertEqual(len(prof_default), len(window)) + self.assertGreater(prof_default.max(), 0) + + # broaden and ensure the peak height drops while shape changes + self.profile.GetPar("W").SetValue(0.05) + prof_broader = self.profile.GetProfile(window, xcenter, *hkl) + + self.assertFalse(np.allclose(prof_default, prof_broader)) + self.assertLess(prof_broader.max(), prof_default.max()) + self.assertEqual(len(prof_default), len(prof_broader)) def test_get_profile_width(self): - assert True + """Ensure full-width increases when W increases.""" + xcenter = float(self.pp.GetPowderPatternX()[len(self.pp.GetPowderPatternX()) // 4]) + width_default = self.profile.GetFullProfileWidth(0.5, xcenter, 1, 0, 0) + self.assertGreater(width_default, 0) + + self.profile.GetPar("W").SetValue(0.05) + width_broader = self.profile.GetFullProfileWidth(0.5, xcenter, 1, 0, 0) + self.assertGreater(width_broader, width_default) def test_create_copy(self): - assert True + """Ensure copy returns an independent profile with identical initial params.""" + copy = self.profile.CreateCopy() + + self.assertIsNot(copy, self.profile) + self.assertEqual(copy.GetClassName(), self.profile.GetClassName()) + + eta0_original = self.profile.GetPar("Eta0").GetValue() + eta0_copy = copy.GetPar("Eta0").GetValue() + self.assertAlmostEqual(eta0_copy, eta0_original) + + self.profile.GetPar("Eta0").SetValue(eta0_original + 0.1) + copy.GetPar("Eta0").SetValue(eta0_copy + 0.2) + + self.assertAlmostEqual(copy.GetPar("Eta0").GetValue(), eta0_original + 0.2) + self.assertAlmostEqual(self.profile.GetPar("Eta0").GetValue(), eta0_original + 0.1) def test_xml_input(self): - assert True + """Ensure XMLInput restores parameters previously serialized with xml().""" + xml_state = self.profile.xml() + eta0_original = self.profile.GetPar("Eta0").GetValue() + + self.profile.GetPar("Eta0").SetValue(eta0_original + 0.3) + self.assertNotAlmostEqual(self.profile.GetPar("Eta0").GetValue(), eta0_original) + + RefinableObj.XMLInput(self.profile, xml_state) + self.assertAlmostEqual(self.profile.GetPar("Eta0").GetValue(), eta0_original) def test_xml_output(self): - assert True + """Ensure XMLOutput emits parameter tags and the expected root element.""" + xml_state = self.profile.xml() + + self.assertIn(" Date: Thu, 20 Nov 2025 23:44:35 +0000 Subject: [PATCH 13/16] [pre-commit.ci] auto fixes from pre-commit hooks --- tests/test_reflectionprofile.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/tests/test_reflectionprofile.py b/tests/test_reflectionprofile.py index d70d31d..9ca604c 100644 --- a/tests/test_reflectionprofile.py +++ b/tests/test_reflectionprofile.py @@ -38,7 +38,8 @@ def setUp(self): self.profile = self.ppd.GetProfile() def test_get_computed_profile(self): - """Sample a profile slice and verify broadening lowers the peak height.""" + """Sample a profile slice and verify broadening lowers the peak + height.""" x = self.pp.GetPowderPatternX() hkl = (1, 0, 0) window = x[100:200] @@ -58,7 +59,9 @@ def test_get_computed_profile(self): def test_get_profile_width(self): """Ensure full-width increases when W increases.""" - xcenter = float(self.pp.GetPowderPatternX()[len(self.pp.GetPowderPatternX()) // 4]) + xcenter = float( + self.pp.GetPowderPatternX()[len(self.pp.GetPowderPatternX()) // 4] + ) width_default = self.profile.GetFullProfileWidth(0.5, xcenter, 1, 0, 0) self.assertGreater(width_default, 0) @@ -67,7 +70,8 @@ def test_get_profile_width(self): self.assertGreater(width_broader, width_default) def test_create_copy(self): - """Ensure copy returns an independent profile with identical initial params.""" + """Ensure copy returns an independent profile with identical + initial params.""" copy = self.profile.CreateCopy() self.assertIsNot(copy, self.profile) @@ -80,22 +84,32 @@ def test_create_copy(self): self.profile.GetPar("Eta0").SetValue(eta0_original + 0.1) copy.GetPar("Eta0").SetValue(eta0_copy + 0.2) - self.assertAlmostEqual(copy.GetPar("Eta0").GetValue(), eta0_original + 0.2) - self.assertAlmostEqual(self.profile.GetPar("Eta0").GetValue(), eta0_original + 0.1) + self.assertAlmostEqual( + copy.GetPar("Eta0").GetValue(), eta0_original + 0.2 + ) + self.assertAlmostEqual( + self.profile.GetPar("Eta0").GetValue(), eta0_original + 0.1 + ) def test_xml_input(self): - """Ensure XMLInput restores parameters previously serialized with xml().""" + """Ensure XMLInput restores parameters previously serialized + with xml().""" xml_state = self.profile.xml() eta0_original = self.profile.GetPar("Eta0").GetValue() self.profile.GetPar("Eta0").SetValue(eta0_original + 0.3) - self.assertNotAlmostEqual(self.profile.GetPar("Eta0").GetValue(), eta0_original) + self.assertNotAlmostEqual( + self.profile.GetPar("Eta0").GetValue(), eta0_original + ) RefinableObj.XMLInput(self.profile, xml_state) - self.assertAlmostEqual(self.profile.GetPar("Eta0").GetValue(), eta0_original) + self.assertAlmostEqual( + self.profile.GetPar("Eta0").GetValue(), eta0_original + ) def test_xml_output(self): - """Ensure XMLOutput emits parameter tags and the expected root element.""" + """Ensure XMLOutput emits parameter tags and the expected root + element.""" xml_state = self.profile.xml() self.assertIn(" Date: Fri, 21 Nov 2025 09:53:23 +0100 Subject: [PATCH 14/16] fix: codespell flags unittest assertIn as a typo --- .codespell/ignore_words.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.codespell/ignore_words.txt b/.codespell/ignore_words.txt index 00659c1..2dd64f3 100644 --- a/.codespell/ignore_words.txt +++ b/.codespell/ignore_words.txt @@ -15,3 +15,6 @@ regist ;; src/pyobjcryst/crystal.py:548 ;; alabelstyle parameter inFront + +;; tests/test_reflectionprofile.py: unittest assertions flagged as typos +assertin From d5ea27068b39af1ccc19ea924255a71d953f5149 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Fri, 21 Nov 2025 11:20:35 +0100 Subject: [PATCH 15/16] feat: added docstrings --- src/extensions/reflectionprofile_ext.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index 61d1134..c734fbf 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -92,24 +92,33 @@ void wrap_reflectionprofile() "ReflectionProfile") .def("CreateCopy", pure_virtual(&ReflectionProfile::CreateCopy), - return_value_policy()) + (return_value_policy()), + "Return a new ReflectionProfile instance copied from this one.") + // Two overloads for GetProfile: + // - Native CrystVector signature (for C++ callers / already-converted vectors). + // - Python-friendly wrapper that accepts sequences/ndarrays and converts them. .def( "GetProfile", pure_virtual((CrystVector_REAL (ReflectionProfile::*)(const CrystVector_REAL &, REAL, REAL, REAL, REAL) const) & ReflectionProfile::GetProfile), (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), - bp::arg("k"), bp::arg("l"))) + bp::arg("k"), bp::arg("l")), + "Compute the profile values at positions `x` for reflection (h, k, l) centered at `xcenter`.") .def( "GetProfile", &_GetProfile, (bp::arg("x"), bp::arg("xcenter"), bp::arg("h"), bp::arg("k"), - bp::arg("l"))) + bp::arg("l")), + "Compute the profile values at positions `x` (sequence/ndarray accepted) for reflection (h, k, l) centered at `xcenter`.") .def("GetFullProfileWidth", pure_virtual((REAL (ReflectionProfile::*)(const REAL, const REAL, const REAL, const REAL, const REAL) const) & ReflectionProfile::GetFullProfileWidth), (bp::arg("relativeIntensity"), bp::arg("xcenter"), - bp::arg("h"), bp::arg("k"), bp::arg("l"))) + bp::arg("h"), bp::arg("k"), bp::arg("l")), + "Return the full profile width at a given relative intensity for reflection (h, k, l) around `xcenter`.") .def("XMLOutput", pure_virtual((void (ReflectionProfile::*)(ostream &, int) const) & ReflectionProfile::XMLOutput), - (bp::arg("os"), bp::arg("indent"))) + (bp::arg("os"), bp::arg("indent")), + "Write this ReflectionProfile as XML to a file-like object. `indent` controls indentation depth.") .def("XMLInput", pure_virtual((void (ReflectionProfile::*)(istream &, const XMLCrystTag &))&ReflectionProfile::XMLInput), - (bp::arg("is"), bp::arg("tag"))); + (bp::arg("is"), bp::arg("tag")), + "Load ReflectionProfile parameters from an XML stream and tag."); } From 9e30840d2757ff8534e36efe07801b95b8a8e273 Mon Sep 17 00:00:00 2001 From: Edoardo Zatterin Date: Fri, 21 Nov 2025 11:22:45 +0100 Subject: [PATCH 16/16] feat: added news describing PR changers --- news/79.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 news/79.rst diff --git a/news/79.rst b/news/79.rst new file mode 100644 index 0000000..301c33b --- /dev/null +++ b/news/79.rst @@ -0,0 +1,25 @@ +**Added:** + +* Exposed `ReflectionProfile` methods (`GetProfile`, `GetFullProfileWidth`, `XMLOutput`, `XMLInput`) via Python bindings. Added unit tests. +* The binding to `ReflectionProfile.GetProfile(x, xcenter, h, k, l)` accepts python sequences / `numpy` arrays for the `x` argument, thanks to the helper function `assignCrystVector`. + +**Changed:** + +* None. + +**Deprecated:** + +* None. + +**Removed:** + +* None. + +**Fixed:** + +* Building with `pip install .` now uses `sysconfig` to locate `ObjCryst++`` libraries outside conda environments. +* Missing definition of `ScatteringData` in `powderpatterndiffraction_ext.ccp` + +**Security:** + +* None.