Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions news/pdf3d-calculator.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
**Added:**

* Expose ``PDF3DCalculator`` through the Python bindings.

**Changed:**

* <news item>

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>
100 changes: 99 additions & 1 deletion src/diffpy/srreal/pdfcalculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
Top-level classes for PDF calculation:
DebyePDFCalculator -- simulate PDF by evaluating Debye sum in Q-space
PDFCalculator -- calculate PDF by peak summation in real space
PDF3DCalculator -- calculate 3D real-space PDF on a cubic grid
"""

from diffpy.srreal.srreal_ext import (
DebyePDFCalculator,
PDF3DCalculator,
PDFCalculator,
fftftog,
fftgtof,
Expand All @@ -31,7 +33,7 @@

# exported items
__all__ = """
DebyePDFCalculator PDFCalculator
DebyePDFCalculator PDFCalculator PDF3DCalculator
fftftog fftgtof
""".split()

Expand Down Expand Up @@ -341,4 +343,100 @@ def _init_kwargs1(self, **kwargs):

# End of class PDFCalculator


# PDF3DCalculator ------------------------------------------------------------

# shared interface of the PDF calculator classes

_defineCommonInterface(PDF3DCalculator)

# Property wrappers to double attributes of the C++ PDF3DCalculator

PDF3DCalculator.calculation_mode3d = propertyFromExtDoubleAttr(
"calculation_mode3d",
(
"3D calculation mode: 0 = full ADP-broadened PDF3D,"
" 1 = raw pair-vector histogram. [0]"
),
)
PDF3DCalculator.histogram_weight_mode3d = propertyFromExtDoubleAttr(
"histogram_weight_mode3d",
(
"Histogram weight mode when calculation_mode3d=1:"
" 0 = scattering weighted, 1 = raw pair count. [0]"
),
)
PDF3DCalculator.enable_nn_delta3d = propertyFromExtDoubleAttr(
"enable_nn_delta3d",
"Enable 3D covariance delta correction. Use 1.0 for on and 0.0 for off. [0]",
)
PDF3DCalculator.nn_delta3d = propertyFromExtDoubleAttr(
"nn_delta3d",
"Legacy shell-constant 3D delta subtracted along the pair direction. [0 A**2]",
)
PDF3DCalculator.nn_delta_positive_eta3d = propertyFromExtDoubleAttr(
"nn_delta_positive_eta3d",
"Safety factor for the positive-definite covariance bound. [0.9]",
)
PDF3DCalculator.delta1_3d = propertyFromExtDoubleAttr(
"delta1_3d",
"Coefficient for the 1/r part of distance-decay 3D covariance delta. [0 A]",
)
PDF3DCalculator.delta2_3d = propertyFromExtDoubleAttr(
"delta2_3d",
(
"Coefficient for the 1/r**2 part of distance-decay 3D covariance"
" delta. [0 A**2]"
),
)
PDF3DCalculator.delta_shell_index3d = propertyFromExtDoubleAttr(
"delta_shell_index3d",
"Shell index for the legacy shell-constant 3D delta mode. [1]",
)
PDF3DCalculator.delta_shell_tolerance3d = propertyFromExtDoubleAttr(
"delta_shell_tolerance3d",
"Distance tolerance used to group neighbor shells for legacy 3D delta. [0.05 A]",
)
PDF3DCalculator.delta_key_tolerance3d = propertyFromExtDoubleAttr(
"delta_key_tolerance3d",
"Coordinate rounding tolerance for matching legacy 3D delta shell pairs. [1e-6 A]",
)
PDF3DCalculator.use_adp_scale_sensitivity3d = propertyFromExtDoubleAttr(
"use_adp_scale_sensitivity3d",
(
"Enable ADP scale sensitivity for 3D delta."
" Use 1.0 for on and 0.0 for off. [0]"
),
)
PDF3DCalculator.adp_scale3d = propertyFromExtDoubleAttr(
"adp_scale3d",
"Scale factor applied to pair covariance in 3D delta calculations. [1]",
)
PDF3DCalculator.rho0_background_scale3d = propertyFromExtDoubleAttr(
"rho0_background_scale3d",
"Scale factor for the rho0 background subtraction in 3D PDF output. [1]",
)

# method overrides to support optional keyword arguments


def _init_kwargs2(self, **kwargs):
"""Create a new instance of PDF3DCalculator.
Keyword arguments can be used to configure the calculator properties,
for example:

