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/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