diff --git a/news/tof-profile.rst b/news/tof-profile.rst new file mode 100644 index 0000000..ad9d2c6 --- /dev/null +++ b/news/tof-profile.rst @@ -0,0 +1,23 @@ +**Added:** + +* Expose the time-of-flight reflection profile ReflectionProfileDoubleExponentialPseudoVoigt. + +**Changed:** + +* PowderPatternDiffraction.SetProfile gives a ReflectionProfileDoubleExponentialPseudoVoigt the unit cell of the component's crystal. + +**Deprecated:** + +* + +**Removed:** + +* + +**Fixed:** + +* + +**Security:** + +* diff --git a/src/extensions/powderpatterndiffraction_ext.cpp b/src/extensions/powderpatterndiffraction_ext.cpp index d504e99..bcdc09a 100644 --- a/src/extensions/powderpatterndiffraction_ext.cpp +++ b/src/extensions/powderpatterndiffraction_ext.cpp @@ -41,7 +41,14 @@ namespace void SetProfileCopy(PowderPatternDiffraction &pdiff, const ReflectionProfile &profile) { - pdiff.SetProfile(profile.CreateCopy()); + ReflectionProfile *copy = profile.CreateCopy(); + // The TOF profile needs a unit cell to compute d_hkl, as in + // PowderPatternDiffraction::SetCrystal and XMLInput. + ReflectionProfileDoubleExponentialPseudoVoigt *tofprofile = + dynamic_cast(copy); + if (tofprofile != 0 && pdiff.HasCrystal()) + tofprofile->SetUnitCell(pdiff.GetCrystal()); + pdiff.SetProfile(copy); } // PowderPatternDiffraction has no public accessor for its texture diff --git a/src/extensions/reflectionprofile_ext.cpp b/src/extensions/reflectionprofile_ext.cpp index 64abcee..acbfb94 100644 --- a/src/extensions/reflectionprofile_ext.cpp +++ b/src/extensions/reflectionprofile_ext.cpp @@ -159,6 +159,31 @@ void wrap_reflectionprofile() bp::arg("scherrerLGmix") = 1), "Set the TCH pseudo-Voigt U, V, W, X, Y, Z, P and LGmix parameters."); + class_ >( + "ReflectionProfileDoubleExponentialPseudoVoigt", init<>()) + .def(init(bp::arg("cell")) + [with_custodian_and_ward<1, 2>()]) + .def(init( + bp::arg("old"))[with_custodian_and_ward<1, 2>()]) + .def("CreateCopy", + &ReflectionProfileDoubleExponentialPseudoVoigt::CreateCopy, + return_value_policy >(), + "Return an independent copy of this profile.") + .def("SetProfilePar", + &ReflectionProfileDoubleExponentialPseudoVoigt::SetProfilePar, + (bp::arg("instrumentAlpha0"), bp::arg("instrumentAlpha1"), + bp::arg("instrumentBeta0"), bp::arg("instrumentBeta1"), + bp::arg("gaussianSigma0"), bp::arg("gaussianSigma1"), + bp::arg("gaussianSigma2"), bp::arg("lorentzianGamma0"), + bp::arg("lorentzianGamma1"), bp::arg("lorentzianGamma2")), + "Set the double-exponential pseudo-Voigt TOF profile parameters.") + .def("SetUnitCell", + &ReflectionProfileDoubleExponentialPseudoVoigt::SetUnitCell, + bp::arg("cell"), with_custodian_and_ward<1, 2>(), + "Set the unit cell used to compute d_hkl for reflections."); + class_ >( "ReflectionProfilePseudoVoigtAnisotropic", init<>()) diff --git a/src/pyobjcryst/reflectionprofile.py b/src/pyobjcryst/reflectionprofile.py index 2bb16f3..a9f69fe 100644 --- a/src/pyobjcryst/reflectionprofile.py +++ b/src/pyobjcryst/reflectionprofile.py @@ -36,6 +36,11 @@ for pdiff in powder_pattern.get_crystalline_components(): pdiff.SetProfile(profile) +For time-of-flight neutron data, use the double-exponential pseudo-Voigt +profile ``ReflectionProfileDoubleExponentialPseudoVoigt``. It needs the +unit cell to compute ``d_hkl``, which ``PowderPatternDiffraction.SetProfile`` +sets from the component's crystal. + Example ------- @@ -69,11 +74,13 @@ "ReflectionProfilePseudoVoigt", "ReflectionProfilePseudoVoigtTCH", "ReflectionProfilePseudoVoigtAnisotropic", + "ReflectionProfileDoubleExponentialPseudoVoigt", "ReflectionProfileType", ] from pyobjcryst._pyobjcryst import ( ReflectionProfile, + ReflectionProfileDoubleExponentialPseudoVoigt, ReflectionProfilePseudoVoigt, ReflectionProfilePseudoVoigtAnisotropic, ReflectionProfilePseudoVoigtTCH, diff --git a/tests/test_powderpattern.py b/tests/test_powderpattern.py index 02ba692..697de67 100644 --- a/tests/test_powderpattern.py +++ b/tests/test_powderpattern.py @@ -483,7 +483,7 @@ def test_add_phase(loadcifdata, phases, expected_par_names): texture.GetPar(i).GetName() for i in range(texture.GetNbPar()) ] assert actual_type == expected_type - assert actual_phases == pytest.approx(expected_phases) + assert actual_phases == [pytest.approx(e) for e in expected_phases] assert actual_par_names == expected_par_names diff --git a/tests/test_reflectionprofile.py b/tests/test_reflectionprofile.py index e0a8678..7db3481 100644 --- a/tests/test_reflectionprofile.py +++ b/tests/test_reflectionprofile.py @@ -1,14 +1,18 @@ """Unit tests for pyobjcryst.reflectionprofile bindings.""" +import gc import unittest +import weakref import numpy as np import pytest from pyobjcryst.powderpattern import PowderPattern +from pyobjcryst.radiation import RadiationType, WavelengthType from pyobjcryst.refinableobj import RefinableObj from pyobjcryst.reflectionprofile import ( ReflectionProfile, + ReflectionProfileDoubleExponentialPseudoVoigt, ReflectionProfilePseudoVoigt, ReflectionProfilePseudoVoigtAnisotropic, ReflectionProfilePseudoVoigtTCH, @@ -293,5 +297,140 @@ def test_xml_output(self): self.assertTrue(xml_from_stream.startswith("