TB2J 0.9.9.4__py3-none-any.whl → 0.9.9.7__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 (38) hide show
  1. TB2J/Jdownfolder.py +3 -2
  2. TB2J/MAEGreen.py +22 -17
  3. TB2J/exchange.py +1 -1
  4. TB2J/exchange_params.py +1 -2
  5. TB2J/interfaces/abacus/abacus_wrapper.py +0 -3
  6. TB2J/interfaces/abacus/gen_exchange_abacus.py +3 -0
  7. TB2J/interfaces/abacus/orbital_api.py +1 -0
  8. TB2J/interfaces/siesta_interface.py +15 -7
  9. TB2J/io_exchange/__init__.py +2 -0
  10. TB2J/io_exchange/io_exchange.py +40 -12
  11. TB2J/magnon/__init__.py +3 -0
  12. TB2J/magnon/io_exchange2.py +695 -0
  13. TB2J/magnon/magnon3.py +334 -0
  14. TB2J/magnon/magnon_io.py +48 -0
  15. TB2J/magnon/magnon_math.py +53 -0
  16. TB2J/magnon/plot.py +58 -0
  17. TB2J/magnon/structure.py +348 -0
  18. TB2J/mathutils/__init__.py +2 -0
  19. TB2J/mathutils/fibonacci_sphere.py +1 -1
  20. TB2J/mathutils/rotate_spin.py +0 -3
  21. TB2J/symmetrize_J.py +1 -1
  22. tb2j-0.9.9.7.data/scripts/TB2J_magnon2.py +78 -0
  23. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/abacus2J.py +0 -1
  24. {tb2j-0.9.9.4.dist-info → tb2j-0.9.9.7.dist-info}/METADATA +2 -3
  25. {tb2j-0.9.9.4.dist-info → tb2j-0.9.9.7.dist-info}/RECORD +38 -30
  26. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_downfold.py +0 -0
  27. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_eigen.py +0 -0
  28. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_magnon.py +0 -0
  29. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_magnon_dos.py +0 -0
  30. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_merge.py +0 -0
  31. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_rotate.py +0 -0
  32. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/TB2J_rotateDM.py +0 -0
  33. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/siesta2J.py +0 -0
  34. {tb2j-0.9.9.4.data → tb2j-0.9.9.7.data}/scripts/wann2J.py +0 -0
  35. {tb2j-0.9.9.4.dist-info → tb2j-0.9.9.7.dist-info}/WHEEL +0 -0
  36. {tb2j-0.9.9.4.dist-info → tb2j-0.9.9.7.dist-info}/entry_points.txt +0 -0
  37. {tb2j-0.9.9.4.dist-info → tb2j-0.9.9.7.dist-info}/licenses/LICENSE +0 -0
  38. {tb2j-0.9.9.4.dist-info → tb2j-0.9.9.7.dist-info}/top_level.txt +0 -0
TB2J/Jdownfolder.py CHANGED
@@ -136,7 +136,7 @@ class JDownfolder_pickle:
136
136
  outpath,
137
137
  qmesh=[7, 7, 7],
138
138
  iso_only=False,
139
- method="pwf",
139
+ method="lowdin",
140
140
  **kwargs,
141
141
  ):
142
142
  self.exc = SpinIO.load_pickle(path=inpath, fname="TB2J.pickle")
@@ -146,6 +146,7 @@ class JDownfolder_pickle:
146
146
  self.ligands = ligands
147
147
  self.outpath = outpath
148
148
  self.method = method
149
+ print("Using method:", self.method)
149
150
 
150
151
  # read atomic structure
151
152
  self.atoms = self.exc.atoms
@@ -176,7 +177,7 @@ class JDownfolder_pickle:
176
177
 
177
178
  def _downfold(self, **kwargs):
178
179
  JR2 = self.exc.get_full_Jtensor_for_Rlist(asr=True)
