TB2J 0.9.10.1__py3-none-any.whl → 0.9.12.17__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.

Potentially problematic release.


This version of TB2J might be problematic. Click here for more details.

Files changed (49) hide show
  1. TB2J/.gitignore +5 -0
  2. TB2J/Jdownfolder.py +43 -19
  3. TB2J/MAEGreen.py +78 -60
  4. TB2J/__init__.py +3 -1
  5. TB2J/anisotropy.py +2 -2
  6. TB2J/basis.py +0 -3
  7. TB2J/contour.py +3 -2
  8. TB2J/exchange.py +335 -48
  9. TB2J/exchangeCL2.py +289 -51
  10. TB2J/exchange_params.py +25 -1
  11. TB2J/gpaw_wrapper.py +0 -3
  12. TB2J/green.py +58 -33
  13. TB2J/interfaces/wannier90_interface.py +4 -4
  14. TB2J/io_exchange/io_espins.py +276 -0
  15. TB2J/io_exchange/io_exchange.py +53 -12
  16. TB2J/io_exchange/io_txt.py +9 -8
  17. TB2J/io_exchange/io_uppasd.py +0 -1
  18. TB2J/io_exchange/io_vampire.py +3 -1
  19. TB2J/magnon/magnon3.py +76 -28
  20. TB2J/magnon/plot_magnon_dos_cli.py +115 -3
  21. TB2J/myTB.py +11 -11
  22. TB2J/pauli.py +32 -2
  23. TB2J/plot.py +8 -7
  24. TB2J/rotate_atoms.py +10 -7
  25. TB2J/scripts/TB2J_downfold.py +97 -0
  26. TB2J/scripts/TB2J_eigen.py +49 -0
  27. TB2J/scripts/TB2J_magnon.py +117 -0
  28. TB2J/scripts/TB2J_magnon2.py +78 -0
  29. TB2J/scripts/TB2J_magnon_dos.py +5 -0
  30. TB2J/scripts/TB2J_merge.py +49 -0
  31. TB2J/scripts/TB2J_plot_magnon_bands.py +22 -0
  32. TB2J/scripts/TB2J_rotate.py +29 -0
  33. TB2J/scripts/TB2J_rotateDM.py +21 -0
  34. TB2J/scripts/__init__.py +0 -0
  35. TB2J/scripts/abacus2J.py +61 -0
  36. TB2J/scripts/siesta2J.py +78 -0
  37. TB2J/scripts/wann2J.py +101 -0
  38. TB2J/spinham/hamiltonian.py +0 -1
  39. TB2J/symmetrize_J.py +2 -2
  40. TB2J/tensor_rotate.py +1 -2
  41. TB2J/versioninfo.py +3 -0
  42. TB2J/wannier/w90_tb_parser.py +0 -2
  43. {tb2j-0.9.10.1.dist-info → tb2j-0.9.12.17.dist-info}/METADATA +7 -7
  44. {tb2j-0.9.10.1.dist-info → tb2j-0.9.12.17.dist-info}/RECORD +48 -33
  45. tb2j-0.9.12.17.dist-info/entry_points.txt +15 -0
  46. tb2j-0.9.10.1.dist-info/entry_points.txt +0 -16
  47. {tb2j-0.9.10.1.dist-info → tb2j-0.9.12.17.dist-info}/WHEEL +0 -0
  48. {tb2j-0.9.10.1.dist-info → tb2j-0.9.12.17.dist-info}/licenses/LICENSE +0 -0
  49. {tb2j-0.9.10.1.dist-info → tb2j-0.9.12.17.dist-info}/top_level.txt +0 -0
TB2J/magnon/magnon3.py CHANGED
@@ -31,6 +31,7 @@ class MagnonParameters:
31
31
  Q: Optional[List[float]] = None
32
32
  uz_file: Optional[str] = None
33
33
  n: Optional[List[float]] = None
34
+ spin_conf_file: Optional[str] = None
34
35
  show: bool = False
35
36
 
36
37
  @classmethod
@@ -57,6 +58,8 @@ class MagnonParameters:
57
58
  # Convert path to absolute path if uz_file is relative to it
58
59
  if self.uz_file and not Path(self.uz_file).is_absolute():
59
60
  self.uz_file = str(Path(self.path) / self.uz_file)
61
+ if self.spin_conf_file and not Path(self.spin_conf_file).is_absolute():
62
+ self.spin_conf_file = str(Path(self.path) / self.spin_conf_file)
60
63
 
61
64
 
62
65
  @dataclass
@@ -76,7 +79,7 @@ class Magnon:
76
79
  _n: np.ndarray
77
80
  pbc: tuple = (True, True, True)
78
81
 
79
- def set_reference(self, Q, uz, n):
82
+ def set_reference(self, Q, uz, n, magmoms=None):
80
83
  """
81
84
  Set reference propagation vector and quantization axis
82
85
 
@@ -92,6 +95,8 @@ class Magnon:
92
95
  self.set_propagation_vector(Q)
93
96
  self._uz = np.array(uz, dtype=float)
94
97
  self._n = np.array(n, dtype=float)
98
+ if magmoms is not None:
99
+ self.magmom = np.array(magmoms, dtype=float)
95
100
 
96
101
  def set_propagation_vector(self, Q):
97
102
  """Set propagation vector"""
@@ -653,26 +658,40 @@ def plot_magnon_bands_from_TB2J(
653
658
  )
654
659
 
655
660
  # Set reference vectors if provided
656
- if any(x is not None for x in [params.Q, params.uz_file, params.n]):
657
- Q = [0, 0, 0] if params.Q is None else params.Q
658
- n = [0, 0, 1] if params.n is None else params.n
659
-
660
- # Handle quantization axes
661
- if params.uz_file is not None:
662
- uz = np.loadtxt(params.uz_file)
663
- if uz.shape[1] != 3:
664
- raise ValueError(
665
- f"Quantization axes file should contain a natom×3 array. Got shape {uz.shape}"
666
- )
667
- if uz.shape[0] != magnon.nspin:
668
- raise ValueError(
669
- f"Number of spins in uz file ({uz.shape[0]}) does not match the system ({magnon.nspin})"
670
- )
671
- else:
672
- # Default: [0, 0, 1] for all spins
673
- uz = np.array([[0.0, 0.0, 1.0] for _ in range(magnon.nspin)])
661
+ Q = [0, 0, 0] if params.Q is None else params.Q
662
+ n = [0, 0, 1] if params.n is None else params.n
663
+
664
+ # Handle quantization axes
665
+ if params.uz_file is not None:
666
+ uz = np.loadtxt(params.uz_file)
667
+ if uz.shape[1] != 3:
668
+ raise ValueError(
669
+ f"Quantization axes file should contain a natom×3 array. Got shape {uz.shape}"
670
+ )
671
+ if uz.shape[0] != magnon.nspin:
672
+ raise ValueError(
673
+ f"Number of spins in uz file ({uz.shape[0]}) does not match the system ({magnon.nspin})"
674
+ )
675
+ else:
676
+ # Default: [0, 0, 1] for all spins
677
+ # uz = np.array([[0.0, 0.0, 1.0] for _ in range(magnon.nspin)])
678
+ uz = np.array([[0, 0, 1]], dtype=float)
679
+
680
+ print(params)
681
+ if params.spin_conf_file is not None:
682
+ magmoms = np.loadtxt(params.spin_conf_file)
683
+ if magmoms.shape[1] != 3:
684
+ raise ValueError(
685
+ f"Spin configuration file should contain a nspin×3 array. Got shape {magmoms.shape}"
686
+ )
687
+ if magmoms.shape[0] != magnon.nspin:
688
+ raise ValueError(
689
+ f"Number of spins in spin configuration file ({magmoms.shape[0]}) does not match the system ({magnon.nspin})"
690
+ )
691
+ else:
692
+ magmoms = None
674
693
 
675
- magnon.set_reference(Q, uz, n)
694
+ magnon.set_reference(Q, uz, n, magmoms)
676
695
 
677
696
  # Get band structure data
678
697
  print(f"\nCalculating bands along path {params.kpath}...")
@@ -714,10 +733,25 @@ def plot_magnon_bands_from_TB2J(
714
733
  return magnon
715
734
 
716
735
 
717
- def main():
718
- """Command line interface for plotting magnon bands from TB2J results."""
736
+ def plot_magnon_bands_cli():
719
737
  import argparse
720
-
738
+ import warnings
739
+
740
+ warnings.warn(
741
+ """
742
+ # !!!!!!!!!!!!!!!!!! WARNING: =============================
743
+ #
744
+ # This functionality is under development and should not be used in production.
745
+ # It is provided for testing and development purposes only.
746
+ # Please use with caution and report any issues to the developers.
747
+ #
748
+ # This warning will be removed in future releases.
749
+ # =====================================
750
+
751
+ """,
752
+ UserWarning,
753
+ stacklevel=2,
754
+ )
721
755
  parser = argparse.ArgumentParser(
722
756
  description="Plot magnon band structure from TB2J results"
723
757
  )
@@ -737,27 +771,32 @@ def main():
737
771
 
738
772
  # Command line arguments (used if no config file is provided)
739
773
  parser.add_argument(
774
+ "-p",
740
775
  "--path",
741
776
  default="TB2J_results",
742
777
  help="Path to TB2J results directory (default: TB2J_results)",
743
778
  )
744
779
  parser.add_argument(
780
+ "-k",
745
781
  "--kpath",
746
782
  default=None,
747
783
  help="k-path specification (default: auto-detected from type of cell)",
748
784
  )
749
785
  parser.add_argument(
786
+ "-n",
750
787
  "--npoints",
751
788
  type=int,
752
789
  default=300,
753
790
  help="Number of k-points along the path (default: 300)",
754
791
  )
755
792
  parser.add_argument(
793
+ "-o",
756
794
  "--output",
757
795
  default="magnon_bands.png",
758
796
  help="Output file name (default: magnon_bands.png)",
759
797
  )
760
798
  parser.add_argument(
799
+ "-j",
761
800
  "--Jiso",
762
801
  action="store_true",
763
802
  default=True,
@@ -770,18 +809,21 @@ def main():
770
809
  help="Exclude isotropic exchange interactions",
771
810
  )
772
811
  parser.add_argument(
812
+ "-a",
773
813
  "--Jani",
774
814
  action="store_true",
775
815
  default=False,
776
816
  help="Include anisotropic exchange interactions (default: False)",
777
817
  )
778
818
  parser.add_argument(
819
+ "-d",
779
820
  "--DMI",
780
821
  action="store_true",
781
822
  default=False,
782
823
  help="Include Dzyaloshinskii-Moriya interactions (default: False)",
783
824
  )
784
825
  parser.add_argument(
826
+ "-q",
785
827
  "--Q",
786
828
  nargs=3,
787
829
  type=float,
@@ -789,11 +831,19 @@ def main():
789
831
  help="Propagation vector [Qx, Qy, Qz] (default: [0, 0, 0])",
790
832
  )
791
833
  parser.add_argument(
834
+ "-u",
792
835
  "--uz-file",
793
836
  type=str,
794
- help="Path to file containing quantization axes for each spin (natom×3 array)",
837
+ help="Path to file containing quantization axes for each spin (nspin×3 array)",
838
+ )
839
+ parser.add_argument(
840
+ "-c",
841
+ "--spin-conf-file",
842
+ type=str,
843
+ help="Path to file containing magnetic moments for each spin (nspin×3 array)",
795
844
  )
796
845
  parser.add_argument(
846
+ "-v",
797
847
  "--n",
798
848
  nargs=3,
799
849
  type=float,
@@ -802,6 +852,7 @@ def main():
802
852
  )
803
853
 
804
854
  parser.add_argument(
855
+ "-s",
805
856
  "--show",
806
857
  action="store_true",
807
858
  default=False,
@@ -833,6 +884,7 @@ def main():
833
884
  DMI=args.DMI,
834
885
  Q=args.Q if args.Q is not None else None,
835
886
  uz_file=args.uz_file,
887
+ spin_conf_file=args.spin_conf_file,
836
888
  n=args.n if args.n is not None else None,
837
889
  show=args.show,
838
890
  )
@@ -840,10 +892,6 @@ def main():
840
892
  plot_magnon_bands_from_TB2J(params)
841
893
 
842
894
 
843
- if __name__ == "__main__":
844
- main()
845
-
846
-
847
895
  class MagnonASEWrapper:
848
896
  def __init__(self, magnon: Magnon):
849
897
  self.magnon = magnon
@@ -4,6 +4,8 @@
4
4
  import argparse
5
5
  from pathlib import Path
6
6
 
7
+ import numpy as np
8
+
7
9
  from TB2J.magnon.magnon3 import Magnon
8
10
  from TB2J.magnon.magnon_dos import plot_magnon_dos
9
11
 
@@ -13,6 +15,7 @@ def main():
13
15
  description="Calculate and plot magnon DOS from TB2J results"
14
16
  )
15
17
  parser.add_argument(
18
+ "-p",
16
19
  "--path",
17
20
  default="TB2J_results",
18
21
  help="Path to TB2J results directory (default: TB2J_results)",
@@ -51,26 +54,135 @@ def main():
51
54
  help="Number of energy points (default: 401)",
52
55
  )
53
56
  parser.add_argument(
57
+ "-o",
54
58
  "--output",
55
59
  default="magnon_dos.png",
56
60
  help="Output filename for plot (default: magnon_dos.png)",
57
61
  )
58
62
  parser.add_argument(
59
- "-show",
63
+ "-s",
64
+ "--show",
60
65
  action="store_true",
61
66
  dest="show",
62
67
  help="Show plot window",
63
68
  )
64
69
 
70
+ # Exchange interaction options (same as in magnon bands)
71
+ parser.add_argument(
72
+ "-j",
73
+ "--Jiso",
74
+ action="store_true",
75
+ default=True,
76
+ help="Include isotropic exchange interactions (default: True)",
77
+ )
78
+ parser.add_argument(
79
+ "--no-Jiso",
80
+ action="store_false",
81
+ dest="Jiso",
82
+ help="Exclude isotropic exchange interactions",
83
+ )
84
+ parser.add_argument(
85
+ "-a",
86
+ "--Jani",
87
+ action="store_true",
88
+ default=False,
89
+ help="Include anisotropic exchange interactions (default: False)",
90
+ )
91
+ parser.add_argument(
92
+ "-d",
93
+ "--DMI",
94
+ action="store_true",
95
+ default=False,
96
+ help="Include Dzyaloshinskii-Moriya interactions (default: False)",
97
+ )
98
+
99
+ # Reference vector options (same as in magnon bands)
100
+ parser.add_argument(
101
+ "-q",
102
+ "--Q",
103
+ nargs=3,
104
+ type=float,
105
+ metavar=("Qx", "Qy", "Qz"),
106
+ help="Propagation vector [Qx, Qy, Qz] (default: [0, 0, 0])",
107
+ )
108
+ parser.add_argument(
109
+ "-u",
110
+ "--uz-file",
111
+ type=str,
112
+ help="Path to file containing quantization axes for each spin (nspin×3 array)",
113
+ )
114
+ parser.add_argument(
115
+ "-c",
116
+ "--spin-conf-file",
117
+ type=str,
118
+ help="Path to file containing magnetic moments for each spin (nspin×3 array)",
119
+ )
120
+ parser.add_argument(
121
+ "-v",
122
+ "--n",
123
+ nargs=3,
124
+ type=float,
125
+ metavar=("nx", "ny", "nz"),
126
+ help="Normal vector for rotation [nx, ny, nz] (default: [0, 0, 1])",
127
+ )
128
+
65
129
  args = parser.parse_args()
66
130
 
67
131
  # Check if TB2J results exist
68
132
  if not Path(args.path).exists():
69
133
  raise FileNotFoundError(f"TB2J results not found at {args.path}")
70
134
 
71
- # Load magnon calculator
135
+ # Load magnon calculator with exchange interaction options
72
136
  print(f"Loading exchange parameters from {args.path}...")
73
- magnon = Magnon.from_TB2J_results(path=args.path)
137
+ magnon = Magnon.from_TB2J_results(
138
+ path=args.path, Jiso=args.Jiso, Jani=args.Jani, DMI=args.DMI
139
+ )
140
+
141
+ # Set reference vectors if provided (same logic as in magnon bands)
142
+ Q = [0, 0, 0] if args.Q is None else args.Q
143
+ n = [0, 0, 1] if args.n is None else args.n
144
+
145
+ # Handle quantization axes
146
+ if args.uz_file is not None:
147
+ # Make path relative to TB2J results if not absolute
148
+ uz_file = args.uz_file
149
+ if not Path(uz_file).is_absolute():
150
+ uz_file = str(Path(args.path) / uz_file)
151
+
152
+ uz = np.loadtxt(uz_file)
153
+ if uz.shape[1] != 3:
154
+ raise ValueError(
155
+ f"Quantization axes file should contain a nspin×3 array. Got shape {uz.shape}"
156
+ )
157
+ if uz.shape[0] != magnon.nspin:
158
+ raise ValueError(
159
+ f"Number of spins in uz file ({uz.shape[0]}) does not match the system ({magnon.nspin})"
160
+ )
161
+ else:
162
+ # Default: [0, 0, 1] for all spins
163
+ uz = np.array([[0, 0, 1]], dtype=float)
164
+
165
+ # Handle spin configuration
166
+ if args.spin_conf_file is not None:
167
+ # Make path relative to TB2J results if not absolute
168
+ spin_conf_file = args.spin_conf_file
169
+ if not Path(spin_conf_file).is_absolute():
170
+ spin_conf_file = str(Path(args.path) / spin_conf_file)
171
+
172
+ magmoms = np.loadtxt(spin_conf_file)
173
+ if magmoms.shape[1] != 3:
174
+ raise ValueError(
175
+ f"Spin configuration file should contain a nspin×3 array. Got shape {magmoms.shape}"
176
+ )
177
+ if magmoms.shape[0] != magnon.nspin:
178
+ raise ValueError(
179
+ f"Number of spins in spin configuration file ({magmoms.shape[0]}) does not match the system ({magnon.nspin})"
180
+ )
181
+ else:
182
+ magmoms = None
183
+
184
+ # Set reference configuration
185
+ magnon.set_reference(Q, uz, n, magmoms)
74
186
 
75
187
  # Convert window from meV to eV if provided
76
188
  window = None
TB2J/myTB.py CHANGED
@@ -1,15 +1,17 @@
1
- import os
2
- import numpy as np
3
1
  import copy
4
- from scipy.linalg import eigh
5
- from scipy.sparse import csr_matrix
6
- from scipy.io import netcdf_file
2
+ import os
7
3
  from collections import defaultdict
8
4
 
5
+ import numpy as np
6
+
9
7
  # from tbmodels import Model
10
8
  from ase.atoms import Atoms
9
+ from scipy.io import netcdf_file
10
+ from scipy.linalg import eigh
11
+ from scipy.sparse import csr_matrix
12
+
11
13
  from TB2J.utils import auto_assign_basis_name
12
- from TB2J.wannier import parse_ham, parse_xyz, parse_atoms, parse_tb
14
+ from TB2J.wannier import parse_atoms, parse_ham, parse_tb, parse_xyz
13
15
 
14
16
 
15
17
  class AbstractTB:
@@ -187,9 +189,7 @@ class MyTB(AbstractTB):
187
189
  if os.path.exists(tb_fname):
188
190
  xcart, nbasis, data, R_degens = parse_tb(fname=tb_fname)
189
191
  else:
190
- nbasis, data, R_degens = parse_ham(
191
- fname=os.path.join(path, prefix + "_hr.dat")
192
- )
192
+ nbasis, data, R_degens = parse_ham(fname=hr_fname)
193
193
  xcart, _, _ = parse_xyz(fname=os.path.join(path, prefix + "_centres.xyz"))
194
194
 
195
195
  if atoms is None:
@@ -237,7 +237,7 @@ class MyTB(AbstractTB):
237
237
  return m
238
238
 
239
239
  def gen_ham(self, k, convention=2):
240
- """
240
+ r"""
241
241
  generate hamiltonian matrix at k point.
242
242
  H_k( i, j)=\sum_R H_R(i, j)^phase.
243
243
  There are two conventions,
@@ -451,7 +451,7 @@ class MyTB(AbstractTB):
451
451
  nbasis = root.dimensions["nbasis"]
452
452
  nspin = root.dimensions["nspin"]
453
453
  ndim = root.dimensions["ndim"]
454
- natom = root.dimensions["natom"]
454
+ _natom = root.dimensions["natom"]
455
455
  Rlist = root.variables["R"][:]
456
456
  mdata_real = root.variables["data_real"][:]
457
457
  mdata_imag = root.variables["data_imag"][:]
TB2J/pauli.py CHANGED
@@ -59,7 +59,7 @@ def pauli_decomp2(M):
59
59
  )
60
60
 
61
61
 
62
- def pauli_sigma_norm(M):
62
+ def pauli_sigma_norm_old(M):
63
63
  MI, Mx, My, Mz = pauli_decomp2(M)
64
64
  return np.linalg.norm([Mx, My, Mz])
65
65
 
@@ -134,7 +134,7 @@ def pauli_block(M, idim):
134
134
  return tmp
135
135
 
136
136
 
137
- def pauli_block_all(M):
137
+ def pauli_block_all_old(M):
138
138
  MI = (M[::2, ::2] + M[1::2, 1::2]) / 2.0
139
139
  Mx = (M[::2, 1::2] + M[1::2, ::2]) / 2.0
140
140
  # Note that this is not element wise product with sigma_y but dot product
@@ -143,6 +143,28 @@ def pauli_block_all(M):
143
143
  return MI, Mx, My, Mz
144
144
 
145
145
 
146
+ def pauli_block_all(array):
147
+ A00 = array[..., ::2, ::2]
148
+ A01 = array[..., ::2, 1::2]
149
+ A10 = array[..., 1::2, ::2]
150
+ A11 = array[..., 1::2, 1::2]
151
+ n2 = array.shape[-1] // 2
152
+
153
+ out_dtype = np.result_type(array.dtype, np.complex64)
154
+ block = np.empty((*array.shape[:-2], 4, n2, n2), dtype=out_dtype)
155
+
156
+ np.add(A00, A11, out=block[..., 0, :, :])
157
+ block[..., 0, :, :] *= 0.5
158
+ np.add(A01, A10, out=block[..., 1, :, :])
159
+ block[..., 1, :, :] *= 0.5
160
+ np.subtract(A01, A10, out=block[..., 2, :, :])
161
+ block[..., 2, :, :] *= 0.5j
162
+ np.subtract(A00, A11, out=block[..., 3, :, :])
163
+ block[..., 3, :, :] *= 0.5
164
+
165
+ return block
166
+
167
+
146
168
  def gather_pauli_blocks(MI, Mx, My, Mz, coeffs=[1.0, 1.0, 1.0, 1.0]):
147
169
  """
