1- import decimal as dec
21import importlib
32import os
43import warnings
@@ -29,6 +28,7 @@ def __init__(
2928 self ._cores = cores
3029 if library is not None :
3130 self ._interactive_library = library
31+ self ._cores = library .cores
3232 elif self ._cores == 1 :
3333 lammps = getattr (importlib .import_module ("lammps" ), "lammps" )
3434 if diable_log_file :
@@ -58,14 +58,13 @@ def interactive_positions_getter(self):
5858 np .array (self ._interactive_library .gather_atoms ("x" , 1 , 3 )),
5959 (len (self ._structure ), 3 ),
6060 )
61- if _check_ortho_prism (prism = self ._prism ):
62- positions = np . matmul ( positions , self ._prism .R . T )
61+ if not _check_ortho_prism (prism = self ._prism ):
62+ positions = self ._prism .vector_to_ase ( positions )
6363 return positions
6464
6565 def interactive_positions_setter (self , positions ):
66- if _check_ortho_prism (prism = self ._prism ):
67- positions = np .array (positions ).reshape (- 1 , 3 )
68- positions = np .matmul (positions , self ._prism .R )
66+ if not _check_ortho_prism (prism = self ._prism ):
67+ positions = self ._prism .vector_to_lammps (positions )
6968 positions = np .array (positions ).flatten ()
7069 if self ._cores == 1 :
7170 self ._interactive_library .scatter_atoms (
@@ -91,12 +90,12 @@ def interactive_cells_getter(self):
9190 ],
9291 ]
9392 )
94- return self ._prism .unfold_cell (cc )
93+ return self ._prism .vector_to_ase (cc )
9594
9695 def interactive_cells_setter (self , cell ):
97- self ._prism = UnfoldingPrism (cell )
96+ self ._prism = Prism (cell )
9897 lx , ly , lz , xy , xz , yz = self ._prism .get_lammps_prism ()
99- if _check_ortho_prism (prism = self ._prism ):
98+ if not _check_ortho_prism (prism = self ._prism ):
10099 warnings .warn (
101100 "Warning: setting upper trangular matrix might slow down the calculation"
102101 )
@@ -131,8 +130,8 @@ def interactive_forces_getter(self):
131130 np .array (self ._interactive_library .gather_atoms ("f" , 1 , 3 )),
132131 (len (self ._structure ), 3 ),
133132 )
134- if _check_ortho_prism (prism = self ._prism ):
135- ff = np . matmul ( ff , self ._prism .R . T )
133+ if not _check_ortho_prism (prism = self ._prism ):
134+ ff = self ._prism .vector_to_ase ( ff )
136135 return ff
137136
138137 def interactive_structure_setter (
@@ -153,8 +152,8 @@ def interactive_structure_setter(
153152 self .interactive_lib_command (command = "atom_style " + atom_style )
154153
155154 self .interactive_lib_command (command = "atom_modify map array" )
156- self ._prism = UnfoldingPrism (structure .cell )
157- if _check_ortho_prism (prism = self ._prism ):
155+ self ._prism = Prism (structure .cell )
156+ if not _check_ortho_prism (prism = self ._prism ):
158157 warnings .warn (
159158 "Warning: setting upper trangular matrix might slow down the calculation"
160159 )
@@ -214,11 +213,10 @@ def interactive_structure_setter(
214213 self .interactive_lib_command (
215214 command = "mass {0:3d} {1:f}" .format (id_eam + 1 , 1.00 ),
216215 )
217- positions = structure .positions .flatten ()
218- if _check_ortho_prism (prism = self ._prism ):
219- positions = np .array (positions ).reshape (- 1 , 3 )
220- positions = np .matmul (positions , self ._prism .R )
221- positions = positions .flatten ()
216+ if not _check_ortho_prism (prism = self ._prism ):
217+ positions = self ._prism .vector_to_lammps (structure .positions ).flatten ()
218+ else :
219+ positions = structure .positions .flatten ()
222220 try :
223221 elem_all = get_lammps_indicies_from_ase_structure (
224222 structure = structure , el_eam_lst = el_eam_lst
@@ -242,7 +240,7 @@ def interactive_structure_setter(
242240 else :
243241 self ._interactive_library .create_atoms (
244242 n = len (structure ),
245- id = None ,
243+ id = range ( 1 , len ( structure ) + 1 ) ,
246244 type = elem_all ,
247245 x = positions ,
248246 v = None ,
@@ -289,9 +287,8 @@ def interactive_pressures_getter(self):
289287 ],
290288 ]
291289 )
292- if _check_ortho_prism (prism = self ._prism ):
293- rotation_matrix = self ._prism .R .T
294- pp = rotation_matrix .T @ pp @ rotation_matrix
290+ if not _check_ortho_prism (prism = self ._prism ):
291+ pp = self ._prism .tensor2_to_ase (pp )
295292 return pp
296293
297294 def interactive_indices_setter (self , indices , el_eam_lst ):
@@ -316,7 +313,7 @@ def interactive_stress_getter(self, enable_stress_computation=True):
316313 if enable_stress_computation :
317314 self .interactive_lib_command ("compute st all stress/atom NULL" )
318315 self .interactive_lib_command ("run 0" )
319- id_lst = self ._interactive_library .extract_atom ("id" , 0 )
316+ id_lst = self ._interactive_library .extract_atom ("id" )
320317 id_lst = np .array ([id_lst [i ] for i in range (len (self ._structure ))]) - 1
321318 id_lst = np .arange (len (id_lst ))[np .argsort (id_lst )]
322319 ind = np .array ([0 , 3 , 4 , 3 , 1 , 5 , 4 , 5 , 2 ])
@@ -330,18 +327,18 @@ def interactive_stress_getter(self, enable_stress_computation=True):
330327 * constants .bar
331328 * constants .angstrom ** 3
332329 )
333- if _check_ortho_prism (prism = self ._prism ):
334- ss = np .einsum ("ij,njk->nik" , self ._prism .R , ss )
335- ss = np .einsum ("nij,kj->nik" , ss , self ._prism .R )
330+ if not _check_ortho_prism (prism = self ._prism ):
331+ ss = np .einsum ("ij,njk->nik" , self ._prism .rot_mat , ss )
332+ ss = np .einsum ("nij,kj->nik" , ss , self ._prism .rot_mat )
336333 return ss
337334
338335 def interactive_velocities_getter (self ):
339336 velocity = np .reshape (
340337 np .array (self ._interactive_library .gather_atoms ("v" , 1 , 3 )),
341338 (len (self ._structure ), 3 ),
342339 )
343- if _check_ortho_prism (prism = self ._prism ):
344- velocity = np . matmul ( velocity , self ._prism .R . T )
340+ if not _check_ortho_prism (prism = self ._prism ):
341+ velocity = self ._prism .vector_to_ase ( velocity )
345342 return velocity
346343
347344 def close (self ):
@@ -366,153 +363,6 @@ def __exit__(self, exc_type, exc_val, exc_tb):
366363 self .close ()
367364
368365
369- class UnfoldingPrism (Prism ):
370- """
371- Create a lammps-style triclinic prism object from a cell
372-
373- The main purpose of the prism-object is to create suitable
374- string representations of prism limits and atom positions
375- within the prism.
376- When creating the object, the digits parameter (default set to 10)
377- specify the precision to use.
378- lammps is picky about stuff being within semi-open intervals,
379- e.g. for atom positions (when using create_atom in the in-file),
380- x must be within [xlo, xhi).
381-
382- Args:
383- cell:
384- pbc:
385- digits:
386- """
387-
388- def __init__ (self , cell , pbc = (True , True , True ), digits = 10 ):
389- # Temporary fix. Since the arguments for the constructor have changed, try to see if it is compatible with
390- # the latest ase. If not, revert to the old __init__ parameters.
391- try :
392- super (UnfoldingPrism , self ).__init__ (
393- cell , pbc = pbc , tolerance = float ("1e-{}" .format (digits ))
394- )
395- except TypeError :
396- super (UnfoldingPrism , self ).__init__ (cell , pbc = pbc , digits = digits )
397- a , b , c = cell
398- an , bn , cn = [np .linalg .norm (v ) for v in cell ]
399-
400- alpha = np .arccos (np .dot (b , c ) / (bn * cn ))
401- beta = np .arccos (np .dot (a , c ) / (an * cn ))
402- gamma = np .arccos (np .dot (a , b ) / (an * bn ))
403-
404- xhi = an
405- xyp = np .cos (gamma ) * bn
406- yhi = np .sin (gamma ) * bn
407- xzp = np .cos (beta ) * cn
408- yzp = (bn * cn * np .cos (alpha ) - xyp * xzp ) / yhi
409- zhi = np .sqrt (cn ** 2 - xzp ** 2 - yzp ** 2 )
410-
411- # Set precision
412- self .car_prec = dec .Decimal ("10.0" ) ** int (
413- np .floor (np .log10 (max ((xhi , yhi , zhi )))) - digits
414- )
415- self .dir_prec = dec .Decimal ("10.0" ) ** (- digits )
416- self .acc = float (self .car_prec )
417- self .eps = np .finfo (xhi ).eps
418-
419- # For rotating positions from ase to lammps
420- apre = np .array (((xhi , 0 , 0 ), (xyp , yhi , 0 ), (xzp , yzp , zhi )))
421- # np.linalg.inv(cell) ?= np.array([np.cross(b, c), np.cross(c, a), np.cross(a, b)]).T / np.linalg.det(cell)
422- self .R = np .dot (np .linalg .inv (cell ), apre )
423-
424- def fold (vec , pvec , i ):
425- p = pvec [i ]
426- x = vec [i ] + 0.5 * p
427- n = (np .mod (x , p ) - x ) / p
428- return [float (self .f2qdec (vec_a )) for vec_a in (vec + n * pvec )], n
429-
430- apre [1 , :], n1 = fold (apre [1 , :], apre [0 , :], 0 )
431- if np .abs (apre [1 , 0 ] / apre [0 , 0 ]) > 0.5 :
432- apre [1 , 0 ] -= np .sign (n1 ) * apre [0 , 0 ]
433- n1 -= np .sign (n1 )
434-
435- apre [2 , :], n2 = fold (apre [2 , :], apre [1 , :], 1 )
436- if np .abs (apre [2 , 1 ] / apre [1 , 1 ]) > 0.5 :
437- apre [2 , 1 ] -= np .sign (n2 ) * apre [1 , 1 ]
438- n2 -= np .sign (n2 )
439-
440- apre [2 , :], n3 = fold (apre [2 , :], apre [0 , :], 0 )
441- if np .abs (apre [2 , 0 ] / apre [0 , 0 ]) > 0.5 :
442- apre [2 , 0 ] -= np .sign (n3 ) * apre [0 , 0 ]
443- n3 -= np .sign (n3 )
444- self .ns = [n1 , n2 , n3 ]
445-
446- d_a = apre [0 , 0 ] / 2 - apre [1 , 0 ]
447- if np .abs (d_a ) < self .acc :
448- if d_a < 0 :
449- print ("debug: apply shift" )
450- apre [1 , 0 ] += 2 * d_a
451- apre [2 , 0 ] += 2 * d_a
452-
453- self .A = apre
454-
455- if self .is_skewed () and (not (pbc [0 ] and pbc [1 ] and pbc [2 ])):
456- warnings .warn (
457- "Skewed lammps cells should have PBC == True in all directions!"
458- )
459-
460- def unfold_cell (self , cell ):
461- """
462- Unfold LAMMPS cell to original
463-
464- Let C be the pyiron_atomistics cell and A be the Lammps cell, then define (in init) the rotation matrix between them as
465- R := C^inv.A
466- And recall that rotation matrices have the property
467- R^T == R^inv
468- Then left multiply the definition of R by C, and right multiply by R.T to get
469- C.R.R^T = C.C^inv.A.R^T
470- Then
471- C = A.R^T
472-
473- After that, account for the folding process.
474-
475- Args:
476- cell: LAMMPS cell,
477-
478- Returns:
479- unfolded cell
480- """
481- # Rotation
482- ucell = np .dot (cell , self .R .T )
483- # Folding
484- a = ucell [0 ]
485- bp = ucell [1 ]
486- cpp = ucell [2 ]
487- (n1 , n2 , n3 ) = self .ns
488- b = bp - n1 * a
489- c = cpp - n2 * bp - n3 * a
490- return np .array ([a , b , c ])
491-
492- def pos_to_lammps (self , position ):
493- """
494- Rotate an ase-cell position to the lammps cell orientation
495-
496- Args:
497- position:
498-
499- Returns:
500- tuple of float.
501- """
502- return tuple ([x for x in np .dot (position , self .R )])
503-
504- def f2qdec (self , f ):
505- return dec .Decimal (repr (f )).quantize (self .car_prec , dec .ROUND_DOWN )
506-
507- def f2s (self , f ):
508- return str (dec .Decimal (repr (f )).quantize (self .car_prec , dec .ROUND_HALF_EVEN ))
509-
510- def get_lammps_prism_str (self ):
511- """Return a tuple of strings"""
512- p = self .get_lammps_prism ()
513- return tuple ([self .f2s (x ) for x in p ])
514-
515-
516366def cell_is_skewed (cell , tolerance = 1.0e-8 ):
517367 """
518368 Check whether the simulation box is skewed/sheared. The algorithm compares the box volume
@@ -538,14 +388,14 @@ def _check_ortho_prism(prism, rtol=0.0, atol=1e-08):
538388 Check if the rotation matrix of the UnfoldingPrism object is sufficiently close to a unit matrix
539389
540390 Args:
541- prism (pyiron_atomistics. lammps.structure.UnfoldingPrism ): UnfoldingPrism object to check
391+ prism (ase.calculators. lammps.Prism ): Prism object to check
542392 rtol (float): relative precision for numpy.isclose()
543393 atol (float): absolute precision for numpy.isclose()
544394
545395 Returns:
546396 boolean: True or False
547397 """
548- return np .isclose (prism .R , np .eye (3 ), rtol = rtol , atol = atol ).all ()
398+ return np .isclose (prism .rot_mat , np .eye (3 ), rtol = rtol , atol = atol ).all ()
549399
550400
551401def get_species_symbols (structure ):
0 commit comments