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/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__(calculation=calculation,
55
- simfolder=simfolder,
56
- log_to_screen=log_to_screen)
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
- lmp.command("fix 3 all nvt temp %f %f %f"%(self.calc._temperature, self.calc._temperature, self.calc.md.thermostat_damping[1]))
68
-
69
- #apply fix
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("At count %d mean k is %f std is %f"%(i+1, k_mean[0], k_std[0]))
79
- if (np.abs(laststd - k_std[0]) < self.calc.tolerance.spring_constant):
80
- #now reevaluate spring constants
81
- self.assign_spring_constants(k_mean)
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("Spring constant input length should be same as number of elements, spring constant length %d, # elements %d"%(len(self.calc.spring_constants), self.calc.n_elements))
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(self.calc.md.n_every_steps*self.calc.md.n_repeat_steps)
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(self.calc.md.n_every_steps*self.calc.md.n_repeat_steps)
105
-
106
- #now we can check if it converted
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, ), unpack=True)[-ncount+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
- lmp.command("fix 3 all nvt temp %f %f %f"%(self.calc._temperature, self.calc._temperature, self.calc.md.thermostat_damping[1]))
145
-
146
- #apply fix
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
- lmp.command("run %d"%int(self.calc.md.n_small_steps))
152
- lmp.command("run %d"%int(self.calc.n_equilibration_steps))
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("Spring constant input length should be same as number of elements, spring constant length %d, # elements %d"%(len(self.calc.spring_constants), self.calc.n_elements))
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(self.cores, self.simfolder, self.calc.md.timestep,
214
- self.calc.md.cmdargs,
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'pair_style {self.calc._pair_style_with_options[0]}')
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'pair_coeff {self.calc.pair_coeff[0]}')
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(self.cores, self.simfolder, self.calc.md.timestep,
293
- self.calc.md.cmdargs,
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'pair_style {self.calc._pair_style_with_options[0]}')
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'pair_coeff {self.calc.pair_coeff[0]}')
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, 'averaging.lmp')
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(self.cores, self.simfolder, self.calc.md.timestep,
374
- self.calc.md.cmdargs,
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'pair_style {self.calc._pair_style_with_options[0]}')
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'pair_coeff {self.calc.pair_coeff[0]}')
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
- #compute com and apply to fix
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("velocity all create %f %d mom yes rot yes dist gaussian"%(self.calc._temperature, np.random.randint(1, 10000)))
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("fix ff%d g%d ti/spring %f %d %d function 2"%(i+1, i+1, self.k[i],
440
- self.calc._n_switching_steps, self.calc.n_equilibration_steps))
441
-
442
- #Equilibriate structure
443
- lmp.command("run %d"%self.calc.n_equilibration_steps)
444
-
445
- #write out energy
446
- str1 = "fix f4 all print 1 \"${dU1} "
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("${lambda}\"")
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("dump d1 all custom %d traj.fe.forward_%d.dat id type mass x y z fx fy fz"%(self.calc.n_print_steps,
459
- iteration))
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
- #Forward switching over ts steps
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 = "fix f4 all print 1 \"${dU1} "
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("${lambda}\"")
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("dump d1 all custom %d traj.fe.backward_%d.dat id type mass x y z fx fy fz"%(self.calc.n_print_steps,
502
- iteration))
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, 'integration.lmp')
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
- self.vol,
557
- self.k,
558
- return_contributions=True)
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
-