calphy 1.3.11__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 +815 -378
- calphy/phase_diagram.py +500 -26
- calphy/postprocessing.py +274 -5
- calphy/routines.py +13 -2
- calphy/scheduler.py +2 -0
- calphy/solid.py +35 -0
- {calphy-1.3.11.dist-info → calphy-1.4.2.dist-info}/METADATA +14 -2
- calphy-1.4.2.dist-info/RECORD +25 -0
- {calphy-1.3.11.dist-info → calphy-1.4.2.dist-info}/WHEEL +1 -1
- {calphy-1.3.11.dist-info → calphy-1.4.2.dist-info}/entry_points.txt +1 -0
- calphy-1.3.11.dist-info/RECORD +0 -25
- {calphy-1.3.11.dist-info → calphy-1.4.2.dist-info/licenses}/LICENSE +0 -0
- {calphy-1.3.11.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,59 +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
|
-
|
|
602
|
-
lxpc =
|
|
727
|
+
# we have to clean the data, so as just the last block is selected
|
|
728
|
+
lx, ly, lz, lxpc = np.loadtxt(file, usecols=(1, 2, 3, 4), unpack=True)
|
|
729
|
+
lx = lx[-ncount + 1 :]
|
|
730
|
+
ly = ly[-ncount + 1 :]
|
|
731
|
+
lz = lx[-ncount + 1 :]
|
|
732
|
+
lxpc = lxpc[-ncount + 1 :]
|
|
603
733
|
mean = np.mean(lxpc)
|
|
604
734
|
std = np.std(lxpc)
|
|
605
|
-
volatom = np.mean((lx*ly*lz)/self.natoms)
|
|
735
|
+
volatom = np.mean((lx * ly * lz) / self.natoms)
|
|
606
736
|
return mean, std, volatom
|
|
607
737
|
|
|
608
|
-
def finalise_pressure(
|
|
738
|
+
def finalise_pressure(
|
|
739
|
+
self,
|
|
740
|
+
):
|
|
609
741
|
if self.calc.script_mode:
|
|
610
|
-
ncount = int(self.calc.n_equilibration_steps)//int(
|
|
611
|
-
|
|
612
|
-
|
|
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
|
+
)
|
|
613
749
|
|
|
614
750
|
file = os.path.join(self.simfolder, "avg.dat")
|
|
615
|
-
lx, ly, lz,
|
|
616
|
-
|
|
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 :]
|
|
756
|
+
|
|
617
757
|
mean = np.mean(lxpc)
|
|
618
758
|
std = np.std(lxpc)
|
|
619
|
-
volatom = np.mean((lx*ly*lz)/self.natoms)
|
|
759
|
+
volatom = np.mean((lx * ly * lz) / self.natoms)
|
|
620
760
|
|
|
621
761
|
self.calc._pressure = mean
|
|
622
|
-
self.lx = np.round(np.mean(lx
|
|
623
|
-
self.ly = np.round(np.mean(ly
|
|
624
|
-
self.lz = np.round(np.mean(lz
|
|
762
|
+
self.lx = np.round(np.mean(lx), decimals=3)
|
|
763
|
+
self.ly = np.round(np.mean(ly), decimals=3)
|
|
764
|
+
self.lz = np.round(np.mean(lz), decimals=3)
|
|
625
765
|
self.volatom = volatom
|
|
626
|
-
self.vol = self.lx*self.ly*self.lz
|
|
627
|
-
self.rho = self.natoms/(self.lx*self.ly*self.lz)
|
|
628
|
-
self.logger.info("finalized vol/atom %f at pressure %f"%(self.volatom, mean))
|
|
629
|
-
self.logger.info(
|
|
630
|
-
|
|
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
|
+
)
|
|
631
772
|
|
|
632
773
|
def run_minimal_constrained_pressure_convergence(self, lmp):
|
|
633
|
-
"""
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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
|
+
)
|
|
637
787
|
lmp.command("thermo_style custom step pe press vol etotal temp lx ly lz")
|
|
638
788
|
lmp.command("thermo 10")
|
|
639
|
-
|
|
640
|
-
#this is when the averaging routine starts
|
|
641
|
-
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),
|
|
642
|
-
int(self.calc.md.n_repeat_steps), int(self.calc.md.n_every_steps*self.calc.md.n_repeat_steps)))
|
|
643
789
|
|
|
644
|
-
|
|
645
|
-
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))
|
|
646
802
|
|
|
647
803
|
lmp.command("unfix 1")
|
|
648
804
|
lmp.command("unfix 2")
|
|
@@ -662,24 +818,30 @@ class Phase:
|
|
|
662
818
|
"""
|
|
663
819
|
report = {}
|
|
664
820
|
|
|
665
|
-
#input quantities
|
|
821
|
+
# input quantities
|
|
666
822
|
report["input"] = {}
|
|
667
823
|
report["input"]["temperature"] = int(self.calc._temperature)
|
|
668
824
|
report["input"]["pressure"] = float(self.calc._pressure)
|
|
669
825
|
report["input"]["lattice"] = str(self.calc._original_lattice)
|
|
670
826
|
report["input"]["element"] = " ".join(np.array(self.calc.element).astype(str))
|
|
671
|
-
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
|
+
)
|
|
672
832
|
|
|
673
|
-
#average quantities
|
|
833
|
+
# average quantities
|
|
674
834
|
report["average"] = {}
|
|
675
835
|
report["average"]["vol_atom"] = float(self.volatom)
|
|
676
|
-
|
|
836
|
+
|
|
677
837
|
if self.k is not None:
|
|
678
|
-
report["average"]["spring_constant"] = " ".join(
|
|
838
|
+
report["average"]["spring_constant"] = " ".join(
|
|
839
|
+
np.array(self.k).astype(str)
|
|
840
|
+
)
|
|
679
841
|
if self.rho is not None:
|
|
680
842
|
report["average"]["density"] = float(self.rho)
|
|
681
843
|
|
|
682
|
-
#results
|
|
844
|
+
# results
|
|
683
845
|
report["results"] = {}
|
|
684
846
|
report["results"]["free_energy"] = float(self.fe)
|
|
685
847
|
report["results"]["error"] = float(self.ferr)
|
|
@@ -696,21 +858,25 @@ class Phase:
|
|
|
696
858
|
self.report = report
|
|
697
859
|
|
|
698
860
|
reportfile = os.path.join(self.simfolder, "report.yaml")
|
|
699
|
-
with open(reportfile,
|
|
861
|
+
with open(reportfile, "w") as f:
|
|
700
862
|
yaml.dump(report, f)
|
|
701
863
|
|
|
702
|
-
self.logger.info("Report written in %s"%reportfile)
|
|
864
|
+
self.logger.info("Report written in %s" % reportfile)
|
|
703
865
|
|
|
704
|
-
#now we have to write out the results
|
|
866
|
+
# now we have to write out the results
|
|
705
867
|
self.logger.info("Please cite the following publications:")
|
|
706
868
|
self.logger.info("- 10.1103/PhysRevMaterials.5.103801")
|
|
869
|
+
self.publications.append("10.1103/PhysRevMaterials.5.103801")
|
|
707
870
|
|
|
708
871
|
if self.calc.mode == "fe":
|
|
709
872
|
if self.calc.reference_phase == "solid":
|
|
710
873
|
self.logger.info("- 10.1016/j.commatsci.2015.10.050")
|
|
874
|
+
self.publications.append("10.1016/j.commatsci.2015.10.050")
|
|
711
875
|
else:
|
|
712
876
|
self.logger.info("- 10.1016/j.commatsci.2018.12.029")
|
|
713
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")
|
|
714
880
|
|
|
715
881
|
def reversible_scaling(self, iteration=1):
|
|
716
882
|
"""
|
|
@@ -725,117 +891,213 @@ class Phase:
|
|
|
725
891
|
-------
|
|
726
892
|
None
|
|
727
893
|
"""
|
|
728
|
-
self.logger.info(f
|
|
894
|
+
self.logger.info(f"Starting temperature sweep cycle: {iteration}")
|
|
729
895
|
solid = False
|
|
730
|
-
if self.calc.reference_phase ==
|
|
896
|
+
if self.calc.reference_phase == "solid":
|
|
731
897
|
solid = True
|
|
732
898
|
|
|
733
899
|
t0 = self.calc._temperature
|
|
734
900
|
tf = self.calc._temperature_stop
|
|
735
901
|
li = 1
|
|
736
|
-
lf = t0/tf
|
|
902
|
+
lf = t0 / tf
|
|
737
903
|
pi = self.calc._pressure
|
|
738
|
-
pf = lf*pi
|
|
904
|
+
pf = lf * pi
|
|
739
905
|
|
|
740
|
-
#create lammps object
|
|
741
|
-
lmp = ph.create_object(
|
|
742
|
-
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
|
+
)
|
|
743
914
|
|
|
744
915
|
lmp.command("echo log")
|
|
745
|
-
lmp.command("variable li equal %f"%li)
|
|
746
|
-
lmp.command("variable lf equal %f"%lf)
|
|
916
|
+
lmp.command("variable li equal %f" % li)
|
|
917
|
+
lmp.command("variable lf equal %f" % lf)
|
|
747
918
|
|
|
748
|
-
lmp.command(f
|
|
919
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
749
920
|
|
|
750
|
-
#read in conf file
|
|
751
|
-
#conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
921
|
+
# read in conf file
|
|
922
|
+
# conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
752
923
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
753
924
|
lmp = ph.read_data(lmp, conf)
|
|
754
925
|
|
|
755
|
-
#set up potential
|
|
756
|
-
lmp.command(f
|
|
926
|
+
# set up potential
|
|
927
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
757
928
|
lmp = ph.set_mass(lmp, self.calc)
|
|
758
929
|
|
|
759
|
-
#remap the box to get the correct pressure
|
|
930
|
+
# remap the box to get the correct pressure
|
|
760
931
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
761
932
|
|
|
762
|
-
#set thermostat and run equilibrium
|
|
933
|
+
# set thermostat and run equilibrium
|
|
763
934
|
if self.calc.npt:
|
|
764
|
-
lmp.command(
|
|
765
|
-
|
|
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
|
+
)
|
|
766
947
|
else:
|
|
767
|
-
lmp.command(
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
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}")
|
|
772
956
|
|
|
773
957
|
lmp.command("unfix f1")
|
|
774
958
|
|
|
775
|
-
#now fix com
|
|
959
|
+
# now fix com
|
|
776
960
|
lmp.command("variable xcm equal xcm(all,x)")
|
|
777
961
|
lmp.command("variable ycm equal xcm(all,y)")
|
|
778
962
|
lmp.command("variable zcm equal xcm(all,z)")
|
|
779
963
|
|
|
780
964
|
if self.calc.npt:
|
|
781
|
-
lmp.command(
|
|
782
|
-
|
|
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
|
+
)
|
|
783
977
|
else:
|
|
784
|
-
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
|
+
)
|
|
785
982
|
|
|
786
|
-
#compute com and modify fix
|
|
983
|
+
# compute com and modify fix
|
|
787
984
|
lmp.command("compute tcm all temp/com")
|
|
788
985
|
lmp.command("fix_modify f1 temp tcm")
|
|
789
986
|
|
|
790
987
|
lmp.command("variable step equal step")
|
|
791
|
-
lmp.command("variable dU equal c_thermo_pe/atoms")
|
|
988
|
+
lmp.command("variable dU equal c_thermo_pe/atoms")
|
|
792
989
|
lmp.command("thermo_style custom step pe c_tcm press vol")
|
|
793
990
|
lmp.command("thermo 10000")
|
|
794
991
|
|
|
795
|
-
#create velocity and equilibriate
|
|
796
|
-
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}")
|
|
797
1001
|
|
|
798
|
-
self.logger.info(f'Starting equilibration with constrained com: {iteration}')
|
|
799
|
-
lmp.command("run %d"%self.calc.n_equilibration_steps)
|
|
800
|
-
self.logger.info(f'Finished equilibration with constrained com: {iteration}')
|
|
801
|
-
|
|
802
1002
|
lmp.command("variable flambda equal ramp(${li},${lf})")
|
|
803
1003
|
lmp.command("variable blambda equal ramp(${lf},${li})")
|
|
804
1004
|
lmp.command("variable fscale equal v_flambda-1.0")
|
|
805
1005
|
lmp.command("variable bscale equal v_blambda-1.0")
|
|
806
1006
|
lmp.command("variable one equal 1.0")
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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]
|
|
810
1016
|
pcraw = pc.split()
|
|
811
|
-
pcnew1 = " ".join(
|
|
812
|
-
|
|
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
|
+
)
|
|
813
1075
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
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
|
+
)
|
|
817
1081
|
|
|
818
|
-
|
|
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}")
|
|
819
1085
|
|
|
820
|
-
if self.calc.
|
|
821
|
-
lmp.command("
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
lmp.command("run %d"%self.calc._n_sweep_steps)
|
|
826
|
-
self.logger.info(f'Finished forward sweep: {iteration}')
|
|
827
|
-
|
|
828
|
-
#unfix
|
|
1086
|
+
if self.calc.monte_carlo.n_swaps > 0:
|
|
1087
|
+
lmp.command("unfix swap")
|
|
1088
|
+
lmp.command("unfix swap2")
|
|
1089
|
+
|
|
1090
|
+
# unfix
|
|
829
1091
|
lmp.command("unfix f3")
|
|
830
|
-
#lmp.command("unfix f1")
|
|
1092
|
+
# lmp.command("unfix f1")
|
|
831
1093
|
|
|
832
1094
|
if self.calc.n_print_steps > 0:
|
|
833
1095
|
lmp.command("undump d1")
|
|
834
1096
|
|
|
835
|
-
#switch potential
|
|
836
|
-
lmp.command("run %d"%self.calc.n_equilibration_steps)
|
|
1097
|
+
# switch potential
|
|
1098
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
837
1099
|
|
|
838
|
-
#check melting or freezing
|
|
1100
|
+
# check melting or freezing
|
|
839
1101
|
if not self.calc.script_mode:
|
|
840
1102
|
self.dump_current_snapshot(lmp, "traj.temp.dat")
|
|
841
1103
|
if solid:
|
|
@@ -845,41 +1107,87 @@ class Phase:
|
|
|
845
1107
|
|
|
846
1108
|
lmp = ph.set_potential(lmp, self.calc)
|
|
847
1109
|
|
|
848
|
-
#reverse scaling
|
|
1110
|
+
# reverse scaling
|
|
849
1111
|
lmp.command("variable flambda equal ramp(${li},${lf})")
|
|
850
1112
|
lmp.command("variable blambda equal ramp(${lf},${li})")
|
|
851
1113
|
lmp.command("variable fscale equal v_flambda-1.0")
|
|
852
1114
|
lmp.command("variable bscale equal v_blambda-1.0")
|
|
853
1115
|
lmp.command("variable one equal 1.0")
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
lmp.command(
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
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
|
+
)
|
|
861
1138
|
|
|
862
1139
|
if self.calc.n_print_steps > 0:
|
|
863
|
-
lmp.command(
|
|
864
|
-
|
|
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")
|
|
865
1175
|
|
|
866
|
-
self.logger.info(f'Started backward sweep: {iteration}')
|
|
867
|
-
lmp.command("run %d"%self.calc._n_sweep_steps)
|
|
868
|
-
self.logger.info(f'Finished backward sweep: {iteration}')
|
|
869
|
-
|
|
870
1176
|
lmp.command("unfix f3")
|
|
871
1177
|
|
|
872
1178
|
if self.calc.n_print_steps > 0:
|
|
873
1179
|
lmp.command("undump d1")
|
|
874
|
-
|
|
875
|
-
#close the object
|
|
1180
|
+
|
|
1181
|
+
# close the object
|
|
876
1182
|
lmp.close()
|
|
877
1183
|
|
|
878
1184
|
self.logger.info("Please cite the following publications:")
|
|
879
1185
|
if self.calc.mode == "mts":
|
|
880
1186
|
self.logger.info("- 10.1063/1.1420486")
|
|
1187
|
+
self.publications.append("10.1063/1.1420486")
|
|
881
1188
|
else:
|
|
882
1189
|
self.logger.info("- 10.1103/PhysRevLett.83.3973")
|
|
1190
|
+
self.publications.append("10.1103/PhysRevLett.83.3973")
|
|
883
1191
|
|
|
884
1192
|
def integrate_reversible_scaling(self, scale_energy=True, return_values=False):
|
|
885
1193
|
"""
|
|
@@ -888,7 +1196,7 @@ class Phase:
|
|
|
888
1196
|
Parameters
|
|
889
1197
|
----------
|
|
890
1198
|
scale_energy : bool, optional
|
|
891
|
-
If True, scale the energy during reversible scaling.
|
|
1199
|
+
If True, scale the energy during reversible scaling.
|
|
892
1200
|
|
|
893
1201
|
return_values : bool, optional
|
|
894
1202
|
If True, return integrated values
|
|
@@ -898,8 +1206,16 @@ class Phase:
|
|
|
898
1206
|
res : list of lists of shape 1x3
|
|
899
1207
|
Only returned if `return_values` is True.
|
|
900
1208
|
"""
|
|
901
|
-
res = integrate_rs(
|
|
902
|
-
|
|
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
|
+
)
|
|
903
1219
|
|
|
904
1220
|
if return_values:
|
|
905
1221
|
return res
|
|
@@ -907,80 +1223,118 @@ class Phase:
|
|
|
907
1223
|
def temperature_scaling(self, iteration=1):
|
|
908
1224
|
"""
|
|
909
1225
|
Perform temperature scaling calculation in NPT
|
|
910
|
-
|
|
1226
|
+
|
|
911
1227
|
Parameters
|
|
912
1228
|
----------
|
|
913
1229
|
iteration : int, optional
|
|
914
1230
|
iteration of the calculation. Default 1
|
|
915
|
-
|
|
1231
|
+
|
|
916
1232
|
Returns
|
|
917
1233
|
-------
|
|
918
1234
|
None
|
|
919
1235
|
"""
|
|
920
1236
|
solid = False
|
|
921
|
-
if self.calc.reference_phase ==
|
|
1237
|
+
if self.calc.reference_phase == "solid":
|
|
922
1238
|
solid = True
|
|
923
1239
|
|
|
924
1240
|
t0 = self.calc._temperature
|
|
925
1241
|
tf = self.calc._temperature_stop
|
|
926
1242
|
li = 1
|
|
927
|
-
lf = t0/tf
|
|
1243
|
+
lf = t0 / tf
|
|
928
1244
|
p0 = self.calc._pressure
|
|
929
|
-
pf = lf*p0
|
|
1245
|
+
pf = lf * p0
|
|
930
1246
|
|
|
931
|
-
#create lammps object
|
|
932
|
-
lmp = ph.create_object(
|
|
933
|
-
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
|
+
)
|
|
934
1255
|
|
|
935
1256
|
lmp.command("echo log")
|
|
936
|
-
lmp.command("variable li equal %f"%li)
|
|
937
|
-
lmp.command("variable lf equal %f"%lf)
|
|
1257
|
+
lmp.command("variable li equal %f" % li)
|
|
1258
|
+
lmp.command("variable lf equal %f" % lf)
|
|
938
1259
|
|
|
939
|
-
lmp.command(f
|
|
1260
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
940
1261
|
|
|
941
|
-
#read in conf
|
|
942
|
-
#conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
1262
|
+
# read in conf
|
|
1263
|
+
# conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
943
1264
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
944
1265
|
lmp = ph.read_data(lmp, conf)
|
|
945
1266
|
|
|
946
|
-
#set up potential
|
|
947
|
-
lmp.command(f
|
|
1267
|
+
# set up potential
|
|
1268
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
948
1269
|
lmp = ph.set_mass(lmp, self.calc)
|
|
949
1270
|
|
|
950
|
-
#remap the box to get the correct pressure
|
|
1271
|
+
# remap the box to get the correct pressure
|
|
951
1272
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
952
1273
|
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
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)
|
|
958
1288
|
lmp.command("unfix 1")
|
|
959
1289
|
|
|
960
|
-
|
|
961
|
-
#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
|
|
962
1291
|
lmp.command("variable step equal step")
|
|
963
1292
|
lmp.command("variable dU equal pe/atoms")
|
|
964
1293
|
lmp.command("variable lambda equal ramp(${li},${lf})")
|
|
965
1294
|
|
|
966
|
-
lmp.command(
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
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)
|
|
970
1312
|
|
|
971
1313
|
lmp.command("unfix f2")
|
|
972
1314
|
lmp.command("unfix f3")
|
|
973
1315
|
|
|
974
|
-
lmp.command(
|
|
975
|
-
|
|
976
|
-
|
|
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)
|
|
977
1329
|
lmp.command("unfix 1")
|
|
978
1330
|
|
|
979
|
-
#check melting or freezing
|
|
980
|
-
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
|
+
)
|
|
981
1335
|
lmp.command("run 0")
|
|
982
1336
|
lmp.command("undump 2")
|
|
983
|
-
|
|
1337
|
+
|
|
984
1338
|
if not self.calc.script_mode:
|
|
985
1339
|
self.dump_current_snapshot(lmp, "traj.temp.dat")
|
|
986
1340
|
if solid:
|
|
@@ -988,26 +1342,38 @@ class Phase:
|
|
|
988
1342
|
else:
|
|
989
1343
|
self.check_if_solidfied(lmp, "traj.temp.dat")
|
|
990
1344
|
|
|
991
|
-
#start reverse loop
|
|
1345
|
+
# start reverse loop
|
|
992
1346
|
lmp.command("variable lambda equal ramp(${lf},${li})")
|
|
993
1347
|
|
|
994
|
-
lmp.command(
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
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)
|
|
998
1365
|
|
|
999
1366
|
lmp.close()
|
|
1000
1367
|
|
|
1001
|
-
|
|
1002
1368
|
def pressure_scaling(self, iteration=1):
|
|
1003
1369
|
"""
|
|
1004
1370
|
Perform pressure scaling calculation in NPT
|
|
1005
|
-
|
|
1371
|
+
|
|
1006
1372
|
Parameters
|
|
1007
1373
|
----------
|
|
1008
1374
|
iteration : int, optional
|
|
1009
1375
|
iteration of the calculation. Default 1
|
|
1010
|
-
|
|
1376
|
+
|
|
1011
1377
|
Returns
|
|
1012
1378
|
-------
|
|
1013
1379
|
None
|
|
@@ -1018,91 +1384,162 @@ class Phase:
|
|
|
1018
1384
|
p0 = self.calc._pressure
|
|
1019
1385
|
pf = self.calc._pressure_stop
|
|
1020
1386
|
|
|
1021
|
-
#create lammps object
|
|
1022
|
-
lmp = ph.create_object(
|
|
1023
|
-
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
|
+
)
|
|
1024
1395
|
|
|
1025
1396
|
lmp.command("echo log")
|
|
1026
|
-
lmp.command("variable li equal %f"%li)
|
|
1027
|
-
lmp.command("variable lf equal %f"%lf)
|
|
1028
|
-
lmp.command("variable p0 equal %f"%p0)
|
|
1029
|
-
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)
|
|
1030
1401
|
|
|
1031
|
-
lmp.command(f
|
|
1402
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
1032
1403
|
|
|
1033
|
-
#read in conf
|
|
1034
|
-
#conf = os.path.join(self.simfolder, "conf.dump")
|
|
1404
|
+
# read in conf
|
|
1405
|
+
# conf = os.path.join(self.simfolder, "conf.dump")
|
|
1035
1406
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
1036
1407
|
lmp = ph.read_data(lmp, conf)
|
|
1037
1408
|
|
|
1038
|
-
#set up potential
|
|
1039
|
-
lmp.command(f
|
|
1409
|
+
# set up potential
|
|
1410
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
1040
1411
|
lmp = ph.set_mass(lmp, self.calc)
|
|
1041
1412
|
|
|
1042
|
-
#remap the box to get the correct pressure
|
|
1413
|
+
# remap the box to get the correct pressure
|
|
1043
1414
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
1044
1415
|
|
|
1045
|
-
#equilibrate first
|
|
1046
|
-
lmp.command(
|
|
1047
|
-
|
|
1048
|
-
|
|
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)
|
|
1049
1430
|
lmp.command("unfix 1")
|
|
1050
1431
|
|
|
1051
|
-
|
|
1052
|
-
#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
|
|
1053
1433
|
lmp.command("variable step equal step")
|
|
1054
1434
|
lmp.command("variable dU equal pe/atoms")
|
|
1055
1435
|
lmp.command("variable lambda equal ramp(${li},${lf})")
|
|
1056
1436
|
lmp.command("variable pp equal ramp(${p0},${pf})")
|
|
1057
1437
|
|
|
1058
|
-
lmp.command(
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
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)
|
|
1062
1455
|
|
|
1063
1456
|
lmp.command("unfix f2")
|
|
1064
1457
|
lmp.command("unfix f3")
|
|
1065
1458
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
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)
|
|
1070
1472
|
lmp.command("unfix 1")
|
|
1071
1473
|
|
|
1072
|
-
#start reverse loop
|
|
1474
|
+
# start reverse loop
|
|
1073
1475
|
lmp.command("variable lambda equal ramp(${lf},${li})")
|
|
1074
1476
|
lmp.command("variable pp equal ramp(${pf},${p0})")
|
|
1075
1477
|
|
|
1076
|
-
lmp.command(
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
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)
|
|
1080
1495
|
|
|
1081
1496
|
lmp.close()
|
|
1082
1497
|
|
|
1083
1498
|
self.logger.info("Please cite the following publications:")
|
|
1084
1499
|
self.logger.info("- 10.1016/j.commatsci.2022.111275")
|
|
1085
|
-
|
|
1086
|
-
|
|
1500
|
+
self.publications.append("10.1016/j.commatsci.2022.111275")
|
|
1501
|
+
|
|
1087
1502
|
def integrate_pressure_scaling(self, return_values=False):
|
|
1088
1503
|
"""
|
|
1089
1504
|
Perform integration after reversible scaling
|
|
1090
|
-
|
|
1505
|
+
|
|
1091
1506
|
Parameters
|
|
1092
1507
|
----------
|
|
1093
1508
|
scale_energy : bool, optional
|
|
1094
|
-
If True, scale the energy during reversible scaling.
|
|
1509
|
+
If True, scale the energy during reversible scaling.
|
|
1095
1510
|
return_values : bool, optional
|
|
1096
1511
|
If True, return integrated values
|
|
1097
|
-
|
|
1512
|
+
|
|
1098
1513
|
Returns
|
|
1099
1514
|
-------
|
|
1100
1515
|
res : list of lists of shape 1x3
|
|
1101
1516
|
Only returned if `return_values` is True.
|
|
1102
1517
|
"""
|
|
1103
|
-
res = integrate_ps(
|
|
1104
|
-
self.
|
|
1105
|
-
|
|
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
|
+
)
|
|
1106
1527
|
|
|
1107
1528
|
if return_values:
|
|
1108
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)
|