Skip to content

Commit 14ab3df

Browse files
committed
Merge branch 'fix-atom-crash-on-numpy-int'
* add conversion utility extractdouble * use `extractdouble` to convert Atom attributes Close #20.
2 parents 6ab6ed3 + 08f0f19 commit 14ab3df

5 files changed

Lines changed: 126 additions & 36 deletions

File tree

src/diffpy/srreal/structureconverters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def _fetchDiffPyStructureData(adpt, stru):
142142
aa = AdapterAtom()
143143
for a0 in stru:
144144
aa.atomtype = a0.element
145-
aa.occupancy = float(a0.occupancy)
145+
aa.occupancy = a0.occupancy
146146
aa.anisotropy = a0.anisotropy
147147
# copy fractional coordinates
148148
aa.xyz_cartn = a0.xyz

src/diffpy/srreal/tests/teststructureadapter.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,42 @@ def test_uij_cartn(self):
599599
self.assertEqual(0.023, a.uc23)
600600
return
601601

602+
def test_xc_yc_zc(self):
603+
'check Atom properties xc, yc, zc.'
604+
a = self.a
605+
a.xc, a.yc, a.zc = numpy.arange(1, 4)
606+
self.assertEqual(1.0, a.xc)
607+
self.assertEqual(2.0, a.yc)
608+
self.assertEqual(3.0, a.zc)
609+
return
610+
611+
def test_occupancy(self):
612+
'check Atom.occupancy'
613+
a = self.a
614+
a.occupancy, = numpy.arange(1)
615+
self.assertEqual(0.0, a.occupancy)
616+
a.occupancy = numpy.float32(0.5)
617+
self.assertEqual(0.5, a.occupancy)
618+
return
619+
620+
def test_anisotropy(self):
621+
'check Atom.anisotropy'
622+
a = self.a
623+
nptrue, npfalse = (numpy.arange(2) < 1)
624+
a.anisotropy = nptrue
625+
self.assertTrue(a.anisotropy)
626+
a.anisotropy = npfalse
627+
self.assertFalse(a.anisotropy)
628+
return
629+
630+
def test_ucij(self):
631+
'check Atom attributes u11, u22, etc.'
632+
a = self.a
633+
a.uc11, a.uc22, a.uc33, a.uc12, a.uc13, a.uc23 = numpy.arange(1, 7)
634+
uijexp = [[1, 4, 5], [4, 2, 6], [5, 6, 3]]
635+
self.assertTrue(numpy.array_equal(uijexp, a.uij_cartn))
636+
return
637+
602638
# End of class TestAtom
603639

604640
# ----------------------------------------------------------------------------

src/extensions/srreal_converters.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,25 @@ NumPyArray_DoublePtr extractNumPyDoubleArray(::boost::python::object& obj)
282282
}
283283

284284

