calphy 1.4.6__py3-none-any.whl → 1.4.12__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 +278 -158
- calphy/composition_transformation.py +148 -54
- calphy/helpers.py +3 -1
- calphy/input.py +1 -2
- calphy/liquid.py +13 -0
- calphy/phase.py +55 -4
- calphy/phase_diagram.py +2 -1
- calphy/routines.py +6 -0
- calphy/solid.py +243 -186
- {calphy-1.4.6.dist-info → calphy-1.4.12.dist-info}/METADATA +1 -1
- calphy-1.4.12.dist-info/RECORD +25 -0
- {calphy-1.4.6.dist-info → calphy-1.4.12.dist-info}/WHEEL +1 -1
- calphy-1.4.6.dist-info/RECORD +0 -25
- {calphy-1.4.6.dist-info → calphy-1.4.12.dist-info}/entry_points.txt +0 -0
- {calphy-1.4.6.dist-info → calphy-1.4.12.dist-info}/licenses/LICENSE +0 -0
- {calphy-1.4.6.dist-info → calphy-1.4.12.dist-info}/top_level.txt +0 -0
calphy/solid.py
CHANGED
|
@@ -3,14 +3,14 @@ calphy: a Python library and command line interface for automated free
|
|
|
3
3
|
energy calculations.
|
|
4
4
|
|
|
5
5
|
Copyright 2021 (c) Sarath Menon^1, Yury Lysogorskiy^2, Ralf Drautz^2
|
|
6
|
-
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
|
|
6
|
+
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
|
|
7
7
|
^2: Ruhr-University Bochum, Bochum, Germany
|
|
8
8
|
|
|
9
|
-
calphy is published and distributed under the Academic Software License v1.0 (ASL).
|
|
10
|
-
calphy is distributed in the hope that it will be useful for non-commercial academic research,
|
|
11
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
9
|
+
calphy is published and distributed under the Academic Software License v1.0 (ASL).
|
|
10
|
+
calphy is distributed in the hope that it will be useful for non-commercial academic research,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
12
12
|
calphy API is published and distributed under the BSD 3-Clause "New" or "Revised" License
|
|
13
|
-
See the LICENSE FILE for more details.
|
|
13
|
+
See the LICENSE FILE for more details.
|
|
14
14
|
|
|
15
15
|
More information about the program can be found in:
|
|
16
16
|
Menon, Sarath, Yury Lysogorskiy, Jutta Rogal, and Ralf Drautz.
|
|
@@ -25,12 +25,14 @@ import numpy as np
|
|
|
25
25
|
import yaml
|
|
26
26
|
import copy
|
|
27
27
|
import sys
|
|
28
|
+
import os
|
|
28
29
|
|
|
29
30
|
from calphy.integrators import *
|
|
30
31
|
import calphy.helpers as ph
|
|
31
32
|
import calphy.phase as cph
|
|
32
33
|
from calphy.errors import *
|
|
33
34
|
|
|
35
|
+
|
|
34
36
|
class Solid(cph.Phase):
|
|
35
37
|
"""
|
|
36
38
|
Class for free energy calculation with solid as the reference state
|
|
@@ -39,7 +41,7 @@ class Solid(cph.Phase):
|
|
|
39
41
|
----------
|
|
40
42
|
options : dict
|
|
41
43
|
dict of input options
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
kernel : int
|
|
44
46
|
the index of the calculation that should be run from
|
|
45
47
|
the list of calculations in the input file
|
|
@@ -48,12 +50,13 @@ class Solid(cph.Phase):
|
|
|
48
50
|
base folder for running calculations
|
|
49
51
|
|
|
50
52
|
"""
|
|
53
|
+
|
|
51
54
|
def __init__(self, calculation=None, simfolder=None, log_to_screen=False):
|
|
52
55
|
|
|
53
|
-
#call base class
|
|
54
|
-
super().__init__(
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
# call base class
|
|
57
|
+
super().__init__(
|
|
58
|
+
calculation=calculation, simfolder=simfolder, log_to_screen=log_to_screen
|
|
59
|
+
)
|
|
57
60
|
|
|
58
61
|
def run_spring_constant_convergence(self, lmp):
|
|
59
62
|
if self.calc.script_mode:
|
|
@@ -62,32 +65,43 @@ class Solid(cph.Phase):
|
|
|
62
65
|
self.run_iterative_spring_constant_convergence(lmp)
|
|
63
66
|
|
|
64
67
|
def run_iterative_spring_constant_convergence(self, lmp):
|
|
65
|
-
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
68
|
+
""" """
|
|
69
|
+
lmp.command(
|
|
70
|
+
"fix 3 all nvt temp %f %f %f"
|
|
71
|
+
% (
|
|
72
|
+
self.calc._temperature,
|
|
73
|
+
self.calc._temperature,
|
|
74
|
+
self.calc.md.thermostat_damping[1],
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# apply fix
|
|
70
79
|
lmp = ph.compute_msd(lmp, self.calc)
|
|
71
|
-
|
|
80
|
+
|
|
72
81
|
if ph.check_if_any_is_none(self.calc.spring_constants):
|
|
73
|
-
#similar averaging routine
|
|
82
|
+
# similar averaging routine
|
|
74
83
|
laststd = 0.00
|
|
75
84
|
for i in range(self.calc.md.n_cycles):
|
|
76
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
85
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
77
86
|
k_mean, k_std = self.analyse_spring_constants()
|
|
78
|
-
self.logger.info(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
self.logger.info(
|
|
88
|
+
"At count %d mean k is %f std is %f" % (i + 1, k_mean[0], k_std[0])
|
|
89
|
+
)
|
|
90
|
+
if np.abs(laststd - k_std[0]) < self.calc.tolerance.spring_constant:
|
|
91
|
+
# now reevaluate spring constants
|
|
92
|
+
self.assign_spring_constants(k_mean)
|
|
82
93
|
break
|
|
83
94
|
laststd = k_std[0]
|
|
84
95
|
|
|
85
96
|
else:
|
|
86
97
|
if not (len(self.calc.spring_constants) == self.calc.n_elements):
|
|
87
|
-
raise ValueError(
|
|
98
|
+
raise ValueError(
|
|
99
|
+
"Spring constant input length should be same as number of elements, spring constant length %d, # elements %d"
|
|
100
|
+
% (len(self.calc.spring_constants), self.calc.n_elements)
|
|
101
|
+
)
|
|
88
102
|
|
|
89
|
-
#still run a small NVT cycle
|
|
90
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
103
|
+
# still run a small NVT cycle
|
|
104
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
91
105
|
self.k = self.calc.spring_constants
|
|
92
106
|
self.logger.info("Used user input sprint constants")
|
|
93
107
|
self.logger.info(self.k)
|
|
@@ -99,64 +113,75 @@ class Solid(cph.Phase):
|
|
|
99
113
|
Analyse spring constant routine
|
|
100
114
|
"""
|
|
101
115
|
if self.calc.script_mode:
|
|
102
|
-
ncount = int(self.calc.md.n_small_steps)//int(
|
|
116
|
+
ncount = int(self.calc.md.n_small_steps) // int(
|
|
117
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
118
|
+
)
|
|
103
119
|
else:
|
|
104
|
-
ncount = int(self.calc.n_equilibration_steps)//int(
|
|
105
|
-
|
|
106
|
-
|
|
120
|
+
ncount = int(self.calc.n_equilibration_steps) // int(
|
|
121
|
+
self.calc.md.n_every_steps * self.calc.md.n_repeat_steps
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# now we can check if it converted
|
|
107
125
|
file = os.path.join(self.simfolder, "msd.dat")
|
|
108
126
|
k_mean = []
|
|
109
127
|
k_std = []
|
|
110
128
|
for i in range(self.calc.n_elements):
|
|
111
|
-
quant = np.loadtxt(file, usecols=(i+1,
|
|
129
|
+
quant = np.loadtxt(file, usecols=(i + 1,), unpack=True)[-ncount + 1 :]
|
|
112
130
|
mean_quant = np.round(np.mean(quant), decimals=2)
|
|
113
131
|
std_quant = np.round(np.std(quant), decimals=2)
|
|
114
132
|
if mean_quant == 0:
|
|
115
133
|
mean_quant = 1.00
|
|
116
|
-
mean_quant = 3*kb*self.calc._temperature/mean_quant
|
|
134
|
+
mean_quant = 3 * kb * self.calc._temperature / mean_quant
|
|
117
135
|
k_mean.append(mean_quant)
|
|
118
136
|
k_std.append(std_quant)
|
|
119
137
|
return k_mean, k_std
|
|
120
|
-
|
|
121
138
|
|
|
122
139
|
def assign_spring_constants(self, k):
|
|
123
140
|
"""
|
|
124
141
|
Here the spring constants are finalised, add added to the class
|
|
125
142
|
"""
|
|
126
|
-
#first replace any provided values with user values
|
|
143
|
+
# first replace any provided values with user values
|
|
127
144
|
if ph.check_if_any_is_not_none(self.calc.spring_constants):
|
|
128
145
|
spring_constants = copy.copy(self.calc.spring_constants)
|
|
129
146
|
k = ph.replace_nones(spring_constants, k, logger=self.logger)
|
|
130
|
-
|
|
131
|
-
#add sanity checks
|
|
147
|
+
|
|
148
|
+
# add sanity checks
|
|
132
149
|
k = ph.validate_spring_constants(k, logger=self.logger)
|
|
133
|
-
|
|
134
|
-
#now save
|
|
150
|
+
|
|
151
|
+
# now save
|
|
135
152
|
self.k = k
|
|
136
153
|
|
|
137
154
|
self.logger.info("finalized sprint constants")
|
|
138
155
|
self.logger.info(self.k)
|
|
139
156
|
|
|
140
|
-
|
|
141
157
|
def run_minimal_spring_constant_convergence(self, lmp):
|
|
142
|
-
"""
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
""" """
|
|
159
|
+
lmp.command(
|
|
160
|
+
"fix 3 all nvt temp %f %f %f"
|
|
161
|
+
% (
|
|
162
|
+
self.calc._temperature,
|
|
163
|
+
self.calc._temperature,
|
|
164
|
+
self.calc.md.thermostat_damping[1],
|
|
165
|
+
)
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
# apply fix
|
|
147
169
|
lmp = ph.compute_msd(lmp, self.calc)
|
|
148
|
-
|
|
170
|
+
|
|
149
171
|
if ph.check_if_any_is_none(self.calc.spring_constants):
|
|
150
|
-
#similar averaging routine
|
|
151
|
-
|
|
152
|
-
|
|
172
|
+
# similar averaging routine
|
|
173
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
174
|
+
lmp.command("run %d" % int(self.calc.n_equilibration_steps))
|
|
153
175
|
|
|
154
176
|
else:
|
|
155
177
|
if not (len(self.calc.spring_constants) == self.calc.n_elements):
|
|
156
|
-
raise ValueError(
|
|
178
|
+
raise ValueError(
|
|
179
|
+
"Spring constant input length should be same as number of elements, spring constant length %d, # elements %d"
|
|
180
|
+
% (len(self.calc.spring_constants), self.calc.n_elements)
|
|
181
|
+
)
|
|
157
182
|
|
|
158
|
-
#still run a small NVT cycle
|
|
159
|
-
lmp.command("run %d"%int(self.calc.md.n_small_steps))
|
|
183
|
+
# still run a small NVT cycle
|
|
184
|
+
lmp.command("run %d" % int(self.calc.md.n_small_steps))
|
|
160
185
|
|
|
161
186
|
lmp.command("unfix 3")
|
|
162
187
|
|
|
@@ -180,7 +205,7 @@ class Solid(cph.Phase):
|
|
|
180
205
|
threshold value.
|
|
181
206
|
If `fix_lattice` option is True, then the input structure is used as it is and the corresponding pressure
|
|
182
207
|
is calculated.
|
|
183
|
-
At the end of the run, the averaged box dimensions are calculated.
|
|
208
|
+
At the end of the run, the averaged box dimensions are calculated.
|
|
184
209
|
"""
|
|
185
210
|
if self.calc.script_mode:
|
|
186
211
|
self.run_minimal_averaging()
|
|
@@ -207,65 +232,71 @@ class Solid(cph.Phase):
|
|
|
207
232
|
threshold value.
|
|
208
233
|
If `fix_lattice` option is True, then the input structure is used as it is and the corresponding pressure
|
|
209
234
|
is calculated.
|
|
210
|
-
At the end of the run, the averaged box dimensions are calculated.
|
|
235
|
+
At the end of the run, the averaged box dimensions are calculated.
|
|
211
236
|
"""
|
|
212
237
|
|
|
213
|
-
lmp = ph.create_object(
|
|
214
|
-
self.
|
|
238
|
+
lmp = ph.create_object(
|
|
239
|
+
self.cores,
|
|
240
|
+
self.simfolder,
|
|
241
|
+
self.calc.md.timestep,
|
|
242
|
+
self.calc.md.cmdargs,
|
|
215
243
|
init_commands=self.calc.md.init_commands,
|
|
216
|
-
script_mode=self.calc.script_mode
|
|
244
|
+
script_mode=self.calc.script_mode,
|
|
245
|
+
)
|
|
217
246
|
|
|
218
|
-
#set up potential
|
|
247
|
+
# set up potential
|
|
219
248
|
if self.calc.potential_file is None:
|
|
220
|
-
lmp.command(f
|
|
249
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
221
250
|
|
|
222
|
-
#set up structure
|
|
251
|
+
# set up structure
|
|
223
252
|
lmp = ph.create_structure(lmp, self.calc)
|
|
224
253
|
|
|
225
254
|
if self.calc.potential_file is None:
|
|
226
|
-
lmp.command(f
|
|
255
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
227
256
|
else:
|
|
228
|
-
lmp.command("include %s"%self.calc.potential_file)
|
|
257
|
+
lmp.command("include %s" % self.calc.potential_file)
|
|
229
258
|
lmp = ph.set_mass(lmp, self.calc)
|
|
230
259
|
|
|
231
|
-
#add some computes
|
|
260
|
+
# add some computes
|
|
232
261
|
lmp.command("variable mvol equal vol")
|
|
233
262
|
lmp.command("variable mlx equal lx")
|
|
234
263
|
lmp.command("variable mly equal ly")
|
|
235
264
|
lmp.command("variable mlz equal lz")
|
|
236
265
|
lmp.command("variable mpress equal press")
|
|
237
266
|
|
|
238
|
-
#Run if a constrained lattice is not needed
|
|
267
|
+
# Run if a constrained lattice is not needed
|
|
239
268
|
if not self.calc._fix_lattice:
|
|
240
269
|
if self.calc._pressure == 0:
|
|
241
270
|
self.run_zero_pressure_equilibration(lmp)
|
|
242
271
|
else:
|
|
243
272
|
self.run_finite_pressure_equilibration(lmp)
|
|
244
273
|
|
|
245
|
-
|
|
246
|
-
#this is when the averaging routine starts
|
|
274
|
+
# this is when the averaging routine starts
|
|
247
275
|
self.run_pressure_convergence(lmp)
|
|
248
276
|
|
|
249
|
-
#dump snapshot and check if melted
|
|
277
|
+
# dump snapshot and check if melted
|
|
250
278
|
self.dump_current_snapshot(lmp, "traj.equilibration_stage1.dat")
|
|
251
279
|
self.check_if_melted(lmp, "traj.equilibration_stage1.dat")
|
|
252
|
-
|
|
253
|
-
#run if a constrained lattice is used
|
|
280
|
+
|
|
281
|
+
# run if a constrained lattice is used
|
|
254
282
|
else:
|
|
255
|
-
#routine in which lattice constant will not varied, but is set to a given fixed value
|
|
283
|
+
# routine in which lattice constant will not varied, but is set to a given fixed value
|
|
256
284
|
self.run_constrained_pressure_convergence(lmp)
|
|
257
285
|
|
|
258
|
-
#start MSD calculation routine
|
|
259
|
-
#there two possibilities here - if spring constants are provided, use it. If not, calculate it
|
|
286
|
+
# start MSD calculation routine
|
|
287
|
+
# there two possibilities here - if spring constants are provided, use it. If not, calculate it
|
|
260
288
|
self.run_spring_constant_convergence(lmp)
|
|
261
289
|
|
|
262
|
-
#check for melting
|
|
290
|
+
# check for melting
|
|
263
291
|
self.dump_current_snapshot(lmp, "traj.equilibration_stage2.dat")
|
|
264
292
|
self.check_if_melted(lmp, "traj.equilibration_stage2.dat")
|
|
265
293
|
lmp = ph.write_data(lmp, "conf.equilibration.data")
|
|
266
|
-
#close object and process traj
|
|
294
|
+
# close object and process traj
|
|
267
295
|
lmp.close()
|
|
268
|
-
|
|
296
|
+
# Preserve log file
|
|
297
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
298
|
+
if os.path.exists(logfile):
|
|
299
|
+
os.rename(logfile, os.path.join(self.simfolder, "averaging.log.lammps"))
|
|
269
300
|
|
|
270
301
|
def run_minimal_averaging(self):
|
|
271
302
|
"""
|
|
@@ -287,64 +318,66 @@ class Solid(cph.Phase):
|
|
|
287
318
|
threshold value.
|
|
288
319
|
If `fix_lattice` option is True, then the input structure is used as it is and the corresponding pressure
|
|
289
320
|
is calculated.
|
|
290
|
-
At the end of the run, the averaged box dimensions are calculated.
|
|
321
|
+
At the end of the run, the averaged box dimensions are calculated.
|
|
291
322
|
"""
|
|
292
|
-
lmp = ph.create_object(
|
|
293
|
-
self.
|
|
323
|
+
lmp = ph.create_object(
|
|
324
|
+
self.cores,
|
|
325
|
+
self.simfolder,
|
|
326
|
+
self.calc.md.timestep,
|
|
327
|
+
self.calc.md.cmdargs,
|
|
294
328
|
init_commands=self.calc.md.init_commands,
|
|
295
|
-
script_mode=self.calc.script_mode
|
|
329
|
+
script_mode=self.calc.script_mode,
|
|
330
|
+
)
|
|
296
331
|
|
|
297
|
-
#set up potential
|
|
332
|
+
# set up potential
|
|
298
333
|
if self.calc.potential_file is None:
|
|
299
|
-
lmp.command(f
|
|
334
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
300
335
|
|
|
301
|
-
#set up structure
|
|
336
|
+
# set up structure
|
|
302
337
|
lmp = ph.create_structure(lmp, self.calc)
|
|
303
338
|
|
|
304
339
|
if self.calc.potential_file is None:
|
|
305
|
-
lmp.command(f
|
|
340
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
306
341
|
else:
|
|
307
|
-
lmp.command("include %s"%self.calc.potential_file)
|
|
342
|
+
lmp.command("include %s" % self.calc.potential_file)
|
|
308
343
|
lmp = ph.set_mass(lmp, self.calc)
|
|
309
344
|
|
|
310
|
-
|
|
311
|
-
#add some computes
|
|
345
|
+
# add some computes
|
|
312
346
|
lmp.command("variable mvol equal vol")
|
|
313
347
|
lmp.command("variable mlx equal lx")
|
|
314
348
|
lmp.command("variable mly equal ly")
|
|
315
349
|
lmp.command("variable mlz equal lz")
|
|
316
350
|
lmp.command("variable mpress equal press")
|
|
317
351
|
|
|
318
|
-
#Run if a constrained lattice is not needed
|
|
352
|
+
# Run if a constrained lattice is not needed
|
|
319
353
|
if not self.calc._fix_lattice:
|
|
320
354
|
if self.calc._pressure == 0:
|
|
321
355
|
self.run_zero_pressure_equilibration(lmp)
|
|
322
356
|
else:
|
|
323
357
|
self.run_finite_pressure_equilibration(lmp)
|
|
324
358
|
|
|
325
|
-
|
|
326
|
-
#this is when the averaging routine starts
|
|
359
|
+
# this is when the averaging routine starts
|
|
327
360
|
self.run_pressure_convergence(lmp)
|
|
328
361
|
|
|
329
|
-
#dump snapshot and check if melted
|
|
362
|
+
# dump snapshot and check if melted
|
|
330
363
|
self.dump_current_snapshot(lmp, "traj.equilibration_stage1.dat")
|
|
331
|
-
|
|
332
|
-
#run if a constrained lattice is used
|
|
364
|
+
|
|
365
|
+
# run if a constrained lattice is used
|
|
333
366
|
else:
|
|
334
|
-
#routine in which lattice constant will not varied, but is set to a given fixed value
|
|
367
|
+
# routine in which lattice constant will not varied, but is set to a given fixed value
|
|
335
368
|
self.run_constrained_pressure_convergence(lmp)
|
|
336
369
|
|
|
337
|
-
#start MSD calculation routine
|
|
338
|
-
#there two possibilities here - if spring constants are provided, use it. If not, calculate it
|
|
370
|
+
# start MSD calculation routine
|
|
371
|
+
# there two possibilities here - if spring constants are provided, use it. If not, calculate it
|
|
339
372
|
self.run_spring_constant_convergence(lmp)
|
|
340
373
|
|
|
341
|
-
#check for melting
|
|
374
|
+
# check for melting
|
|
342
375
|
self.dump_current_snapshot(lmp, "traj.equilibration_stage2.dat")
|
|
343
376
|
lmp = ph.write_data(lmp, "conf.equilibration.data")
|
|
344
|
-
#close object and process traj
|
|
377
|
+
# close object and process traj
|
|
345
378
|
|
|
346
|
-
#now serialise script
|
|
347
|
-
file = os.path.join(self.simfolder,
|
|
379
|
+
# now serialise script
|
|
380
|
+
file = os.path.join(self.simfolder, "averaging.lmp")
|
|
348
381
|
lmp.write(file)
|
|
349
382
|
|
|
350
383
|
def process_averaging_results(self):
|
|
@@ -370,96 +403,123 @@ class Solid(cph.Phase):
|
|
|
370
403
|
Run the integration routine where the initial and final systems are connected using
|
|
371
404
|
the lambda parameter. See algorithm 4 in publication.
|
|
372
405
|
"""
|
|
373
|
-
lmp = ph.create_object(
|
|
374
|
-
self.
|
|
406
|
+
lmp = ph.create_object(
|
|
407
|
+
self.cores,
|
|
408
|
+
self.simfolder,
|
|
409
|
+
self.calc.md.timestep,
|
|
410
|
+
self.calc.md.cmdargs,
|
|
375
411
|
init_commands=self.calc.md.init_commands,
|
|
376
|
-
script_mode=self.calc.script_mode
|
|
412
|
+
script_mode=self.calc.script_mode,
|
|
413
|
+
)
|
|
377
414
|
|
|
378
|
-
#set up potential
|
|
415
|
+
# set up potential
|
|
379
416
|
if self.calc.potential_file is None:
|
|
380
|
-
lmp.command(f
|
|
381
|
-
|
|
382
|
-
#read in the conf file
|
|
383
|
-
#conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
417
|
+
lmp.command(f"pair_style {self.calc._pair_style_with_options[0]}")
|
|
418
|
+
|
|
419
|
+
# read in the conf file
|
|
420
|
+
# conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
384
421
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
385
422
|
lmp = ph.read_data(lmp, conf)
|
|
386
423
|
|
|
387
424
|
if self.calc.potential_file is None:
|
|
388
|
-
lmp.command(f
|
|
425
|
+
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
389
426
|
else:
|
|
390
|
-
lmp.command("include %s"%self.calc.potential_file)
|
|
427
|
+
lmp.command("include %s" % self.calc.potential_file)
|
|
391
428
|
lmp = ph.set_mass(lmp, self.calc)
|
|
392
429
|
|
|
393
|
-
#remap the box to get the correct pressure
|
|
430
|
+
# remap the box to get the correct pressure
|
|
394
431
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
395
432
|
|
|
396
|
-
#create groups - each species belong to one group
|
|
433
|
+
# create groups - each species belong to one group
|
|
397
434
|
for i in range(self.calc.n_elements):
|
|
398
|
-
lmp.command("group g%d type %d"%(i+1, i+1))
|
|
435
|
+
lmp.command("group g%d type %d" % (i + 1, i + 1))
|
|
399
436
|
|
|
400
|
-
#get counts of each group
|
|
437
|
+
# get counts of each group
|
|
401
438
|
for i in range(self.calc.n_elements):
|
|
402
|
-
lmp.command("variable count%d equal count(g%d)"%(i+1, i+1))
|
|
439
|
+
lmp.command("variable count%d equal count(g%d)" % (i + 1, i + 1))
|
|
403
440
|
|
|
404
|
-
#initialise everything
|
|
441
|
+
# initialise everything
|
|
405
442
|
lmp.command("run 0")
|
|
406
443
|
|
|
407
|
-
#apply initial fixes
|
|
444
|
+
# apply initial fixes
|
|
408
445
|
lmp.command("fix f1 all nve")
|
|
409
|
-
|
|
410
|
-
#apply fix for each spring
|
|
411
|
-
#TODO: Add option to select function
|
|
412
|
-
for i in range(self.calc.n_elements):
|
|
413
|
-
lmp.command("fix ff%d g%d ti/spring 10.0 100 100 function 2"%(i+1, i+1))
|
|
414
|
-
|
|
415
|
-
#apply temp fix
|
|
416
|
-
lmp.command("fix f3 all langevin %f %f %f %d zero yes"%(self.calc._temperature, self.calc._temperature, self.calc.md.thermostat_damping[1],
|
|
417
|
-
np.random.randint(1, 10000)))
|
|
418
446
|
|
|
419
|
-
#
|
|
447
|
+
# apply fix for each spring
|
|
448
|
+
# TODO: Add option to select function
|
|
449
|
+
for i in range(self.calc.n_elements):
|
|
450
|
+
lmp.command(
|
|
451
|
+
"fix ff%d g%d ti/spring 10.0 100 100 function 2"
|
|
452
|
+
% (i + 1, i + 1)
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
# apply temp fix
|
|
456
|
+
lmp.command(
|
|
457
|
+
"fix f3 all langevin %f %f %f %d zero yes"
|
|
458
|
+
% (
|
|
459
|
+
self.calc._temperature,
|
|
460
|
+
self.calc._temperature,
|
|
461
|
+
self.calc.md.thermostat_damping[1],
|
|
462
|
+
np.random.randint(1, 10000),
|
|
463
|
+
)
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
# compute com and apply to fix
|
|
420
467
|
lmp.command("compute Tcm all temp/com")
|
|
421
468
|
lmp.command("fix_modify f3 temp Tcm")
|
|
422
469
|
|
|
423
470
|
lmp.command("variable step equal step")
|
|
424
471
|
lmp.command("variable dU1 equal pe/atoms")
|
|
425
472
|
for i in range(self.calc.n_elements):
|
|
426
|
-
lmp.command("variable dU%d equal f_ff%d"%(i+2, i+1))
|
|
427
|
-
|
|
473
|
+
lmp.command("variable dU%d equal f_ff%d" % (i + 2, i + 1))
|
|
474
|
+
|
|
428
475
|
lmp.command("variable lambda equal f_ff1[1]")
|
|
429
476
|
|
|
430
|
-
#add thermo command to force variable evaluation
|
|
477
|
+
# add thermo command to force variable evaluation
|
|
431
478
|
lmp.command("thermo_style custom step pe c_Tcm")
|
|
432
479
|
lmp.command("thermo 10000")
|
|
433
480
|
|
|
434
|
-
#Create velocity
|
|
435
|
-
lmp.command(
|
|
481
|
+
# Create velocity
|
|
482
|
+
lmp.command(
|
|
483
|
+
"velocity all create %f %d mom yes rot yes dist gaussian"
|
|
484
|
+
% (self.calc._temperature, np.random.randint(1, 10000))
|
|
485
|
+
)
|
|
436
486
|
|
|
437
|
-
#reapply
|
|
487
|
+
# reapply
|
|
438
488
|
for i in range(self.calc.n_elements):
|
|
439
|
-
lmp.command(
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
489
|
+
lmp.command(
|
|
490
|
+
"fix ff%d g%d ti/spring %f %d %d function 2"
|
|
491
|
+
% (
|
|
492
|
+
i + 1,
|
|
493
|
+
i + 1,
|
|
494
|
+
self.k[i],
|
|
495
|
+
self.calc._n_switching_steps,
|
|
496
|
+
self.calc.n_equilibration_steps,
|
|
497
|
+
)
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
# Equilibriate structure
|
|
501
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
502
|
+
|
|
503
|
+
# write out energy
|
|
504
|
+
str1 = 'fix f4 all print 1 "${dU1} '
|
|
447
505
|
str2 = []
|
|
448
506
|
for i in range(self.calc.n_elements):
|
|
449
|
-
str2.append("${dU%d}"%(i+2))
|
|
507
|
+
str2.append("${dU%d}" % (i + 2))
|
|
450
508
|
|
|
451
|
-
str2.append(
|
|
509
|
+
str2.append('${lambda}"')
|
|
452
510
|
str2 = " ".join(str2)
|
|
453
|
-
str3 = " screen no file forward_%d.dat"%iteration
|
|
511
|
+
str3 = " screen no file forward_%d.dat" % iteration
|
|
454
512
|
command = str1 + str2 + str3
|
|
455
513
|
lmp.command(command)
|
|
456
514
|
|
|
457
515
|
if self.calc.n_print_steps > 0:
|
|
458
|
-
lmp.command(
|
|
459
|
-
|
|
516
|
+
lmp.command(
|
|
517
|
+
"dump d1 all custom %d traj.fe.forward_%d.dat id type mass x y z fx fy fz"
|
|
518
|
+
% (self.calc.n_print_steps, iteration)
|
|
519
|
+
)
|
|
460
520
|
|
|
461
|
-
#turn on swap moves
|
|
462
|
-
#if self.calc.monte_carlo.n_swaps > 0:
|
|
521
|
+
# turn on swap moves
|
|
522
|
+
# if self.calc.monte_carlo.n_swaps > 0:
|
|
463
523
|
# self.logger.info(f'{self.calc.monte_carlo.n_swaps} swap moves are performed between 1 and 2 every {self.calc.monte_carlo.n_steps}')
|
|
464
524
|
# lmp.command("fix swap all atom/swap %d %d %d %d ke yes types 1 2"%(self.calc.monte_carlo.n_steps,
|
|
465
525
|
# self.calc.monte_carlo.n_swaps,
|
|
@@ -470,39 +530,40 @@ class Solid(cph.Phase):
|
|
|
470
530
|
# lmp.command("variable b equal f_swap[2]")
|
|
471
531
|
# lmp.command("fix swap2 all print 1 \"${a} ${b}\" screen no file swap.fe.forward_%d.dat"%iteration)
|
|
472
532
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
lmp.command("run %d"%self.calc._n_switching_steps)
|
|
533
|
+
# Forward switching over ts steps
|
|
534
|
+
lmp.command("run %d" % self.calc._n_switching_steps)
|
|
476
535
|
lmp.command("unfix f4")
|
|
477
536
|
|
|
478
537
|
if self.calc.n_print_steps > 0:
|
|
479
538
|
lmp.command("undump d1")
|
|
480
539
|
|
|
481
|
-
#if self.calc.monte_carlo.n_swaps > 0:
|
|
540
|
+
# if self.calc.monte_carlo.n_swaps > 0:
|
|
482
541
|
# lmp.command("unfix swap")
|
|
483
542
|
# lmp.command("unfix swap2")
|
|
484
543
|
|
|
485
|
-
#Equilibriate
|
|
486
|
-
lmp.command("run %d"%self.calc.n_equilibration_steps)
|
|
544
|
+
# Equilibriate
|
|
545
|
+
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
487
546
|
|
|
488
|
-
#write out energy
|
|
489
|
-
str1 =
|
|
547
|
+
# write out energy
|
|
548
|
+
str1 = 'fix f4 all print 1 "${dU1} '
|
|
490
549
|
str2 = []
|
|
491
550
|
for i in range(self.calc.n_elements):
|
|
492
|
-
str2.append("${dU%d}"%(i+2))
|
|
551
|
+
str2.append("${dU%d}" % (i + 2))
|
|
493
552
|
|
|
494
|
-
str2.append(
|
|
553
|
+
str2.append('${lambda}"')
|
|
495
554
|
str2 = " ".join(str2)
|
|
496
|
-
str3 = " screen no file backward_%d.dat"%iteration
|
|
555
|
+
str3 = " screen no file backward_%d.dat" % iteration
|
|
497
556
|
command = str1 + str2 + str3
|
|
498
557
|
lmp.command(command)
|
|
499
558
|
|
|
500
559
|
if self.calc.n_print_steps > 0:
|
|
501
|
-
lmp.command(
|
|
502
|
-
|
|
560
|
+
lmp.command(
|
|
561
|
+
"dump d1 all custom %d traj.fe.backward_%d.dat id type mass x y z fx fy fz"
|
|
562
|
+
% (self.calc.n_print_steps, iteration)
|
|
563
|
+
)
|
|
503
564
|
|
|
504
|
-
#add swaps if n_swap is > 0
|
|
505
|
-
#if self.calc.monte_carlo.n_swaps > 0:
|
|
565
|
+
# add swaps if n_swap is > 0
|
|
566
|
+
# if self.calc.monte_carlo.n_swaps > 0:
|
|
506
567
|
# self.logger.info(f'{self.calc.monte_carlo.n_swaps} swap moves are performed between 1 and 2 every {self.calc.monte_carlo.n_steps}')
|
|
507
568
|
# lmp.command("fix swap all atom/swap %d %d %d %d ke yes types 2 1"%(self.calc.monte_carlo.n_steps,
|
|
508
569
|
# self.calc.monte_carlo.n_swaps,
|
|
@@ -513,27 +574,30 @@ class Solid(cph.Phase):
|
|
|
513
574
|
# lmp.command("variable b equal f_swap[2]")
|
|
514
575
|
# lmp.command("fix swap2 all print 1 \"${a} ${b}\" screen no file swap.fe.backward_%d.dat"%iteration)
|
|
515
576
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
#Reverse switching over ts steps
|
|
519
|
-
lmp.command("run %d"%self.calc._n_switching_steps)
|
|
577
|
+
# Reverse switching over ts steps
|
|
578
|
+
lmp.command("run %d" % self.calc._n_switching_steps)
|
|
520
579
|
lmp.command("unfix f4")
|
|
521
580
|
|
|
522
581
|
if self.calc.n_print_steps > 0:
|
|
523
582
|
lmp.command("undump d1")
|
|
524
583
|
|
|
525
|
-
#if self.calc.monte_carlo.n_swaps > 0:
|
|
584
|
+
# if self.calc.monte_carlo.n_swaps > 0:
|
|
526
585
|
# lmp.command("unfix swap")
|
|
527
586
|
# lmp.command("unfix swap2")
|
|
528
587
|
|
|
529
|
-
#close object
|
|
588
|
+
# close object
|
|
530
589
|
if not self.calc.script_mode:
|
|
531
590
|
lmp.close()
|
|
591
|
+
# Preserve log file
|
|
592
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
593
|
+
if os.path.exists(logfile):
|
|
594
|
+
os.rename(
|
|
595
|
+
logfile, os.path.join(self.simfolder, "integration.log.lammps")
|
|
596
|
+
)
|
|
532
597
|
else:
|
|
533
|
-
file = os.path.join(self.simfolder,
|
|
598
|
+
file = os.path.join(self.simfolder, "integration.lmp")
|
|
534
599
|
lmp.write(file)
|
|
535
600
|
|
|
536
|
-
|
|
537
601
|
def thermodynamic_integration(self):
|
|
538
602
|
"""
|
|
539
603
|
Calculate free energy after integration step
|
|
@@ -552,31 +616,24 @@ class Solid(cph.Phase):
|
|
|
552
616
|
matching with Einstein crystal
|
|
553
617
|
"""
|
|
554
618
|
fe, fcm = get_einstein_crystal_fe(
|
|
555
|
-
self.calc,
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
w, q, qerr = find_w(self.simfolder,
|
|
561
|
-
self.calc,
|
|
562
|
-
full=True,
|
|
563
|
-
solid=True)
|
|
564
|
-
|
|
619
|
+
self.calc, self.vol, self.k, return_contributions=True
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
w, q, qerr = find_w(self.simfolder, self.calc, full=True, solid=True)
|
|
623
|
+
|
|
565
624
|
self.fref = fe + fcm
|
|
566
625
|
self.feinstein = fe
|
|
567
626
|
self.fcm = fcm
|
|
568
627
|
self.w = w
|
|
569
628
|
self.ferr = qerr
|
|
570
629
|
|
|
571
|
-
#add pressure contribution if required
|
|
630
|
+
# add pressure contribution if required
|
|
572
631
|
if self.calc._pressure != 0:
|
|
573
|
-
p = self.calc._pressure/(10000*160.21766208)
|
|
574
|
-
v = self.vol/self.natoms
|
|
575
|
-
self.pv = p*v
|
|
632
|
+
p = self.calc._pressure / (10000 * 160.21766208)
|
|
633
|
+
v = self.vol / self.natoms
|
|
634
|
+
self.pv = p * v
|
|
576
635
|
else:
|
|
577
|
-
self.pv = 0
|
|
636
|
+
self.pv = 0
|
|
578
637
|
|
|
579
|
-
#calculate final free energy
|
|
638
|
+
# calculate final free energy
|
|
580
639
|
self.fe = self.fref + self.w + self.pv
|
|
581
|
-
|
|
582
|
-
|