179
- if self.method == "lowdin":
180
+ if self.method.lower() == "lowdin":
180
181
  d = JDownfolder(
181
182
  JR2,
182
183
  self.exc.Rlist,
TB2J/MAEGreen.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import gc
2
2
  from pathlib import Path
3
3
 
4
- import matplotlib.pyplot as plt
5
4
  import numpy as np
6
5
  import tqdm
7
6
  from HamiltonIO.abacus.abacus_wrapper import AbacusSplitSOCParser
@@ -32,7 +31,9 @@ class MAEGreen(ExchangeNCL):
32
31
  """
33
32
  super().__init__(**kwargs)
34
33
  self.natoms = len(self.atoms)
35
- if angles is None or angles == "axis":
34
+ if angles is None or angles == "xyz":
35
+ self.set_angles_xyz()
36
+ elif angles == "axis":
36
37
  self.set_angles_axis()
37
38
  elif angles == "scan":
38
39
  self.set_angles_scan()
@@ -51,6 +52,11 @@ class MAEGreen(ExchangeNCL):
51
52
  self.es_atom = np.zeros((nangles, self.natoms), dtype=complex)
52
53
  self.es_atom_orb = DefaultDict(lambda: 0)
53
54
 
55
+ def set_angles_xyz(self):
56
+ """theta and phi are defined as the x, y, z, xy, yz, xz, xyz, x-yz, -xyz, -x-yz axis."""
57
+ self.thetas = [np.pi / 2, np.pi / 2, 0.0]
58
+ self.phis = [np.pi / 2, 0, 0.0]
59
+
54
60
  def set_angles_axis(self):
55
61
  """theta and phi are defined as the x, y, z, xy, yz, xz, xyz, x-yz, -xyz, -x-yz axis."""
56
62
  self.thetas = [0, np.pi / 2, np.pi / 2, np.pi / 2, np.pi, 0, np.pi / 2, 0, 0, 0]
@@ -75,7 +81,6 @@ class MAEGreen(ExchangeNCL):
75
81
  self.thetas = thetas
76
82
  self.phis = phis
77
83
  self.angle_pairs = list(zip(thetas, phis))
78
- # remove duplicates of angles using sets.
79
84
  self.angle_pairs = list(set(self.angle_pairs))
80
85
  self.thetas, self.phis = zip(*self.angle_pairs)
81
86
 
@@ -248,11 +253,11 @@ class MAEGreen(ExchangeNCL):
248
253
  Path(output_path).mkdir(exist_ok=True)
249
254
  fname = f"{output_path}/MAE.dat"
250
255
  fname_orb = f"{output_path}/MAE_orb.dat"
251
- fname_tensor = f"{output_path}/MAE_tensor.dat"
252
- if figure3d is not None:
253
- fname_fig3d = f"{output_path}/{figure3d}"
254
- if figure_contourf is not None:
255
- fname_figcontourf = f"{output_path}/{figure_contourf}"
256
+ # fname_tensor = f"{output_path}/MAE_tensor.dat"
257
+ # if figure3d is not None:
258
+ # fname_fig3d = f"{output_path}/{figure3d}"
259
+ # if figure_contourf is not None:
260
+ # fname_figcontourf = f"{output_path}/{figure_contourf}"
256
261
 
257
262
  # ouput with eigenvalues.
258
263
  if with_eigen:
@@ -277,18 +282,18 @@ class MAEGreen(ExchangeNCL):
277
282
  f.write(f"{ea*1e3:.8f} ")
278
283
  f.write("\n")
279
284
 
280
- self.ani = self.fit_anisotropy_tensor()
281
- with open(fname_tensor, "w") as f:
282
- f.write("# Anisotropy tensor in meV\n")
283
- f.write(f"{self.ani.tensor_strings(include_isotropic=False)}\n")
285
+ # self.ani = self.fit_anisotropy_tensor()
286
+ # with open(fname_tensor, "w") as f:
287
+ # f.write("# Anisotropy tensor in meV\n")
288
+ # f.write(f"{self.ani.tensor_strings(include_isotropic=False)}\n")
284
289
 
285
- if figure3d is not None:
286
- self.ani.plot_3d(figname=fname_fig3d, show=False)
290
+ # if figure3d is not None:
291
+ # self.ani.plot_3d(figname=fname_fig3d, show=False)
287
292
 
288
- if figure_contourf is not None:
289
- self.ani.plot_contourf(figname=fname_figcontourf, show=False)
293
+ # if figure_contourf is not None:
294
+ # self.ani.plot_contourf(figname=fname_figcontourf, show=False)
290
295
 
291
- plt.close()
296
+ # plt.close()
292
297
  gc.collect()
293
298
 
294
299
  with open(fname_orb, "w") as f:
TB2J/exchange.py CHANGED
@@ -157,7 +157,6 @@ class Exchange(ExchangeParams):
157
157
  or f"{sym}{tag}" in self.magnetic_elements
158
158
  ):
159
159
  self.ind_mag_atoms.append(atom_idx)
160
- print(f"Magnetic atoms: {self.ind_mag_atoms}")
161
160
 
162
161
  def _validate_orbital_assignments(self):
163
162
  """Validate that magnetic atoms have proper orbital assignments."""
@@ -333,6 +332,7 @@ class ExchangeNCL(Exchange):
333
332
 
334
333
  def get_H_atom(self, iatom):
335
334
  orbs = self.iorb(iatom)
335
+ print(orbs)
336
336
  # return self.HR0[self.orb_slice[iatom], self.orb_slice[iatom]]
337
337
  return self.HR0[np.ix_(orbs, orbs)]
338
338
 
TB2J/exchange_params.py CHANGED
@@ -177,8 +177,7 @@ def add_exchange_args_to_parser(parser: argparse.ArgumentParser):
177
177
  )
178
178
 
179
179
  parser.add_argument(
180
- "--np",
181
- "--nproc",
180
+ "-np",
182
181
  help="number of cpu cores to use in parallel, default: 1",
183
182
  default=1,
184
183
  type=int,
@@ -160,8 +160,6 @@ class AbacusParser:
160
160
  self.read_atoms()
161
161
  self.efermi = self.read_efermi()
162
162
  self.nel = self.read_nel()
163
- print(f"efermi: {self.efermi}")
164
- print(f"nel: {self.nel}")
165
163
  self.read_basis()
166
164
 
167
165
  def read_spin(self):
@@ -192,7 +190,6 @@ class AbacusParser:
192
190
  def read_basis(self):
193
191
  fname = str(Path(self.outpath) / "Orbital")
194
192
  self.basis = parse_abacus_orbital(fname)
195
- print(self.basis)
196
193
  return self.basis
197
194
 
198
195
  def read_HSR_collinear(self, binary=None):
@@ -30,6 +30,7 @@ def gen_exchange_abacus(
30
30
  nproc=1,
31
31
  output_path="TB2J_results",
32
32
  orb_decomposition=False,
33
+ index_magnetic_atoms=None,
33
34
  description=None,
34
35
  ):
35
36
  outpath = Path(path) / f"OUT.{suffix}"
@@ -64,6 +65,7 @@ data directory: {outpath}
64
65
  use_cache=use_cache,
65
66
  output_path=output_path,
66
67
  orb_decomposition=orb_decomposition,
68
+ index_magnetic_atoms=index_magnetic_atoms,
67
69
  description=description,
68
70
  )
69
71
  exchange.run(path=output_path)
@@ -90,6 +92,7 @@ data directory: {outpath}
90
92
  nproc=nproc,
91
93
  use_cache=use_cache,
92
94
  orb_decomposition=orb_decomposition,
95
+ index_magnetic_atoms=index_magnetic_atoms,
93
96
  description=description,
94
97
  )
95
98
  exchange.run()
@@ -45,6 +45,7 @@ def parse_abacus_orbital(fname):
45
45
  z = int(z)
46
46
  orbs.append(AbacusOrbital(iatom, sym, ispin, element, n, l, m, z))
47
47
  line = myfile.readline()
48
+ print(orbs)
48
49
  return orbs
49
50
 
50
51
 
@@ -4,6 +4,7 @@ import numpy as np
4
4
 
5
5
  from TB2J.exchange import ExchangeNCL
6
6
  from TB2J.exchangeCL2 import ExchangeCL2
7
+ from TB2J.io_merge import merge
7
8
  from TB2J.MAEGreen import MAEGreen
8
9
 
9
10
  try:
@@ -156,7 +157,7 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
156
157
  atoms=model.atoms,
157
158
  basis=basis,
158
159
  efermi=None,
159
- angles="miller",
160
+ angles="axis",
160
161
  # magnetic_elements=magnetic_elements,
161
162
  # include_orbs=include_orbs,
162
163
  **exargs,
@@ -165,13 +166,12 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
165
166
  # phis = [0, 0, 0, 0]
166
167
  # MAE.set_angles(thetas=thetas, phis=phis)
167
168
  MAE.run(output_path=f"{output_path}_anisotropy", with_eigen=False)
168
- print(
169
- f"MAE calculation finished. The results are in {output_path} directory."
170
- )
169
+ # print(
170
+ # f"MAE calculation finished. The results are in {output_path} directory."
171
+ # )
171
172
 
172
173
  angle = {"x": (np.pi / 2, 0), "y": (np.pi / 2, np.pi / 2), "z": (0, 0)}
173
174
  for key, val in angle.items():
174
- # model = parser.get_model()
175
175
  theta, phi = val
176
176
  model.set_so_strength(1.0)
177
177
  model.set_Hsoc_rotation_angle([theta, phi])
@@ -182,8 +182,6 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
182
182
  atoms=model.atoms,
183
183
  basis=basis,
184
184
  efermi=None, # set to None, compute from efermi.
185
- # magnetic_elements=magnetic_elements,
186
- # include_orbs=include_orbs,
187
185
  **exargs,
188
186
  )
189
187
  exchange.run(path=output_path_full)
@@ -191,3 +189,13 @@ Warning: The DMI component parallel to the spin orientation, the Jani which has
191
189
  print(
192
190
  f"All calculation finished. The results are in {output_path_full} directory."
193
191
  )
192
+
193
+ merge(
194
+ "TB2J_results_x",
195
+ "TB2J_results_y",
196
+ "TB2J_results_z",
197
+ main_path=None,
198
+ save=True,
199
+ write_path="TB2J_results",
200
+ )
201
+ print("Final TB2J_results written to TB2J_results directory.")
@@ -1 +1,3 @@
1
1
  from .io_exchange import SpinIO
2
+
3
+ __all__ = ["SpinIO"]
@@ -335,7 +335,7 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
335
335
  )
336
336
  return Jtensor
337
337
 
338
- def get_full_Jtensor_for_one_R(self, R, iso_only=False):
338
+ def get_full_Jtensor_for_one_R_i3j3(self, R, iso_only=False):
339
339
  """
340
340
  Return the full exchange tensor of all i and j for cell R.
341
341
  param R (tuple of integers): cell index R
@@ -351,18 +351,46 @@ Generation time: {now.strftime("%y/%m/%d %H:%M:%S")}
351
351
  )
