TB2J 0.9.12.9__py3-none-any.whl → 0.9.12.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- TB2J/MAE.py +8 -1
- TB2J/MAEGreen.py +78 -61
- TB2J/contour.py +3 -2
- TB2J/exchange.py +346 -51
- TB2J/exchangeCL2.py +285 -47
- TB2J/exchange_params.py +48 -0
- TB2J/green.py +73 -36
- TB2J/interfaces/abacus/gen_exchange_abacus.py +2 -1
- TB2J/interfaces/wannier90_interface.py +4 -4
- TB2J/io_exchange/__init__.py +19 -1
- TB2J/io_exchange/edit.py +594 -0
- TB2J/io_exchange/io_espins.py +276 -0
- TB2J/io_exchange/io_exchange.py +248 -76
- TB2J/io_exchange/io_tomsasd.py +4 -3
- TB2J/io_exchange/io_txt.py +72 -7
- TB2J/io_exchange/io_vampire.py +4 -2
- TB2J/io_merge.py +60 -40
- TB2J/magnon/magnon3.py +27 -2
- TB2J/mathutils/rotate_spin.py +7 -7
- TB2J/myTB.py +11 -11
- TB2J/mycfr.py +11 -11
- TB2J/pauli.py +32 -2
- TB2J/plot.py +26 -0
- TB2J/rotate_atoms.py +9 -6
- TB2J/scripts/TB2J_edit.py +403 -0
- TB2J/scripts/TB2J_plot_exchange.py +48 -0
- TB2J/spinham/hamiltonian.py +156 -13
- TB2J/spinham/hamiltonian_terms.py +40 -1
- TB2J/spinham/spin_xml.py +40 -8
- TB2J/symmetrize_J.py +140 -9
- TB2J/tests/test_cli_remove_sublattice.py +33 -0
- TB2J/tests/test_cli_toggle_exchange.py +50 -0
- {tb2j-0.9.12.9.dist-info → tb2j-0.9.12.22.dist-info}/METADATA +10 -7
- {tb2j-0.9.12.9.dist-info → tb2j-0.9.12.22.dist-info}/RECORD +38 -34
- {tb2j-0.9.12.9.dist-info → tb2j-0.9.12.22.dist-info}/WHEEL +1 -1
- {tb2j-0.9.12.9.dist-info → tb2j-0.9.12.22.dist-info}/entry_points.txt +2 -0
- TB2J/interfaces/abacus/test_read_HRSR.py +0 -43
- TB2J/interfaces/abacus/test_read_stru.py +0 -32
- {tb2j-0.9.12.9.dist-info → tb2j-0.9.12.22.dist-info}/licenses/LICENSE +0 -0
- {tb2j-0.9.12.9.dist-info → tb2j-0.9.12.22.dist-info}/top_level.txt +0 -0
TB2J/io_exchange/io_exchange.py
CHANGED
|
@@ -55,6 +55,7 @@ class SpinIO(object):
|
|
|
55
55
|
write_experimental=True,
|
|
56
56
|
description=None,
|
|
57
57
|
standardize_Jani=False,
|
|
58
|
+
sia_tensor=None,
|
|
58
59
|
):
|
|
59
60
|
"""
|
|
60
61
|
:param atoms: Ase atoms structure.
|
|
@@ -80,6 +81,7 @@ class SpinIO(object):
|
|
|
80
81
|
:param gyro_ratio: gyromagnetic ratio
|
|
81
82
|
:param write_experimental: write_experimental data to output files
|
|
82
83
|
:param description: add some description into the xml file.
|
|
84
|
+
:param sia_tensor: single ion anisotropy tensor, dictionary {i: 3x3 tensor}
|
|
83
85
|
"""
|
|
84
86
|
self.atoms = atoms #: atomic structures, ase.Atoms object
|
|
85
87
|
self.index_spin = index_spin
|
|
@@ -103,12 +105,10 @@ class SpinIO(object):
|
|
|
103
105
|
self._ind_atoms[ispin] = iatom
|
|
104
106
|
|
|
105
107
|
if exchange_Jdict is not None:
|
|
106
|
-
self.has_exchange = True #: whether there is isotropic exchange
|
|
107
108
|
#: The dictionary of :math:`J_{ij}(R)`, the keys are (i,j, R),
|
|
108
109
|
# where R is a tuple, and the value is the isotropic exchange
|
|
109
110
|
self.exchange_Jdict = exchange_Jdict
|
|
110
111
|
else:
|
|
111
|
-
self.has_exchange = False
|
|
112
112
|
self.exchange_Jdict = None
|
|
113
113
|
|
|
114
114
|
self.Jiso_orb = Jiso_orb
|
|
@@ -120,21 +120,37 @@ class SpinIO(object):
|
|
|
120
120
|
self.dJdx2 = dJdx2
|
|
121
121
|
|
|
122
122
|
if dmi_ddict is not None:
|
|
123
|
-
self.has_dmi = True #: Whether there is DMI.
|
|
124
123
|
#: The dictionary of DMI. the key is the same as exchange_Jdict, the values are 3-d vectors (Dx, Dy, Dz).
|
|
125
124
|
self.dmi_ddict = dmi_ddict
|
|
126
125
|
else:
|
|
127
|
-
self.has_dmi = False
|
|
128
126
|
self.dmi_ddict = None
|
|
129
127
|
|
|
130
128
|
if Jani_dict is not None:
|
|
131
|
-
self.has_bilinear = True #: Whether there is anisotropic exchange term
|
|
132
129
|
#: The dictionary of anisotropic exchange. The vlaues are matrices of shape (3,3).
|
|
133
130
|
self.Jani_dict = Jani_dict
|
|
134
131
|
else:
|
|
135
|
-
self.has_bilinear = False
|
|
136
132
|
self.Jani_dict = None
|
|
137
133
|
|
|
134
|
+
if k1 is not None and k1dir is not None:
|
|
135
|
+
# Convert uniaxial anisotropy to SIA tensor
|
|
136
|
+
if sia_tensor is None:
|
|
137
|
+
sia_tensor = {}
|
|
138
|
+
for i, (K, axis) in enumerate(zip(k1, k1dir)):
|
|
139
|
+
if abs(K) > 1e-10:
|
|
140
|
+
e = np.array(axis)
|
|
141
|
+
norm = np.linalg.norm(e)
|
|
142
|
+
if norm > 1e-6:
|
|
143
|
+
e = e / norm
|
|
144
|
+
# A = K * e * e^T
|
|
145
|
+
A = K * np.outer(e, e)
|
|
146
|
+
if i in sia_tensor:
|
|
147
|
+
sia_tensor[i] += A
|
|
148
|
+
else:
|
|
149
|
+
sia_tensor[i] = A
|
|
150
|
+
# Clear k1 and k1dir as they are now integrated into sia_tensor
|
|
151
|
+
k1 = None
|
|
152
|
+
k1dir = None
|
|
153
|
+
|
|
138
154
|
if k1 is not None and k1dir is not None:
|
|
139
155
|
self.has_uniaxial_anistropy = True
|
|
140
156
|
self.k1 = k1
|
|
@@ -144,13 +160,19 @@ class SpinIO(object):
|
|
|
144
160
|
self.k1 = None
|
|
145
161
|
self.k1dir = None
|
|
146
162
|
|
|
147
|
-
self.has_bilinear = not (Jani_dict == {} or Jani_dict is None)
|
|
148
|
-
|
|
149
163
|
self.has_biquadratic = not (
|
|
150
164
|
biquadratic_Jdict == {} or biquadratic_Jdict is None
|
|
151
165
|
)
|
|
166
|
+
|
|
152
167
|
self.biquadratic_Jdict = biquadratic_Jdict
|
|
153
168
|
|
|
169
|
+
if sia_tensor is not None:
|
|
170
|
+
self.has_sia_tensor = True
|
|
171
|
+
self.sia_tensor = sia_tensor
|
|
172
|
+
else:
|
|
173
|
+
self.has_sia_tensor = False
|
|
174
|
+
self.sia_tensor = None
|
|
175
|
+
|
|
154
176
|
if NJT_ddict is not None:
|
|
155
177
|
self.has_NJT_dmi = True
|
|
156
178
|
self.NJT_ddict = NJT_ddict
|
|
@@ -188,6 +210,18 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
188
210
|
self.orbital_names = orbital_names
|
|
189
211
|
self.TB2J_version = __version__
|
|
190
212
|
|
|
213
|
+
@property
|
|
214
|
+
def has_exchange(self):
|
|
215
|
+
return self.exchange_Jdict is not None
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def has_dmi(self):
|
|
219
|
+
return self.dmi_ddict is not None
|
|
220
|
+
|
|
221
|
+
@property
|
|
222
|
+
def has_bilinear(self):
|
|
223
|
+
return self.Jani_dict is not None
|
|
224
|
+
|
|
191
225
|
def _build_Rlist(self):
|
|
192
226
|
Rset = set()
|
|
193
227
|
ispin_set = set()
|
|
@@ -227,12 +261,14 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
227
261
|
return self.index_spin[symdict[symnum]]
|
|
228
262
|
|
|
229
263
|
def i_spin(self, i):
|
|
230
|
-
if isinstance(i, int):
|
|
231
|
-
return i
|
|
264
|
+
if isinstance(i, (int, np.integer)):
|
|
265
|
+
return int(i)
|
|
232
266
|
elif isinstance(i, str):
|
|
233
267
|
return self.get_symbol_number_ispin(i)
|
|
234
268
|
else:
|
|
235
|
-
raise ValueError(
|
|
269
|
+
raise ValueError(
|
|
270
|
+
f"i must be either an integer or a string. Got {type(i)}: {i}"
|
|
271
|
+
)
|
|
236
272
|
|
|
237
273
|
def get_charge_ispin(self, i):
|
|
238
274
|
i = self.i_spin(i)
|
|
@@ -331,7 +367,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
331
367
|
else:
|
|
332
368
|
return default
|
|
333
369
|
|
|
334
|
-
def get_J_tensor(self, i, j, R, Jiso=True, Jani=
|
|
370
|
+
def get_J_tensor(self, i, j, R, Jiso=True, Jani=True, DMI=True, SIA=True):
|
|
335
371
|
"""
|
|
336
372
|
Return the full exchange tensor for atom i and j, and cell R.
|
|
337
373
|
param i : spin index i
|
|
@@ -352,6 +388,20 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
352
388
|
if Ja is not None:
|
|
353
389
|
Ja *= 1
|
|
354
390
|
Jtensor = combine_J_tensor(Jiso=J, D=D, Jani=Ja)
|
|
391
|
+
if np.linalg.norm(R) < 0.001 and i == j:
|
|
392
|
+
print(f"{SIA=} , {i=}")
|
|
393
|
+
print(f"{self.has_sia_tensor=}")
|
|
394
|
+
|
|
395
|
+
if (
|
|
396
|
+
SIA
|
|
397
|
+
and self.has_sia_tensor
|
|
398
|
+
and self.sia_tensor is not None
|
|
399
|
+
and i == j
|
|
400
|
+
and np.linalg.norm(R) < 0.001
|
|
401
|
+
):
|
|
402
|
+
if i in self.sia_tensor:
|
|
403
|
+
print(f"Adding SIA tensor for {i}, with {self.sia_tensor[i]}")
|
|
404
|
+
Jtensor += self.sia_tensor[i]
|
|
355
405
|
|
|
356
406
|
# if iso_only:
|
|
357
407
|
# J = self.get_Jiso(i, j, R)
|
|
@@ -367,7 +417,9 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
367
417
|
# )
|
|
368
418
|
return Jtensor
|
|
369
419
|
|
|
370
|
-
def get_full_Jtensor_for_one_R_i3j3(
|
|
420
|
+
def get_full_Jtensor_for_one_R_i3j3(
|
|
421
|
+
self, R, Jiso=True, Jani=True, DMI=True, SIA=True
|
|
422
|
+
):
|
|
371
423
|
"""
|
|
372
424
|
Return the full exchange tensor of all i and j for cell R.
|
|
373
425
|
param R (tuple of integers): cell index R
|
|
@@ -379,11 +431,13 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
379
431
|
for i in range(self.nspin):
|
|
380
432
|
for j in range(self.nspin):
|
|
381
433
|
Jmat[i * 3 : i * 3 + 3, j * 3 : j * 3 + 3] = self.get_J_tensor(
|
|
382
|
-
i, j, R, Jiso=Jiso, Jani=Jani, DMI=DMI
|
|
434
|
+
i, j, R, Jiso=Jiso, Jani=Jani, DMI=DMI, SIA=SIA
|
|
383
435
|
)
|
|
384
436
|
return Jmat
|
|
385
437
|
|
|
386
|
-
def get_full_Jtensor_for_one_R_ij33(
|
|
438
|
+
def get_full_Jtensor_for_one_R_ij33(
|
|
439
|
+
self, R, Jiso=True, Jani=True, DMI=True, SIA=True
|
|
440
|
+
):
|
|
387
441
|
"""
|
|
388
442
|
Return the full exchange tensor of all i and j for cell R.
|
|
389
443
|
param R (tuple of integers): cell index R
|
|
@@ -395,20 +449,22 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
395
449
|
for i in range(self.nspin):
|
|
396
450
|
for j in range(self.nspin):
|
|
397
451
|
Jmat[i, j, :, :] = self.get_J_tensor(
|
|
398
|
-
i, j, R, Jiso=Jiso, Jani=Jani, DMI=DMI
|
|
452
|
+
i, j, R, Jiso=Jiso, Jani=Jani, DMI=DMI, SIA=SIA
|
|
399
453
|
)
|
|
400
454
|
return Jmat
|
|
401
455
|
|
|
402
|
-
def get_full_Jtensor_for_one_R_ij(
|
|
456
|
+
def get_full_Jtensor_for_one_R_ij(
|
|
457
|
+
self, R, Jiso=True, Jani=True, DMI=True, SIA=True,
|
|
458
|
+
):
|
|
403
459
|
"""
|
|
404
460
|
Return the full exchange tensor of all i and j for cell R.
|
|
405
461
|
param R (tuple of integers): cell index R
|
|
406
462
|
returns:
|
|
407
463
|
Jmat: (nspin,nspin,3,3) matrix.
|
|
408
464
|
"""
|
|
409
|
-
if Jani or DMI:
|
|
465
|
+
if Jani or DMI or SIA:
|
|
410
466
|
raise ValueError(
|
|
411
|
-
"Jani and
|
|
467
|
+
"Jani, DMI and SIA are not supported for this method. Use get_full_Jtensor_for_one_R_ij33 instead."
|
|
412
468
|
)
|
|
413
469
|
n = self.nspin
|
|
414
470
|
Jmat = np.zeros((n, n), dtype=float)
|
|
@@ -420,7 +476,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
420
476
|
return Jmat
|
|
421
477
|
|
|
422
478
|
def get_full_Jtensor_for_Rlist(
|
|
423
|
-
self, asr=False, Jiso=True, Jani=True, DMI=True, order="i3j3"
|
|
479
|
+
self, asr=False, Jiso=True, Jani=True, DMI=True, SIA=True, order="i3j3"
|
|
424
480
|
):
|
|
425
481
|
n = self.nspin
|
|
426
482
|
n3 = n * 3
|
|
@@ -429,7 +485,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
429
485
|
Jmat = np.zeros((nR, n3, n3), dtype=float)
|
|
430
486
|
for iR, R in enumerate(self.Rlist):
|
|
431
487
|
Jmat[iR] = self.get_full_Jtensor_for_one_R_i3j3(
|
|
432
|
-
R, Jiso=Jiso, Jani=Jani, DMI=DMI
|
|
488
|
+
R, Jiso=Jiso, Jani=Jani, DMI=DMI, SIA=SIA
|
|
433
489
|
)
|
|
434
490
|
if asr:
|
|
435
491
|
iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
|
|
@@ -441,8 +497,9 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
441
497
|
elif order == "ij33":
|
|
442
498
|
Jmat = np.zeros((nR, n, n, 3, 3), dtype=float)
|
|
443
499
|
for iR, R in enumerate(self.Rlist):
|
|
500
|
+
print(f"R={R}")
|
|
444
501
|
Jmat[iR] = self.get_full_Jtensor_for_one_R_ij33(
|
|
445
|
-
R, Jiso=Jiso, Jani=Jani, DMI=DMI
|
|
502
|
+
R, Jiso=Jiso, Jani=Jani, DMI=DMI, SIA=SIA
|
|
446
503
|
)
|
|
447
504
|
if asr:
|
|
448
505
|
iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
|
|
@@ -453,20 +510,22 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
453
510
|
elif order == "i3j3_2D":
|
|
454
511
|
Jmat = np.zeros((nR, n3, n3), dtype=float)
|
|
455
512
|
for iR, R in enumerate(self.Rlist):
|
|
513
|
+
print(f"R={R}")
|
|
456
514
|
Jmat[iR] = self.get_full_Jtensor_for_one_R_i3j3(
|
|
457
|
-
R, Jiso=Jiso, Jani=Jani, DMI=DMI
|
|
515
|
+
R, Jiso=Jiso, Jani=Jani, DMI=DMI, SIA=SIA
|
|
458
516
|
).reshape((n3, n3))
|
|
459
517
|
if asr:
|
|
460
518
|
iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
|
|
461
519
|
assert np.linalg.norm(self.Rlist[iR0]) == 0
|
|
462
|
-
sum_JR = np.sum(np.sum(Jmat, axis=0))
|
|
520
|
+
sum_JR = np.sum(np.sum(Jmat, axis=0), axis=0)
|
|
521
|
+
print(sum_JR)
|
|
463
522
|
for i in range(n3):
|
|
464
|
-
Jmat[iR0][i, i] -=
|
|
523
|
+
Jmat[iR0][i, i] -= sum_JR[i]
|
|
465
524
|
elif order == "ij":
|
|
466
525
|
Jmat = np.zeros((nR, n, n), dtype=float)
|
|
467
526
|
for iR, R in enumerate(self.Rlist):
|
|
468
527
|
Jmat[iR] = self.get_full_Jtensor_for_one_R_ij(
|
|
469
|
-
R, Jiso=Jiso, Jani=Jani, DMI=DMI
|
|
528
|
+
R, Jiso=Jiso, Jani=Jani, DMI=DMI, SIA=SIA
|
|
470
529
|
)
|
|
471
530
|
if asr:
|
|
472
531
|
iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
|
|
@@ -521,6 +580,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
521
580
|
self.write_multibinit(path=os.path.join(path, "Multibinit"))
|
|
522
581
|
self.write_tom_format(path=os.path.join(path, "TomASD"))
|
|
523
582
|
self.write_vampire(path=os.path.join(path, "Vampire"))
|
|
583
|
+
self.write_espins(path=os.path.join(path, "ESPInS"))
|
|
524
584
|
|
|
525
585
|
self.plot_all(savefile=os.path.join(path, "JvsR.pdf"))
|
|
526
586
|
# self.write_Jq(kmesh=[9, 9, 9], path=path)
|
|
@@ -562,17 +622,41 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
562
622
|
marker="o",
|
|
563
623
|
fname=None,
|
|
564
624
|
show=False,
|
|
625
|
+
by_species=False,
|
|
565
626
|
**kwargs,
|
|
566
627
|
):
|
|
567
628
|
if ax is None:
|
|
568
629
|
fig, ax = plt.subplots()
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
630
|
+
if by_species:
|
|
631
|
+
groups = {}
|
|
632
|
+
for key, val in self.exchange_Jdict.items():
|
|
633
|
+
R, i, j = key
|
|
634
|
+
idx_i = self.ind_atoms[i]
|
|
635
|
+
idx_j = self.ind_atoms[j]
|
|
636
|
+
spec_i = self.atoms[idx_i].symbol
|
|
637
|
+
spec_j = self.atoms[idx_j].symbol
|
|
638
|
+
pair = tuple(sorted([spec_i, spec_j]))
|
|
639
|
+
pair_name = "-".join(pair)
|
|
640
|
+
if pair_name not in groups:
|
|
641
|
+
groups[pair_name] = {"ds": [], "Js": []}
|
|
642
|
+
d = self.distance_dict[key][1]
|
|
643
|
+
groups[pair_name]["ds"].append(d)
|
|
644
|
+
groups[pair_name]["Js"].append(val * 1e3)
|
|
645
|
+
|
|
646
|
+
for pair_name, data in groups.items():
|
|
647
|
+
ax.scatter(
|
|
648
|
+
data["ds"], data["Js"], marker=marker, label=pair_name, **kwargs
|
|
649
|
+
)
|
|
650
|
+
ax.legend()
|
|
651
|
+
else:
|
|
652
|
+
ds = []
|
|
653
|
+
Js = []
|
|
654
|
+
for key, val in self.exchange_Jdict.items():
|
|
655
|
+
d = self.distance_dict[key][1]
|
|
656
|
+
ds.append(d)
|
|
657
|
+
Js.append(val * 1e3)
|
|
658
|
+
ax.scatter(ds, Js, marker=marker, color=color, **kwargs)
|
|
659
|
+
|
|
576
660
|
ax.axhline(color="gray")
|
|
577
661
|
ax.set_xlabel(r"Distance ($\AA$)")
|
|
578
662
|
ax.set_ylabel("J (meV)")
|
|
@@ -582,25 +666,68 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
582
666
|
plt.show()
|
|
583
667
|
return ax
|
|
584
668
|
|
|
585
|
-
def plot_DvsR(self, ax=None, fname=None, show=False):
|
|
669
|
+
def plot_DvsR(self, ax=None, fname=None, show=False, by_species=False):
|
|
586
670
|
if ax is None:
|
|
587
671
|
fig, ax = plt.subplots()
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
672
|
+
if by_species:
|
|
673
|
+
groups = {}
|
|
674
|
+
for key, val in self.dmi_ddict.items():
|
|
675
|
+
R, i, j = key
|
|
676
|
+
idx_i = self.ind_atoms[i]
|
|
677
|
+
idx_j = self.ind_atoms[j]
|
|
678
|
+
spec_i = self.atoms[idx_i].symbol
|
|
679
|
+
spec_j = self.atoms[idx_j].symbol
|
|
680
|
+
pair = tuple(sorted([spec_i, spec_j]))
|
|
681
|
+
pair_name = "-".join(pair)
|
|
682
|
+
if pair_name not in groups:
|
|
683
|
+
groups[pair_name] = {"ds": [], "Ds": []}
|
|
684
|
+
d = self.distance_dict[key][1]
|
|
685
|
+
groups[pair_name]["ds"].append(d)
|
|
686
|
+
groups[pair_name]["Ds"].append(val * 1e3)
|
|
687
|
+
|
|
688
|
+
markers = ["s", "o", "D", "v", "^", "<", ">", "p", "*", "h", "H"]
|
|
689
|
+
for idx, (pair_name, data) in enumerate(groups.items()):
|
|
690
|
+
Ds = np.array(data["Ds"])
|
|
691
|
+
marker = markers[idx % len(markers)]
|
|
692
|
+
ax.scatter(
|
|
693
|
+
data["ds"],
|
|
694
|
+
Ds[:, 0],
|
|
695
|
+
marker=marker,
|
|
696
|
+
color="r",
|
|
697
|
+
label=f"{pair_name} Dx",
|
|
698
|
+
)
|
|
699
|
+
ax.scatter(
|
|
700
|
+
data["ds"],
|
|
701
|
+
Ds[:, 1],
|
|
702
|
+
marker=marker,
|
|
703
|
+
color="g",
|
|
704
|
+
label=f"{pair_name} Dy",
|
|
705
|
+
)
|
|
706
|
+
ax.scatter(
|
|
707
|
+
data["ds"],
|
|
708
|
+
Ds[:, 2],
|
|
709
|
+
marker=marker,
|
|
710
|
+
color="b",
|
|
711
|
+
label=f"{pair_name} Dz",
|
|
712
|
+
)
|
|
713
|
+
ax.legend(ncol=3, fontsize="small")
|
|
714
|
+
else:
|
|
715
|
+
ds = []
|
|
716
|
+
Ds = []
|
|
717
|
+
for key, val in self.dmi_ddict.items():
|
|
718
|
+
d = self.distance_dict[key][1]
|
|
719
|
+
ds.append(d)
|
|
720
|
+
Ds.append(val * 1e3)
|
|
721
|
+
Ds = np.array(Ds)
|
|
722
|
+
ax.scatter(ds, Ds[:, 0], marker="s", color="r", label="Dx")
|
|
723
|
+
ax.scatter(
|
|
724
|
+
ds, Ds[:, 1], marker="o", edgecolors="g", facecolors="none", label="Dy"
|
|
725
|
+
)
|
|
726
|
+
ax.scatter(
|
|
727
|
+
ds, Ds[:, 2], marker="D", edgecolors="b", facecolors="none", label="Dz"
|
|
728
|
+
)
|
|
729
|
+
ax.legend(loc=1)
|
|
602
730
|
ax.axhline(color="gray")
|
|
603
|
-
ax.legend(loc=1)
|
|
604
731
|
ax.set_ylabel("D (meV)")
|
|
605
732
|
ax.set_xlabel(r"Distance ($\AA$)")
|
|
606
733
|
if fname is not None:
|
|
@@ -609,31 +736,71 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
609
736
|
plt.show()
|
|
610
737
|
return ax
|
|
611
738
|
|
|
612
|
-
def plot_JanivsR(self, ax=None, fname=None, show=False):
|
|
739
|
+
def plot_JanivsR(self, ax=None, fname=None, show=False, by_species=False):
|
|
613
740
|
if ax is None:
|
|
614
741
|
fig, ax = plt.subplots()
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
742
|
+
if by_species:
|
|
743
|
+
groups = {}
|
|
744
|
+
for key, val in self.Jani_dict.items():
|
|
745
|
+
R, i, j = key
|
|
746
|
+
idx_i = self.ind_atoms[i]
|
|
747
|
+
idx_j = self.ind_atoms[j]
|
|
748
|
+
spec_i = self.atoms[idx_i].symbol
|
|
749
|
+
spec_j = self.atoms[idx_j].symbol
|
|
750
|
+
pair = tuple(sorted([spec_i, spec_j]))
|
|
751
|
+
pair_name = "-".join(pair)
|
|
752
|
+
if pair_name not in groups:
|
|
753
|
+
groups[pair_name] = {"ds": [], "Jani": []}
|
|
754
|
+
d = self.distance_dict[key][1]
|
|
755
|
+
groups[pair_name]["ds"].append(d)
|
|
756
|
+
groups[pair_name]["Jani"].append(val * 1e3)
|
|
757
|
+
|
|
758
|
+
markers = ["s", "o", "D", "v", "^", "<", ">", "p", "*", "h", "H"]
|
|
759
|
+
s = "xyz"
|
|
760
|
+
for idx, (pair_name, data) in enumerate(groups.items()):
|
|
761
|
+
Jani = np.array(data["Jani"])
|
|
762
|
+
marker = markers[idx % len(markers)]
|
|
763
|
+
# Diagonal
|
|
764
|
+
for i in range(3):
|
|
765
|
+
ax.scatter(
|
|
766
|
+
data["ds"],
|
|
767
|
+
Jani[:, i, i],
|
|
768
|
+
marker=marker,
|
|
769
|
+
label=f"{pair_name} J{s[i]}{s[i]}",
|
|
770
|
+
)
|
|
771
|
+
# Off-diagonal
|
|
772
|
+
for i, j in [(0, 1), (0, 2), (1, 2)]:
|
|
773
|
+
ax.scatter(
|
|
774
|
+
data["ds"],
|
|
775
|
+
Jani[:, i, j],
|
|
776
|
+
marker=marker,
|
|
777
|
+
facecolors="none",
|
|
778
|
+
label=f"{pair_name} J{s[i]}{s[j]}",
|
|
779
|
+
)
|
|
780
|
+
ax.legend(ncol=3, fontsize="small")
|
|
781
|
+
else:
|
|
782
|
+
ds = []
|
|
783
|
+
Jani = []
|
|
784
|
+
for key, val in self.Jani_dict.items():
|
|
785
|
+
d = self.distance_dict[key][1]
|
|
786
|
+
ds.append(d)
|
|
787
|
+
# val = val - np.diag([np.trace(val) / 3] * 3)
|
|
788
|
+
Jani.append(val * 1e3)
|
|
789
|
+
Jani = np.array(Jani)
|
|
790
|
+
s = "xyz"
|
|
791
|
+
for i in range(3):
|
|
792
|
+
ax.scatter(ds, Jani[:, i, i], marker="s", label=f"J{s[i]}{s[i]}")
|
|
793
|
+
c = "rgb"
|
|
794
|
+
for ic, (i, j) in enumerate([(0, 1), (0, 2), (1, 2)]):
|
|
795
|
+
ax.scatter(
|
|
796
|
+
ds,
|
|
797
|
+
Jani[:, i, j],
|
|
798
|
+
edgecolors=c[ic],
|
|
799
|
+
facecolors="none",
|
|
800
|
+
label=f"J{s[i]}{s[j]}",
|
|
801
|
+
)
|
|
802
|
+
ax.legend(loc=1, ncol=2)
|
|
635
803
|
ax.axhline(color="gray")
|
|
636
|
-
ax.legend(loc=1, ncol=2)
|
|
637
804
|
ax.set_xlabel(r"Distance ($\AA$)")
|
|
638
805
|
ax.set_ylabel("Jani (meV)")
|
|
639
806
|
if fname is not None:
|
|
@@ -642,7 +809,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
642
809
|
plt.show()
|
|
643
810
|
return ax
|
|
644
811
|
|
|
645
|
-
def plot_all(self, title=None, savefile=None, show=False):
|
|
812
|
+
def plot_all(self, title=None, savefile=None, show=False, by_species=False):
|
|
646
813
|
if self.has_dmi and self.has_bilinear:
|
|
647
814
|
naxis = 3
|
|
648
815
|
else:
|
|
@@ -650,11 +817,11 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
650
817
|
fig, axes = plt.subplots(naxis, 1, sharex=True, figsize=(5, 2.2 * naxis))
|
|
651
818
|
|
|
652
819
|
if self.has_dmi and self.has_bilinear:
|
|
653
|
-
self.plot_JvsR(axes[0])
|
|
654
|
-
self.plot_DvsR(axes[1])
|
|
655
|
-
self.plot_JanivsR(axes[2])
|
|
820
|
+
self.plot_JvsR(axes[0], by_species=by_species)
|
|
821
|
+
self.plot_DvsR(axes[1], by_species=by_species)
|
|
822
|
+
self.plot_JanivsR(axes[2], by_species=by_species)
|
|
656
823
|
else:
|
|
657
|
-
self.plot_JvsR(axes)
|
|
824
|
+
self.plot_JvsR(axes, by_species=by_species)
|
|
658
825
|
|
|
659
826
|
if title is not None:
|
|
660
827
|
fig.suptitle(title)
|
|
@@ -684,6 +851,11 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
|
|
|
684
851
|
|
|
685
852
|
write_uppasd(self, path=path)
|
|
686
853
|
|
|
854
|
+
def write_espins(self, path):
|
|
855
|
+
from TB2J.io_exchange.io_espins import write_espins
|
|
856
|
+
|
|
857
|
+
write_espins(self, path=path)
|
|
858
|
+
|
|
687
859
|
|
|
688
860
|
def gen_distance_dict(ind_mag_atoms, atoms, Rlist):
|
|
689
861
|
distance_dict = {}
|
TB2J/io_exchange/io_tomsasd.py
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import numpy as np
|
|
2
1
|
import os
|
|
3
2
|
from itertools import groupby
|
|
4
3
|
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
5
6
|
|
|
6
7
|
def write_tom_ucf(cls, fname):
|
|
7
8
|
"""
|
|
@@ -25,8 +26,8 @@ def write_tom_ucf(cls, fname):
|
|
|
25
26
|
gyro_ratio = cls.gyro_ratio[i]
|
|
26
27
|
symbol = cls.atoms.get_chemical_symbols()[i]
|
|
27
28
|
if cls.has_uniaxial_anistropy:
|
|
28
|
-
k1 = cls.k1[
|
|
29
|
-
k1dir = cls.k1dir[
|
|
29
|
+
k1 = cls.k1[id_spin]
|
|
30
|
+
k1dir = cls.k1dir[id_spin]
|
|
30
31
|
else:
|
|
31
32
|
k1 = 0.0
|
|
32
33
|
k1dir = [0.0, 0.0, 1.0]
|