TB2J 0.9.9.8__py3-none-any.whl → 0.9.9.10__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.
Files changed (26) hide show
  1. TB2J/__init__.py +1 -1
  2. TB2J/io_exchange/io_exchange.py +57 -25
  3. TB2J/io_exchange/io_vampire.py +9 -3
  4. TB2J/magnon/__init__.py +2 -2
  5. TB2J/magnon/magnon3.py +546 -56
  6. TB2J/magnon/magnon_band.py +180 -0
  7. TB2J/magnon/plot.py +60 -21
  8. TB2J/mathutils/auto_kpath.py +154 -0
  9. tb2j-0.9.9.10.data/scripts/TB2J_plot_magnon_bands.py +7 -0
  10. {tb2j-0.9.9.8.dist-info → tb2j-0.9.9.10.dist-info}/METADATA +3 -1
  11. {tb2j-0.9.9.8.dist-info → tb2j-0.9.9.10.dist-info}/RECORD +26 -23
  12. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_downfold.py +0 -0
  13. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_eigen.py +0 -0
  14. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_magnon.py +0 -0
  15. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_magnon2.py +0 -0
  16. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_magnon_dos.py +0 -0
  17. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_merge.py +0 -0
  18. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_rotate.py +0 -0
  19. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/TB2J_rotateDM.py +0 -0
  20. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/abacus2J.py +0 -0
  21. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/siesta2J.py +0 -0
  22. {tb2j-0.9.9.8.data → tb2j-0.9.9.10.data}/scripts/wann2J.py +0 -0
  23. {tb2j-0.9.9.8.dist-info → tb2j-0.9.9.10.dist-info}/WHEEL +0 -0
  24. {tb2j-0.9.9.8.dist-info → tb2j-0.9.9.10.dist-info}/entry_points.txt +0 -0
  25. {tb2j-0.9.9.8.dist-info → tb2j-0.9.9.10.dist-info}/licenses/LICENSE +0 -0
  26. {tb2j-0.9.9.8.dist-info → tb2j-0.9.9.10.dist-info}/top_level.txt +0 -0
TB2J/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.9.9.8"
1
+ __version__ = "0.9.9.9"
@@ -190,6 +190,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
190
190
  def _build_Rlist(self):
191
191
  Rset = set()
192
192
  ispin_set = set()
193
+ Rset.add((0, 0, 0)) # always add the zero vector
193
194
  for R, i, j in self.exchange_Jdict:
194
195
  Rset.add(R)
195
196
  ispin_set.add(i)
@@ -236,6 +237,23 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
236
237
  i = self.i_spin(i)
237
238
  return self.charges[self.iatom(i)]
238
239
 
240
+ def get_magnetic_moments(self):
241
+ """Get magnetic moments for magnetic atoms only.
242
+
243
+ Returns
244
+ -------
245
+ np.ndarray
246
+ Array of shape (n_magnetic_atoms, 3) containing the magnetic moments.
247
+ For collinear calculations, only the z component is meaningful.
248
+ """
249
+ mag_atoms = [i for i, idx in enumerate(self.index_spin) if idx >= 0]
250
+ if self.spinat.ndim == 1: # Handle collinear case with only z-component
251
+ moments = np.zeros((len(mag_atoms), 3))
252
+ moments[:, 2] = self.spinat[mag_atoms]
253
+ return moments
254
+ else: # Full 3D magnetic moments
255
+ return self.spinat[mag_atoms]
256
+
239
257
  def get_spin_iatom(self, iatom):
240
258
  return self.spinat[iatom]
241
259
 
@@ -263,7 +281,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
263
281
  j,
264
282
  )
265
283
  if self.exchange_Jdict is not None and key in self.exchange_Jdict:
266
- return self.exchange_Jdict[key]
284
+ return np.real(self.exchange_Jdict[key])
267
285
  else:
268
286
  return default
269
287
 
@@ -276,7 +294,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
276
294
  j,
277
295
  )
