ion-CSP 2.1.4__py3-none-any.whl → 2.1.8__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.
Files changed (42) hide show
  1. ion_CSP/__init__.py +2 -2
  2. ion_CSP/convert_SMILES.py +32 -10
  3. ion_CSP/empirical_estimate.py +136 -18
  4. ion_CSP/gen_opt.py +83 -33
  5. ion_CSP/identify_molecules.py +15 -0
  6. ion_CSP/log_and_time.py +55 -8
  7. ion_CSP/mlp_opt.py +52 -6
  8. ion_CSP/model/model.pt +0 -0
  9. ion_CSP/model/options/README.md +5 -0
  10. ion_CSP/model/options/model.ckpt-4000000.pt +0 -0
  11. ion_CSP/param/INCAR_0 +16 -0
  12. ion_CSP/param/INCAR_1 +19 -0
  13. ion_CSP/param/INCAR_2 +19 -0
  14. ion_CSP/param/INCAR_3 +19 -0
  15. ion_CSP/param/POTCAR_C +2319 -0
  16. ion_CSP/param/POTCAR_H +1563 -0
  17. ion_CSP/param/POTCAR_N +2351 -0
  18. ion_CSP/param/POTCAR_O +2487 -0
  19. ion_CSP/param/g16_sub.sh +21 -0
  20. ion_CSP/param/sub_final.sh +91 -0
  21. ion_CSP/param/sub_ori.sh +74 -0
  22. ion_CSP/param/sub_supple.sh +56 -0
  23. ion_CSP/read_mlp_density.py +15 -1
  24. ion_CSP/task_manager.py +2 -2
  25. ion_CSP/upload_download.py +0 -1
  26. ion_CSP/vasp_processing.py +48 -20
  27. {ion_csp-2.1.4.dist-info → ion_csp-2.1.8.dist-info}/METADATA +45 -16
  28. ion_csp-2.1.8.dist-info/RECORD +43 -0
  29. {ion_csp-2.1.4.dist-info → ion_csp-2.1.8.dist-info}/licenses/LICENSE +1 -1
  30. {ion_csp-2.1.4.dist-info → ion_csp-2.1.8.dist-info}/top_level.txt +0 -1
  31. ion_csp-2.1.4.dist-info/RECORD +0 -28
  32. {run → ion_CSP/run}/__init__.py +0 -0
  33. {run → ion_CSP/run}/main_CSP.py +0 -0
  34. {run → ion_CSP/run}/main_EE.py +0 -0
  35. {run → ion_CSP/run}/run_convert_SMILES.py +0 -0
  36. {run → ion_CSP/run}/run_empirical_estimate.py +0 -0
  37. {run → ion_CSP/run}/run_gen_opt.py +0 -0
  38. {run → ion_CSP/run}/run_read_mlp_density.py +0 -0
  39. {run → ion_CSP/run}/run_upload_download.py +0 -0
  40. {run → ion_CSP/run}/run_vasp_processing.py +0 -0
  41. {ion_csp-2.1.4.dist-info → ion_csp-2.1.8.dist-info}/WHEEL +0 -0
  42. {ion_csp-2.1.4.dist-info → ion_csp-2.1.8.dist-info}/entry_points.txt +0 -0
ion_CSP/log_and_time.py CHANGED
@@ -11,7 +11,14 @@ from dpdispatcher.dlog import dlog
11
11
 
12
12
 
13
13
  def log_and_time(func):
14
- """Decorator for recording log information and script runtime"""
14
+ """
15
+ Decorator for recording log information and script runtime
16
+
17
+ :params
18
+ func: The function to be decorated
19
+
20
+ :return: The decorated function with logging and timing capabilities
21
+ """
15
22
  @functools.wraps(func)
16
23
  def wrapper(work_dir, *args, **kwargs):
17
24
  # 使用inspect获取真实脚本文件名
@@ -54,20 +61,49 @@ def log_and_time(func):
54
61
 
55
62
 
56
63
  def merge_config(default_config, user_config, key):
