calphy 1.3.13__py3-none-any.whl → 1.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- calphy/__init__.py +1 -1
- calphy/alchemy.py +66 -8
- calphy/clitools.py +6 -0
- calphy/composition_transformation.py +63 -9
- calphy/helpers.py +6 -2
- calphy/input.py +478 -245
- calphy/kernel.py +3 -1
- calphy/liquid.py +199 -118
- calphy/phase.py +810 -381
- calphy/phase_diagram.py +500 -26
- calphy/postprocessing.py +192 -4
- calphy/routines.py +13 -2
- calphy/scheduler.py +2 -0
- calphy/solid.py +35 -0
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/METADATA +14 -2
- calphy-1.4.2.dist-info/RECORD +25 -0
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/WHEEL +1 -1
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/entry_points.txt +1 -0
- calphy-1.3.13.dist-info/RECORD +0 -25
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info/licenses}/LICENSE +0 -0
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/top_level.txt +0 -0
calphy/phase.py
CHANGED
|
@@ -6,14 +6,14 @@ calphy: a Python library and command line interface for automated free
|
|
|
6
6
|
energy calculations.
|
|
7
7
|
|
|
8
8
|
Copyright 2021 (c) Sarath Menon^1, Yury Lysogorskiy^2, Ralf Drautz^2
|
|
9
|
-
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
|
|
9
|
+
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
|
|
10
10
|
^2: Ruhr-University Bochum, Bochum, Germany
|
|
11
11
|
|
|
12
|
-
calphy is published and distributed under the Academic Software License v1.0 (ASL).
|
|
13
|
-
calphy is distributed in the hope that it will be useful for non-commercial academic research,
|
|
14
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
12
|
+
calphy is published and distributed under the Academic Software License v1.0 (ASL).
|
|
13
|
+
calphy is distributed in the hope that it will be useful for non-commercial academic research,
|
|
14
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
15
15
|
calphy API is published and distributed under the BSD 3-Clause "New" or "Revised" License
|
|
16
|
-
See the LICENSE FILE for more details.
|
|
16
|
+
See the LICENSE FILE for more details.
|
|
17
17
|
|
|
18
18
|
More information about the program can be found in:
|
|
19
19
|
Menon, Sarath, Yury Lysogorskiy, Jutta Rogal, and Ralf Drautz.
|
|
@@ -37,6 +37,7 @@ import calphy.helpers as ph
|
|
|
37
37
|
from calphy.errors import *
|
|
38
38
|
from calphy.input import generate_metadata
|
|
39
39
|
|
|
40
|
+
|
|
40
41
|
class Phase:
|
|
41
42
|
"""
|
|
42
43
|
Class for free energy calculation.
|
|
@@ -45,74 +46,85 @@ class Phase:
|
|
|
45
46
|
----------
|
|
46
47
|
input : Calculation class
|
|
47
48
|
input options
|
|
48
|
-
|
|
49
|
+
|
|
49
50
|
simfolder : string
|
|
50
51
|
base folder for running calculations
|
|
51
52
|
|
|
52
53
|
"""
|
|
54
|
+
|
|
53
55
|
def __init__(self, calculation=None, simfolder=None, log_to_screen=False):
|
|
54
56
|
|
|
55
57
|
self.calc = copy.deepcopy(calculation)
|
|
56
|
-
|
|
57
|
-
#serialise input
|
|
58
|
+
|
|
59
|
+
# serialise input
|
|
58
60
|
indict = {"calculations": [self.calc.dict()]}
|
|
59
|
-
with open(os.path.join(simfolder,
|
|
61
|
+
with open(os.path.join(simfolder, "input_file.yaml"), "w") as fout:
|
|
60
62
|
yaml.safe_dump(indict, fout)
|
|
61
63
|
|
|
62
|
-
#serialise input configuration
|
|
63
|
-
shutil.copy(self.calc.lattice, os.path.join(simfolder, 'input_configuration.data'))
|
|
64
|
-
|
|
65
|
-
#write simple metadata
|
|
66
|
-
with open(os.path.join(simfolder, 'metadata.yaml'), 'w') as fout:
|
|
67
|
-
yaml.safe_dump(generate_metadata(), fout)
|
|
68
|
-
|
|
69
|
-
|
|
70
64
|
self.simfolder = simfolder
|
|
71
65
|
self.log_to_screen = log_to_screen
|
|
72
|
-
|
|
66
|
+
self.publications = []
|
|
67
|
+
|
|
73
68
|
logfile = os.path.join(self.simfolder, "calphy.log")
|
|
74
69
|
self.logger = ph.prepare_log(logfile, screen=log_to_screen)
|
|
75
70
|
|
|
76
71
|
if self.calc._pressure is None:
|
|
77
72
|
pressure_string = "None"
|
|
78
73
|
else:
|
|
79
|
-
pressure_string = "%f"%self.calc._pressure
|
|
74
|
+
pressure_string = "%f" % self.calc._pressure
|
|
80
75
|
|
|
81
|
-
self.logger.info(
|
|
82
|
-
|
|
76
|
+
self.logger.info(
|
|
77
|
+
"Temperature start: %f K, temperature stop: %f K, pressure: %s bar"
|
|
78
|
+
% (self.calc._temperature, self.calc._temperature_stop, pressure_string)
|
|
79
|
+
)
|
|
83
80
|
|
|
84
81
|
if self.calc._iso:
|
|
85
82
|
self.iso = "iso"
|
|
86
83
|
else:
|
|
87
84
|
self.iso = "aniso"
|
|
88
|
-
self.logger.info("Pressure adjusted in %s"%self.iso)
|
|
89
|
-
|
|
85
|
+
self.logger.info("Pressure adjusted in %s" % self.iso)
|
|
90
86
|
|
|
91
|
-
self.logger.info("Reference phase is %s"%self.calc.reference_phase)
|
|
92
|
-
if self.calc.reference_phase ==
|
|
87
|
+
self.logger.info("Reference phase is %s" % self.calc.reference_phase)
|
|
88
|
+
if self.calc.reference_phase == "liquid":
|
|
93
89
|
if self.calc.melting_cycle:
|
|
94
|
-
self.logger.info(
|
|
90
|
+
self.logger.info(
|
|
91
|
+
"Melting cycle will run, this can be turned off using the keyword melting_cycle"
|
|
92
|
+
)
|
|
95
93
|
else:
|
|
96
94
|
self.logger.info("Melting cycle is turned off")
|
|
97
95
|
|
|
98
|
-
#now thermostat and barostat damping process
|
|
96
|
+
# now thermostat and barostat damping process
|
|
99
97
|
if self.calc.equilibration_control is None:
|
|
100
|
-
self.logger.info(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
self.calc.equilibration_control = "nose-hoover"
|
|
98
|
+
self.logger.info(
|
|
99
|
+
"Thermostat/Barostat combo for equilibration cycle is not explicitely specified"
|
|
100
|
+
)
|
|
101
|
+
self.logger.info(
|
|
102
|
+
"Thermostat/Barostat combo for equilibration cycle can be specified using keyword equilibration_control"
|
|
103
|
+
)
|
|
104
|
+
self.calc.equilibration_control = "nose-hoover"
|
|
108
105
|
else:
|
|
109
|
-
self.logger.info(
|
|
106
|
+
self.logger.info(
|
|
107
|
+
"Equilibration stage is done using %s barostat/thermostat"
|
|
108
|
+
% self.calc.equilibration_control
|
|
109
|
+
)
|
|
110
110
|
|
|
111
111
|
if self.calc.equilibration_control == "nose-hoover":
|
|
112
|
-
self.logger.info(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
self.logger.info(
|
|
113
|
+
"Nose-Hoover thermostat damping is %f"
|
|
114
|
+
% self.calc.nose_hoover.thermostat_damping
|
|
115
|
+
)
|
|
116
|
+
self.calc.md.thermostat_damping = [
|
|
117
|
+
self.calc.nose_hoover.thermostat_damping,
|
|
118
|
+
self.calc.md.thermostat_damping,
|
|
119
|
+
]
|
|
120
|
+
self.logger.info(
|
|
121
|
+
"Nose-Hoover barostat damping is %f"
|
|
122
|
+
% self.calc.nose_hoover.barostat_damping
|
|
123
|
+
)
|
|
124
|
+
self.calc.md.barostat_damping = [
|
|
125
|
+
self.calc.nose_hoover.barostat_damping,
|
|
126
|
+
self.calc.md.barostat_damping,
|
|
127
|
+
]
|
|
116
128
|
self.logger.info("These values can be tuned by adding in the input file:")
|
|
117
129
|
self.logger.info("nose_hoover:")
|
|
118
130
|
self.logger.info(" thermostat_damping: <float>")
|
|
@@ -122,10 +134,22 @@ class Phase:
|
|
|
122
134
|
if self.calc.md.barostat_damping[0] > 10.0:
|
|
123
135
|
self.logger.warning("Equil. Nose-Hoover barostat damping is high!")
|
|
124
136
|
else:
|
|
125
|
-
self.logger.info(
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
137
|
+
self.logger.info(
|
|
138
|
+
"Berendsen thermostat damping is %f"
|
|
139
|
+
% self.calc.berendsen.thermostat_damping
|
|
140
|
+
)
|
|
141
|
+
self.calc.md.thermostat_damping = [
|
|
142
|
+
self.calc.berendsen.thermostat_damping,
|
|
143
|
+
self.calc.md.thermostat_damping,
|
|
144
|
+
]
|
|
145
|
+
self.logger.info(
|
|
146
|
+
"Berendsen barostat damping is %f"
|
|
147
|
+
% self.calc.berendsen.barostat_damping
|
|
148
|
+
)
|
|
149
|
+
self.calc.md.barostat_damping = [
|
|
150
|
+
self.calc.berendsen.barostat_damping,
|
|
151
|
+
self.calc.md.barostat_damping,
|
|
152
|
+
]
|
|
129
153
|
self.logger.info("These values can be tuned by adding in the input file:")
|
|
130
154
|
self.logger.info("berendsen:")
|
|
131
155
|
self.logger.info(" thermostat_damping: <float>")
|
|
@@ -135,28 +159,37 @@ class Phase:
|
|
|
135
159
|
if self.calc.md.barostat_damping[0] < 1.0:
|
|
136
160
|
self.logger.warning("Equil. Berendsen barostat damping is high!")
|
|
137
161
|
|
|
138
|
-
self.logger.info(
|
|
139
|
-
|
|
140
|
-
|
|
162
|
+
self.logger.info(
|
|
163
|
+
"Integration stage is done using Nose-Hoover thermostat and barostat when needed"
|
|
164
|
+
)
|
|
165
|
+
self.logger.info(
|
|
166
|
+
"Thermostat damping is %f" % (self.calc.md.thermostat_damping[1])
|
|
167
|
+
)
|
|
168
|
+
self.logger.info("Barostat damping is %f" % (self.calc.md.barostat_damping[1]))
|
|
141
169
|
|
|
142
170
|
if self.calc._fix_lattice:
|
|
143
|
-
self.logger.info(
|
|
171
|
+
self.logger.info(
|
|
172
|
+
"Lattice is fixed, pressure convergence criteria is 50*tolerance.pressure; change if needed!"
|
|
173
|
+
)
|
|
144
174
|
|
|
145
175
|
self.l = self.calc.lattice
|
|
146
176
|
self.alat = self.calc.lattice_constant
|
|
147
177
|
self.vol = None
|
|
148
178
|
|
|
149
|
-
#other properties
|
|
179
|
+
# other properties
|
|
150
180
|
self.cores = self.calc.queue.cores
|
|
151
181
|
self.ncells = np.prod(self.calc.repeat)
|
|
152
|
-
self.natoms = self.calc._natoms
|
|
153
|
-
self.logger.info(
|
|
182
|
+
self.natoms = self.calc._natoms
|
|
183
|
+
self.logger.info(
|
|
184
|
+
"%d atoms in %d cells on %d cores" % (self.natoms, self.ncells, self.cores)
|
|
185
|
+
)
|
|
154
186
|
|
|
155
|
-
#reference system props; may not be always used
|
|
156
|
-
#TODO : Add option to customize UFM parameters
|
|
157
|
-
self.eps = self.calc._temperature*
|
|
187
|
+
# reference system props; may not be always used
|
|
188
|
+
# TODO : Add option to customize UFM parameters
|
|
189
|
+
self.eps = self.calc._temperature * self.calc.uhlenbeck_ford_model.p * kb
|
|
190
|
+
self.ufm_cutoff = 5 * self.calc.uhlenbeck_ford_model.sigma
|
|
158
191
|
|
|
159
|
-
#properties that will be calculated later
|
|
192
|
+
# properties that will be calculated later
|
|
160
193
|
self.volatom = None
|
|
161
194
|
self.k = None
|
|
162
195
|
self.rho = None
|
|
@@ -166,31 +199,32 @@ class Phase:
|
|
|
166
199
|
self.feinstein = 0
|
|
167
200
|
self.fcm = 0
|
|
168
201
|
self.fideal = 0
|
|
169
|
-
|
|
202
|
+
|
|
170
203
|
self.w = 0
|
|
171
204
|
self.pv = 0
|
|
172
205
|
self.fe = 0
|
|
173
206
|
|
|
174
|
-
#box dimensions that need to be stored
|
|
207
|
+
# box dimensions that need to be stored
|
|
175
208
|
self.lx = None
|
|
176
209
|
self.ly = None
|
|
177
210
|
self.lz = None
|
|
178
211
|
|
|
179
|
-
|
|
180
|
-
#now manually tune pair styles
|
|
212
|
+
# now manually tune pair styles
|
|
181
213
|
if self.calc.pair_style is not None:
|
|
182
|
-
self.logger.info("pair_style: %s"%self.calc._pair_style_with_options[0])
|
|
183
|
-
self.logger.info("pair_coeff: %s"%self.calc.pair_coeff[0])
|
|
184
|
-
|
|
185
|
-
#log second pair style
|
|
186
|
-
if len(self.calc.pair_style)>1:
|
|
187
|
-
self.logger.info(
|
|
188
|
-
|
|
214
|
+
self.logger.info("pair_style: %s" % self.calc._pair_style_with_options[0])
|
|
215
|
+
self.logger.info("pair_coeff: %s" % self.calc.pair_coeff[0])
|
|
216
|
+
|
|
217
|
+
# log second pair style
|
|
218
|
+
if len(self.calc.pair_style) > 1:
|
|
219
|
+
self.logger.info(
|
|
220
|
+
"second pair_style: %s" % self.calc._pair_style_with_options[1]
|
|
221
|
+
)
|
|
222
|
+
self.logger.info("second pair_coeff: %s" % self.calc.pair_coeff[1])
|
|
189
223
|
else:
|
|
190
224
|
self.logger.info("pair_style or pair_coeff not provided")
|
|
191
225
|
if self.calc.potential_file is not None:
|
|
192
226
|
self.logger.info("potential is being loaded from file instead")
|
|
193
|
-
|
|
227
|
+
|
|
194
228
|
def __repr__(self):
|
|
195
229
|
"""
|
|
196
230
|
String of the class
|
|
@@ -205,18 +239,19 @@ class Phase:
|
|
|
205
239
|
org_dict[key] = {}
|
|
206
240
|
self._from_dict(org_dict[key], val)
|
|
207
241
|
else:
|
|
208
|
-
org_dict[key] = val
|
|
209
|
-
|
|
242
|
+
org_dict[key] = val
|
|
243
|
+
|
|
210
244
|
def dump_current_snapshot(self, lmp, filename):
|
|
211
|
-
"""
|
|
212
|
-
|
|
213
|
-
|
|
245
|
+
""" """
|
|
246
|
+
lmp.command(
|
|
247
|
+
"dump 2 all custom 1 %s id type mass x y z vx vy vz"
|
|
248
|
+
% (filename)
|
|
249
|
+
)
|
|
214
250
|
lmp.command("run 0")
|
|
215
251
|
lmp.command("undump 2")
|
|
216
252
|
|
|
217
253
|
def get_structures(self, stage="fe", direction="forward", n_iteration=1):
|
|
218
|
-
"""
|
|
219
|
-
"""
|
|
254
|
+
""" """
|
|
220
255
|
species = self.calc.element
|
|
221
256
|
filename = None
|
|
222
257
|
|
|
@@ -224,9 +259,13 @@ class Phase:
|
|
|
224
259
|
filename = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
225
260
|
elif stage == "ts":
|
|
226
261
|
if direction == "forward":
|
|
227
|
-
filename = os.path.join(
|
|
262
|
+
filename = os.path.join(
|
|
263
|
+
self.simfolder, "traj.ts.forward_%d.dat" % n_iteration
|
|
264
|
+
)
|
|
228
265
|
elif direction == "backward":
|
|
229
|
-
filename = os.path.join(
|
|
266
|
+
filename = os.path.join(
|
|
267
|
+
self.simfolder, "traj.ts.backward_%d.dat" % n_iteration
|
|
268
|
+
)
|
|
230
269
|
|
|
231
270
|
structures = None
|
|
232
271
|
if filename is not None:
|
|
@@ -235,24 +274,31 @@ class Phase:
|
|
|
235
274
|
return structures
|
|
236
275
|
|
|
237
276
|
def check_if_melted(self, lmp, filename):
|
|
238
|
-
"""
|
|
239
|
-
"""
|
|
277
|
+
""" """
|
|
240
278
|
solids = ph.find_solid_fraction(os.path.join(self.simfolder, filename))
|
|
241
|
-
if
|
|
279
|
+
if solids / lmp.natoms < self.calc.tolerance.solid_fraction:
|
|
242
280
|
lmp.close()
|
|
243
|
-
raise MeltedError(
|
|
281
|
+
raise MeltedError(
|
|
282
|
+
"System melted, increase size or reduce temp!\n Solid detection algorithm only works with BCC/FCC/HCP/SC/DIA. Detection algorithm can be turned off by setting:\n tolerance.solid_fraction: 0"
|
|
283
|
+
)
|
|
244
284
|
|
|
245
285
|
def check_if_solidfied(self, lmp, filename):
|
|
246
|
-
"""
|
|
247
|
-
"""
|
|
286
|
+
""" """
|
|
248
287
|
solids = ph.find_solid_fraction(os.path.join(self.simfolder, filename))
|
|
249
|
-
if
|
|
288
|
+
if solids / lmp.natoms > self.calc.tolerance.liquid_fraction:
|
|
250
289
|
lmp.close()
|
|
251
|
-
raise SolidifiedError(
|
|
252
|
-
|
|
253
|
-
def fix_nose_hoover(
|
|
254
|
-
|
|
255
|
-
|
|
290
|
+
raise SolidifiedError("System solidified, increase temperature")
|
|
291
|
+
|
|
292
|
+
def fix_nose_hoover(
|
|
293
|
+
self,
|
|
294
|
+
lmp,
|
|
295
|
+
temp_start_factor=1.0,
|
|
296
|
+
temp_end_factor=1.0,
|
|
297
|
+
press_start_factor=1.0,
|
|
298
|
+
press_end_factor=1.0,
|
|
299
|
+
stage=0,
|
|
300
|
+
ensemble="npt",
|
|
301
|
+
):
|
|
256
302
|
"""
|
|
257
303
|
Fix Nose-Hoover thermostat and barostat
|
|
258
304
|
|
|
@@ -264,14 +310,29 @@ class Phase:
|
|
|
264
310
|
-------
|
|
265
311
|
None
|
|
266
312
|
"""
|
|
267
|
-
lmp.command(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
313
|
+
lmp.command(
|
|
314
|
+
"fix nh1 all npt temp %f %f %f %s %f %f %f"
|
|
315
|
+
% (
|
|
316
|
+
temp_start_factor * self.calc._temperature,
|
|
317
|
+
temp_end_factor * self.calc._temperature,
|
|
318
|
+
self.calc.md.thermostat_damping[stage],
|
|
319
|
+
self.iso,
|
|
320
|
+
press_start_factor * self.calc._pressure,
|
|
321
|
+
press_end_factor * self.calc._pressure,
|
|
322
|
+
self.calc.md.barostat_damping[stage],
|
|
323
|
+
)
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
def fix_berendsen(
|
|
327
|
+
self,
|
|
328
|
+
lmp,
|
|
329
|
+
temp_start_factor=1.0,
|
|
330
|
+
temp_end_factor=1.0,
|
|
331
|
+
press_start_factor=1.0,
|
|
332
|
+
press_end_factor=1.0,
|
|
333
|
+
stage=0,
|
|
334
|
+
ensemble="npt",
|
|
335
|
+
):
|
|
275
336
|
"""
|
|
276
337
|
Fix Nose-Hoover thermostat and barostat
|
|
277
338
|
|
|
@@ -284,8 +345,23 @@ class Phase:
|
|
|
284
345
|
None
|
|
285
346
|
"""
|
|
286
347
|
lmp.command("fix b1a all nve")
|
|
287
|
-
lmp.command(
|
|
288
|
-
|
|
348
|
+
lmp.command(
|
|
349
|
+
"fix b1b all temp/berendsen %f %f %f"
|
|
350
|
+
% (
|
|
351
|
+
temp_start_factor * self.calc._temperature,
|
|
352
|
+
temp_end_factor * self.calc._temperature,
|
|
353
|
+
self.calc.md.thermostat_damping[stage],
|
|
354
|
+
)
|
|
355
|
+
)
|
|
356
|
+
lmp.command(
|
|
357
|
+
"fix b1c all press/berendsen %s %f %f %f"
|
|
358
|
+
% (
|
|
359
|
+
self.iso,
|
|
360
|
+
press_start_factor * self.calc._pressure,
|
|
361
|
+
press_end_factor * self.calc._pressure,
|
|
362
|
+
self.calc.md.barostat_damping[stage],
|
|
363
|
+
)
|
|
364
|
+
)
|
|
289
365
|
|
|
290
366
|
def unfix_nose_hoover(self, lmp):
|
|
291
367
|
"""
|
|
@@ -315,7 +391,7 @@ class Phase:
|
|
|
315
391
|
"""
|
|
316
392
|
lmp.command("unfix b1a")
|
|
317
393
|
lmp.command("unfix b1b")
|
|
318
|
-
lmp.command("unfix b1c")
|
|
394
|
+
lmp.command("unfix b1c")
|
|
319
395
|
|
|
320
396
|
def run_zero_pressure_equilibration(self, lmp):
|
|
321
397
|
"""
|
|
@@ -331,31 +407,32 @@ class Phase:
|
|
|
331
407
|
|
|
332
408
|
Notes
|
|
333
409
|
-----
|
|
334
|
-
Each method should close all the fixes. Run a small eqbr routine to achieve zero pressure
|
|
410
|
+
Each method should close all the fixes. Run a small eqbr routine to achieve zero pressure
|
|
335
411
|
"""
|
|
336
|
-
#set velocity
|
|
337
|
-
lmp.command(
|
|
338
|
-
|
|
339
|
-
|
|
412
|
+
# set velocity
|
|
413
|
+
lmp.command(
|
|
414
|
+
"velocity all create %f %d"
|
|
415
|
+
% (self.calc._temperature, np.random.randint(1, 10000))
|
|
416
|
+
)
|
|
417
|
+
|
|
418
|
+
# apply fixes depending on thermostat/barostat
|
|
340
419
|
if self.calc.equilibration_control == "nose-hoover":
|
|
341
420
|
self.fix_nose_hoover(lmp)
|
|
342
421
|
else:
|
|
343
422
|
self.fix_berendsen(lmp)
|
|
344
|
-
#start thermo logging
|
|
423
|
+
# start thermo logging
|
|
345
424
|
lmp.command("thermo_style custom step pe press vol etotal temp lx ly lz")
|
|
346
425
|
lmp.command("thermo 10")
|
|
347
|
-
|
|
348
|
-
#run MD
|
|
349
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
350
|
-
|
|
351
|
-
#remove fixes
|
|
426
|
+
|
|
427
|
+
# run MD
|
|
428
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
429
|
+
|
|
430
|
+
# remove fixes
|
|
352
431
|
if self.calc.equilibration_control == "nose-hoover":
|
|
353
432
|
self.unfix_nose_hoover(lmp)
|
|
354
433
|
else:
|
|
355
434
|
self.unfix_berendsen(lmp)
|
|
356
435
|
|
|
357
|
-
|
|
358
|
-
|
|
359
436
|
def run_finite_pressure_equilibration(self, lmp):
|
|
360
437
|
"""
|
|
361
438
|
Run a finite pressure equilibration
|
|
@@ -367,52 +444,55 @@ class Phase:
|
|
|
367
444
|
Returns
|
|
368
445
|
-------
|
|
369
446
|
None
|
|
370
|
-
|
|
447
|
+
|
|
371
448
|
Notes
|
|
372
449
|
-----
|
|
373
450
|
Each method should close all the fixes. Run a equilibration routine to reach the given finite pressure.
|
|
374
|
-
The pressure is implemented in one fix, while temperature is gradually ramped.
|
|
451
|
+
The pressure is implemented in one fix, while temperature is gradually ramped.
|
|
375
452
|
The thermostat can work faster than barostat, which means that the structure will melt before the pressure is scaled, this ramping
|
|
376
|
-
can prevent the issue.
|
|
453
|
+
can prevent the issue.
|
|
377
454
|
"""
|
|
378
|
-
#create velocity
|
|
379
|
-
lmp.command(
|
|
455
|
+
# create velocity
|
|
456
|
+
lmp.command(
|
|
457
|
+
"velocity all create %f %d"
|
|
458
|
+
% (0.25 * self.calc._temperature, np.random.randint(1, 10000))
|
|
459
|
+
)
|
|
380
460
|
|
|
381
|
-
#for Nose-Hoover thermo/baro combination
|
|
461
|
+
# for Nose-Hoover thermo/baro combination
|
|
382
462
|
if self.calc.equilibration_control == "nose-hoover":
|
|
383
|
-
#Cycle 1: 0.25-0.5 temperature, full pressure
|
|
463
|
+
# Cycle 1: 0.25-0.5 temperature, full pressure
|
|
384
464
|
self.fix_nose_hoover(lmp, temp_start_factor=0.25, temp_end_factor=0.5)
|
|
385
465
|
lmp.command("thermo_style custom step pe press vol etotal temp")
|
|
386
466
|
lmp.command("thermo 10")
|
|
387
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
467
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
388
468
|
self.unfix_nose_hoover(lmp)
|
|
389
469
|
|
|
390
|
-
#Cycle 2: 0.5-1.0 temperature, full pressure
|
|
470
|
+
# Cycle 2: 0.5-1.0 temperature, full pressure
|
|
391
471
|
self.fix_nose_hoover(lmp, temp_start_factor=0.5, temp_end_factor=1.0)
|
|
392
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
472
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
393
473
|
self.unfix_nose_hoover(lmp)
|
|
394
474
|
|
|
395
|
-
#Cycle 3: full temperature, full pressure
|
|
475
|
+
# Cycle 3: full temperature, full pressure
|
|
396
476
|
self.fix_nose_hoover(lmp)
|
|
397
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
477
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
398
478
|
self.unfix_nose_hoover(lmp)
|
|
399
|
-
|
|
479
|
+
|
|
400
480
|
else:
|
|
401
|
-
#Cycle 1: 0.25-0.5 temperature, full pressure
|
|
481
|
+
# Cycle 1: 0.25-0.5 temperature, full pressure
|
|
402
482
|
self.fix_berendsen(lmp, temp_start_factor=0.25, temp_end_factor=0.5)
|
|
403
483
|
lmp.command("thermo_style custom step pe press vol etotal temp")
|
|
404
484
|
lmp.command("thermo 10")
|
|
405
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
485
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
406
486
|
self.unfix_berendsen(lmp)
|
|
407
487
|
|
|
408
|
-
#Cycle 2: 0.5-1.0 temperature, full pressure
|
|
488
|
+
# Cycle 2: 0.5-1.0 temperature, full pressure
|
|
409
489
|
self.fix_berendsen(lmp, temp_start_factor=0.5, temp_end_factor=1.0)
|
|
410
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
490
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
411
491
|
self.unfix_berendsen(lmp)
|
|
412
492
|
|
|
413
|
-
#Cycle 3: full temperature, full pressure
|
|
493
|
+
# Cycle 3: full temperature, full pressure
|
|
414
494
|
self.fix_berendsen(lmp)
|
|
415
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
495
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
416
496
|
self.unfix_berendsen(lmp)
|
|
417
497
|
|
|
418
498
|
def run_pressure_convergence(self, lmp):
|
|
@@ -455,53 +535,70 @@ class Phase:
|
|
|
455
535
|
The cycle is stopped when the average pressure is within the given cutoff of the target pressure.
|
|
456
536
|
"""
|
|
457
537
|
|
|
458
|
-
#apply fixes
|
|
538
|
+
# apply fixes
|
|
459
539
|
if self.calc.equilibration_control == "nose-hoover":
|
|
460
540
|
self.fix_nose_hoover(lmp)
|
|
461
541
|
else:
|
|
462
542
|
self.fix_berendsen(lmp)
|
|
463
543
|
|
|
544
|
+
lmp.command(
|
|
545
|
+
"fix 2 all ave/time %d %d %d v_mlx v_mly v_mlz v_mpress file avg.dat"
|
|
546
|
+
% (
|
|
547
|
+
int(self.calc.md.n_every_steps),
|
|
548
|
+
int(self.calc.md.n_repeat_steps),
|
|
549
|
+
int(self.calc.md.n_every_steps * self.calc.md.n_repeat_steps),
|
|
550
|
+
)
|
|
551
|
+
)
|
|
464
552
|
|
|
465
|
-
lmp.command("fix 2 all ave/time %d %d %d v_mlx v_mly v_mlz v_mpress file avg.dat"%(int(self.calc.md.n_every_steps),
|
|
466
|
-
int(self.calc.md.n_repeat_steps), int(self.calc.md.n_every_steps*self.calc.md.n_repeat_steps)))
|
|
467
|
-
|
|
468
553
|
laststd = 0.00
|
|
469
554
|
converged = False
|
|
470
555
|
|
|
471
556
|
for i in range(int(self.calc.md.n_cycles)):
|
|
472
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
473
|
-
ncount = int(self.calc.md.n_small_steps)//int(
|
|
474
|
-
|
|
557
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
558
|
+
ncount = int(self.calc.md.n_small_steps) // int(
|
|
559
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
560
|
+
)
|
|
561
|
+
# now we can check if it converted
|
|
475
562
|
file = os.path.join(self.simfolder, "avg.dat")
|
|
476
563
|
lx, ly, lz, ipress = np.loadtxt(file, usecols=(1, 2, 3, 4), unpack=True)
|
|
477
|
-
|
|
564
|
+
|
|
478
565
|
lxpc = ipress
|
|
479
566
|
mean = np.mean(lxpc)
|
|
480
567
|
std = np.std(lxpc)
|
|
481
|
-
volatom = np.mean((lx*ly*lz)/self.natoms)
|
|
482
|
-
self.logger.info(
|
|
483
|
-
|
|
568
|
+
volatom = np.mean((lx * ly * lz) / self.natoms)
|
|
569
|
+
self.logger.info(
|
|
570
|
+
"At count %d mean pressure is %f with %f vol/atom"
|
|
571
|
+
% (i + 1, mean, volatom)
|
|
572
|
+
)
|
|
573
|
+
|
|
484
574
|
if (np.abs(mean - self.calc._pressure)) < self.calc.tolerance.pressure:
|
|
485
575
|
|
|
486
|
-
#process other means
|
|
487
|
-
self.lx = np.round(np.mean(lx[-ncount+1:]), decimals=3)
|
|
488
|
-
self.ly = np.round(np.mean(ly[-ncount+1:]), decimals=3)
|
|
489
|
-
self.lz = np.round(np.mean(lz[-ncount+1:]), decimals=3)
|
|
576
|
+
# process other means
|
|
577
|
+
self.lx = np.round(np.mean(lx[-ncount + 1 :]), decimals=3)
|
|
578
|
+
self.ly = np.round(np.mean(ly[-ncount + 1 :]), decimals=3)
|
|
579
|
+
self.lz = np.round(np.mean(lz[-ncount + 1 :]), decimals=3)
|
|
490
580
|
self.volatom = volatom
|
|
491
|
-
self.vol = self.lx*self.ly*self.lz
|
|
492
|
-
self.rho = self.natoms/(self.lx*self.ly*self.lz)
|
|
493
|
-
|
|
494
|
-
self.logger.info(
|
|
495
|
-
|
|
581
|
+
self.vol = self.lx * self.ly * self.lz
|
|
582
|
+
self.rho = self.natoms / (self.lx * self.ly * self.lz)
|
|
583
|
+
|
|
584
|
+
self.logger.info(
|
|
585
|
+
"finalized vol/atom %f at pressure %f" % (self.volatom, mean)
|
|
586
|
+
)
|
|
587
|
+
self.logger.info(
|
|
588
|
+
"Avg box dimensions x: %f, y: %f, z:%f"
|
|
589
|
+
% (self.lx, self.ly, self.lz)
|
|
590
|
+
)
|
|
496
591
|
converged = True
|
|
497
592
|
break
|
|
498
593
|
laststd = std
|
|
499
|
-
|
|
594
|
+
|
|
500
595
|
if not converged:
|
|
501
596
|
lmp.close()
|
|
502
|
-
raise ValueError(
|
|
597
|
+
raise ValueError(
|
|
598
|
+
"Pressure did not converge after MD runs, maybe change lattice_constant and try?"
|
|
599
|
+
)
|
|
503
600
|
|
|
504
|
-
#unfix thermostat and barostat
|
|
601
|
+
# unfix thermostat and barostat
|
|
505
602
|
if self.calc.equilibration_control == "nose-hoover":
|
|
506
603
|
self.unfix_nose_hoover(lmp)
|
|
507
604
|
else:
|
|
@@ -527,20 +624,25 @@ class Phase:
|
|
|
527
624
|
The cycle is stopped when the average pressure is within the given cutoff of the target pressure.
|
|
528
625
|
"""
|
|
529
626
|
|
|
530
|
-
#apply fixes
|
|
627
|
+
# apply fixes
|
|
531
628
|
if self.calc.equilibration_control == "nose-hoover":
|
|
532
629
|
self.fix_nose_hoover(lmp)
|
|
533
630
|
else:
|
|
534
631
|
self.fix_berendsen(lmp)
|
|
535
632
|
|
|
633
|
+
lmp.command(
|
|
634
|
+
"fix 2 all ave/time %d %d %d v_mlx v_mly v_mlz v_mpress file avg.dat"
|
|
635
|
+
% (
|
|
636
|
+
int(self.calc.md.n_every_steps),
|
|
637
|
+
int(self.calc.md.n_repeat_steps),
|
|
638
|
+
int(self.calc.md.n_every_steps * self.calc.md.n_repeat_steps),
|
|
639
|
+
)
|
|
640
|
+
)
|
|
536
641
|
|
|
537
|
-
lmp.command("
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
541
|
-
lmp.command("run %d"%int(self.calc.n_equilibration_steps))
|
|
642
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
643
|
+
lmp.command("run %d" % int(self.calc.n_equilibration_steps))
|
|
542
644
|
|
|
543
|
-
#unfix thermostat and barostat
|
|
645
|
+
# unfix thermostat and barostat
|
|
544
646
|
if self.calc.equilibration_control == "nose-hoover":
|
|
545
647
|
self.unfix_nose_hoover(lmp)
|
|
546
648
|
else:
|
|
@@ -555,34 +657,52 @@ class Phase:
|
|
|
555
657
|
self.run_iterative_constrained_pressure_convergence(lmp)
|
|
556
658
|
|
|
557
659
|
def run_iterative_constrained_pressure_convergence(self, lmp):
|
|
558
|
-
"""
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
660
|
+
""" """
|
|
661
|
+
lmp.command(
|
|
662
|
+
"velocity all create %f %d"
|
|
663
|
+
% (self.calc._temperature, np.random.randint(1, 10000))
|
|
664
|
+
)
|
|
665
|
+
lmp.command(
|
|
666
|
+
"fix 1 all nvt temp %f %f %f"
|
|
667
|
+
% (
|
|
668
|
+
self.calc._temperature,
|
|
669
|
+
self.calc._temperature,
|
|
670
|
+
self.calc.md.thermostat_damping[1],
|
|
671
|
+
)
|
|
672
|
+
)
|
|
562
673
|
lmp.command("thermo_style custom step pe press vol etotal temp lx ly lz")
|
|
563
674
|
lmp.command("thermo 10")
|
|
564
|
-
|
|
565
|
-
#this is when the averaging routine starts
|
|
566
|
-
lmp.command(
|
|
567
|
-
|
|
675
|
+
|
|
676
|
+
# this is when the averaging routine starts
|
|
677
|
+
lmp.command(
|
|
678
|
+
"fix 2 all ave/time %d %d %d v_mlx v_mly v_mlz v_mpress file avg.dat"
|
|
679
|
+
% (
|
|
680
|
+
int(self.calc.md.n_every_steps),
|
|
681
|
+
int(self.calc.md.n_repeat_steps),
|
|
682
|
+
int(self.calc.md.n_every_steps * self.calc.md.n_repeat_steps),
|
|
683
|
+
)
|
|
684
|
+
)
|
|
568
685
|
|
|
569
686
|
lastmean = 100000000
|
|
570
687
|
converged = False
|
|
571
688
|
for i in range(int(self.calc.md.n_cycles)):
|
|
572
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
573
|
-
|
|
574
|
-
#now we can check if it converted
|
|
575
|
-
mean, std,volatom = self.process_pressure()
|
|
576
|
-
self.logger.info(
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
689
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
690
|
+
|
|
691
|
+
# now we can check if it converted
|
|
692
|
+
mean, std, volatom = self.process_pressure()
|
|
693
|
+
self.logger.info(
|
|
694
|
+
"At count %d mean pressure is %f with %f vol/atom"
|
|
695
|
+
% (i + 1, mean, volatom)
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
if (np.abs(mean - lastmean)) < 50 * self.calc.tolerance.pressure:
|
|
699
|
+
# here we actually have to set the pressure
|
|
580
700
|
self.finalise_pressure()
|
|
581
701
|
converged = True
|
|
582
702
|
break
|
|
583
703
|
|
|
584
704
|
lastmean = mean
|
|
585
|
-
|
|
705
|
+
|
|
586
706
|
lmp.command("unfix 1")
|
|
587
707
|
lmp.command("unfix 2")
|
|
588
708
|
|
|
@@ -590,67 +710,95 @@ class Phase:
|
|
|
590
710
|
lmp.close()
|
|
591
711
|
raise ValueError("pressure did not converge")
|
|
592
712
|
|
|
593
|
-
def process_pressure(
|
|
713
|
+
def process_pressure(
|
|
714
|
+
self,
|
|
715
|
+
):
|
|
594
716
|
if self.calc.script_mode:
|
|
595
|
-
ncount = int(self.calc.n_equilibration_steps)//int(
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
717
|
+
ncount = int(self.calc.n_equilibration_steps) // int(
|
|
718
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
719
|
+
)
|
|
720
|
+
else:
|
|
721
|
+
ncount = int(self.calc.md.n_small_steps) // int(
|
|
722
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
723
|
+
)
|
|
724
|
+
|
|
725
|
+
# now we can check if it converted
|
|
600
726
|
file = os.path.join(self.simfolder, "avg.dat")
|
|
601
|
-
#we have to clean the data, so as just the last block is selected
|
|
727
|
+
# we have to clean the data, so as just the last block is selected
|
|
602
728
|
lx, ly, lz, lxpc = np.loadtxt(file, usecols=(1, 2, 3, 4), unpack=True)
|
|
603
|
-
lx = lx[-ncount+1:]
|
|
604
|
-
ly = ly[-ncount+1:]
|
|
605
|
-
lz = lx[-ncount+1:]
|
|
606
|
-
lxpc = lxpc[-ncount+1:]
|
|
729
|
+
lx = lx[-ncount + 1 :]
|
|
730
|
+
ly = ly[-ncount + 1 :]
|
|
731
|
+
lz = lx[-ncount + 1 :]
|
|
732
|
+
lxpc = lxpc[-ncount + 1 :]
|
|
607
733
|
mean = np.mean(lxpc)
|
|
608
734
|
std = np.std(lxpc)
|
|
609
|
-
volatom = np.mean((lx*ly*lz)/self.natoms)
|
|
735
|
+
volatom = np.mean((lx * ly * lz) / self.natoms)
|
|
610
736
|
return mean, std, volatom
|
|
611
737
|
|
|
612
|
-
def finalise_pressure(
|
|
738
|
+
def finalise_pressure(
|
|
739
|
+
self,
|
|
740
|
+
):
|
|
613
741
|
if self.calc.script_mode:
|
|
614
|
-
ncount = int(self.calc.n_equilibration_steps)//int(
|
|
615
|
-
|
|
616
|
-
|
|
742
|
+
ncount = int(self.calc.n_equilibration_steps) // int(
|
|
743
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
744
|
+
)
|
|
745
|
+
else:
|
|
746
|
+
ncount = int(self.calc.md.n_small_steps) // int(
|
|
747
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
748
|
+
)
|
|
617
749
|
|
|
618
750
|
file = os.path.join(self.simfolder, "avg.dat")
|
|
619
|
-
lx, ly, lz, lxpc = np.loadtxt(file, usecols=(1, 2, 3, 4), unpack=True)
|
|
620
|
-
lx = lx[-ncount+1:]
|
|
621
|
-
ly = ly[-ncount+1:]
|
|
622
|
-
lz = lx[-ncount+1:]
|
|
623
|
-
lxpc = lxpc[-ncount+1:]
|
|
751
|
+
lx, ly, lz, lxpc = np.loadtxt(file, usecols=(1, 2, 3, 4), unpack=True)
|
|
752
|
+
lx = lx[-ncount + 1 :]
|
|
753
|
+
ly = ly[-ncount + 1 :]
|
|
754
|
+
lz = lx[-ncount + 1 :]
|
|
755
|
+
lxpc = lxpc[-ncount + 1 :]
|
|
624
756
|
|
|
625
757
|
mean = np.mean(lxpc)
|
|
626
758
|
std = np.std(lxpc)
|
|
627
|
-
volatom = np.mean((lx*ly*lz)/self.natoms)
|
|
759
|
+
volatom = np.mean((lx * ly * lz) / self.natoms)
|
|
628
760
|
|
|
629
761
|
self.calc._pressure = mean
|
|
630
762
|
self.lx = np.round(np.mean(lx), decimals=3)
|
|
631
763
|
self.ly = np.round(np.mean(ly), decimals=3)
|
|
632
764
|
self.lz = np.round(np.mean(lz), decimals=3)
|
|
633
765
|
self.volatom = volatom
|
|
634
|
-
self.vol = self.lx*self.ly*self.lz
|
|
635
|
-
self.rho = self.natoms/(self.lx*self.ly*self.lz)
|
|
636
|
-
self.logger.info("finalized vol/atom %f at pressure %f"%(self.volatom, mean))
|
|
637
|
-
self.logger.info(
|
|
638
|
-
|
|
766
|
+
self.vol = self.lx * self.ly * self.lz
|
|
767
|
+
self.rho = self.natoms / (self.lx * self.ly * self.lz)
|
|
768
|
+
self.logger.info("finalized vol/atom %f at pressure %f" % (self.volatom, mean))
|
|
769
|
+
self.logger.info(
|
|
770
|
+
"Avg box dimensions x: %f, y: %f, z:%f" % (self.lx, self.ly, self.lz)
|
|
771
|
+
)
|
|
639
772
|
|
|
640
773
|
def run_minimal_constrained_pressure_convergence(self, lmp):
|
|
641
|
-
"""
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
774
|
+
""" """
|
|
775
|
+
lmp.command(
|
|
776
|
+
"velocity all create %f %d"
|
|
777
|
+
% (self.calc._temperature, np.random.randint(1, 10000))
|
|
778
|
+
)
|
|
779
|
+
lmp.command(
|
|
780
|
+
"fix 1 all nvt temp %f %f %f"
|
|
781
|
+
% (
|
|
782
|
+
self.calc._temperature,
|
|
783
|
+
self.calc._temperature,
|
|
784
|
+
self.calc.md.thermostat_damping[1],
|
|
785
|
+
)
|
|
786
|
+
)
|
|
645
787
|
lmp.command("thermo_style custom step pe press vol etotal temp lx ly lz")
|
|
646
788
|
lmp.command("thermo 10")
|
|
647
|
-
|
|
648
|
-
#this is when the averaging routine starts
|
|
649
|
-
lmp.command("fix 2 all ave/time %d %d %d v_mlx v_mly v_mlz v_mpress file avg.dat"%(int(self.calc.md.n_every_steps),
|
|
650
|
-
int(self.calc.md.n_repeat_steps), int(self.calc.md.n_every_steps*self.calc.md.n_repeat_steps)))
|
|
651
789
|
|
|
652
|
-
|
|
653
|
-
lmp.command(
|
|
790
|
+
# this is when the averaging routine starts
|
|
791
|
+
lmp.command(
|
|
792
|
+
"fix 2 all ave/time %d %d %d v_mlx v_mly v_mlz v_mpress file avg.dat"
|
|
793
|
+
% (
|
|
794
|
+
int(self.calc.md.n_every_steps),
|
|
795
|
+
int(self.calc.md.n_repeat_steps),
|
|
796
|
+
int(self.calc.md.n_every_steps * self.calc.md.n_repeat_steps),
|
|
797
|
+
)
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
801
|
+
lmp.command("run %d" % int(self.calc.n_equilibration_steps))
|
|
654
802
|
|
|
655
803
|
lmp.command("unfix 1")
|
|
656
804
|
lmp.command("unfix 2")
|
|
@@ -670,24 +818,30 @@ class Phase:
|
|
|
670
818
|
"""
|
|
671
819
|
report = {}
|
|
672
820
|
|
|
673
|
-
#input quantities
|
|
821
|
+
# input quantities
|
|
674
822
|
report["input"] = {}
|
|
675
823
|
report["input"]["temperature"] = int(self.calc._temperature)
|
|
676
824
|
report["input"]["pressure"] = float(self.calc._pressure)
|
|
677
825
|
report["input"]["lattice"] = str(self.calc._original_lattice)
|
|
678
826
|
report["input"]["element"] = " ".join(np.array(self.calc.element).astype(str))
|
|
679
|
-
report["input"]["concentration"] = " ".join(
|
|
827
|
+
report["input"]["concentration"] = " ".join(
|
|
828
|
+
np.array(
|
|
829
|
+
[val["composition"] for key, val in self.calc._element_dict.items()]
|
|
830
|
+
).astype(str)
|
|
831
|
+
)
|
|
680
832
|
|
|
681
|
-
#average quantities
|
|
833
|
+
# average quantities
|
|
682
834
|
report["average"] = {}
|
|
683
835
|
report["average"]["vol_atom"] = float(self.volatom)
|
|
684
|
-
|
|
836
|
+
|
|
685
837
|
if self.k is not None:
|
|
686
|
-
report["average"]["spring_constant"] = " ".join(
|
|
838
|
+
report["average"]["spring_constant"] = " ".join(
|
|
839
|
+
np.array(self.k).astype(str)
|
|
840
|
+
)
|
|
687
841
|
if self.rho is not None:
|
|
688
842
|
report["average"]["density"] = float(self.rho)
|
|
689
843
|
|
|
690
|
-
#results
|
|
844
|
+
# results
|
|
691
845
|
report["results"] = {}
|
|
692
846
|
report["results"]["free_energy"] = float(self.fe)
|
|
693
847
|
report["results"]["error"] = float(self.ferr)
|
|
@@ -704,21 +858,25 @@ class Phase:
|
|
|
704
858
|
self.report = report
|
|
705
859
|
|
|
706
860
|
reportfile = os.path.join(self.simfolder, "report.yaml")
|
|
707
|
-
with open(reportfile,
|
|
861
|
+
with open(reportfile, "w") as f:
|
|
708
862
|
yaml.dump(report, f)
|
|
709
863
|
|
|
710
|
-
self.logger.info("Report written in %s"%reportfile)
|
|
864
|
+
self.logger.info("Report written in %s" % reportfile)
|
|
711
865
|
|
|
712
|
-
#now we have to write out the results
|
|
866
|
+
# now we have to write out the results
|
|
713
867
|
self.logger.info("Please cite the following publications:")
|
|
714
868
|
self.logger.info("- 10.1103/PhysRevMaterials.5.103801")
|
|
869
|
+
self.publications.append("10.1103/PhysRevMaterials.5.103801")
|
|
715
870
|
|
|
716
871
|
if self.calc.mode == "fe":
|
|
717
872
|
if self.calc.reference_phase == "solid":
|
|
718
873
|
self.logger.info("- 10.1016/j.commatsci.2015.10.050")
|
|
874
|
+
self.publications.append("10.1016/j.commatsci.2015.10.050")
|
|
719
875
|
else:
|
|
720
876
|
self.logger.info("- 10.1016/j.commatsci.2018.12.029")
|
|
721
877
|
self.logger.info("- 10.1063/1.4967775")
|
|
878
|
+
self.publications.append("10.1016/j.commatsci.2018.12.029")
|
|
879
|
+
self.publications.append("10.1063/1.4967775")
|
|
722
880
|
|
|
723
881
|
def reversible_scaling(self, iteration=1):
|
|
724
882
|
"""
|
|
@@ -733,117 +891,213 @@ class Phase:
|
|
|
733
891
|
-------
|
|
734
892
|
None
|
|
735
893
|
"""
|
|
736
|
-
self.logger.info(f
|
|
894
|
+
self.logger.info(f"Starting temperature sweep cycle: {iteration}")
|
|
737
895
|
solid = False
|
|
738
|
-
if self.calc.reference_phase ==
|
|
896
|
+
if self.calc.reference_phase == "solid":
|
|
739
897
|
solid = True
|
|
740
898
|
|
|
741
899
|
t0 = self.calc._temperature
|
|
742
900
|
tf = self.calc._temperature_stop
|
|
743
901
|
li = 1
|
|
744
|
-
lf = t0/tf
|
|
902
|
+
lf = t0 / tf
|
|
745
903
|
pi = self.calc._pressure
|
|
746
|
-
pf = lf*pi
|
|
904
|
+
pf = lf * pi
|
|
747
905
|
|
|
748
|
-
#create lammps object
|
|
749
|
-
lmp = ph.create_object(
|
|
750
|
-
self.
|
|
906
|
+
# create lammps object
|
|
907
|
+
lmp = ph.create_object(
|
|
908
|
+
self.cores,
|
|
909
|
+
self.simfolder,
|
|
910
|
+
self.calc.md.timestep,
|
|
911
|
+
self.calc.md.cmdargs,
|
|
912
|
+
self.calc.md.init_commands,
|
|
913
|
+
)
|
|
751
914
|
|
|
752
915
|
lmp.command("echo log")
|
|
753
|
-
lmp.command("variable li equal %f"%li)
|
|
754
|
-
lmp.command("variable lf equal %f"%lf)
|
|
916
|
+
lmp.command("variable li equal %f" % li)
|
|
917
|
+
lmp.command("variable lf equal %f" % lf)
|
|
755
918
|
|
|
756
|
-
lmp.command(f
|
|
919
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
757
920
|
|
|
758
|
-
#read in conf file
|
|
759
|
-
#conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
921
|
+
# read in conf file
|
|
922
|
+
# conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
760
923
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
761
924
|
lmp = ph.read_data(lmp, conf)
|
|
762
925
|
|
|
763
|
-
#set up potential
|
|
764
|
-
lmp.command(f
|
|
926
|
+
# set up potential
|
|
927
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
765
928
|
lmp = ph.set_mass(lmp, self.calc)
|
|
766
929
|
|
|
767
|
-
#remap the box to get the correct pressure
|
|
930
|
+
# remap the box to get the correct pressure
|
|
768
931
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
769
932
|
|
|
770
|
-
#set thermostat and run equilibrium
|
|
933
|
+
# set thermostat and run equilibrium
|
|
771
934
|
if self.calc.npt:
|
|
772
|
-
lmp.command(
|
|
773
|
-
|
|
935
|
+
lmp.command(
|
|
936
|
+
"fix f1 all npt temp %f %f %f %s %f %f %f"
|
|
937
|
+
% (
|
|
938
|
+
t0,
|
|
939
|
+
t0,
|
|
940
|
+
self.calc.md.thermostat_damping[1],
|
|
941
|
+
self.iso,
|
|
942
|
+
pi,
|
|
943
|
+
pi,
|
|
944
|
+
self.calc.md.barostat_damping[1],
|
|
945
|
+
)
|
|
946
|
+
)
|
|
774
947
|
else:
|
|
775
|
-
lmp.command(
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
948
|
+
lmp.command(
|
|
949
|
+
"fix f1 all nvt temp %f %f %f"
|
|
950
|
+
% (t0, t0, self.calc.md.thermostat_damping[1])
|
|
951
|
+
)
|
|
952
|
+
|
|
953
|
+
self.logger.info(f"Starting equilibration: {iteration}")
|
|
954
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
955
|
+
self.logger.info(f"Finished equilibration: {iteration}")
|
|
780
956
|
|
|
781
957
|
lmp.command("unfix f1")
|
|
782
958
|
|
|
783
|
-
#now fix com
|
|
959
|
+
# now fix com
|
|
784
960
|
lmp.command("variable xcm equal xcm(all,x)")
|
|
785
961
|
lmp.command("variable ycm equal xcm(all,y)")
|
|
786
962
|
lmp.command("variable zcm equal xcm(all,z)")
|
|
787
963
|
|
|
788
964
|
if self.calc.npt:
|
|
789
|
-
lmp.command(
|
|
790
|
-
|
|
965
|
+
lmp.command(
|
|
966
|
+
"fix f1 all npt temp %f %f %f %s %f %f %f fixedpoint ${xcm} ${ycm} ${zcm}"
|
|
967
|
+
% (
|
|
968
|
+
t0,
|
|
969
|
+
t0,
|
|
970
|
+
self.calc.md.thermostat_damping[1],
|
|
971
|
+
self.iso,
|
|
972
|
+
pi,
|
|
973
|
+
pi,
|
|
974
|
+
self.calc.md.barostat_damping[1],
|
|
975
|
+
)
|
|
976
|
+
)
|
|
791
977
|
else:
|
|
792
|
-
lmp.command(
|
|
978
|
+
lmp.command(
|
|
979
|
+
"fix f1 all nvt temp %f %f %f fixedpoint ${xcm} ${ycm} ${zcm}"
|
|
980
|
+
% (t0, t0, self.calc.md.thermostat_damping[1])
|
|
981
|
+
)
|
|
793
982
|
|
|
794
|
-
#compute com and modify fix
|
|
983
|
+
# compute com and modify fix
|
|
795
984
|
lmp.command("compute tcm all temp/com")
|
|
796
985
|
lmp.command("fix_modify f1 temp tcm")
|
|
797
986
|
|
|
798
987
|
lmp.command("variable step equal step")
|
|
799
|
-
lmp.command("variable dU equal c_thermo_pe/atoms")
|
|
988
|
+
lmp.command("variable dU equal c_thermo_pe/atoms")
|
|
800
989
|
lmp.command("thermo_style custom step pe c_tcm press vol")
|
|
801
990
|
lmp.command("thermo 10000")
|
|
802
991
|
|
|
803
|
-
#create velocity and equilibriate
|
|
804
|
-
lmp.command(
|
|
992
|
+
# create velocity and equilibriate
|
|
993
|
+
lmp.command(
|
|
994
|
+
"velocity all create %f %d mom yes rot yes dist gaussian"
|
|
995
|
+
% (t0, np.random.randint(1, 10000))
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
self.logger.info(f"Starting equilibration with constrained com: {iteration}")
|
|
999
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
1000
|
+
self.logger.info(f"Finished equilibration with constrained com: {iteration}")
|
|
805
1001
|
|
|
806
|
-
self.logger.info(f'Starting equilibration with constrained com: {iteration}')
|
|
807
|
-
lmp.command("run %d"%self.calc.n_equilibration_steps)
|
|
808
|
-
self.logger.info(f'Finished equilibration with constrained com: {iteration}')
|
|
809
|
-
|
|
810
1002
|
lmp.command("variable flambda equal ramp(${li},${lf})")
|
|
811
1003
|
lmp.command("variable blambda equal ramp(${lf},${li})")
|
|
812
1004
|
lmp.command("variable fscale equal v_flambda-1.0")
|
|
813
1005
|
lmp.command("variable bscale equal v_blambda-1.0")
|
|
814
1006
|
lmp.command("variable one equal 1.0")
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1007
|
+
lmp.command(
|
|
1008
|
+
f"variable ftemp equal v_blambda*{self.calc._temperature_stop}"
|
|
1009
|
+
)
|
|
1010
|
+
lmp.command(
|
|
1011
|
+
f"variable btemp equal v_flambda*{self.calc._temperature_stop}"
|
|
1012
|
+
)
|
|
1013
|
+
|
|
1014
|
+
# set up potential
|
|
1015
|
+
pc = self.calc.pair_coeff[0]
|
|
818
1016
|
pcraw = pc.split()
|
|
819
|
-
pcnew1 = " ".join(
|
|
820
|
-
|
|
1017
|
+
pcnew1 = " ".join(
|
|
1018
|
+
[
|
|
1019
|
+
*pcraw[:2],
|
|
1020
|
+
*[
|
|
1021
|
+
self.calc._pair_style_names[0],
|
|
1022
|
+
],
|
|
1023
|
+
"1",
|
|
1024
|
+
*pcraw[2:],
|
|
1025
|
+
]
|
|
1026
|
+
)
|
|
1027
|
+
pcnew2 = " ".join(
|
|
1028
|
+
[
|
|
1029
|
+
*pcraw[:2],
|
|
1030
|
+
*[
|
|
1031
|
+
self.calc._pair_style_names[0],
|
|
1032
|
+
],
|
|
1033
|
+
"2",
|
|
1034
|
+
*pcraw[2:],
|
|
1035
|
+
]
|
|
1036
|
+
)
|
|
1037
|
+
|
|
1038
|
+
lmp.command(
|
|
1039
|
+
"pair_style hybrid/scaled v_one %s v_fscale %s"
|
|
1040
|
+
% (
|
|
1041
|
+
self.calc._pair_style_with_options[0],
|
|
1042
|
+
self.calc._pair_style_with_options[0],
|
|
1043
|
+
)
|
|
1044
|
+
)
|
|
1045
|
+
lmp.command("pair_coeff %s" % pcnew1)
|
|
1046
|
+
lmp.command("pair_coeff %s" % pcnew2)
|
|
1047
|
+
|
|
1048
|
+
lmp.command(
|
|
1049
|
+
'fix f3 all print 1 "${dU} $(press) $(vol) ${flambda}" screen no file ts.forward_%d.dat'
|
|
1050
|
+
% iteration
|
|
1051
|
+
)
|
|
1052
|
+
|
|
1053
|
+
# add swaps if n_swap is > 0
|
|
1054
|
+
if self.calc.monte_carlo.n_swaps > 0:
|
|
1055
|
+
self.logger.info(
|
|
1056
|
+
f"{self.calc.monte_carlo.n_swaps} swap moves are performed between {self.calc.monte_carlo.swap_types[0]} and {self.calc.monte_carlo.swap_types[1]} every {self.calc.monte_carlo.n_steps}"
|
|
1057
|
+
)
|
|
1058
|
+
lmp.command(
|
|
1059
|
+
"fix swap all atom/swap %d %d %d ${ftemp} ke yes types %d %d"
|
|
1060
|
+
% (
|
|
1061
|
+
self.calc.monte_carlo.n_steps,
|
|
1062
|
+
self.calc.monte_carlo.n_swaps,
|
|
1063
|
+
np.random.randint(1, 10000),
|
|
1064
|
+
self.calc.monte_carlo.swap_types[0],
|
|
1065
|
+
self.calc.monte_carlo.swap_types[1],
|
|
1066
|
+
)
|
|
1067
|
+
)
|
|
1068
|
+
|
|
1069
|
+
lmp.command("variable a equal f_swap[1]")
|
|
1070
|
+
lmp.command("variable b equal f_swap[2]")
|
|
1071
|
+
lmp.command(
|
|
1072
|
+
'fix swap2 all print 1 "${a} ${b} ${ftemp}" screen no file swap.rs.forward_%d.dat'
|
|
1073
|
+
% iteration
|
|
1074
|
+
)
|
|
821
1075
|
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
1076
|
+
if self.calc.n_print_steps > 0:
|
|
1077
|
+
lmp.command(
|
|
1078
|
+
"dump d1 all custom %d traj.ts.forward_%d.dat id type mass x y z vx vy vz"
|
|
1079
|
+
% (self.calc.n_print_steps, iteration)
|
|
1080
|
+
)
|
|
825
1081
|
|
|
826
|
-
|
|
1082
|
+
self.logger.info(f"Started forward sweep: {iteration}")
|
|
1083
|
+
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1084
|
+
self.logger.info(f"Finished forward sweep: {iteration}")
|
|
827
1085
|
|
|
828
|
-
if self.calc.
|
|
829
|
-
lmp.command("
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
lmp.command("run %d"%self.calc._n_sweep_steps)
|
|
834
|
-
self.logger.info(f'Finished forward sweep: {iteration}')
|
|
835
|
-
|
|
836
|
-
#unfix
|
|
1086
|
+
if self.calc.monte_carlo.n_swaps > 0:
|
|
1087
|
+
lmp.command("unfix swap")
|
|
1088
|
+
lmp.command("unfix swap2")
|
|
1089
|
+
|
|
1090
|
+
# unfix
|
|
837
1091
|
lmp.command("unfix f3")
|
|
838
|
-
#lmp.command("unfix f1")
|
|
1092
|
+
# lmp.command("unfix f1")
|
|
839
1093
|
|
|
840
1094
|
if self.calc.n_print_steps > 0:
|
|
841
1095
|
lmp.command("undump d1")
|
|
842
1096
|
|
|
843
|
-
#switch potential
|
|
844
|
-
lmp.command("run %d"%self.calc.n_equilibration_steps)
|
|
1097
|
+
# switch potential
|
|
1098
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
845
1099
|
|
|
846
|
-
#check melting or freezing
|
|
1100
|
+
# check melting or freezing
|
|
847
1101
|
if not self.calc.script_mode:
|
|
848
1102
|
self.dump_current_snapshot(lmp, "traj.temp.dat")
|
|
849
1103
|
if solid:
|
|
@@ -853,41 +1107,87 @@ class Phase:
|
|
|
853
1107
|
|
|
854
1108
|
lmp = ph.set_potential(lmp, self.calc)
|
|
855
1109
|
|
|
856
|
-
#reverse scaling
|
|
1110
|
+
# reverse scaling
|
|
857
1111
|
lmp.command("variable flambda equal ramp(${li},${lf})")
|
|
858
1112
|
lmp.command("variable blambda equal ramp(${lf},${li})")
|
|
859
1113
|
lmp.command("variable fscale equal v_flambda-1.0")
|
|
860
1114
|
lmp.command("variable bscale equal v_blambda-1.0")
|
|
861
1115
|
lmp.command("variable one equal 1.0")
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
lmp.command(
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1116
|
+
lmp.command(
|
|
1117
|
+
f"variable ftemp equal v_blambda*{self.calc._temperature_stop}"
|
|
1118
|
+
)
|
|
1119
|
+
lmp.command(
|
|
1120
|
+
f"variable btemp equal v_flambda*{self.calc._temperature_stop}"
|
|
1121
|
+
)
|
|
1122
|
+
|
|
1123
|
+
lmp.command(
|
|
1124
|
+
"pair_style hybrid/scaled v_one %s v_bscale %s"
|
|
1125
|
+
% (
|
|
1126
|
+
self.calc._pair_style_with_options[0],
|
|
1127
|
+
self.calc._pair_style_with_options[0],
|
|
1128
|
+
)
|
|
1129
|
+
)
|
|
1130
|
+
lmp.command("pair_coeff %s" % pcnew1)
|
|
1131
|
+
lmp.command("pair_coeff %s" % pcnew2)
|
|
1132
|
+
|
|
1133
|
+
# apply fix and perform switching
|
|
1134
|
+
lmp.command(
|
|
1135
|
+
'fix f3 all print 1 "${dU} $(press) $(vol) ${blambda}" screen no file ts.backward_%d.dat'
|
|
1136
|
+
% iteration
|
|
1137
|
+
)
|
|
869
1138
|
|
|
870
1139
|
if self.calc.n_print_steps > 0:
|
|
871
|
-
lmp.command(
|
|
872
|
-
|
|
1140
|
+
lmp.command(
|
|
1141
|
+
"dump d1 all custom %d traj.ts.backward_%d.dat id type mass x y z vx vy vz"
|
|
1142
|
+
% (self.calc.n_print_steps, iteration)
|
|
1143
|
+
)
|
|
1144
|
+
|
|
1145
|
+
# add swaps if n_swap is > 0
|
|
1146
|
+
if self.calc.monte_carlo.n_swaps > 0:
|
|
1147
|
+
self.logger.info(
|
|
1148
|
+
f"{self.calc.monte_carlo.n_swaps} swap moves are performed between {self.calc.monte_carlo.swap_types[1]} and {self.calc.monte_carlo.swap_types[0]} every {self.calc.monte_carlo.n_steps}"
|
|
1149
|
+
)
|
|
1150
|
+
lmp.command(
|
|
1151
|
+
"fix swap all atom/swap %d %d %d ${btemp} ke yes types %d %d"
|
|
1152
|
+
% (
|
|
1153
|
+
self.calc.monte_carlo.n_steps,
|
|
1154
|
+
self.calc.monte_carlo.n_swaps,
|
|
1155
|
+
np.random.randint(1, 10000),
|
|
1156
|
+
self.calc.monte_carlo.swap_types[1],
|
|
1157
|
+
self.calc.monte_carlo.swap_types[0],
|
|
1158
|
+
)
|
|
1159
|
+
)
|
|
1160
|
+
|
|
1161
|
+
lmp.command("variable a equal f_swap[1]")
|
|
1162
|
+
lmp.command("variable b equal f_swap[2]")
|
|
1163
|
+
lmp.command(
|
|
1164
|
+
'fix swap2 all print 1 "${a} ${b} ${btemp}" screen no file swap.rs.backward_%d.dat'
|
|
1165
|
+
% iteration
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
self.logger.info(f"Started backward sweep: {iteration}")
|
|
1169
|
+
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1170
|
+
self.logger.info(f"Finished backward sweep: {iteration}")
|
|
1171
|
+
|
|
1172
|
+
if self.calc.monte_carlo.n_swaps > 0:
|
|
1173
|
+
lmp.command("unfix swap")
|
|
1174
|
+
lmp.command("unfix swap2")
|
|
873
1175
|
|
|
874
|
-
self.logger.info(f'Started backward sweep: {iteration}')
|
|
875
|
-
lmp.command("run %d"%self.calc._n_sweep_steps)
|
|
876
|
-
self.logger.info(f'Finished backward sweep: {iteration}')
|
|
877
|
-
|
|
878
1176
|
lmp.command("unfix f3")
|
|
879
1177
|
|
|
880
1178
|
if self.calc.n_print_steps > 0:
|
|
881
1179
|
lmp.command("undump d1")
|
|
882
|
-
|
|
883
|
-
#close the object
|
|
1180
|
+
|
|
1181
|
+
# close the object
|
|
884
1182
|
lmp.close()
|
|
885
1183
|
|
|
886
1184
|
self.logger.info("Please cite the following publications:")
|
|
887
1185
|
if self.calc.mode == "mts":
|
|
888
1186
|
self.logger.info("- 10.1063/1.1420486")
|
|
1187
|
+
self.publications.append("10.1063/1.1420486")
|
|
889
1188
|
else:
|
|
890
1189
|
self.logger.info("- 10.1103/PhysRevLett.83.3973")
|
|
1190
|
+
self.publications.append("10.1103/PhysRevLett.83.3973")
|
|
891
1191
|
|
|
892
1192
|
def integrate_reversible_scaling(self, scale_energy=True, return_values=False):
|
|
893
1193
|
"""
|
|
@@ -896,7 +1196,7 @@ class Phase:
|
|
|
896
1196
|
Parameters
|
|
897
1197
|
----------
|
|
898
1198
|
scale_energy : bool, optional
|
|
899
|
-
If True, scale the energy during reversible scaling.
|
|
1199
|
+
If True, scale the energy during reversible scaling.
|
|
900
1200
|
|
|
901
1201
|
return_values : bool, optional
|
|
902
1202
|
If True, return integrated values
|
|
@@ -906,8 +1206,16 @@ class Phase:
|
|
|
906
1206
|
res : list of lists of shape 1x3
|
|
907
1207
|
Only returned if `return_values` is True.
|
|
908
1208
|
"""
|
|
909
|
-
res = integrate_rs(
|
|
910
|
-
|
|
1209
|
+
res = integrate_rs(
|
|
1210
|
+
self.simfolder,
|
|
1211
|
+
self.fe,
|
|
1212
|
+
self.calc._temperature,
|
|
1213
|
+
self.natoms,
|
|
1214
|
+
p=self.calc._pressure,
|
|
1215
|
+
nsims=self.calc.n_iterations,
|
|
1216
|
+
scale_energy=scale_energy,
|
|
1217
|
+
return_values=return_values,
|
|
1218
|
+
)
|
|
911
1219
|
|
|
912
1220
|
if return_values:
|
|
913
1221
|
return res
|
|
@@ -915,80 +1223,118 @@ class Phase:
|
|
|
915
1223
|
def temperature_scaling(self, iteration=1):
|
|
916
1224
|
"""
|
|
917
1225
|
Perform temperature scaling calculation in NPT
|
|
918
|
-
|
|
1226
|
+
|
|
919
1227
|
Parameters
|
|
920
1228
|
----------
|
|
921
1229
|
iteration : int, optional
|
|
922
1230
|
iteration of the calculation. Default 1
|
|
923
|
-
|
|
1231
|
+
|
|
924
1232
|
Returns
|
|
925
1233
|
-------
|
|
926
1234
|
None
|
|
927
1235
|
"""
|
|
928
1236
|
solid = False
|
|
929
|
-
if self.calc.reference_phase ==
|
|
1237
|
+
if self.calc.reference_phase == "solid":
|
|
930
1238
|
solid = True
|
|
931
1239
|
|
|
932
1240
|
t0 = self.calc._temperature
|
|
933
1241
|
tf = self.calc._temperature_stop
|
|
934
1242
|
li = 1
|
|
935
|
-
lf = t0/tf
|
|
1243
|
+
lf = t0 / tf
|
|
936
1244
|
p0 = self.calc._pressure
|
|
937
|
-
pf = lf*p0
|
|
1245
|
+
pf = lf * p0
|
|
938
1246
|
|
|
939
|
-
#create lammps object
|
|
940
|
-
lmp = ph.create_object(
|
|
941
|
-
self.
|
|
1247
|
+
# create lammps object
|
|
1248
|
+
lmp = ph.create_object(
|
|
1249
|
+
self.cores,
|
|
1250
|
+
self.simfolder,
|
|
1251
|
+
self.calc.md.timestep,
|
|
1252
|
+
self.calc.md.cmdargs,
|
|
1253
|
+
self.calc.md.init_commands,
|
|
1254
|
+
)
|
|
942
1255
|
|
|
943
1256
|
lmp.command("echo log")
|
|
944
|
-
lmp.command("variable li equal %f"%li)
|
|
945
|
-
lmp.command("variable lf equal %f"%lf)
|
|
1257
|
+
lmp.command("variable li equal %f" % li)
|
|
1258
|
+
lmp.command("variable lf equal %f" % lf)
|
|
946
1259
|
|
|
947
|
-
lmp.command(f
|
|
1260
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
948
1261
|
|
|
949
|
-
#read in conf
|
|
950
|
-
#conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
1262
|
+
# read in conf
|
|
1263
|
+
# conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
951
1264
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
952
1265
|
lmp = ph.read_data(lmp, conf)
|
|
953
1266
|
|
|
954
|
-
#set up potential
|
|
955
|
-
lmp.command(f
|
|
1267
|
+
# set up potential
|
|
1268
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
956
1269
|
lmp = ph.set_mass(lmp, self.calc)
|
|
957
1270
|
|
|
958
|
-
#remap the box to get the correct pressure
|
|
1271
|
+
# remap the box to get the correct pressure
|
|
959
1272
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
960
1273
|
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1274
|
+
# equilibrate first
|
|
1275
|
+
lmp.command(
|
|
1276
|
+
"fix 1 all npt temp %f %f %f %s %f %f %f"
|
|
1277
|
+
% (
|
|
1278
|
+
t0,
|
|
1279
|
+
t0,
|
|
1280
|
+
self.calc.md.thermostat_damping[1],
|
|
1281
|
+
self.iso,
|
|
1282
|
+
p0,
|
|
1283
|
+
p0,
|
|
1284
|
+
self.calc.md.barostat_damping[1],
|
|
1285
|
+
)
|
|
1286
|
+
)
|
|
1287
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
966
1288
|
lmp.command("unfix 1")
|
|
967
1289
|
|
|
968
|
-
|
|
969
|
-
#now scale system to final temp, thereby recording enerfy at every step
|
|
1290
|
+
# now scale system to final temp, thereby recording enerfy at every step
|
|
970
1291
|
lmp.command("variable step equal step")
|
|
971
1292
|
lmp.command("variable dU equal pe/atoms")
|
|
972
1293
|
lmp.command("variable lambda equal ramp(${li},${lf})")
|
|
973
1294
|
|
|
974
|
-
lmp.command(
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1295
|
+
lmp.command(
|
|
1296
|
+
"fix f2 all npt temp %f %f %f %s %f %f %f"
|
|
1297
|
+
% (
|
|
1298
|
+
t0,
|
|
1299
|
+
tf,
|
|
1300
|
+
self.calc.md.thermostat_damping[1],
|
|
1301
|
+
self.iso,
|
|
1302
|
+
p0,
|
|
1303
|
+
pf,
|
|
1304
|
+
self.calc.md.barostat_damping[1],
|
|
1305
|
+
)
|
|
1306
|
+
)
|
|
1307
|
+
lmp.command(
|
|
1308
|
+
'fix f3 all print 1 "${dU} $(press) $(vol) ${lambda}" screen no file ts.forward_%d.dat'
|
|
1309
|
+
% iteration
|
|
1310
|
+
)
|
|
1311
|
+
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
978
1312
|
|
|
979
1313
|
lmp.command("unfix f2")
|
|
980
1314
|
lmp.command("unfix f3")
|
|
981
1315
|
|
|
982
|
-
lmp.command(
|
|
983
|
-
|
|
984
|
-
|
|
1316
|
+
lmp.command(
|
|
1317
|
+
"fix 1 all npt temp %f %f %f %s %f %f %f"
|
|
1318
|
+
% (
|
|
1319
|
+
tf,
|
|
1320
|
+
tf,
|
|
1321
|
+
self.calc.md.thermostat_damping[1],
|
|
1322
|
+
self.iso,
|
|
1323
|
+
pf,
|
|
1324
|
+
pf,
|
|
1325
|
+
self.calc.md.barostat_damping[1],
|
|
1326
|
+
)
|
|
1327
|
+
)
|
|
1328
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
985
1329
|
lmp.command("unfix 1")
|
|
986
1330
|
|
|
987
|
-
#check melting or freezing
|
|
988
|
-
lmp.command(
|
|
1331
|
+
# check melting or freezing
|
|
1332
|
+
lmp.command(
|
|
1333
|
+
"dump 2 all custom 1 traj.temp.dat id type mass x y z vx vy vz"
|
|
1334
|
+
)
|
|
989
1335
|
lmp.command("run 0")
|
|
990
1336
|
lmp.command("undump 2")
|
|
991
|
-
|
|
1337
|
+
|
|
992
1338
|
if not self.calc.script_mode:
|
|
993
1339
|
self.dump_current_snapshot(lmp, "traj.temp.dat")
|
|
994
1340
|
if solid:
|
|
@@ -996,26 +1342,38 @@ class Phase:
|
|
|
996
1342
|
else:
|
|
997
1343
|
self.check_if_solidfied(lmp, "traj.temp.dat")
|
|
998
1344
|
|
|
999
|
-
#start reverse loop
|
|
1345
|
+
# start reverse loop
|
|
1000
1346
|
lmp.command("variable lambda equal ramp(${lf},${li})")
|
|
1001
1347
|
|
|
1002
|
-
lmp.command(
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1348
|
+
lmp.command(
|
|
1349
|
+
"fix f2 all npt temp %f %f %f %s %f %f %f"
|
|
1350
|
+
% (
|
|
1351
|
+
tf,
|
|
1352
|
+
t0,
|
|
1353
|
+
self.calc.md.thermostat_damping[1],
|
|
1354
|
+
self.iso,
|
|
1355
|
+
pf,
|
|
1356
|
+
p0,
|
|
1357
|
+
self.calc.md.barostat_damping[1],
|
|
1358
|
+
)
|
|
1359
|
+
)
|
|
1360
|
+
lmp.command(
|
|
1361
|
+
'fix f3 all print 1 "${dU} $(press) $(vol) ${lambda}" screen no file ts.backward_%d.dat'
|
|
1362
|
+
% iteration
|
|
1363
|
+
)
|
|
1364
|
+
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1006
1365
|
|
|
1007
1366
|
lmp.close()
|
|
1008
1367
|
|
|
1009
|
-
|
|
1010
1368
|
def pressure_scaling(self, iteration=1):
|
|
1011
1369
|
"""
|
|
1012
1370
|
Perform pressure scaling calculation in NPT
|
|
1013
|
-
|
|
1371
|
+
|
|
1014
1372
|
Parameters
|
|
1015
1373
|
----------
|
|
1016
1374
|
iteration : int, optional
|
|
1017
1375
|
iteration of the calculation. Default 1
|
|
1018
|
-
|
|
1376
|
+
|
|
1019
1377
|
Returns
|
|
1020
1378
|
-------
|
|
1021
1379
|
None
|
|
@@ -1026,91 +1384,162 @@ class Phase:
|
|
|
1026
1384
|
p0 = self.calc._pressure
|
|
1027
1385
|
pf = self.calc._pressure_stop
|
|
1028
1386
|
|
|
1029
|
-
#create lammps object
|
|
1030
|
-
lmp = ph.create_object(
|
|
1031
|
-
self.
|
|
1387
|
+
# create lammps object
|
|
1388
|
+
lmp = ph.create_object(
|
|
1389
|
+
self.cores,
|
|
1390
|
+
self.simfolder,
|
|
1391
|
+
self.calc.md.timestep,
|
|
1392
|
+
self.calc.md.cmdargs,
|
|
1393
|
+
self.calc.md.init_commands,
|
|
1394
|
+
)
|
|
1032
1395
|
|
|
1033
1396
|
lmp.command("echo log")
|
|
1034
|
-
lmp.command("variable li equal %f"%li)
|
|
1035
|
-
lmp.command("variable lf equal %f"%lf)
|
|
1036
|
-
lmp.command("variable p0 equal %f"%p0)
|
|
1037
|
-
lmp.command("variable pf equal %f"%pf)
|
|
1397
|
+
lmp.command("variable li equal %f" % li)
|
|
1398
|
+
lmp.command("variable lf equal %f" % lf)
|
|
1399
|
+
lmp.command("variable p0 equal %f" % p0)
|
|
1400
|
+
lmp.command("variable pf equal %f" % pf)
|
|
1038
1401
|
|
|
1039
|
-
lmp.command(f
|
|
1402
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
1040
1403
|
|
|
1041
|
-
#read in conf
|
|
1042
|
-
#conf = os.path.join(self.simfolder, "conf.dump")
|
|
1404
|
+
# read in conf
|
|
1405
|
+
# conf = os.path.join(self.simfolder, "conf.dump")
|
|
1043
1406
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
1044
1407
|
lmp = ph.read_data(lmp, conf)
|
|
1045
1408
|
|
|
1046
|
-
#set up potential
|
|
1047
|
-
lmp.command(f
|
|
1409
|
+
# set up potential
|
|
1410
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
1048
1411
|
lmp = ph.set_mass(lmp, self.calc)
|
|
1049
1412
|
|
|
1050
|
-
#remap the box to get the correct pressure
|
|
1413
|
+
# remap the box to get the correct pressure
|
|
1051
1414
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
1052
1415
|
|
|
1053
|
-
#equilibrate first
|
|
1054
|
-
lmp.command(
|
|
1055
|
-
|
|
1056
|
-
|
|
1416
|
+
# equilibrate first
|
|
1417
|
+
lmp.command(
|
|
1418
|
+
"fix 1 all npt temp %f %f %f %s %f %f %f"
|
|
1419
|
+
% (
|
|
1420
|
+
t0,
|
|
1421
|
+
t0,
|
|
1422
|
+
self.calc.md.thermostat_damping[1],
|
|
1423
|
+
self.iso,
|
|
1424
|
+
p0,
|
|
1425
|
+
p0,
|
|
1426
|
+
self.calc.md.barostat_damping[1],
|
|
1427
|
+
)
|
|
1428
|
+
)
|
|
1429
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
1057
1430
|
lmp.command("unfix 1")
|
|
1058
1431
|
|
|
1059
|
-
|
|
1060
|
-
#now scale system to final temp, thereby recording enerfy at every step
|
|
1432
|
+
# now scale system to final temp, thereby recording enerfy at every step
|
|
1061
1433
|
lmp.command("variable step equal step")
|
|
1062
1434
|
lmp.command("variable dU equal pe/atoms")
|
|
1063
1435
|
lmp.command("variable lambda equal ramp(${li},${lf})")
|
|
1064
1436
|
lmp.command("variable pp equal ramp(${p0},${pf})")
|
|
1065
1437
|
|
|
1066
|
-
lmp.command(
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1438
|
+
lmp.command(
|
|
1439
|
+
"fix f2 all npt temp %f %f %f %s %f %f %f"
|
|
1440
|
+
% (
|
|
1441
|
+
t0,
|
|
1442
|
+
t0,
|
|
1443
|
+
self.calc.md.thermostat_damping[1],
|
|
1444
|
+
self.iso,
|
|
1445
|
+
p0,
|
|
1446
|
+
pf,
|
|
1447
|
+
self.calc.md.barostat_damping[1],
|
|
1448
|
+
)
|
|
1449
|
+
)
|
|
1450
|
+
lmp.command(
|
|
1451
|
+
'fix f3 all print 1 "${dU} ${pp} $(vol) ${lambda}" screen no file ps.forward_%d.dat'
|
|
1452
|
+
% iteration
|
|
1453
|
+
)
|
|
1454
|
+
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1070
1455
|
|
|
1071
1456
|
lmp.command("unfix f2")
|
|
1072
1457
|
lmp.command("unfix f3")
|
|
1073
1458
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1459
|
+
lmp.command(
|
|
1460
|
+
"fix 1 all npt temp %f %f %f %s %f %f %f"
|
|
1461
|
+
% (
|
|
1462
|
+
t0,
|
|
1463
|
+
t0,
|
|
1464
|
+
self.calc.md.thermostat_damping[1],
|
|
1465
|
+
self.iso,
|
|
1466
|
+
pf,
|
|
1467
|
+
pf,
|
|
1468
|
+
self.calc.md.barostat_damping[1],
|
|
1469
|
+
)
|
|
1470
|
+
)
|
|
1471
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
1078
1472
|
lmp.command("unfix 1")
|
|
1079
1473
|
|
|
1080
|
-
#start reverse loop
|
|
1474
|
+
# start reverse loop
|
|
1081
1475
|
lmp.command("variable lambda equal ramp(${lf},${li})")
|
|
1082
1476
|
lmp.command("variable pp equal ramp(${pf},${p0})")
|
|
1083
1477
|
|
|
1084
|
-
lmp.command(
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1478
|
+
lmp.command(
|
|
1479
|
+
"fix f2 all npt temp %f %f %f %s %f %f %f"
|
|
1480
|
+
% (
|
|
1481
|
+
t0,
|
|
1482
|
+
t0,
|
|
1483
|
+
self.calc.md.thermostat_damping[1],
|
|
1484
|
+
self.iso,
|
|
1485
|
+
pf,
|
|
1486
|
+
p0,
|
|
1487
|
+
self.calc.md.barostat_damping[1],
|
|
1488
|
+
)
|
|
1489
|
+
)
|
|
1490
|
+
lmp.command(
|
|
1491
|
+
'fix f3 all print 1 "${dU} ${pp} $(vol) ${lambda}" screen no file ps.backward_%d.dat'
|
|
1492
|
+
% iteration
|
|
1493
|
+
)
|
|
1494
|
+
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1088
1495
|
|
|
1089
1496
|
lmp.close()
|
|
1090
1497
|
|
|
1091
1498
|
self.logger.info("Please cite the following publications:")
|
|
1092
1499
|
self.logger.info("- 10.1016/j.commatsci.2022.111275")
|
|
1093
|
-
|
|
1094
|
-
|
|
1500
|
+
self.publications.append("10.1016/j.commatsci.2022.111275")
|
|
1501
|
+
|
|
1095
1502
|
def integrate_pressure_scaling(self, return_values=False):
|
|
1096
1503
|
"""
|
|
1097
1504
|
Perform integration after reversible scaling
|
|
1098
|
-
|
|
1505
|
+
|
|
1099
1506
|
Parameters
|
|
1100
1507
|
----------
|
|
1101
1508
|
scale_energy : bool, optional
|
|
1102
|
-
If True, scale the energy during reversible scaling.
|
|
1509
|
+
If True, scale the energy during reversible scaling.
|
|
1103
1510
|
return_values : bool, optional
|
|
1104
1511
|
If True, return integrated values
|
|
1105
|
-
|
|
1512
|
+
|
|
1106
1513
|
Returns
|
|
1107
1514
|
-------
|
|
1108
1515
|
res : list of lists of shape 1x3
|
|
1109
1516
|
Only returned if `return_values` is True.
|
|
1110
1517
|
"""
|
|
1111
|
-
res = integrate_ps(
|
|
1112
|
-
self.
|
|
1113
|
-
|
|
1518
|
+
res = integrate_ps(
|
|
1519
|
+
self.simfolder,
|
|
1520
|
+
self.fe,
|
|
1521
|
+
self.natoms,
|
|
1522
|
+
self.calc._pressure,
|
|
1523
|
+
self.calc._pressure_stop,
|
|
1524
|
+
nsims=self.calc.n_iterations,
|
|
1525
|
+
return_values=return_values,
|
|
1526
|
+
)
|
|
1114
1527
|
|
|
1115
1528
|
if return_values:
|
|
1116
1529
|
return res
|
|
1530
|
+
|
|
1531
|
+
def clean_up(self):
|
|
1532
|
+
"""
|
|
1533
|
+
Run a clean up job
|
|
1534
|
+
"""
|
|
1535
|
+
# serialise input configuration
|
|
1536
|
+
shutil.copy(
|
|
1537
|
+
self.calc.lattice, os.path.join(self.simfolder, "input_configuration.data")
|
|
1538
|
+
)
|
|
1539
|
+
|
|
1540
|
+
# write simple metadata
|
|
1541
|
+
metadata = generate_metadata()
|
|
1542
|
+
metadata["publications"] = self.publications
|
|
1543
|
+
|
|
1544
|
+
with open(os.path.join(self.simfolder, "metadata.yaml"), "w") as fout:
|
|
1545
|
+
yaml.safe_dump(metadata, fout)
|