278
296
  if self.exchange_Jdict is not None and key in self.exchange_Jdict:
279
- return self.exchange_Jdict[key]
297
+ return np.real(self.exchange_Jdict[key])
280
298
  else:
281
299
  return default
282
300
 
@@ -289,7 +307,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
289
307
  j,
290
308
  )
291
309
  if self.dmi_ddict is not None and key in self.dmi_ddict:
292
- return self.dmi_ddict[(tuple(R), i, j)]
310
+ return np.real(self.dmi_ddict[(tuple(R), i, j)])
293
311
  else:
294
312
  return default
295
313
 
@@ -308,11 +326,11 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
308
326
  j,
309
327
  )
310
328
  if self.Jani_dict is not None and key in self.Jani_dict:
311
- return self.Jani_dict[(tuple(R), i, j)]
329
+ return np.real(self.Jani_dict[(tuple(R), i, j)])
312
330
  else:
313
331
  return default
314
332
 
315
- def get_J_tensor(self, i, j, R, iso_only=False):
333
+ def get_J_tensor(self, i, j, R, Jiso=True, Jani=False, DMI=False):
316
334
  """
317
335
  Return the full exchange tensor for atom i and j, and cell R.
318
336
  param i : spin index i
@@ -321,21 +339,26 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
321
339
  """
322
340
  i = self.i_spin(i)
323
341
  j = self.i_spin(j)
324
- if iso_only:
325
- J = self.get_Jiso(i, j, R)
326
- if J is not None:
327
- Jtensor = np.eye(3) * self.get_J(i, j, R)
328
- else:
329
- Jtensor = np.eye(3) * 0
330
- else:
331
- Jtensor = combine_J_tensor(
332
- Jiso=self.get_J(i, j, R),
333
- D=self.get_DMI(i, j, R),
334
- Jani=self.get_Jani(i, j, R),
335
- )
342
+ Jtensor = combine_J_tensor(
343
+ Jiso=self.get_J(i, j, R) if Jiso else None,
344
+ D=self.get_DMI(i, j, R) if DMI else None,
345
+ Jani=self.get_Jani(i, j, R) if Jani else None,
346
+ )
347
+ # if iso_only:
348
+ # J = self.get_Jiso(i, j, R)
349
+ # if J is not None:
350
+ # Jtensor = np.eye(3) * self.get_J(i, j, R)
351
+ # else:
352
+ # Jtensor = np.eye(3) * 0
353
+ # else:
354
+ # Jtensor = combine_J_tensor(
355
+ # Jiso=self.get_J(i, j, R),
356
+ # D=self.get_DMI(i, j, R),
357
+ # Jani=self.get_Jani(i, j, R),
358
+ # )
336
359
  return Jtensor
337
360
 
338
- def get_full_Jtensor_for_one_R_i3j3(self, R, iso_only=False):
361
+ def get_full_Jtensor_for_one_R_i3j3(self, R, Jiso=True, Jani=True, DMI=True):
339
362
  """
340
363
  Return the full exchange tensor of all i and j for cell R.
341
364
  param R (tuple of integers): cell index R
@@ -347,11 +370,11 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
347
370
  for i in range(self.nspin):
348
371
  for j in range(self.nspin):
349
372
  Jmat[i * 3 : i * 3 + 3, j * 3 : j * 3 + 3] = self.get_J_tensor(
350
- i, j, R, iso_only=iso_only
373
+ i, j, R, Jiso=Jiso, Jani=Jani, DMI=DMI
351
374
  )
352
375
  return Jmat
353
376
 
354
- def get_full_Jtensor_for_one_R_ij33(self, R, iso_only=False):
377
+ def get_full_Jtensor_for_one_R_ij33(self, R, Jiso=True, Jani=True, DMI=True):
355
378
  """
356
379
  Return the full exchange tensor of all i and j for cell R.
357
380
  param R (tuple of integers): cell index R
@@ -362,27 +385,36 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
362
385
  Jmat = np.zeros((n, n, 3, 3), dtype=float)
