TB2J 0.8.2.7__tar.gz → 0.9.0__tar.gz

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 (85) hide show
  1. {TB2J-0.8.2.7 → TB2J-0.9.0}/PKG-INFO +1 -1
  2. TB2J-0.9.0/TB2J/__init__.py +1 -0
  3. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/abacus_wrapper.py +1 -2
  4. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/exchange.py +2 -2
  5. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/green.py +16 -6
  6. TB2J-0.9.0/TB2J/io_merge.py +184 -0
  7. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/myTB.py +0 -2
  8. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/rotate_atoms.py +22 -20
  9. TB2J-0.9.0/TB2J/rotate_siestaDM.py +36 -0
  10. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/sisl_wrapper.py +0 -1
  11. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J.egg-info/PKG-INFO +1 -1
  12. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J.egg-info/SOURCES.txt +2 -0
  13. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/TB2J_merge.py +9 -2
  14. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/TB2J_rotate.py +6 -1
  15. TB2J-0.9.0/scripts/TB2J_rotateDM.py +21 -0
  16. {TB2J-0.8.2.7 → TB2J-0.9.0}/setup.py +2 -1
  17. TB2J-0.8.2.7/TB2J/__init__.py +0 -1
  18. TB2J-0.8.2.7/TB2J/io_merge.py +0 -435
  19. {TB2J-0.8.2.7 → TB2J-0.9.0}/LICENSE +0 -0
  20. {TB2J-0.8.2.7 → TB2J-0.9.0}/README.md +0 -0
  21. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/Jdownfolder.py +0 -0
  22. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/Jtensor.py +0 -0
  23. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/Oiju.py +0 -0
  24. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/Oiju_epc.py +0 -0
  25. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/__init__.py +0 -0
  26. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/abacus_api.py +0 -0
  27. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/gen_exchange_abacus.py +0 -0
  28. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/orbital_api.py +0 -0
  29. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/stru_api.py +0 -0
  30. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/test_read_HRSR.py +0 -0
  31. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/abacus/test_read_stru.py +0 -0
  32. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/basis.py +0 -0
  33. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/citation.py +0 -0
  34. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/contour.py +0 -0
  35. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/density_matrix.py +0 -0
  36. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/epc.py +0 -0
  37. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/exchangeCL2.py +0 -0
  38. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/exchange_pert.py +0 -0
  39. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/exchange_qspace.py +0 -0
  40. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/external/__init__.py +0 -0
  41. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/external/p_tqdm.py +0 -0
  42. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/gpaw_wrapper.py +0 -0
  43. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/greentest.py +0 -0
  44. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/__init__.py +0 -0
  45. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/io_exchange.py +0 -0
  46. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/io_multibinit.py +0 -0
  47. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/io_tomsasd.py +0 -0
  48. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/io_txt.py +0 -0
  49. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/io_uppasd.py +0 -0
  50. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/io_exchange/io_vampire.py +0 -0
  51. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/kpoints.py +0 -0
  52. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/manager.py +0 -0
  53. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/mathutils.py +0 -0
  54. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/orbmap.py +0 -0
  55. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/pauli.py +0 -0
  56. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/pert.py +0 -0
  57. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/plot.py +0 -0
  58. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/__init__.py +0 -0
  59. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/base_parser.py +0 -0
  60. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/constants.py +0 -0
  61. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/hamiltonian.py +0 -0
  62. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/hamiltonian_terms.py +0 -0
  63. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/plot.py +0 -0
  64. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/qsolver.py +0 -0
  65. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/spin_api.py +0 -0
  66. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/spin_xml.py +0 -0
  67. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/spinham/supercell.py +0 -0
  68. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/tensor_rotate.py +0 -0
  69. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/utest.py +0 -0
  70. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/utils.py +0 -0
  71. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/versioninfo.py +0 -0
  72. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/wannier/__init__.py +0 -0
  73. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/wannier/w90_parser.py +0 -0
  74. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J/wannier/w90_tb_parser.py +0 -0
  75. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J.egg-info/dependency_links.txt +0 -0
  76. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J.egg-info/requires.txt +0 -0
  77. {TB2J-0.8.2.7 → TB2J-0.9.0}/TB2J.egg-info/top_level.txt +0 -0
  78. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/TB2J_downfold.py +0 -0
  79. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/TB2J_eigen.py +0 -0
  80. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/TB2J_magnon.py +0 -0
  81. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/TB2J_magnon_dos.py +0 -0
  82. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/abacus2J.py +0 -0
  83. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/siesta2J.py +0 -0
  84. {TB2J-0.8.2.7 → TB2J-0.9.0}/scripts/wann2J.py +0 -0
  85. {TB2J-0.8.2.7 → TB2J-0.9.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TB2J
3
- Version: 0.8.2.7
3
+ Version: 0.9.0
4
4
  Summary: TB2J: First principle to Heisenberg exchange J using tight-binding Green function method
5
5
  Home-page: UNKNOWN
6
6
  Author: Xu He
@@ -0,0 +1 @@
1
+ __version__ = "0.9.0"
@@ -18,8 +18,7 @@ class AbacusWrapper(AbstractTB):
18
18
  def __init__(self, HR, SR, Rlist, nbasis, nspin=1):
19
19
  self.R2kfactor = -2j * np.pi
20
20
  self.is_orthogonal = False
21
- self.is_siesta = False
22
- self._name = "Abacus"
21
+ self._name = "ABACUS"
23
22
  self.HR = HR
24
23
  self.SR = SR
25
24
  self.Rlist = Rlist
@@ -240,7 +240,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
240
240
  self.mmats = {}
241
241
  self.orbital_names = {}
242
242
  self.norb_reduced = {}
243
- if self.backend_name == "SIESTA":
243
+ if self.backend_name.upper() == "SIESTA":
244
244
  syms = self.atoms.get_chemical_symbols()
245
245
  for iatom, orbs in self.labels.items():
246
246
  if (self.include_orbs is not None) and syms[iatom] in self.include_orbs:
@@ -305,7 +305,7 @@ or badly localized. Please check the Wannier centers in the Wannier90 output fil
305
305
  """
306
306
  sum up the contribution of all the orbitals with same (n,l,m)
307
307
  """
308
- if self.backend_name == "SIESTA":
308
+ if self.backend_name.upper() == "SIESTA":
309
309
  mmat_i = self.mmats[iatom]
310
310
  mmat_j = self.mmats[jatom]
311
311
  Jorbij = mmat_i.T @ Jorbij @ mmat_j
@@ -225,12 +225,22 @@ class TBGreen:
225
225
 
226
226
  def get_density_matrix(self):
227
227
  rho = np.zeros((self.nbasis, self.nbasis), dtype=complex)
228
- for ik, _ in enumerate(self.kpts):
229
- rho += (
230
- (self.get_evecs(ik) * fermi(self.evals[ik], self.efermi))
231
- @ self.get_evecs(ik).T.conj()
232
- * self.kweights[ik]
233
- )
228
+ if self.is_orthogonal:
229
+ for ik, _ in enumerate(self.kpts):
230
+ rho += (
231
+ (self.get_evecs(ik) * fermi(self.evals[ik], self.efermi))
232
+ @ self.get_evecs(ik).T.conj()
233
+ * self.kweights[ik]
234
+ )
235
+ else:
236
+ for ik, _ in enumerate(self.kpts):
237
+ rho += (
238
+ (self.get_evecs(ik) * fermi(self.evals[ik], self.efermi))
239
+ @ self.get_evecs(ik).T.conj()
240
+ @ self.get_Sk(ik)
241
+ * self.kweights[ik]
242
+ )
243
+
234
244
  return rho
235
245
 
236
246
  def get_rho_R(self, Rlist):
@@ -0,0 +1,184 @@
1
+ import os
2
+ import copy
3
+ import warnings
4
+ import numpy as np
5
+ from itertools import combinations_with_replacement, product
6
+ from TB2J.io_exchange import SpinIO
7
+
8
+ u0 = np.zeros(3)
9
+ uy = np.array([0.0, 1.0, 0.0])
10
+ uz = np.array([0.0, 0.0, 1.0])
11
+
12
+ def get_Jani_coefficients(a, R=np.eye(3)):
13
+
14
+ if len(a) == 1:
15
+ u = a
16
+ v = a
17
+ else:
18
+ u = a[[0, 0, 1]]
19
+ v = a[[0, 1, 1]]
20
+
21
+ ur = u @ R.T
22
+ vr = v @ R.T
23
+ coefficients = np.hstack([ur*vr, np.roll(ur, -1, axis=-1)*vr + np.roll(vr, -1, axis=-1)*ur])
24
+
25
+ return coefficients, u, v
26
+
27
+ def get_projections(a, b, tol=1e-2):
28
+
29
+ projections = np.empty((2, 3))
30
+ if np.linalg.matrix_rank([a, b], tol=tol) == 1:
31
+ if np.linalg.matrix_rank([a, uy], tol=tol) == 1:
32
+ projections[0] = np.cross(a, uz)
33
+ else:
34
+ projections[0] = np.cross(a, uy)
35
+ projections[1] = np.cross(a, projections[0])
36
+ projections /= np.linalg.norm(projections, axis=-1).reshape(-1, 1)
37
+ else:
38
+ projections[0] = np.cross(a, b)
39
+ projections[0] /= np.linalg.norm(projections[0])
40
+ projections[1] = u0
41
+
42
+ return projections
43
+
44
+ class SpinIO_merge(SpinIO):
45
+ def __init__(self, *args, **kwargs):
46
+ super(SpinIO_merge, self).__init__(*args, **kwargs)
47
+ self.projv = None
48
+
49
+ def _set_projection_vectors(self):
50
+
51
+ spinat = self.spinat
52
+ idx = [self.ind_atoms[i] for i in self.index_spin if i >= 0]
53
+ projv = {}
54
+ for i, j in combinations_with_replacement(range(self.nspin), 2):
55
+ a, b = spinat[idx][[i, j]]
56
+ projv[i, j] = get_projections(a, b)
57
+ projv[j, i] = projv[i, j]
58
+
59
+ self.projv = projv
60
+
61
+ @classmethod
62
+ def load_pickle(cls, path='TB2J_results', fname='TB2J.pickle'):
63
+ obj = super(SpinIO_merge, cls).load_pickle(path=path, fname=fname)
64
+ obj._set_projection_vectors()
65
+
66
+ return obj
67
+
68
+ def read_pickle(path):
69
+ p1 = os.path.join(path, 'TB2J_results', 'TB2J.pickle')
70
+ p2 = os.path.join(path, 'TB2J.pickle')
71
+ if os.path.exists(p1) and os.path.exists(p2):
72
+ print(f" WARNING!: Both file {p1} and {p2} exist. Use default {p1}.")
73
+ if os.path.exists(p1):
74
+ ret = SpinIO_merge.load_pickle(os.path.join(path, 'TB2J_results'))
75
+ elif os.path.exists(p2):
76
+ ret = SpinIO_merge.load_pickle(path)
77
+ else:
78
+ raise FileNotFoundError(f"Cannot find either file {p1} or {p2}")
79
+ return ret
80
+
81
+ class Merger():
82
+ def __init__(self, *paths, main_path=None):
83
+ self.dat = [read_pickle(path) for path in paths]
84
+
85
+ if main_path is None:
86
+ self.main_dat = copy.deepcopy(self.dat[-1])
87
+ else:
88
+ self.main_dat = read_pickle(main_path)
89
+ self.dat.append(copy.deepcopy(self.main_dat))
90
+
91
+ self._set_projv()
92
+
93
+ def _set_projv(self):
94
+
95
+ cell = self.main_dat.atoms.cell.array
96
+ rotated_cells = np.stack(
97
+ [obj.atoms.cell.array for obj in self.dat], axis=0
98
+ )
99
+ R = np.linalg.solve(cell, rotated_cells)
100
+ indices = range(len(self.dat))
101
+
102
+ proju = {}; projv = {}; coeff_matrix = {}; projectors = {};
103
+ for key in self.main_dat.projv.keys():
104
+ vectors = [obj.projv[key] for obj in self.dat]
105
+ coefficients, u, v = zip(*[get_Jani_coefficients(vectors[i], R=R[i]) for i in indices])
106
+ projectors[key] = np.vstack([u[i] @ R[i].T for i in indices])
107
+ coeff_matrix[key] = np.vstack(coefficients)
108
+ proju[key] = np.stack(u)
109
+ projv[key] = np.stack(v)
110
+ if np.linalg.matrix_rank(coeff_matrix[key], tol=1e-2) < 6:
111
+ warnings.warn('''
112
+ WARNING: The matrix of equations to reconstruct the exchange tensors is
113
+ close to being singular. This happens when the magnetic moments between
114
+ different configurations are cloes to being parallel. You need to consider
115
+ more rotated spin configurations, otherwise the results might have a large
116
+ error.'''
117
+ )
118
+
119
+ self.proju = proju
120
+ self.projv = projv
121
+ self.coeff_matrix = coeff_matrix
122
+ self.projectors = projectors
123
+
124
+ def merge_Jani(self):
125
+ Jani_dict = {}
126
+ proju = self.proju; projv = self.projv; coeff_matrix = self.coeff_matrix;
127
+ for key in self.main_dat.Jani_dict.keys():
128
+ try:
129
+ R, i, j = key
130
+ u = proju[i, j]
131
+ v = projv[i, j]
132
+ Jani = np.stack([sio.Jani_dict[key] for sio in self.dat])
133
+ projections = np.einsum('nmi,nij,nmj->nm', u, Jani, v).flatten()
134
+ except KeyError as err:
135
+ raise KeyError(
136
+ "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
137
+ % err)
138
+ newJani = np.linalg.lstsq(coeff_matrix[i, j], projections, rcond=1e-2)[0]
139
+ Jani_dict[key] = np.array([
140
+ [newJani[0], newJani[3], newJani[5]],
141
+ [newJani[3], newJani[1], newJani[4]],
142
+ [newJani[5], newJani[4], newJani[2]]
143
+ ])
144
+ self.main_dat.Jani_dict = Jani_dict
145
+
146
+ def merge_Jiso(self):
147
+ Jdict={}
148
+ for key in self.main_dat.exchange_Jdict.keys():
149
+ try:
150
+ J = np.mean([obj.exchange_Jdict[key] for obj in self.dat])
151
+ except KeyError as err:
152
+ raise KeyError(
153
+ "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
154
+ % err)
155
+ Jdict[key] = J
156
+ self.main_dat.exchange_Jdict = Jdict
157
+
158
+
159
+ def merge_DMI(self):
160
+ dmi_ddict = {}
161
+ if all(obj.has_dmi for obj in self.dat):
162
+ projectors = self.projectors; proju = self.proju;
163
+ for key in self.main_dat.dmi_ddict.keys():
164
+ try:
165
+ R, i, j = key
166
+ u = proju[i, j]
167
+ DMI = np.stack([sio.dmi_ddict[key] for sio in self.dat])
168
+ projections = np.einsum('nmi,ni->nm', u, DMI).flatten()
169
+ except KeyError as err:
170
+ raise KeyError(
171
+ "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
172
+ % err)
173
+ newDMI = np.linalg.lstsq(projectors[i, j], projections, rcond=4e-1)[0]
174
+ dmi_ddict[key] = newDMI
175
+ self.main_dat.dmi_ddict = dmi_ddict
176
+
177
+ def merge(*paths, main_path=None, save=True, write_path='TB2J_results'):
178
+ m = Merger(*paths, main_path=main_path)
179
+ m.merge_Jiso()
180
+ m.merge_DMI()
181
+ m.merge_Jani()
182
+ if save:
183
+ m.main_dat.write_all(path=write_path)
184
+ return m.dat
@@ -16,7 +16,6 @@ class AbstractTB:
16
16
  def __init__(self, R2kfactor, nspin, norb):
17
17
  #: :math:`\alpha` used in :math:`H(k)=\sum_R H(R) \exp( \alpha k \cdot R)`,
18
18
  #: Should be :math:`2\pi i` or :math:`-2\pi i`
19
- self.is_siesta = False
20
19
  self.is_orthogonal = True
21
20
  self.R2kfactor = R2kfactor
22
21
 
@@ -125,7 +124,6 @@ class MyTB(AbstractTB):
125
124
  self.atoms = None
126
125
  self.R2kfactor = 2.0j * np.pi
127
126
  self.k2Rfactor = -2.0j * np.pi
128
- self.is_siesta = False
129
127
  self.is_orthogonal = True
130
128
  self._name = "Wannier"
131
129
 
@@ -5,19 +5,24 @@ import numpy as np
5
5
  from TB2J.tensor_rotate import Rxx, Rxy, Rxz, Ryx, Ryy, Ryz, Rzx, Rzy, Rzz
6
6
 
7
7
 
8
- def rotate_atom_xyz(atoms):
8
+ def rotate_atom_xyz(atoms, noncollinear=False):
9
9
  """
10
- given a atoms, return:
11
- - 'z'->'x'
12
- - 'z'->'y'
13
- - 'z'->'z'
10
+ given a atoms, return rotated atoms:
11
+ atoms_1, ..., atoms_n,
12
+ where we considered n diffeerent roation axes.
13
+
14
+ When noncollinear == True, more rotated structures
15
+ will be generated.
14
16
  """
15
- atoms_x = copy.deepcopy(atoms)
16
- atoms_x.rotate(90, "y", rotate_cell=True)
17
- atoms_y = copy.deepcopy(atoms)
18
- atoms_y.rotate(90, "x", rotate_cell=True)
19
- atoms_z = atoms
20
- return atoms_x, atoms_y, atoms_z
17
+
18
+ rotation_axes = [(1, 0, 0), (0, 1, 0)]
19
+ if noncollinear:
20
+ rotation_axes += [(1, 1, 0), (1, 0, 1), (0, 1, 1)]
21
+
22
+ for axis in rotation_axes:
23
+ rotated_atoms = copy.deepcopy(atoms)
24
+ rotated_atoms.rotate(90, axis, rotate_cell=True)
25
+ yield rotated_atoms
21
26
 
22
27
 
23
28
  def rotate_atom_spin_one_rotation(atoms, Rotation):
@@ -96,18 +101,15 @@ def check_ftype(ftype):
96
101
  print("=" * 40)
97
102
 
98
103
 
99
- def rotate_xyz(fname, ftype="xyz"):
104
+ def rotate_xyz(fname, ftype="xyz", noncollinear=False):
100
105
  check_ftype(ftype)
101
106
  atoms = read(fname)
102
107
  atoms.set_pbc(True)
103
108
 
104
- atoms_x, atoms_y, atoms_z = rotate_atom_xyz(atoms)
109
+ rotated = rotate_atom_xyz(atoms, noncollinear=noncollinear)
105
110
 
106
- fname_x = f"atoms_x.{ftype}"
107
- fname_y = f"atoms_y.{ftype}"
108
- fname_z = f"atoms_z.{ftype}"
111
+ for i, rotated_atoms in enumerate(rotated):
112
+ write(f"atoms_{i+1}.{ftype}", rotated_atoms)
113
+ write(f"atoms_0.{ftype}", atoms)
109
114
 
110
- write(fname_x, atoms_x)
111
- write(fname_y, atoms_y)
112
- write(fname_z, atoms_z)
113
- print(f"The output has been written to {fname_x}, {fname_y}, {fname_z}")
115
+ print(f"The output has been written to the atoms_i.{ftype} files. atoms_0.{ftype} contains the reference structure.")
@@ -0,0 +1,36 @@
1
+ import sisl
2
+
3
+ def rotate_siesta_DM(DM, noncollinear=False):
4
+
5
+ angles_list = [ [0.0, 90.0, 0.0], [0.0, 90.0, 90.0] ]
6
+ if noncollinear:
7
+ angles_list += [[0.0, 45.0, 0.0], [0.0, 90.0, 45.0], [0.0, 45.0, 90.0]]
8
+
9
+ for angles in angles_list:
10
+ yield DM.spin_rotate(angles)
11
+
12
+ def read_label(fdf_fname):
13
+
14
+ label = 'siesta'
15
+ with open(fdf_fname, 'r') as File:
16
+ for line in File:
17
+ corrected_line = line.lower().replace('.', '').replace('-', '')
18
+ if 'systemlabel' in corrected_line:
19
+ label = line.split()[1]
20
+ break
21
+
22
+ return label
23
+
24
+ def rotate_DM(fdf_fname, noncollinear=False):
25
+
26
+ fdf = sisl.get_sile(fdf_fname)
27
+ DM = fdf.read_density_matrix()
28
+ label = read_label(fdf_fname)
29
+
30
+ rotated = rotate_siesta_DM(DM, noncollinear=noncollinear)
31
+
32
+ for i, rotated_DM in enumerate(rotated):
33
+ rotated_DM.write(f"{label}_{i+1}.DM")
34
+ DM.write(f"{label}_0.DM")
35
+
36
+ print(f"The output has been written to the {label}_i.DM files. {label}_0.DM contains the reference density matrix.")
@@ -10,7 +10,6 @@ from TB2J.mathutils import Lowdin
10
10
 
11
11
  class SislWrapper(AbstractTB):
12
12
  def __init__(self, sisl_hamiltonian, geom=None, spin=None):
13
- self.is_siesta = False
14
13
  self.is_orthogonal = False
15
14
  self.ham = sisl_hamiltonian
16
15
  # k2Rfactor : H(k) = \int_R H(R) * e^(k2Rfactor * k.R)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: TB2J
3
- Version: 0.8.2.7
3
+ Version: 0.9.0
4
4
  Summary: TB2J: First principle to Heisenberg exchange J using tight-binding Green function method
5
5
  Home-page: UNKNOWN
6
6
  Author: Xu He
@@ -28,6 +28,7 @@ TB2J/pauli.py
28
28
  TB2J/pert.py
29
29
  TB2J/plot.py
30
30
  TB2J/rotate_atoms.py
31
+ TB2J/rotate_siestaDM.py
31
32
  TB2J/sisl_wrapper.py
32
33
  TB2J/tensor_rotate.py
33
34
  TB2J/utest.py
@@ -74,6 +75,7 @@ scripts/TB2J_magnon.py
74
75
  scripts/TB2J_magnon_dos.py
75
76
  scripts/TB2J_merge.py
76
77
  scripts/TB2J_rotate.py
78
+ scripts/TB2J_rotateDM.py
77
79
  scripts/abacus2J.py
78
80
  scripts/siesta2J.py
79
81
  scripts/wann2J.py
@@ -2,7 +2,7 @@
2
2
  import argparse
3
3
  import os
4
4
  import sys
5
- from TB2J.io_merge import merge, merge2
5
+ from TB2J.io_merge import merge
6
6
 
7
7
 
8
8
  def main():
@@ -28,11 +28,18 @@ def main():
28
28
  type=str,
29
29
  default="TB2J_results",
30
30
  )