352
352
  return Jmat
353
353
 
354
- def get_full_Jtensor_for_Rlist(self, asr=False, iso_only=True):
355
- n3 = self.nspin * 3
354
+ def get_full_Jtensor_for_one_R_ij33(self, R, iso_only=False):
355
+ """
356
+ Return the full exchange tensor of all i and j for cell R.
357
+ param R (tuple of integers): cell index R
358
+ returns:
359
+ Jmat: (nspin,nspin,3,3) matrix.
360
+ """
361
+ n = self.nspin
362
+ Jmat = np.zeros((n, n, 3, 3), dtype=float)
363
+ for i in range(self.nspin):
364
+ for j in range(self.nspin):
365
+ Jmat[i, j, :, :] = self.get_J_tensor(i, j, R, iso_only=iso_only)
366
+ return Jmat
367
+
368
+ def get_full_Jtensor_for_Rlist(self, asr=False, iso_only=True, order="i3j3"):
369
+ n = self.nspin
370
+ n3 = n * 3
356
371
  nR = len(self.Rlist)
357
- Jmat = np.zeros((nR, n3, n3), dtype=float)
358
- for iR, R in enumerate(self.Rlist):
359
- Jmat[iR] = self.get_full_Jtensor_for_one_R(R, iso_only=iso_only)
360
- if asr:
361
- iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
362
- assert np.linalg.norm(self.Rlist[iR0]) == 0
363
- for i in range(n3):
364
- sum_JRi = np.sum(np.sum(Jmat, axis=0)[i])
365
- Jmat[iR0][i, i] -= sum_JRi
372
+ if order == "i3j3":
373
+ Jmat = np.zeros((nR, n3, n3), dtype=float)
374
+ for iR, R in enumerate(self.Rlist):
375
+ Jmat[iR] = self.get_full_Jtensor_for_one_R_i3j3(R, iso_only=iso_only)
376
+ if asr:
377
+ iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
378
+ assert np.linalg.norm(self.Rlist[iR0]) == 0
379
+ for i in range(n3):
380
+ sum_JRi = np.sum(np.sum(Jmat, axis=0)[i])
381
+ Jmat[iR0][i, i] -= sum_JRi
382
+
383
+ elif order == "ij33":
384
+ 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)
386
+ if asr:
387
+ iR0 = np.argmin(np.linalg.norm(self.Rlist, axis=1))
388
+ assert np.linalg.norm(self.Rlist[iR0]) == 0
389
+ for i in range(n):
390
+ sum_JRi = np.sum(np.sum(Jmat, axis=0)[i])
391
+ Jmat[iR0][i, i] -= sum_JRi
392
+ else:
393
+ raise ValueError("order must be either 'i3j3' or 'ij33'.")
366
394
  return Jmat
367
395
 
368
396
  def write_pickle(self, path="TB2J_results", fname="TB2J.pickle"):
@@ -0,0 +1,3 @@
1
+ from .io_exchange2 import ExchangeIO, plot_tb2j_magnon_bands
2
+
3
+ __all__ = ["ExchangeIO", "plot_tb2j_magnon_bands"]