@@ -258,6 +258,51 @@ def parse_stru_pos(pos_line):
258258 return pos , move , velocity , magmom , angle1 , angle2 , constrain , lambda1
259259
260260
261+ def get_atom_mag_cartesian (atommag , angle1 , angle2 ):
262+ """Transform atommag, angle1, angle2 to magmom in cartesian coordinates.
263+
264+ Parameters
265+ ----------
266+ atommag : float/list of float/None
267+ Atom magnetic moment.
268+ angle1 : float/None
269+ value of angle1.
270+ angle2 : float/None
271+ value of angle2.
272+ ABACUS support defining mag, angle1, angle2 at the same time.
273+ angle1 is the angle between z-axis and real spin (in degrees).
274+ angle2 is the angle between x-axis and real spin projection in xy-plane (in degrees).
275+ If only mag is defined, then transfer it to magmom directly.
276+ And if mag, angle1, angle2 are defined, then mag is only the norm of magmom, and the direction is defined by angle1 and angle2.
277+ """
278+ if atommag is None :
279+ return None
280+ if not (isinstance (atommag , list ) or isinstance (atommag , float )):
281+ raise RuntimeError (f"Invalid atommag: { atommag } " )
282+
283+ if angle1 is None and angle2 is None :
284+ if isinstance (atommag , list ):
285+ return atommag
286+ else :
287+ return [0 , 0 , atommag ]
288+ else :
289+ a1 = 0
290+ a2 = 0
291+ if angle1 is not None :
292+ a1 = angle1
293+ if angle2 is not None :
294+ a2 = angle2
295+ if isinstance (atommag , list ):
296+ mag_norm = np .linalg .norm (atommag )
297+ else :
298+ mag_norm = atommag
299+ return [
300+ mag_norm * np .sin (np .radians (a1 )) * np .cos (np .radians (a2 )),
301+ mag_norm * np .sin (np .radians (a1 )) * np .sin (np .radians (a2 )),
302+ mag_norm * np .cos (np .radians (a1 )),
303+ ]
304+
305+
261306def get_coords (celldm , cell , geometry_inlines , inlines = None ):
262307 coords_lines = get_stru_block (geometry_inlines , "ATOMIC_POSITIONS" )
263308 # assuming that ATOMIC_POSITIONS is at the bottom of the STRU file
@@ -268,16 +313,15 @@ def get_coords(celldm, cell, geometry_inlines, inlines=None):
268313 coords = [] # coordinations of atoms
269314 move = [] # move flag of each atom
270315 velocity = [] # velocity of each atom
271- mag = [] # magnetic moment of each atom
272- angle1 = [] # angle1 of each atom
273- angle2 = [] # angle2 of each atom
316+ mags = [] # magnetic moment of each atom
274317 sc = [] # spin constraint flag of each atom
275318 lambda_ = [] # lambda of each atom
276319
277320 ntype = get_nele_from_stru (geometry_inlines )
278321 line_idx = 1 # starting line of first element
279322 for it in range (ntype ):
280323 atom_names .append (coords_lines [line_idx ].split ()[0 ])
324+ atom_type_mag = float (coords_lines [line_idx + 1 ].split ()[0 ])
281325 line_idx += 2
282326 atom_numbs .append (int (coords_lines [line_idx ].split ()[0 ]))
283327 line_idx += 1
@@ -302,17 +346,20 @@ def get_coords(celldm, cell, geometry_inlines, inlines=None):
302346 if imove is not None :
303347 move .append (imove )
304348 velocity .append (ivelocity )
305- mag .append (imagmom )
306- angle1 .append (iangle1 )
307- angle2 .append (iangle2 )
308349 sc .append (iconstrain )
309350 lambda_ .append (ilambda1 )
310351
352+ # calculate the magnetic moment in cartesian coordinates
353+ mag = get_atom_mag_cartesian (imagmom , iangle1 , iangle2 )
354+ if mag is None :
355+ mag = [0 , 0 , atom_type_mag ]
356+ mags .append (mag )
357+
311358 line_idx += 1
312359 coords = np .array (coords ) # need transformation!!!
313360 atom_types = np .array (atom_types )
314361 move = np .array (move , dtype = bool )
315- return atom_names , atom_numbs , atom_types , coords , move
362+ return atom_names , atom_numbs , atom_types , coords , move , mags
316363
317364
318365def get_energy (outlines ):
@@ -479,9 +526,12 @@ def get_frame(fname):
479526 outlines = fp .read ().split ("\n " )
480527
481528 celldm , cell = get_cell (geometry_inlines )
482- atom_names , natoms , types , coords , move = get_coords (
483- celldm , cell , geometry_inlines , inlines
529+ atom_names , natoms , types , coords , move , magmom = (
530+ get_coords ( # here the magmom is the initial magnetic moment in STRU
531+ celldm , cell , geometry_inlines , inlines
532+ )
484533 )
534+
485535 magmom , magforce = get_mag_force (outlines )
486536 if len (magmom ) > 0 :
487537 magmom = magmom [- 1 :]
@@ -565,7 +615,7 @@ def get_frame_from_stru(fname):
565615 nele = get_nele_from_stru (geometry_inlines )
566616 inlines = [f"ntype { nele } " ]
567617 celldm , cell = get_cell (geometry_inlines )
568- atom_names , natoms , types , coords , move = get_coords (
618+ atom_names , natoms , types , coords , move , magmom = get_coords (
569619 celldm , cell , geometry_inlines , inlines
570620 )
571621 data = {}
@@ -575,6 +625,7 @@ def get_frame_from_stru(fname):
575625 data ["cells" ] = cell [np .newaxis , :, :]
576626 data ["coords" ] = coords [np .newaxis , :, :]
577627 data ["orig" ] = np .zeros (3 )
628+ data ["spins" ] = np .array ([magmom ])
578629 if len (move ) > 0 :
579630 data ["move" ] = move [np .newaxis , :, :]
580631
0 commit comments