64
+ """
65
+ Merge default configuration with user-provided configuration for a specific key.
66
+
67
+ :params
68
+ default_config: The default configuration dictionary.
69
+ user_config: The user-provided configuration dictionary.
70
+ key: The key for which the configuration should be merged.
71
+
72
+ :return: A merged configuration dictionary for the specified key.
73
+ """
74
+ if key not in default_config:
75
+ raise KeyError(f"Key '{key}' not found in default configuration.")
76
+ if key not in user_config:
77
+ raise KeyError(f"Key '{key}' not found in user configuration.")
78
+ if not isinstance(default_config[key], dict) or not isinstance(user_config.get(key, {}), dict):
79
+ raise TypeError(f"Both default and user configurations for '{key}' must be dictionaries.")
80
+ # 合并两个参数配置,优先使用用户参数配置
57
81
  return {**default_config[key], **user_config.get(key, {})}
58
82
 
59
83
 
60
84
  class StatusLogger:
85
+ """
86
+ A singleton class to log the status of a workflow, including RUNNING, SUCCESS, FAILURE, and KILLED.
87
+ It initializes a logger that writes to a log file and a YAML file to record the status of the workflow.
88
+ The logger captures the process ID and handles termination signals (SIGINT, SIGTERM).
89
+ """
90
+ _name = "WorkflowLogger"
61
91
  _instance = None
62
92
 
63
93
  def __new__(cls, *args, **kwargs):
94
+ """Ensure that only one instance of StatusLogger is created (Singleton Pattern)"""
64
95
  if not cls._instance:
65
96
  cls._instance = super(StatusLogger, cls).__new__(cls)
66
97
  cls._instance.__init__(*args, **kwargs)
67
98
  return cls._instance
68
99
 
69
100
  def __init__(self, work_dir, task_name):
70
- """Initialize workflow status logger and generate the .log and .yaml file to record the status"""
101
+ """
102
+ Initialize workflow status logger and generate the .log and .yaml file to record the status
103
+
104
+ :params
105
+ work_dir: The working directory where the log and yaml files will be created
106
+ task_name: The name of the task to be logged"""
71
107
  # 使用单例模式,避免重复的日志记录,缺点是再重新给定task_name之后会覆盖原来的实例,只能顺序调用
72
108
  self.task_name = task_name
73
109
  log_file = os.path.join(work_dir, "workflow_status.log")
@@ -97,12 +133,17 @@ class StatusLogger:
97
133
  self._init_yaml()
98
134
 
99
135
  def set_running(self):
136
+ """
137
+ Set the current task status to RUNNING and log the event.
138
+ This method increments the run count and updates the YAML file.
139
+ """
100
140
  self.current_status = "RUNNING"
101
141
  self.logger.info(f"{self.task_name} Status: {self.current_status}")
102
142
  self.run_count += 1
103
143
  self._update_yaml()
104
144
 
105
145
  def set_success(self):
146
+ """Set the current task status to SUCCESS and log the event"""
106
147
  self.current_status = "SUCCESS"
107
148
  self.logger.info(f"{self.task_name} Status: {self.current_status}\n")
108
149
  self._update_yaml()
@@ -112,12 +153,16 @@ class StatusLogger:
112
153
  return self.current_status == "SUCCESS"
113
154
 
114
155
  def set_failure(self):
156
+ """Set the current task status to FAILURE and log the event"""
115
157
  self.current_status = "FAILURE"
116
158
  self.logger.error(f"{self.task_name} Status: {self.current_status}\n")
117
159
  self._update_yaml()
118
160
 
119
161
  def _signal_handler(self, signum, _):
120
- """Handle termination signals and log the event"""
162
+ """
163
+ Handle termination signals and log the event
164
+ :params
165
+ signum: The signal number received (e.g., SIGINT, SIGTERM)"""
121
166
  if signum == 2:
