@@ -23,27 +23,42 @@ def _setup(self, *args, **kwargs):
2323 self ._scale = 1.
2424
2525 @sile_fh_open ()
26- def write_geometry (self , geometry , dynamic = True ):
26+ def write_geometry (self , geometry , dynamic = True , group_species = False ):
2727 r""" Writes the geometry to the contained file
2828
2929 Parameters
3030 ----------
3131 geometry : Geometry
3232 geometry to be written to the file
33- dynamic : bool or list, optional
33+ dynamic : None, bool or list, optional
3434 define which atoms are dynamic in the VASP run (default is True,
35- which means all atoms are dynamic)
35+ which means all atoms are dynamic).
36+ If None, the resulting file will not contain any dynamic flags
37+ group_species: bool, optional
38+ before writing `geometry` first re-order species to
39+ have species in consecutive blocks (see `geometry_group`)
3640
3741 Examples
3842 --------
3943 >>> car = carSileVASP('POSCAR', 'w')
4044 >>> geom = geom.graphene()
45+ >>> geom.write(car) # regular car without Selective Dynamics
4146 >>> geom.write(car, dynamic=False) # fix all atoms
4247 >>> geom.write(car, dynamic=[False, (True, False, True)]) # fix 1st and y coordinate of 2nd
48+
49+ See Also
50+ --------
51+ geometry_group: method used to group atoms together according to their species
4352 """
4453 # Check that we can write to the file
4554 sile_raise_write (self )
4655
56+ if group_species :
57+ geometry , idx = self .geometry_group (geometry , ret_index = True )
58+ else :
59+ # small hack to allow dynamic
60+ idx = _a .arangei (len (geometry ))
61+
4762 # LABEL
4863 self ._write ('sisl output\n ' )
4964
@@ -52,10 +67,8 @@ def write_geometry(self, geometry, dynamic=True):
5267
5368 # Write unit-cell
5469 fmt = (' ' + '{:18.9f}' * 3 ) + '\n '
55- tmp = np .zeros ([3 ], np .float64 )
5670 for i in range (3 ):
57- tmp [:3 ] = geometry .cell [i , :]
58- self ._write (fmt .format (* tmp ))
71+ self ._write (fmt .format (* geometry .cell [i ]))
5972
6073 # Figure out how many species
6174 pt = PeriodicTable ()
@@ -78,21 +91,26 @@ def write_geometry(self, geometry, dynamic=True):
7891 self ._write (fmt .format (* s ))
7992 fmt = ' {:d}' * len (d ) + '\n '
8093 self ._write (fmt .format (* d ))
81- self ._write ('Selective dynamics\n ' )
94+ if dynamic is None :
95+ # We write in direct mode
96+ dynamic = [None ] * len (geometry )
97+ def todyn (fix ):
98+ return '\n '
99+ else :
100+ self ._write ('Selective dynamics\n ' )
101+ b2s = {True : 'T' , False : 'F' }
102+ def todyn (fix ):
103+ if isinstance (fix , bool ):
104+ return ' {0} {0} {0}\n ' .format (b2s [fix ])
105+ return ' {} {} {}\n ' .format (b2s [fix [0 ]], b2s [fix [1 ]], b2s [fix [2 ]])
82106 self ._write ('Cartesian\n ' )
83107
84108 if isinstance (dynamic , bool ):
85109 dynamic = [dynamic ] * len (geometry )
86110
87- b2s = {True : 'T' , False : 'F' }
88- def todyn (fix ):
89- if isinstance (fix , bool ):
90- return '{0} {0} {0}\n ' .format (b2s [fix ])
91- return '{} {} {}\n ' .format (b2s [fix [0 ]], b2s [fix [1 ]], b2s [fix [2 ]])
92-
93- fmt = '{:18.9f} ' * 3
111+ fmt = '{:18.9f}' * 3
94112 for ia in geometry :
95- self ._write (fmt .format (* geometry .xyz [ia , :]) + todyn (dynamic [ia ]))
113+ self ._write (fmt .format (* geometry .xyz [ia , :]) + todyn (dynamic [idx [ ia ] ]))
96114
97115 @sile_fh_open (True )
98116 def read_supercell (self ):
@@ -115,12 +133,13 @@ def read_supercell(self):
115133 def read_geometry (self , ret_dynamic = False ):
116134 r""" Returns Geometry object from the CONTCAR/POSCAR file
117135
118- Possibly also return the dynamics (if present)
136+ Possibly also return the dynamics (if present).
119137
120138 Parameters
121139 ----------
122140 ret_dynamic : bool, optional
123- also read selective dynamics (if present), if not, a list of True will be returned
141+ also return selective dynamics (if present), if not, None will
142+ be returned.
124143 """
125144 sc = self .read_supercell ()
126145
@@ -148,25 +167,26 @@ def read_geometry(self, ret_dynamic=False):
148167 for spec , nsp in zip (species , species_count )
149168 for i in range (nsp )]
150169
151- # Read whether this is selective or direct
152- # Currently direct is not used
170+ # Number of atoms
171+ na = len (atom )
172+
173+ # check whether this is Selective Dynamics
153174 opt = self .readline ()
154- dynamics = False
155175 if opt [0 ] in 'Ss' :
156176 dynamics = True
177+ # pre-create the dynamic list
178+ dynamic = np .empty ([na , 3 ], dtype = np .bool_ )
157179 opt = self .readline ()
180+ else :
181+ dynamics = False
182+ dynamic = None
158183
159184 # Check whether this is in fractional or direct
160- # coordinates
185+ # coordinates (Direct == fractional)
161186 cart = False
162187 if opt [0 ] in 'CcKk' :
163188 cart = True
164189
165- # Number of atoms
166- na = len (atom )
167- # pre-create the dynamic list
168- dynamic = [[False ] * 3 ] * na
169-
170190 xyz = _a .emptyd ([na , 3 ])
171191 for ia in range (na ):
172192 line = self .readline ().split ()
@@ -183,7 +203,7 @@ def read_geometry(self, ret_dynamic=False):
183203 # The POT/CONT-CAR does not contain information on the atomic species
184204 geom = Geometry (xyz = xyz , atom = atom , sc = sc )
185205 if ret_dynamic :
186- return geom , np . array ( dynamic , dtype = np . bool_ )
206+ return geom , dynamic
187207 return geom
188208
189209 def ArgumentParser (self , p = None , * args , ** kwargs ):
0 commit comments