31
+ parser.add_argument(
32
+ "--main_path",
33
+ help="The path containning the reference structure.",
34
+ type=str,
35
+ default=None
36
+ )
31
37
 
32
38
  args = parser.parse_args()
33
39
  # merge(*(args.directories), args.type.strip().lower(), path=args.output_path)
34
40
  # merge(*(args.directories), method=args.type.strip().lower(), path=args.output_path)
35
- merge2(args.directories, args.type.strip().lower(), path=args.output_path)
41
+ #merge2(args.directories, args.type.strip().lower(), path=args.output_path)
42
+ merge(*args.directories, main_path=args.main_path, write_path=args.output_path)
36
43
 
37
44
 
38
45
  main()
@@ -14,9 +14,14 @@ def main():
14
14
  default="xyz",
15
15
  type=str,
16
16
  )
17
+ parser.add_argument(
18
+ "--noncollinear",
19
+ action="store_true",
20
+ help="If present, six different configurations will be generated. These are required for non-collinear systems."
21
+ )
17
22
 
18
23
  args = parser.parse_args()
19
- rotate_xyz(args.fname, ftype=args.ftype)
24
+ rotate_xyz(args.fname, ftype=args.ftype, noncollinear=args.noncollinear)
20
25
 
21
26
 
22
27
  if __name__ == "__main__":
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env python3
2
+ import argparse
3
+ from TB2J.rotate_siestaDM import rotate_DM
4
+
5
+ def main():
6
+ parser = argparse.ArgumentParser(description="")
7
+ parser.add_argument(
8
+ "--fdf_fname", help="Name of the *.fdf siesta file."
9
+ )
10
+ parser.add_argument(
11
+ "--noncollinear",
12
+ action="store_true",
13
+ help="If present, six different configurations will be generated. These are required for non-collinear systems."
14
+ )
15
+
16
+ args = parser.parse_args()
17
+ rotate_DM(args.fdf_fname, noncollinear=args.noncollinear)
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main()
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  from setuptools import setup, find_packages
3
3
 