148
170
  Gather the I, x, y, z component of a matrix.
@@ -212,3 +234,11 @@ def pauli_block_sigma_norm(M):
212
234
  evec = np.array((ex, ey, ez))
213
235
  evec = evec / np.linalg.norm(evec)
214
236
  return Mx * evec[0] + My * evec[1] + Mz * evec[2]
237
+
238
+
239
+ def pauli_sigma_norm(array):
240
+ block = pauli_block_all(array)[..., 1:, :, :]
241
+ E = np.trace(block, axis1=-2, axis2=-1)
242
+ E /= np.linalg.norm(E, axis=-1, keepdims=True)
243
+ np.multiply(block, E[..., None, None], out=block)
244
+ return block.sum(axis=-3)
TB2J/plot.py CHANGED
@@ -1,11 +1,12 @@
1
+ import argparse
2
+ import os
3
+
1
4
  import matplotlib.pyplot as plt
2
- from TB2J.spinham.spin_api import SpinModel
3
- from TB2J.io_exchange.io_exchange import SpinIO
4
5
  import numpy as np
5
- from TB2J import __version__
6
+
7
+ from TB2J.io_exchange.io_exchange import SpinIO
6
8
  from TB2J.spinham.qsolver import QSolverASEWrapper
7
- import argparse
8
- import os
9
+ from TB2J.spinham.spin_api import SpinModel
9
10
 