p3c = PDF3DCalculator(rmax=10.0, gridstep=0.1, qmax=12)

Raise ValueError for invalid keyword argument.
"""
PDF3DCalculator.__boostpython__init(self)
setattrFromKeywordArguments(self, **kwargs)
return


PDF3DCalculator.__boostpython__init = PDF3DCalculator.__init__
PDF3DCalculator.__init__ = _init_kwargs2

# End of class PDF3DCalculator

# End of file
136 changes: 135 additions & 1 deletion src/extensions/wrap_PDFCalculators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
******************************************************************************
*
* Bindings to DebyePDFCalculator and PDFCalculator classes.
* Bindings to DebyePDFCalculator, PDFCalculator and PDF3DCalculator classes.
*
*****************************************************************************/

Expand All @@ -22,6 +22,7 @@

#include <diffpy/srreal/DebyePDFCalculator.hpp>
#include <diffpy/srreal/PDFCalculator.hpp>
#include <diffpy/srreal/PDF3DCalculator.hpp>

#include "srreal_converters.hpp"
#include "srreal_pickling.hpp"
Expand Down Expand Up @@ -138,6 +139,52 @@ object or a string type of a registered PDFBaseline class.\n\
Use PDFBaseline.getRegisteredTypes() for the set of allowed values.\n\
";

const char* doc_PDF3DCalculator = "\
Calculate 3D real-space pair distribution function on a cubic grid.\n\
";

const char* doc_PDF3DCalculator_pdf3d = "\
3D PDF data as a flattened NumPy array of non-zero bins: [x, y, z, G, ...].\n\
Reshape in Python with arr.reshape(-1, 4).\n\
";

const char* doc_PDF3DCalculator_radialhistogram3d = "\
1D radial histogram from the 3D pair-vector accumulation as [r, weight, ...].\n\
Reshape in Python with arr.reshape(-1, 2).\n\
";

const char* doc_PDF3DCalculator_gridstep = "\
Spacing of the 3D grid in Angstrom. Must be positive.\n\
";

const char* doc_PDF3DCalculator_accumblocksize = "\
Block size used by tiled accumulation loops in 3D real-space summation.\n\
";

const char* doc_PDF3DCalculator_qmin = "\
Lower bound of the Q-range for 3D calculation in 1/A.\n\
";

const char* doc_PDF3DCalculator_qmax = "\
Upper bound of the Q-range for 3D calculation in 1/A.\n\
";

const char* doc_PDF3DCalculator_usecqwindow3d = "\
If True, apply qmin/qmax 3D q-window in C++. If False, export unwindowed G(r) for external FFT post-processing.\n\
";

const char* doc_PDF3DCalculator_exportGrid3DBinary = "\
Export dense 3D grid (nz, ny, nx) directly to a binary file.\n\
path -- output file path\n\
usefloat32 -- True for float32 output, False for float64\n\
applypost -- apply q-window/rdf scale/rho0/qdamp before export\n\
";

const char* doc_PDF3DCalculator_setDeltaPairTypes3D = "\
Set atom-type filter for the 3D covariance delta correction.\n\
Use \"*\" for either argument to match all atom types.\n\
";

const char* doc_fftftog = "\
Perform sine-fast Fourier transform from F(Q) to G(r).\n\
The length of the output array is padded to the next power of 2.\n\
Expand Down Expand Up @@ -173,13 +220,26 @@ DECLARE_PYARRAY_METHOD_WRAPPER(getF, getF_asarray)
DECLARE_PYARRAY_METHOD_WRAPPER(getQgrid, getQgrid_asarray)
DECLARE_PYLIST_METHOD_WRAPPER(usedEnvelopeTypes, usedEnvelopeTypes_aslist)

DECLARE_PYARRAY_METHOD_WRAPPER(get3DPDF, get3DPDF_asarray)
DECLARE_PYARRAY_METHOD_WRAPPER(getRadialHistogram3D, getRadialHistogram3D_asarray)

// wrappers for the peakprofile property

PeakProfilePtr getpeakprofile(PDFCalculator& obj)
{
return obj.getPeakProfile();
}

static double getqmin_value(PDF3DCalculator& obj)
{
return obj.getQmin();
}

static double getqmax_value(PDF3DCalculator& obj)
{
return obj.getQmax();
}

DECLARE_BYTYPE_SETTER_WRAPPER(setPeakProfile, setpeakprofile)

// wrappers for the baseline property
Expand Down Expand Up @@ -436,6 +496,38 @@ class PDFCalculatorPickleSuite :
}
};


class PDF3DCalculatorPickleSuite :
public PairQuantityPickleSuite<PDF3DCalculator, DICT_IGNORE>
{
private:

typedef PairQuantityPickleSuite<PDF3DCalculator> Super;

public:

static tuple getstate(object obj)
{
tuple rv(
getstate_super<Super>(obj) +
getstate_common(obj)
);
return rv;
}


static void setstate(object obj, tuple state)
{
ensure_tuple_length(state, 4);
// restore the state using boost serialization
tuple st0 = extract<tuple>(state[0]);
Super::setstate(obj, st0);
// other items are non-None only when restoring Python class
stl_input_iterator<object> st(state);
setstate_common(obj, st);
}
};

} // namespace nswrap_PDFCalculators

// Wrapper definition --------------------------------------------------------
Expand Down Expand Up @@ -475,6 +567,48 @@ void wrap_PDFCalculators()
.def_pickle(PDFCalculatorPickleSuite())
;

// PDF3DCalculator
class_<PDF3DCalculator,
bases<PairQuantity, PeakWidthModelOwner, ScatteringFactorTableOwner> >
pdf3d_class("PDF3DCalculator", doc_PDF3DCalculator);

pdf3d_class
.def(init<>())
.add_property("pdf3d", get3DPDF_asarray<PDF3DCalculator>,
doc_PDF3DCalculator_pdf3d)
.add_property("radialhistogram3d",
getRadialHistogram3D_asarray<PDF3DCalculator>,
doc_PDF3DCalculator_radialhistogram3d)
.add_property("gridstep",
&PDF3DCalculator::getGridStep,
&PDF3DCalculator::setGridStep,
doc_PDF3DCalculator_gridstep)
.add_property("accumblocksize",
&PDF3DCalculator::getAccumBlockSize,
&PDF3DCalculator::setAccumBlockSize,
doc_PDF3DCalculator_accumblocksize)
.add_property("qmin",
&getqmin_value,
&PDF3DCalculator::setQmin,
doc_PDF3DCalculator_qmin)
.add_property("qmax",
&getqmax_value,
&PDF3DCalculator::setQmax,
doc_PDF3DCalculator_qmax)
.add_property("usecqwindow3d",
&PDF3DCalculator::getUseCQWindow3D,
&PDF3DCalculator::setUseCQWindow3D,
doc_PDF3DCalculator_usecqwindow3d)
.def("exportGrid3DBinary", &PDF3DCalculator::exportGrid3DBinary,
(bp::arg("path"), bp::arg("usefloat32")=true,
bp::arg("applypost")=true),
doc_PDF3DCalculator_exportGrid3DBinary)
.def("setDeltaPairTypes3D", &PDF3DCalculator::setDeltaPairTypes3D,
(bp::arg("atomtype0"), bp::arg("atomtype1")),
doc_PDF3DCalculator_setDeltaPairTypes3D)
.def_pickle(PDF3DCalculatorPickleSuite())
;

// FFT functions
def("fftftog", fftftog_array_step,
(bp::arg("f"), bp::arg("qstep"), bp::arg("qmin")=0.0),
Expand Down
Loading