4
- __version__ = "0.8.2.7"
4
+ __version__ = "0.9.0"
5
5
 
6
6
  long_description = """TB2J is a Python package aimed to compute automatically the magnetic interactions (superexchange and Dzyaloshinskii-Moriya) between atoms of magnetic crystals from DFT Hamiltonian based on Wannier functions or Linear combination of atomic orbitals. It uses the Green's function method and take the local rigid spin rotation as a perturbation. The package can take the output from Wannier90, which is interfaced with many density functional theory codes or from codes based on localised orbitals. A minimal user input is needed, which allows for an easily integration into a high-throughput workflows. """
7
7
 
@@ -19,6 +19,7 @@ setup(
19
19
  "scripts/siesta2J.py",
20
20
  "scripts/abacus2J.py",
21
21
  "scripts/TB2J_rotate.py",
22
+ "scripts/TB2J_rotateDM.py",
22
23
  "scripts/TB2J_merge.py",
23
24
  "scripts/TB2J_magnon.py",
24
25
  "scripts/TB2J_magnon_dos.py",
@@ -1 +0,0 @@
1
- __version__ = "0.8.2.7"
@@ -1,435 +0,0 @@
1
- import os
2
- import copy
3
- import numpy as np
4
- from scipy.spatial.transform import Rotation
5
- from TB2J.io_exchange import SpinIO
6
- from TB2J.tensor_rotate import remove_components
7
- from TB2J.Jtensor import DMI_to_Jtensor, Jtensor_to_DMI
8
- from TB2J.tensor_rotate import Rzx, Rzy, Rzz, Ryz, Rxz
9
-
10
-
11
- def test_rotation_matrix():
12
- x = [1, 0, 0]
13
- y = [0, 1, 0]
14
- z = [0, 0, 1]
15
- print(Rxz.apply(x))
16
- print(Ryz.apply(y))
17
- print(Rzx.apply(z))
18
- print(Rzy.apply(z))
19
-
20
-
21
- def recover_DMI_from_rotated_structure(Ddict, rotation):
22
- """
23
- Recover the DMI vector from the rotated structure.
24
- D: the dictionary of DMI vector in the rotated structure.
25
- rotation: the rotation operator from the original structure to the rotated structure.
26
- """
27
- for key, val in Ddict.items():
28
- Ddict[key] = rotation.apply(val, inverse=True)
29
- return Ddict
30
-
31
-
32
- def recover_Jani_fom_rotated_structure(Janidict, rotation):
33
- """
34
- Recover the Jani tensor from the rotated structure.
35
- Janidict: the dictionary of Jani tensor in the rotated structure.
36
- rotation: the from the original structure to the rotated structure.
37
- """
38
- R = rotation.as_matrix()
39
- RT = R.T
40
- for key, Jani in Janidict.items():
41
- # Note: E=Si J Sj , Si'= Si RT, Sj' = R Sj,
42
- # Si' J' Sj' = Si RT R J RT R Sj => J' = R J RT
43
- # But here we are doing the opposite rotation back to
44
- # the original axis, so we replace R with RT.
45
- Janidict[key] = RT @ Jani @ R
46
- return Janidict
47
-
48
-
49
- def recover_spinat_from_rotated_structure(spinat, rotation):
50
- """
51
- Recover the spinat from the rotated structure.
52
- spinat: the spinat in the rotated structure.
53
- rotation: the rotation operator from the original structure to the rotated structure.
54
- """
55
- for i, spin in enumerate(spinat):
56
- spinat[i] = rotation.apply(spin, inverse=True)
57
- return spinat
58
-
59
-
60
- # test_rotation_matrix()
61
-
62
- # R_xyz = [Rxz.as_matrix(), Ryz.as_matrix(), np.eye(3, dtype=float)]
63
-
64
-
65
- def rot_merge_DMI(Dx, Dy, Dz):
66
- Dx_z = Rzx.apply(Dx)
67
- Dy_z = Rzy.apply(Dy)
68
- D = (
69
- np.array([0.0, 0.5, 0.5]) * Dx_z
70
- + np.array([0.5, 0.0, 0.5]) * Dy_z
71
- + np.array([0.5, 0.5, 0.0]) * Dz
72
- )
73
- return D
74
-
75
-
76
- def rot_merge_DMI2(Dx, Dy, Dz):
77
- Dx_z = Rzx.apply(Dx)
78
- Dy_z = Rzy.apply(Dy)
79
- D = (
80
- np.array([1, 0, 0]) * Dx_z
81
- + np.array([0, 1, 0]) * Dy_z
82
- + np.array([0, 0, 1]) * Dz
83
- )
84
- return D
85
-
86
-
87
- def merge_DMI(Dx, Dy, Dz):
88
- D = (
89
- np.array([0.0, 0.5, 0.5]) * Dx
90
- + np.array([0.5, 0.0, 0.5]) * Dy
91
- + np.array([0.5, 0.5, 0.0]) * Dz
92
- )
93
- return D
94
-
95
-
96
- def merge_DMI2(Dx, Dy, Dz):
97
- D = np.array([1, 0, 0]) * Dx + np.array([0, 1, 0]) * Dy + np.array([0, 0, 1]) * Dz
98
- return D
99
-
100
-
101
- def swap_direction(m, idirections):
102
- """
103
- swap two directions of a tensor m.
104
- idirections: the index of the two directions.
105
- """
106
- idirections = list(idirections)
107
- inv = [idirections[1], idirections[0]]
108
- n = np.copy(m)
109
- n[:, idirections] = n[:, inv]
110
- n[idirections, :] = n[inv, :]
111
- return n
112
-
113
-
114
- def test_swap():
115
- m = np.reshape(np.arange(9), (3, 3))
116
- print(m)
117
- print(swap_direction(m, [0, 1]))
118
-
119
-
120
- def merge_Jani(Janix, Janiy, Janiz):
121
- # This is wrong.
122
- # Jani = (
123
- # np.array([[0, 0, 0], [0, 1, 1], [0, 1, 1]]) * Janix
124
- # + np.array([[1, 0, 1], [0, 0, 0], [1, 0, 1]]) * Janiy
125
- # + np.array([[1, 1, 0], [1, 1, 0], [0, 0, 0]]) * Janiz
126
- # ) / 2.0
127
- wx = np.array([[0, 0, 0], [0, 1, 1], [0, 1, 1]])
128
- wy = np.array([[1, 0, 1], [0, 0, 0], [1, 0, 1]])
129
- wz = np.array([[1, 1, 0], [1, 1, 0], [0, 0, 0]])
130
- Jani = (wx * Janix + wy * Janiy + wz * Janiz) / (wx + wy + wz)
131
- return Jani
132
-
133
-
134
- def read_pickle(path):
135
- p1 = os.path.join(path, "TB2J_results", "TB2J.pickle")
136
- p2 = os.path.join(path, "TB2J.pickle")
137
- if os.path.exists(p1) and os.path.exists(p2):
138
- print(f" WARNING!: Both file {p1} and {p2} exist. Use default {p1}.")
139
- if os.path.exists(p1):
140
- ret = SpinIO.load_pickle(os.path.join(path, "TB2J_results"))
141
- elif os.path.exists(p2):
142
- ret = SpinIO.load_pickle(path)
143
- else:
144
- raise FileNotFoundError(f"Cannot find either file {p1} or {p2}")
145
- return ret
146
-
147
-
148
- class Merger2:
149
- def __init__(self, paths, method):
150
- self.method = method
151
- if method.lower() == "spin":
152
- self.load_with_rotated_spin(paths)
153
- elif method.lower() == "structure":
154
- self.load_with_rotated_structure(paths)
155
- else:
156
- raise ValueError("method should be either 'spin' or 'structure'")
157
-
158
- def load_with_rotated_structure(self, paths):
159
- """
160
- Merge TB2J results from multiple calculations.
161
- :param paths: a list of paths to the TB2J results.
162
- :param method: 'structure' or 'spin'
163
- """
164
- self.paths = paths
165
- if len(self.paths) != 3:
166
- raise ValueError(
167
- "The number of paths should be 3, with structure rotated from z to x, y, z"
168
- )
169
- for i, path in enumerate(self.paths):
170
- read_pickle(path)
171
- self.indata = [read_pickle(path) for path in paths]
172
-
173
- self.dat = copy.deepcopy(self.indata[-1])
174
- # self.dat.description += (
175
- # "Merged from TB2J results in paths: \n " + "\n ".join(paths) + "\n"
176
- # )
177
- Rotations = [Rzx, Rzy, Rzz]
178
- for dat, rotation in zip(self.indata, Rotations):
179
- dat.spinat = recover_spinat_from_rotated_structure(dat.spinat, rotation)
180
- dat.dmi_ddict = recover_DMI_from_rotated_structure(dat.dmi_ddict, rotation)
181
- dat.Jani_dict = recover_Jani_fom_rotated_structure(dat.Jani_dict, rotation)
182
-
183
- def load_with_rotated_spin(self, paths):
184
- """
185
- Merge TB2J results from multiple calculations.
186
- :param paths: a list of paths to the TB2J results.
187
- :param method: 'structure' or 'spin'
188
- """
189
- self.paths = paths
190
- self.indata = [read_pickle(path) for path in paths]
191
- self.dat = copy.deepcopy(self.indata[-1])
192
- # self.dat.description += (
193
- # "Merged from TB2J results in paths: \n " + "\n ".join(paths) + "\n"
194
- # )
195
-
196
- def merge_Jani(self):
197
- """
198
- Merge the anisotropic exchange tensor.
199
- """
200
- Jani_dict = {}
201
- for key, Jani in self.dat.Jani_dict.items():
202
- R, i, j = key
203
- weights = np.zeros((3, 3), dtype=float)
204
- Jani_sum = np.zeros((3, 3), dtype=float)
205
- for dat in self.indata:
206
- Si = dat.get_spin_ispin(i)
207
- Sj = dat.get_spin_ispin(j)
208
- # print(f"{Si=}, {Sj=}")
209
- Jani = dat.get_Jani(i, j, R, default=np.zeros((3, 3), dtype=float))
210
- Jani_removed, w = remove_components(
211
- Jani,
212
- Si,
213
- Sj,
214
- remove_indices=[[0, 2], [1, 2], [2, 2], [2, 1], [2, 0]],
215
- )
216
- w = Jani_removed / Jani
217
- Jani_sum += Jani * w # Jani_removed
218
- # print(f"{Jani* w=}")
219
- weights += w
220
- # print(f"{weights=}")
221
- if np.any(weights == 0):
222
- raise RuntimeError(
223
- "The data set to be merged does not give a complete anisotropic J tensor, please add more data"
224
- )
225
- Jani_dict[key] = Jani_sum / weights
226
- self.dat.Jani_dict = Jani_dict
227
-
228
- def merge_DMI(self):
229
- """
230
- merge the DMI vector
231
- """
232
- DMI = {}
233
- for key, D in self.dat.dmi_ddict.items():
234
- R, i, j = key
235
- weights = np.zeros((3, 3), dtype=float)
236
- Dtensor_sum = np.zeros((3, 3), dtype=float)
237
- for dat in self.indata:
238
- Si = dat.get_spin_ispin(i)
239
- Sj = dat.get_spin_ispin(j)
240
- D = dat.get_DMI(i, j, R, default=np.zeros((3,), dtype=float))
241
- Dtensor = DMI_to_Jtensor(D)
242
- Dtensor_removed, w = remove_components(
243
- Dtensor, Si, Sj, remove_indices=[[0, 1], [1, 0]]
244
- )
245
- Dtensor_sum += Dtensor * w # Dtensor_removed
246
- weights += w
247
- if np.any(weights == 0):
248
- raise RuntimeError(
249
- "The data set to be merged does not give a complete DMI vector, please add more data"
250
- )
251
- DMI[key] = Jtensor_to_DMI(Dtensor_sum / weights)
252
- self.dat.dmi_ddict = DMI
253
-
254
- def merge_Jiso(self):
255
- """
256
- merge the isotropic exchange
257
- """
258
- Jiso = {}
259
- for key, J in self.dat.exchange_Jdict.items():
260
- R, i, j = key
261
- weights = 0.0
262
- Jiso_sum = 0.0
263
- for dat in self.indata:
264
- Si = dat.get_spin_ispin(i)
265
- Sj = dat.get_spin_ispin(j)
266
- J = dat.get_Jiso(i, j, R, default=0.0)
267
- Jiso_sum += J # *np.eye(3, dtype=float)
268
- weights += 1.0
269
- if np.any(weights == 0):
270
- raise RuntimeError(
271
- "The data set to be merged does not give a complete isotropic exchange, please add more data"
272
- )
273
- Jiso[key] = Jiso_sum / weights
274
- self.dat.exchange_Jdict = Jiso
275
-
276
- def write(self, path="TB2J_results"):
277
- """
278
- Write the merged TB2J results to a folder.
279
- :param path: the path to the folder to write the results.
280
- """
281
- self.dat.description += (
282
- "Merged from TB2J results in paths: \n " + "\n ".join(self.paths) + "\n"
283
- )
284
- if self.method == "spin":
285
- self.dat.description += (
286
- ", which are from DFT data with various spin orientations. \n"
287
- )
288
- elif self.method == "structure":
289
- self.dat.description += ", which are from DFT data with structure with z axis rotated to x, y, z\n"
290
- self.dat.description += "\n"
291
- self.dat.write_all(path=path)
292
-
293
-
294
- class Merger:
295
- def __init__(self, path_x, path_y, path_z, method="structure"):
296
- assert method in ["structure", "spin"]
297
- self.dat_x = read_pickle(path_x)
298
- self.dat_y = read_pickle(path_y)
299
- self.dat_z = read_pickle(path_z)
300
- self.dat = copy.copy(self.dat_z)
301
- self.paths = [path_x, path_y, path_z]
302
- self.method = method
303
-
304
- def merge_Jani(self):
305
- Jani_dict = {}
306
- Janixdict = self.dat_x.Jani_dict
307
- Janiydict = self.dat_y.Jani_dict
308
- Janizdict = self.dat_z.Jani_dict
309
- for key, Janiz in Janizdict.items():
310
- try:
311
- R, i, j = key
312
- keyx = R
313
- keyy = R
314
- Janix = Janixdict[(tuple(keyx), i, j)]
315
- Janiy = Janiydict[(tuple(keyy), i, j)]
316
- except KeyError as err:
317
- raise KeyError(
318
- "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
319
- % err
320
- )
321
- if self.method == "spin":
322
- Jani_dict[key] = merge_Jani(Janix, Janiy, Janiz)
323
- else:
324
- Jani_dict[key] = merge_Jani(
325
- swap_direction(Janix, (0, 2)), swap_direction(Janiy, (1, 2)), Janiz
326
- )
327
- self.dat.Jani_dict = Jani_dict
328
-
329
- def merge_Jiso(self):
330
- Jdict = {}
331
- Jxdict = self.dat_x.exchange_Jdict
332
- Jydict = self.dat_y.exchange_Jdict
333
- Jzdict = self.dat_z.exchange_Jdict
334
- for key, J in Jzdict.items():
335
- try:
336
- Jx = Jxdict[key]
337
- Jy = Jydict[key]
338
- Jz = Jzdict[key]
339
- except KeyError as err:
340
- raise KeyError(
341
- "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
342
- % err
343
- )
344
- Jdict[key] = (Jx + Jy + Jz) / 3.0
345
- self.dat.exchange_Jdict = Jdict
346
-
347
- def merge_DMI(self):
348
- dmi_ddict = {}
349
- if self.dat_x.has_dmi and self.dat_y.has_dmi and self.dat_z.has_dmi:
350
- Dxdict = self.dat_x.dmi_ddict
351
- Dydict = self.dat_y.dmi_ddict
352
- Dzdict = self.dat_z.dmi_ddict
353
- for key, Dz in Dzdict.items():
354
- try:
355
- R, i, j = key
356
- keyx = R
357
- keyy = R
358
- Dx = Dxdict[(tuple(keyx), i, j)]
359
- Dy = Dydict[(tuple(keyy), i, j)]
360
- except KeyError as err:
361
- raise KeyError(
362
- "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
363
- % err
364
- )
365
- if self.method == "structure":
366
- dmi_ddict[key] = rot_merge_DMI(Dx, Dy, Dz)
367
- else:
368
- dmi_ddict[key] = merge_DMI(Dx, Dy, Dz)
369
- self.dat.dmi_ddict = dmi_ddict
370
-
371
- dmi_ddict = {}
372
- try:
373
- Dxdict = self.dat_x.debug_dict["DMI2"]
374
- Dydict = self.dat_y.debug_dict["DMI2"]
375
- Dzdict = self.dat_z.debug_dict["DMI2"]
376
- for key, Dz in Dzdict.items():
377
- try:
378
- R, i, j = key
379
- keyx = R
380
- keyy = R
381
- Dx = Dxdict[(tuple(keyx), i, j)]
382
- Dy = Dydict[(tuple(keyy), i, j)]
383
- except KeyError as err:
384
- raise KeyError(
385
- "Can not find key: %s, Please make sure the three calculations use the same k-mesh and same Rcut."
386
- % err
387
- )
388
- if self.method == "structure":
389
- dmi_ddict[key] = rot_merge_DMI2(Dx, Dy, Dz)
390
- elif self.method == "spin":
391
- dmi_ddict[key] = merge_DMI2(Dx, Dy, Dz)
392
-
393
- self.dat.debug_dict["DMI2"] = dmi_ddict
394
- except:
395
- pass
396
-
397
- def write(self, path="TB2J_results"):
398
- self.dat.description += (
399
- "Merged from TB2J results in paths: \n " + "\n ".join(self.paths) + "\n"
400
- )
401
- if self.method == "spin":
402
- self.dat.description += (
403
- ", which are from DFT data with spin along x, y, z orientation\n"
404
- )
405
- elif self.method == "structure":
406
- self.dat.description += ", which are from DFT data with structure with z axis rotated to x, y, z\n"
407
- self.dat.description += "\n"
408
- self.dat.write_all(path=path)
409
-
410
-
411
- def merge(path_x, path_y, path_z, method, save=True, path="TB2J_results"):
412
- m = Merger(path_x, path_y, path_z, method)
413
- m.merge_Jiso()
414
- m.merge_DMI()
415
- m.merge_Jani()
416
- if save:
417
- m.write(path=path)
418
- return m.dat
419
-
420
-
421
- def merge2(paths, method, save=True, path="TB2J_results"):
422
- """
423
- Merge TB2J results from multiple calculations.
424
- :param paths: a list of paths to the TB2J results.
425
- :param method: 'structure' or 'spin'
426
- :param save: whether to save the merged results.
427
- :param path: the path to the folder to write the results.
428
- """
429
- m = Merger2(paths, method)
430
- m.merge_Jiso()
431
- m.merge_DMI()
432
- m.merge_Jani()
433
- if save:
434
- m.write(path=path)
435
- return m.dat
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes