calphy 1.3.13__py3-none-any.whl → 1.4.2__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 +66 -8
- calphy/clitools.py +6 -0
- calphy/composition_transformation.py +63 -9
- calphy/helpers.py +6 -2
- calphy/input.py +478 -245
- calphy/kernel.py +3 -1
- calphy/liquid.py +199 -118
- calphy/phase.py +810 -381
- calphy/phase_diagram.py +500 -26
- calphy/postprocessing.py +192 -4
- calphy/routines.py +13 -2
- calphy/scheduler.py +2 -0
- calphy/solid.py +35 -0
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/METADATA +14 -2
- calphy-1.4.2.dist-info/RECORD +25 -0
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/WHEEL +1 -1
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/entry_points.txt +1 -0
- calphy-1.3.13.dist-info/RECORD +0 -25
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info/licenses}/LICENSE +0 -0
- {calphy-1.3.13.dist-info → calphy-1.4.2.dist-info}/top_level.txt +0 -0
calphy/input.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.
|
|
@@ -23,10 +23,18 @@ sarath.menon@ruhr-uni-bochum.de/yury.lysogorskiy@icams.rub.de
|
|
|
23
23
|
|
|
24
24
|
from typing_extensions import Annotated
|
|
25
25
|
from typing import Any, Callable, List, ClassVar, Optional, Union
|
|
26
|
-
from pydantic import
|
|
26
|
+
from pydantic import (
|
|
27
|
+
BaseModel,
|
|
28
|
+
Field,
|
|
29
|
+
ValidationError,
|
|
30
|
+
model_validator,
|
|
31
|
+
conlist,
|
|
32
|
+
PrivateAttr,
|
|
33
|
+
)
|
|
27
34
|
from pydantic.functional_validators import AfterValidator, BeforeValidator
|
|
28
35
|
from annotated_types import Len
|
|
29
36
|
import mendeleev
|
|
37
|
+
from tqdm import tqdm
|
|
30
38
|
|
|
31
39
|
import yaml
|
|
32
40
|
import numpy as np
|
|
@@ -40,21 +48,25 @@ from pyscal3.core import structure_dict, element_dict, _make_crystal
|
|
|
40
48
|
from ase.io import read, write
|
|
41
49
|
import shutil
|
|
42
50
|
|
|
43
|
-
__version__ = "1.
|
|
51
|
+
__version__ = "1.4.2"
|
|
52
|
+
|
|
44
53
|
|
|
45
54
|
def _check_equal(val):
|
|
46
|
-
if not (val[0]==val[1]==val[2]):
|
|
55
|
+
if not (val[0] == val[1] == val[2]):
|
|
47
56
|
return False
|
|
48
57
|
return True
|
|
49
58
|
|
|
59
|
+
|
|
50
60
|
def to_list(v: Any) -> List[Any]:
|
|
51
61
|
return np.atleast_1d(v)
|
|
52
62
|
|
|
63
|
+
|
|
53
64
|
def _to_str(val):
|
|
54
65
|
if np.isscalar(val):
|
|
55
66
|
return str(val)
|
|
56
67
|
else:
|
|
57
|
-
return [str(x) for x in val]
|
|
68
|
+
return [str(x) for x in val]
|
|
69
|
+
|
|
58
70
|
|
|
59
71
|
def _to_int(val):
|
|
60
72
|
if np.isscalar(val):
|
|
@@ -62,49 +74,91 @@ def _to_int(val):
|
|
|
62
74
|
else:
|
|
63
75
|
return [int(x) for x in val]
|
|
64
76
|
|
|
77
|
+
|
|
65
78
|
def _to_none(val):
|
|
66
|
-
if val in [
|
|
67
|
-
|
|
79
|
+
if val in [
|
|
80
|
+
"none",
|
|
81
|
+
"None",
|
|
82
|
+
]:
|
|
83
|
+
return None
|
|
68
84
|
return val
|
|
69
85
|
|
|
86
|
+
|
|
70
87
|
def _to_float(val):
|
|
71
88
|
if np.isscalar(val):
|
|
72
89
|
return float(val)
|
|
73
90
|
else:
|
|
74
|
-
return [float(x) for x in val]
|
|
75
|
-
|
|
76
|
-
|
|
91
|
+
return [float(x) for x in val]
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class UFMP(BaseModel, title="UFM potential input options"):
|
|
95
|
+
p: Annotated[float, Field(default=50.0)]
|
|
96
|
+
sigma: Annotated[float, Field(default=1.5)]
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class MonteCarlo(
|
|
100
|
+
BaseModel, title="Options for Monte Carlo moves during particle swap moves"
|
|
101
|
+
):
|
|
102
|
+
n_steps: Annotated[
|
|
103
|
+
int, Field(default=1, gt=0, description="perform swap moves every n_step")
|
|
104
|
+
]
|
|
105
|
+
n_swaps: Annotated[
|
|
106
|
+
int, Field(default=0, ge=0, description="number of swap moves to perform")
|
|
107
|
+
]
|
|
108
|
+
reverse_swap: Annotated[bool, Field(default=True)]
|
|
109
|
+
swap_types: Annotated[
|
|
110
|
+
conlist(int, min_length=2, max_length=2),
|
|
111
|
+
Field(default=[1, 2], description="which atoms to swap between"),
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class CompositionScaling(BaseModel, title="Composition scaling input options"):
|
|
77
116
|
_input_chemical_composition: PrivateAttr(default=None)
|
|
78
117
|
output_chemical_composition: Annotated[dict, Field(default={}, required=False)]
|
|
79
|
-
restrictions: Annotated[
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
118
|
+
restrictions: Annotated[
|
|
119
|
+
List[str], BeforeValidator(to_list), Field(default=[], required=False)
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class MD(BaseModel, title="MD specific input options"):
|
|
124
|
+
timestep: Annotated[
|
|
125
|
+
float,
|
|
126
|
+
Field(
|
|
127
|
+
default=0.001,
|
|
128
|
+
description="timestep for md simulation",
|
|
129
|
+
example="timestep: 0.001",
|
|
130
|
+
),
|
|
131
|
+
]
|
|
86
132
|
n_small_steps: Annotated[int, Field(default=10000, gt=0)]
|
|
87
133
|
n_every_steps: Annotated[int, Field(default=10, gt=0)]
|
|
88
134
|
n_repeat_steps: Annotated[int, Field(default=10, gt=0)]
|
|
89
135
|
n_cycles: Annotated[int, Field(default=100, gt=0)]
|
|
90
|
-
thermostat_damping: Annotated[
|
|
91
|
-
|
|
136
|
+
thermostat_damping: Annotated[
|
|
137
|
+
Union[float, conlist(float, min_length=2, max_length=2)],
|
|
138
|
+
Field(default=0.1, gt=0),
|
|
139
|
+
]
|
|
140
|
+
barostat_damping: Annotated[
|
|
141
|
+
Union[float, conlist(float, min_length=2, max_length=2)],
|
|
142
|
+
Field(default=0.1, gt=0),
|
|
143
|
+
]
|
|
92
144
|
cmdargs: Annotated[str, Field(default="")]
|
|
93
145
|
init_commands: Annotated[List, Field(default=[])]
|
|
94
146
|
|
|
95
147
|
|
|
96
|
-
class NoseHoover(BaseModel, title=
|
|
148
|
+
class NoseHoover(BaseModel, title="Specific input options for Nose-Hoover thermostat"):
|
|
97
149
|
thermostat_damping: Annotated[float, Field(default=0.1, gt=0)]
|
|
98
150
|
barostat_damping: Annotated[float, Field(default=0.1, gt=0)]
|
|
99
151
|
|
|
100
|
-
|
|
152
|
+
|
|
153
|
+
class Berendsen(BaseModel, title="Specific input options for Berendsen thermostat"):
|
|
101
154
|
thermostat_damping: Annotated[float, Field(default=100.0, gt=0)]
|
|
102
155
|
barostat_damping: Annotated[float, Field(default=100.0, gt=0)]
|
|
103
156
|
|
|
104
|
-
|
|
105
|
-
|
|
157
|
+
|
|
158
|
+
class Queue(BaseModel, title="Options for configuring queue"):
|
|
159
|
+
scheduler: Annotated[str, Field(default="local")]
|
|
106
160
|
cores: Annotated[int, Field(default=1, gt=0)]
|
|
107
|
-
jobname: Annotated[str, Field(default=
|
|
161
|
+
jobname: Annotated[str, Field(default="calphy")]
|
|
108
162
|
walltime: Annotated[str, Field(default="23:59:00")]
|
|
109
163
|
queuename: Annotated[str, Field(default="")]
|
|
110
164
|
memory: Annotated[str, Field(default="3GB")]
|
|
@@ -112,102 +166,127 @@ class Queue(BaseModel, title='Options for configuring queue'):
|
|
|
112
166
|
options: Annotated[List, Field(default=[])]
|
|
113
167
|
modules: Annotated[List, Field(default=[])]
|
|
114
168
|
|
|
115
|
-
|
|
169
|
+
|
|
170
|
+
class Tolerance(BaseModel, title="Tolerance settings for convergence"):
|
|
116
171
|
lattice_constant: Annotated[float, Field(default=0.0002, ge=0)]
|
|
117
172
|
spring_constant: Annotated[float, Field(default=0.1, gt=0)]
|
|
118
173
|
solid_fraction: Annotated[float, Field(default=0.7, ge=0)]
|
|
119
174
|
liquid_fraction: Annotated[float, Field(default=0.05, ge=0)]
|
|
120
175
|
pressure: Annotated[float, Field(default=0.5, ge=0)]
|
|
121
176
|
|
|
122
|
-
|
|
177
|
+
|
|
178
|
+
class MeltingTemperature(BaseModel, title="Input options for melting temperature mode"):
|
|
123
179
|
guess: Annotated[Union[float, None], Field(default=None, gt=0)]
|
|
124
180
|
step: Annotated[int, Field(default=200, ge=20)]
|
|
125
181
|
attempts: Annotated[int, Field(default=5, ge=1)]
|
|
126
182
|
|
|
127
|
-
|
|
183
|
+
|
|
184
|
+
class Calculation(BaseModel, title="Main input class"):
|
|
185
|
+
monte_carlo: Optional[MonteCarlo] = MonteCarlo()
|
|
128
186
|
composition_scaling: Optional[CompositionScaling] = CompositionScaling()
|
|
129
187
|
md: Optional[MD] = MD()
|
|
130
188
|
nose_hoover: Optional[NoseHoover] = NoseHoover()
|
|
131
189
|
berendsen: Optional[Berendsen] = Berendsen()
|
|
132
190
|
queue: Optional[Queue] = Queue()
|
|
133
|
-
tolerance: Optional[Tolerance] = Tolerance()
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
191
|
+
tolerance: Optional[Tolerance] = Tolerance()
|
|
192
|
+
uhlenbeck_ford_model: Optional[UFMP] = UFMP()
|
|
193
|
+
melting_temperature: Optional[MeltingTemperature] = MeltingTemperature()
|
|
194
|
+
element: Annotated[List[str], BeforeValidator(to_list), Field(default=[])]
|
|
137
195
|
n_elements: Annotated[int, Field(default=0)]
|
|
138
|
-
mass: Annotated[List[float], BeforeValidator(to_list),
|
|
139
|
-
Field(default=[])]
|
|
196
|
+
mass: Annotated[List[float], BeforeValidator(to_list), Field(default=[])]
|
|
140
197
|
_element_dict: dict = PrivateAttr(default={})
|
|
141
198
|
kernel: Annotated[int, Field(default=0)]
|
|
142
|
-
inputfile: Annotated[str, Field(default=
|
|
199
|
+
inputfile: Annotated[str, Field(default="")]
|
|
143
200
|
|
|
144
201
|
mode: Annotated[Union[str, None], Field(default=None)]
|
|
145
202
|
lattice: Annotated[str, Field(default="")]
|
|
146
|
-
file_format: Annotated[str, Field(default=
|
|
147
|
-
|
|
148
|
-
#pressure properties
|
|
149
|
-
pressure: Annotated[
|
|
150
|
-
|
|
151
|
-
|
|
203
|
+
file_format: Annotated[str, Field(default="lammps-data")]
|
|
204
|
+
|
|
205
|
+
# pressure properties
|
|
206
|
+
pressure: Annotated[
|
|
207
|
+
Union[
|
|
208
|
+
None,
|
|
209
|
+
float,
|
|
210
|
+
conlist(float, min_length=1, max_length=2),
|
|
211
|
+
conlist(
|
|
212
|
+
conlist(float, min_length=3, max_length=3), min_length=1, max_length=2
|
|
213
|
+
),
|
|
214
|
+
],
|
|
215
|
+
Field(default=0),
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
_pressure_stop: float = PrivateAttr(default=None)
|
|
219
|
+
_pressure: float = PrivateAttr(default=None)
|
|
152
220
|
_pressure_stop: float = PrivateAttr(default=None)
|
|
153
|
-
_pressure: float = PrivateAttr(default=None)
|
|
154
|
-
_pressure_stop: float = PrivateAttr(default=None)
|
|
155
221
|
_pressure_input: Any = PrivateAttr(default=None)
|
|
156
222
|
_iso: bool = PrivateAttr(default=False)
|
|
157
223
|
_fix_lattice: bool = PrivateAttr(default=False)
|
|
158
224
|
|
|
159
|
-
temperature: Annotated[
|
|
160
|
-
|
|
161
|
-
|
|
225
|
+
temperature: Annotated[
|
|
226
|
+
Union[float, conlist(float, min_length=1, max_length=2)], Field(default=0)
|
|
227
|
+
]
|
|
228
|
+
temperature_high: Annotated[float, Field(default=0.0)]
|
|
162
229
|
_temperature: float = PrivateAttr(default=None)
|
|
163
230
|
_temperature_high: float = PrivateAttr(default=None)
|
|
164
231
|
_temperature_stop: float = PrivateAttr(default=None)
|
|
165
232
|
_temperature_input: float = PrivateAttr(default=None)
|
|
166
|
-
|
|
167
|
-
melting_cycle: Annotated[
|
|
168
|
-
|
|
169
|
-
pair_style: Annotated[
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
233
|
+
|
|
234
|
+
melting_cycle: Annotated[bool, Field(default=True)]
|
|
235
|
+
|
|
236
|
+
pair_style: Annotated[
|
|
237
|
+
Union[List[str], None], BeforeValidator(to_list), Field(default=None)
|
|
238
|
+
]
|
|
239
|
+
pair_coeff: Annotated[
|
|
240
|
+
Union[List[str], None], BeforeValidator(to_list), Field(default=None)
|
|
241
|
+
]
|
|
242
|
+
potential_file: Annotated[Union[str, None], Field(default=None)]
|
|
174
243
|
fix_potential_path: Annotated[bool, Field(default=True)]
|
|
175
244
|
_pair_style_with_options: List[str] = PrivateAttr(default=None)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
script_mode: Annotated[
|
|
184
|
-
lammps_executable: Annotated[
|
|
185
|
-
mpi_executable: Annotated[
|
|
186
|
-
|
|
187
|
-
npt: Annotated[
|
|
188
|
-
n_equilibration_steps: Annotated[
|
|
189
|
-
n_switching_steps: Annotated[
|
|
245
|
+
|
|
246
|
+
reference_phase: Annotated[str, Field(default="")]
|
|
247
|
+
lattice_constant: Annotated[float, Field(default=0)]
|
|
248
|
+
repeat: Annotated[
|
|
249
|
+
conlist(int, min_length=3, max_length=3), Field(default=[1, 1, 1])
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
script_mode: Annotated[bool, Field(default=False)]
|
|
253
|
+
lammps_executable: Annotated[Union[str, None], Field(default=None)]
|
|
254
|
+
mpi_executable: Annotated[Union[str, None], Field(default=None)]
|
|
255
|
+
|
|
256
|
+
npt: Annotated[bool, Field(default=True)]
|
|
257
|
+
n_equilibration_steps: Annotated[int, Field(default=25000)]
|
|
258
|
+
n_switching_steps: Annotated[
|
|
259
|
+
Union[int, conlist(int, min_length=2, max_length=2)],
|
|
260
|
+
Field(default=[50000, 50000]),
|
|
261
|
+
]
|
|
190
262
|
_n_switching_steps: int = PrivateAttr(default=50000)
|
|
191
263
|
_n_sweep_steps: int = PrivateAttr(default=50000)
|
|
192
|
-
n_print_steps: Annotated[int, Field(default
|
|
193
|
-
n_iterations: Annotated[int, Field(default
|
|
194
|
-
equilibration_control: Annotated[Union[str,None], Field(default
|
|
195
|
-
folder_prefix: Annotated[Union[str,None], Field(default
|
|
264
|
+
n_print_steps: Annotated[int, Field(default=0)]
|
|
265
|
+
n_iterations: Annotated[int, Field(default=1)]
|
|
266
|
+
equilibration_control: Annotated[Union[str, None], Field(default=None)]
|
|
267
|
+
folder_prefix: Annotated[Union[str, None], Field(default=None)]
|
|
196
268
|
|
|
197
|
-
#add second level options; for example spring constants
|
|
198
|
-
spring_constants: Annotated[Union[List[float],None], Field(default
|
|
269
|
+
# add second level options; for example spring constants
|
|
270
|
+
spring_constants: Annotated[Union[List[float], None], Field(default=None)]
|
|
199
271
|
|
|
200
|
-
#
|
|
272
|
+
# some input keywords that will be used for the phase diagram mode
|
|
273
|
+
phase_name: Annotated[str, Field(default="")]
|
|
274
|
+
reference_composition: Annotated[float, Field(default=0.00)]
|
|
275
|
+
|
|
276
|
+
# structure items
|
|
201
277
|
_structure: Any = PrivateAttr(default=None)
|
|
202
278
|
|
|
203
|
-
|
|
204
|
-
|
|
279
|
+
# just check for nlements in compscale
|
|
280
|
+
_totalelements = PrivateAttr(default=0)
|
|
281
|
+
|
|
282
|
+
@model_validator(mode="after")
|
|
283
|
+
def _validate_all(self) -> "Input":
|
|
205
284
|
|
|
206
285
|
if not (len(self.element) == len(self.mass)):
|
|
207
|
-
raise ValueError(
|
|
208
|
-
|
|
286
|
+
raise ValueError("mass and elements should have same length")
|
|
287
|
+
|
|
209
288
|
self.n_elements = len(self.element)
|
|
210
|
-
|
|
289
|
+
|
|
211
290
|
self._pressure_input = copy.copy(self.pressure)
|
|
212
291
|
if self.pressure is None:
|
|
213
292
|
self._iso = True
|
|
@@ -231,25 +310,25 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
231
310
|
self._pressure_stop = self.pressure[1]
|
|
232
311
|
elif np.shape(self.pressure) == (1, 3):
|
|
233
312
|
if not _check_equal(self.pressure[0]):
|
|
234
|
-
raise ValueError(
|
|
313
|
+
raise ValueError("All pressure terms must be equal")
|
|
235
314
|
self._iso = False
|
|
236
315
|
self._fix_lattice = False
|
|
237
316
|
self._pressure = self.pressure[0][0]
|
|
238
|
-
self._pressure_stop = self.pressure[0][0]
|
|
317
|
+
self._pressure_stop = self.pressure[0][0]
|
|
239
318
|
elif np.shape(self.pressure) == (2, 3):
|
|
240
319
|
if not (_check_equal(self.pressure[0]) and _check_equal(self.pressure[1])):
|
|
241
|
-
raise ValueError(
|
|
320
|
+
raise ValueError("All pressure terms must be equal")
|
|
242
321
|
self._iso = False
|
|
243
322
|
self._fix_lattice = False
|
|
244
323
|
self._pressure = self.pressure[0][0]
|
|
245
|
-
self._pressure_stop = self.pressure[1][0]
|
|
324
|
+
self._pressure_stop = self.pressure[1][0]
|
|
246
325
|
else:
|
|
247
|
-
raise ValueError(
|
|
326
|
+
raise ValueError("Unknown format for pressure")
|
|
248
327
|
|
|
249
328
|
self._temperature_input = copy.copy(self.temperature)
|
|
250
|
-
#guess a melting temp of the system, this will be mostly ignored
|
|
251
|
-
#chem = mendeleev.element(self.element[0])
|
|
252
|
-
#self._melting_temperature = chem.melting_point
|
|
329
|
+
# guess a melting temp of the system, this will be mostly ignored
|
|
330
|
+
# chem = mendeleev.element(self.element[0])
|
|
331
|
+
# self._melting_temperature = chem.melting_point
|
|
253
332
|
try:
|
|
254
333
|
chem = mendeleev.element(self.element[0])
|
|
255
334
|
self._melting_temperature = chem.melting_point
|
|
@@ -257,16 +336,20 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
257
336
|
self._melting_temperature = None
|
|
258
337
|
|
|
259
338
|
if self.temperature == 0:
|
|
260
|
-
#the only situation in which it can be None is if mode is melting temp
|
|
339
|
+
# the only situation in which it can be None is if mode is melting temp
|
|
261
340
|
if len(self.element) > 1:
|
|
262
|
-
raise ValueError(
|
|
263
|
-
|
|
341
|
+
raise ValueError(
|
|
342
|
+
"Cannot guess start temperature for more than one species, please specify"
|
|
343
|
+
)
|
|
344
|
+
# now try to guess
|
|
264
345
|
if self._melting_temperature is None:
|
|
265
|
-
raise ValueError(
|
|
346
|
+
raise ValueError(
|
|
347
|
+
"Could not guess start temperature for more than one species, please specify"
|
|
348
|
+
)
|
|
266
349
|
self._temperature = self._melting_temperature
|
|
267
350
|
self._temperature_stop = self._melting_temperature
|
|
268
351
|
if self.temperature_high == 0:
|
|
269
|
-
self._temperature_high = 2*self._melting_temperature
|
|
352
|
+
self._temperature_high = 2 * self._melting_temperature
|
|
270
353
|
else:
|
|
271
354
|
self._temperature_high = self.temperature_high
|
|
272
355
|
|
|
@@ -275,83 +358,96 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
275
358
|
self._temperature = temp[0]
|
|
276
359
|
self._temperature_stop = temp[0]
|
|
277
360
|
if self.temperature_high == 0:
|
|
278
|
-
self._temperature_high = 2*temp[0]
|
|
361
|
+
self._temperature_high = 2 * temp[0]
|
|
279
362
|
else:
|
|
280
363
|
self._temperature_high = self.temperature_high
|
|
281
|
-
|
|
364
|
+
|
|
282
365
|
elif np.shape(self.temperature) == (2,):
|
|
283
366
|
temp = self.temperature
|
|
284
367
|
self._temperature = temp[0]
|
|
285
368
|
self._temperature_stop = temp[1]
|
|
286
369
|
if self.temperature_high == 0:
|
|
287
|
-
self._temperature_high = 2*temp[1]
|
|
370
|
+
self._temperature_high = 2 * temp[1]
|
|
288
371
|
else:
|
|
289
372
|
self._temperature_high = self.temperature_high
|
|
290
373
|
|
|
291
|
-
|
|
292
|
-
#
|
|
293
|
-
#two main lists
|
|
374
|
+
# fix pair styles
|
|
375
|
+
# two main lists
|
|
294
376
|
# _pair_style_with_options, read in as it is from file
|
|
295
377
|
# _pair_style_names, just the names of the pair styles
|
|
296
378
|
|
|
297
379
|
_pair_style_names = []
|
|
298
|
-
|
|
380
|
+
|
|
299
381
|
for ps in self.pair_style:
|
|
300
382
|
ps_split = ps.split()
|
|
301
383
|
_pair_style_names.append(ps_split[0])
|
|
302
384
|
|
|
303
|
-
|
|
304
|
-
#only set if its None
|
|
385
|
+
# only set if its None
|
|
305
386
|
self._pair_style_with_options = self.pair_style
|
|
306
|
-
self._pair_style_names = _pair_style_names
|
|
307
|
-
|
|
308
|
-
#now fix pair coeffs with path
|
|
387
|
+
self._pair_style_names = _pair_style_names
|
|
388
|
+
|
|
389
|
+
# now fix pair coeffs with path
|
|
309
390
|
if self.fix_potential_path:
|
|
310
391
|
self.pair_coeff = self.fix_paths(self.pair_coeff)
|
|
311
|
-
|
|
392
|
+
|
|
312
393
|
if np.isscalar(self.n_switching_steps):
|
|
313
394
|
self._n_sweep_steps = self.n_switching_steps
|
|
314
395
|
self._n_switching_steps = self.n_switching_steps
|
|
315
396
|
else:
|
|
316
397
|
self._n_sweep_steps = self.n_switching_steps[1]
|
|
317
398
|
self._n_switching_steps = self.n_switching_steps[0]
|
|
318
|
-
|
|
319
|
-
#here we also prepare lattice dict
|
|
399
|
+
|
|
400
|
+
# here we also prepare lattice dict
|
|
320
401
|
for count, element in enumerate(self.element):
|
|
321
402
|
self._element_dict[element] = {}
|
|
322
|
-
self._element_dict[element][
|
|
323
|
-
self._element_dict[element][
|
|
324
|
-
self._element_dict[element][
|
|
325
|
-
self._element_dict[element][
|
|
326
|
-
|
|
327
|
-
|
|
403
|
+
self._element_dict[element]["mass"] = self.mass[count]
|
|
404
|
+
self._element_dict[element]["count"] = 0
|
|
405
|
+
self._element_dict[element]["composition"] = 0.0
|
|
406
|
+
self._element_dict[element]["atomic_number"] = mendeleev.element(
|
|
407
|
+
element
|
|
408
|
+
).atomic_number
|
|
409
|
+
|
|
410
|
+
# generate temporary filename if needed
|
|
328
411
|
write_structure_file = False
|
|
412
|
+
rename_structure_file = False
|
|
329
413
|
|
|
330
414
|
if self.lattice == "":
|
|
331
|
-
#fetch from dict
|
|
415
|
+
# fetch from dict
|
|
332
416
|
if len(self.element) > 1:
|
|
333
|
-
raise ValueError(
|
|
417
|
+
raise ValueError(
|
|
418
|
+
"Cannot create lattice for more than one element, provide a lammps-data file explicitly"
|
|
419
|
+
)
|
|
334
420
|
if self.element[0] in element_dict.keys():
|
|
335
|
-
self.lattice = element_dict[self.element[0]][
|
|
336
|
-
self.lattice_constant = element_dict[self.element[0]][
|
|
421
|
+
self.lattice = element_dict[self.element[0]]["structure"]
|
|
422
|
+
self.lattice_constant = element_dict[self.element[0]][
|
|
423
|
+
"lattice_constant"
|
|
424
|
+
]
|
|
337
425
|
else:
|
|
338
|
-
raise ValueError(
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
self.repeat = [5,5,5]
|
|
426
|
+
raise ValueError(
|
|
427
|
+
"Could not find structure, please provide lattice and lattice_constant explicitely"
|
|
428
|
+
)
|
|
342
429
|
|
|
343
|
-
|
|
430
|
+
if self.repeat == [1, 1, 1]:
|
|
431
|
+
self.repeat = [5, 5, 5]
|
|
432
|
+
|
|
433
|
+
structure = _make_crystal(
|
|
434
|
+
self.lattice.lower(),
|
|
344
435
|
lattice_constant=self.lattice_constant,
|
|
345
436
|
repetitions=self.repeat,
|
|
346
|
-
element=self.element
|
|
437
|
+
element=self.element,
|
|
438
|
+
)
|
|
347
439
|
structure = structure.write.ase()
|
|
348
|
-
|
|
349
|
-
#extract composition
|
|
350
|
-
types, typecounts = np.unique(
|
|
440
|
+
|
|
441
|
+
# extract composition
|
|
442
|
+
types, typecounts = np.unique(
|
|
443
|
+
structure.get_chemical_symbols(), return_counts=True
|
|
444
|
+
)
|
|
351
445
|
|
|
352
446
|
for c, t in enumerate(types):
|
|
353
|
-
self._element_dict[t][
|
|
354
|
-
self._element_dict[t][
|
|
447
|
+
self._element_dict[t]["count"] = typecounts[c]
|
|
448
|
+
self._element_dict[t]["composition"] = typecounts[c] / np.sum(
|
|
449
|
+
typecounts
|
|
450
|
+
)
|
|
355
451
|
|
|
356
452
|
self._natoms = len(structure)
|
|
357
453
|
self._original_lattice = self.lattice.lower()
|
|
@@ -359,86 +455,138 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
359
455
|
|
|
360
456
|
elif self.lattice.lower() in structure_dict.keys():
|
|
361
457
|
if len(self.element) > 1:
|
|
362
|
-
raise ValueError(
|
|
458
|
+
raise ValueError(
|
|
459
|
+
"Cannot create lattice for more than one element, provide a lammps-data file explicitly"
|
|
460
|
+
)
|
|
363
461
|
|
|
364
|
-
#this is a valid structure
|
|
462
|
+
# this is a valid structure
|
|
365
463
|
if self.lattice_constant == 0:
|
|
366
|
-
#we try try to get lattice_constant
|
|
464
|
+
# we try try to get lattice_constant
|
|
367
465
|
if self.element[0] in element_dict.keys():
|
|
368
|
-
self.lattice_constant = element_dict[self.element[0]][
|
|
466
|
+
self.lattice_constant = element_dict[self.element[0]][
|
|
467
|
+
"lattice_constant"
|
|
468
|
+
]
|
|
369
469
|
else:
|
|
370
|
-
raise ValueError(
|
|
371
|
-
#now create lattice
|
|
372
|
-
structure = _make_crystal(
|
|
470
|
+
raise ValueError("Please provide lattice_constant!")
|
|
471
|
+
# now create lattice
|
|
472
|
+
structure = _make_crystal(
|
|
473
|
+
self.lattice.lower(),
|
|
373
474
|
lattice_constant=self.lattice_constant,
|
|
374
475
|
repetitions=self.repeat,
|
|
375
|
-
element=self.element
|
|
476
|
+
element=self.element,
|
|
477
|
+
)
|
|
376
478
|
structure = structure.write.ase()
|
|
377
|
-
|
|
378
|
-
#extract composition
|
|
379
|
-
types, typecounts = np.unique(structure.get_chemical_symbols(), return_counts=True)
|
|
380
479
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
480
|
+
# extract composition
|
|
481
|
+
types, typecounts = np.unique(
|
|
482
|
+
structure.get_chemical_symbols(), return_counts=True
|
|
483
|
+
)
|
|
384
484
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
485
|
+
for c, t in enumerate(types):
|
|
486
|
+
self._element_dict[t]["count"] = typecounts[c]
|
|
487
|
+
self._element_dict[t]["composition"] = typecounts[c] / np.sum(
|
|
488
|
+
typecounts
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
# concdict_counts = {str(t): typecounts[c] for c, t in enumerate(types)}
|
|
492
|
+
# concdict_frac = {str(t): typecounts[c]/np.sum(typecounts) for c, t in enumerate(types)}
|
|
493
|
+
# self._composition = concdict_frac
|
|
494
|
+
# self._composition_counts = concdict_counts
|
|
389
495
|
self._natoms = len(structure)
|
|
390
496
|
self._original_lattice = self.lattice.lower()
|
|
391
497
|
write_structure_file = True
|
|
392
|
-
|
|
498
|
+
|
|
393
499
|
else:
|
|
394
|
-
#this is a file
|
|
500
|
+
# this is a file
|
|
395
501
|
if not os.path.exists(self.lattice):
|
|
396
|
-
raise ValueError(f
|
|
397
|
-
if self.file_format ==
|
|
398
|
-
#create atomic numbers for proper reading
|
|
399
|
-
Z_of_type = dict(
|
|
400
|
-
|
|
401
|
-
|
|
502
|
+
raise ValueError(f"File {self.lattice} could not be found")
|
|
503
|
+
if self.file_format == "lammps-data":
|
|
504
|
+
# create atomic numbers for proper reading
|
|
505
|
+
Z_of_type = dict(
|
|
506
|
+
[
|
|
507
|
+
(count + 1, self._element_dict[element]["atomic_number"])
|
|
508
|
+
for count, element in enumerate(self.element)
|
|
509
|
+
]
|
|
510
|
+
)
|
|
511
|
+
structure = read(
|
|
512
|
+
self.lattice,
|
|
513
|
+
format="lammps-data",
|
|
514
|
+
style="atomic",
|
|
515
|
+
Z_of_type=Z_of_type,
|
|
516
|
+
)
|
|
517
|
+
# structure = System(aseobj, format='ase')
|
|
518
|
+
rename_structure_file = True
|
|
402
519
|
else:
|
|
403
|
-
raise TypeError(
|
|
520
|
+
raise TypeError("Only lammps-data files are supported!")
|
|
404
521
|
|
|
405
|
-
#extract composition
|
|
406
|
-
#this is the types read in from the file
|
|
407
|
-
types, typecounts = np.unique(
|
|
522
|
+
# extract composition
|
|
523
|
+
# this is the types read in from the file
|
|
524
|
+
types, typecounts = np.unique(
|
|
525
|
+
structure.get_chemical_symbols(), return_counts=True
|
|
526
|
+
)
|
|
408
527
|
for c, t in enumerate(types):
|
|
409
|
-
self._element_dict[t][
|
|
410
|
-
self._element_dict[t][
|
|
411
|
-
|
|
528
|
+
self._element_dict[t]["count"] = typecounts[c]
|
|
529
|
+
self._element_dict[t]["composition"] = typecounts[c] / np.sum(
|
|
530
|
+
typecounts
|
|
531
|
+
)
|
|
532
|
+
|
|
412
533
|
self._natoms = len(structure)
|
|
413
534
|
self._original_lattice = os.path.basename(self.lattice)
|
|
414
535
|
self.lattice = os.path.abspath(self.lattice)
|
|
415
536
|
|
|
416
|
-
#if needed, write the file out
|
|
537
|
+
# if needed, write the file out
|
|
417
538
|
if write_structure_file:
|
|
418
|
-
structure_filename = ".".join(
|
|
539
|
+
structure_filename = ".".join(
|
|
540
|
+
[self.create_identifier(), str(self.kernel), "data"]
|
|
541
|
+
)
|
|
542
|
+
structure_filename = os.path.join(os.getcwd(), structure_filename)
|
|
543
|
+
write(structure_filename, structure, format="lammps-data")
|
|
544
|
+
self.lattice = structure_filename
|
|
545
|
+
|
|
546
|
+
if rename_structure_file:
|
|
547
|
+
structure_filename = ".".join(
|
|
548
|
+
[self.create_identifier(), str(self.kernel), "data"]
|
|
549
|
+
)
|
|
419
550
|
structure_filename = os.path.join(os.getcwd(), structure_filename)
|
|
420
|
-
|
|
551
|
+
shutil.copy(self.lattice, structure_filename)
|
|
421
552
|
self.lattice = structure_filename
|
|
422
|
-
|
|
423
|
-
if self.mode ==
|
|
424
|
-
#we also should check if actual contents are present
|
|
553
|
+
|
|
554
|
+
if self.mode == "composition_scaling":
|
|
555
|
+
# we also should check if actual contents are present
|
|
425
556
|
input_chem_comp = {}
|
|
426
557
|
for key, val in self._element_dict.items():
|
|
427
|
-
input_chem_comp[key] = val[
|
|
558
|
+
input_chem_comp[key] = val["count"]
|
|
428
559
|
self.composition_scaling._input_chemical_composition = input_chem_comp
|
|
429
560
|
|
|
430
|
-
#now we should check output chem comp and see there are no keys extra
|
|
561
|
+
# now we should check output chem comp and see there are no keys extra
|
|
431
562
|
for key in self.composition_scaling.output_chemical_composition.keys():
|
|
432
|
-
if
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
563
|
+
if (
|
|
564
|
+
key
|
|
565
|
+
not in self.composition_scaling._input_chemical_composition.keys()
|
|
566
|
+
):
|
|
567
|
+
raise ValueError(
|
|
568
|
+
"An element in output composition is not possible with the given potential"
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
natoms1 = np.sum(
|
|
572
|
+
[
|
|
573
|
+
val
|
|
574
|
+
for key, val in self.composition_scaling._input_chemical_composition.items()
|
|
575
|
+
]
|
|
576
|
+
)
|
|
577
|
+
natoms2 = np.sum(
|
|
578
|
+
[
|
|
579
|
+
val
|
|
580
|
+
for key, val in self.composition_scaling.output_chemical_composition.items()
|
|
581
|
+
]
|
|
582
|
+
)
|
|
583
|
+
if not (natoms1 == natoms2):
|
|
584
|
+
raise ValueError(
|
|
585
|
+
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}"
|
|
586
|
+
)
|
|
439
587
|
return self
|
|
440
588
|
|
|
441
|
-
def fix_paths(self, potlist):
|
|
589
|
+
def fix_paths(self, potlist):
|
|
442
590
|
"""
|
|
443
591
|
Fix paths for potential files to complete ones
|
|
444
592
|
"""
|
|
@@ -456,7 +604,7 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
456
604
|
else:
|
|
457
605
|
fixedpots.append(pot)
|
|
458
606
|
return fixedpots
|
|
459
|
-
|
|
607
|
+
|
|
460
608
|
def create_identifier(self):
|
|
461
609
|
"""
|
|
462
610
|
Generate an identifier
|
|
@@ -471,21 +619,32 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
471
619
|
identistring: string
|
|
472
620
|
unique identification string
|
|
473
621
|
"""
|
|
474
|
-
#lattice processed
|
|
622
|
+
# lattice processed
|
|
475
623
|
prefix = self.mode
|
|
476
624
|
ts = int(self._temperature)
|
|
477
625
|
if self._pressure is None:
|
|
478
626
|
ps = "None"
|
|
479
627
|
else:
|
|
480
|
-
ps = "%d"%(int(self._pressure))
|
|
628
|
+
ps = "%d" % (int(self._pressure))
|
|
481
629
|
l = self._original_lattice
|
|
482
|
-
l = l.split(
|
|
630
|
+
l = l.split("/")
|
|
483
631
|
l = l[-1]
|
|
484
|
-
|
|
632
|
+
|
|
485
633
|
if self.folder_prefix is None:
|
|
486
|
-
identistring = "-".join(
|
|
634
|
+
identistring = "-".join(
|
|
635
|
+
[prefix, l.lower(), self.reference_phase, str(ts), str(ps)]
|
|
636
|
+
)
|
|
487
637
|
else:
|
|
488
|
-
identistring = "-".join(
|
|
638
|
+
identistring = "-".join(
|
|
639
|
+
[
|
|
640
|
+
self.folder_prefix,
|
|
641
|
+
prefix,
|
|
642
|
+
l.lower(),
|
|
643
|
+
self.reference_phase,
|
|
644
|
+
str(ts),
|
|
645
|
+
str(ps),
|
|
646
|
+
]
|
|
647
|
+
)
|
|
489
648
|
return identistring
|
|
490
649
|
|
|
491
650
|
def get_folder_name(self):
|
|
@@ -509,99 +668,142 @@ class Calculation(BaseModel, title='Main input class'):
|
|
|
509
668
|
"""
|
|
510
669
|
simfolder = self.get_folder_name()
|
|
511
670
|
|
|
512
|
-
#if folder exists, delete it -> then create
|
|
671
|
+
# if folder exists, delete it -> then create
|
|
513
672
|
if os.path.exists(simfolder):
|
|
514
|
-
raise ValueError(
|
|
515
|
-
|
|
673
|
+
raise ValueError(
|
|
674
|
+
f"Simulation folder {simfolder} exists. Please remove and run again!"
|
|
675
|
+
)
|
|
676
|
+
|
|
516
677
|
os.mkdir(simfolder)
|
|
517
678
|
return simfolder
|
|
518
|
-
|
|
679
|
+
|
|
519
680
|
@property
|
|
520
681
|
def savefile(self):
|
|
521
682
|
simfolder = self.get_folder_name()
|
|
522
|
-
return os.path.join(simfolder,
|
|
683
|
+
return os.path.join(simfolder, "job.npy")
|
|
684
|
+
|
|
523
685
|
|
|
524
686
|
def save_job(job):
|
|
525
|
-
filename = os.path.join(job.simfolder,
|
|
687
|
+
filename = os.path.join(job.simfolder, "job.npy")
|
|
526
688
|
np.save(filename, job)
|
|
527
689
|
|
|
690
|
+
|
|
528
691
|
def load_job(filename):
|
|
529
692
|
job = np.load(filename, allow_pickle=True).flatten()[0]
|
|
530
693
|
return job
|
|
531
694
|
|
|
695
|
+
|
|
532
696
|
def read_inputfile(file):
|
|
533
697
|
if not os.path.exists(file):
|
|
534
|
-
raise FileNotFoundError(f
|
|
698
|
+
raise FileNotFoundError(f"Input file {file} not found.")
|
|
535
699
|
|
|
536
|
-
with open(file,
|
|
700
|
+
with open(file, "r") as fin:
|
|
537
701
|
data = yaml.safe_load(fin)
|
|
538
702
|
|
|
539
|
-
if
|
|
540
|
-
#old format
|
|
703
|
+
if "element" in data.keys():
|
|
704
|
+
# old format
|
|
541
705
|
outfile = _convert_legacy_inputfile(file)
|
|
542
706
|
else:
|
|
543
707
|
outfile = file
|
|
544
708
|
calculations = _read_inputfile(outfile)
|
|
545
|
-
return calculations
|
|
709
|
+
return calculations
|
|
710
|
+
|
|
546
711
|
|
|
547
712
|
def _read_inputfile(file):
|
|
548
|
-
with open(file,
|
|
713
|
+
with open(file, "r") as fin:
|
|
549
714
|
data = yaml.safe_load(fin)
|
|
550
715
|
calculations = []
|
|
551
|
-
for count, calc in enumerate(data[
|
|
552
|
-
calc[
|
|
553
|
-
calc[
|
|
554
|
-
if
|
|
555
|
-
calc[
|
|
716
|
+
for count, calc in enumerate(tqdm(data["calculations"])):
|
|
717
|
+
calc["kernel"] = count
|
|
718
|
+
calc["inputfile"] = file
|
|
719
|
+
if "pressure" in calc.keys():
|
|
720
|
+
calc["pressure"] = _to_none(calc["pressure"])
|
|
556
721
|
calculations.append(Calculation(**calc))
|
|
557
722
|
return calculations
|
|
558
723
|
|
|
724
|
+
|
|
559
725
|
def _convert_legacy_inputfile(file, return_calcs=False):
|
|
560
|
-
with open(file,
|
|
726
|
+
with open(file, "r") as fin:
|
|
561
727
|
data = yaml.safe_load(fin)
|
|
562
|
-
if not
|
|
563
|
-
#new format
|
|
564
|
-
raise ValueError(
|
|
728
|
+
if not "element" in data.keys():
|
|
729
|
+
# new format
|
|
730
|
+
raise ValueError("Not old format, exiting..")
|
|
565
731
|
|
|
566
|
-
#prepare combos
|
|
732
|
+
# prepare combos
|
|
567
733
|
calculations = []
|
|
568
|
-
for cc, ci in enumerate(data[
|
|
734
|
+
for cc, ci in enumerate(data["calculations"]):
|
|
569
735
|
mode = ci["mode"]
|
|
570
736
|
if mode == "melting_temperature":
|
|
571
737
|
calc = {}
|
|
572
|
-
for key in [
|
|
738
|
+
for key in [
|
|
739
|
+
"md",
|
|
740
|
+
"queue",
|
|
741
|
+
"tolerance",
|
|
742
|
+
"melting_temperature",
|
|
743
|
+
"nose_hoover",
|
|
744
|
+
"berendsen",
|
|
745
|
+
"composition_scaling",
|
|
746
|
+
"temperature_high",
|
|
747
|
+
]:
|
|
573
748
|
if key in data.keys():
|
|
574
|
-
calc[key] = copy.copy(data[key])
|
|
575
|
-
for key in [
|
|
749
|
+
calc[key] = copy.copy(data[key])
|
|
750
|
+
for key in [
|
|
751
|
+
"element",
|
|
752
|
+
"mass",
|
|
753
|
+
"script_mode",
|
|
754
|
+
"lammps_executable",
|
|
755
|
+
"mpi_executable",
|
|
756
|
+
]:
|
|
576
757
|
if key in data.keys():
|
|
577
758
|
calc[key] = data[key]
|
|
578
|
-
for key in [
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
759
|
+
for key in [
|
|
760
|
+
"mode",
|
|
761
|
+
"pair_style",
|
|
762
|
+
"pair_coeff",
|
|
763
|
+
"pair_style_options",
|
|
764
|
+
"npt",
|
|
765
|
+
"repeat",
|
|
766
|
+
"n_equilibration_steps",
|
|
767
|
+
"n_switching_steps",
|
|
768
|
+
"n_print_steps",
|
|
769
|
+
"n_iterations",
|
|
770
|
+
"potential_file",
|
|
771
|
+
"spring_constants",
|
|
772
|
+
"melting_cycle",
|
|
773
|
+
"equilibration_control",
|
|
774
|
+
"folder_prefix",
|
|
775
|
+
"temperature_high",
|
|
776
|
+
]:
|
|
582
777
|
if key in ci.keys():
|
|
583
778
|
calc[key] = ci[key]
|
|
584
779
|
|
|
585
|
-
#calc['pressure'] = float(np.atleast_1d(ci["pressure"]) if "pressure" in ci.keys() else np.atleast_1d(0))
|
|
586
|
-
#calc['temperature'] = float(np.atleast_1d(ci["temperature"]) if "temperature" in ci.keys() else np.atleast_1d(0))
|
|
587
|
-
#calc['lattice'] = str(ci["lattice"]) if "lattice" in ci.keys() else 'none'
|
|
588
|
-
#calc['reference_phase'] = str(ci["reference_phase"]) if "reference_phase" in ci.keys() else 'none'
|
|
589
|
-
#calc['lattice_constant'] = float(ci["lattice_constant"]) if "lattice_constant" in ci.keys() else 0
|
|
590
|
-
calc[
|
|
591
|
-
calc[
|
|
780
|
+
# calc['pressure'] = float(np.atleast_1d(ci["pressure"]) if "pressure" in ci.keys() else np.atleast_1d(0))
|
|
781
|
+
# calc['temperature'] = float(np.atleast_1d(ci["temperature"]) if "temperature" in ci.keys() else np.atleast_1d(0))
|
|
782
|
+
# calc['lattice'] = str(ci["lattice"]) if "lattice" in ci.keys() else 'none'
|
|
783
|
+
# calc['reference_phase'] = str(ci["reference_phase"]) if "reference_phase" in ci.keys() else 'none'
|
|
784
|
+
# calc['lattice_constant'] = float(ci["lattice_constant"]) if "lattice_constant" in ci.keys() else 0
|
|
785
|
+
calc["kernel"] = cc
|
|
786
|
+
calc["inputfile"] = file
|
|
592
787
|
calculations.append(calc)
|
|
593
788
|
|
|
594
789
|
else:
|
|
595
|
-
pressure = np.atleast_1d(ci[
|
|
596
|
-
temperature = np.atleast_1d(ci[
|
|
597
|
-
lattice = np.atleast_1d(ci[
|
|
598
|
-
reference_phase = np.atleast_1d(ci[
|
|
790
|
+
pressure = np.atleast_1d(ci["pressure"])
|
|
791
|
+
temperature = np.atleast_1d(ci["temperature"])
|
|
792
|
+
lattice = np.atleast_1d(ci["lattice"])
|
|
793
|
+
reference_phase = np.atleast_1d(ci["reference_phase"])
|
|
599
794
|
if "lattice_constant" in ci.keys():
|
|
600
795
|
lattice_constant = np.atleast_1d(ci["lattice_constant"])
|
|
601
796
|
else:
|
|
602
797
|
lattice_constant = [0 for x in range(len(lattice))]
|
|
603
798
|
|
|
604
|
-
lat_props = [
|
|
799
|
+
lat_props = [
|
|
800
|
+
{
|
|
801
|
+
"lattice": lattice[x],
|
|
802
|
+
"lattice_constant": lattice_constant[x],
|
|
803
|
+
"reference_phase": reference_phase[x],
|
|
804
|
+
}
|
|
805
|
+
for x in range(len(lattice))
|
|
806
|
+
]
|
|
605
807
|
|
|
606
808
|
if (mode == "fe") or (mode == "alchemy") or (mode == "composition_scaling"):
|
|
607
809
|
combos = itertools.product(lat_props, pressure, temperature)
|
|
@@ -619,26 +821,55 @@ def _convert_legacy_inputfile(file, return_calcs=False):
|
|
|
619
821
|
cc = 0
|
|
620
822
|
for combo in combos:
|
|
621
823
|
calc = {}
|
|
622
|
-
for key in [
|
|
824
|
+
for key in [
|
|
825
|
+
"md",
|
|
826
|
+
"queue",
|
|
827
|
+
"tolerance",
|
|
828
|
+
"melting_temperature",
|
|
829
|
+
"nose_hoover",
|
|
830
|
+
"berendsen",
|
|
831
|
+
"composition_scaling",
|
|
832
|
+
"temperature_high",
|
|
833
|
+
]:
|
|
623
834
|
if key in data.keys():
|
|
624
|
-
calc[key] = copy.copy(data[key])
|
|
625
|
-
for key in [
|
|
835
|
+
calc[key] = copy.copy(data[key])
|
|
836
|
+
for key in [
|
|
837
|
+
"element",
|
|
838
|
+
"mass",
|
|
839
|
+
"script_mode",
|
|
840
|
+
"lammps_executable",
|
|
841
|
+
"mpi_executable",
|
|
842
|
+
]:
|
|
626
843
|
if key in data.keys():
|
|
627
844
|
calc[key] = data[key]
|
|
628
|
-
for key in [
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
845
|
+
for key in [
|
|
846
|
+
"mode",
|
|
847
|
+
"pair_style",
|
|
848
|
+
"pair_coeff",
|
|
849
|
+
"pair_style_options",
|
|
850
|
+
"npt",
|
|
851
|
+
"repeat",
|
|
852
|
+
"n_equilibration_steps",
|
|
853
|
+
"n_switching_steps",
|
|
854
|
+
"n_print_steps",
|
|
855
|
+
"n_iterations",
|
|
856
|
+
"potential_file",
|
|
857
|
+
"spring_constants",
|
|
858
|
+
"melting_cycle",
|
|
859
|
+
"equilibration_control",
|
|
860
|
+
"folder_prefix",
|
|
861
|
+
"temperature_high",
|
|
862
|
+
]:
|
|
632
863
|
if key in ci.keys():
|
|
633
864
|
calc[key] = ci[key]
|
|
634
|
-
#print(combo)
|
|
865
|
+
# print(combo)
|
|
635
866
|
calc["lattice"] = str(combo[0]["lattice"])
|
|
636
867
|
calc["lattice_constant"] = float(combo[0]["lattice_constant"])
|
|
637
868
|
calc["reference_phase"] = str(combo[0]["reference_phase"])
|
|
638
869
|
calc["pressure"] = _to_float(combo[1])
|
|
639
870
|
calc["temperature"] = _to_float(combo[2])
|
|
640
|
-
calc[
|
|
641
|
-
calc[
|
|
871
|
+
calc["kernel"] = cc
|
|
872
|
+
calc["inputfile"] = file
|
|
642
873
|
cc += 1
|
|
643
874
|
calculations.append(calc)
|
|
644
875
|
|
|
@@ -646,11 +877,13 @@ def _convert_legacy_inputfile(file, return_calcs=False):
|
|
|
646
877
|
return calculations
|
|
647
878
|
else:
|
|
648
879
|
newdata = {}
|
|
649
|
-
newdata[
|
|
650
|
-
#print(newdata)
|
|
651
|
-
outfile =
|
|
652
|
-
warnings.warn(
|
|
653
|
-
|
|
880
|
+
newdata["calculations"] = calculations
|
|
881
|
+
# print(newdata)
|
|
882
|
+
outfile = "new." + file
|
|
883
|
+
warnings.warn(
|
|
884
|
+
f"Old style input file calphy < v2 found. Converted input in {outfile}. Please check!"
|
|
885
|
+
)
|
|
886
|
+
with open(outfile, "w") as fout:
|
|
654
887
|
yaml.safe_dump(newdata, fout)
|
|
655
888
|
return outfile
|
|
656
889
|
|