10
11
 
11
12
  def write_eigen(qmesh, gamma=True, path="./", output_fname="EigenJq.txt", **kwargs):
@@ -25,7 +26,7 @@ def plot_magnon_band(
25
26
  Jq=False,
26
27
  kpath_fname="exchange_kpth.txt",
27
28
  ax=None,
28
- **kwargs
29
+ **kwargs,
29
30
  ):
30
31
  m = SpinModel(fname=fname, sc_matrix=None)
31
32
  m.set_ham(**kwargs)
@@ -57,7 +58,7 @@ def plot_magnon_dos(
57
58
  txt_filename="magnon_dos.txt",
58
59
  Jq=False,
59
60
  ax=None,
60
- **kwargs
61
+ **kwargs,
61
62
  ):
62
63
  ffname = os.path.join(path, "exchange.xml")
63
64
  if not (os.path.exists(ffname) and os.path.isfile(ffname)):
TB2J/rotate_atoms.py CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
  import copy
3
- from ase.io import read, write
3
+
4
4
  import numpy as np
5
- from TB2J.tensor_rotate import Rxx, Rxy, Rxz, Ryx, Ryy, Ryz, Rzx, Rzy, Rzz
5
+ from ase.io import read, write
6
+ from TB2J.tensor_rotate import Rzx, Rzy, Rzz
6
7
 
