Skip to content

Commit edc2c99

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents a8607e9 + 9a30009 commit edc2c99

File tree

3 files changed

+149
-3
lines changed

3 files changed

+149
-3
lines changed

Dans_Diffraction/classes_crystal.py

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,96 @@ def start_gui(self):
365365
except ImportError:
366366
print('Sorry, you need to install tkinter!')
367367

368+
def search_distances(self, min_d=0.65, max_d=3.20, c_ele=None, elems=None,
369+
labels=None, simple=True):
370+
"""
371+
Calculated atoms interatomic distances form each label.
372+
:param c_ele (list,string): only sites with noted elements
373+
if None all site
374+
:param elems (list,string): only distances with noted elements
375+
if None all site
376+
:param min_d: minimum distance
377+
:param max_d: maximum distance
378+
:return dictionary:
379+
380+
"""
381+
xyz = self.Cell.calculateR(self.Atoms.uvw())
382+
UVstar = self.Cell.UVstar()
383+
UV = self.Cell.UV()
384+
Lpar = self.Cell.lp()[:3]
385+
386+
Lran = np.array([0, 0, 0, 0, 0, 0])
387+
388+
for i in range(3):
389+
Lran[i] = min(fg.distance2plane([0, 0, 0], UVstar[i], xyz))
390+
for i in range(3):
391+
Lran[3 + i] = min(fg.distance2plane(UV[i], UVstar[i] + UV[i], xyz))
392+
for i, L in enumerate(Lran):
393+
Lran[i] = np.ceil(max_d / Lpar[i % 3]) if L < max_d else 0
394+
395+
IntRes = self.Structure.generate_lattice(U=Lran[0] + Lran[3],
396+
V=Lran[1] + Lran[4],
397+
W=Lran[2] + Lran[5],
398+
centred=False)[:3]
399+
B_uvw, B_Ele, B_label = IntRes
400+
B_label, B_Ele = np.asarray(B_label), np.asarray(B_Ele)
401+
402+
B_uvw -= np.array(Lran[:3])
403+
B_xyz = self.Cell.calculateR(B_uvw)
404+
405+
if c_ele is None:
406+
c_ele = set(self.Atoms.type)
407+
elif isinstance(c_ele, str):
408+
c_ele = [c_ele]
409+
410+
if elems is None:
411+
elems = set(self.Atoms.type)
412+
elif isinstance(elems, str):
413+
elems = [elems]
414+
415+
if labels is None:
416+
labels = self.Atoms.label
417+
elif isinstance(labels, str):
418+
labels = [labels]
419+
420+
distances = {}
421+
for i, atom in enumerate(xyz):
422+
if not self.Atoms.type[i] in c_ele:
423+
continue
424+
if not self.Atoms.label[i] in labels:
425+
continue
426+
s_dist = {}
427+
vdist = (B_xyz - atom) ** 2
428+
vdist = np.sqrt(np.sum(vdist, axis=1))
429+
cond1 = (vdist > min_d) * (vdist < max_d)
430+
vlabel = B_label[cond1]
431+
vele = B_Ele[cond1]
432+
vdist = vdist[cond1]
433+
434+
Ord = np.argsort(vdist)
435+
cond2 = [ele in elems for ele in vele[Ord]]
436+
s_dist = {'dist': vdist[Ord][cond2],
437+
'label': list(vlabel[Ord][cond2]),
438+
'type': list(vele[Ord][cond2])}
439+
440+
distances[self.Atoms.label[i]] = s_dist
441+
442+
if simple:
443+
# reduce the output for mixed site occupation
444+
lab = [i for i,j in zip(self.Atoms.label, self.Atoms.type) if j in c_ele]
445+
for i, site_i in enumerate(lab):
446+
for site_j in lab[i + 1:]:
447+
uvw_i = self.Atoms[site_i].uvw()
448+
uvw_j = self.Atoms[site_j].uvw()
449+
if all(uvw_i == uvw_j):
450+
lab.remove(site_j)
451+
try:
452+
del distances[site_j]
453+
except KeyError:
454+
pass
455+
456+
return distances
457+
368458
def __add__(self, other):
369459
return MultiCrystal([self, other])
370460

