calphy 1.4.5__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 +298 -136
- calphy/helpers.py +45 -29
- calphy/input.py +81 -3
- calphy/liquid.py +13 -0
- calphy/phase.py +55 -4
- calphy/phase_diagram.py +196 -53
- calphy/routines.py +6 -0
- calphy/scheduler.py +100 -105
- calphy/solid.py +243 -186
- {calphy-1.4.5.dist-info → calphy-1.4.12.dist-info}/METADATA +1 -1
- calphy-1.4.12.dist-info/RECORD +25 -0
- {calphy-1.4.5.dist-info → calphy-1.4.12.dist-info}/WHEEL +1 -1
- calphy-1.4.5.dist-info/RECORD +0 -25
- {calphy-1.4.5.dist-info → calphy-1.4.12.dist-info}/entry_points.txt +0 -0
- {calphy-1.4.5.dist-info → calphy-1.4.12.dist-info}/licenses/LICENSE +0 -0
- {calphy-1.4.5.dist-info → calphy-1.4.12.dist-info}/top_level.txt +0 -0
calphy/helpers.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.
|
|
@@ -34,6 +34,7 @@ from ase.io import read, write
|
|
|
34
34
|
import pyscal3.core as pc
|
|
35
35
|
from pyscal3.trajectory import Trajectory
|
|
36
36
|
|
|
37
|
+
|
|
37
38
|
class LammpsScript:
|
|
38
39
|
def __init__(self):
|
|
39
40
|
self.script = []
|
|
@@ -42,12 +43,14 @@ class LammpsScript:
|
|
|
42
43
|
self.script.append(command_str)
|
|
43
44
|
|
|
44
45
|
def write(self, infile):
|
|
45
|
-
with open(infile,
|
|
46
|
+
with open(infile, "w") as fout:
|
|
46
47
|
for line in self.script:
|
|
47
|
-
fout.write(f
|
|
48
|
+
fout.write(f"{line}\n")
|
|
49
|
+
|
|
48
50
|
|
|
49
|
-
def create_object(
|
|
50
|
-
init_commands=(), script_mode=False
|
|
51
|
+
def create_object(
|
|
52
|
+
cores, directory, timestep, cmdargs="", init_commands=(), script_mode=False
|
|
53
|
+
):
|
|
51
54
|
"""
|
|
52
55
|
Create LAMMPS object
|
|
53
56
|
|
|
@@ -71,28 +74,30 @@ def create_object(cores, directory, timestep, cmdargs="",
|
|
|
71
74
|
else:
|
|
72
75
|
if cmdargs == "":
|
|
73
76
|
cmdargs = None
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
)
|
|
77
|
-
|
|
78
|
-
commands = [
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
elif isinstance(cmdargs, str):
|
|
78
|
+
cmdargs = cmdargs.split()
|
|
79
|
+
lmp = LammpsLibrary(cores=cores, working_directory=directory, cmdargs=cmdargs)
|
|
80
|
+
|
|
81
|
+
commands = [
|
|
82
|
+
["units", "metal"],
|
|
83
|
+
["boundary", "p p p"],
|
|
84
|
+
["atom_style", "atomic"],
|
|
85
|
+
["timestep", str(timestep)],
|
|
86
|
+
["box", "tilt large"],
|
|
87
|
+
]
|
|
83
88
|
|
|
84
89
|
if len(init_commands) > 0:
|
|
85
|
-
#we need to replace some initial commands
|
|
90
|
+
# we need to replace some initial commands
|
|
86
91
|
for rc in init_commands:
|
|
87
|
-
#split the command
|
|
92
|
+
# split the command
|
|
88
93
|
raw = rc.split()
|
|
89
94
|
for x in range(len(commands)):
|
|
90
95
|
if raw[0] == commands[x][0]:
|
|
91
|
-
#we found a matching command
|
|
96
|
+
# we found a matching command
|
|
92
97
|
commands[x] = [rc]
|
|
93
98
|
break
|
|
94
99
|
else:
|
|
95
|
-
#its a new command, add it to the list
|
|
100
|
+
# its a new command, add it to the list
|
|
96
101
|
commands.append([rc])
|
|
97
102
|
|
|
98
103
|
for command in commands:
|
|
@@ -121,12 +126,12 @@ def create_structure(lmp, calc):
|
|
|
121
126
|
|
|
122
127
|
|
|
123
128
|
def set_mass(lmp, options):
|
|
124
|
-
if options.mode ==
|
|
125
|
-
lmp.command(f
|
|
129
|
+
if options.mode == "composition_scaling":
|
|
130
|
+
lmp.command(f"mass * {options.mass[-1]}")
|
|
126
131
|
|
|
127
132
|
else:
|
|
128
133
|
for i in range(options.n_elements):
|
|
129
|
-
lmp.command(f
|
|
134
|
+
lmp.command(f"mass {i + 1} {options.mass[i]}")
|
|
130
135
|
return lmp
|
|
131
136
|
|
|
132
137
|
|
|
@@ -144,19 +149,21 @@ def set_potential(lmp, options):
|
|
|
144
149
|
-------
|
|
145
150
|
lmp : LammpsLibrary object
|
|
146
151
|
"""
|
|
147
|
-
#lmp.pair_style(options.pair_style_with_options[0])
|
|
148
|
-
#lmp.pair_coeff(options.pair_coeff[0])
|
|
149
|
-
lmp.command(f
|
|
150
|
-
lmp.command(f
|
|
152
|
+
# lmp.pair_style(options.pair_style_with_options[0])
|
|
153
|
+
# lmp.pair_coeff(options.pair_coeff[0])
|
|
154
|
+
lmp.command(f"pair_style {options._pair_style_with_options[0]}")
|
|
155
|
+
lmp.command(f"pair_coeff {options.pair_coeff[0]}")
|
|
151
156
|
|
|
152
157
|
lmp = set_mass(lmp, options)
|
|
153
158
|
|
|
154
159
|
return lmp
|
|
155
160
|
|
|
161
|
+
|
|
156
162
|
def read_data(lmp, file):
|
|
157
163
|
lmp.command(f"read_data {file}")
|
|
158
164
|
return lmp
|
|
159
165
|
|
|
166
|
+
|
|
160
167
|
def get_structures(file, species, index=None):
|
|
161
168
|
traj = Trajectory(file)
|
|
162
169
|
if index is None:
|
|
@@ -165,6 +172,7 @@ def get_structures(file, species, index=None):
|
|
|
165
172
|
aseobjs = traj[index].to_ase(species=species)
|
|
166
173
|
return aseobjs
|
|
167
174
|
|
|
175
|
+
|
|
168
176
|
def remap_box(lmp, x, y, z):
|
|
169
177
|
lmp.command("run 0")
|
|
170
178
|
lmp.command(
|
|
@@ -222,8 +230,15 @@ def write_data(lmp, file):
|
|
|
222
230
|
lmp.command(f"write_data {file}")
|
|
223
231
|
return lmp
|
|
224
232
|
|
|
233
|
+
|
|
225
234
|
def prepare_log(file, screen=False):
|
|
226
235
|
logger = logging.getLogger(__name__)
|
|
236
|
+
|
|
237
|
+
# Remove all existing handlers to prevent duplicate logging
|
|
238
|
+
for handler in logger.handlers[:]:
|
|
239
|
+
handler.close()
|
|
240
|
+
logger.removeHandler(handler)
|
|
241
|
+
|
|
227
242
|
handler = logging.FileHandler(file)
|
|
228
243
|
formatter = logging.Formatter("%(asctime)s %(name)-12s %(levelname)-8s %(message)s")
|
|
229
244
|
handler.setFormatter(formatter)
|
|
@@ -238,6 +253,7 @@ def prepare_log(file, screen=False):
|
|
|
238
253
|
logger.addHandler(scr)
|
|
239
254
|
return logger
|
|
240
255
|
|
|
256
|
+
|
|
241
257
|
def check_if_any_is_none(data):
|
|
242
258
|
"""
|
|
243
259
|
Check if any elements of a list is None, if so return True
|
calphy/input.py
CHANGED
|
@@ -49,7 +49,7 @@ from pyscal3.core import structure_dict, element_dict, _make_crystal
|
|
|
49
49
|
from ase.io import read, write
|
|
50
50
|
import shutil
|
|
51
51
|
|
|
52
|
-
__version__ = "1.4.
|
|
52
|
+
__version__ = "1.4.12"
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def _check_equal(val):
|
|
@@ -92,6 +92,49 @@ def _to_float(val):
|
|
|
92
92
|
return [float(x) for x in val]
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
def _extract_elements_from_pair_coeff(pair_coeff_string):
|
|
96
|
+
"""
|
|
97
|
+
Extract element symbols from pair_coeff string.
|
|
98
|
+
Returns None if pair_coeff doesn't contain element specifications.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
pair_coeff_string : str
|
|
103
|
+
The pair_coeff command string (e.g., "* * potential.eam.fs Cu Zr")
|
|
104
|
+
|
|
105
|
+
Returns
|
|
106
|
+
-------
|
|
107
|
+
list or None
|
|
108
|
+
List of element symbols in order, or None if no elements found
|
|
109
|
+
"""
|
|
110
|
+
if pair_coeff_string is None:
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
pcsplit = pair_coeff_string.strip().split()
|
|
114
|
+
elements = []
|
|
115
|
+
|
|
116
|
+
# Start collecting after we find element symbols
|
|
117
|
+
# Elements are typically after the potential filename
|
|
118
|
+
started = False
|
|
119
|
+
|
|
120
|
+
for p in pcsplit:
|
|
121
|
+
# Check if this looks like an element symbol
|
|
122
|
+
# Element symbols are 1-2 characters, start with uppercase
|
|
123
|
+
if len(p) <= 2 and p[0].isupper():
|
|
124
|
+
try:
|
|
125
|
+
# Verify it's a valid element using mendeleev
|
|
126
|
+
_ = mendeleev.element(p)
|
|
127
|
+
elements.append(p)
|
|
128
|
+
started = True
|
|
129
|
+
except:
|
|
130
|
+
# Not a valid element, might be done collecting
|
|
131
|
+
if started:
|
|
132
|
+
# We already started collecting elements and hit a non-element
|
|
133
|
+
break
|
|
134
|
+
|
|
135
|
+
return elements if len(elements) > 0 else None
|
|
136
|
+
|
|
137
|
+
|
|
95
138
|
class UFMP(BaseModel, title="UFM potential input options"):
|
|
96
139
|
p: Annotated[float, Field(default=50.0)]
|
|
97
140
|
sigma: Annotated[float, Field(default=1.5)]
|
|
@@ -165,7 +208,6 @@ class Queue(BaseModel, title="Options for configuring queue"):
|
|
|
165
208
|
memory: Annotated[str, Field(default="3GB")]
|
|
166
209
|
commands: Annotated[List, Field(default=[])]
|
|
167
210
|
options: Annotated[List, Field(default=[])]
|
|
168
|
-
modules: Annotated[List, Field(default=[])]
|
|
169
211
|
|
|
170
212
|
|
|
171
213
|
class Tolerance(BaseModel, title="Tolerance settings for convergence"):
|
|
@@ -308,12 +350,48 @@ class Calculation(BaseModel, title="Main input class"):
|
|
|
308
350
|
|
|
309
351
|
@model_validator(mode="after")
|
|
310
352
|
def _validate_all(self) -> "Input":
|
|
311
|
-
|
|
312
353
|
if not (len(self.element) == len(self.mass)):
|
|
313
354
|
raise ValueError("mass and elements should have same length")
|
|
314
355
|
|
|
315
356
|
self.n_elements = len(self.element)
|
|
316
357
|
|
|
358
|
+
# Validate element/mass/pair_coeff ordering consistency
|
|
359
|
+
# This is critical for multi-element systems where LAMMPS type numbers
|
|
360
|
+
# are assigned based on element order: element[0]=Type1, element[1]=Type2, etc.
|
|
361
|
+
if (
|
|
362
|
+
len(self.element) > 1
|
|
363
|
+
and self.pair_coeff is not None
|
|
364
|
+
and len(self.pair_coeff) > 0
|
|
365
|
+
):
|
|
366
|
+
extracted_elements = _extract_elements_from_pair_coeff(self.pair_coeff[0])
|
|
367
|
+
|
|
368
|
+
if extracted_elements is not None:
|
|
369
|
+
# pair_coeff specifies elements - check ordering
|
|
370
|
+
if set(extracted_elements) != set(self.element):
|
|
371
|
+
raise ValueError(
|
|
372
|
+
f"Element mismatch between 'element' and 'pair_coeff'!\n"
|
|
373
|
+
f" element: {self.element}\n"
|
|
374
|
+
f" pair_coeff: {extracted_elements}\n"
|
|
375
|
+
f"The elements specified must be the same."
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
if list(extracted_elements) != list(self.element):
|
|
379
|
+
raise ValueError(
|
|
380
|
+
f"Element ordering mismatch detected!\n\n"
|
|
381
|
+
f" element: {self.element}\n"
|
|
382
|
+
f" pair_coeff: {extracted_elements}\n"
|
|
383
|
+
f" mass: {self.mass}\n\n"
|
|
384
|
+
f"For multi-element systems, all three must be in the SAME order.\n\n"
|
|
385
|
+
f"Why this matters:\n"
|
|
386
|
+
f" - Element order determines LAMMPS type numbers:\n"
|
|
387
|
+
f" element[0] → Type 1, element[1] → Type 2, etc.\n"
|
|
388
|
+
f" - The pair_coeff elements must match this type order\n"
|
|
389
|
+
f" - The mass values must correspond to the same order\n"
|
|
390
|
+
f" - Composition transformations depend on this ordering\n\n"
|
|
391
|
+
f"Please reorder your input so element, mass, and pair_coeff\n"
|
|
392
|
+
f"all use the same element ordering."
|
|
393
|
+
)
|
|
394
|
+
|
|
317
395
|
self._pressure_input = copy.copy(self.pressure)
|
|
318
396
|
if self.pressure is None:
|
|
319
397
|
self._iso = True
|
calphy/liquid.py
CHANGED
|
@@ -23,6 +23,7 @@ sarath.menon@ruhr-uni-bochum.de/yury.lysogorskiy@icams.rub.de
|
|
|
23
23
|
|
|
24
24
|
import numpy as np
|
|
25
25
|
import yaml
|
|
26
|
+
import os
|
|
26
27
|
|
|
27
28
|
from calphy.integrators import *
|
|
28
29
|
import calphy.helpers as ph
|
|
@@ -100,6 +101,10 @@ class Liquid(cph.Phase):
|
|
|
100
101
|
# if melting cycle is over and still not melted, raise error
|
|
101
102
|
if not melted:
|
|
102
103
|
lmp.close()
|
|
104
|
+
# Preserve log file
|
|
105
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
106
|
+
if os.path.exists(logfile):
|
|
107
|
+
os.rename(logfile, os.path.join(self.simfolder, "melting.log.lammps"))
|
|
103
108
|
raise SolidifiedError(
|
|
104
109
|
"Liquid system did not melt, maybe try a higher thigh temperature."
|
|
105
110
|
)
|
|
@@ -175,6 +180,10 @@ class Liquid(cph.Phase):
|
|
|
175
180
|
self.dump_current_snapshot(lmp, "traj.equilibration_stage2.dat")
|
|
176
181
|
lmp = ph.write_data(lmp, "conf.equilibration.data")
|
|
177
182
|
lmp.close()
|
|
183
|
+
# Preserve log file
|
|
184
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
185
|
+
if os.path.exists(logfile):
|
|
186
|
+
os.rename(logfile, os.path.join(self.simfolder, "averaging.log.lammps"))
|
|
178
187
|
|
|
179
188
|
def run_integration(self, iteration=1):
|
|
180
189
|
"""
|
|
@@ -390,6 +399,10 @@ class Liquid(cph.Phase):
|
|
|
390
399
|
|
|
391
400
|
# close object
|
|
392
401
|
lmp.close()
|
|
402
|
+
# Preserve log file
|
|
403
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
404
|
+
if os.path.exists(logfile):
|
|
405
|
+
os.rename(logfile, os.path.join(self.simfolder, "integration.log.lammps"))
|
|
393
406
|
|
|
394
407
|
def thermodynamic_integration(self):
|
|
395
408
|
"""
|
calphy/phase.py
CHANGED
|
@@ -278,6 +278,12 @@ class Phase:
|
|
|
278
278
|
solids = ph.find_solid_fraction(os.path.join(self.simfolder, filename))
|
|
279
279
|
if solids / lmp.natoms < self.calc.tolerance.solid_fraction:
|
|
280
280
|
lmp.close()
|
|
281
|
+
# Preserve log file on error
|
|
282
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
283
|
+
if os.path.exists(logfile):
|
|
284
|
+
os.rename(
|
|
285
|
+
logfile, os.path.join(self.simfolder, "melted_error.log.lammps")
|
|
286
|
+
)
|
|
281
287
|
raise MeltedError(
|
|
282
288
|
"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
289
|
)
|
|
@@ -287,6 +293,12 @@ class Phase:
|
|
|
287
293
|
solids = ph.find_solid_fraction(os.path.join(self.simfolder, filename))
|
|
288
294
|
if solids / lmp.natoms > self.calc.tolerance.liquid_fraction:
|
|
289
295
|
lmp.close()
|
|
296
|
+
# Preserve log file on error
|
|
297
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
298
|
+
if os.path.exists(logfile):
|
|
299
|
+
os.rename(
|
|
300
|
+
logfile, os.path.join(self.simfolder, "solidified_error.log.lammps")
|
|
301
|
+
)
|
|
290
302
|
raise SolidifiedError("System solidified, increase temperature")
|
|
291
303
|
|
|
292
304
|
def fix_nose_hoover(
|
|
@@ -594,6 +606,15 @@ class Phase:
|
|
|
594
606
|
|
|
595
607
|
if not converged:
|
|
596
608
|
lmp.close()
|
|
609
|
+
# Preserve log file on error
|
|
610
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
611
|
+
if os.path.exists(logfile):
|
|
612
|
+
os.rename(
|
|
613
|
+
logfile,
|
|
614
|
+
os.path.join(
|
|
615
|
+
self.simfolder, "pressure_convergence_error.log.lammps"
|
|
616
|
+
),
|
|
617
|
+
)
|
|
597
618
|
raise ValueError(
|
|
598
619
|
"Pressure did not converge after MD runs, maybe change lattice_constant and try?"
|
|
599
620
|
)
|
|
@@ -708,6 +729,15 @@ class Phase:
|
|
|
708
729
|
|
|
709
730
|
if not converged:
|
|
710
731
|
lmp.close()
|
|
732
|
+
# Preserve log file on error
|
|
733
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
734
|
+
if os.path.exists(logfile):
|
|
735
|
+
os.rename(
|
|
736
|
+
logfile,
|
|
737
|
+
os.path.join(
|
|
738
|
+
self.simfolder, "constrained_pressure_error.log.lammps"
|
|
739
|
+
),
|
|
740
|
+
)
|
|
711
741
|
raise ValueError("pressure did not converge")
|
|
712
742
|
|
|
713
743
|
def process_pressure(
|
|
@@ -1180,6 +1210,12 @@ class Phase:
|
|
|
1180
1210
|
|
|
1181
1211
|
# close the object
|
|
1182
1212
|
lmp.close()
|
|
1213
|
+
# Preserve log file
|
|
1214
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
1215
|
+
if os.path.exists(logfile):
|
|
1216
|
+
os.rename(
|
|
1217
|
+
logfile, os.path.join(self.simfolder, "reversible_scaling.log.lammps")
|
|
1218
|
+
)
|
|
1183
1219
|
|
|
1184
1220
|
self.logger.info("Please cite the following publications:")
|
|
1185
1221
|
if self.calc.mode == "mts":
|
|
@@ -1217,10 +1253,13 @@ class Phase:
|
|
|
1217
1253
|
return_values=return_values,
|
|
1218
1254
|
)
|
|
1219
1255
|
|
|
1220
|
-
self.logger.info(
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1256
|
+
self.logger.info(
|
|
1257
|
+
f"Maximum energy dissipation along the temperature scaling part: {ediss} eV/atom"
|
|
1258
|
+
)
|
|
1259
|
+
if np.abs(ediss) > 1e-4:
|
|
1260
|
+
self.logger.warning(
|
|
1261
|
+
f"Found max energy dissipation of {ediss} along the temperature scaling path. Please ensure there are no structural changes!"
|
|
1262
|
+
)
|
|
1224
1263
|
|
|
1225
1264
|
if return_values:
|
|
1226
1265
|
return res
|
|
@@ -1369,6 +1408,12 @@ class Phase:
|
|
|
1369
1408
|
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1370
1409
|
|
|
1371
1410
|
lmp.close()
|
|
1411
|
+
# Preserve log file
|
|
1412
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
1413
|
+
if os.path.exists(logfile):
|
|
1414
|
+
os.rename(
|
|
1415
|
+
logfile, os.path.join(self.simfolder, "temperature_scaling.log.lammps")
|
|
1416
|
+
)
|
|
1372
1417
|
|
|
1373
1418
|
def pressure_scaling(self, iteration=1):
|
|
1374
1419
|
"""
|
|
@@ -1499,6 +1544,12 @@ class Phase:
|
|
|
1499
1544
|
lmp.command("run %d" % self.calc._n_sweep_steps)
|
|
1500
1545
|
|
|
1501
1546
|
lmp.close()
|
|
1547
|
+
# Preserve log file
|
|
1548
|
+
logfile = os.path.join(self.simfolder, "log.lammps")
|
|
1549
|
+
if os.path.exists(logfile):
|
|
1550
|
+
os.rename(
|
|
1551
|
+
logfile, os.path.join(self.simfolder, "pressure_scaling.log.lammps")
|
|
1552
|
+
)
|
|
1502
1553
|
|
|
1503
1554
|
self.logger.info("Please cite the following publications:")
|
|
1504
1555
|
self.logger.info("- 10.1016/j.commatsci.2022.111275")
|