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 )
@@ -70,9 +80,18 @@ def write_geometry(self, geometry):
7080 self ._write ('Selective dynamics\n ' )
7181 self ._write ('Cartesian\n ' )
7282
73- fmt = '{:18.9f}' * 3 + ' F F F\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
7493 for ia in geometry :
75- self ._write (fmt .format (* geometry .xyz [ia , :]))
94+ self ._write (fmt .format (* geometry .xyz [ia , :]) + todyn ( fixed [ ia ]) )
7695
7796 @sile_fh_open (True )
7897 def read_supercell (self ):
@@ -92,8 +111,15 @@ def read_supercell(self):
92111 return SuperCell (cell )
93112
94113 @sile_fh_open ()
95- def read_geometry (self ):
96- """ 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
97123 """
98124 sc = self .read_supercell ()
99125
@@ -124,9 +150,9 @@ def read_geometry(self):
124150 # Read whether this is selective or direct
125151 # Currently direct is not used
126152 opt = self .readline ()
127- #direct = True
153+ dynamics = False
128154 if opt [0 ] in 'Ss' :
129- #direct = False
155+ dynamics = True
130156 opt = self .readline ()
131157
132158 # Check whether this is in fractional or direct
@@ -137,18 +163,27 @@ def read_geometry(self):
137163
138164 # Number of atoms
139165 na = len (atom )
166+ # pre-create the fixed list
167+ fixed = [[False ] * 3 ] * na
140168
141- xyz = np . empty ([na , 3 ], np . float64 )
169+ xyz = _a . emptyd ([na , 3 ])
142170 for ia in range (na ):
143- 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+
144176 if cart :
145177 # The unit of the coordinates are cartesian
146178 xyz *= self ._scale
147179 else :
148- xyz = np .dot (xyz , sc .cell )
180+ xyz = xyz .dot (sc .cell )
149181
150182 # The POT/CONT-CAR does not contain information on the atomic species
151- 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
152187
153188 def ArgumentParser (self , p = None , * args , ** kwargs ):
154189 """ Returns the arguments that is available for this Sile """
0 commit comments