Coverage for /builds/ase/ase/ase/calculators/lammps/inputwriter.py : 75.76%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2Stream input commands to lammps to perform desired simulations
3"""
4from ase.parallel import paropen
5from ase.calculators.lammps.unitconvert import convert
7# "End mark" used to indicate that the calculation is done
8CALCULATION_END_MARK = "__end_of_ase_invoked_calculation__"
11def lammps_create_atoms(fileobj, parameters, atoms, prismobj):
12 """Create atoms in lammps with 'create_box' and 'create_atoms'
14 :param fileobj: open stream for lammps input
15 :param parameters: dict of all lammps parameters
16 :type parameters: dict
17 :param atoms: Atoms object
18 :type atoms: Atoms
19 :param prismobj: coordinate transformation between ase and lammps
20 :type prismobj: Prism
22 """
23 if parameters["verbose"]:
24 fileobj.write("## Original ase cell\n".encode("utf-8"))
25 fileobj.write(
26 "".join(
27 [
28 "# {0:.16} {1:.16} {2:.16}\n".format(*x)
29 for x in atoms.get_cell()
30 ]
31 ).encode("utf-8")
32 )
34 fileobj.write("lattice sc 1.0\n".encode("utf-8"))
36 # Get cell parameters and convert from ASE units to LAMMPS units
37 xhi, yhi, zhi, xy, xz, yz = convert(prismobj.get_lammps_prism(),
38 "distance", "ASE", parameters.units)
40 if parameters["always_triclinic"] or prismobj.is_skewed():
41 fileobj.write(
42 "region asecell prism 0.0 {0} 0.0 {1} 0.0 {2} ".format(
43 xhi, yhi, zhi
44 ).encode("utf-8")
45 )
46 fileobj.write(
47 "{0} {1} {2} side in units box\n".format(xy, xz, yz).encode(
48 "utf-8"
49 )
50 )
51 else:
52 fileobj.write(
53 "region asecell block 0.0 {0} 0.0 {1} 0.0 {2} "
54 "side in units box\n".format(xhi, yhi, zhi).encode("utf-8")
55 )
57 symbols = atoms.get_chemical_symbols()
58 try:
59 # By request, specific atom type ordering
60 species = parameters["specorder"]
61 except AttributeError:
62 # By default, atom types in alphabetic order
63 species = sorted(set(symbols))
65 species_i = {s: i + 1 for i, s in enumerate(species)}
67 fileobj.write(
68 "create_box {0} asecell\n" "".format(len(species)).encode("utf-8")
69 )
70 for sym, pos in zip(symbols, atoms.get_positions()):
71 # Convert position from ASE units to LAMMPS units
72 pos = convert(pos, "distance", "ASE", parameters.units)
73 if parameters["verbose"]:
74 fileobj.write(
75 "# atom pos in ase cell: {0:.16} {1:.16} {2:.16}\n"
76 "".format(*tuple(pos)).encode("utf-8")
77 )
78 fileobj.write(
79 "create_atoms {0} single {1} {2} {3} remap yes units box\n".format(
80 *((species_i[sym],) + tuple(prismobj.vector_to_lammps(pos)))
81 ).encode("utf-8")
82 )
85def write_lammps_in(lammps_in, parameters, atoms, prismobj,
86 lammps_trj=None, lammps_data=None):
87 """Write a LAMMPS in_ file with run parameters and settings."""
89 def write_model_post_and_masses(fileobj, parameters):
90 # write additional lines needed for some LAMMPS potentials
91 if 'model_post' in parameters:
92 mlines = parameters['model_post']
93 for ii in range(0, len(mlines)):
94 fileobj.write(mlines[ii].encode('utf-8'))
96 if "masses" in parameters:
97 for mass in parameters["masses"]:
98 # Note that the variable mass is a string containing
99 # the type number and value of mass separated by a space
100 fileobj.write("mass {0} \n".format(mass).encode("utf-8"))
102 if isinstance(lammps_in, str):
103 fileobj = paropen(lammps_in, "wb")
104 close_in_file = True
105 else:
106 # Expect lammps_in to be a file-like object
107 fileobj = lammps_in
108 close_in_file = False
110 if parameters["verbose"]:
111 fileobj.write("# (written by ASE)\n".encode("utf-8"))
113 # Write variables
114 fileobj.write(
115 (
116 "clear\n"
117 'variable dump_file string "{0}"\n'
118 'variable data_file string "{1}"\n'
119 )
120 .format(lammps_trj, lammps_data)
121 .encode("utf-8")
122 )
124 if "package" in parameters:
125 fileobj.write(
126 (
127 "\n".join(
128 ["package {0}".format(p) for p in parameters["package"]]
129 )
130 + "\n"
131 ).encode("utf-8")
132 )
134 # setup styles except 'pair_style'
135 for style_type in ("atom", "bond", "angle",
136 "dihedral", "improper", "kspace"):
137 style = style_type + "_style"
138 if style in parameters:
139 fileobj.write(
140 '{} {} \n'.format(
141 style,
142 parameters[style]).encode("utf-8"))
144 # write initialization lines needed for some LAMMPS potentials
145 if 'model_init' in parameters:
146 mlines = parameters['model_init']
147 for ii in range(0, len(mlines)):
148 fileobj.write(mlines[ii].encode('utf-8'))
150 # write units
151 if 'units' in parameters:
152 units_line = 'units ' + parameters['units'] + '\n'
153 fileobj.write(units_line.encode('utf-8'))
154 else:
155 fileobj.write('units metal\n'.encode('utf-8'))
157 pbc = atoms.get_pbc()
158 if "boundary" in parameters:
159 fileobj.write(
160 "boundary {0} \n".format(parameters["boundary"]).encode("utf-8")
161 )
162 else:
163 fileobj.write(
164 "boundary {0} {1} {2} \n".format(
165 *tuple("sp"[int(x)] for x in pbc)
166 ).encode("utf-8")
167 )
168 fileobj.write("atom_modify sort 0 0.0 \n".encode("utf-8"))
169 for key in ("neighbor", "newton"):
170 if key in parameters:
171 fileobj.write(
172 "{0} {1} \n".format(key, parameters[key]).encode("utf-8")
173 )
174 fileobj.write("\n".encode("utf-8"))
176 # write the simulation box and the atoms
177 if not lammps_data:
178 lammps_create_atoms(fileobj, parameters, atoms, prismobj)
179 # or simply refer to the data-file
180 else:
181 fileobj.write("read_data {0}\n".format(lammps_data).encode("utf-8"))
183 # Write interaction stuff
184 fileobj.write("\n### interactions\n".encode("utf-8"))
185 if "kim_interactions" in parameters:
186 fileobj.write(
187 "{}\n".format(
188 parameters["kim_interactions"]).encode("utf-8"))
189 write_model_post_and_masses(fileobj, parameters)
191 elif ("pair_style" in parameters) and ("pair_coeff" in parameters):
192 pair_style = parameters["pair_style"]
193 fileobj.write("pair_style {0} \n".format(pair_style).encode("utf-8"))
194 for pair_coeff in parameters["pair_coeff"]:
195 fileobj.write(
196 "pair_coeff {0} \n" "".format(pair_coeff).encode("utf-8")
197 )
198 write_model_post_and_masses(fileobj, parameters)
200 else:
201 # simple default parameters
202 # that should always make the LAMMPS calculation run
203 fileobj.write(
204 "pair_style lj/cut 2.5 \n"
205 "pair_coeff * * 1 1 \n"
206 "mass * 1.0 \n".encode("utf-8")
207 )
209 if "group" in parameters:
210 fileobj.write(
211 (
212 "\n".join(["group {0}".format(p) for p in parameters["group"]])
213 + "\n"
214 ).encode("utf-8")
215 )
217 fileobj.write("\n### run\n" "fix fix_nve all nve\n".encode("utf-8"))
219 if "fix" in parameters:
220 fileobj.write(
221 (
222 "\n".join(["fix {0}".format(p) for p in parameters["fix"]])
223 + "\n"
224 ).encode("utf-8")
225 )
227 fileobj.write(
228 "dump dump_all all custom {1} {0} id type x y z vx vy vz "
229 "fx fy fz\n"
230 "".format(lammps_trj, parameters["dump_period"]).encode("utf-8")
231 )
232 fileobj.write(
233 "thermo_style custom {0}\n"
234 "thermo_modify flush yes format float %23.16g\n"
235 "thermo 1\n".format(" ".join(parameters["thermo_args"])).encode(
236 "utf-8"
237 )
238 )
240 if "timestep" in parameters:
241 fileobj.write(
242 "timestep {0}\n".format(parameters["timestep"]).encode("utf-8")
243 )
245 if "minimize" in parameters:
246 fileobj.write(
247 "minimize {0}\n".format(parameters["minimize"]).encode("utf-8")
248 )
249 if "run" in parameters:
250 fileobj.write("run {0}\n".format(parameters["run"]).encode("utf-8"))
251 if not (("minimize" in parameters) or ("run" in parameters)):
252 fileobj.write("run 0\n".encode("utf-8"))
254 fileobj.write(
255 'print "{0}" \n'.format(CALCULATION_END_MARK).encode("utf-8")
256 )
257 # Force LAMMPS to flush log
258 fileobj.write("log /dev/stdout\n".encode("utf-8"))
260 fileobj.flush()
261 if close_in_file:
262 fileobj.close()