calphy 1.2.14__py3-none-any.whl → 1.3.0__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 +9 -4
- calphy/helpers.py +15 -187
- calphy/input.py +40 -48
- calphy/integrators.py +61 -34
- calphy/liquid.py +11 -5
- calphy/phase.py +14 -76
- calphy/routines.py +5 -0
- calphy/solid.py +37 -18
- {calphy-1.2.14.dist-info → calphy-1.3.0.dist-info}/METADATA +1 -2
- calphy-1.3.0.dist-info/RECORD +23 -0
- calphy/inputbk.py +0 -862
- calphy/lattice.py +0 -180
- calphy-1.2.14.dist-info/RECORD +0 -25
- {calphy-1.2.14.dist-info → calphy-1.3.0.dist-info}/LICENSE +0 -0
- {calphy-1.2.14.dist-info → calphy-1.3.0.dist-info}/WHEEL +0 -0
- {calphy-1.2.14.dist-info → calphy-1.3.0.dist-info}/entry_points.txt +0 -0
- {calphy-1.2.14.dist-info → calphy-1.3.0.dist-info}/top_level.txt +0 -0
calphy/__init__.py
CHANGED
calphy/alchemy.py
CHANGED
|
@@ -24,9 +24,7 @@ sarath.menon@ruhr-uni-bochum.de/yury.lysogorskiy@icams.rub.de
|
|
|
24
24
|
import numpy as np
|
|
25
25
|
import yaml
|
|
26
26
|
|
|
27
|
-
import pyscal.traj_process as ptp
|
|
28
27
|
from calphy.integrators import *
|
|
29
|
-
import calphy.lattice as pl
|
|
30
28
|
import calphy.helpers as ph
|
|
31
29
|
import calphy.phase as cph
|
|
32
30
|
|
|
@@ -79,11 +77,14 @@ class Alchemy(cph.Phase):
|
|
|
79
77
|
lmp = ph.create_object(self.cores, self.simfolder, self.calc.md.timestep,
|
|
80
78
|
self.calc.md.cmdargs, self.calc.md.init_commands)
|
|
81
79
|
|
|
80
|
+
lmp.command(f'pair_style {self.calc._pair_style_with_options[0]}')
|
|
81
|
+
|
|
82
82
|
#set up structure
|
|
83
83
|
lmp = ph.create_structure(lmp, self.calc)
|
|
84
84
|
|
|
85
85
|
#set up potential
|
|
86
|
-
lmp
|
|
86
|
+
lmp.command(f'pair_coeff {self.calc.pair_coeff[0]}')
|
|
87
|
+
lmp = ph.set_mass(lmp, self.calc)
|
|
87
88
|
|
|
88
89
|
#add some computes
|
|
89
90
|
lmp.command("variable mvol equal vol")
|
|
@@ -145,6 +146,8 @@ class Alchemy(cph.Phase):
|
|
|
145
146
|
# Adiabatic switching parameters.
|
|
146
147
|
lmp.command("variable li equal 1.0")
|
|
147
148
|
lmp.command("variable lf equal 0.0")
|
|
149
|
+
|
|
150
|
+
lmp.command(f'pair_style {self.calc._pair_style_with_options[0]}')
|
|
148
151
|
|
|
149
152
|
#read dump file
|
|
150
153
|
#conf = os.path.join(self.simfolder, "conf.equilibration.dump")
|
|
@@ -153,7 +156,9 @@ class Alchemy(cph.Phase):
|
|
|
153
156
|
|
|
154
157
|
#set up hybrid potential
|
|
155
158
|
#here we only need to set one potential
|
|
156
|
-
lmp
|
|
159
|
+
lmp.command(f'pair_coeff {self.calc.pair_coeff[0]}')
|
|
160
|
+
lmp = ph.set_mass(lmp, self.calc)
|
|
161
|
+
|
|
157
162
|
#lmp = ph.set_double_hybrid_potential(lmp, self.options, self.calc._pressureair_style, self.calc._pressureair_coeff)
|
|
158
163
|
|
|
159
164
|
#remap the box to get the correct pressure
|
calphy/helpers.py
CHANGED
|
@@ -22,16 +22,17 @@ sarath.menon@ruhr-uni-bochum.de/yury.lysogorskiy@icams.rub.de
|
|
|
22
22
|
"""
|
|
23
23
|
|
|
24
24
|
import os
|
|
25
|
-
|
|
25
|
+
import shutil
|
|
26
|
+
import warnings
|
|
26
27
|
import logging
|
|
27
28
|
import numpy as np
|
|
29
|
+
|
|
30
|
+
from pylammpsmpi import LammpsLibrary
|
|
28
31
|
from lammps import lammps
|
|
29
|
-
import calphy.lattice as pl
|
|
30
|
-
import shutil
|
|
31
|
-
import pyscal.core as pc
|
|
32
32
|
from ase.io import read, write
|
|
33
|
-
|
|
34
|
-
import
|
|
33
|
+
|
|
34
|
+
import pyscal3.core as pc
|
|
35
|
+
from pyscal3.trajectory import Trajectory
|
|
35
36
|
|
|
36
37
|
class LammpsScript:
|
|
37
38
|
def __init__(self):
|
|
@@ -117,19 +118,13 @@ def create_structure(lmp, calc):
|
|
|
117
118
|
return lmp
|
|
118
119
|
|
|
119
120
|
|
|
120
|
-
def set_mass(lmp, options
|
|
121
|
-
count = 1
|
|
121
|
+
def set_mass(lmp, options):
|
|
122
122
|
for i in range(options.n_elements):
|
|
123
123
|
lmp.command(f'mass {i+1} {options.mass[i]}')
|
|
124
|
-
count += 1
|
|
125
|
-
|
|
126
|
-
for i in range(ghost_elements):
|
|
127
|
-
lmp.command(f'mass {count+i} 1.00')
|
|
128
|
-
|
|
129
124
|
return lmp
|
|
130
125
|
|
|
131
126
|
|
|
132
|
-
def set_potential(lmp, options
|
|
127
|
+
def set_potential(lmp, options):
|
|
133
128
|
"""
|
|
134
129
|
Set the interatomic potential
|
|
135
130
|
|
|
@@ -148,50 +143,14 @@ def set_potential(lmp, options, ghost_elements=0):
|
|
|
148
143
|
lmp.command(f'pair_style {options._pair_style_with_options[0]}')
|
|
149
144
|
lmp.command(f'pair_coeff {options.pair_coeff[0]}')
|
|
150
145
|
|
|
151
|
-
lmp = set_mass(lmp, options
|
|
152
|
-
|
|
153
|
-
return lmp
|
|
146
|
+
lmp = set_mass(lmp, options)
|
|
154
147
|
|
|
155
|
-
|
|
156
|
-
def read_dump(lmp, file, species=1):
|
|
157
|
-
# Read atoms positions, velocities and box parameters.
|
|
158
|
-
lmp.command("lattice fcc 4.0")
|
|
159
|
-
lmp.command("region box block 0 2 0 2 0 2")
|
|
160
|
-
lmp.command("create_box %d box" % species)
|
|
161
|
-
lmp.command(
|
|
162
|
-
"read_dump %s 0 x y z vx vy vz scaled no box yes add keep" % file
|
|
163
|
-
)
|
|
164
|
-
lmp.command("change_box all triclinic")
|
|
165
148
|
return lmp
|
|
166
149
|
|
|
167
|
-
|
|
168
150
|
def read_data(lmp, file):
|
|
169
151
|
lmp.command(f"read_data {file}")
|
|
170
152
|
return lmp
|
|
171
153
|
|
|
172
|
-
|
|
173
|
-
def convert_to_data_file(inputfile, outputfile, ghost_elements=0):
|
|
174
|
-
atoms = read(inputfile, format="lammps-dump-text")
|
|
175
|
-
write(outputfile, atoms, format="lammps-data")
|
|
176
|
-
|
|
177
|
-
if ghost_elements > 0:
|
|
178
|
-
lines = []
|
|
179
|
-
with open(outputfile, "r") as fin:
|
|
180
|
-
for line in fin:
|
|
181
|
-
raw = line.strip().split()
|
|
182
|
-
if (len(raw) == 3) and (raw[2] == "types"):
|
|
183
|
-
raw[0] = "%d" % ghost_elements
|
|
184
|
-
raw.append("\n")
|
|
185
|
-
rline = " ".join(raw)
|
|
186
|
-
lines.append(rline)
|
|
187
|
-
else:
|
|
188
|
-
lines.append(line)
|
|
189
|
-
|
|
190
|
-
with open(outputfile, "w") as fout:
|
|
191
|
-
for line in lines:
|
|
192
|
-
fout.write(line)
|
|
193
|
-
|
|
194
|
-
|
|
195
154
|
def get_structures(file, species, index=None):
|
|
196
155
|
traj = Trajectory(file)
|
|
197
156
|
if index is None:
|
|
@@ -200,94 +159,6 @@ def get_structures(file, species, index=None):
|
|
|
200
159
|
aseobjs = traj[index].to_ase(species=species)
|
|
201
160
|
return aseobjs
|
|
202
161
|
|
|
203
|
-
|
|
204
|
-
def set_hybrid_potential(lmp, options, eps, ghost_elements=0):
|
|
205
|
-
pc = options.pair_coeff[0]
|
|
206
|
-
pcraw = pc.split()
|
|
207
|
-
pcnew = " ".join(
|
|
208
|
-
[
|
|
209
|
-
*pcraw[:2],
|
|
210
|
-
*[
|
|
211
|
-
options._pair_style_names[0],
|
|
212
|
-
],
|
|
213
|
-
*pcraw[2:],
|
|
214
|
-
]
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
lmp.command(
|
|
218
|
-
"pair_style hybrid/overlay %s ufm 7.5"
|
|
219
|
-
% options._pair_style_with_options[0]
|
|
220
|
-
)
|
|
221
|
-
lmp.command("pair_coeff %s" % pcnew)
|
|
222
|
-
lmp.command("pair_coeff * * ufm %f 1.5" % eps)
|
|
223
|
-
|
|
224
|
-
lmp = set_mass(lmp, options, ghost_elements=ghost_elements)
|
|
225
|
-
|
|
226
|
-
return lmp
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
def set_double_hybrid_potential(lmp, options, ghost_elements=0):
|
|
230
|
-
|
|
231
|
-
pc1 = options.pair_coeff[0]
|
|
232
|
-
pcraw1 = pc1.split()
|
|
233
|
-
|
|
234
|
-
pc2 = options.pair_coeff[1]
|
|
235
|
-
pcraw2 = pc2.split()
|
|
236
|
-
|
|
237
|
-
if options.pair_style[0] == options.pair_style[1]:
|
|
238
|
-
pcnew1 = " ".join(
|
|
239
|
-
[
|
|
240
|
-
*pcraw1[:2],
|
|
241
|
-
*[
|
|
242
|
-
options._pair_style_names[0],
|
|
243
|
-
],
|
|
244
|
-
"1",
|
|
245
|
-
*pcraw1[2:],
|
|
246
|
-
]
|
|
247
|
-
)
|
|
248
|
-
pcnew2 = " ".join(
|
|
249
|
-
[
|
|
250
|
-
*pcraw2[:2],
|
|
251
|
-
*[
|
|
252
|
-
options._pair_style_names[1],
|
|
253
|
-
],
|
|
254
|
-
"2",
|
|
255
|
-
*pcraw2[2:],
|
|
256
|
-
]
|
|
257
|
-
)
|
|
258
|
-
else:
|
|
259
|
-
pcnew1 = " ".join(
|
|
260
|
-
[
|
|
261
|
-
*pcraw1[:2],
|
|
262
|
-
*[
|
|
263
|
-
options._pair_style_names[0],
|
|
264
|
-
],
|
|
265
|
-
*pcraw1[2:],
|
|
266
|
-
]
|
|
267
|
-
)
|
|
268
|
-
pcnew2 = " ".join(
|
|
269
|
-
[
|
|
270
|
-
*pcraw2[:2],
|
|
271
|
-
*[
|
|
272
|
-
options._pair_style_names[1],
|
|
273
|
-
],
|
|
274
|
-
*pcraw2[2:],
|
|
275
|
-
]
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
lmp.command(
|
|
279
|
-
"pair_style hybrid/overlay %s %s"
|
|
280
|
-
% (options._pair_style_with_options[0], options._pair_style_with_options[1])
|
|
281
|
-
)
|
|
282
|
-
|
|
283
|
-
lmp.command("pair_coeff %s" % pcnew1)
|
|
284
|
-
lmp.command("pair_coeff %s" % pcnew2)
|
|
285
|
-
|
|
286
|
-
lmp = set_mass(lmp, options, ghost_elements=ghost_elements)
|
|
287
|
-
|
|
288
|
-
return lmp
|
|
289
|
-
|
|
290
|
-
|
|
291
162
|
def remap_box(lmp, x, y, z):
|
|
292
163
|
lmp.command("run 0")
|
|
293
164
|
lmp.command(
|
|
@@ -329,15 +200,15 @@ PYSCAL helper routines
|
|
|
329
200
|
|
|
330
201
|
|
|
331
202
|
def find_solid_fraction(file):
|
|
332
|
-
sys = pc.System()
|
|
333
|
-
sys.read_inputfile(file)
|
|
203
|
+
sys = pc.System(file)
|
|
334
204
|
try:
|
|
335
|
-
sys.
|
|
205
|
+
sys.find.neighbors(method="cutoff", cutoff=0)
|
|
336
206
|
except RuntimeError:
|
|
337
|
-
sys.
|
|
207
|
+
sys.find.neighbors(
|
|
338
208
|
method="cutoff", cutoff=5.0
|
|
339
209
|
) # Maybe add value as convergence param?
|
|
340
|
-
|
|
210
|
+
sys.find.solids(cluster=False)
|
|
211
|
+
solids = np.sum(sys.atoms.solid)
|
|
341
212
|
return solids
|
|
342
213
|
|
|
343
214
|
|
|
@@ -345,49 +216,6 @@ def write_data(lmp, file):
|
|
|
345
216
|
lmp.command(f"write_data {file}")
|
|
346
217
|
return lmp
|
|
347
218
|
|
|
348
|
-
|
|
349
|
-
def reset_timestep(conf, file="current.data", init_commands=None):
|
|
350
|
-
lmp = create_object(
|
|
351
|
-
cores=1,
|
|
352
|
-
directory=os.path.dirname(file),
|
|
353
|
-
timestep=0,
|
|
354
|
-
cmdargs=None,
|
|
355
|
-
init_commands=init_commands,
|
|
356
|
-
)
|
|
357
|
-
lmp = read_data(lmp, file)
|
|
358
|
-
lmp = write_data(lmp, conf)
|
|
359
|
-
return lmp
|
|
360
|
-
|
|
361
|
-
# with open(file, "r") as f:
|
|
362
|
-
# with open(conf, "w") as c:
|
|
363
|
-
# zero = False
|
|
364
|
-
# for l in f:
|
|
365
|
-
# if zero:
|
|
366
|
-
# c.write("0\n")
|
|
367
|
-
# zero = False
|
|
368
|
-
# continue
|
|
369
|
-
# elif l.startswith("ITEM: TIMESTEP"):
|
|
370
|
-
# zero = True
|
|
371
|
-
# c.write(l)
|
|
372
|
-
|
|
373
|
-
# lmp = create_object(
|
|
374
|
-
# cores=1,
|
|
375
|
-
# directory = os.path.dirname(file),
|
|
376
|
-
# timestep=0,
|
|
377
|
-
# cmdargs=None,
|
|
378
|
-
# )
|
|
379
|
-
# lmp.command("dump 2 all custom 1 %s id type mass x y z vx vy vz"%(file))+
|
|
380
|
-
# lmp.command("reset_timestep 0")
|
|
381
|
-
# lmp.command("run 0")
|
|
382
|
-
# lmp.command("undump 2")
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
"""
|
|
386
|
-
NOrmal helper routines
|
|
387
|
-
---------------------------------------------------------------------
|
|
388
|
-
"""
|
|
389
|
-
|
|
390
|
-
|
|
391
219
|
def prepare_log(file, screen=False):
|
|
392
220
|
logger = logging.getLogger(__name__)
|
|
393
221
|
handler = logging.FileHandler(file)
|
calphy/input.py
CHANGED
|
@@ -58,10 +58,27 @@ def _check_equal(val):
|
|
|
58
58
|
return False
|
|
59
59
|
return True
|
|
60
60
|
|
|
61
|
-
|
|
62
61
|
def to_list(v: Any) -> List[Any]:
|
|
63
62
|
return np.atleast_1d(v)
|
|
64
63
|
|
|
64
|
+
def _to_str(val):
|
|
65
|
+
if np.isscalar(val):
|
|
66
|
+
return str(val)
|
|
67
|
+
else:
|
|
68
|
+
return [str(x) for x in val]
|
|
69
|
+
|
|
70
|
+
def _to_int(val):
|
|
71
|
+
if np.isscalar(val):
|
|
72
|
+
return int(val)
|
|
73
|
+
else:
|
|
74
|
+
return [int(x) for x in val]
|
|
75
|
+
|
|
76
|
+
def _to_float(val):
|
|
77
|
+
if np.isscalar(val):
|
|
78
|
+
return float(val)
|
|
79
|
+
else:
|
|
80
|
+
return [float(x) for x in val]
|
|
81
|
+
|
|
65
82
|
class CompositionScaling(BaseModel, title='Composition scaling input options'):
|
|
66
83
|
_input_chemical_composition: PrivateAttr(default=None)
|
|
67
84
|
output_chemical_composition: Annotated[dict, Field(default=None, required=False)]
|
|
@@ -185,7 +202,6 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
185
202
|
|
|
186
203
|
#add second level options; for example spring constants
|
|
187
204
|
spring_constants: Annotated[List[float], Field(default = None)]
|
|
188
|
-
_ghost_element_count: int = PrivateAttr(default=0)
|
|
189
205
|
|
|
190
206
|
#structure items
|
|
191
207
|
_structure: Any = PrivateAttr(default=None)
|
|
@@ -312,6 +328,7 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
312
328
|
self._element_dict[element]['mass'] = self.mass[count]
|
|
313
329
|
self._element_dict[element]['count'] = 0
|
|
314
330
|
self._element_dict[element]['composition'] = 0.0
|
|
331
|
+
self._element_dict[element]['atomic_number'] = mendeleev.element(element).atomic_number
|
|
315
332
|
|
|
316
333
|
#generate temporary filename if needed
|
|
317
334
|
write_structure_file = False
|
|
@@ -319,7 +336,7 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
319
336
|
if self.lattice == "":
|
|
320
337
|
#fetch from dict
|
|
321
338
|
if len(self.element) > 1:
|
|
322
|
-
raise ValueError("Cannot create lattice for more than one element")
|
|
339
|
+
raise ValueError("Cannot create lattice for more than one element, provide a lammps-data file explicitly")
|
|
323
340
|
if self.element[0] in element_dict.keys():
|
|
324
341
|
self.lattice = element_dict[self.element[0]]['structure']
|
|
325
342
|
self.lattice_constant = element_dict[self.element[0]]['lattice_constant']
|
|
@@ -333,20 +350,23 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
333
350
|
lattice_constant=self.lattice_constant,
|
|
334
351
|
repetitions=self.repeat,
|
|
335
352
|
element=self.element)
|
|
353
|
+
structure = structure.write.ase()
|
|
336
354
|
|
|
337
355
|
#extract composition
|
|
338
|
-
|
|
339
|
-
types, typecounts = np.unique(typelist, return_counts=True)
|
|
356
|
+
types, typecounts = np.unique(structure.get_chemical_symbols(), return_counts=True)
|
|
340
357
|
|
|
341
358
|
for c, t in enumerate(types):
|
|
342
359
|
self._element_dict[t]['count'] = typecounts[c]
|
|
343
360
|
self._element_dict[t]['composition'] = typecounts[c]/np.sum(typecounts)
|
|
344
361
|
|
|
345
|
-
self._natoms = structure
|
|
362
|
+
self._natoms = len(structure)
|
|
346
363
|
self._original_lattice = self.lattice.lower()
|
|
347
364
|
write_structure_file = True
|
|
348
365
|
|
|
349
366
|
elif self.lattice.lower() in structure_dict.keys():
|
|
367
|
+
if len(self.element) > 1:
|
|
368
|
+
raise ValueError("Cannot create lattice for more than one element, provide a lammps-data file explicitly")
|
|
369
|
+
|
|
350
370
|
#this is a valid structure
|
|
351
371
|
if self.lattice_constant == 0:
|
|
352
372
|
#we try try to get lattice_constant
|
|
@@ -359,10 +379,10 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
359
379
|
lattice_constant=self.lattice_constant,
|
|
360
380
|
repetitions=self.repeat,
|
|
361
381
|
element=self.element)
|
|
382
|
+
structure = structure.write.ase()
|
|
362
383
|
|
|
363
384
|
#extract composition
|
|
364
|
-
|
|
365
|
-
types, typecounts = np.unique(typelist, return_counts=True)
|
|
385
|
+
types, typecounts = np.unique(structure.get_chemical_symbols(), return_counts=True)
|
|
366
386
|
|
|
367
387
|
for c, t in enumerate(types):
|
|
368
388
|
self._element_dict[t]['count'] = typecounts[c]
|
|
@@ -372,7 +392,7 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
372
392
|
#concdict_frac = {str(t): typecounts[c]/np.sum(typecounts) for c, t in enumerate(types)}
|
|
373
393
|
#self._composition = concdict_frac
|
|
374
394
|
#self._composition_counts = concdict_counts
|
|
375
|
-
self._natoms = structure
|
|
395
|
+
self._natoms = len(structure)
|
|
376
396
|
self._original_lattice = self.lattice.lower()
|
|
377
397
|
write_structure_file = True
|
|
378
398
|
|
|
@@ -381,20 +401,21 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
381
401
|
if not os.path.exists(self.lattice):
|
|
382
402
|
raise ValueError(f'File {self.lattice} could not be found')
|
|
383
403
|
if self.file_format == 'lammps-data':
|
|
384
|
-
|
|
385
|
-
|
|
404
|
+
#create atomic numbers for proper reading
|
|
405
|
+
Z_of_type = dict([(count+1, self._element_dict[element]['atomic_number']) for count, element in enumerate(self.element)])
|
|
406
|
+
structure = read(self.lattice, format='lammps-data', style='atomic', Z_of_type=Z_of_type)
|
|
407
|
+
#structure = System(aseobj, format='ase')
|
|
386
408
|
else:
|
|
387
409
|
raise TypeError('Only lammps-data files are supported!')
|
|
388
410
|
|
|
389
411
|
#extract composition
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
typelist = [self.element[x-1] for x in typelist]
|
|
393
|
-
types, typecounts = np.unique(typelist, return_counts=True)
|
|
412
|
+
#this is the types read in from the file
|
|
413
|
+
types, typecounts = np.unique(structure.get_chemical_symbols(), return_counts=True)
|
|
394
414
|
for c, t in enumerate(types):
|
|
395
415
|
self._element_dict[t]['count'] = typecounts[c]
|
|
396
416
|
self._element_dict[t]['composition'] = typecounts[c]/np.sum(typecounts)
|
|
397
|
-
|
|
417
|
+
|
|
418
|
+
self._natoms = len(structure)
|
|
398
419
|
self._original_lattice = os.path.basename(self.lattice)
|
|
399
420
|
self.lattice = os.path.abspath(self.lattice)
|
|
400
421
|
|
|
@@ -402,13 +423,10 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
402
423
|
if write_structure_file:
|
|
403
424
|
structure_filename = ".".join([self.create_identifier(), str(self.kernel), "data"])
|
|
404
425
|
structure_filename = os.path.join(os.getcwd(), structure_filename)
|
|
405
|
-
|
|
426
|
+
write(structure_filename, structure, format='lammps-data')
|
|
406
427
|
self.lattice = structure_filename
|
|
407
428
|
|
|
408
429
|
if self.mode == 'composition_scaling':
|
|
409
|
-
aseobj = read(self.lattice, format='lammps-data', style='atomic')
|
|
410
|
-
structure = System(aseobj, format='ase')
|
|
411
|
-
|
|
412
430
|
#we also should check if actual contents are present
|
|
413
431
|
input_chem_comp = {}
|
|
414
432
|
for key, val in self._element_dict.items():
|
|
@@ -422,7 +440,7 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
422
440
|
|
|
423
441
|
natoms1 = np.sum([val for key, val in self.composition_scaling._input_chemical_composition.items()])
|
|
424
442
|
natoms2 = np.sum([val for key, val in self.composition_scaling.output_chemical_composition.items()])
|
|
425
|
-
if not (natoms1==natoms2
|
|
443
|
+
if not (natoms1==natoms2):
|
|
426
444
|
raise ValueError(f"Input and output number of atoms are not conserved! Input {self.dict_to_string(self.input_chemical_composition)}, output {self.dict_to_string(self.output_chemical_composition)}, total atoms in structure {structure.natoms}")
|
|
427
445
|
return self
|
|
428
446
|
|
|
@@ -517,13 +535,6 @@ def load_job(filename):
|
|
|
517
535
|
job = np.load(filename, allow_pickle=True).flatten()[0]
|
|
518
536
|
return job
|
|
519
537
|
|
|
520
|
-
def check_dict(indict, key, retval=None):
|
|
521
|
-
if key in indict.items():
|
|
522
|
-
return indict[key]
|
|
523
|
-
else:
|
|
524
|
-
return retval
|
|
525
|
-
|
|
526
|
-
|
|
527
538
|
def read_inputfile(file):
|
|
528
539
|
if not os.path.exists(file):
|
|
529
540
|
raise FileNotFoundError(f'Input file {file} not found.')
|
|
@@ -645,23 +656,4 @@ def _convert_legacy_inputfile(file, return_calcs=False):
|
|
|
645
656
|
warnings.warn(f'Old style input file calphy < v2 found. Converted input in {outfile}. Please check!')
|
|
646
657
|
with open(outfile, 'w') as fout:
|
|
647
658
|
yaml.safe_dump(newdata, fout)
|
|
648
|
-
return outfile
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
def _to_str(val):
|
|
652
|
-
if np.isscalar(val):
|
|
653
|
-
return str(val)
|
|
654
|
-
else:
|
|
655
|
-
return [str(x) for x in val]
|
|
656
|
-
|
|
657
|
-
def _to_int(val):
|
|
658
|
-
if np.isscalar(val):
|
|
659
|
-
return int(val)
|
|
660
|
-
else:
|
|
661
|
-
return [int(x) for x in val]
|
|
662
|
-
|
|
663
|
-
def _to_float(val):
|
|
664
|
-
if np.isscalar(val):
|
|
665
|
-
return float(val)
|
|
666
|
-
else:
|
|
667
|
-
return [float(x) for x in val]
|
|
659
|
+
return outfile
|
calphy/integrators.py
CHANGED
|
@@ -30,7 +30,7 @@ import warnings
|
|
|
30
30
|
from calphy.splines import splines, sum_spline1, sum_spline25, sum_spline50, sum_spline75, sum_spline100
|
|
31
31
|
from scipy.integrate import cumtrapz
|
|
32
32
|
from tqdm import tqdm
|
|
33
|
-
import
|
|
33
|
+
import pyscal3.core as pc
|
|
34
34
|
from ase.io import read
|
|
35
35
|
|
|
36
36
|
#Constants
|
|
@@ -46,10 +46,12 @@ eV2J = const.eV
|
|
|
46
46
|
# TI PATH INTEGRATION ROUTINES
|
|
47
47
|
#--------------------------------------------------------------------
|
|
48
48
|
|
|
49
|
-
def integrate_path(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
def integrate_path(calc,
|
|
50
|
+
fwdfilename,
|
|
51
|
+
bkdfilename,
|
|
52
|
+
solid=True,
|
|
53
|
+
alchemy=False,
|
|
54
|
+
composition_integration=False):
|
|
53
55
|
"""
|
|
54
56
|
Get a filename with columns du and dlambda and integrate
|
|
55
57
|
|
|
@@ -72,23 +74,36 @@ def integrate_path(fwdfilename, bkdfilename,
|
|
|
72
74
|
q : float
|
|
73
75
|
heat dissipation during switching of system
|
|
74
76
|
"""
|
|
77
|
+
natoms = np.array([calc._element_dict[x]['count'] for x in calc.element])
|
|
78
|
+
concentration = np.array([calc._element_dict[x]['composition'] for x in calc.element])
|
|
79
|
+
fdata = np.loadtxt(fwdfilename, unpack=True, comments="#")
|
|
80
|
+
bdata = np.loadtxt(bkdfilename, unpack=True, comments="#")
|
|
81
|
+
|
|
75
82
|
if solid:
|
|
76
|
-
fdui =
|
|
77
|
-
bdui =
|
|
83
|
+
fdui = fdata[0]
|
|
84
|
+
bdui = bdata[0]
|
|
78
85
|
|
|
79
86
|
fdur = np.zeros(len(fdui))
|
|
80
87
|
bdur = np.zeros(len(bdui))
|
|
81
88
|
|
|
82
|
-
for i in range(
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
for i in range(calc.n_elements):
|
|
90
|
+
if natoms[i] > 0:
|
|
91
|
+
fdur += concentration[i]*fdata[i+1]/natoms[i]
|
|
92
|
+
bdur += concentration[i]*bdata[i+1]/natoms[i]
|
|
85
93
|
|
|
86
|
-
flambda =
|
|
87
|
-
blambda =
|
|
94
|
+
flambda = fdata[calc.n_elements+1]
|
|
95
|
+
blambda = bdata[calc.n_elements+1]
|
|
88
96
|
|
|
89
97
|
else:
|
|
90
|
-
fdui
|
|
91
|
-
bdui
|
|
98
|
+
fdui = fdata[0]
|
|
99
|
+
bdui = bdata[0]
|
|
100
|
+
|
|
101
|
+
fdur = fdata[1]
|
|
102
|
+
bdur = bdata[1]
|
|
103
|
+
|
|
104
|
+
flambda = fdata[2]
|
|
105
|
+
blambda = bdata[2]
|
|
106
|
+
|
|
92
107
|
|
|
93
108
|
fdu = fdui - fdur
|
|
94
109
|
bdu = bdui - bdur
|
|
@@ -106,11 +121,12 @@ def integrate_path(fwdfilename, bkdfilename,
|
|
|
106
121
|
return w, q, flambda
|
|
107
122
|
|
|
108
123
|
|
|
109
|
-
def find_w(mainfolder,
|
|
110
|
-
|
|
111
|
-
full=False,
|
|
124
|
+
def find_w(mainfolder,
|
|
125
|
+
calc,
|
|
126
|
+
full=False,
|
|
112
127
|
solid=True,
|
|
113
|
-
alchemy=False,
|
|
128
|
+
alchemy=False,
|
|
129
|
+
composition_integration=False):
|
|
114
130
|
"""
|
|
115
131
|
Integrate the irreversible work and dissipation for independent simulations
|
|
116
132
|
|
|
@@ -142,15 +158,20 @@ def find_w(mainfolder, nelements=1,
|
|
|
142
158
|
ws = []
|
|
143
159
|
qs = []
|
|
144
160
|
|
|
145
|
-
for i in range(
|
|
161
|
+
for i in range(calc.n_iterations):
|
|
146
162
|
fwdfilestring = 'forward_%d.dat' % (i+1)
|
|
147
163
|
fwdfilename = os.path.join(mainfolder,fwdfilestring)
|
|
164
|
+
|
|
148
165
|
bkdfilestring = 'backward_%d.dat' % (i+1)
|
|
149
166
|
bkdfilename = os.path.join(mainfolder,bkdfilestring)
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
167
|
+
|
|
168
|
+
w, q, flambda = integrate_path(calc,
|
|
169
|
+
fwdfilename,
|
|
170
|
+
bkdfilename,
|
|
171
|
+
solid=solid,
|
|
172
|
+
alchemy=alchemy,
|
|
173
|
+
composition_integration=composition_integration)
|
|
174
|
+
|
|
154
175
|
ws.append(w)
|
|
155
176
|
qs.append(q)
|
|
156
177
|
|
|
@@ -356,12 +377,10 @@ def integrate_dcc(folder1, folder2, nsims=1, scale_energy=True,
|
|
|
356
377
|
"""
|
|
357
378
|
|
|
358
379
|
#get number of atoms
|
|
359
|
-
sys = pc.System()
|
|
360
|
-
sys.read_inputfile(os.path.join(folder1, "traj.equilibration_stage1.dat"))
|
|
380
|
+
sys = pc.System(os.path.join(folder1, "traj.equilibration_stage1.dat"))
|
|
361
381
|
natoms1 = int(sys.natoms)
|
|
362
382
|
|
|
363
|
-
sys = pc.System()
|
|
364
|
-
sys.read_inputfile(os.path.join(folder2, "traj.equilibration_stage1.dat"))
|
|
383
|
+
sys = pc.System(os.path.join(folder2, "traj.equilibration_stage1.dat"))
|
|
365
384
|
natoms2 = int(sys.natoms)
|
|
366
385
|
|
|
367
386
|
#get temp and pressure
|
|
@@ -446,7 +465,11 @@ def integrate_dcc(folder1, folder2, nsims=1, scale_energy=True,
|
|
|
446
465
|
# REF. STATE ROUTINES: SOLID
|
|
447
466
|
#--------------------------------------------------------------------
|
|
448
467
|
|
|
449
|
-
def get_einstein_crystal_fe(
|
|
468
|
+
def get_einstein_crystal_fe(
|
|
469
|
+
calc,
|
|
470
|
+
vol,
|
|
471
|
+
k,
|
|
472
|
+
cm_correction=True):
|
|
450
473
|
"""
|
|
451
474
|
Get the free energy of einstein crystal
|
|
452
475
|
|
|
@@ -477,7 +500,10 @@ def get_einstein_crystal_fe(temp, natoms, mass, vol, k, concentration, cm_correc
|
|
|
477
500
|
|
|
478
501
|
"""
|
|
479
502
|
#convert mass first for single particle in kg
|
|
480
|
-
mass =
|
|
503
|
+
mass = np.array([calc._element_dict[x]['mass'] for x in calc.element])
|
|
504
|
+
mass = (mass/Na)*1E-3
|
|
505
|
+
natoms = np.sum([calc._element_dict[x]['count'] for x in calc.element])
|
|
506
|
+
concentration = np.array([calc._element_dict[x]['composition'] for x in calc.element])
|
|
481
507
|
|
|
482
508
|
#convert k from ev/A2 to J/m2
|
|
483
509
|
k = np.array(k)*(eV2J/1E-20)
|
|
@@ -490,12 +516,13 @@ def get_einstein_crystal_fe(temp, natoms, mass, vol, k, concentration, cm_correc
|
|
|
490
516
|
F_cm = 0
|
|
491
517
|
|
|
492
518
|
for count, om in enumerate(omega):
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
519
|
+
if concentration[count] > 0:
|
|
520
|
+
F_harm += concentration[count]*np.log((hbar*om)/(kb*calc._temperature))
|
|
521
|
+
if cm_correction:
|
|
522
|
+
F_cm += np.log((natoms*concentration[count]/vol)*(2*np.pi*kbJ*calc._temperature/(natoms*concentration[count]*k[count]))**1.5)
|
|
496
523
|
#F_cm = 0
|
|
497
|
-
F_harm = 3*kb*
|
|
498
|
-
F_cm = (kb*
|
|
524
|
+
F_harm = 3*kb*calc._temperature*F_harm
|
|
525
|
+
F_cm = (kb*calc._temperature/natoms)*F_cm
|
|
499
526
|
|
|
500
527
|
F_harm = F_harm + F_cm
|
|
501
528
|
|