122
167
  self.logger.warning(
123
168
  f"Process {os.getpid()} has been interrupted by 'Ctrl + C'\n"
@@ -134,6 +179,7 @@ class StatusLogger:
134
179
  sys.exit(0)
135
180
 
136
181
  def _set_killed(self):
182
+ """Set the current task status to KILLED and log the event"""
137
183
  self.current_status = "KILLED"
138
184
  self.logger.warning(f"{self.task_name} Status: {self.current_status}\n")
139
185
  self._update_yaml()
@@ -193,11 +239,12 @@ def redirect_dpdisp_logging(custom_log_path):
193
239
 
194
240
 
195
241
  def get_work_dir_and_config():
196
- """获取工作目录并加载配置文件
197
- Returns:
198
- tuple: (工作目录路径, 合并后的配置字典)
199
- Raises:
200
- SystemExit: 当输入无效时退出程序
242
+ """
243
+ Get the working directory and user configuration from command line arguments or interactive input.
244
+ If the working directory is not specified, it prompts the user to input it interactively.
245
+ It also reads the configuration from a 'config.yaml' file in the specified directory.
246
+
247
+ :return: A tuple containing the working directory and the user configuration dictionary.
201
248
  """
202
249
  parser = argparse.ArgumentParser(
203
250
  description="The full workflow of ionic crystal design for a certain ion combination, including generation, mlp optimization, screening, vasp optimization and analysis."
ion_CSP/mlp_opt.py CHANGED
@@ -14,13 +14,22 @@ base_dir = os.path.dirname(__file__)
14
14
  relative_path = './model.pt'
15
15
  file_path = os.path.join(base_dir, relative_path)
16
16
  calc = DP(file_path)
17
- '''
17
+ """
18
18
  structure optimization with DP model and ASE
19
19
  PSTRESS and fmax should exist in input.dat
20
- '''
20
+ """
21
21
 
22
22
  def get_element_num(elements):
23
- '''Using the Atoms.symples to Know Element&Num'''
23
+ """
24
+ Using the Atoms.symples to Know Element and Number
25
+
26
+ :params
27
+ elements: list of elements in the structure
28
+
29
+ :returns
30
+ element: list of unique elements in the structure
31
+ ele: dictionary with elements as keys and their counts as values
32
+ """
24
33
  element = []
25
34
  ele = {}
26
35
  element.append(elements[0])
@@ -32,7 +41,15 @@ def get_element_num(elements):
32
41
  return element, ele
33
42
 
34
43
  def write_CONTCAR(element, ele, lat, pos, index):
35
- '''Write CONTCAR'''
44
+ """
45
+ Write CONTCAR file in VASP format
46
+
47
+ :params
48
+ element: list of elements in the structure
49
+ ele: dictionary of element counts
50
+ lat: lattice vectors
51
+ pos: atomic positions in direct coordinates
52
+ index: index for the output file"""
36
53
  f = open(f'{base_dir}/CONTCAR_'+str(index),'w')
37
54
  f.write('ASE-DPKit-Optimization\n')
38
55
  f.write('1.0\n')
@@ -51,7 +68,21 @@ def write_CONTCAR(element, ele, lat, pos, index):
51
68
  f.write('%15.10f %15.10f %15.10f\n' % tuple(dpos[i]))
52
69
 
53
70
  def write_OUTCAR(element, ele, masses, volume, lat, pos, ene, force, stress, pstress, index):
54
- '''Write OUTCAR'''
71
+ """
72
+ Write OUTCAR file in VASP format
73
+ :params
74
+ element: list of elements in the structure
75
+ ele: dictionary of element counts
76
+ masses: total mass of the atoms
77
+ volume: volume of the unit cell
78
+ lat: lattice vectors
79
+ pos: atomic positions in direct coordinates
80
+ ene: total energy of the system
81
+ force: forces on the atoms
82
+ stress: stress tensor components
83
+ pstress: external pressure
84
+ index: index for the output file
85
+ """
55
86
  f = open(f'{base_dir}/OUTCAR_'+str(index),'w')
56
87
  for x in element:
57
88
  f.write('VRHFIN =' + str(x) + '\n')
@@ -88,6 +119,13 @@ def write_OUTCAR(element, ele, masses, volume, lat, pos, ene, force, stress, pst
88
119
  f.write('enthalpy TOTEN = %20.6f %20.6f\n' % (enthalpy, enthalpy/na))
89
120
 
90
121
  def get_indexes():
122
+ """
123
+ Get the indexes of POSCAR files in the current directory.
124
+ This function scans the current directory for files starting with 'POSCAR_' and extracts their numeric indexes.
125
+
126
+ :returns
127
+ A sorted list of indexes extracted from the POSCAR files.
128
+ """
91
129
  base_dir = os.path.dirname(__file__)
92
130
  POSCAR_files = [f for f in os.listdir(base_dir) if f.startswith('POSCAR_')]
93
131
  indexes = []
@@ -100,7 +138,11 @@ def get_indexes():
100
138
  return indexes
101
139
 
102
140
  def run_opt(index: int):
103
- '''Using the ASE&DP to Optimize Configures'''
141
+ """
142
+ Using the ASE&DP to Optimize Configures
143
+ :params
144
+ index: index of the POSCAR file to be optimized
145
+ """
104
146
  if os.path.isfile(f'{base_dir}/OUTCAR'):
105
147
  os.system(f'mv {base_dir}/OUTCAR {base_dir}/OUTCAR-last')
106
148
  fmax, pstress = 0.03, 0
@@ -143,6 +185,10 @@ def run_opt(index: int):
143
185
 
144
186
 
145
187
  def main():
188
+ """
189
+ Main function to run the optimization in parallel.
190
+ It initializes a multiprocessing pool and maps the run_opt function to the indexes of POSCAR files.
191
+ """
146
192
  ctx=multiprocessing.get_context("spawn")
147
193
  pool=ctx.Pool(8)
148
194
  indexes = get_indexes()
ion_CSP/model/model.pt ADDED
Binary file
@@ -0,0 +1,5 @@
1
+ # 目录 ./model
2
+ 用于存放所调用的机器学习势文件,文件名必须为 model.pt。
3
+
4
+ # 目录 ./model/options
5
+ 用于存放其他机器学习势文件,文件名任意。
ion_CSP/param/INCAR_0 ADDED
@@ -0,0 +1,16 @@
1
+ SYSTEM = ION_CSP
2
+ NPAR = 4
3
+ PREC = Accurate
4
+ ENCUT = 800
5
+ EDIFF = 1e-4 # 1e-6
6
+ IBRION = -1
7
+ ISMEAR = 0 ; SIGMA = 0.05
8
+ #No writing charge density and wavefunction
9
+ LCHARG = FALSE
10
+ LWAVE = FALSE
11
+ #Target Pressure
12
+ #PSTRESS = 100
13
+ #Finer optimization
14
+ EDIFFG = -0.05 # 1e-4
15
+ KSPACING = 0.25
16
+ IVDW = 11
ion_CSP/param/INCAR_1 ADDED
@@ -0,0 +1,19 @@
1
+ SYSTEM = ION_CSP
2
+ NPAR = 4
3
+ PREC = Accurate
4
+ ENCUT = 600 # 800
5
+ EDIFF = 1e-4 # 1e-6
6
+ IBRION = 2
7
+ ISIF = 8
8
+ NSW = 300 # 200
9
+ ISMEAR = 0 ; SIGMA = 0.05
10
+ POTIM = 0.05
11
+ #No writing charge density and wavefunction
12
+ LCHARG = FALSE
13
+ LWAVE = FALSE
14
+ #Target Pressure
15
+ #PSTRESS = 100
16
+ #Finer optimization
17
+ EDIFFG = -0.05 # 1e-4
18
+ KSPACING = 0.7 # 0.25
19
+ IVDW = 12
ion_CSP/param/INCAR_2 ADDED
@@ -0,0 +1,19 @@
1
+ SYSTEM = ION_CSP
2
+ NPAR = 4
3
+ PREC = Accurate
4
+ ENCUT = 800
5
+ EDIFF = 1e-6
6
+ IBRION = 2
7
+ ISIF = 8
8
+ NSW = 300 # 200
9
+ ISMEAR = 0 ; SIGMA = 0.05
10
+ POTIM = 0.05
11
+ #No writing charge density and wavefunction
12
+ LCHARG = FALSE
13
+ LWAVE = FALSE
14
+ #Target Pressure
15
+ #PSTRESS = 100
16
+ #Finer optimization
17
+ EDIFFG = -0.02
18
+ KSPACING = 0.5
19
+ IVDW = 12
ion_CSP/param/INCAR_3 ADDED
@@ -0,0 +1,19 @@
1
+ SYSTEM = ION_CSP
2
+ NPAR = 4
3
+ PREC = Accurate
4
+ ENCUT = 800
5
+ EDIFF = 1e-6
6
+ IBRION = 2
7
+ ISIF = 3
8
+ NSW = 300 # 200
9
+ ISMEAR = 0 ; SIGMA = 0.05
10
+ POTIM = 0.05
11
+ #No writing charge density and wavefunction
12
+ LCHARG = FALSE
13
+ LWAVE = FALSE
14
+ #Target Pressure
15
+ #PSTRESS = 100
16
+ #Finer optimization
17
+ EDIFFG = -0.02
18
+ KSPACING = 0.5
19
+ IVDW = 12