calphy 2.1.0__tar.gz → 2.1.2__tar.gz
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-2.1.0 → calphy-2.1.2}/PKG-INFO +1 -1
- {calphy-2.1.0 → calphy-2.1.2}/calphy/__init__.py +1 -1
- {calphy-2.1.0 → calphy-2.1.2}/calphy/alchemy.py +163 -245
- {calphy-2.1.0 → calphy-2.1.2}/calphy/helpers.py +75 -46
- {calphy-2.1.0 → calphy-2.1.2}/calphy/input.py +29 -7
- {calphy-2.1.0 → calphy-2.1.2}/calphy/liquid.py +17 -4
- {calphy-2.1.0 → calphy-2.1.2}/calphy/phase.py +114 -33
- {calphy-2.1.0 → calphy-2.1.2}/calphy/routines.py +52 -13
- {calphy-2.1.0 → calphy-2.1.2}/calphy/runner.py +7 -4
- {calphy-2.1.0 → calphy-2.1.2}/calphy/solid.py +34 -7
- {calphy-2.1.0 → calphy-2.1.2}/calphy.egg-info/PKG-INFO +1 -1
- {calphy-2.1.0 → calphy-2.1.2}/calphy.egg-info/SOURCES.txt +1 -0
- {calphy-2.1.0 → calphy-2.1.2}/pyproject.toml +1 -1
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_command_vocabulary.py +2 -2
- calphy-2.1.2/tests/test_composition_scaling_potential.py +76 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_golden_streams.py +103 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_helpers.py +54 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_input_validation.py +55 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_runner.py +35 -0
- {calphy-2.1.0 → calphy-2.1.2}/LICENSE +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/README.md +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/clitools.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/composition_transformation.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/errors.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/integrators.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/kernel.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/library_runner.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/phase_diagram.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/postprocessing.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/queuekernel.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/range_scan.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/scheduler.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/splines.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy/utils.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy.egg-info/dependency_links.txt +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy.egg-info/entry_points.txt +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy.egg-info/requires.txt +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/calphy.egg-info/top_level.txt +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/setup.cfg +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_composition_transformation_bug.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_dissipation_check.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_element_ordering.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_ex07.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_find_tm_crossing_error.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_fix_paths_user_expansion.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_gather_results_sweep_data.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_integration_lammps.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_integrators.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_library_runner.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_meam_pair_coeff.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_melting_temperature_n_iterations.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_options.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_phase_detection_defaults.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_phase_diagram.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_phase_diagram_validation.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_postprocessing.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_preflight.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_pressure_convergence_pv_fit.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_pressure_coupling.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_qtb_input.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_scheduler.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_seed.py +0 -0
- {calphy-2.1.0 → calphy-2.1.2}/tests/test_solid_methods.py +0 -0
|
@@ -58,6 +58,91 @@ class Alchemy(cph.Phase):
|
|
|
58
58
|
calculation=calculation, simfolder=simfolder, log_to_screen=log_to_screen,
|
|
59
59
|
)
|
|
60
60
|
|
|
61
|
+
def _end_states(self):
|
|
62
|
+
"""
|
|
63
|
+
The initial and final potential of the alchemical switch.
|
|
64
|
+
|
|
65
|
+
The pair lists hold both end states back to back: the first half
|
|
66
|
+
describes the initial potential, the second half the final one. Each
|
|
67
|
+
half is one physical potential made of one component (a plain pair
|
|
68
|
+
style) or several (``pair_mode: overlay``, or the component-wise
|
|
69
|
+
rewrite done by composition scaling). A component is the tuple
|
|
70
|
+
(style with options, style name, pair_coeff).
|
|
71
|
+
"""
|
|
72
|
+
styles = self.calc._pair_style_with_options
|
|
73
|
+
names = self.calc._pair_style_names
|
|
74
|
+
coeffs = self.calc.pair_coeff
|
|
75
|
+
if len(styles) % 2 or len(styles) != len(coeffs):
|
|
76
|
+
raise ValueError(
|
|
77
|
+
"alchemical switching needs pair_style and pair_coeff lists of "
|
|
78
|
+
"equal, even length (initial components followed by final "
|
|
79
|
+
"components); got %d pair styles and %d pair coeffs"
|
|
80
|
+
% (len(styles), len(coeffs))
|
|
81
|
+
)
|
|
82
|
+
half = len(styles) // 2
|
|
83
|
+
components = list(zip(styles, names, coeffs))
|
|
84
|
+
return components[:half], components[half:]
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def _pure_pair_style_command(components):
|
|
88
|
+
"""``pair_style`` for one potential on its own: the plain style for a
|
|
89
|
+
single component, ``hybrid/overlay`` of the components otherwise."""
|
|
90
|
+
if len(components) == 1:
|
|
91
|
+
return "pair_style %s" % components[0][0]
|
|
92
|
+
return "pair_style hybrid/overlay %s" % " ".join(
|
|
93
|
+
style for style, _, _ in components
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _pure_pair_coeff_commands(components):
|
|
98
|
+
"""``pair_coeff`` lines matching :meth:`_pure_pair_style_command`."""
|
|
99
|
+
if len(components) == 1:
|
|
100
|
+
return ["pair_coeff %s" % components[0][2]]
|
|
101
|
+
return ph.hybrid_pair_coeff_commands_for(
|
|
102
|
+
[name for _, name, _ in components], [coeff for _, _, coeff in components]
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _scaled_pair_commands(self, initial, final, initial_scale, final_scale):
|
|
106
|
+
"""
|
|
107
|
+
Install ``hybrid/scaled`` with every initial component scaled by
|
|
108
|
+
``initial_scale`` and every final component by ``final_scale``,
|
|
109
|
+
then define computes ``c1``/``c2`` (or ``c1_1, c1_2, ...`` for
|
|
110
|
+
multi-component ends) holding the two potential energies and the
|
|
111
|
+
per-atom variables ``dU1``/``dU2`` recorded during switching.
|
|
112
|
+
|
|
113
|
+
Returns the commands and the compute ids to release afterwards.
|
|
114
|
+
"""
|
|
115
|
+
terms = ["%s %s" % (initial_scale, style) for style, _, _ in initial]
|
|
116
|
+
terms += ["%s %s" % (final_scale, style) for style, _, _ in final]
|
|
117
|
+
commands = ["pair_style hybrid/scaled %s" % " ".join(terms)]
|
|
118
|
+
|
|
119
|
+
components = initial + final
|
|
120
|
+
names = [name for _, name, _ in components]
|
|
121
|
+
commands += ph.hybrid_pair_coeff_commands_for(
|
|
122
|
+
names, [coeff for _, _, coeff in components]
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
tags = ph.hybrid_component_tags(names)
|
|
126
|
+
compute_ids, energies = [], []
|
|
127
|
+
for label, part, part_tags in (
|
|
128
|
+
("c1", initial, tags[: len(initial)]),
|
|
129
|
+
("c2", final, tags[len(initial) :]),
|
|
130
|
+
):
|
|
131
|
+
ids = (
|
|
132
|
+
[label]
|
|
133
|
+
if len(part) == 1
|
|
134
|
+
else ["%s_%d" % (label, i) for i in range(1, len(part) + 1)]
|
|
135
|
+
)
|
|
136
|
+
compute_commands, energy = ph.hybrid_pair_compute_commands(ids, part_tags)
|
|
137
|
+
commands += compute_commands
|
|
138
|
+
compute_ids += ids
|
|
139
|
+
energies.append(energy if len(ids) == 1 else "(%s)" % energy)
|
|
140
|
+
|
|
141
|
+
commands.append("variable step equal step")
|
|
142
|
+
commands.append("variable dU1 equal %s/atoms" % energies[0])
|
|
143
|
+
commands.append("variable dU2 equal %s/atoms" % energies[1])
|
|
144
|
+
return commands, compute_ids
|
|
145
|
+
|
|
61
146
|
def _coupling_pair(self, lmp, ramp="0.0", tag=None):
|
|
62
147
|
"""Coupling mode: base components (all but last) at constant scale
|
|
63
148
|
1.0, the LAST component scaled by `ramp` (a constant or v_name).
|
|
@@ -180,13 +265,16 @@ class Alchemy(cph.Phase):
|
|
|
180
265
|
lmp = ph.create_structure(lmp, self.calc)
|
|
181
266
|
self._coupling_pair(lmp, ramp="0.0")
|
|
182
267
|
else:
|
|
183
|
-
|
|
268
|
+
# equilibrate with the initial potential on its own
|
|
269
|
+
initial, _ = self._end_states()
|
|
270
|
+
lmp.command(self._pure_pair_style_command(initial))
|
|
184
271
|
|
|
185
272
|
# set up structure
|
|
186
273
|
lmp = ph.create_structure(lmp, self.calc)
|
|
187
274
|
|
|
188
275
|
# set up potential
|
|
189
|
-
|
|
276
|
+
for command in self._pure_pair_coeff_commands(initial):
|
|
277
|
+
lmp.command(command)
|
|
190
278
|
lmp = ph.set_mass(lmp, self.calc)
|
|
191
279
|
|
|
192
280
|
# add some computes
|
|
@@ -254,6 +342,8 @@ class Alchemy(cph.Phase):
|
|
|
254
342
|
if self.calc.alchemy_coupling:
|
|
255
343
|
return self._run_integration_coupling(iteration=iteration)
|
|
256
344
|
|
|
345
|
+
initial, final = self._end_states()
|
|
346
|
+
|
|
257
347
|
# create lammps object
|
|
258
348
|
lmp = ph.create_object(self.calc, self.simfolder)
|
|
259
349
|
|
|
@@ -261,22 +351,16 @@ class Alchemy(cph.Phase):
|
|
|
261
351
|
lmp.command("variable li equal 1.0")
|
|
262
352
|
lmp.command("variable lf equal 0.0")
|
|
263
353
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
# read dump file
|
|
267
|
-
# conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
354
|
+
# the equilibrated configuration is read in with the initial potential
|
|
355
|
+
lmp.command(self._pure_pair_style_command(initial))
|
|
268
356
|
conf = os.path.join(self.simfolder, "conf.equilibration.data")
|
|
269
357
|
lmp = ph.read_data(lmp, conf)
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
# here we only need to set one potential
|
|
273
|
-
lmp.command(f"pair_coeff {self.calc.pair_coeff[0]}")
|
|
358
|
+
for command in self._pure_pair_coeff_commands(initial):
|
|
359
|
+
lmp.command(command)
|
|
274
360
|
lmp = ph.set_mass(lmp, self.calc)
|
|
275
361
|
|
|
276
|
-
# NEW ADDED
|
|
277
362
|
lmp.command("group g1 type 1")
|
|
278
363
|
lmp.command("group g2 type 2")
|
|
279
|
-
# lmp = ph.set_double_hybrid_potential(lmp, self.options, self.calc._pressureair_style, self.calc._pressureair_coeff)
|
|
280
364
|
|
|
281
365
|
# remap the box to get the correct pressure
|
|
282
366
|
lmp = ph.remap_box(lmp, self.lx, self.ly, self.lz)
|
|
@@ -316,143 +400,20 @@ class Alchemy(cph.Phase):
|
|
|
316
400
|
# equilibration run is over
|
|
317
401
|
|
|
318
402
|
# ---------------------------------------------------------------
|
|
319
|
-
# FWD cycle
|
|
403
|
+
# FWD cycle: initial potential scaled 1 -> 0, final potential 0 -> 1
|
|
320
404
|
# ---------------------------------------------------------------
|
|
321
405
|
lmp.command("variable flambda equal ramp(${li},${lf})")
|
|
322
406
|
lmp.command("variable blambda equal ramp(${lf},${li})")
|
|
323
407
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
# Compute pair definitions
|
|
327
|
-
if self.calc.pair_style[0] == self.calc.pair_style[1]:
|
|
328
|
-
pc = self.calc.pair_coeff[0]
|
|
329
|
-
pcraw = pc.split()
|
|
330
|
-
pc1 = " ".join(
|
|
331
|
-
[
|
|
332
|
-
*pcraw[:2],
|
|
333
|
-
*[
|
|
334
|
-
self.calc._pair_style_names[0],
|
|
335
|
-
],
|
|
336
|
-
"1",
|
|
337
|
-
*pcraw[2:],
|
|
338
|
-
]
|
|
339
|
-
)
|
|
340
|
-
pc = self.calc.pair_coeff[1]
|
|
341
|
-
pcraw = pc.split()
|
|
342
|
-
pc2 = " ".join(
|
|
343
|
-
[
|
|
344
|
-
*pcraw[:2],
|
|
345
|
-
*[
|
|
346
|
-
self.calc._pair_style_names[1],
|
|
347
|
-
],
|
|
348
|
-
"2",
|
|
349
|
-
*pcraw[2:],
|
|
350
|
-
]
|
|
351
|
-
)
|
|
352
|
-
else:
|
|
353
|
-
pc = self.calc.pair_coeff[0]
|
|
354
|
-
pcraw = pc.split()
|
|
355
|
-
pc1 = " ".join(
|
|
356
|
-
[
|
|
357
|
-
*pcraw[:2],
|
|
358
|
-
*[
|
|
359
|
-
self.calc._pair_style_names[0],
|
|
360
|
-
],
|
|
361
|
-
*pcraw[2:],
|
|
362
|
-
]
|
|
363
|
-
)
|
|
364
|
-
pc = self.calc.pair_coeff[1]
|
|
365
|
-
pcraw = pc.split()
|
|
366
|
-
pc2 = " ".join(
|
|
367
|
-
[
|
|
368
|
-
*pcraw[:2],
|
|
369
|
-
*[
|
|
370
|
-
self.calc._pair_style_names[1],
|
|
371
|
-
],
|
|
372
|
-
*pcraw[2:],
|
|
373
|
-
]
|
|
374
|
-
)
|
|
375
|
-
|
|
376
|
-
lmp.command(
|
|
377
|
-
"pair_style hybrid/scaled v_flambda %s v_blambda %s"
|
|
378
|
-
% (
|
|
379
|
-
self.calc._pair_style_with_options[0],
|
|
380
|
-
self.calc._pair_style_with_options[1],
|
|
381
|
-
)
|
|
408
|
+
commands, compute_ids = self._scaled_pair_commands(
|
|
409
|
+
initial, final, "v_flambda", "v_blambda"
|
|
382
410
|
)
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
# apply pair force commands
|
|
387
|
-
if self.calc._pair_style_names[0] == self.calc._pair_style_names[1]:
|
|
388
|
-
lmp.command(
|
|
389
|
-
"compute c1 all pair %s 1" % self.calc._pair_style_names[0]
|
|
390
|
-
)
|
|
391
|
-
lmp.command(
|
|
392
|
-
"compute c2 all pair %s 2" % self.calc._pair_style_names[1]
|
|
393
|
-
)
|
|
394
|
-
else:
|
|
395
|
-
lmp.command(
|
|
396
|
-
"compute c1 all pair %s" % self.calc._pair_style_names[0]
|
|
397
|
-
)
|
|
398
|
-
lmp.command(
|
|
399
|
-
"compute c2 all pair %s" % self.calc._pair_style_names[1]
|
|
400
|
-
)
|
|
411
|
+
for command in commands:
|
|
412
|
+
lmp.command(command)
|
|
401
413
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
"variable dU1 equal c_c1/atoms"
|
|
406
|
-
) # Driving-force obtained from NEHI procedure.
|
|
407
|
-
lmp.command("variable dU2 equal c_c2/atoms")
|
|
408
|
-
|
|
409
|
-
# add swaps if n_swap is > 0 - forward pass
|
|
410
|
-
if (
|
|
411
|
-
self.calc.monte_carlo.n_swaps > 0
|
|
412
|
-
and len(self.calc.monte_carlo.forward_swap_types) >= 2
|
|
413
|
-
):
|
|
414
|
-
swap_types = self.calc.monte_carlo.forward_swap_types
|
|
415
|
-
swap_combos = list(itertools.combinations(swap_types, 2))
|
|
416
|
-
self.logger.info(
|
|
417
|
-
f"Forward pass: {self.calc.monte_carlo.n_swaps} swap moves per combo, {len(swap_combos)} combinations every {self.calc.monte_carlo.n_steps}"
|
|
418
|
-
)
|
|
419
|
-
for combo in swap_combos:
|
|
420
|
-
self.logger.info(f" Swapping types: {combo[0]} <-> {combo[1]}")
|
|
421
|
-
|
|
422
|
-
for idx, (type1, type2) in enumerate(swap_combos):
|
|
423
|
-
swap_str = f"{type1} {type2}"
|
|
424
|
-
if self.calc.monte_carlo.use_custom_lammps:
|
|
425
|
-
lmp.command(
|
|
426
|
-
"fix swap%d all atom/swap %d %d %d %f ke no types %s noforce yes localE yes"
|
|
427
|
-
% (
|
|
428
|
-
idx,
|
|
429
|
-
self.calc.monte_carlo.n_steps,
|
|
430
|
-
self.calc.monte_carlo.n_swaps,
|
|
431
|
-
np.random.randint(1, 10000),
|
|
432
|
-
self.calc._temperature,
|
|
433
|
-
swap_str,
|
|
434
|
-
)
|
|
435
|
-
)
|
|
436
|
-
else:
|
|
437
|
-
lmp.command(
|
|
438
|
-
"fix swap%d all atom/swap %d %d %d %f ke no types %s"
|
|
439
|
-
% (
|
|
440
|
-
idx,
|
|
441
|
-
self.calc.monte_carlo.n_steps,
|
|
442
|
-
self.calc.monte_carlo.n_swaps,
|
|
443
|
-
np.random.randint(1, 10000),
|
|
444
|
-
self.calc._temperature,
|
|
445
|
-
swap_str,
|
|
446
|
-
)
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
# Use the first swap fix for output tracking
|
|
450
|
-
# lmp.command("variable a equal f_swap0[1]")
|
|
451
|
-
# lmp.command("variable b equal f_swap0[2]")
|
|
452
|
-
# lmp.command(
|
|
453
|
-
# 'fix swap_print all print 1 "${a} ${b} ${flambda}" screen no file swap.forward_%d.dat'
|
|
454
|
-
# % iteration
|
|
455
|
-
# )
|
|
414
|
+
swap_fixes = self._add_swap_fixes(
|
|
415
|
+
lmp, self.calc.monte_carlo.forward_swap_types, "Forward"
|
|
416
|
+
)
|
|
456
417
|
|
|
457
418
|
# Thermo output.
|
|
458
419
|
lmp.command("thermo_style custom step v_dU1 v_dU2")
|
|
@@ -467,21 +428,16 @@ class Alchemy(cph.Phase):
|
|
|
467
428
|
)
|
|
468
429
|
lmp.command("run %d" % self.calc._n_switching_steps)
|
|
469
430
|
|
|
470
|
-
# now equilibrate at the second potential
|
|
471
431
|
lmp.command("unfix f2")
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
if self.calc.monte_carlo.n_swaps > 0:
|
|
477
|
-
swap_types = self.calc.monte_carlo.forward_swap_types
|
|
478
|
-
swap_combos = list(itertools.combinations(swap_types, 2))
|
|
479
|
-
for idx in range(len(swap_combos)):
|
|
480
|
-
lmp.command(f"unfix swap{idx}")
|
|
481
|
-
# lmp.command("unfix swap_print")
|
|
432
|
+
for compute_id in compute_ids:
|
|
433
|
+
lmp.command("uncompute %s" % compute_id)
|
|
434
|
+
for swap_fix in swap_fixes:
|
|
435
|
+
lmp.command("unfix %s" % swap_fix)
|
|
482
436
|
|
|
483
|
-
|
|
484
|
-
lmp.command(
|
|
437
|
+
# now equilibrate with the final potential on its own
|
|
438
|
+
lmp.command(self._pure_pair_style_command(final))
|
|
439
|
+
for command in self._pure_pair_coeff_commands(final):
|
|
440
|
+
lmp.command(command)
|
|
485
441
|
|
|
486
442
|
# Thermo output.
|
|
487
443
|
lmp.command("thermo_style custom step pe")
|
|
@@ -490,90 +446,21 @@ class Alchemy(cph.Phase):
|
|
|
490
446
|
# run eqbrm run
|
|
491
447
|
lmp.command("run %d" % self.calc.n_equilibration_steps)
|
|
492
448
|
|
|
493
|
-
#
|
|
449
|
+
# ---------------------------------------------------------------
|
|
450
|
+
# BKD cycle: initial potential scaled 0 -> 1, final potential 1 -> 0
|
|
451
|
+
# ---------------------------------------------------------------
|
|
494
452
|
lmp.command("variable flambda equal ramp(${lf},${li})")
|
|
495
453
|
lmp.command("variable blambda equal ramp(${li},${lf})")
|
|
496
454
|
|
|
497
|
-
|
|
498
|
-
"
|
|
499
|
-
% (
|
|
500
|
-
self.calc._pair_style_with_options[0],
|
|
501
|
-
self.calc._pair_style_with_options[1],
|
|
502
|
-
)
|
|
455
|
+
commands, compute_ids = self._scaled_pair_commands(
|
|
456
|
+
initial, final, "v_flambda", "v_blambda"
|
|
503
457
|
)
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
# apply pair force commands
|
|
508
|
-
if self.calc._pair_style_names[0] == self.calc._pair_style_names[1]:
|
|
509
|
-
lmp.command(
|
|
510
|
-
"compute c1 all pair %s 1" % self.calc._pair_style_names[0]
|
|
511
|
-
)
|
|
512
|
-
lmp.command(
|
|
513
|
-
"compute c2 all pair %s 2" % self.calc._pair_style_names[1]
|
|
514
|
-
)
|
|
515
|
-
else:
|
|
516
|
-
lmp.command(
|
|
517
|
-
"compute c1 all pair %s" % self.calc._pair_style_names[0]
|
|
518
|
-
)
|
|
519
|
-
lmp.command(
|
|
520
|
-
"compute c2 all pair %s" % self.calc._pair_style_names[1]
|
|
521
|
-
)
|
|
458
|
+
for command in commands:
|
|
459
|
+
lmp.command(command)
|
|
522
460
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
"variable dU1 equal c_c1/atoms"
|
|
527
|
-
) # Driving-force obtained from NEHI procedure.
|
|
528
|
-
lmp.command("variable dU2 equal c_c2/atoms")
|
|
529
|
-
|
|
530
|
-
# add swaps if n_swap is > 0 - reverse pass
|
|
531
|
-
if (
|
|
532
|
-
self.calc.monte_carlo.n_swaps > 0
|
|
533
|
-
and len(self.calc.monte_carlo.reverse_swap_types) >= 2
|
|
534
|
-
):
|
|
535
|
-
swap_types = self.calc.monte_carlo.reverse_swap_types
|
|
536
|
-
swap_combos = list(itertools.combinations(swap_types, 2))
|
|
537
|
-
self.logger.info(
|
|
538
|
-
f"Reverse pass: {self.calc.monte_carlo.n_swaps} swap moves per combo, {len(swap_combos)} combinations every {self.calc.monte_carlo.n_steps}"
|
|
539
|
-
)
|
|
540
|
-
for combo in swap_combos:
|
|
541
|
-
self.logger.info(f" Swapping types: {combo[0]} <-> {combo[1]}")
|
|
542
|
-
|
|
543
|
-
for idx, (type1, type2) in enumerate(swap_combos):
|
|
544
|
-
swap_str = f"{type1} {type2}"
|
|
545
|
-
if self.calc.monte_carlo.use_custom_lammps:
|
|
546
|
-
lmp.command(
|
|
547
|
-
"fix swap%d all atom/swap %d %d %d %f ke no types %s noforce yes localE yes"
|
|
548
|
-
% (
|
|
549
|
-
idx,
|
|
550
|
-
self.calc.monte_carlo.n_steps,
|
|
551
|
-
self.calc.monte_carlo.n_swaps,
|
|
552
|
-
np.random.randint(1, 10000),
|
|
553
|
-
self.calc._temperature,
|
|
554
|
-
swap_str,
|
|
555
|
-
)
|
|
556
|
-
)
|
|
557
|
-
else:
|
|
558
|
-
lmp.command(
|
|
559
|
-
"fix swap%d all atom/swap %d %d %d %f ke no types %s"
|
|
560
|
-
% (
|
|
561
|
-
idx,
|
|
562
|
-
self.calc.monte_carlo.n_steps,
|
|
563
|
-
self.calc.monte_carlo.n_swaps,
|
|
564
|
-
np.random.randint(1, 10000),
|
|
565
|
-
self.calc._temperature,
|
|
566
|
-
swap_str,
|
|
567
|
-
)
|
|
568
|
-
)
|
|
569
|
-
|
|
570
|
-
# Use the first swap fix for output tracking
|
|
571
|
-
# lmp.command("variable a equal f_swap0[1]")
|
|
572
|
-
# lmp.command("variable b equal f_swap0[2]")
|
|
573
|
-
# lmp.command(
|
|
574
|
-
#'fix swap_print all print 1 "${a} ${b} ${blambda}" screen no file swap.backward_%d.dat'
|
|
575
|
-
# % iteration
|
|
576
|
-
# )
|
|
461
|
+
swap_fixes = self._add_swap_fixes(
|
|
462
|
+
lmp, self.calc.monte_carlo.reverse_swap_types, "Reverse"
|
|
463
|
+
)
|
|
577
464
|
|
|
578
465
|
# Thermo output.
|
|
579
466
|
lmp.command("thermo_style custom step v_dU1 v_dU2")
|
|
@@ -588,21 +475,52 @@ class Alchemy(cph.Phase):
|
|
|
588
475
|
)
|
|
589
476
|
lmp.command("run %d" % self.calc._n_switching_steps)
|
|
590
477
|
|
|
591
|
-
# now equilibrate at the second potential
|
|
592
478
|
lmp.command("unfix f2")
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
swap_types = self.calc.monte_carlo.reverse_swap_types
|
|
598
|
-
swap_combos = list(itertools.combinations(swap_types, 2))
|
|
599
|
-
for idx in range(len(swap_combos)):
|
|
600
|
-
lmp.command(f"unfix swap{idx}")
|
|
601
|
-
# lmp.command("unfix swap_print")
|
|
479
|
+
for compute_id in compute_ids:
|
|
480
|
+
lmp.command("uncompute %s" % compute_id)
|
|
481
|
+
for swap_fix in swap_fixes:
|
|
482
|
+
lmp.command("unfix %s" % swap_fix)
|
|
602
483
|
|
|
603
484
|
self.lammps_close(lmp=lmp)
|
|
604
485
|
lmp.rotate_logs("integration")
|
|
605
486
|
|
|
487
|
+
def _add_swap_fixes(self, lmp, swap_types, pass_name):
|
|
488
|
+
"""
|
|
489
|
+
Add ``fix atom/swap`` moves between every pair of ``swap_types`` when
|
|
490
|
+
Monte Carlo swaps are requested; returns the fix ids that were added.
|
|
491
|
+
"""
|
|
492
|
+
mc = self.calc.monte_carlo
|
|
493
|
+
if not (mc.n_swaps > 0 and len(swap_types) >= 2):
|
|
494
|
+
return []
|
|
495
|
+
|
|
496
|
+
swap_combos = list(itertools.combinations(swap_types, 2))
|
|
497
|
+
self.logger.info(
|
|
498
|
+
f"{pass_name} pass: {mc.n_swaps} swap moves per combo, "
|
|
499
|
+
f"{len(swap_combos)} combinations every {mc.n_steps}"
|
|
500
|
+
)
|
|
501
|
+
for combo in swap_combos:
|
|
502
|
+
self.logger.info(f" Swapping types: {combo[0]} <-> {combo[1]}")
|
|
503
|
+
|
|
504
|
+
fix_ids = []
|
|
505
|
+
for idx, (type1, type2) in enumerate(swap_combos):
|
|
506
|
+
fix_id = "swap%d" % idx
|
|
507
|
+
extra = " noforce yes localE yes" if mc.use_custom_lammps else ""
|
|
508
|
+
lmp.command(
|
|
509
|
+
"fix %s all atom/swap %d %d %d %f ke no types %s %s%s"
|
|
510
|
+
% (
|
|
511
|
+
fix_id,
|
|
512
|
+
mc.n_steps,
|
|
513
|
+
mc.n_swaps,
|
|
514
|
+
np.random.randint(1, 10000),
|
|
515
|
+
self.calc._temperature,
|
|
516
|
+
type1,
|
|
517
|
+
type2,
|
|
518
|
+
extra,
|
|
519
|
+
)
|
|
520
|
+
)
|
|
521
|
+
fix_ids.append(fix_id)
|
|
522
|
+
return fix_ids
|
|
523
|
+
|
|
606
524
|
def thermodynamic_integration(self):
|
|
607
525
|
"""
|
|
608
526
|
Calculate free energy after integration step
|
|
@@ -208,26 +208,78 @@ def _component_pair_coeffs(options):
|
|
|
208
208
|
return components
|
|
209
209
|
|
|
210
210
|
|
|
211
|
-
def
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
211
|
+
def hybrid_component_tags(style_names):
|
|
212
|
+
"""
|
|
213
|
+
Sub-style tags of the components of a hybrid pair_style.
|
|
214
|
+
|
|
215
|
+
LAMMPS addresses a sub-style of a hybrid pair_style by its name, followed
|
|
216
|
+
by a 1-based occurrence index when the same style appears more than once
|
|
217
|
+
(``pair_coeff * * eam/alloy 2 ...``, ``compute c all pair eam/alloy 2``).
|
|
218
|
+
|
|
219
|
+
Parameters
|
|
220
|
+
----------
|
|
221
|
+
style_names : list of str
|
|
222
|
+
Style names in the order they appear in the hybrid pair_style.
|
|
223
|
+
|
|
224
|
+
Returns
|
|
225
|
+
-------
|
|
226
|
+
list of (str, int or None)
|
|
227
|
+
One (name, index) tag per component; the index is None for a style
|
|
228
|
+
that occurs once.
|
|
229
|
+
"""
|
|
230
|
+
counts = Counter(style_names)
|
|
217
231
|
seen = defaultdict(int)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
232
|
+
tags = []
|
|
233
|
+
for name in style_names:
|
|
234
|
+
seen[name] += 1
|
|
235
|
+
tags.append((name, seen[name] if counts[name] > 1 else None))
|
|
236
|
+
return tags
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def hybrid_pair_coeff_commands_for(style_names, pair_coeffs):
|
|
240
|
+
"""
|
|
241
|
+
``pair_coeff`` commands for the components of a hybrid pair_style.
|
|
242
|
+
|
|
243
|
+
Parameters
|
|
244
|
+
----------
|
|
245
|
+
style_names : list of str
|
|
246
|
+
Style names in hybrid order, one per pair_coeff.
|
|
247
|
+
pair_coeffs : list of str
|
|
248
|
+
The pair_coeff arguments, with or without the style name already
|
|
249
|
+
included after the type pair.
|
|
250
|
+
"""
|
|
251
|
+
return [
|
|
252
|
+
"pair_coeff %s" % _with_hybrid_pair_coeff_style(pair_coeff, name, index)
|
|
253
|
+
for (name, index), pair_coeff in zip(hybrid_component_tags(style_names), pair_coeffs)
|
|
254
|
+
]
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def hybrid_pair_compute_commands(compute_ids, tags):
|
|
258
|
+
"""
|
|
259
|
+
``compute pair`` commands, one per hybrid sub-style tag.
|
|
221
260
|
|
|
261
|
+
Returns the commands and the LAMMPS expression summing the computes.
|
|
262
|
+
"""
|
|
222
263
|
commands = []
|
|
223
|
-
for
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
return commands
|
|
264
|
+
for compute_id, (name, index) in zip(compute_ids, tags):
|
|
265
|
+
if index is None:
|
|
266
|
+
commands.append("compute %s all pair %s" % (compute_id, name))
|
|
267
|
+
else:
|
|
268
|
+
commands.append(
|
|
269
|
+
"compute %s all pair %s %d" % (compute_id, name, index)
|
|
270
|
+
)
|
|
271
|
+
return commands, "+".join("c_%s" % compute_id for compute_id in compute_ids)
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def hybrid_pair_coeff_commands(options, repeat_index=0, total_repeats=1):
|
|
275
|
+
components = _component_pair_coeffs(options)
|
|
276
|
+
n = len(components)
|
|
277
|
+
style_names = [style_name for style_name, _ in components] * total_repeats
|
|
278
|
+
tags = hybrid_component_tags(style_names)[repeat_index * n : (repeat_index + 1) * n]
|
|
279
|
+
return [
|
|
280
|
+
"pair_coeff %s" % _with_hybrid_pair_coeff_style(pair_coeff, name, index)
|
|
281
|
+
for (name, index), (_, pair_coeff) in zip(tags, components)
|
|
282
|
+
]
|
|
231
283
|
|
|
232
284
|
|
|
233
285
|
def set_pair_coeff(lmp, options):
|
|
@@ -253,35 +305,12 @@ def real_pair_compute_commands(
|
|
|
253
305
|
options, prefix="c_real", total_repeats=1, repeat_index=0
|
|
254
306
|
):
|
|
255
307
|
components = _component_pair_coeffs(options)
|
|
256
|
-
|
|
257
|
-
for _ in
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
for style_name, _ in components:
|
|
263
|
-
seen[style_name] += 1
|
|
264
|
-
|
|
265
|
-
commands = []
|
|
266
|
-
terms = []
|
|
267
|
-
for idx, (style_name, _) in enumerate(components, start=1):
|
|
268
|
-
seen[style_name] += 1
|
|
269
|
-
compute_id = "%s%d" % (prefix, idx)
|
|
270
|
-
if total_counts[style_name] > 1:
|
|
271
|
-
commands.append(
|
|
272
|
-
"compute %s all pair %s %d"
|
|
273
|
-
% (compute_id, style_name, seen[style_name])
|
|
274
|
-
)
|
|
275
|
-
else:
|
|
276
|
-
commands.append(
|
|
277
|
-
"compute %s all pair %s" % (compute_id, style_name)
|
|
278
|
-
)
|
|
279
|
-
terms.append("c_%s" % compute_id)
|
|
280
|
-
return (
|
|
281
|
-
commands,
|
|
282
|
-
"+".join(terms),
|
|
283
|
-
["%s%d" % (prefix, idx) for idx in range(1, len(components) + 1)],
|
|
284
|
-
)
|
|
308
|
+
n = len(components)
|
|
309
|
+
style_names = [style_name for style_name, _ in components] * total_repeats
|
|
310
|
+
tags = hybrid_component_tags(style_names)[repeat_index * n : (repeat_index + 1) * n]
|
|
311
|
+
compute_ids = ["%s%d" % (prefix, idx) for idx in range(1, n + 1)]
|
|
312
|
+
commands, energy = hybrid_pair_compute_commands(compute_ids, tags)
|
|
313
|
+
return commands, energy, compute_ids
|
|
285
314
|
|
|
286
315
|
|
|
287
316
|
def set_potential(lmp, options):
|