363
386
  for i in range(self.nspin):
364
387
  for j in range(self.nspin):
365
- Jmat[i, j, :, :] = self.get_J_tensor(i, j, R, iso_only=iso_only)
388
+ Jmat[i, j, :, :] = self.get_J_tensor(
389
+ i, j, R, Jiso=Jiso, Jani=Jani, DMI=DMI
390
+ )
366
391
  return Jmat
367
392
 
368
- def get_full_Jtensor_for_Rlist(self, asr=False, iso_only=True, order="i3j3"):
393
+ def get_full_Jtensor_for_Rlist(
394
+ self, asr=False, Jiso=True, Jani=True, DMI=True, order="i3j3"
395
+ ):
369
396
  n = self.nspin
370
397
  n3 = n * 3
371
398
  nR = len(self.Rlist)
372
399
  if order == "i3j3":
373
400
  Jmat = np.zeros((nR, n3, n3), dtype=float)
374
401
  for iR, R in enumerate(self.Rlist):
375
- Jmat[iR] = self.get_full_Jtensor_for_one_R_i3j3(R, iso_only=iso_only)
402
+ Jmat[iR] = self.get_full_Jtensor_for_one_R_i3j3(
403
+ R, Jiso=Jiso, Jani=Jani, DMI=DMI
404
+ )
376
405
  if asr:
377
406
  iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
378
407
  assert np.linalg.norm(self.Rlist[iR0]) == 0
379
408
  for i in range(n3):
380
409
  sum_JRi = np.sum(np.sum(Jmat, axis=0)[i])
381
- Jmat[iR0][i, i] -= sum_JRi
410
+ Jmat[iR0][i, :, i, :] -= sum_JRi
382
411
 
383
412
  elif order == "ij33":
384
413
  Jmat = np.zeros((nR, n, n, 3, 3), dtype=float)
385
- Jmat[iR] = self.get_full_Jtensor_for_one_R_ij33(R, iso_only=iso_only)
414
+ for iR, R in enumerate(self.Rlist):
415
+ Jmat[iR] = self.get_full_Jtensor_for_one_R_ij33(
416
+ R, Jiso=Jiso, Jani=Jani, DMI=DMI
417
+ )
386
418
  if asr:
387
419
  iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
388
420
  assert np.linalg.norm(self.Rlist[iR0]) == 0
@@ -1,5 +1,6 @@
1
- import numpy as np
2
1
  import os
2
+
3
+ import numpy as np
3
4
  from ase.units import J
4
5
 
5
6
 
@@ -51,10 +52,15 @@ def write_vampire_unitcell_file(cls, fname):
51
52
  R, ispin, jspin = key
52
53
  Jtensor = cls.get_J_tensor(ispin, jspin, R)
53
54
  counter += 1 # starts at 0
54
- myfile.write(f"{counter} {ispin} {jspin} {R[0]} {R[1]} {R[2]} ")
55
+ myfile.write(
56
+ f"{counter:5d} {ispin:3d} {jspin:3d} {R[0]:3d} {R[1]:3d} {R[2]:3d} "
57
+ )
55
58
  for i in range(3):
56
59
  for j in range(3):
57
- myfile.write(f"{Jtensor[i,j]*2.0/J} ")
60
+ val = np.real(Jtensor[i, j] * 2.0 / J)
61
+ if np.abs(val) < 1e-30:
62
+ val = 0.0
63
+ myfile.write(f"{val:<012.5e} ")
58
64
  myfile.write("\n")
59
65
 
60
66
 
TB2J/magnon/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- from .io_exchange2 import ExchangeIO, plot_tb2j_magnon_bands
1
+ # from .io_exchange2 import ExchangeIO, plot_tb2j_magnon_bands
2
2
 
3
- __all__ = ["ExchangeIO", "plot_tb2j_magnon_bands"]
3
+ # __all__ = ["ExchangeIO", "plot_tb2j_magnon_bands"]