ion-CSP 2.0.8__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.
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.6.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
run/__init__.py ADDED
@@ -0,0 +1,8 @@
1
+ from importlib.metadata import version, PackageNotFoundError
2
+
3
+ try:
4
+ __version__ = version("binary4fun")
5
+ except PackageNotFoundError:
6
+ __version__ = "unknown version"
7
+
8
+ name = "run"
run/main_CSP.py ADDED
@@ -0,0 +1,134 @@
1
+ import os
2
+ import logging
3
+ from ion_CSP.gen_opt import CrystalGenerator
4
+ from ion_CSP.read_mlp_density import ReadMlpDensity
5
+ from ion_CSP.vasp_processing import VaspProcessing
6
+ from ion_CSP.log_and_time import StatusLogger
7
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
8
+
9
+ # 默认配置
10
+ DEFAULT_CONFIG = {
11
+ "gen_opt": {
12
+ "num_per_group": 500, # 每个空间群要生成的晶体结构数量
13
+ "space_groups_limit": 230, # 空间群搜索的限制
14
+ "nodes": 1, # 机器学习势优化占用 GPU 节点数
15
+ },
16
+ "read_mlp_density": {
17
+ "n_screen": 10, # 筛选机器学习势优化后密度最大的n个CONTCAR与对应的OUTCAR
18
+ "molecules_screen": True, # 是否排除离子改变的晶体结构
19
+ "detail_log": False, # 是否额外生成详细的筛选日志文件
20
+ },
21
+ "vasp_processing": {
22
+ "nodes": 2, # VASP 分步优化占用 CPU 节点数
23
+ "molecules_prior": True, # 是否检查离子晶体结构中所有离子的结构
24
+ },
25
+ }
26
+
27
+
28
+ @log_and_time
29
+ def main(work_dir, config):
30
+ logging.info(f"Using config: {config}")
31
+ tasks = {
32
+ "1_generation": lambda: generation_task(work_dir, config),
33
+ "1_optimization": lambda: mlp_optimization_task(work_dir, config),
34
+ "2_read_mlp_density": lambda: read_mlp_density_task(work_dir, config),
35
+ "3_vasp_optimization": lambda: vasp_optimization_task(work_dir, config),
36
+ "3_vasp_relaxation": lambda: vasp_relaxation_task(work_dir, config),
37
+ }
38
+ for task_name, task_func in tasks.items():
39
+ task_logger = StatusLogger(work_dir=work_dir, task_name=task_name)
40
+ if not task_logger.is_successful():
41
+ try:
42
+ task_logger.set_running()
43
+ task_func()
44
+ task_logger.set_success()
45
+ except Exception:
46
+ task_logger.set_failure()
47
+ raise
48
+ logging.info(f"All tasks have been run successfully, including {tasks.keys()}")
49
+
50
+
51
+ def generation_task(work_dir, config):
52
+ generator = CrystalGenerator(
53
+ work_dir=work_dir,
54
+ ion_numbers=config["gen_opt"]["ion_numbers"],
55
+ species=config["gen_opt"]["species"],
56
+ )
57
+ # 根据提供的离子与对应的配比,使用 pyxtal 基于晶体空间群进行离子晶体结构的随机生成。
58
+ generator.generate_structures(
59
+ num_per_group=config["gen_opt"]["num_per_group"],
60
+ space_groups_limit=config["gen_opt"]["space_groups_limit"],
61
+ )
62
+ # 使用 phonopy 生成对称化的原胞另存于 primitive_cell 文件夹中,降低后续优化的复杂性,同时检查原子数以防止 pyxtal 生成双倍比例的超胞。
63
+ generator.phonopy_processing()
64
+
65
+
66
+ def mlp_optimization_task(work_dir, config):
67
+ generator = CrystalGenerator(
68
+ work_dir=work_dir,
69
+ ion_numbers=config["gen_opt"]["ion_numbers"],
70
+ species=config["gen_opt"]["species"],
71
+ )
72
+ # 基于 dpdispatcher 模块,在远程GPU服务器上批量准备并提交输入文件,并在任务结束后回收机器学习势优化的输出文件 OUTCAR 与 CONTCAR
73
+ generator.dpdisp_mlp_tasks(
74
+ machine=config["gen_opt"]["machine"],
75
+ resources=config["gen_opt"]["resources"],
76
+ nodes=config["gen_opt"]["nodes"],
77
+ )
78
+
79
+
80
+ def read_mlp_density_task(work_dir, config):
81
+ # 分析处理机器学习势优化得到的CONTCAR文件
82
+ mlp_result = ReadMlpDensity(work_dir=work_dir)
83
+ # 读取密度数据,根据离子是否成键进行筛选,并将前n个最大密度的文件保存到max_density文件夹
84
+ mlp_result.read_density_and_sort(
85
+ n_screen=config["read_mlp_density"]["n_screen"],
86
+ molecules_screen=config["read_mlp_density"]["molecules_screen"],
87
+ detail_log=config["read_mlp_density"]["detail_log"],
88
+ )
89
+ # 将max_density文件夹中的结构文件利用 phononpy 模块进行对称化处理,方便后续对于结构的查看,同时不影响晶胞性质
90
+ mlp_result.phonopy_processing_max_density()
91
+
92
+
93
+ def vasp_optimization_task(work_dir, config):
94
+ # VASP分步固定晶胞角度优化处理
95
+ vasp_result = VaspProcessing(work_dir=work_dir)
96
+ # 基于 dpdispatcher 模块,在远程CPU服务器上批量准备并提交VASP分步优化任务
97
+ vasp_result.dpdisp_vasp_optimization_tasks(
98
+ machine=config["vasp_processing"]["machine"],
99
+ resources=config["vasp_processing"]["resources"],
100
+ nodes=config["vasp_processing"]["nodes"],
101
+ )
102
+ # 批量读取 VASP 分步优化的输出文件,并将能量和密度等结果保存到目录中的相应CSV文件
103
+ vasp_result.read_vaspout_save_csv(
104
+ molecules_prior=config["vasp_processing"]["molecules_prior"]
105
+ )
106
+
107
+
108
+ def vasp_relaxation_task(work_dir, config):
109
+ # VASP无约束晶胞优化处理
110
+ vasp_result = VaspProcessing(work_dir=work_dir)
111
+ # 基于 dpdispatcher 模块,在远程CPU服务器上批量准备并提交VASP分步优化任务
112
+ vasp_result.dpdisp_vasp_relaxation_tasks(
113
+ machine=config["vasp_processing"]["machine"],
114
+ resources=config["vasp_processing"]["resources"],
115
+ nodes=config["vasp_processing"]["nodes"],
116
+ )
117
+ # 批量读取 VASP 分步优化的输出文件,并将能量和密度等结果保存到目录中的相应CSV文件
118
+ vasp_result.read_vaspout_save_csv(
119
+ molecules_prior=config["vasp_processing"]["molecules_prior"], relaxation=True
120
+ )
121
+ vasp_result.export_max_density_structure()
122
+
123
+
124
+ if __name__ == "__main__":
125
+ # 获取工作目录和配置
126
+ work_dir, config = get_work_dir_and_config()
127
+ # 合并配置(假设有merge_config函数)
128
+ modules = ["gen_opt", "read_mlp_density", "vasp_processing"]
129
+ for module in modules:
130
+ config[module] = merge_config(
131
+ default_config=DEFAULT_CONFIG, user_config=config, key=module
132
+ )
133
+ # 调用主函数
134
+ main(os.path.basename(__file__), work_dir, config)
run/main_EE.py ADDED
@@ -0,0 +1,133 @@
1
+ import os
2
+ import logging
3
+ from ion_CSP.convert_SMILES import SmilesProcessing
4
+ from ion_CSP.empirical_estimate import EmpiricalEstimation
5
+ from ion_CSP.log_and_time import StatusLogger
6
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
7
+
8
+ # 默认配置
9
+ DEFAULT_CONFIG = {
10
+ "convert_SMILES": {
11
+ "csv_file": "", # 默认CSV文件名
12
+ "screen": False, # 默认不进行筛选
13
+ "charge_screen": "", # 默认电荷筛选为空
14
+ "group_screen": "", # 默认官能团筛选为空
15
+ "group_name": "", # 默认分组名称
16
+ "group_screen_invert": False, # 默认不进行反向筛选
17
+ },
18
+ "empirical_estimate": {
19
+ "folders": [], # 默认文件夹列表
20
+ "ratios": [], # 默认离子配比
21
+ "sort_by": "density", # 默认排序方式
22
+ "make_combo_dir": True, # 默认不创建组合目录
23
+ "target_dir": "", # 默认目标目录
24
+ "num_combos": 100, # 默认组合数量
25
+ "ion_numbers": [], # 默认离子数量
26
+ "update": True, # 默认每次运行都会更新组合文件夹
27
+ },
28
+ }
29
+
30
+
31
+ @log_and_time
32
+ def main(work_dir, config):
33
+ logging.info(f"Using config: {config}")
34
+ empirical_estimate_dir = os.path.join(work_dir, "1_2_Gaussian_optimized")
35
+ tasks = {
36
+ "0_convertion": lambda: convertion_task(work_dir, config),
37
+ "0_estimation": lambda: estimation_task(empirical_estimate_dir, config),
38
+ "0_update_combo": lambda: combination_task(empirical_estimate_dir, config),
39
+ }
40
+ for task_name, task_func in tasks.items():
41
+ task_logger = StatusLogger(work_dir=work_dir, task_name=task_name)
42
+ if not task_logger.is_successful():
43
+ try:
44
+ task_logger.set_running()
45
+ task_func()
46
+ task_logger.set_success()
47
+ except Exception:
48
+ task_logger.set_failure()
49
+ raise
50
+
51
+ if config["empirical_estimate"]["update"]:
52
+ task_logger = StatusLogger(work_dir=work_dir, task_name="0_update_combo")
53
+ try:
54
+ task_logger.set_running()
55
+ combination_task(empirical_estimate_dir, config)
56
+ task_logger.set_success()
57
+ except Exception:
58
+ task_logger.set_failure()
59
+ raise
60
+
61
+ def convertion_task(work_dir, config):
62
+ # 给定与脚本同目录的csv文件名
63
+ convertion = SmilesProcessing(
64
+ work_dir=work_dir, csv_file=config["convert_SMILES"]["csv_file"]
65
+ )
66
+ # 根据电荷进行分组创建文件夹并将SMILES码转换为对应的结构文件
67
+ convertion.charge_group()
68
+ if config["convert_SMILES"]["screen"]:
69
+ # 根据提供的官能团和电荷进行筛选, 在本数据集中硝基的SMILES码为[N+](=O)[O-]
70
+ convertion.screen(
71
+ charge_screen=config["convert_SMILES"]["charge_screen"],
72
+ group_screen=config["convert_SMILES"]["group_screen"],
73
+ group_name=config["convert_SMILES"]["group_name"],
74
+ group_screen_invert=config["convert_SMILES"]["group_screen_invert"],
75
+ )
76
+ # 基于 dpdispatcher 模块,在远程CPU服务器上批量准备并提交Gaussian优化任务
77
+ convertion.dpdisp_gaussian_tasks(
78
+ # 注意,此处需要人为指定文件夹以避免浪费计算资源,默认通过empirical_estimate中的folders来确定
79
+ folders=config["empirical_estimate"]["folders"],
80
+ machine=config["convert_SMILES"]["machine"],
81
+ resources=config["convert_SMILES"]["resources"],
82
+ nodes=config["convert_SMILES"]["nodes"],
83
+ )
84
+
85
+ def estimation_task(work_dir, config):
86
+ # 在工作目录下准备 Gaussian 优化处理后具有 .gjf、.fchk 和 .log 文件的文件夹, 并提供对应的离子配比
87
+ estimation = EmpiricalEstimation(
88
+ work_dir=work_dir,
89
+ folders=config["empirical_estimate"]["folders"],
90
+ ratios=config["empirical_estimate"]["ratios"],
91
+ sort_by=config["empirical_estimate"]["sort_by"],
92
+ )
93
+ # 对 .fchk 文件用 Multiwfn 进行静电势分析, 并将经验公式所需的分析结果保存到同名 JSON 文件中
94
+ estimation.multiwfn_process_fchk_to_json()
95
+ # 由于后续晶体生成不支持 .log 文件,需要将 Gaussian 优化得到的 .log 文件最后一帧转为 .gjf 结构文件
96
+ estimation.gaussian_log_to_optimized_gjf()
97
+ # 如果依据密度排序,则需要经验公式根据配比生成离子晶体组合,读取 .json 文件并将静电势分析得到的各离子性质代入经验公式
98
+ if config["empirical_estimate"]["sort_by"] == "density":
99
+ # 最终将预测的离子晶体密度以及对应的组分输出到 .csv 文件并根据密度从大到小排序
100
+ estimation.empirical_estimate()
101
+ # 如果依据氮含量排序,则调用另一套根据 .gjf 文件中化学分布信息
102
+ elif config["empirical_estimate"]["sort_by"] == "nitrogen":
103
+ # 最终将预测的离子晶体氮含量以及对应的组分输出到 .csv 文件并根据氮含量从大到小排序
104
+ estimation.nitrogen_content_estimate()
105
+
106
+ def combination_task(work_dir, config):
107
+ # 在工作目录下准备 Gaussian 优化处理后具有 .gjf、.fchk 和 .log 文件的文件夹, 并提供对应的离子配比
108
+ combination = EmpiricalEstimation(
109
+ work_dir=work_dir,
110
+ folders=config["empirical_estimate"]["folders"],
111
+ ratios=config["empirical_estimate"]["ratios"],
112
+ sort_by=config["empirical_estimate"]["sort_by"],
113
+ )
114
+ # 基于排序依据 sort_by 对应的 .csv 文件创建 combo_n 文件夹,并复制相应的 .gjf 结构文件。
115
+ if config["empirical_estimate"]["make_combo_dir"]:
116
+ combination.make_combo_dir(
117
+ target_dir=config["empirical_estimate"]["target_dir"],
118
+ num_combos=config["empirical_estimate"]["num_combos"],
119
+ ion_numbers=config["empirical_estimate"]["ion_numbers"],
120
+ )
121
+
122
+
123
+ if __name__ == "__main__":
124
+ # 获取工作目录和配置
125
+ work_dir, config = get_work_dir_and_config()
126
+ # 合并配置(假设有merge_config函数)
127
+ modules = ["convert_SMILES", "empirical_estimate"]
128
+ for module in modules:
129
+ config[module] = merge_config(
130
+ default_config=DEFAULT_CONFIG, user_config=config, key=module
131
+ )
132
+ # 调用主函数
133
+ main(os.path.basename(__file__), work_dir, config)
@@ -0,0 +1,50 @@
1
+ import os
2
+ from ion_CSP.convert_SMILES import SmilesProcessing
3
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
4
+
5
+ # 默认配置
6
+ DEFAULT_CONFIG = {
7
+ "convert_SMILES": {
8
+ "csv_file": "", # 默认CSV文件名
9
+ "screen": False, # 默认不进行筛选
10
+ "charge_screen": "", # 默认电荷筛选为空
11
+ "group_screen": "", # 默认官能团筛选为空
12
+ "group_name": "", # 默认分组名称
13
+ "group_screen_invert": False, # 默认不进行反向筛选
14
+ }
15
+ }
16
+
17
+ @log_and_time
18
+ def main(work_dir, config):
19
+ # 给定与脚本同目录的csv文件名
20
+ result = SmilesProcessing(
21
+ work_dir=work_dir,
22
+ csv_file=config["convert_SMILES"]["csv_file"]
23
+ )
24
+ # 根据电荷进行分组创建文件夹并将SMILES码转换为对应的结构文件
25
+ result.charge_group()
26
+ if config["convert_SMILES"]["screen"]:
27
+ # 根据提供的官能团和电荷进行筛选, 在本数据集中硝基的SMILES码为[N+](=O)[O-]
28
+ result.screen(
29
+ charge_screen=config["convert_SMILES"]["charge_screen"],
30
+ group_screen=config["convert_SMILES"]["group_screen"],
31
+ group_name=config["convert_SMILES"]["group_name"],
32
+ group_screen_invert=config["convert_SMILES"]["group_screen_invert"],
33
+ )
34
+ result.dpdisp_gaussian_tasks(
35
+ # 注意,此处需要人为指定文件夹以避免浪费计算资源,默认通过empirical_estimate中的folders来确定
36
+ folders=config["empirical_estimate"]["folders"],
37
+ machine=config["convert_SMILES"]["machine"],
38
+ resources=config["convert_SMILES"]["resources"],
39
+ nodes=config["convert_SMILES"]["nodes"],
40
+ )
41
+
42
+ if __name__ == "__main__":
43
+ # 获取工作目录和配置
44
+ work_dir, config = get_work_dir_and_config()
45
+ # 合并配置(假设有merge_config函数)
46
+ config["convert_SMILES"] = merge_config(
47
+ default_config=DEFAULT_CONFIG, user_config=config, key="convert_SMILES"
48
+ )
49
+ # 调用主函数
50
+ main(os.path.basename(__file__), work_dir, config)
@@ -0,0 +1,56 @@
1
+ import os
2
+ from ion_CSP.empirical_estimate import EmpiricalEstimation
3
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
4
+
5
+ # 默认配置
6
+ DEFAULT_CONFIG = {
7
+ "empirical_estimate": {
8
+ "folders": [], # 默认文件夹列表
9
+ "ratios": [], # 默认离子配比
10
+ "sort_by": "density", # 默认排序方式
11
+ "make_combo_dir": True, # 默认不创建组合目录
12
+ "target_dir": "", # 默认目标目录
13
+ "num_combos": 100, # 默认组合数量
14
+ "ion_numbers": [], # 默认离子数量
15
+ }
16
+ }
17
+
18
+ @log_and_time
19
+ def main(work_dir, config):
20
+ # 在工作目录下准备 Gaussian 优化处理后具有 .gjf、.fchk 和 .log 文件的文件夹, 并提供对应的离子配比
21
+ result = EmpiricalEstimation(
22
+ work_dir=work_dir,
23
+ folders=config["empirical_estimate"]["folders"],
24
+ ratios=config["empirical_estimate"]["ratios"],
25
+ sort_by=config["empirical_estimate"]["sort_by"],
26
+ )
27
+ # 对 .fchk 文件用 Multiwfn 进行静电势分析, 并将经验公式所需的分析结果保存到同名 JSON 文件中
28
+ result.multiwfn_process_fchk_to_json()
29
+ # 由于后续晶体生成不支持 .log 文件,需要将 Gaussian 优化得到的 .log 文件最后一帧转为 .gjf 结构文件
30
+ result.gaussian_log_to_optimized_gjf()
31
+ # 如果依据密度排序,则需要经验公式根据配比生成离子晶体组合,读取 .json 文件并将静电势分析得到的各离子性质代入经验公式
32
+ if config["empirical_estimate"]["sort_by"] == 'density':
33
+ # 最终将预测的离子晶体密度以及对应的组分输出到 .csv 文件并根据密度从大到小排序
34
+ result.empirical_estimate()
35
+ # 如果依据氮含量排序,则调用另一套根据 .gjf 文件中化学分布信息
36
+ elif config["empirical_estimate"]["sort_by"] == 'nitrogen':
37
+ # 最终将预测的离子晶体氮含量以及对应的组分输出到 .csv 文件并根据氮含量从大到小排序
38
+ result.nitrogen_content_estimate()
39
+ # 基于排序依据 sort_by 对应的 .csv 文件创建 combo_n 文件夹,并复制相应的 .gjf 结构文件。
40
+ if config["empirical_estimate"]["make_combo_dir"]:
41
+ result.make_combo_dir(
42
+ target_dir=config["empirical_estimate"]["target_dir"],
43
+ num_combos=config["empirical_estimate"]["num_combos"],
44
+ ion_numbers=config["empirical_estimate"]["ion_numbers"],
45
+ )
46
+
47
+
48
+ if __name__ == "__main__":
49
+ # 获取工作目录和配置
50
+ work_dir, config = get_work_dir_and_config()
51
+ # 合并配置(假设有merge_config函数)
52
+ config["empirical_estimate"] = merge_config(
53
+ default_config=DEFAULT_CONFIG, user_config=config, key="empirical_estimate"
54
+ )
55
+ # 调用主函数
56
+ main(os.path.basename(__file__), work_dir, config)
run/run_gen_opt.py ADDED
@@ -0,0 +1,66 @@
1
+ import os
2
+ from ion_CSP.gen_opt import CrystalGenerator
3
+ from ion_CSP.log_and_time import StatusLogger
4
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
5
+
6
+ # 默认配置
7
+ DEFAULT_CONFIG = {
8
+ "gen_opt": {
9
+ "num_per_group": 500, # 每个空间群要生成的晶体结构数量
10
+ "space_groups_limit": 230, # 空间群搜索的限制
11
+ "nodes": 1, # 机器学习势优化占用 GPU 节点数
12
+ }
13
+ }
14
+
15
+ @log_and_time
16
+ def main(work_dir, config):
17
+ generator = CrystalGenerator(
18
+ work_dir=work_dir,
19
+ ion_numbers=config["gen_opt"]["ion_numbers"],
20
+ species=config["gen_opt"]["species"],
21
+ )
22
+ task_name_1_1 = "1_generation"
23
+ task_1_1 = StatusLogger(work_dir=work_dir, task_name=task_name_1_1)
24
+ if not task_1_1.is_successful():
25
+ try:
26
+ task_1_1.set_running()
27
+ # 根据提供的离子与对应的配比,使用 pyxtal 基于晶体空间群进行离子晶体结构的随机生成。
28
+ generator.generate_structures(
29
+ num_per_group=config["gen_opt"]["num_per_group"],
30
+ space_groups_limit=config["gen_opt"]["space_groups_limit"],
31
+ )
32
+ # 使用 phonopy 生成对称化的原胞另存于 primitive_cell 文件夹中,降低后续优化的复杂性,同时检查原子数以防止 pyxtal 生成双倍比例的超胞。
33
+ generator.phonopy_processing()
34
+ task_1_1.set_success()
35
+ except Exception:
36
+ task_1_1.set_failure()
37
+ raise
38
+
39
+ if task_1_1.is_successful():
40
+ task_name_1_2 = "1_optimization"
41
+ task_1_2 = StatusLogger(work_dir=work_dir, task_name=task_name_1_2)
42
+ if not task_1_2.is_successful():
43
+ try:
44
+ task_1_2.set_running()
45
+ # 基于 dpdispatcher 模块,在远程服务器上批量准备并提交输入文件,并在任务结束后回收机器学习势优化的输出文件 OUTCAR 与 CONTCAR
46
+ generator.dpdisp_mlp_tasks(
47
+ machine=config["gen_opt"]["machine"],
48
+ resources=config["gen_opt"]["resources"],
49
+ python_path=config["gen_opt"]["python_path"],
50
+ nodes=config["gen_opt"]["nodes"],
51
+ )
52
+ task_1_2.set_success()
53
+ except Exception:
54
+ task_1_2.set_failure()
55
+ raise
56
+
57
+
58
+ if __name__ == "__main__":
59
+ # 获取工作目录和配置
60
+ work_dir, config = get_work_dir_and_config()
61
+ # 合并配置(假设有merge_config函数)
62
+ config["gen_opt"] = merge_config(
63
+ default_config=DEFAULT_CONFIG, user_config=config, key="gen_opt"
64
+ )
65
+ # 调用主函数
66
+ main(os.path.basename(__file__), work_dir, config)
@@ -0,0 +1,43 @@
1
+ import os
2
+ from ion_CSP.read_mlp_density import ReadMlpDensity
3
+ from ion_CSP.log_and_time import StatusLogger
4
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
5
+
6
+ # 默认配置
7
+ DEFAULT_CONFIG = {
8
+ "read_mlp_density": {
9
+ "n_screen": 10, # 筛选机器学习势优化后密度最大的n个CONTCAR与对应的OUTCAR
10
+ "molecules_screen": True, # 是否排除离子改变的晶体结构
11
+ "detail_log": False, # 是否额外生成详细的筛选日志文件
12
+ },
13
+ }
14
+
15
+
16
+ @log_and_time
17
+ def main(work_dir, config):
18
+ task_name = "2_read_mlp_density"
19
+ task = StatusLogger(work_dir=work_dir, task_name=task_name)
20
+ try:
21
+ task.set_running()
22
+ # 分析处理机器学习势优化得到的CONTCAR文件
23
+ result = ReadMlpDensity(work_dir=work_dir)
24
+ # 读取密度数据,根据离子是否成键进行筛选,并将前n个最大密度的文件保存到max_density文件夹
25
+ result.read_density_and_sort(n_screen=config["read_mlp_density"]["n_screen"],
26
+ molecules_screen=config["read_mlp_density"]["molecules_screen"],
27
+ detail_log=config["read_mlp_density"]["detail_log"],)
28
+ # 将max_density文件夹中的结构文件利用 phononpy 模块进行对称化处理,方便后续对于结构的查看,同时不影响晶胞性质
29
+ result.phonopy_processing_max_density()
30
+ task.set_success()
31
+ except Exception:
32
+ task.set_failure()
33
+ raise
34
+
35
+ if __name__ == "__main__":
36
+ # 获取工作目录和配置
37
+ work_dir, config = get_work_dir_and_config()
38
+ # 合并配置(假设有merge_config函数)
39
+ config["read_mlp_density"] = merge_config(
40
+ default_config=DEFAULT_CONFIG, user_config=config, key="read_mlp_density"
41
+ )
42
+ # 调用主函数
43
+ main(os.path.basename(__file__), work_dir, config)
@@ -0,0 +1,68 @@
1
+ import os
2
+ import yaml
3
+ import logging
4
+ import argparse
5
+ from ion_CSP.log_and_time import log_and_time, StatusLogger
6
+ from ion_CSP.upload_download import SSHBatchJob
7
+
8
+
9
+ @log_and_time
10
+ def main(work_dir, config):
11
+ task_name_3_1 = '3_upload_vasp'
12
+ task_3_1 = StatusLogger(work_dir=work_dir, task_name=task_name_3_1)
13
+
14
+ batch_config = {"upload_prefixes": ["CONTCAR_", "OUTCAR_"]}
15
+ folder_name = os.path.normpath(os.path.abspath(work_dir)).split(os.sep)[-1]
16
+ job = SSHBatchJob(
17
+ work_dir=work_dir,
18
+ machine_json=config["upload_download"]["machine_json"],
19
+ machine_type="ssh_direct",
20
+ )
21
+ if not task_3_1.is_successful():
22
+ try:
23
+ task_3_1.set_running()
24
+ script = "steps_opt_monitor.sh"
25
+ command = f"./steps_opt_monitor.sh {folder_name}"
26
+ job.prepare_and_submit(
27
+ command=command, forward_common_files=[script], batch_config=batch_config
28
+ )
29
+ # 关闭 SFTP 和 SSH 客户端
30
+ job.close_connection()
31
+ task_3_1.set_success()
32
+ except Exception:
33
+ task_3_1.set_failure()
34
+ raise
35
+
36
+ if task_3_1.is_successful():
37
+ task_name_3_2 = '3_download_vasp'
38
+ task_3_2 = StatusLogger(work_dir=work_dir, task_name=task_name_3_2)
39
+ if not task_3_2.is_successful():
40
+ try:
41
+ task_3_2.set_running()
42
+ job.download_entire_folder()
43
+ job.client.exec_command(f"rm -r {job.remote_dir}/{folder_name}")
44
+ print(f"Deleted remote folder {folder_name}")
45
+ logging.info(f"Deleted remote folder {folder_name}")
46
+ # 关闭 SFTP 和 SSH 客户端
47
+ job.close_connection()
48
+ task_3_2.set_success()
49
+ except Exception:
50
+ task_3_2.set_failure()
51
+ raise
52
+
53
+
54
+ if __name__ == "__main__":
55
+ parser = argparse.ArgumentParser(description="Process files in a specified working directory")
56
+ parser.add_argument("work_dir", type=str, help="The working directory to run the script in")
57
+ args = parser.parse_args()
58
+ # 尝试读取配置文件
59
+ try:
60
+ with open(os.path.join(args.work_dir, "config.yaml"), "r") as file:
61
+ config = yaml.safe_load(file)
62
+ except FileNotFoundError:
63
+ print(f"config.yaml not found in {args.work_dir}.")
64
+ raise
65
+ # 获取当前脚本的名称
66
+ script_name = os.path.basename(__file__)
67
+ # 调用主函数
68
+ main(script_name, args.work_dir, config)
@@ -0,0 +1,43 @@
1
+ import os
2
+ from ion_CSP.vasp_processing import VaspProcessing
3
+ from ion_CSP.log_and_time import StatusLogger
4
+ from ion_CSP.log_and_time import log_and_time, merge_config, get_work_dir_and_config
5
+
6
+ # 默认配置
7
+ DEFAULT_CONFIG = {
8
+ "vasp_processing": {
9
+ "nodes": 2, # VASP 分步优化占用 CPU 节点数
10
+ "molecules_prior": True, # 是否检查离子晶体结构中所有离子的结构
11
+ },
12
+ }
13
+
14
+ @log_and_time
15
+ def main(work_dir, config):
16
+ task_name = "4_vasp_processing"
17
+ task = StatusLogger(work_dir=work_dir, task_name=task_name)
18
+ try:
19
+ task.set_running()
20
+ result = VaspProcessing(work_dir=work_dir)
21
+ # 基于 dpdispatcher 模块,在远程CPU服务器上批量准备并提交VASP分步优化任务
22
+ # result.dpdisp_vasp_tasks(
23
+ # machine=config["vasp_processing"]["machine"],
24
+ # resources=config["vasp_processing"]["resources"],
25
+ # nodes=config["vasp_processing"]["nodes"],
26
+ # )
27
+ # 批量读取 VASP 分步优化的输出文件,并将能量和密度等结果保存到目录中的相应CSV文件
28
+ result.read_vaspout_save_csv(config["vasp_processing"]["molecules_prior"])
29
+ task.set_success()
30
+ except Exception:
31
+ task.set_failure()
32
+ raise
33
+
34
+
35
+ if __name__ == "__main__":
36
+ # 获取工作目录和配置
37
+ work_dir, config = get_work_dir_and_config()
38
+ # 合并配置(假设有merge_config函数)
39
+ config["vasp_processing"] = merge_config(
40
+ default_config=DEFAULT_CONFIG, user_config=config, key="vasp_processing"
41
+ )
42
+ # 调用主函数
43
+ main(os.path.basename(__file__), work_dir, config)
@@ -1,19 +0,0 @@
1
- ion_CSP/__init__.py,sha256=M5RcbYDdt-UBVpsDKiJWJqLvSFfoBfU6aTUVccgK_BE,190
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=TinsFGJPF0TPVZKMCzPyxuHBGrdeqw7yOnGh-78qbqo,11209
10
- ion_CSP/steps_opt_monitor.sh,sha256=1klPjnK0gqkDbvI9PtjdK5qidJ5G0Mo8q1SfrlLW5xM,3330
11
- ion_CSP/task_manager.py,sha256=S0QK7EJhKrQL1hzMqkR6a6y3Du027Ppyz-zHenWrFQ4,16241
12
- ion_CSP/upload_download.py,sha256=Hiz5jKOy9x26hJJdcpt-owQdVUbzzGuGOelro6JozY8,23801
13
- ion_CSP/vasp_processing.py,sha256=eQTMKIPBzi1X4HHTqWkHE1Lt8dvCCV-MXPCR3RtKYZ0,13977
14
- ion_csp-2.0.8.dist-info/licenses/LICENSE,sha256=2J6A8GT2iIf2LhuWO1_0ilgx7ijzzpQ2BXU7rHKe8Cc,1068
15
- ion_csp-2.0.8.dist-info/METADATA,sha256=pZg7XM0CD5Du6rQJvijc_VOyfvtFVlnmWAZiwBPmeIU,6380
16
- ion_csp-2.0.8.dist-info/WHEEL,sha256=QZxptf4Y1BKFRCEDxD4h2V0mBFQOVFLFEpvxHmIs52A,91
17
- ion_csp-2.0.8.dist-info/entry_points.txt,sha256=NexQJDs9f69kJA2DgoU6tsA3V8a66nadJRem1U_c_6g,54
18
- ion_csp-2.0.8.dist-info/top_level.txt,sha256=aYZa43dDebjLpWPN6bDIlBb6BVwA8gk4ajEjDDK9b9I,8
19
- ion_csp-2.0.8.dist-info/RECORD,,