55from ..sile import *
66
77# Import the geometry object
8+ import sisl ._array as _a
89from sisl .messages import warn
910from sisl import Geometry , PeriodicTable , Atom , SuperCell
1011
@@ -22,13 +23,22 @@ def _setup(self, *args, **kwargs):
2223 self ._scale = 1.
2324
2425 @sile_fh_open ()
25- def write_geometry (self , geometry ):
26- """ Writes the geometry to the contained file
26+ def write_geometry (self , geometry , fixed = False ):
27+ r """ Writes the geometry to the contained file
2728
2829 Parameters
2930 ----------
3031 geometry : Geometry
3132 geometry to be written to the file
33+ fixed : bool or list, optional
34+ define which atoms to be fixed in the VASP run
35+
36+ Examples
37+ --------
38+ >>> car = carSileVASP('POSCAR', 'w')
39+ >>> geom = geom.graphene()
40+ >>> geom.write(car, fixed=False) # fix none
41+ >>> geom.write(car, fixed=[True, (False, True, False)]) # fix 1st and y coordinate of 2nd
3242 """
3343 # Check that we can write to the file
3444 sile_raise_write (self )
@@ -67,11 +77,21 @@ def write_geometry(self, geometry):
6777 self ._write (fmt .format (* s ))
6878 fmt = ' {:d}' * len (d ) + '\n '
6979 self ._write (fmt .format (* d ))
80+ self ._write ('Selective dynamics\n ' )
7081 self ._write ('Cartesian\n ' )
7182
72- fmt = '{:18.9f}' * 3 + '\n '
83+ if isinstance (fixed , bool ):
84+ fixed = [fixed ] * len (geometry )
85+
86+ b2s = {True : 'T' , False : 'F' }
87+ def todyn (fix ):
88+ if isinstance (fix , bool ):
89+ return '{0} {0} {0}\n ' .format (b2s [fix ])
90+ return '{} {} {}\n ' .format (b2s [fix [0 ]], b2s [fix [1 ]], b2s [fix [2 ]])
91+
92+ fmt = '{:18.9f} ' * 3
7393 for ia in geometry :
74- self ._write (fmt .format (* geometry .xyz [ia , :]))
94+ self ._write (fmt .format (* geometry .xyz [ia , :]) + todyn ( fixed [ ia ]) )
7595
7696 @sile_fh_open (True )
7797 def read_supercell (self ):
@@ -91,8 +111,15 @@ def read_supercell(self):
91111 return SuperCell (cell )
92112
93113 @sile_fh_open ()
94- def read_geometry (self ):
95- """ Returns Geometry object from the CONTCAR/POSCAR file
114+ def read_geometry (self , ret_fixed = False ):
115+ r""" Returns Geometry object from the CONTCAR/POSCAR file
116+
117+ Possibly also return the dynamics (if present)
118+
119+ Parameters
120+ ----------
121+ ret_fixed : bool, optional
122+ also read selective dynamics (if present), if not, a list of False will be returned
96123 """
97124 sc = self .read_supercell ()
98125
@@ -123,9 +150,9 @@ def read_geometry(self):
123150 # Read whether this is selective or direct
124151 # Currently direct is not used
125152 opt = self .readline ()
126- #direct = True
153+ dynamics = False
127154 if opt [0 ] in 'Ss' :
128- #direct = False
155+ dynamics = True
129156 opt = self .readline ()
130157
131158 # Check whether this is in fractional or direct
@@ -136,18 +163,27 @@ def read_geometry(self):
136163
137164 # Number of atoms
138165 na = len (atom )
166+ # pre-create the fixed list
167+ fixed = [[False ] * 3 ] * na
139168
140- xyz = np . empty ([na , 3 ], np . float64 )
169+ xyz = _a . emptyd ([na , 3 ])
141170 for ia in range (na ):
142- xyz [ia , :] = list (map (float , self .readline ().split ()[:3 ]))
171+ line = self .readline ().split ()
172+ xyz [ia , :] = list (map (float , line [:3 ]))
173+ if dynamics :
174+ fixed [ia ] = list (map (lambda x : x .lower () == 't' , line [3 :6 ]))
175+
143176 if cart :
144177 # The unit of the coordinates are cartesian
145178 xyz *= self ._scale
146179 else :
147- xyz = np .dot (xyz , sc .cell )
180+ xyz = xyz .dot (sc .cell )
148181
149182 # The POT/CONT-CAR does not contain information on the atomic species
150- return Geometry (xyz = xyz , atom = atom , sc = sc )
183+ geom = Geometry (xyz = xyz , atom = atom , sc = sc )
184+ if ret_fixed :
185+ return geom , np .array (fixed , dtype = np .bool_ )
186+ return geom
151187
152188 def ArgumentParser (self , p = None , * args , ** kwargs ):
153189 """ Returns the arguments that is available for this Sile """
0 commit comments