@@ -564,7 +654,7 @@ def indexQ(self, Q):
564654
Convert coordinates [x,y,z], in an orthogonal basis, to
565655
coordinates [h,k,l], in the basis of the reciprocal lattice
566656
H(h,k,l) = Q(x,y,z) / [A*,B*,C*]
567-
657+
568658
E.G.
569659
HKL = indexQ([2.2046264, 1.2728417, 0.0000000]) # for a hexagonal system, a = 2.85
570660
> HKL = [1,0,0]
@@ -577,7 +667,6 @@ def calculateR(self, UVW):
577667
Convert coordinates [u,v,w], in the basis of the unit cell, to
578668
coordinates [x,y,z], in an orthogonal basis, in units of A
579669
R(x,y,z) = uA + vB + wC
580-
581670
E.G.
582671
R = Cell.calculateR([0.1,0,0]) # for a hexagonal system, a = 2.85
583672
> R = array([[0.285, 0, 0]])
@@ -1030,6 +1119,8 @@ def __call__(self, u=[0], v=[0], w=[0], type=None,
10301119
self.__init__(u, v, w, type, label, occupancy, uiso, mxmymz=None)
10311120

10321121
def __getitem__(self, idx):
1122+
if isinstance(idx, str):
1123+
idx = self.label.index(idx)
10331124
return self.atom(idx)
10341125

10351126
def fromcif(self, cifvals):

Dans_Diffraction/classes_plotting.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,43 @@ def plot_crystal(self, show_labels=False):
143143
plt.legend(fontsize=24, frameon=False)
144144

145145
plt.title(self.xtl.name, fontsize=28, fontweight='bold')
146-
146+
147+
def plot_distance(self, min_d=0.65, max_d=3.20, labels=None,
148+
c_ele=None, elems=None, ranges=None, step=0.04):
149+
"""
150+
Plot atoms interatomic distances form each label.
151+
:param c_ele (list,string): only sites with noted elements
152+
if None all site
153+
:param elems (list,string): only distances with noted elements
154+
if None all site
155+
:param min_d: minimum distance
156+
:param max_d: maximum distance
157+
:return:
158+
"""
159+
dist = self.xtl.search_distances(c_ele=c_ele, elems=elems,
160+
labels=labels, min_d=min_d,
161+
max_d=max_d)
162+
163+
if ranges is None:
164+
all_d = np.hstack([i['dist'] for i in dist.values()])
165+
ranges = (np.floor(min(all_d)), np.ceil(max(all_d)))
166+
# Create plot
167+
if len(dist) == 0:
168+
print('no distance present')
169+
return
170+
fig, axs = plt.subplots(len(dist), constrained_layout=True)
171+
if len(dist) == 1:
172+
axs = [axs]
173+
for i, site in enumerate(dist):
174+
axs[i].set_title(site)
175+
axs[i].hist(dist[site]['dist'], range=ranges,
176+
bins=int((ranges[1] - ranges[0]) / step))
177+
axs[i].set(ylabel='n. Atoms')
178+
axs[-1].set(xlabel='$\AA$')
179+
if len(dist) > 1:
180+
for ax in axs.flat:
181+
ax.label_outer()
182+
147183
def plot_layers(self, layers=None, layer_axis=2, layer_width=0.05, show_labels=False):
148184
"""
149185
Separate the structure into layers along the chosen axis

Dans_Diffraction/functions_general.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,25 @@ def distance2line(line_start, line_end, point):
497497
return np.sqrt(np.sum(vec_arb ** 2))
498498

499499

500+
def distance2plane(line_start, line_end, point):
501+
"""
502+
Calculate distance from a plane (defined by a perpendicular vector) to an arbitary point in space
503+
:param vector_start: array, position lying on plane and vector start
504+
:param line_end: array, position of the end of the vector
505+
:param point: array, arbitary position in space
506+
:return: float
507+
"""
508+
line_start = np.asarray(line_start)
509+
line_end = np.asarray(line_end)
510+
point = np.asarray(point)
511+
512+
line_diff = line_end - line_start
513+
unit_line = line_diff / np.sqrt(np.sum(line_diff ** 2))
514+
515+
vec_arb = np.dot((point - line_start), unit_line)
516+
return abs(vec_arb)
517+
518+
500519
def vector_intersection(point1, direction1, point2, direction2):
501520
"""
502521
Calculate the point in 2D where two lines cross.

0 commit comments

Comments
 (0)