ion-CSP 2.0.7__py3-none-any.whl → 2.1.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.
- ion_CSP/__init__.py +16 -5
- ion_CSP/read_mlp_density.py +2 -2
- ion_CSP/task_manager.py +13 -2
- ion_CSP/vasp_processing.py +382 -15
- {ion_csp-2.0.7.dist-info → ion_csp-2.1.2.dist-info}/METADATA +15 -11
- ion_csp-2.1.2.dist-info/RECORD +28 -0
- {ion_csp-2.0.7.dist-info → ion_csp-2.1.2.dist-info}/WHEEL +1 -1
- {ion_csp-2.0.7.dist-info → ion_csp-2.1.2.dist-info}/top_level.txt +1 -0
- run/__init__.py +8 -0
- run/main_CSP.py +134 -0
- run/main_EE.py +133 -0
- run/run_convert_SMILES.py +50 -0
- run/run_empirical_estimate.py +56 -0
- run/run_gen_opt.py +66 -0
- run/run_read_mlp_density.py +43 -0
- run/run_upload_download.py +68 -0
- run/run_vasp_processing.py +43 -0
- ion_csp-2.0.7.dist-info/RECORD +0 -19
- {ion_csp-2.0.7.dist-info → ion_csp-2.1.2.dist-info}/entry_points.txt +0 -0
- {ion_csp-2.0.7.dist-info → ion_csp-2.1.2.dist-info}/licenses/LICENSE +0 -0
ion_CSP/__init__.py
CHANGED
@@ -1,8 +1,19 @@
|
|
1
|
-
|
1
|
+
__author__ = "Ze Yang"
|
2
|
+
__contact__ = "yangze1995007@163.com"
|
3
|
+
__license__ = "MIT"
|
4
|
+
__version__ = "2.1.2"
|
5
|
+
__date__ = "2025-06-09"
|
6
|
+
|
2
7
|
|
3
8
|
try:
|
4
|
-
|
5
|
-
except
|
6
|
-
|
9
|
+
from importlib.metadata import version # python >= 3.11
|
10
|
+
except Exception:
|
11
|
+
try:
|
12
|
+
from importlib_metadata import version
|
13
|
+
except Exception:
|
14
|
+
pass
|
7
15
|
|
8
|
-
|
16
|
+
try:
|
17
|
+
__version__ = version("ion_CSP")
|
18
|
+
except Exception:
|
19
|
+
pass
|
ion_CSP/read_mlp_density.py
CHANGED
@@ -81,8 +81,8 @@ class ReadMlpDensity:
|
|
81
81
|
os.makedirs(self.max_density_dir, exist_ok=True)
|
82
82
|
for density, CONTCAR_filename in sorted_filename[:n_screen]:
|
83
83
|
# 生成新的包含密度值的文件名,并重命名文件
|
84
|
-
# 密度转换为字符串,保留
|
85
|
-
density_str = f'{density:.
|
84
|
+
# 密度转换为字符串,保留3位小数
|
85
|
+
density_str = f'{density:.3f}'
|
86
86
|
mlp_densities.append(density_str)
|
87
87
|
# 保留 CONTCAR 的序数信息,方便回推检查
|
88
88
|
number = CONTCAR_filename.split("_")[1]
|
ion_CSP/task_manager.py
CHANGED
@@ -47,6 +47,9 @@ class TaskManager:
|
|
47
47
|
self.env = "DOCKER"
|
48
48
|
self.workspace = Path("/app")
|
49
49
|
self.log_dir = Path("/app/logs")
|
50
|
+
conda_env = os.getenv("CONDA_DEFAULT_ENV")
|
51
|
+
env_msg = conda_env if conda_env else "Not Conda Env"
|
52
|
+
self.envs = f"{self.env} ({env_msg})"
|
50
53
|
self.workspace.mkdir(exist_ok=True)
|
51
54
|
|
52
55
|
def _setup_logging(self):
|
@@ -224,8 +227,13 @@ class TaskManager:
|
|
224
227
|
console_log = work_dir / f"main_{module}_console.log"
|
225
228
|
pid_file = work_dir / "pid.txt"
|
226
229
|
|
230
|
+
# 动态加载模块
|
231
|
+
module_name = f"run.main_{module}"
|
232
|
+
spec = importlib.util.find_spec(module_name)
|
233
|
+
if not spec:
|
234
|
+
raise ImportError(f"Module {module_name} not found")
|
227
235
|
# 启动子进程
|
228
|
-
cmd = [
|
236
|
+
cmd = [sys.executable, "-m", module_name, str(work_dir)]
|
229
237
|
|
230
238
|
with open(console_log, "w") as f:
|
231
239
|
process = subprocess.Popen(
|
@@ -271,6 +279,9 @@ class TaskManager:
|
|
271
279
|
continue
|
272
280
|
try:
|
273
281
|
file_path = log_file.resolve(strict=True)
|
282
|
+
if not os.path.exists(file_path):
|
283
|
+
os.remove(log_file)
|
284
|
+
continue
|
274
285
|
mtime = file_path.stat().st_mtime
|
275
286
|
log_tasks.append({
|
276
287
|
"pid": 0, # 日志无PID
|
@@ -358,7 +369,7 @@ class TaskManager:
|
|
358
369
|
os.system("clear" if os.name == "posix" else "cls")
|
359
370
|
print("========== Task Execution Sys1tem ==========")
|
360
371
|
print(f"Current Version: {self.version}")
|
361
|
-
print(f"Current Environment: {self.
|
372
|
+
print(f"Current Environment: {self.envs}")
|
362
373
|
print(f"Current Directory: {self.workspace}")
|
363
374
|
print(f"Log Base Directory: {self.log_dir}")
|
364
375
|
print("=" * 50)
|
ion_CSP/vasp_processing.py
CHANGED
@@ -20,7 +20,7 @@ class VaspProcessing:
|
|
20
20
|
self.vasp_optimized_dir = f"{work_dir}/4_vasp_optimized"
|
21
21
|
self.param_dir = os.path.join(os.path.dirname(__file__), "../../param")
|
22
22
|
|
23
|
-
def
|
23
|
+
def dpdisp_vasp_optimization_tasks(
|
24
24
|
self,
|
25
25
|
machine: str,
|
26
26
|
resources: str,
|
@@ -72,7 +72,7 @@ class VaspProcessing:
|
|
72
72
|
"POTCAR_C",
|
73
73
|
"POTCAR_N",
|
74
74
|
"POTCAR_O",
|
75
|
-
"
|
75
|
+
"sub_ori.sh",
|
76
76
|
]
|
77
77
|
backward_files = ["log", "err"]
|
78
78
|
# 将所有参数文件各复制一份到每个 task_dir 目录下
|
@@ -93,7 +93,7 @@ class VaspProcessing:
|
|
93
93
|
)
|
94
94
|
|
95
95
|
remote_task_dir = f"{parent}pop{pop}"
|
96
|
-
command = "chmod +x
|
96
|
+
command = "chmod +x sub_ori.sh && ./sub_ori.sh"
|
97
97
|
task = Task(
|
98
98
|
command=command,
|
99
99
|
task_work_path=remote_task_dir,
|
@@ -139,7 +139,240 @@ class VaspProcessing:
|
|
139
139
|
shutil.rmtree(os.path.join(self.for_vasp_opt_dir, parent))
|
140
140
|
logging.info("Batch VASP optimization completed!!!")
|
141
141
|
|
142
|
-
def
|
142
|
+
def dpdisp_vasp_relaxation_tasks(
|
143
|
+
self,
|
144
|
+
machine: str,
|
145
|
+
resources: str,
|
146
|
+
nodes: int = 1,
|
147
|
+
):
|
148
|
+
"""
|
149
|
+
Based on the dpdispatcher module, prepare and submit files for optimization on remote server or local machine.
|
150
|
+
"""
|
151
|
+
# 调整工作目录,减少错误发生
|
152
|
+
os.chdir(self.vasp_optimized_dir)
|
153
|
+
# 读取machine.json和resources.json的参数
|
154
|
+
if machine.endswith(".json"):
|
155
|
+
machine = Machine.load_from_json(machine)
|
156
|
+
elif machine.endswith(".yaml"):
|
157
|
+
machine = Machine.load_from_yaml(machine)
|
158
|
+
else:
|
159
|
+
raise KeyError("Not supported machine file type")
|
160
|
+
if resources.endswith(".json"):
|
161
|
+
resources = Resources.load_from_json(resources)
|
162
|
+
elif resources.endswith(".yaml"):
|
163
|
+
resources = Resources.load_from_yaml(resources)
|
164
|
+
else:
|
165
|
+
raise KeyError("Not supported resources file type")
|
166
|
+
# 由于dpdispatcher对于远程服务器以及本地运行的forward_common_files的默认存放位置不同,因此需要预先进行判断,从而不改动优化脚本
|
167
|
+
machine_inform = machine.serialize()
|
168
|
+
if machine_inform["context_type"] == "SSHContext":
|
169
|
+
# 如果调用远程服务器,则创建二级目录
|
170
|
+
parent = "data/"
|
171
|
+
elif machine_inform["context_type"] == "LocalContext":
|
172
|
+
# 如果在本地运行作业,则只在后续创建一级目录
|
173
|
+
parent = ""
|
174
|
+
|
175
|
+
# 获取dir文件夹中所有以prefix_name开头的文件,在此实例中为POSCAR_
|
176
|
+
vasp_optimized_folders = [
|
177
|
+
f
|
178
|
+
for f in os.listdir(self.vasp_optimized_dir)
|
179
|
+
if os.path.isdir(f) and f != "data"
|
180
|
+
]
|
181
|
+
# 创建一个嵌套列表来存储每个节点的任务并将文件平均依次分配给每个节点
|
182
|
+
# 例如:对于10个结构文件任务分发给4个节点的情况,则4个节点领到的任务分别[0, 4, 8], [1, 5, 9], [2, 6], [3, 7]
|
183
|
+
node_jobs = [[] for _ in range(nodes)]
|
184
|
+
for index, file in enumerate(vasp_optimized_folders):
|
185
|
+
node_index = index % nodes
|
186
|
+
node_jobs[node_index].append(index)
|
187
|
+
task_list = []
|
188
|
+
for pop in range(nodes):
|
189
|
+
forward_files = [
|
190
|
+
"INCAR_3",
|
191
|
+
"POTCAR_H",
|
192
|
+
"POTCAR_C",
|
193
|
+
"POTCAR_N",
|
194
|
+
"POTCAR_O",
|
195
|
+
"sub_supple.sh",
|
196
|
+
]
|
197
|
+
backward_files = ["log", "err"]
|
198
|
+
# 将所有参数文件各复制一份到每个 task_dir 目录下
|
199
|
+
task_dir = os.path.join(self.vasp_optimized_dir, f"{parent}pop{pop}")
|
200
|
+
os.makedirs(task_dir, exist_ok=True)
|
201
|
+
for file in forward_files:
|
202
|
+
shutil.copyfile(f"{self.param_dir}/{file}", f"{task_dir}/{file}")
|
203
|
+
for job_i in node_jobs[pop]:
|
204
|
+
# 将分配好的POSCAR文件添加到对应的上传文件中
|
205
|
+
vasp_dir = vasp_optimized_folders[job_i]
|
206
|
+
fine_optimized_file = f"{vasp_dir}/fine/CONTCAR"
|
207
|
+
forward_files.append(fine_optimized_file)
|
208
|
+
os.makedirs(
|
209
|
+
os.path.dirname(f"{task_dir}/{fine_optimized_file}"), exist_ok=True
|
210
|
+
)
|
211
|
+
shutil.copyfile(
|
212
|
+
f"{self.vasp_optimized_dir}/{fine_optimized_file}",
|
213
|
+
f"{task_dir}/{fine_optimized_file}",
|
214
|
+
)
|
215
|
+
# 每个POSCAR文件在优化后都取回对应的CONTCAR和OUTCAR输出文件
|
216
|
+
backward_files.append(f"{vasp_dir}/*")
|
217
|
+
backward_files.append(f"{vasp_dir}/fine/*")
|
218
|
+
backward_files.append(f"{vasp_dir}/fine/final/*")
|
219
|
+
|
220
|
+
remote_task_dir = f"{parent}pop{pop}"
|
221
|
+
command = "chmod +x sub_supple.sh && ./sub_supple.sh"
|
222
|
+
task = Task(
|
223
|
+
command=command,
|
224
|
+
task_work_path=remote_task_dir,
|
225
|
+
forward_files=forward_files,
|
226
|
+
backward_files=backward_files,
|
227
|
+
)
|
228
|
+
task_list.append(task)
|
229
|
+
|
230
|
+
submission = Submission(
|
231
|
+
work_base=self.vasp_optimized_dir,
|
232
|
+
machine=machine,
|
233
|
+
resources=resources,
|
234
|
+
task_list=task_list,
|
235
|
+
)
|
236
|
+
submission.run_submission()
|
237
|
+
|
238
|
+
for pop in range(nodes):
|
239
|
+
# 从传回的 pop 文件夹中将结果文件取到 4_vasp_optimized 目录
|
240
|
+
task_dir = os.path.join(self.vasp_optimized_dir, f"{parent}pop{pop}")
|
241
|
+
for job_i in node_jobs[pop]:
|
242
|
+
vasp_dir = vasp_optimized_folders[job_i]
|
243
|
+
shutil.copytree(
|
244
|
+
f"{task_dir}/{vasp_dir}/fine/final",
|
245
|
+
f"{self.vasp_optimized_dir}/{vasp_dir}/fine/final",
|
246
|
+
)
|
247
|
+
# 在成功完成 VASP 分步优化后,删除 4_vasp_optimized /{parent}/pop{n} 文件夹以节省空间
|
248
|
+
shutil.rmtree(task_dir)
|
249
|
+
if machine_inform["context_type"] == "SSHContext":
|
250
|
+
# 如果调用远程服务器,则删除data级目录
|
251
|
+
shutil.rmtree(os.path.join(self.vasp_optimized_dir, parent))
|
252
|
+
logging.info("Batch VASP optimization completed!!!")
|
253
|
+
|
254
|
+
def dpdisp_vasp_complete_tasks(
|
255
|
+
self,
|
256
|
+
machine: str,
|
257
|
+
resources: str,
|
258
|
+
nodes: int = 1,
|
259
|
+
):
|
260
|
+
"""
|
261
|
+
Based on the dpdispatcher module, prepare and submit files for optimization on remote server or local machine.
|
262
|
+
"""
|
263
|
+
# 调整工作目录,减少错误发生
|
264
|
+
os.chdir(self.for_vasp_opt_dir)
|
265
|
+
# 读取machine.json和resources.json的参数
|
266
|
+
if machine.endswith(".json"):
|
267
|
+
machine = Machine.load_from_json(machine)
|
268
|
+
elif machine.endswith(".yaml"):
|
269
|
+
machine = Machine.load_from_yaml(machine)
|
270
|
+
else:
|
271
|
+
raise KeyError("Not supported machine file type")
|
272
|
+
if resources.endswith(".json"):
|
273
|
+
resources = Resources.load_from_json(resources)
|
274
|
+
elif resources.endswith(".yaml"):
|
275
|
+
resources = Resources.load_from_yaml(resources)
|
276
|
+
else:
|
277
|
+
raise KeyError("Not supported resources file type")
|
278
|
+
# 由于dpdispatcher对于远程服务器以及本地运行的forward_common_files的默认存放位置不同,因此需要预先进行判断,从而不改动优化脚本
|
279
|
+
machine_inform = machine.serialize()
|
280
|
+
if machine_inform["context_type"] == "SSHContext":
|
281
|
+
# 如果调用远程服务器,则创建二级目录
|
282
|
+
parent = "data/"
|
283
|
+
elif machine_inform["context_type"] == "LocalContext":
|
284
|
+
# 如果在本地运行作业,则只在后续创建一级目录
|
285
|
+
parent = ""
|
286
|
+
|
287
|
+
# 获取dir文件夹中所有以prefix_name开头的文件,在此实例中为POSCAR_
|
288
|
+
mlp_contcar_files = [
|
289
|
+
f for f in os.listdir(self.for_vasp_opt_dir) if f.startswith("CONTCAR_")
|
290
|
+
]
|
291
|
+
# 创建一个嵌套列表来存储每个节点的任务并将文件平均依次分配给每个节点
|
292
|
+
# 例如:对于10个结构文件任务分发给4个节点的情况,则4个节点领到的任务分别[0, 4, 8], [1, 5, 9], [2, 6], [3, 7]
|
293
|
+
node_jobs = [[] for _ in range(nodes)]
|
294
|
+
for index, file in enumerate(mlp_contcar_files):
|
295
|
+
node_index = index % nodes
|
296
|
+
node_jobs[node_index].append(index)
|
297
|
+
task_list = []
|
298
|
+
for pop in range(nodes):
|
299
|
+
forward_files = [
|
300
|
+
"INCAR_1",
|
301
|
+
"INCAR_2",
|
302
|
+
"INCAR_3",
|
303
|
+
"POTCAR_H",
|
304
|
+
"POTCAR_C",
|
305
|
+
"POTCAR_N",
|
306
|
+
"POTCAR_O",
|
307
|
+
"sub_final.sh",
|
308
|
+
]
|
309
|
+
backward_files = ["log", "err"]
|
310
|
+
# 将所有参数文件各复制一份到每个 task_dir 目录下
|
311
|
+
task_dir = os.path.join(self.for_vasp_opt_dir, f"{parent}pop{pop}")
|
312
|
+
os.makedirs(task_dir, exist_ok=True)
|
313
|
+
for file in forward_files:
|
314
|
+
shutil.copyfile(f"{self.param_dir}/{file}", f"{task_dir}/{file}")
|
315
|
+
for job_i in node_jobs[pop]:
|
316
|
+
# 将分配好的POSCAR文件添加到对应的上传文件中
|
317
|
+
forward_files.append(mlp_contcar_files[job_i])
|
318
|
+
vasp_dir = mlp_contcar_files[job_i].split("CONTCAR_")[1]
|
319
|
+
# 每个POSCAR文件在优化后都取回对应的CONTCAR和OUTCAR输出文件
|
320
|
+
backward_files.append(f"{vasp_dir}/*")
|
321
|
+
backward_files.append(f"{vasp_dir}/fine/*")
|
322
|
+
backward_files.append(f"{vasp_dir}/fine/final/*")
|
323
|
+
shutil.copyfile(
|
324
|
+
f"{self.for_vasp_opt_dir}/{mlp_contcar_files[job_i]}",
|
325
|
+
f"{task_dir}/{mlp_contcar_files[job_i]}",
|
326
|
+
)
|
327
|
+
|
328
|
+
remote_task_dir = f"{parent}pop{pop}"
|
329
|
+
command = "chmod +x sub_final.sh && ./sub_final.sh"
|
330
|
+
task = Task(
|
331
|
+
command=command,
|
332
|
+
task_work_path=remote_task_dir,
|
333
|
+
forward_files=forward_files,
|
334
|
+
backward_files=backward_files,
|
335
|
+
)
|
336
|
+
task_list.append(task)
|
337
|
+
|
338
|
+
submission = Submission(
|
339
|
+
work_base=self.for_vasp_opt_dir,
|
340
|
+
machine=machine,
|
341
|
+
resources=resources,
|
342
|
+
task_list=task_list,
|
343
|
+
)
|
344
|
+
submission.run_submission()
|
345
|
+
|
346
|
+
# 创建用于存放优化后文件的 4_vasp_optimized 目录
|
347
|
+
os.makedirs(self.vasp_optimized_dir, exist_ok=True)
|
348
|
+
mlp_outcar_files = [
|
349
|
+
f for f in os.listdir(self.for_vasp_opt_dir) if f.startswith("OUTCAR_")
|
350
|
+
]
|
351
|
+
for mlp_contcar, mlp_outcar in zip(mlp_contcar_files, mlp_outcar_files):
|
352
|
+
shutil.copyfile(
|
353
|
+
f"{self.for_vasp_opt_dir}/{mlp_contcar}",
|
354
|
+
f"{self.vasp_optimized_dir}/{mlp_contcar}",
|
355
|
+
)
|
356
|
+
shutil.copyfile(
|
357
|
+
f"{self.for_vasp_opt_dir}/{mlp_outcar}",
|
358
|
+
f"{self.vasp_optimized_dir}/{mlp_outcar}",
|
359
|
+
)
|
360
|
+
for pop in range(nodes):
|
361
|
+
# 从传回的 pop 文件夹中将结果文件取到 4_vasp_optimized 目录
|
362
|
+
task_dir = os.path.join(self.for_vasp_opt_dir, f"{parent}pop{pop}")
|
363
|
+
for job_i in node_jobs[pop]:
|
364
|
+
vasp_dir = mlp_contcar_files[job_i].split("CONTCAR_")[1]
|
365
|
+
shutil.copytree(
|
366
|
+
f"{task_dir}/{vasp_dir}", f"{self.vasp_optimized_dir}/{vasp_dir}"
|
367
|
+
)
|
368
|
+
# 在成功完成 VASP 分步优化后,删除 3_for_vasp_opt/{parent}/pop{n} 文件夹以节省空间
|
369
|
+
shutil.rmtree(task_dir)
|
370
|
+
if machine_inform["context_type"] == "SSHContext":
|
371
|
+
# 如果调用远程服务器,则删除data级目录
|
372
|
+
shutil.rmtree(os.path.join(self.for_vasp_opt_dir, parent))
|
373
|
+
logging.info("Batch VASP optimization completed!!!")
|
374
|
+
|
375
|
+
def read_vaspout_save_csv(self, molecules_prior: bool, relaxation: bool = False):
|
143
376
|
"""
|
144
377
|
Read VASP output files in batches and save energy and density to corresponding CSV files in the directory
|
145
378
|
"""
|
@@ -148,6 +381,7 @@ class VaspProcessing:
|
|
148
381
|
numbers, mlp_densities, mlp_energies = [], [], []
|
149
382
|
rough_densities, rough_energies = [], []
|
150
383
|
fine_densities, fine_energies = [], []
|
384
|
+
final_densities, final_energies = [], []
|
151
385
|
ions_checks, packing_coefficients = [], []
|
152
386
|
for folder in os.listdir(vasp_opt_dir):
|
153
387
|
vasp_opt_path = os.path.join(vasp_opt_dir, folder)
|
@@ -166,7 +400,7 @@ class VaspProcessing:
|
|
166
400
|
for line in lines:
|
167
401
|
if "TOTEN" in line:
|
168
402
|
values = line.split()
|
169
|
-
mlp_energy = round(float(values[-2]),
|
403
|
+
mlp_energy = round(float(values[-2]), 1)
|
170
404
|
except FileNotFoundError:
|
171
405
|
logging.error(
|
172
406
|
f" No avalible MLP OUTCAR_{mlp_density}_{number} found"
|
@@ -180,8 +414,8 @@ class VaspProcessing:
|
|
180
414
|
rough_atoms.get_masses()
|
181
415
|
) # 质量单位为原子质量单位(amu)
|
182
416
|
# 1.66054这一转换因子用于将原子质量单位转换为克,以便在宏观尺度上计算密度g/cm³
|
183
|
-
rough_density = round(1.66054 * atoms_masses / atoms_volume,
|
184
|
-
rough_energy = round(rough_atoms.get_total_energy(),
|
417
|
+
rough_density = round(1.66054 * atoms_masses / atoms_volume, 3)
|
418
|
+
rough_energy = round(rough_atoms.get_total_energy(), 1)
|
185
419
|
logging.info(
|
186
420
|
f" MLP_Density: {mlp_density}, MLP_Energy: {mlp_energy}"
|
187
421
|
)
|
@@ -211,9 +445,9 @@ class VaspProcessing:
|
|
211
445
|
) # 质量单位为原子质量单位(amu)
|
212
446
|
# 1.66054这一转换因子用于将原子质量单位转换为克,以便在宏观尺度上计算密度g/cm³
|
213
447
|
fine_density = round(
|
214
|
-
1.66054 * fine_atoms_masses / fine_atoms_volume,
|
448
|
+
1.66054 * fine_atoms_masses / fine_atoms_volume, 3
|
215
449
|
)
|
216
|
-
fine_energy = round(fine_atoms.get_total_energy(),
|
450
|
+
fine_energy = round(fine_atoms.get_total_energy(), 1)
|
217
451
|
logging.info(
|
218
452
|
f" Fine_Density: {fine_density}, Fine_Energy: {fine_energy}"
|
219
453
|
)
|
@@ -226,6 +460,49 @@ class VaspProcessing:
|
|
226
460
|
)
|
227
461
|
fine_density, fine_energy, molecules_flag = False, False, False
|
228
462
|
|
463
|
+
final_density, final_energy = (
|
464
|
+
False,
|
465
|
+
False,
|
466
|
+
)
|
467
|
+
if relaxation:
|
468
|
+
# 读取三级目录下的 OUTCAR 文件
|
469
|
+
final_OUTCAR_file_path = os.path.join(
|
470
|
+
vasp_opt_path, "fine", "final", "OUTCAR"
|
471
|
+
)
|
472
|
+
try:
|
473
|
+
final_atoms = read_vasp_out(final_OUTCAR_file_path)
|
474
|
+
molecules, molecules_flag, initial_information = (
|
475
|
+
identify_molecules(final_atoms)
|
476
|
+
)
|
477
|
+
if not initial_information:
|
478
|
+
raise KeyError("No available initial molecules")
|
479
|
+
final_atoms_volume = (
|
480
|
+
final_atoms.get_volume()
|
481
|
+
) # 体积单位为立方埃(ų)
|
482
|
+
final_atoms_masses = sum(
|
483
|
+
final_atoms.get_masses()
|
484
|
+
) # 质量单位为原子质量单位(amu)
|
485
|
+
# 1.66054这一转换因子用于将原子质量单位转换为克,以便在宏观尺度上计算密度g/cm³
|
486
|
+
final_density = round(
|
487
|
+
1.66054 * final_atoms_masses / final_atoms_volume, 3
|
488
|
+
)
|
489
|
+
final_energy = round(final_atoms.get_total_energy(), 1)
|
490
|
+
logging.info(
|
491
|
+
f" Final_Density: {final_density}, Final_Energy: {final_energy}"
|
492
|
+
)
|
493
|
+
molecules_information(
|
494
|
+
molecules, molecules_flag, initial_information
|
495
|
+
)
|
496
|
+
except (ParseError, FileNotFoundError):
|
497
|
+
logging.error(
|
498
|
+
f" Unfinished final optimization job of CONTCAR_{mlp_density}_{number}"
|
499
|
+
)
|
500
|
+
final_density, final_energy, molecules_flag = (
|
501
|
+
False,
|
502
|
+
False,
|
503
|
+
False,
|
504
|
+
)
|
505
|
+
|
229
506
|
# 读取根目录下的 config.yaml 信息与对应的 .json 文件
|
230
507
|
config_path = os.path.join(self.base_dir, "config.yaml")
|
231
508
|
with open(config_path, "r") as file:
|
@@ -242,9 +519,14 @@ class VaspProcessing:
|
|
242
519
|
property = json.load(file)
|
243
520
|
molecular_volume = float(property["volume"])
|
244
521
|
molecular_volumes += molecular_volume * count
|
245
|
-
|
246
|
-
|
247
|
-
|
522
|
+
if relaxation:
|
523
|
+
packing_coefficient = round(
|
524
|
+
molecular_volumes / final_atoms_volume, 3
|
525
|
+
)
|
526
|
+
else:
|
527
|
+
packing_coefficient = round(
|
528
|
+
molecular_volumes / fine_atoms_volume, 3
|
529
|
+
)
|
248
530
|
except (FileNotFoundError, UnboundLocalError):
|
249
531
|
packing_coefficient = False
|
250
532
|
|
@@ -253,6 +535,8 @@ class VaspProcessing:
|
|
253
535
|
rough_energies.append(rough_energy)
|
254
536
|
fine_densities.append(fine_density)
|
255
537
|
fine_energies.append(fine_energy)
|
538
|
+
final_densities.append(final_density)
|
539
|
+
final_energies.append(final_energy)
|
256
540
|
ions_checks.append(molecules_flag)
|
257
541
|
packing_coefficients.append(packing_coefficient)
|
258
542
|
|
@@ -273,6 +557,19 @@ class VaspProcessing:
|
|
273
557
|
"Fine_Density",
|
274
558
|
"Ions_Check",
|
275
559
|
]
|
560
|
+
if relaxation:
|
561
|
+
header = [
|
562
|
+
"Number",
|
563
|
+
"MLP_E",
|
564
|
+
"Rough_E",
|
565
|
+
"Fine_E",
|
566
|
+
"Final_E",
|
567
|
+
"MLP_Density",
|
568
|
+
"Rough_Density",
|
569
|
+
"Fine_Density",
|
570
|
+
"Final_Density",
|
571
|
+
"Ions_Check",
|
572
|
+
]
|
276
573
|
if packing_coefficients:
|
277
574
|
header.append("Pack_Coef")
|
278
575
|
datas = list(
|
@@ -288,12 +585,82 @@ class VaspProcessing:
|
|
288
585
|
(*packing_coefficients,) if packing_coefficients else (),
|
289
586
|
)
|
290
587
|
)
|
588
|
+
if relaxation:
|
589
|
+
datas = list(
|
590
|
+
zip(
|
591
|
+
numbers,
|
592
|
+
mlp_energies,
|
593
|
+
rough_energies,
|
594
|
+
fine_energies,
|
595
|
+
final_energies,
|
596
|
+
mlp_densities,
|
597
|
+
rough_densities,
|
598
|
+
fine_densities,
|
599
|
+
final_densities,
|
600
|
+
ions_checks,
|
601
|
+
(*packing_coefficients,) if packing_coefficients else (),
|
602
|
+
)
|
603
|
+
)
|
291
604
|
if molecules_prior:
|
292
|
-
# 如果设置了 molecules_prior 参数为 True
|
293
|
-
datas.sort(key=lambda x: (not x[
|
605
|
+
# 如果设置了 molecules_prior 参数为 True,则优先第倒数Ions_Check 为 True 的结果,再根据第6列的 Fine_Density 降序排序
|
606
|
+
datas.sort(key=lambda x: (not x[-2], -float(x[-3])))
|
294
607
|
else:
|
295
608
|
# 否则,直接根据第6列(从0列开始)的 Fine_Density 降序排序
|
296
|
-
datas.sort(key=lambda x: -float(x[
|
609
|
+
datas.sort(key=lambda x: -float(x[-3]))
|
297
610
|
writer.writerow(header)
|
298
611
|
for data in datas:
|
299
612
|
writer.writerow(data)
|
613
|
+
|
614
|
+
def export_max_density_structure(self):
|
615
|
+
"""
|
616
|
+
Read the structure number from the vasp_sensitiy_energy.csv file in the results folder, then search for the corresponding folder based on that sequence number, copy the highest density and highest precision CONTCAR file, and rename it POSCAR
|
617
|
+
"""
|
618
|
+
# 找到 vas_density_energy.csv 文件
|
619
|
+
csv_file_path = os.path.join(self.base_dir, "vasp_density_energy.csv")
|
620
|
+
if os.path.exists(csv_file_path):
|
621
|
+
# 读取 CSV 文件
|
622
|
+
with open(csv_file_path, "r") as csvfile:
|
623
|
+
reader = csv.reader(csvfile)
|
624
|
+
# 跳过表头读取第一行结构序号,即符合结构筛选要求的最大密度结构
|
625
|
+
first_row = next(reader)
|
626
|
+
structure_number = str(first_row[0])
|
627
|
+
# 根据结构序号构建要查找的文件夹路径
|
628
|
+
vasp_optimized_dir = os.path.join(self.base_dir, "4_vasp_optimized")
|
629
|
+
for vasp_folder_name in os.listdir(vasp_optimized_dir):
|
630
|
+
vasp_folder_path = os.path.join(vasp_optimized_dir, vasp_folder_name)
|
631
|
+
if os.path.isdir(vasp_folder_path) and vasp_folder_name.endswith(
|
632
|
+
structure_number
|
633
|
+
):
|
634
|
+
# 查找 CONTCAR 文件
|
635
|
+
final_contcar_path = os.path.join(
|
636
|
+
vasp_folder_path, "fine", "final", "CONTCAR"
|
637
|
+
)
|
638
|
+
fine_contcar_path = os.path.join(
|
639
|
+
vasp_folder_path, "fine", "CONTCAR"
|
640
|
+
)
|
641
|
+
logging.info(
|
642
|
+
f"Trying to get the final structure from {vasp_folder_path}"
|
643
|
+
)
|
644
|
+
if os.path.exists(final_contcar_path):
|
645
|
+
# 复制 CONTCAR 文件到 combo_n 文件夹并重命名为 POSCAR
|
646
|
+
shutil.copy(
|
647
|
+
final_contcar_path, os.path.join(self.base_dir, "POSCAR")
|
648
|
+
)
|
649
|
+
logging.info(
|
650
|
+
f"Renamed CONTCAR to POSCAR in {self.base_dir}, copied from {final_contcar_path}"
|
651
|
+
)
|
652
|
+
elif os.path.exists(fine_contcar_path):
|
653
|
+
logging.info(
|
654
|
+
f"CONTCAR not found in {os.path.join(vasp_folder_path, 'fine', 'final')}"
|
655
|
+
)
|
656
|
+
# 复制 CONTCAR 文件到 combo_n 文件夹并重命名为 POSCAR
|
657
|
+
shutil.copy(
|
658
|
+
fine_contcar_path, os.path.join(self.base_dir, "POSCAR")
|
659
|
+
)
|
660
|
+
logging.info(
|
661
|
+
f"Renamed CONTCAR to POSCAR in {self.base_dir}, copied from {fine_contcar_path}"
|
662
|
+
)
|
663
|
+
else:
|
664
|
+
print(f"Eligible CONTCAR not found in {vasp_folder_path}")
|
665
|
+
else:
|
666
|
+
logging.info(f"CSV file not found in {self.base_dir}")
|
@@ -1,12 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ion_CSP
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.1.2
|
4
4
|
Summary: Crystal Structure Design Software Based on Molecular/Ionic Configuration.
|
5
5
|
Home-page: https://github.com/bagabaga007/ion_CSP
|
6
6
|
Author: Ze Yang
|
7
7
|
Author-email: Ze Yang <yangze1995007@163.com>
|
8
|
-
License
|
9
|
-
Keywords:
|
8
|
+
License: MIT
|
9
|
+
Keywords: Ion_Crystal, Crystal_Structure_Prediction
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
11
|
Classifier: Operating System :: OS Independent
|
12
12
|
Requires-Python: >=3.11
|
@@ -27,10 +27,10 @@ Dynamic: home-page
|
|
27
27
|
Dynamic: license-file
|
28
28
|
Dynamic: requires-python
|
29
29
|
|
30
|
-
# Crystal Structure Design Software V2.
|
30
|
+
# Crystal Structure Design Software V2.1
|
31
31
|
|
32
32
|
## 项目概述
|
33
|
-
|
33
|
+
基于分子/离子构型的晶体结构设计软件通过结合经验公式、机器学习势函数微调、第一性原理分步优化和分子/离子识别技术,实现了从分子/离子构型出发的高效晶体结构设计。该软件采用模块化设计,支持全流程自动化材料筛选,在保证预测精度的同时显著提升计算效率。
|
34
34
|
|
35
35
|
## 功能特性
|
36
36
|
### 核心功能
|
@@ -76,7 +76,9 @@ python -m venv venv
|
|
76
76
|
source venv/bin/activate # Linux/Mac
|
77
77
|
|
78
78
|
# 安装依赖
|
79
|
-
|
79
|
+
git clone https://github.com/Bagabaga007/ion_CSP.git
|
80
|
+
cd ion_CSP
|
81
|
+
pip install -e .
|
80
82
|
```
|
81
83
|
|
82
84
|
## 快速入门
|
@@ -127,15 +129,15 @@ graph TD
|
|
127
129
|
|
128
130
|
## 技术支持
|
129
131
|
- **文档更新**:2025年5月
|
130
|
-
- **最新版本**:v2.0
|
132
|
+
- **最新版本**:v2.1.0
|
131
133
|
- **问题追踪**:https://github.com/bagabaga007/ion_CSP/issues
|
132
134
|
|
133
135
|
---
|
134
136
|
|
135
|
-
# Crystal Structure Design Software V2.
|
137
|
+
# Crystal Structure Design Software V2.1
|
136
138
|
|
137
139
|
## Project Overview
|
138
|
-
This software enables efficient crystal structure
|
140
|
+
This software enables efficient crystal structure design from molecular/ion configurations by integrating empirical formulas, tuned machine learning potentials, stepwise first-principles optimization, and molecular/ion recognition techniques. The modular architecture ensures extensibility and maintainability while maintaining prediction accuracy.
|
139
141
|
|
140
142
|
## Key Features
|
141
143
|
### Core Functionalities
|
@@ -181,7 +183,9 @@ python -m venv venv
|
|
181
183
|
source venv/bin/activate # Linux/Mac
|
182
184
|
|
183
185
|
# Install dependencies
|
184
|
-
|
186
|
+
git clone https://github.com/Bagabaga007/ion_CSP.git
|
187
|
+
cd ion_CSP
|
188
|
+
pip install -e .
|
185
189
|
```
|
186
190
|
|
187
191
|
## Quick Start
|
@@ -232,5 +236,5 @@ MIT License, see LICENSE file.
|
|
232
236
|
|
233
237
|
## Support
|
234
238
|
- Documentation last updated: May 2025
|
235
|
-
- Latest version: v2.0
|
239
|
+
- Latest version: v2.1.0
|
236
240
|
- Issue tracker: https://github.com/bagabaga007/ion_CSP/issues
|
@@ -0,0 +1,28 @@
|
|
1
|
+
ion_CSP/__init__.py,sha256=hYxxDupiYyKqFBRl78HzhGiku8nFYpnk1GujZQaInXk,374
|
2
|
+
ion_CSP/__main__.py,sha256=XlNCx5eMSrL7yld9ddSYXhjXvg2ZYGD_uk9LdqNabvs,74
|
3
|
+
ion_CSP/convert_SMILES.py,sha256=4fndMcuIEypYtkXWBoS7W7uEXkZXVLeMDshdXEIk5kY,13864
|
4
|
+
ion_CSP/empirical_estimate.py,sha256=_U5VRWSIAiJGcxnP3mnCHn8zKzviFEQhQwN7TjPTnCU,29089
|
5
|
+
ion_CSP/gen_opt.py,sha256=aVZmf2RqePCwZShgpNvzqfntNAW0I0yctWHGXoe3mgw,19463
|
6
|
+
ion_CSP/identify_molecules.py,sha256=hFKXS0Jjd7LyMsYGc9RmnoRPu1ibXF9fYO_9lR3wTfo,4634
|
7
|
+
ion_CSP/log_and_time.py,sha256=6RKegXF8Gc1HqzAbE-PT9ejX3Ncyuz3v3FivujJt8to,9072
|
8
|
+
ion_CSP/mlp_opt.py,sha256=ox4Qxg4D6WzrB8dxVnUWmAngnOA_wdcInP5UhBWsH4c,5535
|
9
|
+
ion_CSP/read_mlp_density.py,sha256=3N7kgM2RCe1gbP8QxpgtwYRaj77w4niNglWA5VDoQsk,11209
|
10
|
+
ion_CSP/steps_opt_monitor.sh,sha256=1klPjnK0gqkDbvI9PtjdK5qidJ5G0Mo8q1SfrlLW5xM,3330
|
11
|
+
ion_CSP/task_manager.py,sha256=SdpmpQS6q-ZdnMpwrGrquX6dQjT0UBsAoP7_eG5_DdE,16728
|
12
|
+
ion_CSP/upload_download.py,sha256=Hiz5jKOy9x26hJJdcpt-owQdVUbzzGuGOelro6JozY8,23801
|
13
|
+
ion_CSP/vasp_processing.py,sha256=TshMNs7fA0zABvk4sKlVjofJFwGH9DVYcCGbcUpoH1s,31542
|
14
|
+
ion_csp-2.1.2.dist-info/licenses/LICENSE,sha256=2J6A8GT2iIf2LhuWO1_0ilgx7ijzzpQ2BXU7rHKe8Cc,1068
|
15
|
+
run/__init__.py,sha256=_9EAXp4cv41ARbxahCkihwqY4F00Y18tBeTauWeD9mw,186
|
16
|
+
run/main_CSP.py,sha256=qR3SVZVwJwudnrIDypJrtCAYGzFswL3UGsYRBRMcaxs,5936
|
17
|
+
run/main_EE.py,sha256=8gazhe-JzvygbSIqxVITmums2E5McRnld6QB3Us2i5s,6373
|
18
|
+
run/run_convert_SMILES.py,sha256=sngOyse2pdSsWGZhOTVNtlb2Bg9uBFL4qejpgKu38Gs,2094
|
19
|
+
run/run_empirical_estimate.py,sha256=D1600cl9isiglhWk528nmvfD7Zh6YBawrrc9x8LpKww,2869
|
20
|
+
run/run_gen_opt.py,sha256=xert_S4urD0lkGjOO2hX2T3aD3UPzt39GWQVkqzxUGI,2765
|
21
|
+
run/run_read_mlp_density.py,sha256=1QSRlOWEVpEnoGL4jIR3t-73V9dM4_pu6FtD9aisLH0,1902
|
22
|
+
run/run_upload_download.py,sha256=rX82igeAWssmx-qaU8i45VezxtZvY3wDKlrT1a_2i3Y,2528
|
23
|
+
run/run_vasp_processing.py,sha256=JqliNn-Qan89byUbgJAKRbRVHjZ9CwCixkD1YUTaHj8,1650
|
24
|
+
ion_csp-2.1.2.dist-info/METADATA,sha256=3lXbX3oY09e3y51j2ORdVcnb7pOISQNY-3e0r7lfrVk,6488
|
25
|
+
ion_csp-2.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
26
|
+
ion_csp-2.1.2.dist-info/entry_points.txt,sha256=NexQJDs9f69kJA2DgoU6tsA3V8a66nadJRem1U_c_6g,54
|
27
|
+
ion_csp-2.1.2.dist-info/top_level.txt,sha256=Vp0RHefYscYU7uQ4Fu6bOKhC_ASrdGOzZxYfN5r0f2M,12
|
28
|
+
ion_csp-2.1.2.dist-info/RECORD,,
|