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/inputbk.py
DELETED
|
@@ -1,862 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
calphy: a Python library and command line interface for automated free
|
|
3
|
-
energy calculations.
|
|
4
|
-
|
|
5
|
-
Copyright 2021 (c) Sarath Menon^1, Yury Lysogorskiy^2, Ralf Drautz^2
|
|
6
|
-
^1: Max Planck Institut für Eisenforschung, Dusseldorf, Germany
|
|
7
|
-
^2: Ruhr-University Bochum, Bochum, Germany
|
|
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.
|
|
12
|
-
calphy API is published and distributed under the BSD 3-Clause "New" or "Revised" License
|
|
13
|
-
See the LICENSE FILE for more details.
|
|
14
|
-
|
|
15
|
-
More information about the program can be found in:
|
|
16
|
-
Menon, Sarath, Yury Lysogorskiy, Jutta Rogal, and Ralf Drautz.
|
|
17
|
-
“Automated Free Energy Calculation from Atomistic Simulations.” Physical Review Materials 5(10), 2021
|
|
18
|
-
DOI: 10.1103/PhysRevMaterials.5.103801
|
|
19
|
-
|
|
20
|
-
For more information contact:
|
|
21
|
-
sarath.menon@ruhr-uni-bochum.de/yury.lysogorskiy@icams.rub.de
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
import os
|
|
25
|
-
import yaml
|
|
26
|
-
import warnings
|
|
27
|
-
import copy
|
|
28
|
-
import yaml
|
|
29
|
-
import itertools
|
|
30
|
-
import shutil
|
|
31
|
-
import numpy as np
|
|
32
|
-
import datetime
|
|
33
|
-
|
|
34
|
-
def read_report(folder):
|
|
35
|
-
"""
|
|
36
|
-
Read the finished calculation report
|
|
37
|
-
"""
|
|
38
|
-
repfile = os.path.join(folder, "report.yaml")
|
|
39
|
-
if not os.path.exists(repfile):
|
|
40
|
-
raise FileNotFoundError(f"file {repfile} not found")
|
|
41
|
-
|
|
42
|
-
with open(repfile, 'r') as fin:
|
|
43
|
-
data = yaml.safe_load(fin)
|
|
44
|
-
return data
|
|
45
|
-
|
|
46
|
-
class InputTemplate:
|
|
47
|
-
def __init__(self):
|
|
48
|
-
pass
|
|
49
|
-
|
|
50
|
-
def add_from_dict(self, indict, keys=None):
|
|
51
|
-
if keys is None:
|
|
52
|
-
for key, val in indict.items():
|
|
53
|
-
setattr(self, key, val)
|
|
54
|
-
elif isinstance(keys, list):
|
|
55
|
-
for key, val in indict.items():
|
|
56
|
-
if key in keys:
|
|
57
|
-
setattr(self, key, val)
|
|
58
|
-
|
|
59
|
-
def from_dict(self, indict):
|
|
60
|
-
for key, val in indict.items():
|
|
61
|
-
if isinstance(val, dict):
|
|
62
|
-
setattr(self, key, InputTemplate())
|
|
63
|
-
getattr(self, key).from_dict(val)
|
|
64
|
-
else:
|
|
65
|
-
setattr(self, key, val)
|
|
66
|
-
|
|
67
|
-
def to_dict(self):
|
|
68
|
-
tdict = copy.deepcopy(self.__dict__)
|
|
69
|
-
for key, val in tdict.items():
|
|
70
|
-
if isinstance(val, InputTemplate):
|
|
71
|
-
tdict[key] = val.to_dict()
|
|
72
|
-
return tdict
|
|
73
|
-
|
|
74
|
-
def check_and_convert_to_list(self, data, check_none=False):
|
|
75
|
-
"""
|
|
76
|
-
Check if the given item is a list, if not convert to a single item list
|
|
77
|
-
"""
|
|
78
|
-
if not isinstance(data, list):
|
|
79
|
-
data = [data]
|
|
80
|
-
|
|
81
|
-
if check_none:
|
|
82
|
-
data = [None if x=="None" else x for x in data]
|
|
83
|
-
|
|
84
|
-
return data
|
|
85
|
-
|
|
86
|
-
@staticmethod
|
|
87
|
-
def convert_to_list(data, check_none=False):
|
|
88
|
-
"""
|
|
89
|
-
Check if the given item is a list, if not convert to a single item list
|
|
90
|
-
"""
|
|
91
|
-
if not isinstance(data, list):
|
|
92
|
-
data = [data]
|
|
93
|
-
|
|
94
|
-
if check_none:
|
|
95
|
-
data = [None if x=="None" else x for x in data]
|
|
96
|
-
|
|
97
|
-
return data
|
|
98
|
-
|
|
99
|
-
def merge_dicts(self, dicts):
|
|
100
|
-
"""
|
|
101
|
-
Merge dicts from a given list
|
|
102
|
-
"""
|
|
103
|
-
merged_dict = {}
|
|
104
|
-
for d in dicts:
|
|
105
|
-
for key, val in d.items():
|
|
106
|
-
merged_dict[key] = val
|
|
107
|
-
return merged_dict
|
|
108
|
-
|
|
109
|
-
class CompositionScaling(InputTemplate):
|
|
110
|
-
def __init__(self):
|
|
111
|
-
self._input_chemical_composition = None
|
|
112
|
-
self._output_chemical_composition = None
|
|
113
|
-
self._restrictions = None
|
|
114
|
-
|
|
115
|
-
@property
|
|
116
|
-
def input_chemical_composition(self):
|
|
117
|
-
return self._input_chemical_composition
|
|
118
|
-
|
|
119
|
-
@input_chemical_composition.setter
|
|
120
|
-
def input_chemical_composition(self, val):
|
|
121
|
-
if isinstance(val, list):
|
|
122
|
-
val = self.merge_dicts(val)
|
|
123
|
-
self._input_chemical_composition = val
|
|
124
|
-
|
|
125
|
-
@property
|
|
126
|
-
def output_chemical_composition(self):
|
|
127
|
-
return self._output_chemical_composition
|
|
128
|
-
|
|
129
|
-
@output_chemical_composition.setter
|
|
130
|
-
def output_chemical_composition(self, val):
|
|
131
|
-
if isinstance(val, list):
|
|
132
|
-
val = self.merge_dicts(val)
|
|
133
|
-
self._output_chemical_composition = val
|
|
134
|
-
|
|
135
|
-
@property
|
|
136
|
-
def restrictions(self):
|
|
137
|
-
return self._restrictions
|
|
138
|
-
|
|
139
|
-
@restrictions.setter
|
|
140
|
-
def restrictions(self, val):
|
|
141
|
-
self._restrictions = self.check_and_convert_to_list(val)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
class Calculation(InputTemplate):
|
|
145
|
-
def __init__(self):
|
|
146
|
-
super(InputTemplate, self).__init__()
|
|
147
|
-
self._element = None
|
|
148
|
-
self._n_elements = 0
|
|
149
|
-
self._mass = 1.0
|
|
150
|
-
self._mode = None
|
|
151
|
-
self._lattice = None
|
|
152
|
-
self._pressure = 0
|
|
153
|
-
self._pressure_stop = 0
|
|
154
|
-
self._pressure_input = None
|
|
155
|
-
self._temperature = None
|
|
156
|
-
self._temperature_stop = None
|
|
157
|
-
self._temperature_high = None
|
|
158
|
-
self._temperature_input = None
|
|
159
|
-
self._iso = False
|
|
160
|
-
self._fix_lattice = False
|
|
161
|
-
self._melting_cycle = True
|
|
162
|
-
self._pair_style = None
|
|
163
|
-
self._pair_style_options = None
|
|
164
|
-
self._pair_coeff = None
|
|
165
|
-
self._potential_file = None
|
|
166
|
-
self._fix_potential_path = True
|
|
167
|
-
self._reference_phase = None
|
|
168
|
-
self._lattice_constant = 0
|
|
169
|
-
self._repeat = [1, 1, 1]
|
|
170
|
-
self._script_mode = False
|
|
171
|
-
self._lammps_executable = None
|
|
172
|
-
self._mpi_executable = None
|
|
173
|
-
self._npt = True
|
|
174
|
-
self._n_equilibration_steps = 25000
|
|
175
|
-
self._n_switching_steps = 50000
|
|
176
|
-
self._n_sweep_steps = 50000
|
|
177
|
-
self._n_print_steps = 0
|
|
178
|
-
self._n_iterations = 1
|
|
179
|
-
self._equilibration_control = None
|
|
180
|
-
self._folder_prefix = None
|
|
181
|
-
|
|
182
|
-
#add second level options; for example spring constants
|
|
183
|
-
self._spring_constants = None
|
|
184
|
-
self._ghost_element_count = 0
|
|
185
|
-
|
|
186
|
-
self.md = InputTemplate()
|
|
187
|
-
self.md.timestep = 0.001
|
|
188
|
-
self.md.n_small_steps = 10000
|
|
189
|
-
self.md.n_every_steps = 10
|
|
190
|
-
self.md.n_repeat_steps = 10
|
|
191
|
-
self.md.n_cycles = 100
|
|
192
|
-
self.md.thermostat_damping = 0.1
|
|
193
|
-
self.md.barostat_damping = 0.1
|
|
194
|
-
self.md.cmdargs = None
|
|
195
|
-
self.md.init_commands = None
|
|
196
|
-
|
|
197
|
-
self.nose_hoover = InputTemplate()
|
|
198
|
-
self.nose_hoover.thermostat_damping = 0.1
|
|
199
|
-
self.nose_hoover.barostat_damping = 0.1
|
|
200
|
-
|
|
201
|
-
self.berendsen = InputTemplate()
|
|
202
|
-
self.berendsen.thermostat_damping = 100.0
|
|
203
|
-
self.berendsen.barostat_damping = 100.0
|
|
204
|
-
|
|
205
|
-
self.queue = InputTemplate()
|
|
206
|
-
self.queue.scheduler = "local"
|
|
207
|
-
self.queue.cores = 1
|
|
208
|
-
self.queue.jobname = "calphy"
|
|
209
|
-
self.queue.walltime = None
|
|
210
|
-
self.queue.queuename = None
|
|
211
|
-
self.queue.memory = "3GB"
|
|
212
|
-
self.queue.commands = None
|
|
213
|
-
self.queue.options = None
|
|
214
|
-
self.queue.modules = None
|
|
215
|
-
|
|
216
|
-
self.tolerance = InputTemplate()
|
|
217
|
-
self.tolerance.lattice_constant = 0.0002
|
|
218
|
-
self.tolerance.spring_constant = 0.1
|
|
219
|
-
self.tolerance.solid_fraction = 0.7
|
|
220
|
-
self.tolerance.liquid_fraction = 0.05
|
|
221
|
-
self.tolerance.pressure = 0.5
|
|
222
|
-
|
|
223
|
-
#specific input options
|
|
224
|
-
self.melting_temperature = InputTemplate()
|
|
225
|
-
self.melting_temperature.guess = None
|
|
226
|
-
self.melting_temperature.step = 200
|
|
227
|
-
self.melting_temperature.attempts = 5
|
|
228
|
-
|
|
229
|
-
#new mode for composition trf
|
|
230
|
-
self.composition_scaling = CompositionScaling()
|
|
231
|
-
|
|
232
|
-
def __repr__(self):
|
|
233
|
-
"""
|
|
234
|
-
String of the class
|
|
235
|
-
"""
|
|
236
|
-
data = "%s system with T=%s, P=%s in %s lattice for mode %s"%(self.to_string(self.reference_phase),
|
|
237
|
-
self.to_string(self._temperature), self.to_string(self._pressure), self.to_string(self.lattice), self.to_string(self.mode))
|
|
238
|
-
return data
|
|
239
|
-
|
|
240
|
-
def _repr_json_(self):
|
|
241
|
-
return self.to_dict()
|
|
242
|
-
|
|
243
|
-
def to_string(self, val):
|
|
244
|
-
if val is None:
|
|
245
|
-
return "None"
|
|
246
|
-
else:
|
|
247
|
-
return str(val)
|
|
248
|
-
|
|
249
|
-
def to_bool(self, val):
|
|
250
|
-
if val in ["True", "true", 1, "1", True]:
|
|
251
|
-
return True
|
|
252
|
-
elif val in ["False", "false", 0, "0", False]:
|
|
253
|
-
return False
|
|
254
|
-
else:
|
|
255
|
-
raise ValueError(f'Unknown bool input of type {type(val)} with value {val}')
|
|
256
|
-
|
|
257
|
-
@property
|
|
258
|
-
def element(self):
|
|
259
|
-
return self._element
|
|
260
|
-
|
|
261
|
-
@element.setter
|
|
262
|
-
def element(self, val):
|
|
263
|
-
val = self.check_and_convert_to_list(val)
|
|
264
|
-
self._n_elements = len(val)
|
|
265
|
-
self._element = val
|
|
266
|
-
|
|
267
|
-
@property
|
|
268
|
-
def n_elements(self):
|
|
269
|
-
return self._n_elements
|
|
270
|
-
|
|
271
|
-
@property
|
|
272
|
-
def mass(self):
|
|
273
|
-
return self._mass
|
|
274
|
-
|
|
275
|
-
@mass.setter
|
|
276
|
-
def mass(self, val):
|
|
277
|
-
val = self.check_and_convert_to_list(val)
|
|
278
|
-
if self.element is not None:
|
|
279
|
-
if not len(self.element) == len(val):
|
|
280
|
-
raise ValueError("Elements and mass must have same length")
|
|
281
|
-
self._mass = val
|
|
282
|
-
|
|
283
|
-
@property
|
|
284
|
-
def mode(self):
|
|
285
|
-
return self._mode
|
|
286
|
-
|
|
287
|
-
@mode.setter
|
|
288
|
-
def mode(self, val):
|
|
289
|
-
#add check
|
|
290
|
-
self._mode = val
|
|
291
|
-
if val == "melting_temperature":
|
|
292
|
-
self.temperature = 0
|
|
293
|
-
self.pressure = 0
|
|
294
|
-
|
|
295
|
-
@property
|
|
296
|
-
def lattice(self):
|
|
297
|
-
return self._lattice
|
|
298
|
-
|
|
299
|
-
@lattice.setter
|
|
300
|
-
def lattice(self, val):
|
|
301
|
-
self._lattice = val
|
|
302
|
-
|
|
303
|
-
@property
|
|
304
|
-
def pressure(self):
|
|
305
|
-
return self._pressure_input
|
|
306
|
-
|
|
307
|
-
@pressure.setter
|
|
308
|
-
def pressure(self, val):
|
|
309
|
-
"""
|
|
310
|
-
Pressure input can be of many diff types:
|
|
311
|
-
Input iso fix_lattice Mode add. constraints
|
|
312
|
-
1. None True True any No
|
|
313
|
-
2. scalar True False any No
|
|
314
|
-
3. list of scalar len 1 True False any No
|
|
315
|
-
4. list of scalar len 2 True False ps No
|
|
316
|
-
5. list of scalar len 3 False False any All terms equal
|
|
317
|
-
6. list of list len 1x3 False False any Each inner term equal
|
|
318
|
-
7. list of list len 2x3 False False ps Each inner term equal
|
|
319
|
-
"""
|
|
320
|
-
def _check_equal(val):
|
|
321
|
-
if not (val[0]==val[1]==val[2]):
|
|
322
|
-
return False
|
|
323
|
-
return True
|
|
324
|
-
|
|
325
|
-
self._pressure_input = val
|
|
326
|
-
|
|
327
|
-
error_message = "Available pressure types are of shape: None, 1, 3, (1x1), (2x1), (3x1), (2x3)"
|
|
328
|
-
# Case: 1
|
|
329
|
-
if val is None:
|
|
330
|
-
self._iso = True
|
|
331
|
-
self._fix_lattice = True
|
|
332
|
-
self._pressure = None
|
|
333
|
-
self._pressure_stop = None
|
|
334
|
-
|
|
335
|
-
# Cases: 3,4,5,6,7
|
|
336
|
-
elif isinstance(val, list):
|
|
337
|
-
shape = np.shape(val)
|
|
338
|
-
indx = shape[0]
|
|
339
|
-
indy = shape[1] if len(shape)==2 else None
|
|
340
|
-
|
|
341
|
-
if indx == 1:
|
|
342
|
-
if indy is None:
|
|
343
|
-
# Case: 3
|
|
344
|
-
self._iso = True
|
|
345
|
-
self._fix_lattice = False
|
|
346
|
-
self._pressure = val[0]
|
|
347
|
-
self._pressure_stop = val[0]
|
|
348
|
-
elif indy == 3:
|
|
349
|
-
# Case: 6
|
|
350
|
-
if _check_equal(val[0]):
|
|
351
|
-
self._iso = False
|
|
352
|
-
self._fix_lattice = False
|
|
353
|
-
self._pressure = val[0][0]
|
|
354
|
-
self._pressure_stop = val[0][0]
|
|
355
|
-
else:
|
|
356
|
-
raise NotImplementedError("Pressure should have px=py=pz")
|
|
357
|
-
else:
|
|
358
|
-
raise NotImplementedError(error_message)
|
|
359
|
-
elif indx == 2:
|
|
360
|
-
if indy is None:
|
|
361
|
-
# Case: 4
|
|
362
|
-
self._iso = True
|
|
363
|
-
self._fix_lattice = False
|
|
364
|
-
self._pressure = val[0]
|
|
365
|
-
self._pressure_stop = val[1]
|
|
366
|
-
elif indy == 3:
|
|
367
|
-
# Case: 7
|
|
368
|
-
self._iso = False
|
|
369
|
-
self._fix_lattice = False
|
|
370
|
-
if _check_equal(val[0]) and _check_equal(val[1]):
|
|
371
|
-
self._pressure = val[0][0]
|
|
372
|
-
self._pressure_stop = val[1][0]
|
|
373
|
-
else:
|
|
374
|
-
raise NotImplementedError("Pressure should have px=py=pz")
|
|
375
|
-
else:
|
|
376
|
-
raise NotImplementedError(error_message)
|
|
377
|
-
|
|
378
|
-
elif indx == 3:
|
|
379
|
-
if indy is None:
|
|
380
|
-
# Case: 5
|
|
381
|
-
if _check_equal(val):
|
|
382
|
-
self._iso = False
|
|
383
|
-
self._fix_lattice = False
|
|
384
|
-
self._pressure = val[0]
|
|
385
|
-
self._pressure_stop = val[0]
|
|
386
|
-
else:
|
|
387
|
-
raise NotImplementedError("Pressure should have px=py=pz")
|
|
388
|
-
else:
|
|
389
|
-
raise NotImplementedError(error_message)
|
|
390
|
-
else:
|
|
391
|
-
raise NotImplementedError()
|
|
392
|
-
|
|
393
|
-
# Case: 2
|
|
394
|
-
else:
|
|
395
|
-
self._pressure = val
|
|
396
|
-
self._pressure_stop = val
|
|
397
|
-
self._iso = True
|
|
398
|
-
self._fix_lattice = False
|
|
399
|
-
|
|
400
|
-
@property
|
|
401
|
-
def temperature(self):
|
|
402
|
-
return self._temperature_input
|
|
403
|
-
|
|
404
|
-
@temperature.setter
|
|
405
|
-
def temperature(self, val):
|
|
406
|
-
self._temperature_input = val
|
|
407
|
-
if val is None:
|
|
408
|
-
self._temperature = val
|
|
409
|
-
self._temperature_stop = val
|
|
410
|
-
self._temperature_high = val
|
|
411
|
-
elif isinstance(val, list):
|
|
412
|
-
if len(val) == 2:
|
|
413
|
-
self._temperature = val[0]
|
|
414
|
-
self._temperature_stop = val[1]
|
|
415
|
-
if self._temperature_high is None:
|
|
416
|
-
self._temperature_high = 2*val[1]
|
|
417
|
-
else:
|
|
418
|
-
raise ValueError("Temperature cannot have len>2")
|
|
419
|
-
else:
|
|
420
|
-
self._temperature = val
|
|
421
|
-
self._temperature_stop = val
|
|
422
|
-
if self._temperature_high is None:
|
|
423
|
-
self._temperature_high = 2*val
|
|
424
|
-
|
|
425
|
-
@property
|
|
426
|
-
def temperature_high(self):
|
|
427
|
-
return self._temperature_high
|
|
428
|
-
|
|
429
|
-
@temperature_high.setter
|
|
430
|
-
def temperature_high(self, val):
|
|
431
|
-
self._temperature_high = val
|
|
432
|
-
|
|
433
|
-
@property
|
|
434
|
-
def pair_style(self):
|
|
435
|
-
return self._pair_style
|
|
436
|
-
|
|
437
|
-
@pair_style.setter
|
|
438
|
-
def pair_style(self, val):
|
|
439
|
-
val = self.check_and_convert_to_list(val)
|
|
440
|
-
ps_lst = []
|
|
441
|
-
ps_options_lst = []
|
|
442
|
-
for ps in val:
|
|
443
|
-
ps_split = ps.split()
|
|
444
|
-
ps_lst.append(ps_split[0])
|
|
445
|
-
if len(ps) > 1:
|
|
446
|
-
ps_options_lst.append(" ".join(ps_split[1:]))
|
|
447
|
-
else:
|
|
448
|
-
ps_options_lst.append("")
|
|
449
|
-
|
|
450
|
-
#val = self.fix_paths(val)
|
|
451
|
-
self._pair_style = ps_lst
|
|
452
|
-
|
|
453
|
-
#only set if its None
|
|
454
|
-
if self.pair_style_options is None:
|
|
455
|
-
self.pair_style_options = ps_options_lst
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
@property
|
|
459
|
-
def pair_style_options(self):
|
|
460
|
-
return self._pair_style_options
|
|
461
|
-
|
|
462
|
-
@pair_style_options.setter
|
|
463
|
-
def pair_style_options(self, val):
|
|
464
|
-
val = self.check_and_convert_to_list(val)
|
|
465
|
-
self._pair_style_options = val
|
|
466
|
-
|
|
467
|
-
@property
|
|
468
|
-
def pair_style_with_options(self):
|
|
469
|
-
#ignore options if lengths do not match
|
|
470
|
-
if len(self.pair_style) != len(self.pair_style_options):
|
|
471
|
-
self.pair_style_options = [self.pair_style_options[0] for x in range(len(self.pair_style))]
|
|
472
|
-
return [" ".join([self.pair_style[i], self.pair_style_options[i]]) for i in range(len(self.pair_style))]
|
|
473
|
-
|
|
474
|
-
@property
|
|
475
|
-
def pair_coeff(self):
|
|
476
|
-
return self._pair_coeff
|
|
477
|
-
|
|
478
|
-
@pair_coeff.setter
|
|
479
|
-
def pair_coeff(self, val):
|
|
480
|
-
val = self.check_and_convert_to_list(val)
|
|
481
|
-
if self._fix_potential_path:
|
|
482
|
-
val = self.fix_paths(val)
|
|
483
|
-
self._pair_coeff = val
|
|
484
|
-
|
|
485
|
-
@property
|
|
486
|
-
def potential_file(self):
|
|
487
|
-
return self._potential_file
|
|
488
|
-
|
|
489
|
-
@potential_file.setter
|
|
490
|
-
def potential_file(self, val):
|
|
491
|
-
if os.path.exists(val):
|
|
492
|
-
self._potential_file = val
|
|
493
|
-
else:
|
|
494
|
-
raise FileNotFoundError("File %s not found"%val)
|
|
495
|
-
|
|
496
|
-
@property
|
|
497
|
-
def reference_phase(self):
|
|
498
|
-
return self._reference_phase
|
|
499
|
-
|
|
500
|
-
@reference_phase.setter
|
|
501
|
-
def reference_phase(self, val):
|
|
502
|
-
self._reference_phase = val
|
|
503
|
-
|
|
504
|
-
@property
|
|
505
|
-
def lattice_constant(self):
|
|
506
|
-
return self._lattice_constant
|
|
507
|
-
|
|
508
|
-
@lattice_constant.setter
|
|
509
|
-
def lattice_constant(self, val):
|
|
510
|
-
self._lattice_constant = val
|
|
511
|
-
|
|
512
|
-
@property
|
|
513
|
-
def repeat(self):
|
|
514
|
-
return self._repeat
|
|
515
|
-
|
|
516
|
-
@repeat.setter
|
|
517
|
-
def repeat(self, val):
|
|
518
|
-
if isinstance(val, list):
|
|
519
|
-
if not len(val) == 3:
|
|
520
|
-
raise ValueError("repeat should be three")
|
|
521
|
-
else:
|
|
522
|
-
val = [val, val, val]
|
|
523
|
-
self._repeat = val
|
|
524
|
-
|
|
525
|
-
@property
|
|
526
|
-
def npt(self):
|
|
527
|
-
return self._npt
|
|
528
|
-
|
|
529
|
-
@npt.setter
|
|
530
|
-
def npt(self, val):
|
|
531
|
-
val = self.to_bool(val)
|
|
532
|
-
if isinstance(val, bool):
|
|
533
|
-
self._npt = val
|
|
534
|
-
else:
|
|
535
|
-
raise TypeError("NPT should be either True/False")
|
|
536
|
-
|
|
537
|
-
@property
|
|
538
|
-
def script_mode(self):
|
|
539
|
-
return self._script_mode
|
|
540
|
-
|
|
541
|
-
@script_mode.setter
|
|
542
|
-
def script_mode(self, val):
|
|
543
|
-
val = self.to_bool(val)
|
|
544
|
-
if isinstance(val, bool):
|
|
545
|
-
self._script_mode = val
|
|
546
|
-
else:
|
|
547
|
-
raise TypeError("script mode should be either True/False")
|
|
548
|
-
|
|
549
|
-
@property
|
|
550
|
-
def lammps_executable(self):
|
|
551
|
-
return self._lammps_executable
|
|
552
|
-
|
|
553
|
-
@lammps_executable.setter
|
|
554
|
-
def lammps_executable(self, val):
|
|
555
|
-
self._lammps_executable = val
|
|
556
|
-
|
|
557
|
-
@property
|
|
558
|
-
def mpi_executable(self):
|
|
559
|
-
return self._mpi_executable
|
|
560
|
-
|
|
561
|
-
@mpi_executable.setter
|
|
562
|
-
def mpi_executable(self, val):
|
|
563
|
-
self._mpi_executable = val
|
|
564
|
-
|
|
565
|
-
@property
|
|
566
|
-
def n_equilibration_steps(self):
|
|
567
|
-
return self._n_equilibration_steps
|
|
568
|
-
|
|
569
|
-
@n_equilibration_steps.setter
|
|
570
|
-
def n_equilibration_steps(self, val):
|
|
571
|
-
self._n_equilibration_steps = val
|
|
572
|
-
|
|
573
|
-
@property
|
|
574
|
-
def n_switching_steps(self):
|
|
575
|
-
return self._n_switching_steps
|
|
576
|
-
|
|
577
|
-
@n_switching_steps.setter
|
|
578
|
-
def n_switching_steps(self, val):
|
|
579
|
-
if isinstance(val, list):
|
|
580
|
-
if len(val) == 2:
|
|
581
|
-
self._n_switching_steps = val[0]
|
|
582
|
-
self._n_sweep_steps = val[1]
|
|
583
|
-
else:
|
|
584
|
-
raise TypeError("n_switching_steps should be len 1 or 2")
|
|
585
|
-
else:
|
|
586
|
-
self._n_switching_steps = val
|
|
587
|
-
self._n_sweep_steps = val
|
|
588
|
-
|
|
589
|
-
@property
|
|
590
|
-
def n_print_steps(self):
|
|
591
|
-
return self._n_print_steps
|
|
592
|
-
|
|
593
|
-
@n_print_steps.setter
|
|
594
|
-
def n_print_steps(self, val):
|
|
595
|
-
self._n_print_steps = val
|
|
596
|
-
|
|
597
|
-
@property
|
|
598
|
-
def n_iterations(self):
|
|
599
|
-
return self._n_iterations
|
|
600
|
-
|
|
601
|
-
@n_iterations.setter
|
|
602
|
-
def n_iterations(self, val):
|
|
603
|
-
self._n_iterations = val
|
|
604
|
-
|
|
605
|
-
@property
|
|
606
|
-
def equilibration_control(self):
|
|
607
|
-
return self._equilibration_control
|
|
608
|
-
|
|
609
|
-
@equilibration_control.setter
|
|
610
|
-
def equilibration_control(self, val):
|
|
611
|
-
if val not in ["berendsen", "nose-hoover", None]:
|
|
612
|
-
raise ValueError("Equilibration control should be either berendsen or nose-hoover or None")
|
|
613
|
-
self._equilibration_control = val
|
|
614
|
-
|
|
615
|
-
@property
|
|
616
|
-
def melting_cycle(self):
|
|
617
|
-
return self._melting_cycle
|
|
618
|
-
|
|
619
|
-
@melting_cycle.setter
|
|
620
|
-
def melting_cycle(self, val):
|
|
621
|
-
val = self.to_bool(val)
|
|
622
|
-
if isinstance(val, bool):
|
|
623
|
-
self._melting_cycle = val
|
|
624
|
-
else:
|
|
625
|
-
raise TypeError("Melting cycle should be either True/False")
|
|
626
|
-
|
|
627
|
-
@property
|
|
628
|
-
def spring_constants(self):
|
|
629
|
-
return self._spring_constants
|
|
630
|
-
|
|
631
|
-
@spring_constants.setter
|
|
632
|
-
def spring_constants(self, val):
|
|
633
|
-
val = self.check_and_convert_to_list(val, check_none=True)
|
|
634
|
-
self._spring_constants = val
|
|
635
|
-
|
|
636
|
-
@property
|
|
637
|
-
def folder_prefix(self):
|
|
638
|
-
return self._folder_prefix
|
|
639
|
-
|
|
640
|
-
@folder_prefix.setter
|
|
641
|
-
def folder_prefix(self, val):
|
|
642
|
-
self._folder_prefix = val
|
|
643
|
-
|
|
644
|
-
def fix_paths(self, potlist):
|
|
645
|
-
"""
|
|
646
|
-
Fix paths for potential files to complete ones
|
|
647
|
-
"""
|
|
648
|
-
fixedpots = []
|
|
649
|
-
for pot in potlist:
|
|
650
|
-
pcraw = pot.split()
|
|
651
|
-
if len(pcraw) >= 3:
|
|
652
|
-
filename = pcraw[2]
|
|
653
|
-
filename = os.path.abspath(filename)
|
|
654
|
-
pcnew = " ".join([*pcraw[:2], filename, *pcraw[3:]])
|
|
655
|
-
fixedpots.append(pcnew)
|
|
656
|
-
else:
|
|
657
|
-
fixedpots.append(pot)
|
|
658
|
-
return fixedpots
|
|
659
|
-
|
|
660
|
-
def create_identifier(self):
|
|
661
|
-
"""
|
|
662
|
-
Generate an identifier
|
|
663
|
-
|
|
664
|
-
Parameters
|
|
665
|
-
----------
|
|
666
|
-
calc: dict
|
|
667
|
-
a calculation dict
|
|
668
|
-
|
|
669
|
-
Returns
|
|
670
|
-
-------
|
|
671
|
-
identistring: string
|
|
672
|
-
unique identification string
|
|
673
|
-
"""
|
|
674
|
-
#lattice processed
|
|
675
|
-
prefix = self.mode
|
|
676
|
-
if prefix == 'melting_temperature':
|
|
677
|
-
ts = int(0)
|
|
678
|
-
ps = int(0)
|
|
679
|
-
l = 'tm'
|
|
680
|
-
else:
|
|
681
|
-
ts = int(self._temperature)
|
|
682
|
-
if self._pressure is None:
|
|
683
|
-
ps = "None"
|
|
684
|
-
else:
|
|
685
|
-
ps = "%d"%(int(self._pressure))
|
|
686
|
-
l = self.lattice
|
|
687
|
-
l = l.split('/')
|
|
688
|
-
l = l[-1]
|
|
689
|
-
|
|
690
|
-
if self.folder_prefix is None:
|
|
691
|
-
identistring = "-".join([prefix, l, str(ts), str(ps)])
|
|
692
|
-
else:
|
|
693
|
-
identistring = "-".join([self.folder_prefix, prefix, l, str(ts), str(ps)])
|
|
694
|
-
return identistring
|
|
695
|
-
|
|
696
|
-
def get_folder_name(self):
|
|
697
|
-
identistring = self.create_identifier()
|
|
698
|
-
simfolder = os.path.join(os.getcwd(), identistring)
|
|
699
|
-
return simfolder
|
|
700
|
-
|
|
701
|
-
def create_folders(self):
|
|
702
|
-
"""
|
|
703
|
-
Create the necessary folder for calculation
|
|
704
|
-
|
|
705
|
-
Parameters
|
|
706
|
-
----------
|
|
707
|
-
calc : dict
|
|
708
|
-
calculation block
|
|
709
|
-
|
|
710
|
-
Returns
|
|
711
|
-
-------
|
|
712
|
-
folder : string
|
|
713
|
-
create folder
|
|
714
|
-
"""
|
|
715
|
-
simfolder = self.get_folder_name()
|
|
716
|
-
|
|
717
|
-
#if folder exists, delete it -> then create
|
|
718
|
-
try:
|
|
719
|
-
if os.path.exists(simfolder):
|
|
720
|
-
shutil.rmtree(simfolder)
|
|
721
|
-
except OSError:
|
|
722
|
-
newstr = '-'.join(str(datetime.datetime.now()).split())
|
|
723
|
-
newstr = '-'.join([simfolder, newstr])
|
|
724
|
-
shutil.move(simfolder, newstr)
|
|
725
|
-
|
|
726
|
-
os.mkdir(simfolder)
|
|
727
|
-
return simfolder
|
|
728
|
-
|
|
729
|
-
@classmethod
|
|
730
|
-
def generate(cls, indata):
|
|
731
|
-
if not isinstance(indata, dict):
|
|
732
|
-
if os.path.exists(indata):
|
|
733
|
-
with open(indata) as file:
|
|
734
|
-
indata = yaml.load(file, Loader=yaml.FullLoader)
|
|
735
|
-
if isinstance(indata, dict):
|
|
736
|
-
calc = cls()
|
|
737
|
-
calc.element = indata["element"]
|
|
738
|
-
calc.mass = indata["mass"]
|
|
739
|
-
|
|
740
|
-
calc.script_mode = check_dict(indata, "script_mode", retval=False)
|
|
741
|
-
calc.lammps_executable = check_dict(indata, "lammps_executable")
|
|
742
|
-
calc.mpi_executable = check_dict(indata, "mpi_executable")
|
|
743
|
-
|
|
744
|
-
if "md" in indata.keys():
|
|
745
|
-
calc.md.add_from_dict(indata["md"])
|
|
746
|
-
if "queue" in indata.keys():
|
|
747
|
-
calc.queue.add_from_dict(indata["queue"])
|
|
748
|
-
if "tolerance" in indata.keys():
|
|
749
|
-
calc.tolerance.add_from_dict(indata["tolerance"])
|
|
750
|
-
if "melting_temperature" in indata.keys():
|
|
751
|
-
calc.melting_temperature.add_from_dict(indata["melting_temperature"])
|
|
752
|
-
if "nose_hoover" in indata.keys():
|
|
753
|
-
calc.nose_hoover.add_from_dict(indata["nose_hoover"])
|
|
754
|
-
if "berendsen" in indata.keys():
|
|
755
|
-
calc.berendsen.add_from_dict(indata["berendsen"])
|
|
756
|
-
if "composition_scaling" in indata.keys():
|
|
757
|
-
calc.composition_scaling.add_from_dict(indata["composition_scaling"])
|
|
758
|
-
#if temperature_high is present, set it
|
|
759
|
-
if "temperature_high" in indata.keys():
|
|
760
|
-
calc.temperature_high = indata["temperature_high"]
|
|
761
|
-
return calc
|
|
762
|
-
else:
|
|
763
|
-
raise FileNotFoundError('%s input file not found'% indata)
|
|
764
|
-
|
|
765
|
-
@staticmethod
|
|
766
|
-
def read_file(file):
|
|
767
|
-
if os.path.exists(file):
|
|
768
|
-
with open(file) as file:
|
|
769
|
-
indata = yaml.load(file, Loader=yaml.FullLoader)
|
|
770
|
-
else:
|
|
771
|
-
raise FileNotFoundError('%s input file not found'% file)
|
|
772
|
-
return indata
|
|
773
|
-
|
|
774
|
-
@property
|
|
775
|
-
def savefile(self):
|
|
776
|
-
simfolder = self.get_folder_name()
|
|
777
|
-
return os.path.join(simfolder, 'job.npy')
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
def read_inputfile(file):
|
|
781
|
-
"""
|
|
782
|
-
Read calphy inputfile
|
|
783
|
-
|
|
784
|
-
Parameters
|
|
785
|
-
----------
|
|
786
|
-
file : string
|
|
787
|
-
input file
|
|
788
|
-
|
|
789
|
-
Returns
|
|
790
|
-
-------
|
|
791
|
-
options : dict
|
|
792
|
-
dictionary containing input options
|
|
793
|
-
"""
|
|
794
|
-
indata = Calculation.read_file(file)
|
|
795
|
-
calculations = []
|
|
796
|
-
for ci in indata["calculations"]:
|
|
797
|
-
#get main variables
|
|
798
|
-
mode = ci["mode"]
|
|
799
|
-
if mode == "melting_temperature":
|
|
800
|
-
calc = Calculation.generate(indata)
|
|
801
|
-
calc.add_from_dict(ci, keys=["mode", "pair_style", "pair_coeff", "repeat", "n_equilibration_steps",
|
|
802
|
-
"n_switching_steps", "n_print_steps", "n_iterations", "spring_constants", "equilibration_control",
|
|
803
|
-
"folder_prefix"])
|
|
804
|
-
calc.pressure = Calculation.convert_to_list(ci["pressure"], check_none=True) if "pressure" in ci.keys() else 0
|
|
805
|
-
calc.temperature = Calculation.convert_to_list(ci["temperature"]) if "temperature" in ci.keys() else None
|
|
806
|
-
calc.lattice = Calculation.convert_to_list(ci["lattice"]) if "lattice" in ci.keys() else None
|
|
807
|
-
calc.reference_phase = Calculation.convert_to_list(ci["reference_phase"]) if "reference_phase" in ci.keys() else None
|
|
808
|
-
calc.lattice_constant = Calculation.convert_to_list(ci["lattice_constant"]) if "lattice_constant" in ci.keys() else 0
|
|
809
|
-
calculations.append(calc)
|
|
810
|
-
else:
|
|
811
|
-
pressure = Calculation.convert_to_list(ci["pressure"], check_none=True) if "pressure" in ci.keys() else []
|
|
812
|
-
temperature = Calculation.convert_to_list(ci["temperature"]) if "temperature" in ci.keys() else []
|
|
813
|
-
lattice = Calculation.convert_to_list(ci["lattice"])
|
|
814
|
-
reference_phase = Calculation.convert_to_list(ci["reference_phase"])
|
|
815
|
-
if "lattice_constant" in ci.keys():
|
|
816
|
-
lattice_constant = Calculation.convert_to_list(ci["lattice_constant"])
|
|
817
|
-
else:
|
|
818
|
-
lattice_constant = [0 for x in range(len(lattice))]
|
|
819
|
-
if not len(lattice_constant)==len(reference_phase)==len(lattice):
|
|
820
|
-
raise ValueError("lattice constant, reference phase and lattice should have same length")
|
|
821
|
-
lat_props = [{"lattice": lattice[x], "lattice_constant":lattice_constant[x], "reference_phase":reference_phase[x]} for x in range(len(lattice))]
|
|
822
|
-
if (mode == "fe") or (mode == "alchemy") or (mode == "composition_scaling"):
|
|
823
|
-
combos = itertools.product(lat_props, pressure, temperature)
|
|
824
|
-
elif mode == "ts" or mode == "tscale" or mode == "mts":
|
|
825
|
-
if not len(temperature) == 2:
|
|
826
|
-
raise ValueError("ts/tscale mode needs 2 temperature values")
|
|
827
|
-
temperature = [temperature]
|
|
828
|
-
combos = itertools.product(lat_props, pressure, temperature)
|
|
829
|
-
elif mode == "pscale":
|
|
830
|
-
if not len(pressure) == 2:
|
|
831
|
-
raise ValueError("pscale mode needs 2 pressure values")
|
|
832
|
-
pressure = [pressure]
|
|
833
|
-
combos = itertools.product(lat_props, pressure, temperature)
|
|
834
|
-
#create calculations
|
|
835
|
-
for combo in combos:
|
|
836
|
-
calc = Calculation.generate(indata)
|
|
837
|
-
calc.add_from_dict(ci, keys=["mode", "pair_style", "pair_coeff", "pair_style_options", "npt",
|
|
838
|
-
"repeat", "n_equilibration_steps",
|
|
839
|
-
"n_switching_steps", "n_print_steps", "n_iterations", "potential_file", "spring_constants",
|
|
840
|
-
"melting_cycle", "equilibration_control", "folder_prefix", "temperature_high"])
|
|
841
|
-
calc.lattice = combo[0]["lattice"]
|
|
842
|
-
calc.lattice_constant = combo[0]["lattice_constant"]
|
|
843
|
-
calc.reference_phase = combo[0]["reference_phase"]
|
|
844
|
-
calc.pressure = combo[1]
|
|
845
|
-
calc.temperature = combo[2]
|
|
846
|
-
calculations.append(calc)
|
|
847
|
-
return calculations
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
def save_job(job):
|
|
851
|
-
filename = os.path.join(job.simfolder, 'job.npy')
|
|
852
|
-
np.save(filename, job)
|
|
853
|
-
|
|
854
|
-
def load_job(filename):
|
|
855
|
-
job = np.load(filename, allow_pickle=True).flatten()[0]
|
|
856
|
-
return job
|
|
857
|
-
|
|
858
|
-
def check_dict(indict, key, retval=None):
|
|
859
|
-
if key in indict.items():
|
|
860
|
-
return indict[key]
|
|
861
|
-
else:
|
|
862
|
-
return retval
|