7
8
 
8
9
  def rotate_atom_xyz(atoms, noncollinear=False):
@@ -15,14 +16,16 @@ def rotate_atom_xyz(atoms, noncollinear=False):
15
16
  will be generated.
16
17
  """
17
18
 
19
+ yield atoms
18
20
  rotation_axes = [(1, 0, 0), (0, 1, 0)]
19
21
  if noncollinear:
20
22
  rotation_axes += [(1, 1, 0), (1, 0, 1), (0, 1, 1)]
21
-
23
+
22
24
  for axis in rotation_axes:
23
25
  rotated_atoms = copy.deepcopy(atoms)
24
26
  rotated_atoms.rotate(90, axis, rotate_cell=True)
25
27
  yield rotated_atoms
28
+ yield atoms
26
29
 
27
30
 
28
31
  def rotate_atom_spin_one_rotation(atoms, Rotation):
@@ -109,7 +112,7 @@ def rotate_xyz(fname, ftype="xyz", noncollinear=False):
109
112
  rotated = rotate_atom_xyz(atoms, noncollinear=noncollinear)
110
113
 
111
114
  for i, rotated_atoms in enumerate(rotated):
112
- write(f"atoms_{i+1}.{ftype}", rotated_atoms)
113
- write(f"atoms_0.{ftype}", atoms)
114
-
115
- print(f"The output has been written to the atoms_i.{ftype} files. atoms_0.{ftype} contains the reference structure.")
115
+ write(f"atoms_{i}.{ftype}", rotated_atoms)
116
+ print(
117
+ f"The output has been written to the atoms_i.{ftype} files. atoms_0.{ftype} contains the reference structure."
118
+ )
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+
4
+ from TB2J.Jdownfolder import JDownfolder_pickle
5
+ from TB2J.versioninfo import print_license
6
+
7
+
8
+ def main():
9
+ parser = argparse.ArgumentParser(
10
+ description="TB2J_downfold: Downfold the exchange parameter with ligand spin as independent variable to that only with metal site spin as independent variables."
11
+ )
12
+ parser.add_argument(
13
+ "--inpath",
14
+ "-i",
15
+ type=str,
16
+ help="The path of the input TB2J results before the downfolding.",
17
+ default="TB2J_results",
18
+ )
19
+
20
+ parser.add_argument(
21
+ "--outpath",
22
+ "-o",
23
+ type=str,
24
+ help="The path of the output TB2J results path after the downfolding",
25
+ default="TB2J_results_downfolded",
26
+ )
27
+
28
+ parser.add_argument(
29
+ "--metals",
30
+ "-m",
31
+ type=str,
32
+ help="List of magnetic cation elements",
33
+ nargs="+",
34
+ default=[],
35
+ )
36
+
37
+ parser.add_argument(
38
+ "--ligands",
39
+ "-l",
40
+ type=str,
41
+ help="List of ligand elements",
42
+ nargs="+",
43
+ default=[],
44
+ )
45
+
46
+ parser.add_argument(
47
+ "--qmesh",
48
+ help="kmesh in the format of kx ky kz",
49
+ type=int,
50
+ nargs="*",
51
+ default=[5, 5, 5],
52
+ )
53
+
54
+ parser.add_argument(
55
+ "--iso_only",
56
+ help="whether to downfold only the isotropic part. The other parts will be neglected.",
57
+ action="store_true",
58
+ default=False,
59
+ )
60
+
61
+ parser.add_argument(
62
+ "--method",
63
+ help="The method to downfold the exchange parameter. Options are Lowdin and PWF (projected Wannier function). ",
64
+ type=str,
65
+ default="Lowdin",
66
+ )
67
+
68
+ args = parser.parse_args()
69
+
70
+ if len(args.metals) == []:
71
+ print("List of magnetic cation elements cannot be empty")
72
+
73
+ if len(args.ligands) == []:
74
+ print("List of ligand elements cannot be empty")
75
+
76
+ print_license()
77
+ print("Input path:", args.inpath)
78
+ print("Output path:", args.outpath)
79
+ print("Magnetic cation elements:", args.metals)
80
+ print("Ligand elements:", args.ligands)
81
+ print("k-mesh:", args.qmesh)
82
+ print("Downfolding method:", args.method)
83
+ print("Downfolding only isotropic part:", args.iso_only)
84
+ print("Begining downfolding the exchange parameters:")
85
+ JDownfolder_pickle(
86
+ inpath=args.inpath,
87
+ metals=args.metals,
88
+ ligands=args.ligands,
89
+ outpath=args.outpath,
90
+ qmesh=args.qmesh,
91
+ iso_only=args.iso_only,
92
+ method=args.method,
93
+ )
94
+ print("Downfolding finished. Results are saved in:", args.outpath)
95
+
96
+
97
+ main()