285+
/// extract double with a support for numpy.int types
286+
double extractdouble(boost::python::object obj)
287+
{
288+
using namespace boost;
289+
python::extract<double> getx(obj);
290+
if (getx.check()) return getx();
291+
PyObject* pobj = obj.ptr();
292+
if (PyArray_CheckScalar(pobj))
293+
{
294+
double x;
295+
PyArray_CastScalarToCtype(pobj, &x,
296+
PyArray_DescrFromType(NPY_DOUBLE));
297+
return x;
298+
}
299+
// nothing worked, call getx which will raise an exception
300+
return getx();
301+
}
302+
303+
285304
/// extract integer with a support for numpy.int types
286305
int extractint(boost::python::object obj)
287306
{

src/extensions/srreal_converters.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,10 @@ extractQuantityType(::boost::python::object obj,
395395
NumPyArray_DoublePtr extractNumPyDoubleArray(::boost::python::object& obj);
396396

397397

398+
/// extract double with a support for numpy numeric types
399+
double extractdouble(::boost::python::object obj);
400+
401+
398402
/// extract integer with a support for numpy.int types
399403
int extractint(::boost::python::object obj);
400404

src/extensions/wrap_AtomicStructureAdapter.cpp

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ view to the data in C++ class. Do not resize or reshape.\n\
6767
const char* doc_Atom_init_copy = "\
6868
Make a deep copy of an existing Atom.\n\
6969
";
70-
const char* doc_Atom_xic = "Vector element in xyz_cartn";
71-
const char* doc_Atom_uijc = "Matrix element in uij_cartn";
70+
const char* doc_Atom_xic = "Vector element in xyz_cartn.";
71+
const char* doc_Atom_occ = "Fractional occupancy of this atom.";
72+
const char* doc_Atom_anisotropy =
73+
"Boolean flag for anisotropic displacements.";
74+
const char* doc_Atom_uijc = "Matrix element in uij_cartn.";
7275

7376
// class AtomicStructureAdapter
7477

@@ -270,28 +273,55 @@ void set_uij_cartn(Atom& a, object& value)
270273
}
271274

272275

273-
double get_xc(const Atom& a) { return a.xyz_cartn[0]; }
274-
void set_xc(Atom& a, double value) { a.xyz_cartn[0] = value; }
275-
double get_yc(const Atom& a) { return a.xyz_cartn[1]; }
276-
void set_yc(Atom& a, double value) { a.xyz_cartn[1] = value; }
277-
double get_zc(const Atom& a) { return a.xyz_cartn[2]; }
278-
void set_zc(Atom& a, double value) { a.xyz_cartn[2] = value; }
279-
280-
double get_uc11(const Atom& a) { return a.uij_cartn(0, 0); }
281-
void set_uc11(Atom& a, double value) { a.uij_cartn(0, 0) = value; }
282-
double get_uc22(const Atom& a) { return a.uij_cartn(1, 1); }
283-
void set_uc22(Atom& a, double value) { a.uij_cartn(1, 1) = value; }
284-
double get_uc33(const Atom& a) { return a.uij_cartn(2, 2); }
285-
void set_uc33(Atom& a, double value) { a.uij_cartn(2, 2) = value; }
286-
double get_uc12(const Atom& a) { return a.uij_cartn(0, 1); }
287-
void set_uc12(Atom& a, double value) {
288-
a.uij_cartn(0, 1) = a.uij_cartn(1, 0) = value; }
289-
double get_uc13(const Atom& a) { return a.uij_cartn(0, 2); }
290-
void set_uc13(Atom& a, double value) {
291-
a.uij_cartn(0, 2) = a.uij_cartn(2, 0) = value; }
292-
double get_uc23(const Atom& a) { return a.uij_cartn(1, 2); }
293-
void set_uc23(Atom& a, double value) {
294-
a.uij_cartn(1, 2) = a.uij_cartn(2, 1) = value; }
276+
template <const int i>
277+
double get_xyz(const Atom& a)
278+
{
279+
return a.xyz_cartn[i];
280+
}
281+
282+
template <const int i>
283+
void set_xyz(Atom& a, object value)
284+
{
285+
a.xyz_cartn[i] = extractdouble(value);
286+
}
287+
288+
289+
double get_occ(const Atom& a)
290+
{
291+
return a.occupancy;
292+
}
293+
294+
void set_occ(Atom& a, object value)
295+
{
296+
a.occupancy = extractdouble(value);
297+
}
298+
299+
300+
bool get_anisotropy(const Atom& a)
301+
{
302+
return a.anisotropy;
303+
}
304+
305+
void set_anisotropy(Atom& a, object value)
306+
{
307+
a.anisotropy = bool(value);
308+
}
309+
310+
311+
template <const int i, const int j>
312+
double get_uc(const Atom& a)
313+
{
314+
assert(i <= j);
315+
return a.uij_cartn(i, j);
316+
}
317+
318+
template <const int i, const int j>
319+
void set_uc(Atom& a, object value)
320+
{
321+
assert(i <= j);
322+
a.uij_cartn(i, j) = extractdouble(value);
323+
if (i != j) a.uij_cartn(j, i) = a.uij_cartn(i, j);
324+
}
295325

296326
// template wrapper class for overloading of clone and _customPQConfig
297327

@@ -524,20 +554,21 @@ void wrap_AtomicStructureAdapter()
524554
.add_property("xyz_cartn",
525555
atom_class.attr("_get_xyz_cartn"),
526556
set_xyz_cartn)
527-
.add_property("xc", get_xc, set_xc, doc_Atom_xic)
528-
.add_property("yc", get_yc, set_yc, doc_Atom_xic)
529-
.add_property("zc", get_zc, set_zc, doc_Atom_xic)
530-
.def_readwrite("occupancy", &Atom::occupancy)
531-
.def_readwrite("anisotropy", &Atom::anisotropy)
557+
.add_property("xc", get_xyz<0>, set_xyz<0>, doc_Atom_xic)
558+
.add_property("yc", get_xyz<1>, set_xyz<1>, doc_Atom_xic)
559+
.add_property("zc", get_xyz<2>, set_xyz<2>, doc_Atom_xic)
560+
.add_property("occupancy", get_occ, set_occ, doc_Atom_occ)
561+
.add_property("anisotropy", get_anisotropy, set_anisotropy,
562+
doc_Atom_anisotropy)
532563
.add_property("uij_cartn",
533564
atom_class.attr("_get_uij_cartn"),
534565
set_uij_cartn)
535-
.add_property("uc11", get_uc11, set_uc11, doc_Atom_uijc)
536-
.add_property("uc22", get_uc22, set_uc22, doc_Atom_uijc)
537-
.add_property("uc33", get_uc33, set_uc33, doc_Atom_uijc)
538-
.add_property("uc12", get_uc12, set_uc12, doc_Atom_uijc)
539-
.add_property("uc13", get_uc13, set_uc13, doc_Atom_uijc)
540-
.add_property("uc23", get_uc23, set_uc23, doc_Atom_uijc)
566+
.add_property("uc11", get_uc<0, 0>, set_uc<0, 0>, doc_Atom_uijc)
567+
.add_property("uc22", get_uc<1, 1>, set_uc<1, 1>, doc_Atom_uijc)
568+
.add_property("uc33", get_uc<2, 2>, set_uc<2, 2>, doc_Atom_uijc)
569+
.add_property("uc12", get_uc<0, 1>, set_uc<0, 1>, doc_Atom_uijc)
570+
.add_property("uc13", get_uc<0, 2>, set_uc<0, 2>, doc_Atom_uijc)
571+
.add_property("uc23", get_uc<1, 2>, set_uc<1, 2>, doc_Atom_uijc)
541572
.def_pickle(SerializationPickleSuite<Atom,DICT_IGNORE>())
542573
;
543574

0 commit comments

Comments
 (0)